PDA

View Full Version : Has anyone used a texture atlas and used it in Chrome?



xman84
04-03-2011, 12:51 PM
I created a texture atlas and in Chrome there is some white on the edges of the cubes. However in Firefox it displays just fine. When I use colors there are not white edges either in Chrome or Firefox so it appears to be strictly a texturing problem. The texture atlas is 64 x 64 pixels and there are 16 total textures within the texture atlas at a width of 16 each.

Has anyone had a similar issue or know maybe why I am having this problem?

oak3d
04-03-2011, 08:01 PM
Yes, I experienced the same problem, it seems to be related to the hardware platform you are using. When I tested it in another pc, the problem just disappeared.
My platform with problems: AMD Phenom II x4 945, GTX460, Win7
Fine platform: Intel Core2 E7500, 9500GT, WinXP

SteveBaker
04-04-2011, 05:56 AM
Could one of you guys share a screenshot and a copy of the texture map & shader?

oak3d
04-04-2011, 07:41 AM
http://www.oak3d.com/wp-content/uploads/2011/04/error.jpg

oak3d
04-04-2011, 07:46 AM
The artifacts only appears on Chrome. In firefox it's fine on all platforms.

SteveBaker
04-04-2011, 04:01 PM
How certain are you that your vertices are accurately snapped together - with no 'T-edges'? One common difference between Chrome and Firefox (on some hardware) is that Chrome will enable antialiasing when Firefox won't.

If your vertices are not 100% perfectly shared - then you'll get teeny-tiny gaps (which we're seeing white background through) that are visible because the antialiasing is rendering the edges just perfectly...but without antialiasing, the gaps would show up less often (but be much more noticeable when they do show up).

That's my best theory...but it's hard to guess from such little information.

As a test, turn off antialiasing when you create your rendering context. If that makes Chrome and Firefox look the same - then I'm 99% sure I'm right. If it doesn't make a difference...then I need to have another think...so show us the texture AND the shader.

xman84
04-04-2011, 06:01 PM
vertex shader:

attribute vec3 aVertexPosition;
attribute vec3 aVertexNormal;
attribute vec2 aTextureCoord;
attribute float aInShade;
attribute vec4 aVertexColor;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
uniform mat4 uNMatrix;
uniform vec3 uAmbientColor;
uniform vec3 uLightingDirection;
uniform vec3 uDirectionalColor;
uniform bool uUseLighting;
uniform bool uUseShadows;
uniform bool uUseColor;
varying vec2 vTextureCoord;
varying vec3 vLightWeighting;
varying vec4 vColor;

vec3 halfLambertDiffuse(void) {
vec4 transformedLightingDirection = uMVMatrix * vec4(uLightingDirection, 0.0);
vec4 transformedNormal = uNMatrix * vec4(aVertexNormal, 1.0);
float directionalLightWeighting = max(sqrt(0.5 * dot(transformedNormal.xyz, transformedLightingDirection.xyz) + 0.5), 0.0);
//float directionalLightWeighting = max(dot(transformedNormal.xyz, transformedLightingDirection.xyz), 0.6);
vLightWeighting = uAmbientColor + uDirectionalColor * directionalLightWeighting;
return vLightWeighting;
}

void main(void)
{
vec4 mvPosition = uMVMatrix * vec4(aVertexPosition, 1.0);
gl_Position = uPMatrix * mvPosition;
if (!uUseColor) {
vTextureCoord = aTextureCoord;
if (!uUseLighting) {
vLightWeighting = vec3(1.0, 1.0, 1.0);
} else {
//shading with shadows
if (uUseShadows) {
if (aInShade == 0.0) {
vLightWeighting = halfLambertDiffuse();
} else {
vLightWeighting = uAmbientColor;
}
} else {
//shading only
vLightWeighting = halfLambertDiffuse();
}
}
} else {
vColor = aVertexColor;
if (uUseLighting) {
vLightWeighting = halfLambertDiffuse();
}
}
}

fragment shader:

#ifdef GL_ES
precision highp float;
#endif
varying vec2 vTextureCoord;
varying vec3 vLightWeighting;
varying vec4 vColor;
uniform sampler2D uSampler;
uniform bool uUseColor;
uniform bool uUseLighting;
void main(void)
{
if (!uUseColor) {
vec4 textureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
gl_FragColor = vec4(textureColor.rgb * vLightWeighting, textureColor.a);
//gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
} else {
if (!uUseLighting) {
gl_FragColor = vColor;
} else {
gl_FragColor = vec4(vColor.rgb * vLightWeighting, vColor.a);
}
}
}

