Question

I'm having a terrible time figuring out a way to better-handle the seams between 3D tile objects in my game engine. You only see them when the camera is tilted down at a far enough angle like this... I do not believe it is a texture problem or a texture rendering problem (but I could be wrong).

Below are two screenshots - the first one demonstrates the problem, while the second is the UV wrapping I'm using for the tiles in Blender. I'm providing room in the UVs for overlap, such that if the texture needs to overdraw during smaller mip-maps, I should still be good. I am loading textures with the following texture params:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

It appears to me that the sides of the 3D tiles are slightly being drawn, and you especially notice the artifact due to the lighting angle (directional) that is being applied from this angle.

Are there any tricks or things I can check to eliminate this effect? I am rendering in "layers", but within those layers based on camera distance (furthest away first). All of these objects are in the same layer. Any ideas would be greatly appreciated!

If useful, this is a project for iPhone/iPad using OpenGLES2.0. I'm happy to provide any code snippets - just let me know what might be a good place to start.

Screenshot from engine demonstrating seams between tiles at low angles

UVs from Blender

UPDATE WITH VERTEX/PIXEL SHADER & MODEL VERTICES

Presently, I am using PowerVR's POD format to store model data exported from Blender (via Collada then Collada2Pod converter by PowerVR). Here's the GL_SHORT vertex coords (model space):

64 -64 32
64 64 32
-64 64 32
-64 -64 32
64 -64 -32
-64 -64 -32
-64 64 -32
64 64 -32
64 -64 32
64 -64 -32
64 64 -32
64 64 32
64 64 32
64 64 -32
-64 64 -32
-64 64 32
-64 64 32
-64 64 -32
-64 -64 -32
-64 -64 32
64 -64 -32
64 -64 32
-64 -64 32
-64 -64 -32

So everything should be perfectly flush, I would expect. Here's the shaders:

attribute highp vec3  inVertex; 
attribute highp vec3  inNormal;
attribute highp vec2  inTexCoord;

uniform highp mat4  ProjectionMatrix;
uniform highp mat4  ModelviewMatrix;
uniform highp mat3  ModelviewITMatrix;
uniform highp vec3  LightColor;
uniform highp vec3  LightPosition1;
uniform highp float LightStrength1;
uniform highp float LightStrength2;
uniform highp vec3  LightPosition2;
uniform highp float Shininess;

varying mediump vec2  TexCoord;
varying lowp    vec3  DiffuseLight;
varying lowp    vec3  SpecularLight;

void main()
{
    // transform normal to eye space
    highp vec3 normal = normalize(ModelviewITMatrix * inNormal);

    // transform vertex position to eye space
    highp vec3 ecPosition = vec3(ModelviewMatrix * vec4(inVertex, 1.0));

    // initalize light intensity varyings
    DiffuseLight = vec3(0.0);
    SpecularLight = vec3(0.0);

    // Run the directional light
    PointLight(true, normal, LightPosition1, ecPosition, LightStrength1);
    PointLight(true, normal, LightPosition2, ecPosition, LightStrength2);

    // Transform position
    gl_Position = ProjectionMatrix * ModelviewMatrix * vec4(inVertex, 1.0);

    // Pass through texcoords and filter
    TexCoord = inTexCoord;
}      
Was it helpful?

Solution

I do not know how your boxes are drawn - but I believe this is the issue. When computing the vertices for each box I guess you do something like this (pseudocode)

int i,j,k;
float widht

for i,j,k in dims: 
  upper_left = (i,j,k)*width;
  upper_right = (upper_left.x+width,upper_left.y,upper_left.z);
  lower_left = (upper_left.x, upper_left.y+width,upper_left.z);
  lower_right = (upper_left.x+width,upper_left.y+width,upper_left.z);

This will fail because you lose precision when adding, so corners that should share the same position actually do not. This is what is creating the gaps.

instead you should do something like this

for i,j,k: 
  upper_left = (i,j,k)*width;
  upper_right = (i+1,j,k)*width;
  lower_left = (i,j+1,k)*width;
  lower_right = (i+1,j+1,k)*width;

This will ensure that the corners will use the same coordinates.

EDIT

It is still a precision problem. From what I understand, you are doing a drawcall per block, where the only thing that changes per block is the ModelviewMatrix. This means that you are expecting that this line

position = ProjectionMatrix * ModelviewMatrix * vec4(inVertex, 1.0);

will give the same value for two different values of inVertex and ModelviewMatrix, which is wrong.

To solve this you can do "fake" instancing (since ES do not support instancing), by saving the per-instance values in uniforms and compute the per-attribute values from an index given in an attribute.

Edit 2:

Ok, please do not think about "fake" instancing for now. Now, please just ensure that the coordinates are the same. So instead of providing coordinates for only one block, provide them for all the blocks instead, and use only one ModelViewMatrix. That will probably be faster as well.

OTHER TIPS

try these

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top