Search code examples
c++opengltexturesfragment-shadertexture2d

How can I texture with vertex position coordinates? openGL,c++


I want to texture my terrain without predetermined texture coordinates. I want to determine the coordinates in the vertex or fragmant shader using vertex position coordinates. I now use position 'xz' coordinates (up=(0,1,0)), but if I have a for example wall which is 90 degrees with the ground the texture will be like this:

enter image description here

How can I transform this position these coordinates to work well?

Here's my vertex shader:

#version 430

in layout(location=0) vec3 position;
in layout(location=1) vec2 textCoord;
in layout(location=2) vec3 normal;

out vec3 pos;
out vec2 text;
out vec3 norm;


uniform mat4 transformation;

void main()
{   
    gl_Position = transformation * vec4(position, 1.0);
    norm = normal;
    pos = position;
    text = position.xz;

}

And here's my fragmant shader:

#version 430

in vec3 pos;
in vec2 text;
in vec3 norm;

//uniform sampler2D textures[3];

layout(binding=3) uniform sampler2D texture_1;
layout(binding=4) uniform sampler2D texture_2;
layout(binding=5) uniform sampler2D texture_3;

vec3 lightPosition = vec3(-200, 700, 50);
vec3 lightAmbient = vec3(0,0,0);
vec3 lightDiffuse = vec3(1,1,1);
vec3 lightSpecular = vec3(1,1,1);

out vec4 fragColor;
vec4 theColor;



void main()
{
    vec3 unNormPos = pos;
    vec3 lightVector = normalize(lightPosition) - normalize(pos);
    //lightVector = normalize(lightVector);

    float cosTheta = clamp(dot(normalize(lightVector), normalize(norm)), 0.5, 1.0);

    if(pos.y <= 120){
        fragColor = texture2D(texture_2, text*0.05) * cosTheta;
    }
    if(pos.y > 120 && pos.y  <  150){
        fragColor = (texture2D(texture_2, text*0.05) * (1 - (pos.y-120)/29) +  texture2D(texture_3, text*0.05) * ((pos.y-120)/29))*cosTheta;
    }
    if(pos.y >= 150)
    {
        fragColor = texture2D(texture_3, text*0.05) * cosTheta;
    }   
}

EDIT: (Fons)

text = 0.05 * (position.xz + vec2(0,position.y)); 

enter image description here

text = 0.05 * (position.xz + vec2(position.y,position.y)); 

Now the wall work but terrain not. enter image description here


Solution

  • The problem is actually a very difficult one, since you cannot devise a formula for the texture coordinates that displays vertical walls correctly, using only the xyz coordinates.

    To visualize this, imagine a hill next to a piece of flat land. Since the path going over the hill is longer than that going over the flat piece of land, the texture should wrap more times on the hill the on the flat piece of land. In the image below, the texture wraps 5 times on the hill and 4 times on the flat piece.

    Hill visualization

    If the texture coordinates are (0,0) on the left, should they be (4,0) or (5,0) on the right? Since both answers are valid, this proves that there is no function that calculates correct texture coordinates based purely on the xyz coordinates. :(

    However, your problems might be solved with different methods:

    • The walls can be corrected by generating them independently from the terrain, and assigning correct texture coordinates to them. It actually makes more sense not to incorporate those in your terrain.
    • You can add more detail to the sides of steep hills with normal maps, textures of higher resolution, or a combination of different textures. There might be a better solution that I don't know about.

    Edit: Triplanar mapping will solve your problem!