Everything in the game world is made of cubes. Notice the textured cubes have the white edges vs the colored cubes (the character) has no white edges.

http://i.imgur.com/9fbek.png

xman84
04-04-2011, 06:08 PM
Another angle:
http://i.imgur.com/farRG.png

xman84
04-04-2011, 06:13 PM
texture:
http://i.imgur.com/04rQQ.png

SteveBaker
04-04-2011, 08:05 PM
There is no bug in driver, browser or WebGL here. Your program is the problem. You're probably getting away with it on some systems because the results sensitively depend on roundoff error - and antialiassing is almost certainly what's making it more noticable. However, with the issues I describe below, you'll eventually see issues on any platform under some camera angles/lighting/whatever.

There are a couple of issues here:

1) If you draw two cubes bang up against each other (eg on the ground), the top row of pixels of front-facing vertical face of the further cube will potentialy have the exact same Z coordinate as the far edge of the upper face of the nearer cube...so they will "flimmer"/"Z-fight" at some camera angles. You can't make a voxel game just by drawing a bunch of cubes - you have to eliminate the faces of cubes that are butting up against other cubes.

2) When you render a texture with LINEAR or MIPMAP_LINEAR modes, then adjacent texels will be linearly blended. Hence you can't use atlassed textures that are packed together tightly like that. You have to inset the area you use out of each sub-map by at least a few texels and color the "no-man's land" between the sub-maps in the same color as the adjacent sub-maps. So instead of using UV values like 0.0 to 0.25 for one map and 0.25 to 0.5 for the next - use 0.0+(inset/mapres) to 0.25-(inset/mapres) for one and 0.25+(inset/mapres) to 0.5-(inset/mapres) for the next...where 'inset' is 2.0 or so and 'mapres' is the resolution of your map in texels. If you're MIPmapping (which you don't seem to be doing in your screenshot - but you'll definitely need to do to avoid horrible moire & aliassing because you're using perspective) then there is no amount of "inset" that'll perfectly avoid the problem at lower MIP levels - so you'd also do well to avoid textures of violently differing colors being right next to each other in the atlas...try to keep similar colors together. If you have unused areas in the map...paint them a neutral color that's similar to the nearby maps.

Because your foreground character seems to be working - I deduce that (2) is your main problem...but I predict that (1) will also come back to bite you. 3D graphics are quite intolerant of this kind of inattention to roundoff and precision issues.

-- Steve

SteveBaker
04-04-2011, 08:16 PM
Oh - and incidentally, using unnecessary "if" statements inside shaders is a really bad idea - especially on older hardware. Shaders are NOT general purpose CPU's and you can't treat GLSL like it was C or C++.

On some older machines, both the 'then' and the 'else' part consume time, even if they aren't being executed!!! eg:

if ( a )
do_something () ;
else
do_something_else () ;

...executes at a speed that is equal to the time it would take to do BOTH "do_something" AND "do_something_else". Even modern machines will suffer this problem in pixel shaders under some rather common situations!!

Hence, even when you have lighting and shadowing turned off - you're still paying the price for doing both. With your deeply-nested "if" statements, you're running every statement in the shader even if just one assignment was all that was needed!

Since it looks like you're using uniform variables to switch various modes on and off - you'd be better to create different shaders for each combination of modes using #if/#else/#endif to keep your sanity! When you're rendering, consider sorting your objects according to the shader they need in order to minimize shader reloading.

-- Steve

xman84
04-04-2011, 09:11 PM
Wow thank you for the helpful advice. I have a lot to digest as I do this as a hobby and have been teaching myself WebGL/OpenGL for the past 6 months outside of work. There are some things regarding the textures I didn't understand but I want to do some Googling and be less tired before asking.

I'll probably be posting some more questions tomorrow, after I get out of work, to make sure I understand. Thanks again. I really do owe you one.

oak3d
04-05-2011, 08:41 AM
But my artifacts appears where is drawn in one draw batch and I don't even use a texture.

SteveBaker
04-05-2011, 05:26 PM
OK guys - this is getting confusing!

