文章目录

  • 效果展示
  • 原理简介
    • 大致流程:
    • 关键点:
  • 最终代码
    • 主函数代码
    • 着色器代码
    • 包含头文件

效果展示

https://www.bilibili.com/video/BV1Ri4y1g7Gg

阴影效果不是怎么好。

原理简介

大致流程:

使用的是现代OpenGL。

主要思路是首先递归(已改为迭代)生成每个正方体的偏移位置,保存到数组里面。总共迭代了5次,产生了3200000个正方体(每次正方体*20,再迭代一次的话,GPU渲染跟不上)。

然后根据OpenGL多实例渲染的特性,传入刚刚生成的偏移位置到顶点着色器(当然这些数据在代码渲染循环前已经设置为VBO传入到显存了,所以应该是着色器从显存里取)。通过在顶点着色器里面构造平移矩阵,在绘制正方体之前都平移到相应位置。

然后就是光照了,这里用的冯氏光照模型(着色处理在片段着色器)。最终产生该效果。

关键点:

  • 内存解决: 因为VS x86运行最多给2G内存,然后迭代6次的话光存储偏移就用了接近1G的内存,所以并没有在主函数里面计算好模型矩阵后传入,而是直接传入正方体的偏移位置在着色器里面构造平移矩阵。但是这样虽然内存可以支持6次迭代,但是我的GTX1050渲染跟不上。
  • 这里产生谢尔宾斯基(Sierpinski)地毯的迭代方法是将一个基本的谢尔宾斯基(Sierpinski)地毯分解为20个正方体(下面一层和上面一层各8个,中间一层4个),即每增加一次迭代都将上一次的谢尔宾斯基(Sierpinski)地毯构造20个。
  • 使用了背面剔除,OpenGL中使用顶点绕序(winding order)来确定。所谓绕序就是当几何对象细分为三角形时,三角形顶点相对于中心的定义顺序。左侧的三角形顶点顺序为1->2->3,右侧的三角形顶点顺序为1->2->3。当观察者在右侧时,则右边的三角形方向为逆时针方向为正面,而左侧的三角形为顺时针则为背面;当观察者转到左侧时,左侧的三角形为逆时针绕序判定为正面,而右侧的三角形为顺时针绕序判定为背面。可以看出正面和背面是由三角形的顶点定义顺序和观察者的观察方向共同决定的,而且随着观察方向的改变,正面和背面将会跟着改变。

最后,talk is cheap, show me the code,我将代码都给出了,然后在关键地方添加了注释!

欢迎大家批判指正,如果有任何优化的地方都欢迎指出!

最终代码

主函数代码

  • main.cpp
#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 facesizeCube,  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 frameint 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 OptionsglfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);glewExperimental = GL_TRUE;glewInit();// Define the viewport dimensionsglViewport(0, 0, WIDTH, HEIGHT);// OpenGL optionsglEnable(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)); // 初始赋值为posvec.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和一个表示正方体偏移的instanceVBOGLuint 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 attributeglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);glEnableVertexAttribArray(0);// Normal attributeglVertexAttribPointer(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共用VBOGLuint 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 colorbufferglClearColor(0.1f, 0.1f, 0.1f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Use cooresponding shader when setting uniforms/drawing objectslightingShader.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 transformationsglm::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 locationsGLint modelLoc = glGetUniformLocation(lightingShader.Program, "model");GLint viewLoc = glGetUniformLocation(lightingShader.Program, "view");GLint projLoc = glGetUniformLocation(lightingShader.Program, "projection");// Pass the matrices to the shaderglUniformMatrix4fv(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 shaderlampShader.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 matricesglUniformMatrix4fv(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 buffersglfwSwapBuffers(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 controlsif (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 leftlastX = xpos;lastY = ypos;camera.ProcessMouseMovement(xoffset, yoffset);
}void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {camera.ProcessMouseScroll(yoffset);
}

着色器代码

  • lighting.vs
#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;  // 修复不等比缩放,正规矩阵被定义为“模型矩阵左上角的逆矩阵的转置矩阵”
}
  • lighting.frag
