1
votes

As a side project I've had for a while now I've been trying to create some Voxel terrain. However, to my dismay the textures seems to not be working properly. I'm mapping the texture with GL_REPEAT and GL_NEAREST. The texture is found in a sprite sheet and is 16x16. I'm currently using the minecraft textures for debugging. I've tried fixing it by moving the texture 1 texel in but this didn't work either.

enter image description here

Here is the code that handles it:

void Chunk::CreateCube(int x, int y, int z, bool activeStates[], int ID)
{

        double TEXTURE_SIZE = 256;
        glm::vec3 p1(x-BLOCK_RENDER_SIZE, y-BLOCK_RENDER_SIZE, z+BLOCK_RENDER_SIZE); //left bottom  front
        glm::vec2 t1(0.5/TEXTURE_SIZE, 0.5/TEXTURE_SIZE);
        glm::vec3 p2(x+BLOCK_RENDER_SIZE, y-BLOCK_RENDER_SIZE, z+BLOCK_RENDER_SIZE); //right bottom front
        glm::vec2 t2(1-(0.5/TEXTURE_SIZE), 0.5/TEXTURE_SIZE);
        glm::vec3 p3(x+BLOCK_RENDER_SIZE, y+BLOCK_RENDER_SIZE, z+BLOCK_RENDER_SIZE); // right top front
        glm::vec2 t3(1-(0.5/TEXTURE_SIZE), 1-(0.5/TEXTURE_SIZE));
        glm::vec3 p4(x-BLOCK_RENDER_SIZE, y+BLOCK_RENDER_SIZE, z+BLOCK_RENDER_SIZE); // left top front
        glm::vec2 t4(0.5/TEXTURE_SIZE, 1-(0.5/TEXTURE_SIZE));
        glm::vec3 p5(x+BLOCK_RENDER_SIZE, y-BLOCK_RENDER_SIZE, z-BLOCK_RENDER_SIZE); // right bottom back
        glm::vec2 t5(0.5/TEXTURE_SIZE, 0.5/TEXTURE_SIZE);
        glm::vec3 p6(x-BLOCK_RENDER_SIZE, y-BLOCK_RENDER_SIZE, z-BLOCK_RENDER_SIZE); // left bottom back
        glm::vec2 t6(1-(0.5/TEXTURE_SIZE), 0.5/TEXTURE_SIZE);
        glm::vec3 p7(x-BLOCK_RENDER_SIZE, y+BLOCK_RENDER_SIZE, z-BLOCK_RENDER_SIZE); // left top back
        glm::vec2 t7(1-(0.5/TEXTURE_SIZE), 1-(0.5/TEXTURE_SIZE));
        glm::vec3 p8(x+BLOCK_RENDER_SIZE, y+BLOCK_RENDER_SIZE, z-BLOCK_RENDER_SIZE); // right top back
        glm::vec2 t8(0.5/TEXTURE_SIZE, 1-(0.5/TEXTURE_SIZE));

        int numCols = 16;
        int numRows = 16;

        double u = ((double)(ID % numCols) / (double)numCols);
        double v = ((double)(ID / numRows) / (double)numRows);
        double TILE_TEXTURE_SIZE = 16;

        glm::vec3 n1;


        if(activeStates[5] == false)
        {
                // Front Face Normal
                n1 = glm::vec3(0.0f, 0.0f, 1.0f);
                //Triangle 1
                vertexData.push_back(p1);
                uvData.push_back(glm::vec2(t1.x/TILE_TEXTURE_SIZE + u, t1.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p2);
                uvData.push_back(glm::vec2(t2.x/TILE_TEXTURE_SIZE + u, t2.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p3);
                uvData.push_back(glm::vec2(t3.x/TILE_TEXTURE_SIZE + u, t3.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);
                //Triangle 2
                vertexData.push_back(p1);
                uvData.push_back(glm::vec2(t1.x/TILE_TEXTURE_SIZE + u, t1.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p3);
                uvData.push_back(glm::vec2(t3.x/TILE_TEXTURE_SIZE + u, t3.y/TILE_TEXTURE_SIZE + v ));
                normalData.push_back(n1);

                vertexData.push_back(p4);
                uvData.push_back(glm::vec2(t4.x/TILE_TEXTURE_SIZE + u, t4.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);
        }

        if(activeStates[4] == false)
        {
                // Back
                n1 = glm::vec3(0.0f, 0.0f, -1.0f);
                //Triangle 1
                vertexData.push_back(p5);
                uvData.push_back(glm::vec2(t5.x/TILE_TEXTURE_SIZE + u, t5.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p6);
                uvData.push_back(glm::vec2(t6.x/TILE_TEXTURE_SIZE + u, t6.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p7);
                uvData.push_back(glm::vec2(t7.x/TILE_TEXTURE_SIZE + u, t7.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);
                //Triangle 2
                vertexData.push_back(p5);
                uvData.push_back(glm::vec2(t5.x/TILE_TEXTURE_SIZE + u, t5.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p7);
                uvData.push_back(glm::vec2(t7.x/TILE_TEXTURE_SIZE + u, t7.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p8);
                uvData.push_back(glm::vec2(t8.x/TILE_TEXTURE_SIZE + u, t8.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);
        }
        if(activeStates[1] == false)
        {
                // Right
                n1 = glm::vec3(1.0f, 0.0f, 0.0f);
                //Triangle 1
                vertexData.push_back(p2);
                uvData.push_back(glm::vec2(t2.x/TILE_TEXTURE_SIZE + u, t2.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p5);
                uvData.push_back(glm::vec2(t5.x/TILE_TEXTURE_SIZE + u, t5.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p8);
                uvData.push_back(glm::vec2(t8.x/TILE_TEXTURE_SIZE + u, t8.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);
                //Triangle 2
                vertexData.push_back(p2);
                uvData.push_back(glm::vec2(t2.x/TILE_TEXTURE_SIZE + u, t2.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p8);
                uvData.push_back(glm::vec2(t8.x/TILE_TEXTURE_SIZE + u, t8.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p3);
                uvData.push_back(glm::vec2(t3.x/TILE_TEXTURE_SIZE + u, t3.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);
        }
        if(activeStates[0] == false)
        {
                // left
                n1 = glm::vec3(-1.0f, 0.0f, 0.0f);
                //Triangle 1
                vertexData.push_back(p6);
                uvData.push_back(glm::vec2(t6.x/TILE_TEXTURE_SIZE + u, t6.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p1);
                uvData.push_back(glm::vec2(t1.x/TILE_TEXTURE_SIZE + u, t1.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p4);
                uvData.push_back(glm::vec2(t4.x/TILE_TEXTURE_SIZE + u, t4.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);
                //Triangle 2
                vertexData.push_back(p6);
                uvData.push_back(glm::vec2(t6.x/TILE_TEXTURE_SIZE + u, t6.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p4);
                uvData.push_back(glm::vec2(t4.x/TILE_TEXTURE_SIZE + u, t4.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p7);
                uvData.push_back(glm::vec2(t7.x/TILE_TEXTURE_SIZE + u, t7.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);
        }
        if(activeStates[3] == false)
        {
                // Top
                n1 = glm::vec3(0.0f, 1.0f, 0.0f);
                //Triangle 1
                vertexData.push_back(p4);
                uvData.push_back(glm::vec2(t6.x/TILE_TEXTURE_SIZE + u, t6.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p3);
                uvData.push_back(glm::vec2(t1.x/TILE_TEXTURE_SIZE + u, t1.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p8);
                uvData.push_back(glm::vec2(t4.x/TILE_TEXTURE_SIZE + u, t4.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);
                //Triangle 2
                vertexData.push_back(p4);
                uvData.push_back(glm::vec2(t6.x/TILE_TEXTURE_SIZE + u, t6.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p8);
                uvData.push_back(glm::vec2(t4.x/TILE_TEXTURE_SIZE + u, t4.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p7);
                uvData.push_back(glm::vec2(t7.x/TILE_TEXTURE_SIZE + u, t7.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);
        }

        if(activeStates[2] == false)
        {
                // Bottom
                n1 = glm::vec3(0.0f, -1.0f, 0.0f);

                //Triangle 1
                vertexData.push_back(p6);
                uvData.push_back(glm::vec2(t6.x/TILE_TEXTURE_SIZE + u, t6.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p5);
                uvData.push_back(glm::vec2(t1.x/TILE_TEXTURE_SIZE + u, t1.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p2);
                uvData.push_back(glm::vec2(t4.x/TILE_TEXTURE_SIZE + u, t4.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);
                //Triangle 2
                vertexData.push_back(p6);
                uvData.push_back(glm::vec2(t6.x/TILE_TEXTURE_SIZE + u, t6.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p2);
                uvData.push_back(glm::vec2(t4.x/TILE_TEXTURE_SIZE + u, t4.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);

                vertexData.push_back(p1);
                uvData.push_back(glm::vec2(t7.x/TILE_TEXTURE_SIZE + u, t7.y/TILE_TEXTURE_SIZE + v));
                normalData.push_back(n1);
        }

        /*glm::vec2 t1(0.5/256, 0.5/256);

        glm::vec2 t2(1-(0.5/256), 0.5/256);

        glm::vec2 t3(1-(0.5/256), 1-(0.5/256));

        glm::vec2 t4(0.5/256, 1-(0.5/256));

        glm::vec2 t5(0.5/256, 0.5/256);

        glm::vec2 t6(1-(0.5/256), 0.5/256);

        glm::vec2 t7(1-(0.5/256), 1-(0.5/256));

        glm::vec2 t8(0.5/256, 1-(0.5/256));
        */

        /*
        for(int i = 0; i < vertexData.size(); i+=3)
        {

        // get the three vertices that make the faces
        glm::vec3 p1 = vertexData[i+0];
        glm::vec3 p2 = vertexData[i+1];
        glm::vec3 p3 = vertexData[i+2];

        glm::vec3 v1 = p2 - p1;
        glm::vec3 v2 = p3 - p1;
        glm::vec3 normal = glm::cross( v1,v2 );

        normal = glm::normalize(normal);

        normalData[i+0] = normal;
        normalData[i+1] = normal;
        normalData[i+2] = normal;

        }
        */
}



GLuint Graphics3D::loadTexture(const char* theFileName)
{
        ILuint imageID;                

        GLuint textureID;              

        ILboolean success;

        ILenum error;                          

        ilGenImages(1, &imageID);      

        ilBindImage(imageID);          

        success = ilLoadImage(theFileName);

        if (success)
        {

                ILinfo ImageInfo;
                iluGetImageInfo(&ImageInfo);
                if (ImageInfo.Origin == IL_ORIGIN_UPPER_LEFT)
                {
        //              iluFlipImage();
                }

                success = ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE);


                if (!success)
                {
                        error = ilGetError();
                        std::cout << "Image conversion failed - IL reports error: " << error << " - " << iluErrorString(error) << std::endl;
                }


                glGenTextures(1, &textureID);

        glBindTexture(GL_TEXTURE_2D, textureID);


                glTexImage2D(GL_TEXTURE_2D,                             // Type of texture
                        0,                              // Pyramid level (for mip-mapping) - 0 is the top level
                        ilGetInteger(IL_IMAGE_BPP),     // Image colour depth
                        ilGetInteger(IL_IMAGE_WIDTH),   // Image width
                        ilGetInteger(IL_IMAGE_HEIGHT),  // Image height
                        0,                              // Border width in pixels (can either be 1 or 0)
                        ilGetInteger(IL_IMAGE_FORMAT),  // Image format (i.e. RGB, RGBA, BGR etc.)
                        GL_UNSIGNED_BYTE,               // Image data type
                        ilGetData());                   // The actual image data itself
                /*
                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_MAG_FILTER, GL_LINEAR);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
                */

        //      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_WRAP_S, GL_REPEAT);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

                if(GLEW_EXT_texture_filter_anisotropic)
                {

                        GLfloat maximumAnisotropy;
                        //get the value
                        glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maximumAnisotropy);
                        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maximumAnisotropy);
                }

                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
        //      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        //      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
                glGenerateMipmap(GL_TEXTURE_2D);


        }
        else
        {
                error = ilGetError();
                std::cout << "Image load failed - IL reports error: " << error << " - " << iluErrorString(error) << std::endl;

        }

        ilDeleteImages(1, &imageID);

        std::cout << "Texture creation successful." << std::endl;

        return textureID;

}

It seems the further away I am the more visible the lines are. So I tried removing mipmaps. This didn't help either. I'm at a loss on how to deal with this. Any ideas? This is the texture: enter image description here

2
Edit that code into the question. Pastebins die, SO doesn't. - genpfault
And try to narrow your problem down. Having us look through 345 lines of code is not ideal. - Bart
While we're at it, show the texture you're using. - Bahbar
You'll certainly have to be very careful with the texture coordinates to correctly map sub-textures. Your UV generation looks pretty suspect to me - adding half-pixel offsets, then dividing by the tile-size (which just happens to be the square-root of the texture size, or I suspect it wouldn't work) and the tile-UV generation is wrong too, but again happens to work because the tile-map is square. Might not be the actual issue here, but I'd fix the UVs first. - JasonD

2 Answers

0
votes

This is almost certainly down to having some form of filtering enabled.

I note that you're turning on anisotropic filtering. Even without mip-mapping, this will cause pixels outside of your sub-texture to be fetched, causing artefacts like you are seeing here.

You really need to turn that off, as well as getting rid of the mip-mapping.

Also, I think your UV generation is off, and contains some errors. Those probably aren't the issue here, but I'd recommend fixing them.

For example, here you add half a texel:

glm::vec2 t1(0.5/TEXTURE_SIZE, 0.5/TEXTURE_SIZE);

However this is later scaled down, so actually you're only offsetting by a small amount. It's probably unnecessary anyway (why do you think you need to do this at all?), but it's almost certainly not doing what you think its doing. A very small offset might be a good idea to prevent any rounding errors slipping the fetched texel into the next sub-texture, but only a tiny amount.

Then you do this:

double u = ((double)(ID % numCols) / (double)numCols);
double v = ((double)(ID / numRows) / (double)numRows);

You should be using the same value to both divide and modulo ID. It only works because you have the same number of rows and columns.

Finally you calculate the UVs like this:

t1.x/TILE_TEXTURE_SIZE + u

Dividing by the tile size is wrong. It should be * TILE_SIZE / TEXTURE_SIZE. Fortunately for you this happens to be the same (256 / 16 = 16). If you have different sized textures, it wouldn't work.

0
votes

Your basic problem is that you have several images tiled into one large texture. This will cause a problem with any sort of texture filtering such as mipmapping and anisotropic filtering. You DO NOT want to disable texture filtering. Instead, you should have each image be treated logically as a different image. An easy way to do this is to make each tile a separate texture. That is a bit slow, so for better performance you should instead use an Array Texture.