Max Leroux
Max Leroux

Reputation: 131

GLSL Check texture alpha between 2 vectors

I'm trying to learn how to make shaders, and a little while ago, I posted a question here : GLSL Shader - Shadow between 2 textures on a plane

So, the answer gave me the right direction to take, but I have some trouble for checking if there is a fragment that is not transparent between the current fragment and the light position.

So here is the code :

Vertex Shader :

attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;

varying vec2 uvVarying;
varying vec3 normalVarying;
varying vec3 posVarying;

uniform vec4 uvBounds0;

uniform mat4 agk_World;
uniform mat4 agk_ViewProj;
uniform mat3 agk_WorldNormal;

void main()
{
    vec4 pos = agk_World * vec4(position,1);
    gl_Position = agk_ViewProj * pos;
    vec3 norm = agk_WorldNormal * normal;
    posVarying = pos.xyz;
    normalVarying = norm;
    uvVarying = uv * uvBounds0.xy + uvBounds0.zw;
}

And the fragment shader :

#ifdef GL_ES
   #ifdef GL_FRAGMENT_PRECISION_HIGH   
      precision highp float;
   #else
      precision mediump float;
   #endif
#endif

uniform sampler2D texture0;
uniform sampler2D texture1;

varying vec2 uvVarying;
varying vec3 normalVarying;
varying vec3 posVarying;

uniform vec4 uvBounds0;
uniform vec2 playerPos;
uniform vec2 agk_resolution;
uniform vec4 agk_PLightPos;
uniform vec4 agk_PLightColor;
uniform vec4 agk_ObjColor;

void main (void)
{
    vec4 lightPos = agk_PLightPos;
    lightPos.x = playerPos.x;
    lightPos.y = -playerPos.y;

    vec3 dir = vec3(lightPos.x - posVarying.x, lightPos.y - posVarying.y, lightPos.z - posVarying.z);
    vec3 norm = normalize(normalVarying);
    float atten = dot(dir,dir);
    atten = clamp(lightPos.w/atten,0.0,1.0);
    float intensity = dot(normalize(dir),norm);
    intensity = clamp(intensity,0.0,1.0);
    vec3 lightColor = agk_PLightColor.rgb * intensity * atten;
    vec3 shadowColor = agk_PLightColor.rgb * 0;

    bool inTheShadow = false;

    if (intensity * atten > 0.05) {
        float distanceToLight = length(posVarying.xy - lightPos.xy);

        for (float i = distanceToLight; i > 0.0; i -= 0.1) {

            vec2 uvShadow = ???

            if (texture2D(texture0, uvShadow).a > 0) {
                inTheShadow = true;

                break;
            }
        }
    }

    if (texture2D(texture0, uvVarying).a == 0) {
        if (inTheShadow == true) {
            gl_FragColor = texture2D(texture1, uvVarying) * vec4(shadowColor, 1) * agk_ObjColor;
        }
        else {
            gl_FragColor = texture2D(texture1, uvVarying) * vec4(lightColor, 1) * agk_ObjColor;
        }
    }
    else {
        gl_FragColor = texture2D(texture0, uvVarying) * agk_ObjColor;
    }
}

So, this is the part where I have some troubles :

bool inTheShadow = false;

    if (intensity * atten > 0.05) {
        float distanceToLight = length(posVarying.xy - lightPos.xy);

        for (float i = distanceToLight; i > 0.0; i -= 0.1) {

            vec2 uvShadow = ???

            if (texture2D(texture0, uvShadow).a > 0) {
                inTheShadow = true;

                break;
            }
        }
    }

I first check if I'm in the light radius with intensity * atten > 0.05

Then I get the distance from the current fragment to the light position.

And then, I make a for loop, to check each fragment between the current fragment and the light position. I tried some calculations to get the current fragment, but with no success.

So, any idea on how I can calculate the uvShadow in my loop ?

I hope I'm using the good variables too, cause in the last part of my code, where I use gl_FragColor, I'm using uvVarying to get the current fragment (If i'm not mistaken), but to get the light distance, I had to calculate the length between posVarying and lightPos and not between uvVarying and lightPos (I made a test, where the further I was from the light, the more red it became, and with posVarying, it made me a circle with gradient around my player (lightPos) but when I used uvVarying, the circle was only one color, and it was more or less red, when I was approaching my player to the center of the screen).

Thanks and best regards,

Max

Upvotes: 0

Views: 464

Answers (1)

ashleysmithgpu
ashleysmithgpu

Reputation: 1935

When you access a texture through texture2D() you use normalised coordinates. I.e. numbers that go from (0.0, 0.0) to (1.0, 1.0). So you need to convert your world positions to this normalised space. So something like:

vec2 uvShadow = posVarying.xy + ((distanceToLight / 0.1) * i * (posVarying.xy - lightPos.xy));
// Take uvShadow from world space to view space, this is -1.0 to 1.0
uvShadow *= mat2(inverse(agk_View)); // This could be optimized if you are using orthographic projection
// Now take it to texture space
uvShadow += 0.5;
uvShadow *= 0.5;

Upvotes: 1

Related Questions