当前位置: 首页 > news >正文

OpengGL教程(七)---摄像机

本章参考官方教程:摄像机

本系列历史文
OpengGL教程(一)—OpenGL环境的配置(GLFW3,GLAD)
OpengGL教程(二)—渲染一个简单的窗体
OpengGL教程(三)—使用VAO和VBO方式绘制三角形
OpengGL教程(四)—使用EBO方式绘制矩形
OpengGL教程(五)—纹理的应用
OpengGL教程(六)—坐标的变换和坐标系的变换

本章主要讲述了MVP矩阵中的V矩阵。
需要了解:格拉姆—施密特正交化

OpenGL本身没有摄像机(Camera)的概念,但我们可以通过把场景中的所有物体往相反方向移动的方式来模拟出摄像机,产生一种我们在移动的感觉,而不是场景在移动。

官网中有上面这样一段话,不要去纠结有无摄像机,就默认为有,对于此章节我们一切矩阵操作的对象都是摄像机

在这里插入图片描述
摄像机看一个物体有哪些需要注意点地方呢?

1、摄像机的位置:摄像机不同的位置,拍摄的角度不同,则看到的画面就不同。
2、摄像机的注视点:摄像机位置不动,但是我可以控制对着哪拍阿,看的地方不动,画面肯定也不一样。
3、摄像机的姿态: 摄像机位置不动,摄像机上下反过来,最终拍出的照片不就颠倒了莫。

那么对于此章我们要注意的不就是上面这三点嘛,下面我们对于这三点分别分析。

摄像机的位置

在这里插入图片描述

摄像机的注视点

在这里插入图片描述

摄像机的姿态

在这里插入图片描述
图中绿色的箭头为摄像头的上向量(0,1,0),上向量的不同,摄像头的姿态是不是也是不同。如果给图中绿色箭头朝向改为向下(0,-1,0).那么拍摄的画面就倒过来咯。

上诉这三个要点,每个要点都可以通过矩阵的方式来表示,具体推导见官网教案,这里不做详细表述。下面是一些简单的推导。

下面举个例子:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

根据上诉例子在结合下面内容就好理解。

在这里插入图片描述

GLM已经提供了这些支持。我们要做的只是定义一个摄像机位置,一个目标位置和一个表示世界空间中的上向量的向量(我们计算右向量使用的那个上向量)。接着GLM就会创建一个LookAt矩阵,我们可以把它当作我们的观察矩阵:

glm::mat4 view;
view = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f), 
           glm::vec3(0.0f, 0.0f, 0.0f), 
           glm::vec3(0.0f, 1.0f, 0.0f));

glm::LookAt函数需要一个位置、目标上向量。它会创建一个和在上一节使用的一样的观察矩阵。

演示demo

main.cpp

#include <iostream>
#include <string>
#include <vector>
#include "glew.h"
#include "glfw3.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"


#include "log.h"
#include "GlslDealConfig.h"


GLfloat vertices[] = {
        -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
         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,  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,  1.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 1.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,  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, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

         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, 1.0f,
         0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.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,
         0.5f, -0.5f,  0.5f,  1.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,  0.0f, 1.0f,
         0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f
};

std::vector<glm::vec3> cubePositions = {
		  glm::vec3( 0.0f,  0.0f,   0.0f), 
		  glm::vec3( 0.0f,  1.2f,   0.0f),
		  glm::vec3( 1.2f,  1.2f,   0.0f),
		  glm::vec3( 0.0f,  -1.2f,  0.0f),
		  glm::vec3( 1.2f,  -1.2f,  0.0f),
		  glm::vec3( 1.2f,  0.0f,   0.0f), 
		  glm::vec3( -1.2f,  0.0f,   0.0f), 
		  glm::vec3( -1.2f,  1.2f,   0.0f), 
		  glm::vec3( -1.2f,  -1.2f,   0.0f), 
		  glm::vec3(-1.5f, -2.2f, -2.5f),  
		  glm::vec3( 2.4f, -0.4f, -3.5f),  
		  glm::vec3( 1.3f, -2.0f, -2.5f),  
		  glm::vec3( 1.5f,  2.0f, -2.5f), 
		  glm::vec3( 1.5f,  0.2f, -1.5f), 
		  glm::vec3(-1.3f,  1.0f, -1.5f)  
};


