You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenGL C++透视投影异常问题求助(已解决附方案)

3D立方体透视投影渲染问题

我尝试在窗口中渲染3D立方体并观察透视投影效果:在顶点Shader中不乘以投影矩阵时,立方体可正常渲染但无透视效果;乘以透视投影矩阵后,立方体出现过度放大现象或窗口直接显示黑屏。

原始代码

顶点Shader

//Vertex Shader
#version 420 core

layout (location = 0) in vec3 pos;

out vec4 col;

uniform mat4 model;
uniform mat4 projection;

void main(){
    gl_Position = model * projection * vec4(pos,1.0f);
    col = vec4(clamp(pos, 0.1f, 100.0f), 1.0f);
}

main.cpp

#include <iostream>
#include <vector>
#include <stdio.h>

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include <GLM/glm.hpp>
#include <GLM/gtc/matrix_transform.hpp>
#include <GLM/gtc/type_ptr.hpp>

#include "Window.h"
#include "Shader.h"
#include "Buffers.h"
#include "Camera.h"
Window window;
std::vector<Buffers*> bufferList;
std::vector<Shader> shaderList;

static const char* vShader = "Shaders/shader.vert";
static const char* fShader = "Shaders/shader.frag";


void CreateObjects() {


    GLfloat Cubevertices[] = {
        1.0f,1.0f,1.0f,      //0
        -1.0f,1.0f,1.0f,     //1
        1.0f,-1.0f,1.0f,     //2
        -1.0f,-1.0f,1.0f,    //3
        1.0f,1.0f,-1.0f,     //4
        -1.0f,1.0f,-1.0f,    //5 
        -1.0f,-1.0f,-1.0f,   //6
        1.0f,-1.0f,-1.0f,    //7
    };

    unsigned int Cubeindices[] = {
        0,1,3,
        3,0,2,
        3,2,6,
        6,7,2,
        1,3,5,
        5,6,3,
        0,1,4,
        4,5,1,
        2,0,7,
        7,4,0,
        5,6,4,
        4,7,6
    };



    Buffers* obj1 = new Buffers();
    obj1->CreateBuffer(Cubevertices, Cubeindices, 24, 36);  //24 36
    bufferList.push_back(obj1);

}

void CreateShaders() {
    Shader* shader1 = new Shader();
    shader1->createFromFiles(vShader, fShader);
    shaderList.push_back(*shader1);
}


GLfloat toRad = 3.14159265359f/180.0f;

GLfloat r_angle = 0.0f;

bool direction = true;
float offset = 0.0f;
float maxoffset = 0.7f;
float inc = 0.0005f;

float cursize = 0.5f;
bool sizedir = true;

int main() {
    window = Window(500, 500, "Cube");
    window.Initialize();

    CreateObjects();
    CreateShaders();

    GLuint u_model = 0, u_project = 0, u_view = 0;
    glm::mat4 projection = glm::perspective(glm::radians(10.0f), (GLfloat)window.getBufferWidth() / window.getBufferHeight(), 1.0f, 100.0f);

    while (!window.windowClose()) {
        glfwPollEvents();
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);


        glEnable(GL_DEPTH_TEST);
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

        shaderList[0].UseShader();
        u_model = shaderList[0].getUniformModelLocation();
        u_project = shaderList[0].getProjectionModelLocation();

        glm::mat4 model(1.0f);

        //TRANSLATION
        if (direction) {
            offset += inc;
        }
        else {
            offset -= inc;
        }
        if (abs(offset) >= maxoffset) {
            direction = !direction;
        }



        model = glm::scale(model, glm::vec3(0.3f, 0.3f, 0.3f));
        model = glm::translate(model, glm::vec3(0.0f, offset, 0.0f));
        model = glm::rotate(model, toRad*45.0f, glm::vec3(1.0f, 1.0f, 1.0f));
        glUniformMatrix4fv(u_project, 1, GL_FALSE, glm::value_ptr(projection));
        glUniformMatrix4fv(u_model, 1, GL_FALSE, glm::value_ptr(model));
        bufferList[0]->Render();
        window.swapBuffers();

    }
    return 0;
}

