具有阴影映射和摄像机移动的点照明



尝试在我的场景中创建聚光灯时遇到问题。问题是我的相机在场景中移动,因此,照明有问题。此外,我只看到一个黑屏。我知道我在某个地方错过了转型,或者做了一些额外的事情,但是在哪里 - 我真的不知道。

下面是我的着色器的代码。

片段着色器:

#version 330 core
precision mediump float;                        // Set the default precision to medium. We don't need as high of a
// precision in the fragment shader.
#define MAX_LAMPS_COUNT 8                   // Max lamps count.
uniform vec3 u_ViewPos;                     // Camera position
uniform int u_LampsCount;                   // Lamps count
uniform int u_ShadowMapWidth = 1024;        // shadow map width / default is 1024
uniform int u_ShadowMapHeight = 1024;       // shadow map height / default is 1024
uniform float brightnessThreshold = 0.5;        // brightness threshold variable
uniform float far_plane = 16;
varying mat4 v_MVMatrix;                    // Model View matrix
varying mat3 v_TBN;                         // Tangent Bitangent Normal matrix
varying vec4 v_Position;                    // Position for this fragment.
varying vec3 v_Normal;                      // Interpolated normal for this fragment.
varying vec2 v_Texture;                     // Texture coordinates.
varying float v_NormalMapping;              // Is normal mapping enabled 0 - false, 1 - true
struct Lamp {
float ambientStrength;
float diffuseStrength;
float specularStrength;
float kc; // constant term
float kl; // linear term
float kq; // quadratic term
int shininess;
vec3 lampPos; // in eye space, cameraViewMatrix * lamp world coordinates
vec3 lampColor;
};
uniform samplerCube shadowMaps[MAX_LAMPS_COUNT];
uniform struct Mapping {
sampler2D ambient;
sampler2D diffuse;
sampler2D specular;
sampler2D normal;
} u_Mapping;
uniform Lamp u_Lamps[MAX_LAMPS_COUNT];
vec3 norm;
vec3 fragPos;
float shadow;
// output colors
layout(location = 0) out vec4 fragColor;
layout(location = 1) out vec4 fragBrightColor;
float calculateShadow(int textureIndex, vec3 lightPos) {
// get vector between fragment position and light position
vec3 fragToLight = fragPos - lightPos;
// use the light to fragment vector to sample from the depth map
float closestDepth = texture(shadowMaps[textureIndex], fragToLight).r;
// it is currently in linear range between [0,1]. Re-transform back to original value
closestDepth *= far_plane;
// now get current linear depth as the length between the fragment and light position
float currentDepth = length(fragToLight);
// now test for shadows
float bias = 0.05;
float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
//fragColor = vec4(vec3(closestDepth / far_plane), 1.0);  // visualization
return shadow;
}
float calculateAttenuation(Lamp lamp) {
float distance = length(lamp.lampPos - fragPos);
return 1.0 / (
lamp.kc +
lamp.kl * distance +
lamp.kq * (distance * distance)
);
}
vec4 toVec4(vec3 v) {
return vec4(v, 1);
}
// The entry point for our fragment shader.
void main() {
// Transform the vertex into eye space.
fragPos = vec3(v_MVMatrix * v_Position);
vec3 viewDir = normalize(u_ViewPos - fragPos);
if (v_NormalMapping == 0) norm = vec3(normalize(v_MVMatrix * vec4(v_Normal, 0)));
else { // using normal map if normal mapping enabled
norm = texture2D(u_Mapping.normal, v_Texture).rgb;
norm = normalize(norm * 2.0 - 1.0); // from [0; 1] to [-1; -1]
norm = normalize(v_TBN * norm);
}
vec3 ambientResult = vec3(0, 0, 0); // result of ambient lighting for all lamps
vec3 diffuseResult = vec3(0, 0, 0); // result of diffuse lighting for all lamps
vec3 specularResult = vec3(0, 0, 0); // result of specular lighting for all lamps
for (int i = 0; i<u_LampsCount; i++) {
// attenuation
float attenuation = calculateAttenuation(u_Lamps[i]);
// ambient
vec3 ambient = u_Lamps[i].ambientStrength * u_Lamps[i].lampColor * attenuation;
// diffuse
vec3 lightDir = normalize(u_Lamps[i].lampPos - fragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = u_Lamps[i].diffuseStrength * diff * u_Lamps[i].lampColor * attenuation;
// specular
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), u_Lamps[i].shininess);
vec3 specular = u_Lamps[i].specularStrength * spec * u_Lamps[i].lampColor * attenuation;
// fragment position in light space
//fragLightSpacePos = u_Lamps[i].lightSpaceMatrix * u_Lamps[i].lightModelMatrix * v_Position;
// calculate shadow
shadow = calculateShadow(i, u_Lamps[i].lampPos);
// result for this(i) lamp
ambientResult += ambient;
diffuseResult += diffuse * (1-shadow);
specularResult += specular * (1-shadow);
}
fragColor =
toVec4(ambientResult) * texture2D(u_Mapping.ambient, v_Texture) +
toVec4(diffuseResult) * texture2D(u_Mapping.diffuse, v_Texture) +
toVec4(specularResult) * texture2D(u_Mapping.specular, v_Texture);
// brightness calculation
//float brightness = dot(fragColor.rgb, vec3(0.2126, 0.7152, 0.0722));
//if (brightness > brightnessThreshold) fragBrightColor = vec4(fragColor.rgb, 1.0);
fragBrightColor = vec4(0, 0, 0, 1);
}

顶点着色器:

#version 130
uniform mat4 u_MVPMatrix;      // A constant representing the combined model/view/projection matrix.
uniform mat4 u_MVMatrix;       // A constant representing the combined model/view matrix.
uniform float u_NormalMapping;  // Normal mapping; 0 - false, 1 - true
attribute vec4 a_Position;     // Per-vertex position information we will pass in.
attribute vec3 a_Normal;       // Per-vertex normal information we will pass in.
attribute vec3 a_Tangent;      // Per-vertex tangent information we will pass in.
attribute vec3 a_Bitangent;    // Per-vertex bitangent information we will pass in.
attribute vec2 a_Texture;      // Per-vertex texture information we will pass in.
varying mat4 v_MVMatrix;       // This will be passed into the fragment shader.
varying mat3 v_TBN;            // This will be passed into the fragment shader.
varying vec4 v_Position;       // This will be passed into the fragment shader.
varying vec3 v_Normal;         // This will be passed into the fragment shader.
varying vec2 v_Texture;        // This will be passed into the fragment shader.
varying float v_NormalMapping;  // This will be passed into the fragment shader.
void main() {
// creating TBN (tangent-bitangent-normal) matrix if normal mapping enabled
if (u_NormalMapping == 1) {
vec3 T = normalize(vec3(u_MVMatrix * vec4(a_Tangent, 0.0)));
vec3 B = normalize(vec3(u_MVMatrix * vec4(a_Bitangent, 0.0)));
vec3 N = normalize(vec3(u_MVMatrix * vec4(a_Normal, 0.0)));
mat3 TBN = mat3(T, B, N);
v_TBN = TBN;
}
// gl_Position is a special variable used to store the final position.
// Multiply the vertex by the matrix to get the final point in normalized screen coordinates.
gl_Position = u_MVPMatrix * a_Position;
// sending all needed variables to fragment shader
v_Position = a_Position;
v_Texture = a_Texture;
v_NormalMapping = u_NormalMapping;
v_MVMatrix = u_MVMatrix;
v_Normal = a_Normal;
}

顶点阴影着色器:

#version 130
attribute vec3 a_Position;
uniform mat4 u_ModelMatrix;
void main() {
gl_Position = u_ModelMatrix * vec4(a_Position, 1.0);
}

片段阴影着色器:

#version 330 core
in vec4 fragPos;
uniform vec3 lightPos; // cameraViewMatrix * lamp world coordinates
uniform float far_plane = 16;
void main()
{
float lightDistance = length(fragPos.xyz - lightPos);
// map to [0;1] range by dividing by far_plane
lightDistance = lightDistance / far_plane;
// write this as modified depth
gl_FragDepth = lightDistance;
}

几何阴影着色器:

#version 330 core
layout (triangles) in;
layout (triangle_strip, max_vertices=18) out;
uniform mat4 shadowMatrices[6];
out vec4 fragPos; // FragPos from GS (output per emitvertex)
void main() {
for(int face = 0; face < 6; ++face) {
gl_Layer = face; // built-in variable that specifies to which face we render.
for(int i = 0; i < 3; ++i) // for each triangle's vertices
{
fragPos = gl_in[i].gl_Position;
gl_Position = shadowMatrices[face] * fragPos;
EmitVertex();
}
EndPrimitive();
}
}

以及演示可视化阴影图的视频: https://youtu.be/zaNXGG1qLaw

我知道

我在某处错过了转换,或者做了一些额外的事情,但是在哪里 - 我真的不知道。

shadowMaps[textureIndex]的内容很可能是在"光空间"中拍摄的深度图。这意味着它是从光源看到的深度图。

fragPos = vec3(v_MVMatrix * v_Position);

struct Lamp {
.....
vec3 lampPos; // in eye space, cameraViewMatrix * lamp world coordinates
.....
};

在视野中空间坐标。这会导致

vec3 fragToLight = fragPos - lightPos;

是从摄像机看到的视图空间中的一个方向。

如果你这样做

float closestDepth = texture(shadowMaps[textureIndex], fragToLight).r;

然后通过"视图空间"向量访问"光空间"映射。缺少从视图空间坐标到"光空间"坐标的转换。

为了解决这个问题,你需要一个从世界坐标转换为"光空间"坐标的矩阵。 这是您在创建shadowMaps时使用的视图投影矩阵的矩阵。

mat4 inverse_light_vp_mat[MAX_LAMPS_COUNT];

片段位置必须转换为世界坐标,然后必须转换为"光空间"坐标,inverse_light_vp_mat

varying mat4 v_ModelMatrix;  // Model matrix
vec4 fragLightPos = inverse_light_vp_mat[textureIndex] * v_ModelMatrix * v_Position;
fragLightPos.xyz /= fragLightPos.w;

在"光空间"中,光的位置是vec3(0.0,0.0,0.0(,因为光源的位置是"光空间"的原点。因此,shadowMaps中的查找可以直接使用fragLightPos完成:

float closestDepth = texture(shadowMaps[textureIndex], fragLightPos.xyz).r;

问题解决了。这是因为我考虑了相机空间(视图空间(中的阴影地图,但在世界空间中这是必要的。此外,在计算阴影本身的过程中,还需要计算世界空间中的所有内容。

片段着色器:

vec3 fragToLight = vec3(model * v_Position) - lightPosWorldSpace;

vec3 fragToLight = vec3(model * v_Position) - vec3(inverse(view) * lightPos);(光Pos - vec4(

片段阴影着色器:

float lightDistance = length(fragPos.xyz - lightPos);, lightPos - 灯在世界空间中的位置

最新更新