// 主函数
int main() {
    GlslDealConfig glslConfig;

    // 初始化 GLFW
    if (!glfwInit()) {
        LOGE("Failed to initialize GLFW");
        return -1;
    }

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // 创建窗口
    GLFWwindow* window = glfwCreateWindow(1000, 1000, "3D Demo", nullptr, nullptr);
    if (!window) {
        LOGE("Failed to create GLFW window");
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);

    // 初始化 GLEW
    GLenum err = glewInit();
    if (err != GLEW_OK) {
        LOGE("Failed to initialize GLEW: %s", reinterpret_cast<const char*>(glewGetErrorString(err)));
        return -1;
    }

    glfwSwapInterval(1);

    // 加载着色器
    std::string vertexShaderCode   = glslConfig.ReadGlslFile("/home/ryan/zxp/Rendering/demo/glsl/Trans/VertexShader.glsl");
    std::string fragmentShaderCode = glslConfig.ReadGlslFile("/home/ryan/zxp/Rendering/demo/glsl/Trans/FragmentShader.glsl");

    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    const GLchar* vShaderSource = vertexShaderCode.c_str();
    const GLchar* fShaderSource = fragmentShaderCode.c_str();

    glShaderSource(vertexShader, 1, &vShaderSource, nullptr);
    glShaderSource(fragmentShader, 1, &fShaderSource, nullptr);

    glCompileShader(vertexShader);
    glCompileShader(fragmentShader);
    glslConfig.CheckShaderCompileV(vertexShader);
    glslConfig.CheckShaderCompileF(fragmentShader);

    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    glslConfig.CheckProgmaLinkStatus(shaderProgram);

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    // 配置 VAO, VBO, EBO
    GLuint VAO, VBO[2];
    glGenVertexArrays(1, &VAO);
    glGenBuffers(2, VBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(3*sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    // 加载纹理
    GLuint texture[2];
    texture[0] = glslConfig.loadTexture("/home/ryan/zxp/Rendering/demo/resource/brickwall.jpg",   GL_RGB);
    texture[1] = glslConfig.loadTexture("/home/ryan/zxp/Rendering/demo/resource/awesomeface.png", GL_RGBA);

    // 设置投影矩阵
    glm::mat4 projection = glm::mat4(1.0f);

    glUseProgram(shaderProgram);
    GLuint projLoc = glGetUniformLocation(shaderProgram, "projection");
    glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));

    // 激活纹理单元
    glActiveTexture(GL_TEXTURE3);
    GLuint textureLocation = glGetUniformLocation(shaderProgram, "textureClass");
    glUniform1i(textureLocation, 3);

    glActiveTexture(GL_TEXTURE6);
    GLuint textureLocation2 = glGetUniformLocation(shaderProgram, "textureClass2");
    glUniform1i(textureLocation2, 6);


    glm::mat4 Mmatrix    = glm::mat4(1.0f);
    glm::mat4 Vmatrix    = glm::mat4(1.0f);
    glm::mat4 Pmatrix    = glm::mat4(1.0f);

    Pmatrix = glm::perspective(glm::radians(45.0f), 1000.0f/1000.0f, 0.1f, 100.0f);

    GLuint TransM = glGetUniformLocation(shaderProgram, "Mtrans");
    GLuint TransV = glGetUniformLocation(shaderProgram, "Vtrans");
    GLuint TransP = glGetUniformLocation(shaderProgram, "Ptrans");
    glUniformMatrix4fv(TransM, 1, GL_FALSE, glm::value_ptr(Mmatrix));
    glUniformMatrix4fv(TransV, 1, GL_FALSE, glm::value_ptr(Vmatrix));
    glUniformMatrix4fv(TransP, 1, GL_FALSE, glm::value_ptr(Pmatrix));



    glEnable(GL_DEPTH_TEST);

    // 渲染循环
    while (!glfwWindowShouldClose(window))
    {
        glViewport(0, 0, 1000, 1000);
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);


        glActiveTexture(GL_TEXTURE3);
        glBindTexture(GL_TEXTURE_2D, texture[0]);

        glActiveTexture(GL_TEXTURE6);
        glBindTexture(GL_TEXTURE_2D, texture[1]);


        glm::mat4 view = glm::mat4(1.0f); 
        float radius = 10.0f;
        float camX = static_cast<float>(sin(glfwGetTime()) * radius);
        float camZ = static_cast<float>(cos(glfwGetTime()) * radius);
        //一个位置、目标和上向量
        view = glm::lookAt(glm::vec3(camX, 0.0f, camZ), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
        glUniformMatrix4fv(TransV, 1, GL_FALSE, glm::value_ptr(view));


        for(unsigned int i = 0; i < cubePositions.size(); i++)
        {
            glm::mat4 model = glm::mat4(1.0f);
            model = glm::translate(model, cubePositions[i]);
            glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "Mtrans"), 1, GL_FALSE, glm::value_ptr(model));
            glDrawArrays(GL_TRIANGLES, 0, 36);
        }

        glBindVertexArray(0);
        glBindTexture(GL_TEXTURE_2D, 0);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // 清理资源
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(2, VBO);
    glDeleteProgram(shaderProgram);

    glfwTerminate();
    return 0;
}