#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()
{// Ambientfloat 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;// Specularfloat 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);
}
  • lamp.vs
#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);
}
  • lamp.frag
#version 330 core
out vec4 color;void main()
{color = vec4(1.0f); //设置四维向量的所有元素为 1.0f
}

包含头文件

  • Shader.h
#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 flyShader(const GLchar* vertexPath, const GLchar* fragmentPath) {// 1. Retrieve the vertex/fragment source code from filePathstd::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 filesvShaderFile.open(vertexPath);fShaderFile.open(fragmentPath);std::stringstream vShaderStream, fShaderStream;// Read file's buffer contents into streamsvShaderStream << vShaderFile.rdbuf();fShaderStream << fShaderFile.rdbuf();// close file handlersvShaderFile.close();fShaderFile.close();// Convert stream into stringvertexCode = 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 shadersGLuint vertex, fragment;GLint success;GLchar infoLog[512];// Vertex Shadervertex = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertex, 1, &vShaderCode, NULL);glCompileShader(vertex);// Print compile errors if anyglGetShaderiv(vertex, GL_COMPILE_STATUS, &success);if (!success) {glGetShaderInfoLog(vertex, 512, NULL, infoLog);std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;}// Fragment Shaderfragment = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragment, 1, &fShaderCode, NULL);glCompileShader(fragment);// Print compile errors if anyglGetShaderiv(fragment, GL_COMPILE_STATUS, &success);if (!success) {glGetShaderInfoLog(fragment, 512, NULL, infoLog);std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;}// Shader Programthis->Program = glCreateProgram();glAttachShader(this->Program, vertex);glAttachShader(this->Program, fragment);glLinkProgram(this->Program);// Print linking errors if anyglGetProgramiv(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 necesseryglDeleteShader(vertex);glDeleteShader(fragment);}// Uses the current shadervoid Use() {glUseProgram(this->Program);}
};#endif
  • Camera.h
#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 Attributesglm::vec3 Position;glm::vec3 Front;glm::vec3 Up;glm::vec3 Right;glm::vec3 WorldUp;// Euler Anglesfloat Yaw;float Pitch;// Camera optionsfloat MovementSpeed;float MouseSensitivity;float Zoom;// Constructor with vectorsCamera(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 valuesCamera(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 Matrixglm::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 flippedif (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 anglesupdateCameraVectors();}// Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axisvoid 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 Anglesvoid updateCameraVectors(){// Calculate the new Front vectorglm::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 vectorRight = 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

