GLSL着色器 - 平面上2个纹理之间的阴影

时间:2014-06-19 17:55:19

标签: opengl textures glsl shadow plane

我正在用AGK(App Game Kit)编写游戏,我想用着色器制作一些阴影。 (目前AGK仅支持GLSL 1.20)

在我的游戏中,我有一个平面物体,我有2个纹理。第一个纹理是背景纹理,第二个纹理是前景纹理,透明路径我们看到背景纹理(它们就像墙壁),我有一个指针灯。

这是一个例子(左边是我的,右边是我想要的):

example

以下是代码:

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;
}

并且:

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;
    }
}

所以,我把第一个纹理,计算光,然后我检查第二个纹理,如果片段是透明的,我把背景纹理和光,如果它不透明,我只是把第二个质地。

因此,代码执行图像的左侧示例,我想知道,如果它可以计算光线,那么它是否会通过第二个纹理的非透明片段停止?所以它确实像图像的正确例子。

我搜索了很多,我只找到了带有3D对象着色器的阴影示例,如何创建阴影贴图等...但是你可以在同一个对象的2个纹理之间进行计算吗?

1 个答案:

答案 0 :(得分:2)

我会考虑以下想法:对于光线范围内的每个像素,您需要对光源进行跟踪并测试路径上是否没有黑色像素。看起来或多或少会像这样:

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;
  }
}

它应该做的伎俩。您只需要在标有“xxx”的行中计算YOUR_NEW_UV。我希望你理解这个想法。您基本上需要测试当前像素和光源之间的可见UV,并检查墙面纹理是否在整个过程中都是一样的。