核心代码

        glm::mat4 view = glm::mat4(1.0f); 
        float radius = 10.0f;
        float camX = static_cast<float>(sin(glfwGetTime()) * radius);
        float camZ = static_cast<float>(cos(glfwGetTime()) * radius);
        //一个位置、目标和上向量
        view = glm::lookAt(glm::vec3(camX, 0.0f, camZ), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));

相机位置 :glm::vec3(camX, 0.0f, camZ)
相机注视点 :glm::vec3(0.0f, 0.0f, 0.0f)
相机姿态 :glm::vec3(0.0f, 1.0f, 0.0f)

需要注意,是通过相机的位置和相机的注视点来确定相机看向的位置的。注视点向量 - 相机位置向量 = 相机看向的方向
ps:看向的方向,并不是看向某一个点,是方向!

运行效果
在这里插入图片描述
基于上面内容,我们修改以下代码实现键盘WASD控制摄像头移动的效果。

glm::vec3 cameraPos   = glm::vec3(0.0f, 0.0f,  3.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp    = glm::vec3(0.0f, 1.0f,  0.0f);

void processInput(GLFWwindow *window)
{
    float cameraSpeed = 0.05f; // adjust accordingly
    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
        cameraPos += cameraSpeed * cameraFront;
    if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
        cameraPos -= cameraSpeed * cameraFront;
    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
        cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
    if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
        cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
}

processInput添加到循环渲染中去。

    // 渲染循环
    while (!glfwWindowShouldClose(window))
    {
		......
		......
        processInput(window);
		......
		......
    }

补充叉积数学定义

在这里插入图片描述

视角移动

为了能够改变视角,我们需要根据鼠标的输入改变cameraFront向量,这就引入了一个新的知识点欧拉角。

欧拉角(Euler angles)是一种用来描述三维空间中物体方向(姿态)的方式,通过绕固定顺序的三个轴的旋转来表示一个方向或旋转。
即由俯仰角(上下看)、偏转角(左右看)、旋转角(打滚看)。

在这里插入图片描述

如何运用欧拉角实现改变视角:这部分建议看官网有一点点掌握即可

官网中给出的改变视角的方法就下面这三行代码

    glm::vec3 front;
    front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
    front.y = sin(glm::radians(pitch));
    front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));

下面解释这段代码是怎么来的。这三行代码的实质就是将球面坐标系转换成笛卡尔坐标系。如下图的点A。设OA的距离为R,
则在球面坐标系中A点的坐标可以表示为 A(R, pitch, yaw)。pitch是俯仰角,yaw是偏转角。

在这里插入图片描述

我们将A(R, pitch, yaw)转换为笛卡尔坐标系下的坐标:

注意:我的坐标系是按照OpenGL建造的,即Z轴正半轴指向屏幕前的你。

y = R * sin(pitch)

x = OK = OB * cos(yaw) = R * cos(pitch) * cos(yaw)

z = KB = OB * sin(yaw) = R * cos(pitch) * sin(yaw)

视角移动完整代码

#include <iostream>
#include <string>
#include <vector>
#include "glew.h"
#include "glfw3.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"


#include "log.h"
#include "GlslDealConfig.h"


GLfloat vertices[] = {
        -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
         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,  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,  1.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 1.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,  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, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

         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, 1.0f,
         0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.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,
         0.5f, -0.5f,  0.5f,  1.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,  0.0f, 1.0f,
         0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f
};

std::vector<glm::vec3> cubePositions = {
  glm::vec3( 0.0f,  0.0f,   0.0f), 
  glm::vec3( 0.0f,  1.2f,   0.0f),
  glm::vec3( 1.2f,  1.2f,   0.0f),
  glm::vec3( 0.0f,  -1.2f,  0.0f),
  glm::vec3( 1.2f,  -1.2f,  0.0f),
  glm::vec3( 1.2f,  0.0f,   0.0f), 
  glm::vec3( -1.2f,  0.0f,   0.0f), 
  glm::vec3( -1.2f,  1.2f,   0.0f), 
  glm::vec3( -1.2f,  -1.2f,   0.0f), 
  glm::vec3(-1.5f, -2.2f, -2.5f),  
  glm::vec3( 2.4f, -0.4f, -3.5f),  
  glm::vec3( 1.3f, -2.0f, -2.5f),  
  glm::vec3( 1.5f,  2.0f, -2.5f), 
  glm::vec3( 1.5f,  0.2f, -1.5f), 
  glm::vec3(-1.3f,  1.0f, -1.5f)  
};

