使用 GLSL 直接从着色器中的位置计算转换矩阵



我正在穿一个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);

最新更新