Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说
【OpenGL】谢尔宾斯基(Sierpinski)地毯 OpenGL分形(七),希望能够帮助你!!!。
https://www.bilibili.com/video/BV1Ri4y1g7Gg
阴影效果不是怎么好。
使用的是现代OpenGL。
主要思路是首先递归(已改为迭代)生成每个正方体的偏移位置,保存到数组里面。总共迭代了5次,产生了个正方体(每次正方体*20,再迭代一次的话,GPU渲染跟不上)。
然后根据OpenGL多实例渲染的特性,传入刚刚生成的偏移位置到顶点着色器(当然这些数据在代码渲染循环前已经设置为VBO传入到显存了,所以应该是着色器从显存里取)。通过在顶点着色器里面构造平移矩阵,在绘制正方体之前都平移到相应位置。
然后就是光照了,这里用的冯氏光照模型(着色处理在片段着色器)。最终产生该效果。
最后,talk is cheap, show me the code,我将代码都给出了,然后在关键地方添加了注释!
欢迎大家批判指正,如果有任何优化的地方都欢迎指出!
#include <iostream> #include <vector> #include <cmath> #define GLEW_STATIC #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 "Shader.h" #include "Camera.h" bool stop = true; // 空格键 控制是否旋转 const GLfloat sizeCube = 0.1f; // 正方体大小 const int pos[] = {
// 20个位置,表示一个谢尔宾斯基(Sierpinski)地毯 0, 0, 0, 0, 1, 0, 0, 2, 0, 1, 0, 0, 2, 0, 0, 1, 2, 0, 2, 1, 0, 2, 2, 0, 0, 0, 1, 0, 2, 1, 2, 0, 1, 2, 2, 1, 0, 0, 2, 0, 1, 2, 0, 2, 2, 1, 0, 2, 2, 0, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2 }; GLfloat vertices[] = {
// 正方体局部坐标 法向量(用于光照) // 正方体局部坐标 法向量(用于光照) // Back face -sizeCube, -sizeCube, -sizeCube, 0.0f, 0.0f, -1.0f, sizeCube, -sizeCube, -sizeCube, 0.0f, 0.0f, -1.0f, sizeCube, sizeCube, -sizeCube, 0.0f, 0.0f, -1.0f, sizeCube, sizeCube, -sizeCube, 0.0f, 0.0f, -1.0f, -sizeCube, sizeCube, -sizeCube, 0.0f, 0.0f, -1.0f, -sizeCube, -sizeCube, -sizeCube, 0.0f, 0.0f, -1.0f, // Front face -sizeCube, -sizeCube, sizeCube, 0.0f, 0.0f, 1.0f, sizeCube, sizeCube, sizeCube, 0.0f, 0.0f, 1.0f, sizeCube, -sizeCube, sizeCube, 0.0f, 0.0f, 1.0f, sizeCube, sizeCube, sizeCube, 0.0f, 0.0f, 1.0f, -sizeCube, -sizeCube, sizeCube, 0.0f, 0.0f, 1.0f, -sizeCube, sizeCube, sizeCube, 0.0f, 0.0f, 1.0f, // Left face -sizeCube, sizeCube, sizeCube, -1.0f, 0.0f, 0.0f, -sizeCube, -sizeCube, -sizeCube, -1.0f, 0.0f, 0.0f, -sizeCube, sizeCube, -sizeCube, -1.0f, 0.0f, 0.0f, -sizeCube, -sizeCube, -sizeCube, -1.0f, 0.0f, 0.0f, -sizeCube, sizeCube, sizeCube, -1.0f, 0.0f, 0.0f, -sizeCube, -sizeCube, sizeCube, -1.0f, 0.0f, 0.0f, // Right face sizeCube, sizeCube, sizeCube, 1.0f, 0.0f, 0.0f, sizeCube, sizeCube, -sizeCube, 1.0f, 0.0f, 0.0f, sizeCube, -sizeCube, -sizeCube, 1.0f, 0.0f, 0.0f, sizeCube, -sizeCube, -sizeCube, 1.0f, 0.0f, 0.0f, sizeCube, -sizeCube, sizeCube, 1.0f, 0.0f, 0.0f, sizeCube, sizeCube, sizeCube, 1.0f, 0.0f, 0.0f, // Bottom face -sizeCube, -sizeCube, -sizeCube, 0.0f, -1.0f, 0.0f, sizeCube, -sizeCube, sizeCube, 0.0f, -1.0f, 0.0f, sizeCube, -sizeCube, -sizeCube, 0.0f, -1.0f, 0.0f, sizeCube, -sizeCube, sizeCube, 0.0f, -1.0f, 0.0f, -sizeCube, -sizeCube, -sizeCube, 0.0f, -1.0f, 0.0f, -sizeCube, -sizeCube, sizeCube, 0.0f, -1.0f, 0.0f, // Top face -sizeCube, sizeCube, -sizeCube, 0.0f, 1.0f, 0.0f, sizeCube, sizeCube, -sizeCube, 0.0f, 1.0f, 0.0f, sizeCube, sizeCube, sizeCube, 0.0f, 1.0f, 0.0f, sizeCube, sizeCube, sizeCube, 0.0f, 1.0f, 0.0f, -sizeCube, sizeCube, sizeCube, 0.0f, 1.0f, 0.0f, -sizeCube, sizeCube, -sizeCube, 0.0f, 1.0f, 0.0f }; /** * 把递归改成了迭代,step表示当前步数,k表示目标步数 */ void func(std::vector<GLfloat>& vec, int step, int k) {
while (step < k) {
int stepLen = pow(3, step); std::vector<GLfloat> temp = vec; int len = temp.size() / 3; for (int i = 1; i < 20; i++) {
int alphaX = pos[i * 3] * stepLen; int alphaY = pos[i * 3 + 1] * stepLen; int alphaZ = pos[i * 3 + 2] * stepLen; for (int j = 0; j < len; j++) {
vec.push_back(temp[j * 3] + alphaX); vec.push_back(temp[j * 3 + 1] + alphaY); vec.push_back(temp[j * 3 + 2] + alphaZ); } } step++; } } void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); void mouse_callback(GLFWwindow* window, double xpos, double ypos); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); void do_movement(); // Window dimensions const GLuint WIDTH = 800, HEIGHT = 600; // Camera Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); GLfloat lastX = WIDTH / 2.0; GLfloat lastY = HEIGHT / 2.0; bool keys[1024]; glm::vec3 lightPos; // Deltatime GLfloat deltaTime = 0.0f; // Time between current frame and last frame GLfloat lastFrame = 0.0f; // Time of last frame int main() {
glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // 全屏 /*bool isFullScreen = true; GLFWmonitor* pMonitor = isFullScreen ? glfwGetPrimaryMonitor() : NULL; GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", pMonitor, nullptr);*/ GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr); glfwMakeContextCurrent(window); glfwSetKeyCallback(window, key_callback); glfwSetCursorPosCallback(window, mouse_callback); glfwSetScrollCallback(window, scroll_callback); // GLFW Options glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glewExperimental = GL_TRUE; glewInit(); // Define the viewport dimensions glViewport(0, 0, WIDTH, HEIGHT); // OpenGL options glEnable(GL_DEPTH_TEST); // 未开启面剔除、好像会影响渲染效果 Shader lightingShader("lighting.vs", "lighting.frag"); // 正方体的着色器 Shader lampShader("lamp.vs", "lamp.frag"); // 中心灯的着色器 const int k = 5; // 迭代次数 std::vector<GLfloat> vec(pos, pos + sizeof(pos) / sizeof(float)); // 初始赋值为pos vec.reserve(3 * pow(20, k)); // 提前计算并分配好空间 func(vec, 1, k); for (auto& item : vec) item *= sizeCube * 2; // 每一项移动为正方体边长比例 lightPos.x = lightPos.y = lightPos.z = pow(3, k) * sizeCube; // 光源位置初始化为中央 GLuint amount = vec.size() / 3; // 正方体个数 //std::cout << amount; // containerVAO 正方体VAO,使用一个顶点坐标和方向量的VBO和一个表示正方体偏移的instanceVBO GLuint VBO, instanceVBO, containerVAO; glGenVertexArrays(1, &containerVAO); glBindVertexArray(containerVAO); {
glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // Position attribute glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); // Normal attribute glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, 0); glGenBuffers(1, &instanceVBO); glBindBuffer(GL_ARRAY_BUFFER, instanceVBO); glBufferData(GL_ARRAY_BUFFER, vec.size() * sizeof(float), &vec[0], GL_STATIC_DRAW); // 偏移(用于绘制多个正方体) glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(3); glVertexAttribDivisor(3, 1); // 第一个参数2表示layout索引,第二个参数指定顶点属性的更新方式 glBindBuffer(GL_ARRAY_BUFFER, 0); } glBindVertexArray(0); // lightVAO 中心光源VAO, 同containerVAO共用VBO GLuint lightVAO; glGenVertexArrays(1, &lightVAO); glBindVertexArray(lightVAO); {
glBindBuffer(GL_ARRAY_BUFFER, VBO); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); } glBindVertexArray(0); glCullFace(GL_BACK); // 设置剔除的面是背面(默认剔除背面) glFrontFace(GL_CW); // 使用顺时针表示正面。clockwise(默认逆时针表示正面) glEnable(GL_CULL_FACE); // 开启面剔除(默认不开启) while (!glfwWindowShouldClose(window)) {
GLfloat currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; glfwPollEvents(); do_movement(); // Clear the colorbuffer glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Use cooresponding shader when setting uniforms/drawing objects lightingShader.Use(); GLint objectColorLoc = glGetUniformLocation(lightingShader.Program, "objectColor"); GLint lightColorLoc = glGetUniformLocation(lightingShader.Program, "lightColor"); GLint lightPosLoc = glGetUniformLocation(lightingShader.Program, "lightPos"); GLint viewPosLoc = glGetUniformLocation(lightingShader.Program, "viewPos"); glUniform3f(objectColorLoc, 0.75f, 0.75f, 0.75f); glUniform3f(lightColorLoc, 1.0f, 1.0f, 1.0f); glUniform3f(lightPosLoc, lightPos.x, lightPos.y, lightPos.z); glUniform3f(viewPosLoc, camera.Position.x, camera.Position.y, camera.Position.z); // Create camera transformations glm::mat4 view = camera.GetViewMatrix(); glm::mat4 projection = glm::perspective(camera.Zoom, (GLfloat)WIDTH / (GLfloat)HEIGHT, 0.1f, 100.0f); glm::mat4 model = glm::mat4(); // 让正方体旋转 static float angle = 0; if (!stop) angle += 0.1f; model = glm::rotate(model, angle, glm::vec3(1, 1, 1)); // Get the uniform locations GLint modelLoc = glGetUniformLocation(lightingShader.Program, "model"); GLint viewLoc = glGetUniformLocation(lightingShader.Program, "view"); GLint projLoc = glGetUniformLocation(lightingShader.Program, "projection"); // Pass the matrices to the shader glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection)); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); // Draw the container (using container's vertex attributes) glBindVertexArray(containerVAO); glDrawArraysInstanced(GL_TRIANGLES, 0, 36, amount); glBindVertexArray(0); // Also draw the lamp object, again binding the appropriate shader lampShader.Use(); model = glm::mat4(); model = glm::translate(model, glm::vec3(lightPos.x, lightPos.y, lightPos.z)); // 光源移动到中心 // Get location objects for the matrices on the lamp shader (these could be different on a different shader) modelLoc = glGetUniformLocation(lampShader.Program, "model"); viewLoc = glGetUniformLocation(lampShader.Program, "view"); projLoc = glGetUniformLocation(lampShader.Program, "projection"); // Set matrices glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection)); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); // Draw the light object (using light's vertex attributes) glBindVertexArray(lightVAO); glDrawArrays(GL_TRIANGLES, 0, 36); glBindVertexArray(0); // Swap the screen buffers glfwSwapBuffers(window); } // Terminate GLFW, clearing any resources allocated by GLFW. glfwTerminate(); return 0; } // Is called whenever a key is pressed/released via GLFW void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) {
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GL_TRUE); if (key >= 0 && key < 1024) {
if (action == GLFW_PRESS) {
keys[key] = true; if (key == GLFW_KEY_SPACE) stop = !stop; } else if (action == GLFW_RELEASE) keys[key] = false; } } void do_movement() {
// Camera controls if (keys[GLFW_KEY_W]) camera.ProcessKeyboard(FORWARD, deltaTime); if (keys[GLFW_KEY_S]) camera.ProcessKeyboard(BACKWARD, deltaTime); if (keys[GLFW_KEY_A]) camera.ProcessKeyboard(LEFT, deltaTime); if (keys[GLFW_KEY_D]) camera.ProcessKeyboard(RIGHT, deltaTime); } bool firstMouse = true; void mouse_callback(GLFWwindow* window, double xpos, double ypos) {
if (firstMouse) {
lastX = xpos; lastY = ypos; firstMouse = false; } GLfloat xoffset = xpos - lastX; GLfloat yoffset = lastY - ypos; // Reversed since y-coordinates go from bottom to left lastX = xpos; lastY = ypos; camera.ProcessMouseMovement(xoffset, yoffset); } void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {
camera.ProcessMouseScroll(yoffset); }
#version 330 core layout (location = 0) in vec3 position; layout (location = 1) in vec3 normal; layout (location = 3) in vec3 pos; // 正方体偏移 out vec3 Normal; out vec3 FragPos; uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main() {
mat4 instanceMatrix = mat4( // 平移矩阵的构造 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, pos.x, pos.y, pos.z, 1.0 ); gl_Position = projection * view * model * instanceMatrix * vec4(position, 1.0f); // 先平移到指定位置,再进行视图变换 FragPos = vec3(model * instanceMatrix * vec4(position, 1.0f)); // 需要顶点位置属性乘以模型矩阵(Model Matrix,只用模型矩阵不需要用观察和投影矩阵)来把它变换到世界空间坐标 Normal = mat3(transpose(inverse(model * instanceMatrix))) * normal; // 修复不等比缩放,正规矩阵被定义为“模型矩阵左上角的逆矩阵的转置矩阵” }
#version 330 core out vec4 color; in vec3 Normal; in vec3 FragPos; uniform vec3 lightPos; uniform vec3 viewPos; uniform vec3 lightColor; uniform vec3 objectColor; void main() {
// Ambient float ambientStrength = 0.1f; vec3 ambient = ambientStrength * lightColor; // Diffuse vec3 norm = normalize(Normal); // 保证自身为单位向量 vec3 lightDir = normalize(lightPos - FragPos); float diff = max(dot(norm, lightDir), 0.0); // dot 点乘 为0表示垂直,a1b1+a2b2 第一个向量投影到第二个向量上 vec3 diffuse = diff * lightColor; // Specular float specularStrength = 0.5f; // 镜面强度(Specular Intensity)变量specularStrength,给镜面高光一个中等亮度颜色,这样就不会产生过度的影响了。 vec3 viewDir = normalize(viewPos - FragPos); vec3 reflectDir = reflect(-lightDir, norm); // norm 标准化的法向量 float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); // 32是高光的发光值(Shininess)。一个物体的发光值越高,反射光的能力越强,散射得越少,高光点越小。 vec3 specular = specularStrength * spec * lightColor; vec3 result = (ambient + diffuse + specular) * objectColor; // 冯氏光照模型 color = vec4(result, 1.0f); }
#version 330 core layout (location = 0) in vec3 position; uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main() {
gl_Position = projection * view * model * vec4(position, 1.0f); }
#version 330 core out vec4 color; void main() {
color = vec4(1.0f); //设置四维向量的所有元素为 1.0f }
#ifndef SHADER_H #define SHADER_H #include <string> #include <fstream> #include <sstream> #include <iostream> #include <GL/glew.h> class Shader {
public: GLuint Program; // Constructor generates the shader on the fly Shader(const GLchar* vertexPath, const GLchar* fragmentPath) {
// 1. Retrieve the vertex/fragment source code from filePath std::string vertexCode; std::string fragmentCode; std::ifstream vShaderFile; std::ifstream fShaderFile; // ensures ifstream objects can throw exceptions: vShaderFile.exceptions(std::ifstream::badbit); fShaderFile.exceptions(std::ifstream::badbit); try {
// Open files vShaderFile.open(vertexPath); fShaderFile.open(fragmentPath); std::stringstream vShaderStream, fShaderStream; // Read file's buffer contents into streams vShaderStream << vShaderFile.rdbuf(); fShaderStream << fShaderFile.rdbuf(); // close file handlers vShaderFile.close(); fShaderFile.close(); // Convert stream into string vertexCode = vShaderStream.str(); fragmentCode = fShaderStream.str(); } catch (std::ifstream::failure e) {
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl; } const GLchar* vShaderCode = vertexCode.c_str(); const GLchar* fShaderCode = fragmentCode.c_str(); // 2. Compile shaders GLuint vertex, fragment; GLint success; GLchar infoLog[512]; // Vertex Shader vertex = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex, 1, &vShaderCode, NULL); glCompileShader(vertex); // Print compile errors if any glGetShaderiv(vertex, GL_COMPILE_STATUS, &success); if (!success) {
glGetShaderInfoLog(vertex, 512, NULL, infoLog); std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; } // Fragment Shader fragment = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment, 1, &fShaderCode, NULL); glCompileShader(fragment); // Print compile errors if any glGetShaderiv(fragment, GL_COMPILE_STATUS, &success); if (!success) {
glGetShaderInfoLog(fragment, 512, NULL, infoLog); std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; } // Shader Program this->Program = glCreateProgram(); glAttachShader(this->Program, vertex); glAttachShader(this->Program, fragment); glLinkProgram(this->Program); // Print linking errors if any glGetProgramiv(this->Program, GL_LINK_STATUS, &success); if (!success) {
glGetProgramInfoLog(this->Program, 512, NULL, infoLog); std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; } // Delete the shaders as they're linked into our program now and no longer necessery glDeleteShader(vertex); glDeleteShader(fragment); } // Uses the current shader void Use() {
glUseProgram(this->Program); } }; #endif
#ifndef CAMERA_H #define CAMERA_H #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <vector> // Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods enum Camera_Movement {
FORWARD, BACKWARD, LEFT, RIGHT }; // Default camera values const float YAW = -90.0f; const float PITCH = 0.0f; const float SPEED = 5; const float SENSITIVITY = 0.1f; const float ZOOM = 45.0f; // An abstract camera class that processes input and calculates the corresponding Euler Angles, Vectors and Matrices for use in OpenGL class Camera {
public: // Camera Attributes glm::vec3 Position; glm::vec3 Front; glm::vec3 Up; glm::vec3 Right; glm::vec3 WorldUp; // Euler Angles float Yaw; float Pitch; // Camera options float MovementSpeed; float MouseSensitivity; float Zoom; // Constructor with vectors Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM) {
Position = position; WorldUp = up; Yaw = yaw; Pitch = pitch; updateCameraVectors(); } // Constructor with scalar values Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM) {
Position = glm::vec3(posX, posY, posZ); WorldUp = glm::vec3(upX, upY, upZ); Yaw = yaw; Pitch = pitch; updateCameraVectors(); } // Returns the view matrix calculated using Euler Angles and the LookAt Matrix glm::mat4 GetViewMatrix() {
return glm::lookAt(Position, Position + Front, Up); } // Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems) void ProcessKeyboard(Camera_Movement direction, float deltaTime) {
float velocity = MovementSpeed * deltaTime; if (direction == FORWARD) Position += Front * velocity; if (direction == BACKWARD) Position -= Front * velocity; if (direction == LEFT) Position -= Right * velocity; if (direction == RIGHT) Position += Right * velocity; } // Processes input received from a mouse input system. Expects the offset value in both the x and y direction. void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true) {
xoffset *= MouseSensitivity; yoffset *= MouseSensitivity; Yaw += xoffset; Pitch += yoffset; // Make sure that when pitch is out of bounds, screen doesn't get flipped if (constrainPitch) {
if (Pitch > 89.0f) Pitch = 89.0f; if (Pitch < -89.0f) Pitch = -89.0f; } // Update Front, Right and Up Vectors using the updated Euler angles updateCameraVectors(); } // Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis void ProcessMouseScroll(float yoffset) {
if (Zoom >= 1.0f && Zoom <= 45.0f) Zoom -= yoffset; if (Zoom <= 1.0f) Zoom = 1.0f; if (Zoom >= 45.0f) Zoom = 45.0f; } private: // Calculates the front vector from the Camera's (updated) Euler Angles void updateCameraVectors() {
// Calculate the new Front vector 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)); Front = glm::normalize(front); // Also re-calculate the Right and Up vector Right = glm::normalize(glm::cross(Front, WorldUp)); // Normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement. Up = glm::normalize(glm::cross(Right, Front)); } }; #endif
今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
上一篇
已是最后文章
下一篇
已是最新文章