计算着色器统一优化不当?
Compute shader uniform optimized away improperly?
获取制服的位置'uniform Sphere spheres[10]'(通过 glGetUniformLocation(program, name))。 Return -1 即使程序中还有其他制服 (frustum_planes) 也有效。
frustum_planes和球体制服也用在相同的地方,这使得两者中只有一个存在很奇怪。
知道可能出了什么问题吗?
着色器
#version 460 core
// Required by compute shaders apparently
// Process one object per shader invocation (optimisation?)
layout (local_size_x = 1) in;
struct Sphere {
vec3 center;
float radius;
};
uniform Sphere spheres[10];
// Plane defined as: Ax + By + Cz = D
uniform vec4 frustum_planes[6];
uint test(Sphere obj, vec4 plane) {
const float distance = plane.x * obj.center.x + plane.y * obj.center.y + plane.z * obj.center.z + plane.w;
if (distance < -obj.radius) {
return 0; // Negative halfspace
}
return 1; // Positive halfspace or on the plane
}
/// Same as the OpenGL provided struct: DrawElementsIndirectCommand
struct DrawCommand {
uint count; // Num elements (vertices)
uint instanceCount; // Number of instances to draw (a.k.a primcount)
uint firstIndex; // Specifies a byte offset (cast to a pointer type) into the buffer bound to GL_ELEMENT_ARRAY_BUFFER to start reading indices from.
uint baseVertex; // Specifies a constant that should be added to each element of indices when chosing elements from the enabled vertex arrays.
uint baseInstance; // Specifies the base instance for use in fetching instanced vertex attributes.
// 20 bytes
uint padding0;
uint padding1;
uint padding2;
// 32 bytes (multiple of 16)
};
// One draw command per object
// Command buffer backed by Shader Storage Object Buffer (SSBO)
layout(std140, binding = 0) writeonly buffer DrawCommandsBlock {
DrawCommand draw_commands[];
};
void main() {
const uint idx = gl_GlobalInvocationID.x;
uint inside = 0;
for (int i = 0; i < 6; i++) {
inside += test(spheres[idx], frustum_planes[i]) << i;
}
const uint INSIDE_ALL_PLANES = 63; // = 0b111111;
const bool visible = inside == INSIDE_ALL_PLANES;
draw_commands[idx].count = 25350; // sphere.indices.size();
draw_commands[idx].instanceCount = visible ? 1 : 0; // This is the trick right here
draw_commands[idx].baseInstance = 0;
draw_commands[idx].baseVertex = 0;
draw_commands[idx].padding0 = 0; // Avoid optimisation
draw_commands[idx].padding1 = 0;
draw_commands[idx].padding2 = 0;
}
正在调用 glGetUniformLocation
glGetUniformLocation(gl_state.cull_shader.gl_program, "spheres[0].center");
main.cpp
glUseProgram(gl_state.cull_shader.gl_program);
if (glGetUniformLocation(gl_state.cull_shader.gl_program, "frustum_planes") == -1) {
std::cerr << "Work!" << std::endl;
}
if (glGetUniformLocation(gl_state.cull_shader.gl_program, "spheres") == -1) {
std::cerr << "Does not work?!" << std::endl;
}
glUniform4fv(glGetUniformLocation(gl_state.cull_shader.gl_program, "spheres"), NUM_OBJECTS, &bounding_volumes[0].pos.x);
glUniform4fv(glGetUniformLocation(gl_state.cull_shader.gl_program, "frustum_planes"), 6, glm::value_ptr(frustum[0]));
glDispatchCompute(NUM_OBJECTS, 1, 1);
glMemoryBarrier(GL_COMMAND_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT); // Buffer objects affected by this bit are derived from the GL_DRAW_INDIRECT_BUFFER binding.
无法查询非基本类型或基本类型数组的制服位置。 OpenGL Wiki 状态:
The introspection APIs will often make a single "variable" definition in GLSL appear as though it were multiple variables. This is done for variables that are not basic types or arrays of basic types (note that in GLSL, "basic types" include vector and matrix types).
...
Instead, each sub-element of the struct that is a basic type is visible.
这意味着,您不能查询spheres
(或spheres[0]
)。您要做的是分别查询每个结构的每个成员。为了获得第一个球体中心的位置,您必须查询 spheres[0].center
.
请注意,查询 frustum_planes
按预期工作,因为它是一个 vec4 数组(这是一种基本类型)。
获取制服的位置'uniform Sphere spheres[10]'(通过 glGetUniformLocation(program, name))。 Return -1 即使程序中还有其他制服 (frustum_planes) 也有效。
frustum_planes和球体制服也用在相同的地方,这使得两者中只有一个存在很奇怪。
知道可能出了什么问题吗?
着色器
#version 460 core
// Required by compute shaders apparently
// Process one object per shader invocation (optimisation?)
layout (local_size_x = 1) in;
struct Sphere {
vec3 center;
float radius;
};
uniform Sphere spheres[10];
// Plane defined as: Ax + By + Cz = D
uniform vec4 frustum_planes[6];
uint test(Sphere obj, vec4 plane) {
const float distance = plane.x * obj.center.x + plane.y * obj.center.y + plane.z * obj.center.z + plane.w;
if (distance < -obj.radius) {
return 0; // Negative halfspace
}
return 1; // Positive halfspace or on the plane
}
/// Same as the OpenGL provided struct: DrawElementsIndirectCommand
struct DrawCommand {
uint count; // Num elements (vertices)
uint instanceCount; // Number of instances to draw (a.k.a primcount)
uint firstIndex; // Specifies a byte offset (cast to a pointer type) into the buffer bound to GL_ELEMENT_ARRAY_BUFFER to start reading indices from.
uint baseVertex; // Specifies a constant that should be added to each element of indices when chosing elements from the enabled vertex arrays.
uint baseInstance; // Specifies the base instance for use in fetching instanced vertex attributes.
// 20 bytes
uint padding0;
uint padding1;
uint padding2;
// 32 bytes (multiple of 16)
};
// One draw command per object
// Command buffer backed by Shader Storage Object Buffer (SSBO)
layout(std140, binding = 0) writeonly buffer DrawCommandsBlock {
DrawCommand draw_commands[];
};
void main() {
const uint idx = gl_GlobalInvocationID.x;
uint inside = 0;
for (int i = 0; i < 6; i++) {
inside += test(spheres[idx], frustum_planes[i]) << i;
}
const uint INSIDE_ALL_PLANES = 63; // = 0b111111;
const bool visible = inside == INSIDE_ALL_PLANES;
draw_commands[idx].count = 25350; // sphere.indices.size();
draw_commands[idx].instanceCount = visible ? 1 : 0; // This is the trick right here
draw_commands[idx].baseInstance = 0;
draw_commands[idx].baseVertex = 0;
draw_commands[idx].padding0 = 0; // Avoid optimisation
draw_commands[idx].padding1 = 0;
draw_commands[idx].padding2 = 0;
}
正在调用 glGetUniformLocation
glGetUniformLocation(gl_state.cull_shader.gl_program, "spheres[0].center");
main.cpp
glUseProgram(gl_state.cull_shader.gl_program);
if (glGetUniformLocation(gl_state.cull_shader.gl_program, "frustum_planes") == -1) {
std::cerr << "Work!" << std::endl;
}
if (glGetUniformLocation(gl_state.cull_shader.gl_program, "spheres") == -1) {
std::cerr << "Does not work?!" << std::endl;
}
glUniform4fv(glGetUniformLocation(gl_state.cull_shader.gl_program, "spheres"), NUM_OBJECTS, &bounding_volumes[0].pos.x);
glUniform4fv(glGetUniformLocation(gl_state.cull_shader.gl_program, "frustum_planes"), 6, glm::value_ptr(frustum[0]));
glDispatchCompute(NUM_OBJECTS, 1, 1);
glMemoryBarrier(GL_COMMAND_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT); // Buffer objects affected by this bit are derived from the GL_DRAW_INDIRECT_BUFFER binding.
无法查询非基本类型或基本类型数组的制服位置。 OpenGL Wiki 状态:
The introspection APIs will often make a single "variable" definition in GLSL appear as though it were multiple variables. This is done for variables that are not basic types or arrays of basic types (note that in GLSL, "basic types" include vector and matrix types).
...
Instead, each sub-element of the struct that is a basic type is visible.
这意味着,您不能查询spheres
(或spheres[0]
)。您要做的是分别查询每个结构的每个成员。为了获得第一个球体中心的位置,您必须查询 spheres[0].center
.
请注意,查询 frustum_planes
按预期工作,因为它是一个 vec4 数组(这是一种基本类型)。