【问题标题】:OpenGL and GLM matrix doesn't scale properly, always scales downOpenGL 和 GLM 矩阵无法正确缩放,总是按比例缩小
【发布时间】:2020-10-28 22:00:32
【问题描述】:

当我使用 glm::scale 更新顶点着色器中的模型矩阵时,无论我做什么,它总是会缩小它。有人知道我在做什么错吗?图片有时也会上下翻转。

尽管代码不同,但 key == 'w' 和 key == 's' 做的事情完全相同,目标是按 W 使模型变大,按 S 使模型变小。但现在它两按都会变小。

用于根据按键进行缩放的相关代码为:

if (key == 'w') {
        model = glm::scale(model, glm::vec3(0.5, 0.5, 0.5));
        int loc = glGetUniformLocation(prog, "model");
        glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(model));
    }
    if (key == 's') {
        model = glm::scale(model, glm::vec3(-0.5, -0.5, -0.5));
        int loc = glGetUniformLocation(prog, "model");
        glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(model));
    }

整个代码是:

#include <Windows.h>
#include <GL\glew.h>
#include <GL\freeglut.h>
#include <iostream>
#include <SOIL.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "OBJ.h"

const char* vs = "#version 330 core\n"
"layout (location = 0) in vec3 pos;\n"
"layout (location = 1) in vec2 texpos;\n"
"out vec2 texCoords;\n"
"uniform mat4 model;\n"
"uniform mat4 view;\n"
"uniform mat4 projection;\n"
"void main()\n"
"{\n"
"gl_Position = projection * view * model * vec4(pos, 1);\n"
"texCoords = texpos;\n"
"}\0";

const char* fs = "#version 330 core\n"
"in vec2 texCoords;\n"
"out vec4 fragColor;\n"
"uniform sampler2D tex;\n"
"void main()\n"
"{\n"
"fragColor = texture(tex, texCoords);"
"}\0";

float verts[] = {
    0, 1, 0, 0.5, 1,
    -1, -1, 0, 0, 0,
    1, -1, 0, 1, 0
};

unsigned short indices[] = {
    0, 1, 2
};

unsigned int vao, vbo, ebo, prog, vert, frag, texid;

glm::mat4 model, view, projection;


void changeViewPort(int w, int h)
{
    glViewport(0, 0, w, h);
}

void render()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glBindVertexArray(vao);
    glBindTexture(GL_TEXTURE_2D, texid);
    glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0);
    glutSwapBuffers();
}

void initGL() {
    //Context stuff
    glViewport(0, 0, 800, 600);
    glClearColor(0.5, 0.5, 0.5, 1);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    //Shader stuff
    int success;
    prog = glCreateProgram();
    vert = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vert, 1, &vs, NULL);
    glCompileShader(vert);
    glGetShaderiv(vert, GL_COMPILE_STATUS, &success);
    std::cout << "Vertex shader " << (success ? "compiled" : "not compiled") << std::endl;

    frag = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(frag, 1, &fs, NULL);
    glCompileShader(frag);
    glGetShaderiv(frag, GL_COMPILE_STATUS, &success);
    std::cout << "Fragment shader " << (success ? "compiled" : "not compiled") << std::endl;

    glAttachShader(prog, vert);
    glAttachShader(prog, frag);

    glLinkProgram(prog);
    glUseProgram(prog);

    glGetShaderiv(prog, GL_LINK_STATUS, &success);
    std::cout << "Program " << (success ? "linked" : "not linked") << std::endl;

    glDeleteShader(vert);
    glDeleteShader(frag);
    //Vertex stuff
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glGenBuffers(1, &vbo);
    glGenBuffers(1, &ebo);

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(verts), &verts, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GL_FLOAT), 0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GL_FLOAT), (void*)(3 * sizeof(GL_FLOAT)));
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), &indices, GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    //Texture stuff
    int width, height;
    unsigned char* texData = SOIL_load_image("brick.png", &width, &height, NULL, SOIL_LOAD_RGBA);

    glGenTextures(1, &texid);
    glBindTexture(GL_TEXTURE_2D, texid);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    if (texData) {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData);
        glGenerateMipmap(GL_TEXTURE_2D);
    } else {
        std::cout << "Texture not loaded." << std::endl;
    }
    glBindTexture(GL_TEXTURE_2D, 0);
    SOIL_free_image_data(texData);

    //Matrix stuff
    //Model matrix
    model = glm::mat4(1.0f);
    model = glm::scale(model, glm::vec3(0.5, 0.5, 0.5));
    int modelMatrix = glGetUniformLocation(prog, "model");
    glUniformMatrix4fv(modelMatrix, 1, GL_FALSE, glm::value_ptr(model));
    //View matrix
    view = glm::mat4(1.0f);
    view = glm::translate(view, glm::vec3(0, 0, -3));
    int viewMatrix = glGetUniformLocation(prog, "view");
    glUniformMatrix4fv(viewMatrix, 1, GL_FALSE, glm::value_ptr(view));
    //Projection matrix, something is messing up here
    projection = glm::mat4(1.0f);
    projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);
    int projectionMatrix = glGetUniformLocation(prog, "projection");
    glUniformMatrix4fv(projectionMatrix, 1, GL_FALSE, glm::value_ptr(projection));

}

