c++ - 使用 GLSL 直接在着色器中从位置计算平移矩阵

标签 c++ opengl glsl glm-math coordinate-transformation

我正在研究 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;
}


但是,如果您只想通过偏移 来操纵顶点位置,则不需要转换矩阵。您可以简单地将 offset 添加到顶点位置(前提是 offset 是笛卡尔坐标而不是齐次坐标,如您的情况):

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]));


进一步查看:

关于c++ - 使用 GLSL 直接在着色器中从位置计算平移矩阵,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46776217/

相关文章:

c++ - Cuda - 从设备全局内存复制到纹理内存

java - 过多的native调用并不影响速度

java - 在 Pi 3 B+ 上使用 Processing Pi 的 GLSL 着色器

c++ - 使用深度缓冲区 : horribly inaccurate? 进行光线拾取

c++ - stb 图像加载库返回白色纹理

c++ - 处理多个灯光和 GLSL 着色器程序

c++ - GLSL - 统一缓冲对象奇怪的行为

c++ - 将字符串文字传递给采用 std::string& 的函数

C++ 映射删除(开始、结束)不起作用

c++ - 为什么 QCoreApplication 在 Unix/Linux 上默认调用 `setlocale(LC_ALL, "")`?