为啥 GPU 外的顶点变换与 GPU 内的顶点变换不同?

Posted

技术标签:

【中文标题】为啥 GPU 外的顶点变换与 GPU 内的顶点变换不同?【英文标题】:Why vertex transformation outside GPU is not the same vertex transformation inside GPU?为什么 GPU 外的顶点变换与 GPU 内的顶点变换不同? 【发布时间】:2017-04-16 13:25:08 【问题描述】:

我们知道,如果我们想在世界空间中绘制一些东西,我们需要将我们的数据乘以视图和投影矩阵。现在我的任务需要在着色器之外进行顶点转换并直接发送转换后的顶点。像这样:

初始化矩阵

glm::mat4 view, projection;
view = glm::lookAt(this->cameraPos, this->cameraPivot, this->Up);
projection = glm::perspective(glm::radians(60.0f), (float)screenWidth / (float)screenHeight, 0.1f, 100.0f);

代码

vector<glm::vec3> data;
glm::mat4 projection, view;
...
data.push_back(glm::vec3(projection * view * glm::vec4(0.0, 0.0, 0.5, 0.0)));
data.push_back(glm::vec3(projection * view * glm::vec4(0.0, 0.5, 0.5, 0.0)));
data.push_back(glm::vec3(projection * view * glm::vec4(0.5, 0.5, 0.5, 0.0)));
data.push_back(glm::vec3(projection * view * glm::vec4(0.5, 0.0, 0.5, 0.0)));
...
shader.set();
GLuint VAO,VBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &wVBO);
glBindVertexArray(wVAO);
glBindBuffer(GL_ARRAY_BUFFER, wVBO);
glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(vector<glm::vec3>), &data.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
...
glBindVertexArray(wVAO);
glDrawArrays(GL_LINE_LOOP, 0, data.size());
glBindVertexArray(0);

着色器

#version 330 core
layout (location = 0) in vec3 position;

void main()

    gl_Position = vec4(position, 1.0f);

但是我得到了错误的视图转换 - 看起来我的数据没有考虑投影矩阵,只考虑了视图矩阵。但是如果我像往常一样改变它:

代码

 ...
 data.push_back(glm::vec3(glm::vec4(0.0, 0.0, 0.5, 0.0)));
 ...
 shader.set();
 glUniformMatrix4fv(glGetUniformLocation(shader.Program, "matrices"), 1,
 GL_FALSE, glm::value_ptr(projection * view));

着色器

#version 330 core
layout (location = 0) in vec3 position;

uniform mat4 matrices;

void main()

    gl_Position = matrices * vec4(position, 1.0f);

它按预期工作。我的错误是什么?在我的任务中,需要知道所有顶点在世界空间中的位置,然后才能将其发送到着色器中。我怎样才能做到这一点?

【问题讨论】:

有点难以比较,当我们不知道你的顶点着色器时。 好的,一分钟! 还请显示初始化视图和投影矩阵的代码 好的,两分钟!) glm::vec4(0.0, 0.0, 0.5, 0.0)) 应该是 glm::vec4(0.0, 0.0, 0.5, 1.0)) 对于所有顶点,w 坐标应该是 1,否则没有转变会发生 【参考方案1】:

顶点的齐次坐标“w”应为 1.0f,否则不会对顶点应用任何变换。

【讨论】:

【参考方案2】:

我明白了!谢谢丹尼尔的想法!!! 在我的情况下,“w”在顶点的初始化中无关紧要。这在另一个方面很重要。 查看示例 #2 中的着色器代码:

#version 330 core
layout (location = 0) in --->vec3<--- position;

uniform mat4 matrices;

void main()

    gl_Position = matrices * vec4(position, --->1.0f<---);

在输入着色器中,我发送了 vec3,但它是错误的!我们需要保存矩阵乘法产生的“w”分量:

着色器

layout (location = 0) in vec4 position;
...
void main()

    gl_Position = matrices * position;

代码

vector<glm::vec4> data;
glm::mat4 projection, view;
...
data.push_back(projection * view * glm::vec4(0.0, 0.0, 0.5, 1.0));
...
glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(glm::vec4), &data.data(), GL_STATIC_DRAW);
....
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);

就是这样!谢谢大家!

【讨论】:

【参考方案3】:

glm::vec4 当着色器需要 4 个浮点数时,字节是 smth + 4 个浮点数。至少大小是错误的(我也怀疑数据)。这就是所有内容:问题、答案和 cmets。

【讨论】:

以上是关于为啥 GPU 外的顶点变换与 GPU 内的顶点变换不同?的主要内容,如果未能解决你的问题,请参考以下文章

glsl attributes变量怎么用

渲染管道应用阶段“顶点数据”

为啥绘图调用很昂贵?

图形流水线

如何将模型矩阵包含到 VBO?

OpenGL学习——绘制三角形