Firstly, I should explain that I have been doing 3D graphics since 1980. I've seen every kind of problem you could possibly imagine. So I'm not guessing when I'm telling you what's wrong!

You two guys have totally different problems that just happen to look the same. They are both teeny-tiny roundoff kinds of problem that show up most clearly when antialiassing is enabled - which it typically is in Chrome and typically isn't in Firefox - and may be visible on some kinds of hardware and not others. In both cases you have made fairly elementary mistakes that I've seen 100 times before...but they appear to be different mistakes!

Accusing Chrome is unfair...you'll both see these problems in Firefox too - but because of the antialiassing in Chrome, the statistical probability of a "crack" showing up is much greater - but the crack itself is much narrower. When Firefox shows the problem, it'll be MUCH bigger...but it's also less probable.

To avoid further confusion - let me separate out my responses to each of you!

@oak3d: The "drawn in one batch" thing doesn't matter a damn. The cause of the symptoms you are reporting are very different from those that xman84 is seeing - the panda/bear image almost certainly has cracks because the vertices aren't perfectly shared, even though it's only one draw call - and even if it's not textured. If you don't believe me (and to be fair, all I've got to go on is one screenshot!) try clearing the screen to some really bright color instead of white. If you clear the screen to green, do the "cracks" turn green? If they do then you must have fine cracks in your geometry that are letting the background color leak through - right? That's what I'm betting...but you should do the experiment. Do you know what a "T-edge" is? If not, I can explain that. I'm pretty certain that you either have T-edges or unshared vertices - or (much less likely) some other weird bad geometry issue.


@xman84: Your texture atlas issues are at least a part of the problem - as I described before (although possibly not ALL of your problem). We know this for 100% certain because if you look at the 'cracks' on the building, some of them are red - and that's because you have red texture next to the grey/black "stone" texture. All of the cracks in the "grass" are white because the texture tile next to the green one is white. You never see red cracks in the grass because there is no red texture adjacent to the green one. Just to test my theory, look at the sky. There are white cracks on the left/right side of the map and green cracks at the top. Look at your texture atlas and guess what? You have grass next to one side of the blue patch and white on the other side. This isn't just a theory anymore...we have solid evidence! OpenGL/WebGL/Direct3D all do a trick where they blend the edges of adjacent texels together to avoid texture aliassing. At the very edges of your polygons, the texture UV coordinates are probably EXACTLY on the boundary between the grey/black stone and the bright red sub-map. So when WebGL blends in a little of the adjacent texel, you get some red mixed into the grey for a small fraction of the pixel. When you run in Firefox, the lack of polygon edge antialiassing is hiding this problem from you to some degree - but it WILL show up there under some circumstances...I guarantee it.

SteveBaker
04-05-2011, 05:50 PM
@oak3d: Your panda's body is a "volume of revolution" - right? I bet your code says something like:


for ( a = 0 ; a < 360 ; a+=10 ) // Do a full circle in 10 degree steps
{
a0 = a * 3.14159 / 180.0 ; // Convert to radians
x0 = sin ( a0 ) * radius ;
y0 = cos ( a0 ) * radius ;
a1 = (a+1) * 3.14159 / 180.0 ;
x1 = sin ( a1 ) * radius ;
y1 = cos ( a1 ) * radius ;
// make a quad from x0,y0 to x1,y1...
...
}

If you did anything like that then you are assuming that the sine and cosine of 0*pi/180 are PRECISELY equal to those at 36*pi/180 - but they aren't because in floating point math, bigger numbers are stored less precisely than small ones - and those two angles are not precisely two-pi radians apart. Note that it doesn't matter whether you do this in amazingly high precision math - or even whether you typed pi in to enough decimal places...the nature of computers is that floating point numbers are never 100% precise.

