GLSL Shader - Shadow between 2 textures on a plane

我是研究僧i 提交于 2020-01-05 10:36:17

问题


I'm writting a game with AGK (App Game Kit) and I wanted to make some shadows with shaders. (AGK only support GLSL 1.20 at the moment)

On my game, I have a plane object, where I have 2 textures. The first texture is the background texture, and the second, is the foreground texture, with a transparent path where we see the background texture (they are like the walls) and I have a pointer light.

Here is an example (left is what I have, right is what I want) :

And here is the code :

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 :

uniform sampler2D texture0;
uniform sampler2D texture1;

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

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 color = agk_PLightColor.rgb * intensity * atten;

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

So, i put the first texture, calculate the light, then I check the secondtexture, if the fragment is transparent, I put the background texture and the light, if it's not transparent, i just put the second texture.

So, the code does the left example of the image, and I wanted to know, if it's possible to calculate the light so it stop if it goes through a non-transparent fragment of the second texture ? So it does like the right example of the image.

I searched a lot and I only found examples of shadows with shaders with 3D objects, how to create a shadow map etc... but can you calculate this between 2 textures on the same object ?


回答1:


I would go for the following idea: for each pixel in the range of your light yo will want to do a trace to the light origin and test if there is no black pixel on the path. It will look more or less like that:

bool inTheShadow = false;
//Check if you're in the light range
if (intensity>0){
  vec2 delta = dir.xy / numSamples; //You can either use constant number of samples, or base it on the distance to the light source
  vec2 currentPointer = vec2(posVarying.x,posVarying.y);
  for (int i=0; i<numSamples ; i++){
    xxx //Calculate uv for currentPointer
    if(texture2D(texture0, YOUR_NEW_UV).a > 0){
      inTheShadow = true;
      break;
    }
    currentPointer += delta;
  }
}

It should do the trick. You only need to calculate YOUR_NEW_UV in the line marked with "xxx". I hope that you understand this idea. You basically need to test visible UVs between the current pixel and the light origin and check if the wall texture is enpty along the whole way.



来源:https://stackoverflow.com/questions/24313286/glsl-shader-shadow-between-2-textures-on-a-plane

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!