【OpenGL】谢尔宾斯基(Sierpinski)地毯 OpenGL分形(七)相关推荐

  1. 分形之谢尔宾斯基(Sierpinski)地毯

    前面讲了谢尔宾斯基三角形,和这一节的将把三角形变为正方形,即谢尔宾斯基地毯,它是由瓦茨瓦夫·谢尔宾斯基于1916年提出的一种分形,是自相似集的一种. 谢尔宾斯基地毯的构造与谢尔宾斯基三角形相似,区别仅 ...

  2. sierpinski三角形的维数_谢尔宾斯基(Sierpinski)三角形

    分形之谢尔宾斯基(Sierpinski)三角形 谢尔宾斯基三角形(英语:Sierpinski triangle)是一种分形,由波兰数学家谢尔宾斯基在1915年提出,它是一种典型的自相似集.也有的资料将 ...

  3. 混沌分形之谢尔宾斯基(Sierpinski)

    本文以使用混沌方法生成若干种谢尔宾斯基相关的分形图形. (1)谢尔宾斯基三角形 给三角形的3个顶点,和一个当前点,然后以以下的方式进行迭代处理: a.随机选择三角形的某一个顶点,计算出它与当前点的中点 ...

  4. Java学习日记:UI篇(6)--谢尔宾斯基地毯图

    Java学习日记:UI篇(6)–谢尔宾斯基地毯图 引言:谢尔宾斯基地毯是数学家谢尔宾斯基提出的一个分形图形,谢尔宾斯基地毯和谢尔宾斯基三角形基本类似,不同之处在于谢尔宾斯基地毯采用的是正方形进行分形构 ...

  5. 谢尔宾斯基地毯的讲解

    谢尔宾斯基地毯是数学家谢尔宾斯基提出的一个分形图形,谢尔宾斯基地毯和谢尔宾斯基三角形基本类似,不同之处在于谢尔宾斯基地毯采用的是正方形进行分形构造,而谢尔宾斯基三角形采用的等边三角形进行分形构造.谢尔 ...

  6. 关于谢尔宾斯基地毯的讲解

    和谢尔宾斯基三角形一样,谢尔宾斯基地毯也是数学家谢尔宾斯基提出的一个分形图形,谢尔宾斯基地毯和谢尔宾斯基三角形基本类似,不同之处在于谢尔宾斯基地毯采用的是正方形进行分形构造,而谢尔宾斯基三角形采用的等 ...

  7. 混沌与分形(一):谢尔宾斯基三角形与门格海绵

    研究混沌运动,少不了对分形理论的探讨.分形:通常被定义为"一个粗糙或零碎的几何形状,可以分成数个部分,且每一部分都(至少近似地)是整体缩小后的形状",即具有自相似的性质. 本篇将从 ...

  8. 数据结构与算法(Python版)二十二:递归可视化(谢尔宾斯基三角形)

    谢尔宾斯基Sierpinski三角形 分形构造, 平面称谢尔宾斯基三角形, 立体称谢尔宾斯基金字塔 谢尔宾斯基三角形:作图思路 根据自相似特性, 谢尔宾斯基三角形是由3个尺寸减半的谢尔宾斯基三角形按照 ...

  9. 谢尔宾斯基三角形GUI

    源代码:https://github.com/ltoddy/Python-useful sierpinskitriangle.py from tkinter import *class Sierpin ...

最新文章

  1. 2022-2028年中国电子陶瓷行业深度调研及投资前景预测报告
  2. 零基础学C++进腾讯,这份GitHub热榜的「从入门到高薪」请你收下
  3. CVPR2021直播|点云补全的方法梳理及最新进展分享
  4. 代码编译delphi条件编译
  5. 【DIY】送给儿子的感应小夜灯,DIY小夜灯
  6. 二叉树遍历(已知先序和中序)
  7. python学习-高阶函数(函数传参、返回函数(闭包)、匿名函数lambda)
  8. java 夏令时标志_夏令时随绝对日期而变化
  9. linux系统下聊天工具,linux系统环境下如何使用amsn聊天工具_linux教程
  10. 随想录(skyeye中的soc仿真)
  11. linux内核编译步骤
  12. scala方法中的变量_Scala变量,变量范围,字段变量,方法参数示例
  13. C语言静态链表常用吗,C语言实现静态链表
  14. mysql数据库sql注入原理_如何SQL注入的原理和SQL注入的基础
  15. 知识竞赛系统的计时器数字或滚动抽签数字不显示的原因解惑
  16. plsql如何破解的方法
  17. 从IT时代到DT时代
  18. 【转】免费进入学术数据库
  19. 基于javaFX的固定资产管理系统
  20. tabIndex 和 aria注意点

热门文章

  1. keydown、keypress 和 keyup
  2. 汉字为什么能流传至今_汉字为什么是世界上仅存的语素文字?世界各国文字的起源...
  3. windows常见的命令操作大全
  4. 计算机远程桌面在什么地方查找,远程桌面连接在哪里 来看看小编是怎么讲解的...
  5. 我的Java学习笔记
  6. NXPowerLite Desktop 9(文件压缩软件)官方中文版V9.0.3 | 极品文件压缩器
  7. Flume的学习笔记
  8. 骨传导蓝牙耳机品牌哪个好、最值得入手的骨传导耳机推荐
  9. 全网首发,一篇文章带你走进pycharm的世界----别再问我pycharm的安装和环境配置了!!!万字只为君一笑,赶紧收藏起来吧
  10. Flex布局下如何使用text-overflow:ellipsis省略过长文本