源码效果
C++源码
纹理图片
需下载stb_image.h这个解码图片的库,该库只有一个头文件。
具体代码:
vertexShader.glsl
#version 330 corelayout(location = 0) in vec3 aPos;
layout(location = 1) in vec2 aUV;out vec2 outUV;uniform mat4 _modelMatrix;
uniform mat4 _viewMatrix;
uniform mat4 _projMatrix;void main()
{gl_Position = _projMatrix* _viewMatrix * _modelMatrix * vec4(aPos.x, aPos.y, aPos.z, 1.0);outUV = aUV;
}
vertexShader.glsl
#version 330 coreout vec4 FragColor;in vec2 outUV;uniform sampler2D ourTexture;void main()
{// 使用图片纹理及色彩混合FragColor = texture(ourTexture, outUV);
}
OpenGLClass.cpp
#include "OpenGLClass.h"Camera _camera;void OpenGLClass::bck_GLFWframebuffersizefun(GLFWwindow* window, int width, int height)
{// 在窗口中定义一个像素矩形,最终的图形将映射到个矩形中glViewport(0, 0, width, height);
}OpenGLClass::OpenGLClass()
{// 初始化glfw上下文if (glfwInit() == GLFW_FALSE) { std::cout << "glfwInit fail!\n"; return; }glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // 3.3版本glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 使用OpenGL核心模式// 创建OpenGL窗体GLFWwindow *window = glfwCreateWindow(windowWidth, windowHeight, "OpenGL Core", nullptr, nullptr);if (!window) { std::cout << "glfwCreateWindow fail!\n"; return; }// 当前OpenGL上下文绑定窗口glfwMakeContextCurrent(window);// 加载所有OpenGL函数指针if (GL_FALSE == gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "gladLoadGLLoader fail!\n"; return; }// 在窗口中定义一个像素矩形,最终的图形将映射到个矩形中glViewport(0, 0, windowWidth, windowHeight);// 窗口大小调整回调glfwSetFramebufferSizeCallback(window, OpenGLClass::bck_GLFWframebuffersizefun);// 摄像机控制glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); // 鼠标不可见glfwSetCursorPosCallback(window, mouse_callback); // 鼠标移动回调_camera.setSpeed(0.02f);_camera.lookAt(glm::vec3(0.0f, 0.0f, 3.0f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, 1.0f, 0.0f));// 初始化VAO/VBOinitModel();// 初始化纹理if (!initTexture()) { std::cout << "initTexture fail!\n"; system("pause"); return; }// 初始化shaderif (!initShader("vertexShader.glsl", "fragmentShader.glsl")) { std::cout << "initShader fail!\n"; system("pause"); return; }// 窗口标志是否是关闭while (!glfwWindowShouldClose(window)){// 输入按键处理ProcessKeyPInput(window);#if 0// 使用红,绿,蓝以及alpha值来清除颜色缓冲区glClearColor(0.328125f, 0.35156f, 0.82421f, 1.0f);// 将从窗口中清除最后一次所绘制的图形/*GL_COLOR_BUFFER_BIT: 当前可写的颜色缓冲GL_DEPTH_BUFFER_BIT: 深度缓冲GL_ACCUM_BUFFER_BIT: 累积缓冲GL_STENCIL_BUFFER_BIT: 模板缓冲*/glClear(GL_COLOR_BUFFER_BIT);
#endifFlushRender();// 双缓冲,使用OpenGL或OpenGL ES进行渲染glfwSwapBuffers(window);// glfw事件循环glfwPollEvents();// 睡眠10ms,防止造成GPU疯狂消耗。实际具体调整Sleep(10);}// 释放窗口glfwDestroyWindow(window);// 释放资源,终止GLFW库glfwTerminate();
}OpenGLClass::~OpenGLClass()
{// 释放if (glIsProgram(shaderProgram)) { glDeleteProgram(shaderProgram); }shaderProgram = 0;if (glIsBuffer(VAO)) { glDeleteBuffers(1, &VAO); } VAO = 0;if (glIsBuffer(VBO)) { glDeleteBuffers(1, &VBO); } VBO = 0;
}void OpenGLClass::ProcessKeyPInput(GLFWwindow *window)
{if (window){if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) // 获取窗口按键是否ESC{// 设置窗口关闭标志glfwSetWindowShouldClose(window, true);}if (glfwGetKey(window, GLFW_KEY_LEFT_BRACKET) == GLFW_PRESS){_camera.setSpeed(_camera.getSpeed() - 0.005);std::cout << "已按'[' 减速键:速度-0.005,当前速度为:" << _camera.getSpeed() << std::endl;}if (glfwGetKey(window, GLFW_KEY_RIGHT_BRACKET) == GLFW_PRESS){_camera.setSpeed(_camera.getSpeed() + 0.005);std::cout << "已按']' 增速键:速度+0.005,当前速度为:" << _camera.getSpeed() << std::endl;}if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS){_camera.move(CAMERA_MOVE::MOVE_FRONT);std::cout << "已按'w'键:向(前)运动,速度为:" << _camera.getSpeed() << std::endl;}if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS){_camera.move(CAMERA_MOVE::MOVE_BACK);std::cout << "已按's'键:向(后)运动,速度为:" << _camera.getSpeed() << std::endl;}if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS){_camera.move(CAMERA_MOVE::MOVE_LEFT);std::cout << "已按'a'键:向(左)运动,速度为:" << _camera.getSpeed() << std::endl;}if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS){_camera.move(CAMERA_MOVE::MOVE_RIGHT);std::cout << "已按'd'键:向(右)运动,速度为:" << _camera.getSpeed() << std::endl;}if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS){_camera.move(CAMERA_MOVE::MOVE_UP);std::cout << "已按'↑'键:向(上)运动,速度为:" << _camera.getSpeed() << std::endl;}if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS){_camera.move(CAMERA_MOVE::MOVE_DOWN);std::cout << "已按'↓'键:向(上)运动,速度为:" << _camera.getSpeed() << std::endl;}if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS){_camera.move(CAMERA_MOVE::MOVE_InitialPosition);std::cout << "********** 已按' ' (空格)恢复初始位置! **********" << std::endl;}}window = nullptr;
}void OpenGLClass::mouse_callback(GLFWwindow *window, double xpos, double ypos)
{_camera.onMouseMove(xpos, ypos);
}void OpenGLClass::setMatrix(const std::string &_name, glm::mat4 _matrix) const
{// 获得指定shader程序中uniform变量的位置int shaderNameId = glGetUniformLocation(shaderProgram, _name.c_str());/*将4x4的矩阵数据传递给着色器location:指定要更改的uniform变量的位置。count:指定要更改的矩阵的数量。如果只更改一个矩阵,该值为1。transpose:指定是否需要将矩阵进行转置。一般情况下,设为GL_FALSE即可。value:指向包含矩阵数据的指针。*/glUniformMatrix4fv(shaderNameId,1,GL_FALSE,glm::value_ptr(_matrix));
}void OpenGLClass::FlushRender()
{// 判断VAO是否被删除if (glIsVertexArray(VAO)){// 使用红,绿,蓝以及alpha值来清除颜色缓冲区glClearColor(0.328125f, 0.35156f, 0.82421f, 1.0f);// 将从窗口中清除最后一次所绘制的图形,GL_DEPTH_BUFFER_BIT将深度信息也清除glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 开启深度检测glEnable(GL_DEPTH_TEST);/// // 模型平移数据glm::vec3 modelVecs[] ={glm::vec3(0.0f,0.0f,0.0f),glm::vec3(2.0f, 5.0f, -15.0f),glm::vec3(-1.5f, -2.2f, -2.5f),glm::vec3(-3.8f, -2.0f, -12.3f),glm::vec3(2.4f, -0.4f, -3.5f),glm::vec3(-1.7f, 3.0f, -7.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)};//////// 观察者/摄像机矩阵
#if 0glm::mat4 _viewMatrix = glm::lookAt(glm::vec3(0.0f, 0.0f, 2.4f), // 摄像机位置glm::vec3(0.0f, 0.0f, 0.0f), // 摄像机看向的位置glm::vec3(0.0f, 1.0f, 0.0f) // 摄像机顶部的位置);
#else_camera.update();
#endif// 投影矩阵glm::mat4 _projMatrix = glm::perspective(glm::radians(45.0f),(float)windowWidth / (float)(windowHeight),0.1f, 100.0f);///#if 0// 使用程序glUseProgram(shaderProgram);///setMatrix("_viewMatrix", _viewMatrix);setMatrix("_projMatrix", _projMatrix);///// 绑定纹理glBindTexture(GL_TEXTURE_2D, _texture);// 绑定VAOglBindVertexArray(VAO);// 绘制三角形glDrawArrays(GL_TRIANGLES, 0, 36);// 关闭使用程序glUseProgram(0);
#else// 使用程序glUseProgram(shaderProgram);// 绘制10个立方体for (unsigned short index = 0; index < 10; ++index){glm::mat4 _modelMatrix(1.0f);_modelMatrix = glm::translate(_modelMatrix, modelVecs[index]);_modelMatrix = glm::rotate(_modelMatrix, glm::radians((float)glfwGetTime()*(index + 1) * 10), glm::vec3(0.5f, 1.0f, 0.0f));///setMatrix("_modelMatrix", _modelMatrix);setMatrix("_viewMatrix", _camera.getMatrix());setMatrix("_projMatrix", _projMatrix);///// 绑定纹理glBindTexture(GL_TEXTURE_2D, _texture);// 绑定VAOglBindVertexArray(VAO);// 绘制矩形glDrawArrays(GL_TRIANGLES, 0, 36);}// 关闭使用程序glUseProgram(0);
#endif}
}bool OpenGLClass::initTexture()
{// 读取图片相关信息ffImage *pImage = ffImage::readFromFile("./rec/wall.jpeg");if (!pImage) { return false; }// 生成纹理glGenTextures(1, &_texture);// 以2D方式绑定纹理// 将当前绑定的纹理对象替换为参数中指定的纹理对象glBindTexture(GL_TEXTURE_2D, _texture);// 设置纹理属性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_MIN_FILTER, GL_NEAREST);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// 读取图片数据,完成数据绑定glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pImage->getWidth(), pImage->getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, pImage->getData());if (pImage) { delete pImage; }pImage = nullptr;return true;
}void OpenGLClass::initModel()
{// 坐标、纹理位置float 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};/****************************************************/ // VAO// 创建VAOglGenVertexArrays(1, &VAO);// 绑定指定的顶点数组对象(Vertex Array Object, VAO)glBindVertexArray(VAO);/****************************************************//****************************************************/ // VBO// 生成缓冲区对象glGenBuffers(1, &VBO);// 绑定命名缓冲区对象glBindBuffer(GL_ARRAY_BUFFER, VBO);// 缓冲对象(VBO,IBO 等)分配空间并存储数据glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);/*指定顶点属性在顶点缓冲对象中的布局,并将其与顶点着色器中的顶点属性进行关联参数1:第n个layout (对应glsl中顶点着色器的layout)参数2:顶点属性的组成元素的数量,例如3表示顶点属性是由3个浮点数组成参数3:顶点属性的数据类型参数4:是否将非浮点型的数据归一化到[-1, 1]或[0, 1]范围内参数5:相邻两个顶点属性之间的字节数,通常为0或属性类型大小乘以数量参数6:顶点属性在顶点缓冲对象中的偏移量或者数据的首地址*/glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(sizeof(float) * 3));// 激活锚点(参数:第n个layout)glEnableVertexAttribArray(0);glEnableVertexAttribArray(1);// 解绑VAO/VBOglBindVertexArray(0);glBindBuffer(GL_ARRAY_BUFFER, 0);/****************************************************/
}std::string OpenGLClass::ReadGlslContext(const char *sPath)
{std::string strContext;if (!sPath) { return strContext; }std::ifstream sFile;sFile.open(sPath);if (sFile.is_open()){std::stringstream sStream;sStream << sFile.rdbuf();strContext = sStream.str();}return strContext;
}bool OpenGLClass::initShader(const char *_vertexPath, const char *_fragPath)
{char infoLog[512] = { 0 };int successFlag = 0;/*********************************************************/ // vertex编译std::string vertexContext = ReadGlslContext(_vertexPath); if (vertexContext.empty()) { return false; }const char *cVertexContext = vertexContext.c_str();// 创建顶点着色器对象unsigned int iVertexID = glCreateShader(GL_VERTEX_SHADER);// 为顶点着色器指定源码(参数2:传过去几个)glShaderSource(iVertexID, 1, &cVertexContext, nullptr);// 编译顶点着色器源码glCompileShader(iVertexID);// 查看编译顶点着色器源码结果glGetShaderiv(iVertexID, GL_COMPILE_STATUS, &successFlag);if (!successFlag) // 编译失败{// 获取编译失败原因glGetShaderInfoLog(iVertexID, 512, nullptr, infoLog);std::cout << "glGetShaderiv GL_VERTEX_SHADER" << iVertexID << " fail:" << infoLog << std::endl; return false;}cVertexContext = nullptr;/*********************************************************//*********************************************************/ // fragment编译std::string fragmentContext = ReadGlslContext(_fragPath); if (fragmentContext.empty()) { return false; }const char *cFragmentContext = fragmentContext.c_str();// 创建片段着色器对象unsigned int iFragmentID = glCreateShader(GL_FRAGMENT_SHADER);// 为片段着色器指定源码(参数2:传过去几个)glShaderSource(iFragmentID, 1, &cFragmentContext, nullptr);// 编译片段着色器源码glCompileShader(iFragmentID);// 查看编译片段着色器源码结果glGetShaderiv(iFragmentID, GL_COMPILE_STATUS, &successFlag);if (!successFlag) // 编译失败{// 获取编译失败原因glGetShaderInfoLog(iFragmentID, 512, nullptr, infoLog);std::cout << "glGetShaderiv GL_FRAGMENT_SHADER" << iFragmentID << " fail:" << infoLog << std::endl; return false;}cFragmentContext = nullptr;/*********************************************************//*********************************************************/ // 链接// 创建一个空的程序对象shaderProgram = glCreateProgram();if (shaderProgram == 0) { std::cout << "glCreateProgram fail!\n"; return false; }// 将着色器对象附加到程序对象上(注:glDetachShader为移除程序对象中的指定着色器对象)glAttachShader(shaderProgram, iVertexID);glAttachShader(shaderProgram, iFragmentID);// 进行链接程序对象glLinkProgram(shaderProgram);// 查看链接状态glGetProgramiv(shaderProgram, GL_LINK_STATUS, &successFlag);if (!successFlag) // 链接失败{// 获取链接失败原因glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);std::cout << "glGetProgramiv " << shaderProgram << " fail:" << infoLog << std::endl; return false;}/*********************************************************//* 在链接完成后,将编译shader相关删除。仅留下链接ID */if (glIsShader(iVertexID)) { glDeleteShader(iVertexID); }if (glIsShader(iFragmentID)) { glDeleteShader(iFragmentID); }return true;
}
OpenGLClass.h
#pragma once#include "Global.h"
#include "ffImage.h"
#include "Camera.h"class OpenGLClass
{
public:OpenGLClass();~OpenGLClass();protected:// 初始化纹理bool initTexture();// 初始化模型VAO/VBOvoid initModel();// 初始化shader文件bool initShader(const char *_vertexPath, const char *_fragPath);// 读取glsl文件内容std::string ReadGlslContext(const char *sPath);// 刷新Rendervoid FlushRender();// 回调 - 窗口尺寸变化回调static void bck_GLFWframebuffersizefun(GLFWwindow* window, int width, int height);// 处理按键输入void ProcessKeyPInput(GLFWwindow *window);// 设置矩阵void setMatrix(const std::string &_name, glm::mat4 _matrix)const;// 回调 - 摄像机旋转static void mouse_callback(GLFWwindow *window, double xpos, double ypos);private:unsigned short windowWidth = 800, windowHeight = 600;unsigned int shaderProgram = 0; // 链接程序对象unsigned int VBO = 0, VAO = 0, _texture = 0;
};
Camera.cpp
#include "Camera.h"Camera::Camera()
{
}Camera::~Camera()
{
}void Camera::setSpeed(float _spped)
{if (_spped > 0 && _spped < 0.5){m_speed = _spped;}
}float Camera::getSpeed()
{return m_speed;
}void Camera::lookAt(glm::vec3 _pos, glm::vec3 _front, glm::vec3 _up)
{InitialPosition = _pos;m_position = _pos;m_front = glm::normalize(_front);m_up = _up;m_vMatrix = glm::lookAt(m_position, m_position + m_front, m_up);
}void Camera::update()
{m_vMatrix = glm::lookAt(m_position, m_position + m_front, m_up);
}glm::mat4 Camera::getMatrix()
{return m_vMatrix;
}void Camera::move(CAMERA_MOVE _mode)
{switch (_mode){case CAMERA_MOVE::MOVE_LEFT:m_position -= glm::normalize(glm::cross(m_front, m_up)) * m_speed;break;case CAMERA_MOVE::MOVE_RIGHT:m_position += glm::normalize(glm::cross(m_front, m_up)) * m_speed;break;case CAMERA_MOVE::MOVE_FRONT:m_position += m_speed * m_front;break;case CAMERA_MOVE::MOVE_BACK:m_position -= m_speed * m_front;break;case CAMERA_MOVE::MOVE_UP:m_position += glm::normalize(glm::cross(glm::vec3(1.0f, 0.0f, 0.0f), m_front))*m_speed;break;case CAMERA_MOVE::MOVE_DOWN:m_position -= glm::normalize(glm::cross(glm::vec3(1.0f, 0.0f, 0.0f), m_front))*m_speed;break;case CAMERA_MOVE::MOVE_InitialPosition:m_position = InitialPosition;break;default:break;}
}void Camera::pitch(float _yOffset)
{m_pitch += _yOffset * m_sensitivity;// 约定俗成,俯仰角度必须在范围内m_pitch = m_pitch > 89.0f ? 89.0f : m_pitch;m_pitch = m_pitch < -89.0f ? -89.0f : m_pitch;m_front.y = sin(glm::radians(m_pitch));m_front.x = cos(glm::radians(m_yaw)) * cos(glm::radians(m_pitch));m_front.z = sin(glm::radians(m_yaw)) * cos(glm::radians(m_pitch));m_front = glm::normalize(m_front);update();
}void Camera::yaw(float _xOffset)
{m_yaw += _xOffset * m_sensitivity;m_front.y = sin(glm::radians(m_pitch));m_front.x = cos(glm::radians(m_yaw)) * cos(glm::radians(m_pitch));m_front.z = sin(glm::radians(m_yaw)) * cos(glm::radians(m_pitch));m_front = glm::normalize(m_front);update();
}void Camera::setSentitivity(float _m_sensitivity)
{m_sensitivity = _m_sensitivity;
}void Camera::onMouseMove(double _xpos, double _ypos)
{if (m_firstMove){m_xpos = _xpos;m_ypos = _ypos;m_firstMove = false;return;}float _xOffset = _xpos - m_xpos;float _yOffset = -(_ypos - m_ypos);pitch(_yOffset);yaw(_xOffset);m_xpos = _xpos;m_ypos = _ypos;
}
Camera.h
#pragma once#include "Global.h"enum class CAMERA_MOVE
{MOVE_LEFT,MOVE_RIGHT,MOVE_FRONT,MOVE_BACK,MOVE_UP,MOVE_DOWN,MOVE_InitialPosition
};class Camera
{
public:Camera();~Camera();void setSpeed(float);float getSpeed();void lookAt(glm::vec3 _pos, glm::vec3 _front, glm::vec3 _up);void update();glm::mat4 getMatrix();// 摄像机平移void move(CAMERA_MOVE);// 摄像机旋转相关void pitch(float);void yaw(float);void setSentitivity(float);void onMouseMove(double _xpos, double _ypos);private:glm::vec3 m_position = glm::vec3(1.0f), InitialPosition = glm::vec3(1.0f);glm::vec3 m_front = glm::vec3(1.0f);glm::vec3 m_up = glm::vec3(1.0f);float m_speed = 0.01f;// 旋转模型,达到俯仰效果float m_pitch = 0.0;float m_yaw = -90; // 由于初始时看向了z的负方向float m_sensitivity = 0.05f; // 鼠标位移变化值float m_xpos = 0.0f, m_ypos = 0.0f; // 鼠标上一次位置bool m_firstMove = true;glm::mat4 m_vMatrix = glm::mat4(1.0f);
};
完整源码下载
源码下载
关注
Wx GZH:码农总动员
笔者 - jxd