www.tombraiderforums.com

Go Back   www.tombraiderforums.com > Tomb Raider Modding > Tomb Raider Level Editor > Software Development

Reply
 
Thread Tools
Old 18-06-13, 21:32   #121
Titak
Moderator
 
Titak's Avatar
 
Join Date: Jul 2003
Location: Drenthe, The Netherlands
Posts: 32,147
Default

I've seen those lines between textures before and was told it was caused by the graphicscard when anti-aliasing is set in the card's settings.
So not in the gamesettings but in the card settings.
And people have also reported the problem being fixed after they had disabled the anti-aliasing setting in the graphicscard.

Not sure if it means anything to you or if it is usefull but I thought I'd just throw it out there.


Good news on the optimizing!
Something my levels can certainly use!
And many others as well ofcourse.
__________________
If it walks like a duck and if it quacks like a duck, it is a duck.
Titak is offline   Reply With Quote
Old 18-06-13, 21:42   #122
Lwmte
Explorer
 
Join Date: Aug 2010
Posts: 939
Default

meta2tr, the problem is mipmapping WILL cause edge bleeding in any case, because it downsamples original textures and therefore interpolates adjacent pixels (no matter if it is bilinear, bicubic or mitchell algorithm, no matter if it's power of 2 or not). You indeed can align UV coordinates to cut off edges, but it's not a proper solution, because bleeding edges will become more and more obvious with every mip level, so you will have to increase cutting off more and more, which will in turn produce incorrect texture transitions between faces.

Cochrane, yes, every texinfo can intersect any other texinfo, but we don't need strict child-parent relationship, we only need to define max. size of parent tile, and then clamp it. All other texinfos that are inside this parent tile will be automatically downsampled correctly.
Lwmte is offline   Reply With Quote
Old 18-06-13, 21:54   #123
Cochrane
Gold Contributor
 
Cochrane's Avatar
 
Join Date: Apr 2006
Location: Germany
Posts: 16,048
Default

Quote:
Originally Posted by meta2tr View Post
I really know nothing about 3d rendering like you guys, but I can't see why mipmapping would necessarily cause bleeding if it's done right?
Background: When rendering, the texture unit of the GPU has to find the right color for a given set of texture coordinates. Standard bilinear filtering selects the four closest pixels to that spot on the texture, then calculates a linear average (in both directions, hence "bi"-linear). For values at the edges of the polygon, in a texture map, some of those four closest pixels can belong to other textures. To reduce this you select pixel centers instead of pixel borders. That part is easy.

As you know, mipmapping means that if the camera is further away from the polygon, a lower-resolution version of the texture is used instead (or actually most often two, with a linear interpolation between the results, hence "tri"-linear filtering). With the lower resolution, more and more texture coordinate locations will lie close enough to the edge to be problematic - before, there may have been, say, three pixels between the location and the edge, but at the low resolution used for mipmapping, it's only one or even none. Hence, the next texture starts to affect the resulting color values for texture coordinate locations much further from the edge. This becomes the bleeding effect.

To solve that bleeding, I could tell OpenGL to switch to the low-resolution version later (but this doesn't solve it, it just hides it a bit), or I add areas of the edge color between the different textures (the thing discussed now) so that the color that bleeds in is actually correct. I could also dynamically move the texture coordinates based on the resolution selected, which would require pixel shaders, but that would mean that textures get distorted when they are further away, which will look horrible.

I cannot tell the texture unit to limit the pixels it picks to satisfy a particular color request. So it's one of these kludges I mentioned above. That, or disabling mipmapping.

Quote:
Originally Posted by meta2tr View Post
If I understood right, the atlas feature means that many texture tiles are placed onto one large texture tiles. I once did this to import tut1 into Blender, I packed all of the tiles onto a single 2048x2048 texture. I got texture bleeding in Blender due to the fact that I had calculated uv polygons to be aligned to pixel borders, not to pixel centers, as is the case in tomb4. How are uv coordinates calculated in OpenTomb?
Yes, that's exactly what's happening with the atlas here, too. UV coordinates in OpenTomb are calculated on pixel centers (the classic Tomb Raider format actually includes special support for this) for precisely the reason you mentioned. But as I pointed out above, if each pixel covers more area (which is one way to see mipmapping), that won't work as well anymore.


Edit to add:
Quote:
Originally Posted by Titak View Post
I've seen those lines between textures before and was told it was caused by the graphicscard when anti-aliasing is set in the card's settings.
So not in the gamesettings but in the card settings.
And people have also reported the problem being fixed after they had disabled the anti-aliasing setting in the graphicscard.

Not sure if it means anything to you or if it is usefull but I thought I'd just throw it out there.
That is a related issue, but not actually the problem here, since OpenTomb doesn't use any super-sampling (and it's not set via the graphics card either).

Quote:
Originally Posted by Titak View Post
Good news on the optimizing!
Something my levels can certainly use!
And many others as well ofcourse.
That's why we do it!

Quote:
Originally Posted by Lwmte View Post
meta2tr, the problem is mipmapping WILL cause edge bleeding in any case, because it downsamples original textures and therefore interpolates adjacent pixels (no matter if it is bilinear, bicubic or mitchell algorithm, no matter if it's power of 2 or not). You indeed can align UV coordinates to cut off edges, but it's not a proper solution, because bleeding edges will become more and more obvious with every mip level, so you will have to increase cutting off more and more, which will in turn produce incorrect texture transitions between faces.

Cochrane, yes, every texinfo can intersect any other texinfo, but we don't need strict child-parent relationship, we only need to define max. size of parent tile, and then clamp it. All other texinfos that are inside this parent tile will be automatically downsampled correctly.
I can easily construct you examples where the maximum size of the parent tile is 256x256 even though no single tile is larger than 4x4. I'm not sure if that's something that occurs often, or ever, in actual levels.

In general, I'm not sure if this really provides many advantages over just padding each texinfo individually. There are certainly edge cases where it can help, but the required finding of intersections is not quite trivial. Plus, the resulting resizing regions need not be rectangular. I guess I could start with the "each texinfo individually" version and then later try your version as an optimization to cut down on VRAM usage.

(In an earlier version of my post I said that your method couldn't work. That was actually me misunderstanding what you wanted to do, so please ignore it.)
__________________
GŁter auf die Bahn!

Last edited by Cochrane; 18-06-13 at 22:06.
Cochrane is offline   Reply With Quote
Old 19-06-13, 07:35   #124
Lwmte
Explorer
 
Join Date: Aug 2010
Posts: 939
Default

Quote:
Originally Posted by -Roli- View Post
Try on his youtube channel, there he is more active.
Thanks, I've sent him a PM with a question on this mipmap issue, hopefully he will answer.

Quote:
Originally Posted by Titak View Post
I've seen those lines between textures before and was told it was caused by the graphicscard when anti-aliasing is set in the card's settings.
I guess, antialiasing also makes texture borders "naked", which results in same artifacts; however, in case of AA it most likely depends on antialiasing algorithm used, with strict supersampling there should be no such artifacts... But who knows.

Quote:
Originally Posted by Cochrane View Post
I can easily construct you examples where the maximum size of the parent tile is 256x256 even though no single tile is larger than 4x4. I'm not sure if that's something that occurs often, or ever, in actual levels.
Yes, I thought about it, but I think that level builders rarely use textures in that way. Theoretically one could apply two adjacent textures to single face and therefore break into wrong "parent" tile, but I can't imagine such situation.

BUT!!! Suddenly I remembered something about animated textures in TR engines. At least in TR3 they had 4 animated ranges on a single 64x64 texture tile, and this whole tile was placed somewhere in every level where it couldn't be seen. For ex., in HOUSE.TR2 it is placed on manor's roof:


I don't remember the exact purpose of it, but I guess they did it to overcome some kind of animated ranges bug.

So, this effectively makes my solution unusable at least in TR3.

Quote:
I guess I could start with the "each texinfo individually" version...
Yeah, I also think that is the way shabtronic did it in his RetroFit. But what about texture memory? Modern custom levels can have thousands of texinfos, I have no idea how much texinfos are in this new Psiko's Hypersquare level, but if he used 1000+ texture pages, I guess, texinfo count could right up to tens of thousands... How much memory it will eat up and how it will affect performance?

Quote:
...and then later try your version as an optimization to cut down on VRAM usage.
Regarding an issue I've described above, I guess, we should scrap the idea of applying mipmaps independently to "parent" tiles and do something different.

Last edited by Lwmte; 19-06-13 at 07:44.
Lwmte is offline   Reply With Quote
Old 19-06-13, 08:48   #125
meta2tr
Historian
 
Join Date: Apr 2008
Posts: 368
Default

Thanks for the explanations on mipmapping. It certainly does seem quite difficult to get it right.

Quote:
Originally Posted by Lwmte View Post
But what about texture memory? Modern custom levels can have thousands of texinfos, I have no idea how much texinfos are in this new Psiko's Hypersquare level, but if he used 1000+ texture pages, I guess, texinfo count could right up to tens of thousands... How much memory it will eat up and how it will affect performance?
He is right up to the limits (32k in TRNG, 16k in the original TRLE engine). The texinfo table size doesn't appear to affect framerate. If I remember right each texinfo entry in the tr4 file is 38 bytes, so as a we could expect 32768 x 38 = 1.2Mb of RAM to be used if they are read directly into memory (which of course may not be the case).

I've created a couple of levels with lots of texture pages (1024 and 2000).

Each texture page is unique, and the number of dots in the image is the page number.

The level is a modified tut1 where the starting room has a wall of textures in grid, in which each face is mapped to a texture page like this:



On my pc, TRNG can display pages 1 to 1037, then from mid-way into 1038 they appear as black. However, in classic tomb4, all 2000 are displayed!!
meta2tr is offline   Reply With Quote
Old 19-06-13, 09:36   #126
shabtronic
Hobbyist
 
Join Date: Feb 2012
Posts: 56
Default

Awesome work Lwmte, much respect because the TR format is a real headache, it's a massive amount of work to get it as far as you - well done!!

Tragically I lost all the retrofit src in a HD crash a while - buuuut it's so freaky I started rewriting it again last night as I finally have some free time, and then I got your message!!


The answer you are looking for to fix the mip map line problem is here:

typedef struct { // 4 bytes
u8 Xcoordinate; // 1 if Xpixel is the low value, 255 if Xpixel is the high value in the object texture
u8 Xpixel;
u8 Ycoordinate; // 1 if Ypixel is the low value, 255 if Ypixel is the high value in the object texture
u8 Ypixel;
} tr2_object_texture_vert;

is incorrect in the documents it's actually as follows:

typedef struct { // 4 bytes
i8 Xcoordinate; // 1 if Xpixel is the low value, 255 if Xpixel is the high value in the object texture
u8 Xpixel;
i8 Ycoordinate; // 1 if Ypixel is the low value, 255 if Ypixel is the high value in the object texture
u8 Ypixel;
} tr2_object_texture_vert;


XCoordinate and YCoordinate are signed 8 bit values - so you final texture co-ords will be:

u=(float)((Xpixel+(i8&)XCoordinate))/255
v=(float)((Ypixel+(i8&)YCoordinate))/255


it seems they built in the edge correction because of issues with earlier vid cards and all that.

should fix the horrid line issue - have fun man!!
shabtronic is offline   Reply With Quote
Old 19-06-13, 10:00   #127
meta2tr
Historian
 
Join Date: Apr 2008
Posts: 368
Default

Quote:
Originally Posted by shabtronic View Post

u=(float)((Xpixel+(i8&)XCoordinate))/255
v=(float)((Ypixel+(i8&)YCoordinate))/255


it seems they built in the edge correction because of issues with earlier vid cards and all that.
Yep, I noticed the unsigned to signed discrepancy too.

But using your formula, wouldn't that make uv edges go from 0 to (254/255)? That means, for u, the max value is a little to the left of the left side of the rightmost pixel.

In the original game engine I noticed that texture coordinates were aligned to pixel centers, so I wonder if it's not more like this:

u=((float)((Xpixel+(i8&)XCoordinate))/255) + (1/512)

Edit: nope, that's not right either. A full tile goes from

Xpixel 0 Xcoord 0
to
Xpixel FF Xcoord FF

Half a tile is

Xpixel 0 Xcoord 0
to
Xpixel 7F Xcoord FF

In fact, it seems that we can throw away Xcoord, like so

u_pixel_center=(Xpixel+0.5)/256
v_pixel_center=(Ypixel+0.5)/256

That way a tile goes from 1/512 to 511/512
and a half tile goes from 1/512 to 255/512

Thoughts?

Last edited by meta2tr; 19-06-13 at 16:14.
meta2tr is offline   Reply With Quote
Old 19-06-13, 10:16   #128
shabtronic
Hobbyist
 
Join Date: Feb 2012
Posts: 56
Default

Quote:
Originally Posted by meta2tr View Post
Yep, I noticed the unsigned to signed discrepancy too.

But using your formula, wouldn't that make uv edges go from 0 to (254/255)? That means, for u, the max value is a little to the left of the left side of the rightmost pixel.

In the original game engine I noticed that texture coordinates were aligned to pixel centers, so I wonder if it's not more like this:

u=((float)((Xpixel+(i8&)XCoordinate))/256) + (1/512)

Thoughts?
Yeah - Just took the time to read the last few pages on the forum. That /255 code is from my code frenzy last night - and it's almost correct - yes you are correct it can make go from (1 to 254)/255 it's only slightly out - what it does do is always shrink the UV inwards so there's no bleed when mipping when using standard texture pages. After reading the last 2 pages - I realise your probably talking about the massive atlas problem? I can't actually remember how I fixed that - maybe I clamped in the shader or made some space between texture pages on the massive atlas I used or maybe I shrunk the edge UV's by more than 1. Coz I don't have the code I can't look. Shrinking the Edge co-ords is pretty easy because you can check if they are edge UV simply (test for 0 or 255 and if it's the lowest or highest - and do whatever shrinking you like?
float xmul=1;
float ymul=1;
if (XPixel==0 !! XPixel==255) xmul=5;
if (YPixel==0 !! YPixel==255) ymul=5;

u=((float)((Xpixel+((i8&)XCoordinate)*xmul))/255);
v=((float)((Ypixel+((i8&)YCoordinate)*ymul))/255);

then convert to your atlas co-ords, something like that would probably work e.t.c.
I do remember the mipping param I used if thats any help and it was
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

*edit*

From my point of view XCoordinate and YCoordinate are needed - because they tell you the direction in which to shrink the UV coords, I think it was a fudge from the early days of video cards - when nobody knew what they were doing :P


The Level I tested all this stuff out on was - Antartica TR3 - coz that level just really shows up all the mipping horrors right away.
have fun!

Last edited by shabtronic; 19-06-13 at 11:07.
shabtronic is offline   Reply With Quote
Old 19-06-13, 11:26   #129
Cochrane
Gold Contributor
 
Cochrane's Avatar
 
Join Date: Apr 2006
Location: Germany
Posts: 16,048
Default

Two things first, before anything else:

A negative LOD bias solves the bleeding issue. To try it yourself, insert glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -2.0f); in texture_atlas.cpp after the other calls to glTexParameter. This works by making sure that the higher resolution mipmap is used longer. My first instinct is that Iíll continue to use this fix until and unless someone complains. All my other discussions about this issue are purely theoretical.

Is it just me, or are transparent triangles on static objects not rendered properly? That one level with the waterfall that someone mentioned (Lmwte? Sorry, thanks to slow internet it's actually rather painful to go back and check right now) shows it very clearly. Obviously thatís a bug. The question is: Is that my bug, or is that issue already present in the original engine?

On to the details:

The additional cost for the border per tex info is ((circumference of texinfo) * (border size) + 4 * (border size)^2) * 4 bytes. Iíve generated some statistics for BOAT.TR2. This has 1730 texinfos with a total circumference of 159078 pixels (average 91.953). With a two pixel border, I end up with 1383344 bytes (155 kB) and with four pixels, I get 2988128 additional bytes (2.84 MB) just for the borders. This is not taking into account any necessary duplication of interior pixels due to overlapping texinfos, and it assumes that I can pack all resulting padded texinfo pieces perfectly, neither of which is a realistic assumption. So Iíd say about twice that sounds like a good (perhaps a little high) upper bound for classic TR levels. For high-performance TRNG levels, I believe the overhead in percent may actually be lower, since it is linear to texture size while memory use for the interior is quadratic with texture size, but of course it will be higher in total bytes.

meta2tr: Thanks for the test level! Iím on a train right now, connected to the internet via my phone, so it may be quite a while before I can download the level (specifically, I hope to get it in Kassel, but it may be Frankfurt before I have it. Since Hanover, I got 9.8 MB).

That dropping of Xcoord wonít work, because with your formula a full tile goes from 0.5/256 to 256.5/256 (or 1/512 to 513/512).

shabtronic: TeslaRus has already implemented it like that. I think we need a new TRosettaStone document, maybe as a wiki. There are many known flaws in it, and every new programmer gets to discover them for himself from scratch every time. Thatís annoying.

The approach taken by TeslaRus actually adds/subtracts half a pixel. Changing that to a full pixel may help some, now that I think about it.
__________________
GŁter auf die Bahn!
Cochrane is offline   Reply With Quote
Old 19-06-13, 11:26   #130
Titak
Moderator
 
Titak's Avatar
 
Join Date: Jul 2003
Location: Drenthe, The Netherlands
Posts: 32,147
Default

Quote:
Originally Posted by Lwmte View Post
BUT!!! Suddenly I remembered something about animated textures in TR engines. At least in TR3 they had 4 animated ranges on a single 64x64 texture tile, and this whole tile was placed somewhere in every level where it couldn't be seen. For ex., in HOUSE.TR2 it is placed on manor's roof:

I don't remember the exact purpose of it, but I guess they did it to overcome some kind of animated ranges bug.
The bug is that for some odd reason the textures won't animate if it isn't placed like that somewhere in the level.
__________________
If it walks like a duck and if it quacks like a duck, it is a duck.
Titak is offline   Reply With Quote
Reply

Bookmarks

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off



All times are GMT. The time now is 04:21.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2019, vBulletin Solutions Inc.