0
votes

Im trying to texture my terrain but it seems to be either taking the average color of the texture of just picking one color from the texture and using it everywhere. I have looked at other solutions but they havent help me. I am new so it could be a simple mistake

The textures are generated from SOIL2

Generates Texture

int texID = SOIL_load_OGL_texture(
    filename.c_str(),
    SOIL_LOAD_AUTO,
    SOIL_CREATE_NEW_ID,
    SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT
    );

Generates UV coordinates (removed the not important stuff for my question)

int i=0;
for (int z = 0; z < m_Size; z++) // loop through columns
{
    for (int x = 0; x < m_Size; x++) // loop through rows
    {
        model.mesh.uvs[i] = Math::Vector2(x / m_Size, z / m_Size); //Terrain is square
        i++;
    }

}

Creates Texture buffer

if (model->mesh.numOfUVs != 0)
{
    glGenBuffers(1, &model->textureBufferID);
    glBindBuffer(GL_ARRAY_BUFFER, model->textureBufferID);
    glBufferData(GL_ARRAY_BUFFER, model->mesh.numOfUVs * sizeof(Math::Vector2), model->mesh.uvs, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Math::Vector2), (void*)(0));     
}

Drawing the terrain (not full code)

            glBindVertexArray(ID);

            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, model->textureID1);
            unsigned int textureLocation = glGetUniformLocation(shaderID, "grassTex");
            glUniform1i(textureLocation, 0);

            glUniformMatrix4fv(glGetUniformLocation(shaderID, "MVP"), 1, false, &newMVP.mat[0][0]);

            glDrawElements(GL_TRIANGLES, model->mesh.numOfIndices, GL_UNSIGNED_INT, (void*)0);


            glBindVertexArray(0);

Vert Shader

#version 330 core

layout(location = 0) in vec2 texturecoord;

uniform mat4 MVP;

out vec2 texcoord;

void main(){
    texcoord = texturecoord;
    gl_Position = MVP * vec4(in_position, 1);
}

Frag Shader

#version 330 core

layout(location = 0) out vec4 out_colour;

in vec2 texcoord;
uniform sampler2D grassTex;

void main()
{
    out_colour = texture2D(grassTex, texcoord);
}

If something doesnt make sense it might be because i have removed a lot of code to try reduce how much code i post

what it looks like(theres 3 textures in the pic but i have removed the code in this post as i dont think it has anything to do with the number of textures im using) https://imgur.com/a/rSPp7Ru

1
Can you show the declaration of m_Size? - Indiana Kernick
All it is the width of the terrain ( terrain is also square ) in this case it is 1024 - Dash100555
Is m_Size an int? - Indiana Kernick
Yeh it is a int - Dash100555

1 Answers

1
votes

The problem is integer division. When you divide integers, you get an integer. This is where you're generating UV coordinates.

for (int z = 0; z < m_Size; z++) // loop through columns
{
    for (int x = 0; x < m_Size; x++) // loop through rows
    {
        model.mesh.uvs[i] = Math::Vector2(x / m_Size, z / m_Size); //Terrain is square
        i++;
    }
}

x and z are always smaller than m_Size. This means that x / m_Size and z / m_Size are always 0 because you can't store 0.2 in an int. Since all of your UV coordinates are 0, 0, you're just seeing one corner (I think it's bottom-left) of the texture across the whole triangle.

To solve this, cast one of the operands to a float or double.

model.mesh.uvs[i] = Math::Vector2(
  static_cast<float>(x) / m_Size, 
  static_cast<float>(z) / m_Size
);

If you divide a float by an int, the int is promoted to a float so float division will be performed.