我只使用一个点光源成功实现了立方体贴图阴影贴图。
为了渲染这个场景,我在第一个渲染过程几何着色器中使用它来调度6个截头。在第二个渲染过程中,我使用片段着色器中的samplerCubeShadow来计算阴影因子。
我使用NVIDIA GeForce GTX 780M的OpenGL / GLSL版本4.40。
以下是截图:
但现在我想实现多个立方体贴图阴影贴图,使用几个点光源渲染阴影。
我的片段着色器中有一些代码安静:
[...]
/*
** Shadow Cube sampler array.
*/
uniform samplerCubeShadow ShadowCubeSampler[5]; //Max point light by scene = 5
[...]
float ConvertDistToClipSpace(vec3 lightDir_ws)
{
vec3 AbsVec = abs(lightDir_ws);
float LocalZcomp = max(AbsVec.x, max(AbsVec.y, AbsVec.z));
float NormZComp = (NearFar.y + NearFar.x)/(NearFar.y - NearFar.x)
- (2.0f * NearFar.y * NearFar.x)/(LocalZcomp * NearFar.y - NearFar.x);
return ((NormZComp + 1) * 0.5f);
}
float GetCubeShadowFactor(vec3 vertexPosition_ws, float shadowFactor, int idx)
{
vec3 lightToVertexDir_ws = vertexPosition_ws - LightPos_ws.xyz;
float LightToVertexClipDist = ConvertDistToClipSpace(lightToVertexDir_ws);
float LightToOccluderClipDist = texture(
ShadowCubeSampler[idx], vec4(lightToVertexDir_ws, LightToVertexClipDist));
if (LightToOccluderClipDist < LightToVertexClipDist)
{
shadowFactor = 0.0f;
}
return (shadowFactor);
}
void main(void)
{
[...]
for (int idx = 0; idx < 1; idx++) //Test first with 1 point light
{
float ShadowFactor = GetCubeShadowFactor(Position_ws.xyz, ShadowFactor, idx);
}
[...]
}
问题是我有错误1282(INVALID_OPERATION)。为了恢复这里的情况,我希望使用SINGLE点光源显示与上图完全相同的场景,但这次使用的是samplerCubeShadow数组。令人惊奇的是,如果我用“ShadowCubeSampler [0]”替换函数“texture”'ShadowCubeSampler [idx]'的第一个参数就可以了!但是'idx'的值始终为'0'。我尝试了以下代码但没有成功:
int toto = 0;
float LightToOccluderClipDist = texture(ShadowCubeSampler[toto], vec4(lightToVertexDir_ws, LightToVertexClipDist));
我已经有错误1282!索引的类型是相同的(int)!
我已经使用'sampler2DShadow'或'sampler2D'数组而没有问题。
那么,为什么使用'samplerCubeShadow'并且解决方案'ShadowCubeSampler [0]'不起作用而不能正常工作?
PS:如果我定义一个2的数组,如果我使用2个立方体贴图,那么2点光源就可以了。因此,如果我加载了一些比碎片着色器中指定的数量更差的立方体贴图,它就会失败!
我没有编译错误,也没有链接错误。这是我用来检查着色器程序状态的代码:
void video::IEffectBase::Log(void) const
{
GLint errorLink = 0;
glGetProgramiv(this->m_Handle, GL_LINK_STATUS, &errorLink);
if (errorLink != GL_TRUE)
{
GLint sizeError = 0;
glGetProgramiv(this->m_Handle, GL_INFO_LOG_LENGTH, &sizeError);
char *erreur = new char[sizeError + 1];
glGetShaderInfoLog(this->m_Handle, sizeError, &sizeError, erreur);
erreur[sizeError] = '\0';
std::cerr << erreur << std::endl;
glDeleteProgram(this->m_Handle);
delete[] erreur;
}
}
关于纹理单位限制:
std::cout << GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS << std::endl;
std::cout << GL_MAX_TEXTURE_IMAGE_UNITS << std::endl;
$> 35660
$> 34930
如果我使用'ShadowCubeSampler [0]','0'直接写在代码中我有相同的显示,就像图片一样,我的帖子开头没有错误。如果我使用idx = 0的'ShadowCubeSampler [idx]',我有以下显示:
如您所见,尚未渲染共享此着色器的所有几何体。但是我没有任何链接错误。你怎么解释这个?系统是否可以取消连接着色器程序?
更新
假设我的samplerCubeShadow数组可以包含2个最大采样器(uniform samplerCubeShadow tex_shadow 2)。
我注意到如果我只加载一个点光源,那么一个立方体贴图:
CASE 1
uniform samplerCubeShadow tex_shadow[1]; //MAX POINT LIGHT = 1
for (int i=0; i < 1; i++) {tex_shadow[i];} //OK
for (int i=0; i < 1; i++) {texture(tex_shadow[i], ...);} //OK
for (int i=0; i < 1; i++) {texture(tex_shadow[0], ...);} //OK
CASE 2
uniform samplerCubeShadow tex_shadow[2]; //MAX POINT LIGHT = 2
for (int i=0; i < 1; i++) {tex_shadow[i];} //NOT OK - 1282
for (int i=0; i < 1; i++) {texture(tex_shadow[i], ...);} //NOT OK - 1282
for (int i=0; i < 1; i++) {texture(tex_shadow[0], ...);} //OK
CASE 3
uniform samplerCubeShadow tex_shadow[2]; //MAX POINT LIGHT = 2
for (int i=0; i < 2; i++) {tex_shadow[i];} //OK
for (int i=0; i < 2; i++) {texture(tex_shadow[i], ...);} //OK
for (int i=0; i < 2; i++) {texture(tex_shadow[0], ...);} //OK
结论:如果采样器的最大数量等于加载的采样器数量,我可以循环遍历数组中包含的采样器。如果数字较差,则不起作用!每次使用着色器程序时,我最多可以使用32个纹理单元。我使用samplerCube关键字时遇到同样的问题。
这很奇怪,因为我使用sampler2D或sampler2DShadow进行聚光灯影计算没有任何问题。
我用NSight检查我在片段着色器文件中放置了一个断点,当然还有断点。这就像着色器程序没有关联,但事实并非如此。
您是否认为这可能是有关cubeMap采样器的问题,或者问题来自立方体贴图初始化?
有人可以帮助我吗?
答案 0 :(得分:0)
我从来没有在glsl里面使用过数组,而且我现在没有设备这么做, 但你有没有尝试在glsl中使用unsigned int uint。
float GetCubeShadowFactor(vec3 vertexPosition_ws, float shadowFactor, uint idx) {
....
}
另请注意,您不能在着色器中使用无限采样器。
答案 1 :(得分:0)
OpenGL根据目标版本对opaque类型的数组有特殊限制(纹理就是其中之一)。在OpenGL 4循环这样的数组之前是不可能的。您可以在此处查看详细信息:OpenGL Wiki - Data Types