c++ - 替换为 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

标签 c++ opengl glsl

有几个这样的问题,但我还是没有真正理解。我在 10 多年前使用 OpenGL 进行编码,并注意到进入现代 OpenGL 是多么困难。 OpenGL.org 页面在示例方面一团糟,您永远不知道它是什么版本,任何版本似乎都混在各种代码示例中。 好吧,我有一个旧代码,我想至少更新到 OpenGL >3。所以我做的第一件事就是从 glVertex3fv 继续前进,最终使用 glVertexAttribPointer 实现它(在我读到它现在也被弃用之前,使用 glVertexPointer 进行了一步)。这很好用,但是当尝试放置纹理时我很快就卡住了,我认为这是因为定位错误,我想摆脱 C++ 代码:

glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glFrustum( -RProjZ, +RProjZ, -Aspect*RProjZ, +Aspect*RProjZ, 1.0, 32768.0 );

然后画出来

// bind vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, VertBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * size, verts, GL_STATIC_DRAW);

// enable arrays
glEnableVertexAttribArray(0); 

// set pointers
glVertexAttribPointer(0,3,GL_FLOAT, GL_FALSE, sizeof(float) * floatsPerVertex, 0);

// render ComplexSurface
glDrawArrays(GL_TRIANGLE_FAN, 0, size);
glDisableVertexAttribArray(0);

在顶点着色器中

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 

一切都在神奇地运作。现在不要误会我的意思,我是魔法的忠实粉丝,但是...... 然后我发现了几个矩阵转换,可以用来得到一个矩阵来替换 glFrustum,但是每当我尝试替换它时,它都会严重失败(尽管我认为我理解 glFrustum 背后的数学和矩阵的转换)。

试过的是这样的

buildPerspProjMat(g_ProjView,FovAngle,Aspect,1.0,32768.0 );

glUseProgram(g_program);
glUniformMatrix4fv(g_programFrustum, 1, GL_FALSE, g_ProjView );
glUseProgram(0);

并使用来自上述缓冲区的着色器中的位置和投影矩阵,但这根本行不通。

所以我现在不清楚的是在哪里替换它以及用着色器中的什么替换它。我不知道 glMatrixMode 发生在什么时候以及“何时”用一些统一矩阵替换它(将 args 作为统一传递不是这里的问题)。 我无法计算我已经阅读了多少教程,但我总是对所有混合版本感到困惑。我总是对一些代码示例很满意,但请使用 OpenGL 3 或更高版本。

下一个将是替代 glTexCoord2f 的纹理,但那是另一回事 :)

最佳答案

我发现在考虑现代 OpenGL 时最好忘记 glMatrixMode 曾经存在过。

考虑到这一点,让我们回顾一下最基本的绘制操作所需的内容:gl_ModelViewProjectionMatrix 的替代品。顾名思义,这是 3 个不同矩阵的组合:模型矩阵、 View 矩阵和投影矩阵。

因此,您需要在着色器中容纳 3 个 mat4 类型的统一变量。你会像这样使用它:

uniform mat4 projMat;
uniform mat4 viewMat;
uniform mat4 modelMat;

layout (location = 0) in vec3 position;

void main()
{
    gl_Position = projMat * viewMat * modelMat * vec4(position, 1.0);
}

这段着色器代码执行与上面代码相​​同的功能。改变的是内置的 gl_ModelViewProjectionMatrix 被 3 个统一变量取代(如果您确保在传入之前在 C++ 端自己将它们相乘,则可以将它们合并为一个)。并且内置的 gl_Vertex 被一个输入变量所取代。

在 C++ 方面,您需要做两件事。首先,您需要获取这些制服中每一个的位置:

GLuint modelMatIdx = glGetUniformLocation(shaderProgId, "modelMat");
GLuint viewMatIdx = glGetUniformLocation(shaderProgId, "viewMat");
GLuint projMatIdx = glGetUniformLocation(shaderProgId, "projMat");

有了这个,您现在可以在使用 glUniformMatrix4fv 绘制之前传递每个制服的值。

一个使这特别容易的特定库是 glm .例如,要获得与您的示例相同的投影矩阵:

glm::mat4 projMat = glm::frustum(-RProjZ, +RProjZ, -Aspect*RProjZ, +Aspect*RProjZ, 1.0, 32768.0);

你会像这样传递它:

glUniformMatrix4fv(projMatIdx, 1, GL_FALSE, glm::value_ptr(projMat));

现在您已经知道怎么做了,我想谈谈“何时”的问题。你说你不清楚矩阵模式的东西,这让我回到了我之前的“忘掉它”的断言。矩阵模式在那里,因此您可以告诉 opengl 哪个内置应该受到调用 OpenGL 矩阵操作(如 glTranslate、glFrustum 等)的影响,但现在所有这些都消失了。您现在负责管理所涉及的(可能很多)矩阵。您所要做的就是在绘制之前将它们传递进来(如上所示),您会没事的。在尝试修改其制服之前,只需确保该程序已绑定(bind)。

这是一个工作示例(如果您对 gl::... 而不是 gl... 感到惊讶,那是因为我使用的是 glLoadGen 生成的 opengl header ,它将所有 opengl API 函数放在 gl 命名空间中).

