我已经通过LearnOpengl实现了视差遮挡贴图,现在我想添加自阴影,以便碎片挤出在表面上留下阴影。我已经阅读了一些有关该主题的论文,但是我承认这对我来说有点先进。据我了解,这与视差遮挡贴图的过程相同,但是从灯光的方向而不是视图的方向来看。我尝试修改片段着色器,但阴影仍然不显示。
这就是我想要的样子。 http://www.cs.utah.edu/~sujin/courses/reports/cs6610/project-report/images/pom.png
这是修改后的片段着色器的结果。只是视差遮挡图什么都没有改变。
这是修改后的片段着色器。我已经标记了我添加到原始视差教程代码中的部分。
#version 330 core
in vec2 o_texCoord;
in vec3 o_worldPos;
in vec3 world_normal;
in vec3 world_tangent;
out vec4 fragColor;
uniform vec3 light_pos;
uniform sampler2D diffuseMap;
uniform sampler2D normalMap;
uniform sampler2D heightMap;
uniform vec3 viewPosition;
uniform float heightScale;
vec2 ParallaxMapping (vec2 texCoord, vec3 viewDir)
{
float minLayers = 0;
float maxLayers = 32;
float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), viewDir)));
float layerDepth = 1.0 / numLayers;
float currentLayerDepth = 0;
vec2 P = viewDir.xy / viewDir.z * heightScale;
vec2 deltaTexCoords = P / numLayers;
vec2 currentTexCoords = texCoord;
float currentDepthMapValue = texture(heightMap, currentTexCoords).r;
while (currentLayerDepth < currentDepthMapValue)
{
currentTexCoords -= deltaTexCoords;
currentDepthMapValue = texture(heightMap, currentTexCoords).r;
currentLayerDepth += layerDepth;
}
vec2 prevTexCoords = currentTexCoords + deltaTexCoords;
float afterDepth = currentDepthMapValue - currentLayerDepth;
float beforeDepth = texture(heightMap, prevTexCoords).r - currentLayerDepth + layerDepth;
float weight = afterDepth / (afterDepth - beforeDepth);
vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);
return finalTexCoords;
}
// FUNCTION I ADDED FOR SHADOW CALCULATION
float ShadowCalc(vec2 texCoord, vec3 lightDir)
{
float minLayers = 0;
float maxLayers = 32;
float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), lightDir)));
float layerDepth = 1.0 / numLayers;
float currentLayerDepth = 0;
vec2 P = lightDir.xy / lightDir.z * heightScale;
vec2 deltaTexCoords = P / numLayers;
vec2 currentTexCoords = texCoord;
float currentDepthMapValue = texture(heightMap, currentTexCoords).r;
while (currentLayerDepth < currentDepthMapValue)
{
currentTexCoords -= deltaTexCoords;
currentDepthMapValue = texture(heightMap, currentTexCoords).r;
currentLayerDepth += layerDepth;
}
float r = currentDepthMapValue > currentLayerDepth ? 0.0 : 1.0;
return r;
}
void main()
{
mat3 TBN_norm = transpose(mat3(normalize(world_tangent),
normalize(cross(world_normal, world_tangent)),
normalize(world_normal)));
vec3 viewDir = TBN_norm * normalize(o_worldPos - viewPosition);
vec2 currentTex = ParallaxMapping(o_texCoord, viewDir);
if (currentTex.x > 1.0 || currentTex.y > 1.0 || currentTex.x < 0.0 || currentTex.y < 0.0)
{
discard;
}
vec3 normal = texture(normalMap, currentTex).rgb;
normal = normalize(normal * 2.0 - 1.0);
vec3 lightDir = normalize(TBN_norm * light_pos - TBN_norm * o_worldPos);
float dc = max(0.0, dot(lightDir, normal));
// STUFF I ADDED FOR SHADOWS
float shadow = 0;
if (dc > 0)
{
shadow = ShadowCalc(currentTex, lightDir);
}
fragColor = shadow * dc * texture(diffuseMap, currentTex);
}
答案 0 :(得分:2)
首先,光源指向纹理空间中片段的方向是:
vec3 lightDir = TBN_norm * normalize(o_worldPos - light_pos);
float dc = max(0.0, dot(-lightDir, normal));
要检查碎片是否在自阴影中,必须从启动“视差”纹理像素开始跟踪到光源的光线。
float shadow = dc > 0.0 ? ShadowCalc(currentTex, lightDir) : 0.0;
初始高度(currentLayerDepth
)是当前片段的高度:
float currentDepthMapValue = texture(heightMap, currentTexCoords).r;
float currentLayerDepth = currentDepthMapValue;
由于深度mao是反向深度图(1.0为低),因此如果任何层深度(currentLayerDepth
)小于或等于当前高度(currentDepthMapValue
),则片段处于阴影中。如果达到最大深度(最小值为0.0),则必须中止采样。
请注意,在比较currentLayerDepth -= layerDepth
算法时,深度会减小(currentTexCoords += deltaTexCoords
),纹理样本是沿相反的方向(ParallaxMapping
)进行采样:
while (currentLayerDepth <= currentDepthMapValue && currentLayerDepth > 0.0)
{
currentTexCoords += deltaTexCoords;
currentDepthMapValue = texture(heightMap, currentTexCoords).r;
currentLayerDepth -= layerDepth;
}
float r = currentLayerDepth > currentDepthMapValue ? 0.0 : 1.0;
由于被(P = lightDir.xy / lightDir.z
,P
和deltaTexCoords
中的z分量所划分,因此总是指向光源(当然是投影到纹理) 。
如果lightDir
的z分量大于0.0,则从背面照亮表面。这导致了早期中止的情况:
if ( lightDir.z >= 0.0 )
return 0.0;
完整功能ShadowCalc
的功能可能如下所示:
float ShadowCalc(vec2 texCoord, vec3 lightDir)
{
if ( lightDir.z >= 0.0 )
return 0.0;
float minLayers = 0;
float maxLayers = 32;
float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), lightDir)));
vec2 currentTexCoords = texCoord;
float currentDepthMapValue = texture(heightMap, currentTexCoords).r;
float currentLayerDepth = currentDepthMapValue;
float layerDepth = 1.0 / numLayers;
vec2 P = lightDir.xy / lightDir.z * heightScale;
vec2 deltaTexCoords = P / numLayers;
while (currentLayerDepth <= currentDepthMapValue && currentLayerDepth > 0.0)
{
currentTexCoords += deltaTexCoords;
currentDepthMapValue = texture(heightMap, currentTexCoords).r;
currentLayerDepth -= layerDepth;
}
float r = currentLayerDepth > currentDepthMapValue ? 0.0 : 1.0;
return r;
}