我试图学习如何制作着色器,不久之前,我在这里发了一个问题:GLSL Shader - Shadow between 2 textures on a plane
所以,答案给了我正确的方向,但我在检查当前片段和灯光位置之间是否存在不透明的片段时遇到了一些麻烦。
所以这是代码:
顶点着色器:
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;
}
片段着色器:
#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;
}
}
所以,这是我遇到麻烦的部分:
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;
}
}
}
我首先检查我是否在光线半径内有强度*注意> 0.05
然后我得到当前片段到光照位置的距离。
然后,我制作一个for循环,检查当前片段和灯光位置之间的每个片段。我尝试了一些计算来获取当前片段,但没有成功。
那么,关于我如何在循环中计算uvShadow的任何想法?
我希望我也使用好的变量,导致我的代码的最后一部分,我使用gl_FragColor,我使用uvVarying来获取当前片段(如果我不是但是为了获得光照距离,我必须计算posVarying和lightPos之间的长度,而不是uvVarying和lightPos之间的长度(我做了一个测试,我从光线越远,它变得越红,并且使用posVarying它让我在我的播放器(lightPos)周围有一个渐变的圆圈,但是当我使用uvVarying时,圆圈只有一种颜色,当我接近我的播放器到屏幕中心时,它或多或少是红色的。) / p>
谢谢和最诚挚的问候,
最高
答案 0 :(得分:1)
通过texture2D()
访问纹理时,使用标准化坐标。即数字从(0.0,0.0)到(1.0,1.0)。因此,您需要将世界位置转换为此标准化空间。如下所示:
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;