GLuint simpleProgramID;
// load the shader and make the program

GLuint modelMatIdx = gl::GetUniformLocation(simpleProgramID, "modelMat");
GLuint viewMatIdx = gl::GetUniformLocation(simpleProgramID, "viewMat");
GLuint projMatIdx = gl::GetUniformLocation(simpleProgramID, "projMat");

GLuint vaoID;
gl::GenVertexArrays(1, &vaoID);
gl::BindVertexArray(vaoID);

GLuint vertBufferID, indexBufferID;
gl::GenBuffers(1, &vertBufferID);
gl::GenBuffers(1, &indexBufferID);

struct Vec2 { float x, y; };
struct Vec3 { float x, y, z; };
struct Vert { Vec3 pos; Vec2 tex; };

std::array<Vert, 8> cubeVerts = {{
    { {  0.5f,  0.5f,  0.5f }, { 1.0f, 0.0f } }, { {  0.5f,  0.5f, -0.5f }, { 1.0f, 1.0f } },
    { {  0.5f, -0.5f, -0.5f }, { 0.0f, 1.0f } }, { {  0.5f, -0.5f,  0.5f }, { 0.0f, 0.0f } },
    { { -0.5f,  0.5f,  0.5f }, { 0.0f, 0.0f } }, { { -0.5f,  0.5f, -0.5f }, { 0.0f, 1.0f } },
    { { -0.5f, -0.5f, -0.5f }, { 1.0f, 1.0f } }, { { -0.5f, -0.5f,  0.5f }, { 1.0f, 0.0f } }
}};

std::array<unsigned int, 36> cubeIdxs = {{ 
    0, 2, 1, 0, 3, 2, // Right
    4, 5, 6, 4, 6, 7, // Left
    0, 7, 3, 0, 4, 7, // Top
    1, 6, 2, 1, 5, 6, // Bottom
    0, 5, 1, 0, 4, 5, // Front
    3, 7, 6, 3, 6, 2  // Back
}};

// Vertex buffer
gl::BindBuffer(gl::ARRAY_BUFFER, vertBufferID);
gl::BufferData(gl::ARRAY_BUFFER, sizeof(Vert) * cubeVerts.size(), cubeVerts.data(), gl::STATIC_DRAW);
gl::EnableVertexAttribArray(0); // Matches layout (location = 0)
gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE_, sizeof(Vert), 0);
gl::EnableVertexAttribArray(1); // Matches layout (location = 1)
gl::VertexAttribPointer(1, 2, gl::FLOAT, gl::FALSE_, sizeof(Vert), (GLvoid*)sizeof(Vec3));

// Index buffer
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, indexBufferID);
gl::BufferData(gl::ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * cubeIdxs.size(), cubeIdxs.data(), gl::STATIC_DRAW);
gl::BindVertexArray(0);

glm::mat4 projMat = glm::perspective(56.25f, 16.0f/9.0f, 0.1f, 100.0f);
glm::mat4 viewMat = glm::lookAt(glm::vec3(5, 5, 5), glm::vec3(0, 0, 0), glm::vec3(0, 0, 1));
glm::mat4 modelMat; // identity

while (!glfwWindowShouldClose(window))
{
    gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);

    gl::UseProgram(simpleProgramID);
    gl::UniformMatrix4fv(projMatIdx, 1, gl::FALSE_, glm::value_ptr(projMat));
    gl::UniformMatrix4fv(viewMatIdx, 1, gl::FALSE_, glm::value_ptr(viewMat));
    gl::UniformMatrix4fv(modelMatIdx, 1, gl::FALSE_, glm::value_ptr(modelMat));

    gl::BindVertexArray(vaoID);
    gl::DrawElements(gl::TRIANGLES, 36, gl::UNSIGNED_INT, 0);
    gl::BindVertexArray(0);

    gl::UseProgram(0);

    glfwSwapBuffers(window);
    glfwPollEvents();
}

关联的顶点着色器:

//[VERTEX SHADER]
#version 430

uniform mat4 projMat;
uniform mat4 viewMat;
uniform mat4 modelMat;

layout (location = 0) in vec3 in_position; // matches gl::EnableVertexAttribArray(0);
layout (location = 1) in vec2 in_uv; // matches gl::EnableVertexAttribArray(1);

out vec2 uv;

void main()
{
    gl_Position = projMat * viewMat * modelMat * vec4(in_position, 1.0);
    uv = in_uv;
}

最后是片段着色器:

//[FRAGMENT SHADER]
#version 430

in vec2 uv;

out vec4 color;

void main()
{
    color = vec4(uv, 0.0, 1.0);
}

生成的图像是:

enter image description here

关于c++ - 替换为 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21980947/

相关文章:

math - 如何在 OpenGL 着色器中使用行专业?

glsl - 如何在 GLSL 中复制数组?

c++ - LLVM:如何将 IR 写入文件并运行它?

c++ - argv[] 分配了多少内存?

c++ - boost::asio:发送到套接字的数据排序

c++ - OpenGL 和 GLM : How to send a matrices array to GLSL

c++ - 如何正确绑定(bind)2个纹理

c++ - 在 C++ 中初始化数组

c++ - 在OpenGL中实现自己的旋转功能

opengl - 如何在 CLion 中添加 OpenGL 库?