- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我目前创建了两个 SSBO 来处理一些光线,因为 VS-FS in
out
接口(interface)无法处理很多光线(我使用的是正向着色)。对于第一个,我只将值传递给着色器(基本上是只读的)[cpp]:
struct GLightProperties
{
unsigned int numLights;
LightProperties properties[];
};
...
glp = (GLightProperties*)malloc(sizeof(GLightProperties) + sizeof(LightProperties) * lastSize);
...
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLightProperties) + sizeof(LightProperties) * lastSize, glp, GL_DYNAMIC_COPY);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
着色器文件[GLSL]:
layout(std430, binding = 1) buffer Lights
{
uint numLights;
LightProperties properties[];
}lights;
因此,第一个 SSBO 运行良好。然而,在另一个目的是 VS-FS 接口(interface)的情况下,存在一些问题:
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo2);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * 4 * 3 * lastSize, nullptr, GL_DYNAMIC_COPY);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
GLSL:
struct TangentProperties
{
vec4 TangentLightPos;
vec4 TangentViewPos;
vec4 TangentFragPos;
};
layout(std430, binding = 0) buffer TangentSpace
{
TangentProperties tangentProperties[];
}tspace;
所以在这里你注意到我将 nullptr
传递给 glBufferData
因为 vs 将写入缓冲区而 fs 将读取其内容。就像在 VS 阶段一样:
for(int i = 0; i < lights.numLights; i++)
{
tspace.tangentProperties[index].TangentLightPos.xyz = TBN * lights.properties[index].lightPosition.xyz;
tspace.tangentProperties[index].TangentViewPos.xyz = TBN * camPos;
tspace.tangentProperties[index].TangentFragPos.xyz = TBN * vec3(worldPosition);
memoryBarrierBuffer();
}
在此之后,FS 读取值,结果证明这些值只是垃圾。我在内存障碍方面做错了吗?
最佳答案
好吧,让我们把明显的错误排除在外:
for(int i = 0; i < lights.numLights; i++)
{
tspace.tangentProperties[index].TangentLightPos.xyz = TBN * lights.properties[index].lightPosition.xyz;
tspace.tangentProperties[index].TangentViewPos.xyz = TBN * camPos;
tspace.tangentProperties[index].TangentFragPos.xyz = TBN * vec3(worldPosition);
memoryBarrierBuffer();
}
index
在此循环中永远不会改变,因此您只写了一个灯,并且只写了最后 个灯的值。所有其他灯将具有垃圾/未定义的值。
所以你的意思可能是 i
而不是 index
。
但这只是问题的开始。看,如果你做了那个改变,你会得到这个:
for(int i = 0; i < lights.numLights; i++)
{
tspace.tangentProperties[i].TangentLightPos.xyz = TBN * lights.properties[i].lightPosition.xyz;
tspace.tangentProperties[i].TangentViewPos.xyz = TBN * camPos;
tspace.tangentProperties[i].TangentFragPos.xyz = TBN * vec3(worldPosition);
}
memoryBarrierBuffer();
注意屏障在循环之外。
这会产生一个新问题。此代码将使每个顶点着色器调用写入相同的内存缓冲区。毕竟,SSBO 不是 VS 输出变量。输出变量存储为顶点的一部分。然后,光栅化器在光栅化图元时将此顶点数据插值到图元中,这提供了 the input values。对于FS。所以一个 VS 不能踩踏另一个 VS 的输出变量。
SSBO 不会发生这种情况。每个 VS 都作用于相同 SSBO 内存。因此,如果他们写入同一数组的相同索引,那么他们就是在写入相同的内存地址。这是一个竞争条件(因为兄弟调用之间不能同步),因此是未定义的行为。
因此,您尝试做的唯一方法可能会起作用,如果您的缓冲区在整个场景中的每个顶点都有 numLights
条目.
这是一个根本不合理的空间量。即使您可以将其降低到特定绘图调用中的顶点数量(这是可行的,但我不打算说明如何实现),您仍然会在性能上落后。每次 FS 调用都必须为每盏灯读取 144 字节的数据(3 个表条目,三角形的每个顶点一个),对这些值进行线性插值,然后进行光照计算。 p>
将 TBN 矩阵作为 VS 输出传递并在 FS 中进行矩阵乘法对您来说会更快。是的,这是很多矩阵乘法,但 GPU 在矩阵乘法上非常快,并且在读取内存时非常慢。
另外,重新考虑您是否需要切线空间片段位置。一般来说,您永远不会这样做。
关于c++ - OpenGL 着色器存储缓冲区/memoryBarrierBuffer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52515023/
我目前创建了两个 SSBO 来处理一些光线,因为 VS-FS in out 接口(interface)无法处理很多光线(我使用的是正向着色)。对于第一个,我只将值传递给着色器(基本上是只读的)[cpp
我是一名优秀的程序员,十分优秀!