延迟着色 - 多光源 (OpenGL/GLSL)
Deferred Shading - Multiple Lights (OpenGL/GLSL)
我正在开发一个延迟着色程序,现在我必须在场景中设置 50 个不同的灯光。为此,我使用这段代码随机生成它的属性(位置、漫反射颜色、镜面反射颜色):
void FBORender::BuildLights()
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(0.0, 0.1);
for (int i = 0; i < NUM_LIGHTS; i++)
{
float dc_r = (float) dis(gen);
float dc_g = (float) dis(gen);
float dc_b = (float) dis(gen);
printf("%f\n", dc_r);
float lp_x = (float)(rand() % 40 - 20);
float lp_y = (float)(rand() % 100 + 10);
float lp_z = (float)(rand() % 40 - 20);
DC[i * NUM_LIGHTS] = dc_r;
DC[i * NUM_LIGHTS + 1] = dc_g;
DC[i * NUM_LIGHTS + 2] = dc_b;
LP[i * NUM_LIGHTS] = lp_x;
LP[i * NUM_LIGHTS + 1] = lp_y;
LP[i * NUM_LIGHTS + 2] = lp_z;
}
}
但是,我不太确定如何使用多盏灯进行照明。有人说环境光应该等于漫反射光,镜面光应该是白色的。
调整我必须执行 Phong Ilumination 的着色器,我有这个:
#version 410 core
#define numLights 5
uniform sampler2D tDiffuse;
uniform sampler2D tPosition;
uniform sampler2D tNormals;
uniform vec4 specularColor;
uniform vec3 diffuseColor[numLights];
uniform vec3 vLightPosition[numLights];
in vec2 texCoord;
out vec4 fragColor;
void main( void )
{
vec3 tex = texture( tDiffuse, texCoord.st ).xyz;
vec3 vPosition = texture( tPosition, texCoord.st ).xyz;
vec3 vNormal = normalize( texture( tNormals, texCoord.st ).xyz * 2 - 1 );
vec3 vVaryingNormal = vNormal;
for (int i = 0; i < numLights; i++)
{
vec3 vVaryingLightDir = normalize( vLightPosition[i] - vPosition );
float diff = max( 0.0, dot( normalize( vVaryingNormal ), normalize( vVaryingLightDir ) ) );
vec4 partialColor = diff * vec4(diffuseColor[i], 1.0);
partialColor = vec4( mix( partialColor.rgb, tex, 0.5 ), partialColor.a );
partialColor += vec4( diffuseColor[i], 1.0 );
vec3 vReflection = normalize( reflect( -normalize( vVaryingLightDir ), normalize( vVaryingNormal )));
float spec = max( 0.0, dot( normalize( vVaryingNormal ), vReflection ));
if( diff != 0 )
{
float fSpec = pow( spec, 128.0 );
partialColor.rgb += vec3( fSpec, fSpec, fSpec );
}
fragColor += partialColor;
}
}
然而,我得到的结果很难看(如果没有错的话),如下图所示:
这个结果只使用了 2 个灯。因为我必须使用 50,所以我认为我只会看到一个白屏...
我没有看到任何基于距离的计算,但这是必需的,否则场景中的所有内容都会以相同的方式受到每个灯光的影响。
有多种方法可以计算基于距离的灯光,最常见的是 inverse square root,基本上是:
intensity = 1 / sqrt(distance * distance)
您还可以在 GameDev 上查看 this article。
当然,如果使用 PBS(基于物理的着色;例如:Unreal Engine 4 shading),您可以获得更好的外观。
在延迟渲染中,您通常会单独渲染每盏灯,然后让 GPU 将结果混合在一起。这降低了着色器的复杂性。
让我们仔细看看您的光照计算。
partialColor = vec4( mix( partialColor.rgb, tex, 0.5 ), partialColor.a );
嗯...这条线应该做什么?那时,partialColor
包含漫射阴影颜色(假设是白色 material)。如果你真的想通过混合来计算material颜色(这看起来有点奇怪),你应该在之后做阴影:
vec3 materialColor = mix( vec3(1.0, 1.0, 1.0), tex, 0.5 );
vec4 partialColor = vec4(diffuseColor[i] * diff * materialColor, 1.0);
代码中的下一行:
partialColor += vec4( diffuseColor[i], 1.0 );
我不知道这应该做什么。离开它。
下一行:
vec3 vReflection = normalize( reflect( -normalize( vVaryingLightDir ), normalize( vVaryingNormal )));
float spec = max( 0.0, dot( normalize( vVaryingNormal ), vReflection ));
您正在混合使用 Phong 和 Blinn-Phong。 Phong 需要反射光向量和眼睛向量的点积。 Blinn-Phong 需要法线与光向量和眼睛向量之间的半向量的点积。
下一行:
partialColor.rgb += vec3( fSpec, fSpec, fSpec );
这应该乘以光的镜面反射颜色。此外,您应该检查 spec > 0
.
,而不是检查 diff != 0.0
如果您仍然遇到问题,请关闭镜面反射照明并查看漫反射照明是否正确。
另外,你的灯好像有点亮。光色的期望值为(0.05, 0.05, 0.05)
。其中 50 盏灯总共 (2.5, 2.5, 2.5)
,这比白灯要亮得多。
我正在开发一个延迟着色程序,现在我必须在场景中设置 50 个不同的灯光。为此,我使用这段代码随机生成它的属性(位置、漫反射颜色、镜面反射颜色):
void FBORender::BuildLights()
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(0.0, 0.1);
for (int i = 0; i < NUM_LIGHTS; i++)
{
float dc_r = (float) dis(gen);
float dc_g = (float) dis(gen);
float dc_b = (float) dis(gen);
printf("%f\n", dc_r);
float lp_x = (float)(rand() % 40 - 20);
float lp_y = (float)(rand() % 100 + 10);
float lp_z = (float)(rand() % 40 - 20);
DC[i * NUM_LIGHTS] = dc_r;
DC[i * NUM_LIGHTS + 1] = dc_g;
DC[i * NUM_LIGHTS + 2] = dc_b;
LP[i * NUM_LIGHTS] = lp_x;
LP[i * NUM_LIGHTS + 1] = lp_y;
LP[i * NUM_LIGHTS + 2] = lp_z;
}
}
但是,我不太确定如何使用多盏灯进行照明。有人说环境光应该等于漫反射光,镜面光应该是白色的。
调整我必须执行 Phong Ilumination 的着色器,我有这个:
#version 410 core
#define numLights 5
uniform sampler2D tDiffuse;
uniform sampler2D tPosition;
uniform sampler2D tNormals;
uniform vec4 specularColor;
uniform vec3 diffuseColor[numLights];
uniform vec3 vLightPosition[numLights];
in vec2 texCoord;
out vec4 fragColor;
void main( void )
{
vec3 tex = texture( tDiffuse, texCoord.st ).xyz;
vec3 vPosition = texture( tPosition, texCoord.st ).xyz;
vec3 vNormal = normalize( texture( tNormals, texCoord.st ).xyz * 2 - 1 );
vec3 vVaryingNormal = vNormal;
for (int i = 0; i < numLights; i++)
{
vec3 vVaryingLightDir = normalize( vLightPosition[i] - vPosition );
float diff = max( 0.0, dot( normalize( vVaryingNormal ), normalize( vVaryingLightDir ) ) );
vec4 partialColor = diff * vec4(diffuseColor[i], 1.0);
partialColor = vec4( mix( partialColor.rgb, tex, 0.5 ), partialColor.a );
partialColor += vec4( diffuseColor[i], 1.0 );
vec3 vReflection = normalize( reflect( -normalize( vVaryingLightDir ), normalize( vVaryingNormal )));
float spec = max( 0.0, dot( normalize( vVaryingNormal ), vReflection ));
if( diff != 0 )
{
float fSpec = pow( spec, 128.0 );
partialColor.rgb += vec3( fSpec, fSpec, fSpec );
}
fragColor += partialColor;
}
}
然而,我得到的结果很难看(如果没有错的话),如下图所示:
这个结果只使用了 2 个灯。因为我必须使用 50,所以我认为我只会看到一个白屏...
我没有看到任何基于距离的计算,但这是必需的,否则场景中的所有内容都会以相同的方式受到每个灯光的影响。
有多种方法可以计算基于距离的灯光,最常见的是 inverse square root,基本上是:
intensity = 1 / sqrt(distance * distance)
您还可以在 GameDev 上查看 this article。 当然,如果使用 PBS(基于物理的着色;例如:Unreal Engine 4 shading),您可以获得更好的外观。
在延迟渲染中,您通常会单独渲染每盏灯,然后让 GPU 将结果混合在一起。这降低了着色器的复杂性。
让我们仔细看看您的光照计算。
partialColor = vec4( mix( partialColor.rgb, tex, 0.5 ), partialColor.a );
嗯...这条线应该做什么?那时,partialColor
包含漫射阴影颜色(假设是白色 material)。如果你真的想通过混合来计算material颜色(这看起来有点奇怪),你应该在之后做阴影:
vec3 materialColor = mix( vec3(1.0, 1.0, 1.0), tex, 0.5 );
vec4 partialColor = vec4(diffuseColor[i] * diff * materialColor, 1.0);
代码中的下一行:
partialColor += vec4( diffuseColor[i], 1.0 );
我不知道这应该做什么。离开它。
下一行:
vec3 vReflection = normalize( reflect( -normalize( vVaryingLightDir ), normalize( vVaryingNormal )));
float spec = max( 0.0, dot( normalize( vVaryingNormal ), vReflection ));
您正在混合使用 Phong 和 Blinn-Phong。 Phong 需要反射光向量和眼睛向量的点积。 Blinn-Phong 需要法线与光向量和眼睛向量之间的半向量的点积。
下一行:
partialColor.rgb += vec3( fSpec, fSpec, fSpec );
这应该乘以光的镜面反射颜色。此外,您应该检查 spec > 0
.
diff != 0.0
如果您仍然遇到问题,请关闭镜面反射照明并查看漫反射照明是否正确。
另外,你的灯好像有点亮。光色的期望值为(0.05, 0.05, 0.05)
。其中 50 盏灯总共 (2.5, 2.5, 2.5)
,这比白灯要亮得多。