我正在用AGK(App Game Kit)编写游戏,我想用着色器制作一些阴影。 (目前AGK仅支持GLSL 1.20)
在我的游戏中,我有一个平面物体,我有2个纹理。第一个纹理是背景纹理,第二个纹理是前景纹理,透明路径我们看到背景纹理(它们就像墙壁),我有一个指针灯。
这是一个例子(左边是我的,右边是我想要的):
以下是代码:
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个纹理之间进行计算吗?
答案 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,并检查墙面纹理是否在整个过程中都是一样的。