Dash100555
Dash100555

Reputation: 15

OpenGL, Texture is outputting as a solid color

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://i.sstatic.net/kPfWt.jpg

Upvotes: 0

Views: 280

Answers (1)

Indiana Kernick
Indiana Kernick

Reputation: 5341

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.

Upvotes: 1

Related Questions