体积光无法正确渲染体积
Volumetric Light not rendering volume correctly
我一直在按照本教程 (https://www.programmersought.com/article/68075912719/) 学习体积光。但是我没有得到正确的输出。
阴影体积渲染不正确,我不确定我做错了什么。我的顶点和片段着色器看起来与教程完全一样,但我仍然没有得到正确的输出。
这是顶点着色器代码
#version 450 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in vec3 normal;
uniform mat4 model;
uniform mat4 vp;
uniform float zFar;
uniform float fov;;
uniform float aspectRatio;
out vec2 TexCoord;
out vec2 farPlanePos;
void main(void){
gl_Position = vec4(position, 1.0);
TexCoord = vec2 (texCoord.x, 1 - texCoord.y);
float t = tan(fov/2);
farPlanePos.x = (TexCoord.x * 2 - 1) * zFar * t * aspectRatio;
farPlanePos.y = (TexCoord.y * 2 - 1) * zFar * t;
}
这是片段着色器代码
#版本 450 核心
in vec2 TexCoord;
uniform vec3 cameraPos;
uniform vec3 lightPos;
uniform vec3 lightColor;
uniform mat4 invViewMatrix;
uniform mat4 invProjectionMatrix;
uniform float ambientStrength;
uniform sampler2D gPosition;
uniform sampler2D gNormal;
uniform sampler2D gAlbedoSpec;
uniform sampler2D gDepth;
uniform sampler2D shadowMapTexture;
in vec2 farPlanePos;
uniform float zFar;
uniform float zNear;
float g = 0.0f;
uniform mat4 lightViewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
vec3 yellow_light = vec3(1,198.0/255.0,107.0/255.0);
out vec4 finalColor;
// use linear z depth
vec3 ComputeWorldPos(float depth){
vec4 pos = vec4(vec3(farPlanePos.x, farPlanePos.y, -zFar) * depth , 1.0f);
vec4 ret = invViewMatrix * pos;
return ret.xyz / ret.w;
}
bool IsInShadow(vec4 worldPos){
float fShadow = 0.0;
vec4 lightPos = (lightViewMatrix * (worldPos));
float fDistance = -lightPos.z / zFar;
lightPos = projectionMatrix * lightPos;
vec2 uv = lightPos.xy / lightPos.w * 0.5 + vec2(0.5f, 0.5f);
uv.x = clamp(uv.x, 0.0f, 1.0f);
uv.y = clamp(uv.y, 0.0f, 1.0f);
float offset = 0.5f/zFar;
float distanceMap = texture2D(shadowMapTexture, uv).r;
return fDistance - offset > distanceMap;
}
void main(void){
float depth = texture2D(gDepth, TexCoord).w;
vec3 total_light;
// volume light
{
float I = 0.0f;
float d = depth * zFar;
int virtual_plane_num = 100;
int begin = int(virtual_plane_num * zNear / (d - zNear));
int end = int(virtual_plane_num * (zFar - d) / (d - zNear));
for(int j = begin; j <= virtual_plane_num + begin; j++)
{
float z = 1.0f * j / (begin + virtual_plane_num + end);
vec3 pos = ComputeWorldPos(z);
if(z < depth && !IsInShadow(vec4(pos,1.0f)))
{
//vec3 lightDis = pos - lightPos;
//vec3 viewDis = pos - cameraPos;
//float lightDis2 = lightDis.x * lightDis.x + lightDis.y * lightDis.y + lightDis.z * lightDis.z;
vec3 lightDir = normalize(pos - lightPos);
vec3 viewDir = normalize(pos - cameraPos);
float cosTheta = dot(lightDir,normalize(-lightPos));
float hg = 1.0f/(4.0f*3.14f)* (1.0f - g*g)/ pow(1.0f + g * g - 2.0f * g * dot(lightDir,-viewDir), 1.5f);
if(cosTheta >0.9){
I += clamp(10 * hg / virtual_plane_num, 0.0f, 1.0f);
}
}
}
I = clamp(I , 0.0f,1.0f);
total_light += I * yellow_light;
}
vec3 normal = texture2D(gNormal, TexCoord).xyz * 2 - 1; //result.xyz * 2 - 1;
vec3 worldPos = ComputeWorldPos(depth);
// parallel lights
/*
{
vec3 ViewDir = normalize( cameraPos - worldPos );
vec3 lightDir = normalize(vec3(0.5,1,0.2) );
vec3 halfDir = normalize(lightDir + ViewDir);
float diffuse = 0.3 * clamp(dot(normal, lightDir), 0, 1) ;
vec3 reflectDir = normalize(reflect(-lightDir,normal));
float specular = 0.3 * pow(clamp(dot(reflectDir,halfDir),0,1),50.0);
vec3 color = (diffuse + specular) *vec3(1,1,1);
total_light += color;
}
*/
vec3 color = vec3(texture2D(gAlbedoSpec,TexCoord));
float ambient = 0.1;
finalColor = vec4(total_light + ambient * color,1);
}
所以你可以看到顶点和片段着色器代码和博客一模一样,但输出仍然不同。
不幸的是,它没有说明如何联系博主,否则我会直接问他们。所以下一个最佳选择是 stockoverflow,所以我在这里问。
好的,我在 2 天后解决了这个问题。我认为 isInShadow 函数是不正确的,因为它总是透视 zFar 并且在获得当前深度之前也不会乘以投影矩阵。
所以我用 learnOpengl 阴影计算替换了代码,如下所示。
bool IsInShadow(vec4 worldPos){
vec4 lightPos = (lightViewMatrix * (worldPos));
//float fDistance = -lightPos.z/ zFar;
lightPos = projectionMatrix * lightPos;
vec3 projCoords = lightPos.xyz / lightPos.w ;
projCoords = projCoords* 0.5 + 0.5f;
//uv.x = clamp(uv.x, 0.0f, 1.0f);
//uv.y = clamp(uv.y, 0.0f, 1.0f);
float offset = 0.5f/zFar;
float distanceMap = texture2D(shadowMapTexture, projCoords.xy).r;
return projCoords.z - offset > distanceMap;
}
现在代码可以工作了!!
我一直在按照本教程 (https://www.programmersought.com/article/68075912719/) 学习体积光。但是我没有得到正确的输出。
阴影体积渲染不正确,我不确定我做错了什么。我的顶点和片段着色器看起来与教程完全一样,但我仍然没有得到正确的输出。
这是顶点着色器代码
#version 450 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in vec3 normal;
uniform mat4 model;
uniform mat4 vp;
uniform float zFar;
uniform float fov;;
uniform float aspectRatio;
out vec2 TexCoord;
out vec2 farPlanePos;
void main(void){
gl_Position = vec4(position, 1.0);
TexCoord = vec2 (texCoord.x, 1 - texCoord.y);
float t = tan(fov/2);
farPlanePos.x = (TexCoord.x * 2 - 1) * zFar * t * aspectRatio;
farPlanePos.y = (TexCoord.y * 2 - 1) * zFar * t;
}
这是片段着色器代码
#版本 450 核心
in vec2 TexCoord;
uniform vec3 cameraPos;
uniform vec3 lightPos;
uniform vec3 lightColor;
uniform mat4 invViewMatrix;
uniform mat4 invProjectionMatrix;
uniform float ambientStrength;
uniform sampler2D gPosition;
uniform sampler2D gNormal;
uniform sampler2D gAlbedoSpec;
uniform sampler2D gDepth;
uniform sampler2D shadowMapTexture;
in vec2 farPlanePos;
uniform float zFar;
uniform float zNear;
float g = 0.0f;
uniform mat4 lightViewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
vec3 yellow_light = vec3(1,198.0/255.0,107.0/255.0);
out vec4 finalColor;
// use linear z depth
vec3 ComputeWorldPos(float depth){
vec4 pos = vec4(vec3(farPlanePos.x, farPlanePos.y, -zFar) * depth , 1.0f);
vec4 ret = invViewMatrix * pos;
return ret.xyz / ret.w;
}
bool IsInShadow(vec4 worldPos){
float fShadow = 0.0;
vec4 lightPos = (lightViewMatrix * (worldPos));
float fDistance = -lightPos.z / zFar;
lightPos = projectionMatrix * lightPos;
vec2 uv = lightPos.xy / lightPos.w * 0.5 + vec2(0.5f, 0.5f);
uv.x = clamp(uv.x, 0.0f, 1.0f);
uv.y = clamp(uv.y, 0.0f, 1.0f);
float offset = 0.5f/zFar;
float distanceMap = texture2D(shadowMapTexture, uv).r;
return fDistance - offset > distanceMap;
}
void main(void){
float depth = texture2D(gDepth, TexCoord).w;
vec3 total_light;
// volume light
{
float I = 0.0f;
float d = depth * zFar;
int virtual_plane_num = 100;
int begin = int(virtual_plane_num * zNear / (d - zNear));
int end = int(virtual_plane_num * (zFar - d) / (d - zNear));
for(int j = begin; j <= virtual_plane_num + begin; j++)
{
float z = 1.0f * j / (begin + virtual_plane_num + end);
vec3 pos = ComputeWorldPos(z);
if(z < depth && !IsInShadow(vec4(pos,1.0f)))
{
//vec3 lightDis = pos - lightPos;
//vec3 viewDis = pos - cameraPos;
//float lightDis2 = lightDis.x * lightDis.x + lightDis.y * lightDis.y + lightDis.z * lightDis.z;
vec3 lightDir = normalize(pos - lightPos);
vec3 viewDir = normalize(pos - cameraPos);
float cosTheta = dot(lightDir,normalize(-lightPos));
float hg = 1.0f/(4.0f*3.14f)* (1.0f - g*g)/ pow(1.0f + g * g - 2.0f * g * dot(lightDir,-viewDir), 1.5f);
if(cosTheta >0.9){
I += clamp(10 * hg / virtual_plane_num, 0.0f, 1.0f);
}
}
}
I = clamp(I , 0.0f,1.0f);
total_light += I * yellow_light;
}
vec3 normal = texture2D(gNormal, TexCoord).xyz * 2 - 1; //result.xyz * 2 - 1;
vec3 worldPos = ComputeWorldPos(depth);
// parallel lights
/*
{
vec3 ViewDir = normalize( cameraPos - worldPos );
vec3 lightDir = normalize(vec3(0.5,1,0.2) );
vec3 halfDir = normalize(lightDir + ViewDir);
float diffuse = 0.3 * clamp(dot(normal, lightDir), 0, 1) ;
vec3 reflectDir = normalize(reflect(-lightDir,normal));
float specular = 0.3 * pow(clamp(dot(reflectDir,halfDir),0,1),50.0);
vec3 color = (diffuse + specular) *vec3(1,1,1);
total_light += color;
}
*/
vec3 color = vec3(texture2D(gAlbedoSpec,TexCoord));
float ambient = 0.1;
finalColor = vec4(total_light + ambient * color,1);
}
所以你可以看到顶点和片段着色器代码和博客一模一样,但输出仍然不同。
不幸的是,它没有说明如何联系博主,否则我会直接问他们。所以下一个最佳选择是 stockoverflow,所以我在这里问。
好的,我在 2 天后解决了这个问题。我认为 isInShadow 函数是不正确的,因为它总是透视 zFar 并且在获得当前深度之前也不会乘以投影矩阵。
所以我用 learnOpengl 阴影计算替换了代码,如下所示。
bool IsInShadow(vec4 worldPos){
vec4 lightPos = (lightViewMatrix * (worldPos));
//float fDistance = -lightPos.z/ zFar;
lightPos = projectionMatrix * lightPos;
vec3 projCoords = lightPos.xyz / lightPos.w ;
projCoords = projCoords* 0.5 + 0.5f;
//uv.x = clamp(uv.x, 0.0f, 1.0f);
//uv.y = clamp(uv.y, 0.0f, 1.0f);
float offset = 0.5f/zFar;
float distanceMap = texture2D(shadowMapTexture, projCoords.xy).r;
return projCoords.z - offset > distanceMap;
}
现在代码可以工作了!!