已解决

透视投影中相机默认位于原点,需将立方体沿-Z轴平移才能正常观察。以下是修正后的代码及渲染效果:

修正后的顶点Shader

#version 330

layout (location = 0) in vec3 pos;

out vec4 vCol;

uniform mat4 model;
uniform mat4 projection;

void main(){
    gl_Position = projection * model * vec4(pos,1.0);
    vCol = vec4(clamp(pos,0.0f,1.0f),1.0f);
}

修正后的main.cpp

#include <stdio.h>
#include <string.h>
#include <cmath>
#include <vector>

#include <GL\glew.h>
#include <GLFW\glfw3.h>

#include <glm\glm.hpp>
#include <glm\gtc\matrix_transform.hpp>
#include <glm\gtc\type_ptr.hpp>

#include "Window.h"
#include "Mesh.h"
#include "Shader.h"

Window mainWindow;
std::vector<Mesh*> meshList;
std::vector<Shader> shaderList;

static const char* vShader = "Shaders/shader.vert";
static const char* fShader = "Shaders/shader.frag";

void CreateObjects() {
    unsigned int indices[] = {
        0,1,2,
        2,3,0,
        4,5,6,
        6,7,4,
        1,6,5,
        5,2,1,
        7,0,3,
        3,4,7,
        3,2,5,
        5,4,3,
        7,6,1,
        1,0,7
    };

    GLfloat vertices[] = {
         -0.5f,-0.5f,-0.5f,
            -0.5f,0.5f,-0.5f,
             0.5f,0.5f,-0.5f,
             0.5f,-0.5f,-0.5f,
             0.5f,-0.5f,0.5f,
             0.5f,0.5f,0.5f,
            -0.5f,0.5f,0.5f,
            -0.5f,-0.5f,0.5f
    };

    Mesh* obj = new Mesh();
    obj->CreateMesh(vertices, indices, 24, 36);
    meshList.push_back(obj);
}

void CreateShader() {
    Shader* shader = new Shader();
    shader->CreateFromFiles(vShader, fShader);
    shaderList.push_back(*shader);
}

GLfloat r_angle = 0.0f;

int main() {
    mainWindow = Window(800, 600);
    mainWindow.Initialize();

    CreateObjects();
    CreateShader();

    GLuint uniformProjection = 0, uniformModel = 0;
    glm::mat4 projection = glm::perspective(glm::radians(45.0f), (GLfloat)mainWindow.getBufferWidth() / mainWindow.getBufferHeight(), 0.1f, 100.0f);

    while (!mainWindow.getShouldClose()) {
        glfwPollEvents();

        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        shaderList[0].UseShader();

        uniformModel = shaderList[0].GetModelLocation();
        uniformProjection = shaderList[0].GetProjectionLocation();

        r_angle += 0.05f;
        if (r_angle >= 360)
        {
            r_angle -= 360;
        }

        glm::mat4 model(1.0f);
        model = glm::translate(model, glm::vec3(0.0f, 0.0f, -2.0f));
        model = glm::rotate(model, glm::radians(r_angle), glm::vec3(0.0f, 1.0f, 0.0f));
         
        glUniformMatrix4fv(uniformModel, 1, GL_FALSE, glm::value_ptr(model));
        glUniformMatrix4fv(uniformProjection, 1, GL_FALSE, glm::value_ptr(projection));

        meshList[0]->RenderMesh();

        glUseProgram(0);

        mainWindow.swapBuffers();
    }

    return  0;
}

渲染效果

可正常显示带透视投影的旋转立方体,远处的面尺寸更小,近处的面尺寸更大,完全符合透视投影的视觉规律。


内容的提问来源于stack exchange,提问作者arudhraC

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 05:54:52