So if I'm right then it's no coincidence that the join between the first row of vertices and the last is where the crack shows up...and right down the center line of the panda is where it is! (That's my clue!)

The fix (if my guess is right) is to change the calculation of 'a1':

if ( a == 35 ) a1 = 0 * 3.14159/180.0 ; else a1 = (a+1)*3.14159/180.0 ;

...which ensures that the last column of vertices exactly lines up with the first.

But better still, use an indexed rendering mode and make the index of the final row of triangles re-use the actual vertices from the first row so you're not relying on math precision at all.

I can't be 100% sure of this - but I'd bet $10 that if you're generating the geometry programmatically that you did something kinda like that!

This explains the vertical crack - but it can only explain the horizontal ones if you're also not sharing the vertices vertically between rows of triangles either. That suggests that you're sending at least twice as many vertices to the GPU as you need to - and your panda will probably take twice as long to draw as it ideally could.

-- Steve

xman84
04-05-2011, 06:30 PM
Steve,

Would it better for me to do something like suggested here? Specifically the third pic from the top.
http://www.ogre3d.org/forums/viewtopic.php?f=4&t=61602

Which I think is what you suggested earlier with the inset. The picture is nice confirmation that I understand.

Or should I just modify my texture coordinates slightly, say by .05 to get rid of the bleeding? I'll probably make the changes over the next day or two and report back.

-Xavier

oak3d
04-05-2011, 06:49 PM
Steve,
Thank you for your detailed reply. I'll check out the mesh to see if there's anything as what you said.

zed
04-05-2011, 07:45 PM
if its not Tjunctions like steve saiz, its most likely filtering
to see if thats the cause use gl.( NEAREST ) texture filtering instead of LINEAR

SteveBaker
04-05-2011, 07:50 PM
@xman84:


Steve,

Would it better for me to do something like suggested here? Specifically the third pic from the top.
http://www.ogre3d.org/forums/viewtopic.php?f=4&t=61602

Which I think is what you suggested earlier with the inset. The picture is nice confirmation that I understand.


Yes - I think you understand.

That's the kind of thing you have to do to the texture map - but you'll still have to inset your texture coordinates by a couple of pixels from where they are right now. An inset of 0.05 would probably be enough for a texture of around 128x128 resolution. You could make it a bit less than that for larger maps maybe.

The problem is that there is no "correct" amount. If you have the eyepoint far enough back - or if the polygons are sufficiently edge-on, you'll still get some bleed. But hopefully the texture will be so "muddy" by then that you'll get away with it.

I do this kind of thing a lot because atlassed textures save the need to have separate draw calls for things with a lot of different maps - and I use shader code to switch sub-maps on the fly to make simple animations and other effects.

Keeping my UV coordinates a couple of pixels away from edge of each sub-map is good enough for most applications...perfection is overrated!

The other trick (if you can) is to try to avoid having maps that are too violently different in color/tone in the same texture...and if you can't avoid that, at least try to arrange your maps so that the most similarly colored ones are together.

Take a look at this atlas texture from my cowboy bar-fight game at http://tubagames.net for example:

http://www.tubagames.net/barfight/images/cowboy_diffuse.png

Good luck!

SteveBaker
04-05-2011, 07:57 PM
if its not Tjunctions like steve saiz, its most likely filtering
to see if thats the cause use gl.( NEAREST ) texture filtering instead of LINEAR

You're getting as confused as I was! There are two completely separate problems going on in this thread.

oak3d's problem (with his panda model) could be either Tjunctions (T-edges, whatever) or just roundoff error in the vertex math causing the polygons to not quite join up along their edges (I'm betting on the latter).

xman84's problem (with his voxel-based world) is a texture color bleed problem - which could be "solved" using gl.NEAREST texture filtering as you suggest. But the quality implications of using totally unfiltered textures in a 3D application are fairly horrifying - definitely not something I'd ever recommend!

xman84
04-05-2011, 08:06 PM
I am and have been using Nearest for mag and min filtering because I liked the look. Should I not be doing that? Lol.

SteveBaker
04-05-2011, 08:25 PM
Yeesh! I wouldn't want to play any game with NEAREST texture filtering on 3D surfaces! I'd have a blinding headache within minutes! More or less the only thing I use NEAREST for is rendering things like text that I know the exact size of - and which is rendered onto polygons that are guaranteed to be parallel to the screen.

For everything else, you get this insanely "noisy" mush out further from the camera and as things go more edge-on.

Generally:

* NEAREST - for stuff like fonts that need to be super-crisp and where you know their precise relationship to the camera. I also use them for lookup tables and other things that aren't really pictures.
* LINEAR - for really specialized shader applications...I can't think of an easily explicable example right now.
* LINEAR_MIPMAP_LINEAR - for 99% of all other 3D rendering things.
* Some hardware also supports ANISOTROPIC filtering - which is good for horizontal polygons in low eye point applications that are often close to being edge-on and which have strong near-to-far edges in them (eg the stripes painted down the center and sides of a road texture in a driving game).