glm::vec3 cameraPos   = glm::vec3(0.0f, 0.0f,  3.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp    = glm::vec3(0.0f, 1.0f,  0.0f);

bool  firstMouse = true;
float yaw   = -90.0f;
float pitch =  0.0f;
float lastX =  800.0f / 2.0;
float lastY =  600.0 / 2.0;
float fov   =  45.0f;

void processInput(GLFWwindow *window)
{
    float cameraSpeed = 0.05f; // adjust accordingly
    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
        cameraPos += cameraSpeed * cameraFront;
    if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
        cameraPos -= cameraSpeed * cameraFront;
    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
        cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
    if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
        cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
}

void mouse_callback(GLFWwindow* window, double xposIn, double yposIn)
{
    float xpos = static_cast<float>(xposIn);
    float ypos = static_cast<float>(yposIn);

    if (firstMouse)
    {
        lastX = xpos;
        lastY = ypos;
        firstMouse = false;
    }

    float xoffset = xpos - lastX;
    float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
    lastX = xpos;
    lastY = ypos;

    float sensitivity = 0.1f; // change this value to your liking
    xoffset *= sensitivity;
    yoffset *= sensitivity;

    yaw += xoffset;
    pitch += yoffset;

    printf("pitch : %f\n", pitch);
    printf("yaw   : %f\n", yaw);

    // make sure that when pitch is out of bounds, screen doesn't get flipped
    if (pitch > 89.0f)
        pitch = 89.0f;
    if (pitch < -89.0f)
        pitch = -89.0f;

    glm::vec3 front;
    front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
    front.y = sin(glm::radians(pitch));
    front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
    cameraFront = glm::normalize(front);
}

// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
    fov -= (float)yoffset;
    if (fov < 1.0f)
        fov = 1.0f;
    if (fov > 45.0f)
        fov = 45.0f;
}

