我正在穿一个C++的OpengL程序和GLSL顶点和片段着色器。
我正在创建同一对象的多个实例。我只需要在实例之间更改对象位置。
这是我所做的:我正在使用一个统一变量,它是一个转换矩阵数组。每个矩阵代表一个对象实例。
MVP 也是一个转换矩阵,但 MVP 由摄像机位置、方向和属性设置。
这是我的顶点着色器:
#version 330 core
layout(location = 0) in vec3 vertex_position;
layout(location = 1) in vec3 vertex_color;
uniform mat4 object_positions[20];
out vec3 fragment_color;
uniform mat4 MVP;
void main()
{
gl_Position = object_positions[gl_InstanceID] * MVP * vec4(vertex_position,1.0);
fragment_color = vertex_color;
}
这是我C++程序中设置对象位置所必须做的事情:
glm::mat4 object_positions[20];
object_positions[0] = glm::translate(glm::mat4(1), glm::vec3(0.4f,0.2f,0.0f));
object_positions[1] = glm::translate(glm::mat4(1), glm::vec3(0.5f,1.4f,0.0f));
...
object_positions[19] = glm::translate(glm::mat4(1), glm::vec3(-10.6f,0.2f,0.0f));
GLuint object_positions_id = glGetUniformLocation(program_id, "object_positions");
...
glUniformMatrix4fv(object_positions_id, 7, GL_FALSE, glm::value_ptr(object_positions[0]));
您看到的 glm::translate 的第二个参数 vec3 包含每个对象位置。在这一点上,一切都很好。
我想做的是在着色器中计算 glm::translte。实际上,我想要的是为每个位置发送一个 vec3 而不是一个 mat4。我希望 GPU 而不是 CPU 计算转换矩阵。我尝试的所有方法都不起作用。
谢谢
4*4 矩阵如下所示:
c0 c1 c2 c3 c0 c1 c2 c3
[ Xx Yx Zx Tx ] [ 0 4 8 12 ]
[ Xy Yy Zy Ty ] [ 1 5 9 13 ]
[ Xz Yz Zz Tz ] [ 2 6 10 14 ]
[ 0 0 0 1 ] [ 3 7 11 15 ]
在 GLSL 中,mat4 m;
的列是这样寻址的:
vec4 c0 = m[0].xyzw;
vec4 c1 = m[1].xyzw;
vec4 c2 = m[2].xyzw;
vec4 c3 = m[3].xyzw;
您可以在顶点着色器中设置mat4
,如下所示:
#version 330 core
layout(location = 0) in vec3 vertex_position;
layout(location = 1) in vec3 vertex_color;
out vec3 fragment_color;
uniform mat4 MVP;
uniform vec3 object_positions[20];
void main()
{
mat4 posMat = mat4(
vec4( 1.0, 0.0, 0.0, 0.0),
vec4( 0.0, 1.0, 0.0, 0.0),
vec4( 0.0, 0.0, 1.0, 0.0),
vec4( object_positions[gl_InstanceID], 1.0) );
gl_Position = MVP * posMat * vec4(vertex_position,1.0);
fragment_color = vertex_color;
}
但是,如果您只想通过偏移来操作顶点位置,则不需要转换矩阵。您可以简单地将偏移添加到顶点位置(前提是偏移量是笛卡尔坐标而不是齐次坐标,如您的情况):
void main()
{
gl_Position = MVP * vec4(object_positions[gl_InstanceID] + vertex_position, 1.0);
fragment_color = vertex_color;
}
你必须像这样设置制服:
glm::vec3 object_positions[20];
object_positions[0] = glm::vec3(0.4f,0.2f,0.0f);
object_positions[1] = glm::vec3(0.5f,1.4f,0.0f);
...
object_positions[19] = glm::vec3(-10.6f,0.2f,0.0f);
GLuint object_positions_id = glGetUniformLocation(program_id, "object_positions");
...
glUniform3fv(object_positions_id, 20, glm::value_ptr(object_positions[0]));
进一步查看:
- GLSL 4×4 矩阵字段
- GLSL 编程/向量和矩阵运算
- 数据类型 (GLSL)
对于 OpenGL 来说,变换矩阵只是包含 16 个条目的一维数组(说到 4X4 矩阵)。在此矩阵中,第 13、14、15 个条目定义了您的翻译组件。因此,如果您将矩阵存储在第 4 行主要形式的第 4 行中,第 0、第 1 和第 2 个条目应该是您要发送到着色器的矢量 x、y、z 分量。您可以通过这种方式在着色器中构建翻译矩阵。请确保您有行主矩阵,那么要转换顶点,您需要通过矩阵预乘以查看平移的效果。
gl_Position = Translation Matrix * gl_Vertex;
如果您的矩阵是列主矩阵,您将发布乘法。
你绝对不能做object_positions[gl_InstanceID] * MVP * vec4(vertex_position,1.0);
(即使object_positions是矩阵),因为这会在应用投影矩阵后进行转换。
如果您没有对实例进行任何轮换,则没有理由不这样做
gl_Position = MVP * vec4(vertex_position + object_positions[gl_InstanceID],1.0);