如何在OpenGL中扩展模型?

Ant*_*nio 0 c++ opengl

我正在尝试在OpenGL中扩展模型,但我不知道从哪里开始,我正在尝试使用glScalef(),但我不知道是否有这种方式,我不知道很多关于openGL,我更了解理论(那我必须用矩阵乘以我的向量,但我没有找到任何关于此的好教程... ...我的代码是:

bool res = loadOBJ(object, vertices, uvs, normals);
indexVBO(vertices, uvs, normals, indices, indexed_vertices, indexed_uvs, indexed_normals);

glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, indexed_vertices.size() * sizeof(glm::vec3), &indexed_vertices[0], GL_STATIC_DRAW);


glGenBuffers(1, &uvbuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glBufferData(GL_ARRAY_BUFFER, indexed_uvs.size() * sizeof(glm::vec2), &indexed_uvs[0], GL_STATIC_DRAW);


glGenBuffers(1, &normalbuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glBufferData(GL_ARRAY_BUFFER, indexed_normals.size() * sizeof(glm::vec3), &indexed_normals[0], GL_STATIC_DRAW);

// Generate a buffer for the indices as well

glGenBuffers(1, &elementbuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned short), &indices[0], GL_STATIC_DRAW);

// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
    0,                  // attribute
    3,                  // size
    GL_FLOAT,           // type
    GL_FALSE,           // normalized?
    0,                  // stride
    (void*)0            // array buffer offset
    );

// 2nd attribute buffer : UVs
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glVertexAttribPointer(
    1,                                // attribute
    2,                                // size
    GL_FLOAT,                         // type
    GL_FALSE,                         // normalized?
    0,                                // stride
    (void*)0                          // array buffer offset
    );

// 3rd attribute buffer : normals
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glVertexAttribPointer(
    2,                                // attribute
    3,                                // size
    GL_FLOAT,                         // type
    GL_FALSE,                         // normalized?
    0,                                // stride
    (void*)0                          // array buffer offset
    );

// Index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);

glScalef(10, 10, 10);

glDrawElements(
    GL_TRIANGLES,        // mode
    indices.size(),      // count
    GL_UNSIGNED_SHORT,   // type
    (void*)0             // element array buffer offset
    );
Run Code Online (Sandbox Code Playgroud)

Exi*_*ide 6

缩放是您可以对模型矩阵进行的三种转换之一,以及平移和旋转.

模型矩阵是三个矩阵之一,它将顶点转换为屏幕上的像素,以及视图和投影矩阵.

由于您想要的缩放类型仅适用于模型矩阵,我们现在将跳过其他两个.但我建议阅读所有三个以及它们如何相互作用,因为它们对OpenGL至关重要.

在我们开始之前,我建议选择一个像GLM这样的图书馆,因为它会为我们做很多繁重的工作.从这里开始,我将使用GLM语法来保持简洁.

首先让我们将比例存储在3d矢量中:

glm::vec3 scale = glm::vec3(10f, 10f, 10f);
Run Code Online (Sandbox Code Playgroud)

现在我们需要一个没有变换的基本模型矩阵:

glm::mat4 modelMatrix = glm::mat4();
Run Code Online (Sandbox Code Playgroud)

现在我们可以将比例应用于我们的模型矩阵:

modelMatrix = glm::scale(modelMatrix, scale);
Run Code Online (Sandbox Code Playgroud)

现在我们有了一个可以应用于任何顶点集的矩阵,并在所有三个维度中将它们缩放10.

接下来,我们需要将此信息提供给着色器.就像glVertexAttribPointer告诉着色器在哪里找到顶点属性一样,我们将使用glUniform来发送我们的矩阵:

GLuint location = getUniformLocation("model");
glUniformMatrix4fv(location, 1, false, glm::value_ptr(modelMatrix));
Run Code Online (Sandbox Code Playgroud)

在这里,我们向着色器查询"模型"制服的位置.然后我们将1个统一矩阵(我们的modelMatrix)提交到该位置.

最后,我们需要在着色器中使用该矩阵.这是一个超级简单的顶点着色器,可以满足我们的需求:

#version 400 core

in vec3 position;
in vec3 normal;
in vec2 uv;
uniform mat4 model;

void main() {
    gl_Position = model * vec4(position, 1.0f);
}
Run Code Online (Sandbox Code Playgroud)

通常我们会将普通信息和uv信息传递给片段着色器,但我现在省略了它以保持简单.

这就对了.希望这能让你到达目的地.


另外,该功能glScalef在GL3及更新版本中已弃用.我喜欢使用docs.gl作为参考,因为它区分了版本.

编辑:如何构建着色器程序

我上面发布的代码只是顶点着色器的源代码,它只是更大着色器程序的一部分.着色器程序可以具有顶点着色器,几何着色器和片段着色器.现在虽然我们只关注两个必需的; 顶点和片段着色器.

首先将上面的顶点着色器代码放入一个名为的文件中vertex.glsl.加载文件超出了本答案的范围,所以我假设你有一个名为的函数loadSourceFromFile,它接受一个参数,即文件名.

在我们继续之前,让我们做一些实用功能:

function Gluint compileShader(const char* source, GLuint type) {
    GLuint shader = glCreateShader(type);
    glShaderSource(shader, source);
    glCompileShader(shader);
    return shader;
}

function void verifyShaderCompilation(GLuint shader) {
    GLunit status = glGetShaderi(shader, GL_COMPILE_STATUS);
    assert(status == GL_TRUE);
}
Run Code Online (Sandbox Code Playgroud)

现在,让我们编译该顶点着色器:

const char* vertexSource = loadSourceFromFile("vertex.glsl");
Gluint vertexShader = compileShader(vertexSource, GL_VERTEX_SHADER);
verifyShaderCompilation(vertexShader);
Run Code Online (Sandbox Code Playgroud)

接下来我们要构建片段着色器.将以下代码放入另一个名为的文件中fragment.glsl:

#version 400 core

out vec4 color;

void main()
{
    color = vec4(0, 0.5, 0, 1);
}
Run Code Online (Sandbox Code Playgroud)

此片段着色器将使其处理绿色的每个片段.现在让我们像编译顶点着色器一样编译它:

const char* fragmentSource = loadSourceFromFile("fragment.glsl");
Gluint fragmentShader = compileShader(fragmentSource, GL_FRAGMENT_SHADER);
verifyShaderCompilation(fragmentShader);
Run Code Online (Sandbox Code Playgroud)

现在我们有两个编译着色器.是时候将它们链接到一个着色器程序:

GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
Run Code Online (Sandbox Code Playgroud)

您需要在调用之前完成所有这些操作,glVertexAttribPointer因为它需要与您构建的着色器程序进行通信.

编辑:调试OpenGL函数

在尝试解决问题时,我建议在每次GL函数调用后使用以下函数:

function void verifyNoGLError() {
    int errorCode = glGetError();
    assert(errorCode == 0);
}
Run Code Online (Sandbox Code Playgroud)

OpenGL是一个复杂的状态机,一旦出现问题,你就会想知道.