// 主函数
int main() {
    GlslDealConfig glslConfig;

    // 初始化 GLFW
    if (!glfwInit()) {
        LOGE("Failed to initialize GLFW");
        return -1;
    }

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // 创建窗口
    GLFWwindow* window = glfwCreateWindow(1000, 1000, "3D Demo", nullptr, nullptr);
    if (!window) {
        LOGE("Failed to create GLFW window");
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetCursorPosCallback(window, mouse_callback);
    glfwSetScrollCallback(window,    scroll_callback);

    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

    // 初始化 GLEW
    GLenum err = glewInit();
    if (err != GLEW_OK) {
        LOGE("Failed to initialize GLEW: %s", reinterpret_cast<const char*>(glewGetErrorString(err)));
        return -1;
    }

    glfwSwapInterval(1);

    // 加载着色器
    std::string vertexShaderCode   = glslConfig.ReadGlslFile("/home/ryan/zxp/Rendering/demo/glsl/Trans/VertexShader.glsl");
    std::string fragmentShaderCode = glslConfig.ReadGlslFile("/home/ryan/zxp/Rendering/demo/glsl/Trans/FragmentShader.glsl");

    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    const GLchar* vShaderSource = vertexShaderCode.c_str();
    const GLchar* fShaderSource = fragmentShaderCode.c_str();

    glShaderSource(vertexShader, 1, &vShaderSource, nullptr);
    glShaderSource(fragmentShader, 1, &fShaderSource, nullptr);

    glCompileShader(vertexShader);
    glCompileShader(fragmentShader);
    glslConfig.CheckShaderCompileV(vertexShader);
    glslConfig.CheckShaderCompileF(fragmentShader);

    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    glslConfig.CheckProgmaLinkStatus(shaderProgram);

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    // 配置 VAO, VBO, EBO
    GLuint VAO, VBO[2];
    glGenVertexArrays(1, &VAO);
    glGenBuffers(2, VBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(3*sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    // 加载纹理
    GLuint texture[2];
    texture[0] = glslConfig.loadTexture("/home/ryan/zxp/Rendering/demo/resource/brickwall.jpg",   GL_RGB);
    texture[1] = glslConfig.loadTexture("/home/ryan/zxp/Rendering/demo/resource/awesomeface.png", GL_RGBA);

    // 设置投影矩阵
    glm::mat4 projection = glm::mat4(1.0f);

    glUseProgram(shaderProgram);
    GLuint projLoc = glGetUniformLocation(shaderProgram, "projection");
    glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));

    // 激活纹理单元
    glActiveTexture(GL_TEXTURE3);
    GLuint textureLocation = glGetUniformLocation(shaderProgram, "textureClass");
    glUniform1i(textureLocation, 3);

    glActiveTexture(GL_TEXTURE6);
    GLuint textureLocation2 = glGetUniformLocation(shaderProgram, "textureClass2");
    glUniform1i(textureLocation2, 6);


    glm::mat4 Mmatrix    = glm::mat4(1.0f);
    glm::mat4 Vmatrix    = glm::mat4(1.0f);
    glm::mat4 Pmatrix    = glm::mat4(1.0f);

    Pmatrix = glm::perspective(glm::radians(45.0f), 1000.0f/1000.0f, 0.1f, 100.0f);

    GLuint TransM = glGetUniformLocation(shaderProgram, "Mtrans");
    GLuint TransV = glGetUniformLocation(shaderProgram, "Vtrans");
    GLuint TransP = glGetUniformLocation(shaderProgram, "Ptrans");
    glUniformMatrix4fv(TransM, 1, GL_FALSE, glm::value_ptr(Mmatrix));
    glUniformMatrix4fv(TransV, 1, GL_FALSE, glm::value_ptr(Vmatrix));
    glUniformMatrix4fv(TransP, 1, GL_FALSE, glm::value_ptr(Pmatrix));

    glEnable(GL_DEPTH_TEST);

    // 渲染循环
    while (!glfwWindowShouldClose(window))
    {
        glViewport(0, 0, 1000, 1000);
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);

        glActiveTexture(GL_TEXTURE3);
        glBindTexture(GL_TEXTURE_2D, texture[0]);

        glActiveTexture(GL_TEXTURE6);
        glBindTexture(GL_TEXTURE_2D, texture[1]);

        processInput(window);

        Pmatrix = glm::perspective(glm::radians(fov), 1000.0f/1000.0f, 0.1f, 100.0f);
        glUniformMatrix4fv(TransP, 1, GL_FALSE, glm::value_ptr(Pmatrix));

        glm::mat4 view = glm::mat4(1.0f); 

        //始终注释相机正前方
        view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);

        // view = glm::lookAt(cameraPos, glm::vec3(0.0f, 0.0f, 0.0f), cameraUp);

        glUniformMatrix4fv(TransV, 1, GL_FALSE, glm::value_ptr(view));


        for(unsigned int i = 0; i < cubePositions.size(); i++)
        {
            glm::mat4 model = glm::mat4(1.0f);
            model = glm::translate(model, cubePositions[i]);
            glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "Mtrans"), 1, GL_FALSE, glm::value_ptr(model));
            glDrawArrays(GL_TRIANGLES, 0, 36);
        }

        glBindVertexArray(0);
        glBindTexture(GL_TEXTURE_2D, 0);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // 清理资源
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(2, VBO);
    glDeleteProgram(shaderProgram);

    glfwTerminate();
    return 0;
}

相关文章:

  • 在Ubuntu服务器上安装Docker(支持Ubuntu 20.04/22.04等版本):
  • 道路运输安全员岗位事项有哪些?
  • HBuilderX中uni-app打包Android(apk)全流程超详细打包
  • 建设“大数据智慧招商平台”,助力园区突破招商瓶颈!
  • 2025 年“认证杯”数学中国数学建模网络挑战赛 C题 化工厂生产流程的预测和控制
  • 03--Deepseek服务器部署与cjson解析
  • 魔改chromium源码——新增自定义变量到windows属性
  • 前端学习10—Ajax
  • iOS应用开发指南
  • 力扣第272场周赛
  • UniAD:自动驾驶的统一架构 - 创新与挑战并存
  • 生物化学笔记:医学免疫学原理14 感染免疫 感染免疫的机制+病原体的免疫逃逸机制
  • LeetCode算法题(Go语言实现)_40
  • UNIX域套接字(Unix Domain Sockets, UDS) 的两种接口
  • FOUPK3system5XOS系统19.60 (FOUPK3system5XOSONSX9内核)Application开源计划1.0正式发布
  • 通过AWS EKS 生成并部署容器化应用
  • VRRP学习
  • Postgresql安装mysql_fdw并映射MySQL数据库
  • 在图像处理领域,什么是缓冲区堆积问题
  • es的告警信息
  • 铭誉摄影网站/seo管理
  • 大型集团网站/商品推广软文范例300字
  • 做外贸网站义乌/网络推广营销网站建设专家
  • asp网站首页模板/抖音seo推广
  • 网站推广怎么推/ip反查域名网站
  • 中国在数码网站注册域名好>/怎么免费建个人网站