On modern hardware, the LINEAR_MIPMAP_LINEAR mode is also generally the fastest because it automatically drops you down to lower resolution versions of the texture where it can - and that dramatically improves the cache availability in the GPU.

LINEAR_MIPMAP_LINEAR also looks a million times better - it's smooth and doesn't break up with moire fringing and other nastiness.

In general, set everything to LINEAR_MIPMAP_LINEAR unless you have really REALLY good technical reasons not to.

oak3d
04-05-2011, 09:38 PM
Steve,
I checked the mesh in 3dsmax and all the vertices where the artifacts appeared are perfectly shared by polygon and there's no revolution-generated thing.
And even though on chrome, I can only see artifacts in one PC, when I display the same model with chrome in other pcs, all artifacts just go out.
If you want to check out this issue, you can visit this page:
http://www.oak3d.com/?page_id=9 and the "Demo 4" is the one.

SteveBaker
04-06-2011, 04:33 PM
So did you try the experiment of clearing the screen to some other color and looking to see if the cracks are background-color?

-- Steve

oak3d
04-06-2011, 06:42 PM
Not yet. I'll let you know when I test it.

oak3d
04-07-2011, 05:09 AM
I found where the problem is.
First: the white line is the gap between neighboring polygons.
Second: the gap only appears when I disable the back face culling. If I disable the back face culling, I can see the back face of the model through the polygon gap. But when the back face culling is enabled, I can not see anything wrong(if the gap is still there then I should see the background color through the gaps).

SteveBaker
04-07-2011, 05:34 PM
I'm pretty sure you have it backwards:

If you disable back face culling then what you see through the gap is the inside of the model - which is going to be very similar in color to the front face of the model - so it disguises the gaps.

If you enable backface culling then you'll see the background color through the cracks because the "inside" of the model is being culled.

So...as I said at the start...you have gaps in your model. No mystery here!

-- Steve

oak3d
04-07-2011, 06:24 PM
No, I mean when I disable the back face culling, I can see the back face of the model through the gaps(due to the diffuse lighting, I can disguish them by the different color).
But when I enable the back face culling, I can not see the background color everywhere on the model no matter what the background color is.

oak3d
04-07-2011, 06:29 PM
I tryed using different model material color and the background color to test where the color of the gaps came from and I'm sure that the gaps only appears when back face culling is disabled.

SteveBaker
04-07-2011, 06:33 PM
OK - so if you ENABLE back face culling and clear the screen to (say) red - your artifacts disappear?

Can I see a screen shot of that?

oak3d
04-07-2011, 06:57 PM
Yes, that's right, I tried clear backround to different colors and no gap-like things can be found when back face culling is enabled. But when back face culling is disabled, you can see the gaps clearly(Indeed, I think the model may have duplicated faces with different vertex index order).
The problem only appears on one of my computer and that one is not here right now so I'll post a pair of pics to compare the difference later :).

oak3d
04-08-2011, 04:46 AM
1 Disable Back Face Culling
http://www.oak3d.com/wp-content/uploads/2011/04/1.jpg
2 Enable Back Face Culling
http://www.oak3d.com/wp-content/uploads/2011/04/2.jpg

SteveBaker
04-08-2011, 08:43 AM
I agree that it sounds like you have inside-out geometry that's Z-fighting with forward-facing geometry.

oak3d
04-10-2011, 06:30 PM
There's nothing wrong with the mesh. I think it's a platform related bug.

xman84
04-15-2011, 07:21 PM
FYI - incase anyone runs into similar issues as me. In Chrome anti-aliasing is enabled by default when the Webgl context is created. In javascript you can pass options to disable it. That fixed the texture bleeding issues I had.

SteveBaker
04-15-2011, 09:58 PM
I guarantee it didn't "fix" anything - you still have an underlying problem - you're just covering it up. I'm sure it'll show up again in some other way, even with antialiassing turned off.

WebGL (and the browser itself) have nothing whatever to do with the technicalities of how the pixels are drawn - that's only a matter of how the hardware and the underlying Direct3D or OpenGL driver works. If this were really a bug then it would be incredibly obvious in almost all PC-based games and it would have been fixed long ago.

-- Steve