[图形学]OpenGL实现斯坦福兔子(Stanford Bunny)实验代码
文章目录
- 项目整体文件结构
- 兔子数据(ply2文件)
- main.cpp
- bunny.fs 兔子面元着色器
- bunny.vs 兔子顶点着色器
- lamp.fs 灯光面元着色器
- lamp.vs 灯光顶点着色器
- camera.h 相机头文件
- parser.h 读取数据头文件
- parser.cpp 读取数据源文件
- select.fs 选取面元着色器
- select.vs 选取顶点着色器
- shader.h 着色器头文件
- 运行结果
- 参考
作者运行环境:XCode Version 12.3 (12C33)
需要先自行配置opengl
,glfw
,glad
,glm
的环境。(用homebrew命令行下载,并在项目里配置路径即可。
项目源代码:
链接: https://pan.baidu.com/s/1aMGJGCb8vUvaw3dCBbOkow 密码: go4e
项目整体文件结构
兔子数据(ply2文件)
链接: https://pan.baidu.com/s/1itfQ_GsuBPH0ehqCUzt_Ew 密码: c7r9
main.cpp
/// OpenGL Mathematics (GLM) is a header only C++ mathematics library for graphics software based on the OpenGL Shading Language (GLSL) specifications.#include <glad/glad.h>
#include <GLFW/glfw3.h>#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>#include <iostream>#include "shader.h"
#include "camera.h"
#include "parser.h"using namespace std;
using namespace glm;#define INF 1.0e10// 函数声明
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void picking_callback(GLFWwindow *window, int button, int action, int mods);
void key_callback(GLFWwindow *window, int key, int scancode, int action, int mode);
void interactionFunctions();// 设置窗口大小
const unsigned int SCR_WIDTH = 1024;
const unsigned int SCR_HEIGHT = 768;// 相机
Camera camera(vec3(0.0f, 0.0f, 30.0f));
float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 2.0f;
bool firstMouse = true; // 判断鼠标是否刚进入第一模式, 用于更新光标禁用时鼠标的初始坐标// 时间参数
float deltaTime = 0.0f; // 也用于相机的调整速度
float lastFrame = 0.0f;// 兔子参数
mat4 modelBunny = mat4(1.0f); //四阶单位阵
GLuint vertices_size, indices_size; //无符号整型 顶点以及面片size// !!!: 光照参数
vec3 PointlightPos(15.0f, 15.0f, 15.0f); //三维向量 光照// 鼠标参数
GLfloat mouseX = SCR_WIDTH / 2.0;
GLfloat mouseY = SCR_HEIGHT / 2.0;
GLuint selectedPointIndice = 0; // maxconst int MAXPOINT = 40000;
const int MAXINDEX = 70000;const char* normalFile = "bunny_normal.ply2";
const char *SPLIT = "--------------------------------------------------------------";
GLfloat vertices[MAXPOINT*6];
GLuint indices[MAXINDEX*3];bool keys[1024]; // 存取键码,判断按键情况
bool isAttenuation = false; // 判断光照是否衰减
bool isFlashlight = false; // 判断是否打开闪光灯
bool cursorDisabled = true; // 判断光标是否被禁用void description(){cout << SPLIT << std::endl;cout << "Starting GLFW context, OpenGL 3.3\n";cout << "=: 点光源衰减\n";cout << "ENTER: 光照开关\n";cout << "A: 相机向左.\n";cout << "D: 相机向右.\n";cout << "W: 相机向前\n";cout << "S: 相机向后.\n";cout << "方向键<-: 兔子左移.\n";cout << "方向键->: 兔子右移.\n";cout << "J: 兔子向左旋转.\n";cout << "L: 兔子向右旋转.\n";cout << "I: 兔子向前旋转.\n";cout << "K: 兔子向后旋转\n";cout << "↑或鼠标向上滚动: 兔子放大\n";cout << "↓或鼠标向下滚动: 兔子缩小\n";cout << SPLIT << std::endl;
}//窗口初始化函数
GLFWwindow* init(){glfwInit();//初始化glfw库glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//主版本glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//次版本glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);#ifdef __APPLE__glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif// glfw 窗口创建GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Stanford bunny", NULL, NULL);//如果窗口创建失败,返回失败信息。if (window == NULL){cout << "Failed to create GLFW window" << endl;glfwTerminate(); //释放所有资源exit(EXIT_SUCCESS);}glfwMakeContextCurrent(window); // 设置当前的窗口上下文//注册函数,该函数还可以注册其他相关硬件的回调函数glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//设置按键回调函数glfwSetKeyCallback(window, key_callback);glfwSetCursorPosCallback(window, mouse_callback); //设置光标回调函数glfwSetMouseButtonCallback(window, picking_callback); //设置鼠标按键回调函数glfwSetScrollCallback(window, scroll_callback); //设置滚轮回调函数// 让GLFW捕获鼠标glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);// glad: 加载所有openGL函数指针if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;exit(EXIT_SUCCESS);}// 配置opengl的全局状态: 开启深度测试glEnable(GL_DEPTH_TEST);return window;
}int main(){// glfw: 初始化并且配置相关参数// 输出按键说明description();//调用窗口初始化函数GLFWwindow* window = init();//建立并编译着色器Shader lightingShader("bunny.vs", "bunny.fs"); //vs文件用来处理顶点 fs文件用来处理像素Shader lampShader("lamp.vs", "lamp.fs"); //灯着色器Shader selectShader("select.vs", "select.fs"); //拾取着色器// 设置顶点数据(和缓冲区)并配置顶点属性// 导入ply2文件parseNormal(normalFile, vertices, indices, vertices_size, indices_size);
// parseIndex(normalFile, vertices, indices, vertices_size, indices_size);/*//test code:cout << "测试是否读取正确:" << endl;for (int i = 0; i < 3; i++){cout << vertices[6*i] << " " << vertices[6*i+1] << " " << vertices[6*i+2] << " " << vertices[6*i+3] << " " << vertices[6*i+4] << " " << vertices[6*i+5] << std::endl;}cout << SPLIT << endl;*/// 灯光顶点数据float lightVertices[] = {-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,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,-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,-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,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.2f, -0.2f, -0.2f, 0.2f, -0.2f, -0.2f,// 0.2f, 0.2f, -0.2f, 0.2f, 0.2f, -0.2f,// -0.2f, 0.2f, -0.2f, -0.2f, -0.2f, -0.2f,// -0.2f, -0.2f, 0.2f, 0.2f, -0.2f, 0.2f,// 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f,// -0.2f, 0.2f, 0.2f, -0.2f, -0.2f, 0.2f,// -0.2f, 0.2f, 0.2f, -0.2f, 0.2f, -0.2f,// -0.2f, -0.2f, -0.2f, -0.2f, -0.2f, -0.2f,// -0.2f, -0.2f, 0.2f, -0.2f, 0.2f, 0.2f,// 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, -0.2f,// 0.2f, -0.2f, -0.2f, 0.2f, -0.2f, -0.2f,// 0.2f, -0.2f, 0.2f, 0.2f, 0.2f, 0.2f,// -0.2f, -0.2f, -0.2f, 0.2f, -0.2f, -0.2f,// 0.2f, -0.2f, 0.2f, 0.2f, -0.2f, 0.2f,// -0.2f, -0.2f, 0.2f, -0.2f, -0.2f, -0.2f,// -0.2f, 0.2f, -0.2f, 0.2f, 0.2f, -0.2f,// 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f,// -0.2f, 0.2f, 0.2f, -0.2f, 0.2f, -0.2f};// 第一步,配置兔子的VAO(和VBO)unsigned int bunnyVAO, bunnyVBO, bunnyEBO;glGenVertexArrays(1, &bunnyVAO); // 创建一个顶点数组(Vertex Array Object)对象glGenBuffers(1, &bunnyVBO); // 申请显存空间,分配顶点缓冲对象(Vertex Buffer Object)的IDglGenBuffers(1, &bunnyEBO); // 创建索引缓冲对象(Element Buffer Object)glBindVertexArray(bunnyVAO); // 绑定VAO对象glBindBuffer(GL_ARRAY_BUFFER, bunnyVBO); // 绑定VBOglBufferData(GL_ARRAY_BUFFER, 6*vertices_size*sizeof(GLfloat), vertices, GL_STATIC_DRAW); // 将用户定义的顶点数据传输到绑定的显存缓冲区中glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bunnyEBO); // 绑定EBOglBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * indices_size * sizeof(GLuint), indices, GL_STATIC_DRAW); // 将索引存储到EBO当中/*glVertexAttribPointer()第一个参数指定顶点属性位置,与顶点着色器中layout(location=0)对应。第二个参数指定顶点属性大小。第三个参数指定数据类型。第四个参数定义是否希望数据被标准化。第五个参数是步长(Stride),指定在连续的顶点属性之间的间隔。第六个参数表示我们的位置数据在缓冲区起始位置的偏移量*/// 位置属性glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (void*)0); //通知OPENGL怎么解释这些顶点数据glEnableVertexAttribArray(0); //开启顶点属性// 普通属性glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));glEnableVertexAttribArray(1);glBindBuffer(GL_ARRAY_BUFFER, 0); // 请注意,这是允许的,对glVertexAttribPointer的调用将VBO注册为当前绑定的顶点缓冲区对象,因此之后我们可以安全地取消绑定glBindVertexArray(0); // 取消绑定VAO(取消绑定任何缓冲区/数组以防止出现奇怪的错误始终是一件好事),请记住:请勿取消绑定EBO,继续将其与VAO绑定glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //解除绑定VAO后解除EBO绑定。// 其次,配置灯光的VAO(和VBO)unsigned int lightVAO, lightVBO;glGenVertexArrays(1, &lightVAO);glGenBuffers(1, &lightVBO);glBindBuffer(GL_ARRAY_BUFFER, lightVBO); //绑定缓存glBufferData(GL_ARRAY_BUFFER, sizeof(lightVertices), lightVertices, GL_STATIC_DRAW); //灯光顶点数据绑定到缓存中glBindVertexArray(lightVAO); //绑定灯光VAO对象glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); //通知OPENGL处理顶点数据glEnableVertexAttribArray(0);glBindBuffer(GL_ARRAY_BUFFER, 0); // 请注意,这是允许的,对glVertexAttribPointer的调用将VBO注册为当前绑定的顶点缓冲区对象,因此之后我们可以安全地取消绑定glBindVertexArray(0); // 取消绑定VAO(取消绑定任何缓冲区/数组以防止出现奇怪的错误始终是一件好事),请记住:请勿取消绑定EBO,继续将其与VAO绑定//兔子的初始状态(第二个参数为初始角度,radians设置弧度)modelBunny = rotate(modelBunny, radians(135.0f), vec3(0.0f, 1.0f, 0.0f));// 渲染循环while (!glfwWindowShouldClose(window)){ //glfwWindowShouldClose 检查窗口是否需要关闭// 每帧的时间逻辑float currentFrame = glfwGetTime();deltaTime = currentFrame - lastFrame;lastFrame = currentFrame;// 输入interactionFunctions();// !!!: 设置初始模式if(!cursorDisabled) //如果光标没有禁用// 显示物体所有面,显示线段,多边形用轮廓显示glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);else//否则 显示面,多边形采用填充式glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);// !!!: 渲染背景颜色glClearColor(0.8f, 0.8f, 0.8f, 0.8f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除颜色缓冲以及深度缓冲// 设置格式/绘图对象时一定要激活着色器lightingShader.use();lightingShader.setVec3("viewPos", camera.Position);// 灯光特性vec3 lightColor;// !!!: 颜色按时改变/*//兔子颜色变换,根据glfwGetTime获取时间lightColor.x = sin(glfwGetTime() * 2.0f);lightColor.y = sin(glfwGetTime() * 0.7f);lightColor.z = sin(glfwGetTime() * 1.3f);*/// !!!: 设置光照属性lightColor.x = 4.0f; // 0.0flightColor.y = 4.0f; // 0.0flightColor.z = 0.0f;vec3 diffuseColor = lightColor * vec3(0.3f); // 减少影响vec3 ambientColor = diffuseColor * vec3(0.2f); // 低影响// 点光源lightingShader.setVec3("pointLights.position", PointlightPos);lightingShader.setVec3("pointLights.ambient", ambientColor);lightingShader.setVec3("pointLights.diffuse", diffuseColor);lightingShader.setVec3("pointLights.specular", 1.0f, 1.0f, 1.0f);lightingShader.setFloat("pointLights.constant", 1.0f);lightingShader.setFloat("pointLights.linear", (isAttenuation ? 0.014 : 0.0f));lightingShader.setFloat("pointLights.quadratic", (isAttenuation ? 0.0007 : 0.0f));// 聚光灯lightingShader.setVec3("spotLight.position", camera.Position);lightingShader.setVec3("spotLight.direction", camera.Front);lightingShader.setVec3("spotLight.ambient", 5.0f, 5.0f, 5.0f); //环境光lightingShader.setVec3("spotLight.diffuse", 5.0f, 5.0f, 5.0f); //漫反射光lightingShader.setVec3("spotLight.specular", 0.0f, 0.0f, 0.0f); //镜面高光lightingShader.setFloat("spotLight.constant", (isFlashlight? 1.0f : INF));lightingShader.setFloat("spotLight.linear", 0.045f);lightingShader.setFloat("spotLight.quadratic", 0.0075f);lightingShader.setFloat("spotLight.cutOff", cos(radians(5.0f)));lightingShader.setFloat("spotLight.outerCutOff", cos(radians(9.0f)));// 材料特性lightingShader.setVec3("material.ambient", 1.0f, 0.5f, 0.31f); //环境光
// lightingShader.setVec3("material.ambient", 0.5f, 0.5f, 0.5f); // 环境光lightingShader.setVec3("material.diffuse", 1.0f, 0.5f, 0.2f); //漫反射光lightingShader.setVec3("material.specular", 1.0f, 1.0f, 1.0f); // 镜面光不会完全影响该物体的材质(高光)lightingShader.setFloat("material.shininess", 320.0f);// 查看/投影转换mat4 projection = perspective(radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 1000.0f);mat4 view = camera.GetViewMatrix(); //获取相机的视野矩阵lightingShader.setMat4("projection", projection); //将投影矩阵传入到着色器lightingShader.setMat4("view", view); //相机视野矩阵传入着色器// 世界坐标转换// model = glm::rotate(model, (float)glfwGetTime(), glm::vec3(0.0f, 1.0f, 0.0f));lightingShader.setMat4("model", modelBunny); // 兔子模型参数传入到model着色器// 渲染兔子glBindVertexArray(bunnyVAO); //绑定兔子的VAOglDrawElements(GL_TRIANGLES, 3*indices_size, GL_UNSIGNED_INT, 0);//图元绘制函数glBindVertexArray(0); //取消绑定// !!!: 画出灯的对象lampShader.use();lampShader.setMat4("projection", projection);lampShader.setMat4("view", view);mat4 model = mat4(1.0f);model = translate(model, PointlightPos);model = scale(model, vec3(0.4f)); // 一个较小的立方体(灯源)lampShader.setMat4("model", model);glBindVertexArray(lightVAO);glDrawArrays(GL_TRIANGLES, 0, 36); //根据顶点数组中的坐标数据和指定的模式,进行绘制glBindVertexArray(0);//取消绑定// !!!: 拾取点的坐标if (selectedPointIndice <= vertices_size){ //如果点的索引小于点的个数selectShader.use(); //启用着色器//创建一个四维向量记录当前点的位置//n1 n2 n3 分别为该点的xyz坐标vec4 now(modelBunny * vec4(vertices[selectedPointIndice * 6], vertices[selectedPointIndice * 6 + 1], vertices[selectedPointIndice * 6 + 2], 1.0f));// 创建一个平移矩阵,第一个参数为目标矩阵,第二个矩阵是平移的方向向量smodel = translate(mat4(1.0f), vec3(now.x, now.y, now.z));// model是一个小立方体,scale用于创建一个缩放矩阵model = scale(model, vec3(0.01f, 0.01f, 0.01f));view = camera.GetViewMatrix(); // 视野矩阵projection = perspective(radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 1000.0f); // 查看矩阵// 着色器设置相关矩阵参数selectShader.setMat4("projection", projection);selectShader.setMat4("view", view);selectShader.setMat4("model", model);glBindVertexArray(lightVAO);glDrawArrays(GL_TRIANGLES, 0, 36); //画出一个小立方体框住所选的点。 函数说明:根据顶点数组中的坐标数据和指定的模式(三角形)进行绘制}// glfw: 交换缓冲区和轮询IO事件(按下/释放键,鼠标移动等)glfwSwapBuffers(window); // 交换缓冲区,使用双缓冲(让这个小方块显示在屏幕上);glfwPollEvents();}// optional: 一旦实现了目标取消所有资源分配glDeleteVertexArrays(1, &bunnyVAO);glDeleteVertexArrays(1, &lightVAO);glDeleteBuffers(1, &bunnyVBO);glDeleteBuffers(1, &lightVBO);// glfw: 最后一步,释放所有已分配的GLFW资源。glfwTerminate();return 0;
}// 输入函数
void interactionFunctions(){// 调节旋转/缩放速度GLfloat bunnySpeed = 30.0f * deltaTime;// 相机向前if (keys[GLFW_KEY_W])camera.ProcessKeyboard(FORWARD, bunnySpeed);// 相机向后if (keys[GLFW_KEY_S])camera.ProcessKeyboard(BACKWARD, bunnySpeed);// 相机向左if (keys[GLFW_KEY_A])camera.ProcessKeyboard(LEFT, bunnySpeed);// 相机向右if (keys[GLFW_KEY_D])camera.ProcessKeyboard(RIGHT, bunnySpeed);// <- 兔子向左移动if (keys[GLFW_KEY_LEFT])modelBunny = translate(modelBunny, vec3(bunnySpeed, 0, 0));// -> 兔子向右移动if (keys[GLFW_KEY_RIGHT])modelBunny = translate(modelBunny, vec3(-bunnySpeed, 0, 0));// J 兔子向左转if (keys[GLFW_KEY_J])modelBunny = rotate(modelBunny, radians(bunnySpeed), vec3(0.f, 0.f, 1.f));// L 兔子向右转if (keys[GLFW_KEY_L])modelBunny = glm::rotate(modelBunny, glm::radians(-bunnySpeed), glm::vec3(0.f, 0.f, 1.f));// I 兔子向前转if (keys[GLFW_KEY_I])modelBunny = glm::rotate(modelBunny, glm::radians(-bunnySpeed), glm::vec3(1.f, 0.f, 0.f));// K 兔子向后转if (keys[GLFW_KEY_K])modelBunny = glm::rotate(modelBunny, glm::radians(bunnySpeed), glm::vec3(1.f, 0.f, 0.f));// ↓键 兔子缩小if (keys[GLFW_KEY_DOWN])modelBunny = glm::scale(modelBunny, glm::vec3(1.0f - 0.1f * bunnySpeed, 1.0f - 0.1f * bunnySpeed, 1.0f - 0.1f * bunnySpeed));// ↑键 兔子放大if (keys[GLFW_KEY_UP])modelBunny = glm::scale(modelBunny, glm::vec3(1.0f + 0.1f * bunnySpeed, 1.0f + 0.1f * bunnySpeed, 1.0f + 0.1f * bunnySpeed));
}//处理所有输入:查询GLFW是否在此帧中按下/释放了相关的按键并做出相应的反应
void key_callback(GLFWwindow *window, int key, int scancode, int action, int mode){// 如果按下“=”键if (key == GLFW_KEY_EQUAL && action == GLFW_PRESS){isAttenuation = !isAttenuation; // 将光照是否衰减取反cout << "点光源衰减: ";if(isAttenuation)cout << "打开.\n";elsecout << "关闭.\n";cout << SPLIT << endl;}// 按下Enter键,打开闪光灯if (key == GLFW_KEY_ENTER && action == GLFW_PRESS){isFlashlight = !isFlashlight;cout << "闪光灯: ";if(isFlashlight)cout << "打开.\n";elsecout << "关闭.\n";cout << SPLIT << std::endl;}// 按下esc关闭窗口if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS){glfwSetWindowShouldClose(window, true);}// 按下tab键切换模式if (key == GLFW_KEY_TAB && action == GLFW_PRESS){//获取当前的输入模式,判断光标是否禁用if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED){// 如果禁用,则恢复使用光标glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);cursorDisabled = false; //禁用标志}else{//如果当前光标不被禁用,则禁用光标(离开拾取模式)glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);cursorDisabled = true;firstMouse = true; // 记录鼠标返回第一视角模式}}// 判断所有按键的按下与松开状态if (key >= 0 && key < 1024){if (action == GLFW_PRESS)keys[key] = true;else if (action == GLFW_RELEASE)keys[key] = false;}
}// glfw: 每当改变窗口大小时,就会执行回调函数
void framebuffer_size_callback(GLFWwindow* window, int width, int height){// 确保视口与新的窗口尺寸匹配,请注意,窗口的宽度和高度将大于视口在显示屏上的指定的宽和高glViewport(0, 0, width, height);
}// glfw: 任何时候移动鼠标调用该回调函数
void mouse_callback(GLFWwindow* window, double xpos, double ypos){mouseX = xpos; //鼠标x坐标mouseY = ypos; //鼠标y坐标if(cursorDisabled){ // 如果光标禁用if (firstMouse){ // 如果鼠标第一视角可用更新当前xy坐标lastX = xpos;lastY = ypos;
// cout << lastX << " " << lastY << endl;firstMouse = false;}//计算x y坐标的偏移量float xoffset = xpos - lastX;float yoffset = lastY - ypos; // 反转,在Y坐标轴上,从下到上lastX = xpos;lastY = ypos;camera.ProcessMouseMovement(xoffset, yoffset); // 相机根据坐标偏移量移动}
}// glfw: 任何时候鼠标滚轮滚动时都会调用该函数
// 根据滚轮的滑动,调节相机视图的zoom参数来进行放大缩小
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset){camera.ProcessMouseScroll(yoffset);
}// !!!: 拾取点坐标
void picking_callback(GLFWwindow *window, int button, int action, int mods){// bool test = false;// 判断光标是否没有被禁用 鼠标左键是否被按下if (!cursorDisabled && button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_MOUSE_BUTTON_LEFT){// 鼠标的xy坐标GLfloat xpos = mouseX;GLfloat ypos = mouseY;cout << "
[图形学]OpenGL实现斯坦福兔子(Stanford Bunny)实验代码相关推荐
- 斯坦福兔子和其他图形学模型数据下载
常见模型的下载地址:http://www.cc.gatech.edu/projects/large_models/ 斯坦福兔子的下载地址:http://www.cc.gatech.edu/projec ...
- 计算机图形学 裁剪算法源代码,OpenGL计算机图形学梁友栋裁剪算法实验代码及运行结果.doc...
OpenGL计算机图形学梁友栋裁剪算法实验代码及运行结果.doc (10页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 14.9 积分 .<计算 ...
- 计算机图形Opengl的实验报告,计算机图形学OpenGL实验四.doc
计算机图形学OpenGL实验四 实验报告 学院(系)名称: 姓名学号专业班级实验项目实验四:场景漫游课程名称计算机图形学课程代码实验时间实验地点批改意见成绩教师签字:实验环境(软.硬件环境) 实验目的 ...
- matlab读入三维点云数据斯坦福兔子
其中点云数据是斯坦福兔子,做三维点云重构后的人可以好好看看,只是简单读入程序,作为初学者比较好些,进一步的研究还在后边,有机会的话会继续上传,比如说delauny三角网格划分,还想进一步研究snake ...
- 计算机图形学 opengl版本 第三版------胡事民 第四章 图形学中的向量工具
计算机图形学 opengl版本 第三版------胡事民 第四章 图形学中的向量工具 一 基础 1:向量分析和变换 两个工具 可以设计出各种几何对象 点和向量基于坐标系定义 拇指指向z轴正 ...
- 斯坦福兔子的伪全息舞台剧
前两天用 Python 语言写了个小工具 Hamal,可以将一些朴素的数据文件转化为 POV-Ray 场景文件,然后进行光线跟踪渲染,从而实现数据的可视化.有关 Hamal 的用法,详见 「Hamal ...
- 计算机图形学——OpenGL学习系列之绘制3D下的小桌子
计算机图形学--OpenGL学习系列之绘制3D下的小桌子 做的一个小练习,主要用到了几何变换还有gl自带的一个绘制立方体的函数,顺便体会一下glPush和glPop的用法.另外,从2D到3D,开心到飞 ...
- PCL环境配置+斯坦福兔子测试程序
开发环境:windows10+VisualStudio2017+PCL-1.8.1-AllInOne-msvc2017-win64.exe+pcl-1.8.1-pdb-msvc2017-win64.z ...
- PCL1.12安装+VS2019环境配置+测试程序:斯坦福兔子
PCL 本文源码:PCL环境配置以及测试案例,显示斯坦福兔子 安装 下载PCL的安装包和pdb文件,即PCL...AllInOne...exe和pcl...pdb...zip, 安装.exe文件 我安 ...
- TSP问题由标准格式转成简单格式(我的实验代码需要的格式)
为什么80%的码农都做不了架构师?>>> 最近从网上收集tsp问题实例,因为网上的格式较为复杂,于是进行了一些小的转换.从而成为简单的格式,用于我的实验代码输入.我的代码需要的 ...
最新文章
- Linux下修改Mysql的用户(root)的密码
- shell 安装lamp
- poj 3101 Astronomy (java 分数的最小公倍数 gcd)
- cli2弃用了吗 vue_vue cli - 2 升级到 3的问题汇总
- timespan怎么比较大小_钻石吊坠回收怎么选择大小?
- Git使用教程-idea系列中git使用教程
- java case switch面试_Java基础篇——Java中switch case语句用法及注意事项面试题9期
- 专访京东副总裁翁志:全方位解读 CNCC 2018「数据开创商业新生态」技术论坛 | CNCC 2018...
- 飞机大战游戏微信小程序源码
- cnn视频下载软件附代码
- 某年某月有多少天c语言程序,判断某年某月有多少天(C语言)
- 变量undefined详解
- 交换游戏(状态压缩、记忆化搜索)
- qt导出word模板(模块化程序,直接调用保存数据到指定路径)
- Privacy Policy of Clone App
- 迷你四足机器人制作_从0到1
- Docker学习手记-1
- Unity_7 如何使用遮挡剔除Occlusion Culling
- ios html调起高德地图,iOS开发笔记 调起本地地图导航(百度、高德、腾讯、苹果自带)...
- 观景台售票情况数据分析【Python】
热门文章
- 图解机器学习—算法原理与Python语言实现(文末留言送书)
- 【Appium实战】如何使用mumu模拟器模拟安卓手机
- 【战“疫”案例展】上海临港方舱医院——7天打造“数字方舱”,搭建智能化管理系统平台...
- Docker for Mac配置阿里加速器
- CEEMDAN算法及其应用
- 【Spring学习03】Spring简单入门实例
- matlab画中国,用matlab绘制中国地图
- SQL Server 添加字段 修改字段 删除字段 语句
- 智伴机器人传销_智伴机器人是传销吗?
- 智伴机器人wifi键在哪里_智伴机器人连不上WiFi