void input(unsigned char key, int x, int y) {
    if (key == 'a') {
        model = glm::translate(model, glm::vec3(-0.5, 0, 0));
        int loc = glGetUniformLocation(prog, "model");
        glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(model));
    }
    if (key == 'd') {
        model = glm::translate(model, glm::vec3(0.5, 0, 0));
        int loc = glGetUniformLocation(prog, "model");
        glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(model));
    }
    if (key == 'w') {
        model = glm::scale(model, glm::vec3(0.5, 0.5, 0.5));
        int loc = glGetUniformLocation(prog, "model");
        glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(model));
    }
    if (key == 's') {
        model = glm::scale(model, glm::vec3(-0.5, -0.5, -0.5));
        int loc = glGetUniformLocation(prog, "model");
        glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(model));
    }
    if (key == 'q') {

        model = glm::rotate(model, glm::radians(45.0f), glm::vec3(0, 0, 1));
        int loc = glGetUniformLocation(prog, "model");
        glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(model));
    }
    if (key == 'e') {

        model = glm::rotate(model, glm::radians(-45.0f), glm::vec3(0, 0, 1));
        int loc = glGetUniformLocation(prog, "model");
        glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(model));
    }
    glutPostRedisplay();
}

int main(int argc, char* argv[]) {

    // Initialize GLUT
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(800, 600);
    glutCreateWindow("OBJ Viewer");
    glutReshapeFunc(changeViewPort);
    glutDisplayFunc(render);
    glutKeyboardFunc(input);
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW error");
        return 1;
    }
    initGL();
    glutMainLoop();
    return 0;
}

【问题讨论】:

  • x*0.5 和 x*-0.5 都是按比例缩小的,不是吗?
  • 否,因为如果 x 为 1,则 1 * 0.5 = 0.5 和 1 * -0.5 = -0.5 所以前者应该按比例放大 0.5,而后者应该按比例缩小 0.5
  • 不,那样不行,我问你(x*0.5)*0.5是什么,(x*-0.5)*-0.5是什么
  • 哦,我明白你在说什么。但是如何在我的代码中解决这个问题?我应该在我的代码中进行哪些更改以使其放大半个坐标并正确缩小半个坐标?
  • 如果你想扩大规模,那么扩大规模 > 1。顺便说一句。使用负值缩放可能会导致镜像。

标签: c++ opengl matrix glm-math


【解决方案1】:

不清楚你所说的半个坐标是什么意思,但很明显你想改变一个绝对值的大小,而比例矩阵是相对于模型的。事实上,你也应该考虑当模型不在原点周围时会发生什么——模型和原点之间的空间也被缩放了!

要获得绝对尺寸变化,我建议计算模型的边界框和所需尺寸。两者的比率将进入比例函数。例如,如果模型的边界框是 (20, 10, 5),而您希望它是 (19.5, 9.5, 4.5),那么您需要 scale(20/19.5, 10/19.5, 5/4.5)。

应在每次旋转更改后计算模型的边界框。在一般情况下,您可以在 CPU 上执行此操作,遍历 CPU 转换的顶点并获取每个坐标的最小值和最大值。根据您的特殊情况,可能会有更快的方法。

【讨论】:

  • [RE:your first paragraph.] 对模型矩阵进行操作仅依赖于本地原点,这应该始终可靠。
  • 另外,您可能应该包括 如何 获取边界框。
  • 根据您的建议进行了编辑。不幸的是,您的第一条评论不相关。我遇到过模型的顶点与本地原点相比都是偏移的,所以原点不在模型内部。
  • 可以说你的原始模型矩阵应该调整它,然后比例仍然可以工作。
  • 当然,经过足够的正确类型的矩阵乘法之后,一切都会好起来的 :) 你只需要知道它就在那里。
【解决方案2】:

当您缩放模型时,您会将模型矩阵和缩放向量传递给 glm::scale 函数。当您执行model = glm::scale(model, glm::vec3(0.5, 0.5, 0.5)); 时,这意味着将您的模型大小乘以0.5,而不是相加。与-0.5 相同。这就是您的模型总是按比例缩小的原因。

据我了解,您希望您的模型在分别按“w”和“s”时按比例放大和缩小 50%。因此,只需使用 model = glm::scale(model, glm::vec3(1.5, 1.5, 1.5)); 放大,使用 model = glm::scale(model, glm::vec3(0.5, 0.5, 0.5)); 缩小。

【讨论】:

    猜你喜欢
    • 2012-02-05
    • 1970-01-01
    • 2014-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    相关资源
    最近更新 更多