OpenGL 实例化 初探 之 非实例化绘制行星带
来源:互联网 发布:什么软件收二手手机 编辑:程序博客网 时间:2024/05/20 04:10
http://learnopengl-cn.readthedocs.io/zh/latest/04%20Advanced%20OpenGL/10%20Instancing/
http://blog.csdn.net/wangdingqiaoit/article/details/52733351
main.cpp
// 引入GLEW库 定义静态链接#define GLEW_STATIC#include <glew.h>// 引入GLFW库#include <GLFW/glfw3.h>// 引入SOIL库#include <SOIL/SOIL.h>// 引入GLM库#include <GLM/glm.hpp>#include <GLM/gtc/matrix_transform.hpp>#include <GLM/gtc/type_ptr.hpp>#include <iostream>#include <vector>#include <cstdlib>// 包含着色器加载库#include "shader.h"// 包含相机控制辅助类#include "camera.h"// 包含纹理加载类#include "texture.h"// 加载模型的类#include "model.h"#pragma comment(lib, "./SOIL.lib")#pragma comment (lib, "opengl32.lib")#pragma comment (lib, "glew32s.lib")#pragma comment (lib, "glfw3.lib") #pragma comment (lib, "glfw3dll.lib") #pragma comment (lib, "glew32mxs.lib")#pragma comment (lib, "assimp.lib")// 键盘回调函数原型声明void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);// 鼠标移动回调函数原型声明void mouse_move_callback(GLFWwindow* window, double xpos, double ypos);// 鼠标滚轮回调函数原型声明void mouse_scroll_callback(GLFWwindow* window, double xoffset, double yoffset);// 场景中移动void do_movement();void prepareInstanceMatrices(std::vector<glm::mat4>& modelMatrices, const int amount);// 定义程序常量const int WINDOW_WIDTH = 800, WINDOW_HEIGHT = 600;// 用于相机交互参数GLfloat lastX = WINDOW_WIDTH / 2.0f, lastY = WINDOW_HEIGHT / 2.0f;bool firstMouseMove = true;bool keyPressedStatus[1024]; // 按键情况记录GLfloat deltaTime = 0.0f; // 当前帧和上一帧的时间差GLfloat lastFrame = 0.0f; // 上一帧时间Camera camera(glm::vec3(0.0f, 0.0f, 55.0f));const int INSTANCE_COUNT = 10000;int main(int argc, char** argv){ if (!glfwInit()) // 初始化glfw库 { std::cout << "Error::GLFW could not initialize GLFW!" << std::endl; return -1; } // 开启OpenGL 3.3 core profile std::cout << "Start OpenGL core profile version 3.3" << std::endl; 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); // 创建窗口 GLFWwindow* window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo of instancing model", NULL, NULL); if (!window) { std::cout << "Error::GLFW could not create winddow!" << std::endl; glfwTerminate(); std::system("pause"); return -1; } // 创建的窗口的context指定为当前context glfwMakeContextCurrent(window); // 注册窗口键盘事件回调函数 glfwSetKeyCallback(window, key_callback); // 注册鼠标事件回调函数 glfwSetCursorPosCallback(window, mouse_move_callback); // 注册鼠标滚轮事件回调函数 glfwSetScrollCallback(window, mouse_scroll_callback); // 鼠标捕获 停留在程序内 //glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); // 初始化GLEW 获取OpenGL函数 glewExperimental = GL_TRUE; // 让glew获取所有拓展函数 GLenum status = glewInit(); if (status != GLEW_OK) { std::cout << "Error::GLEW glew version:" << glewGetString(GLEW_VERSION) << " error string:" << glewGetErrorString(status) << std::endl; glfwTerminate(); std::system("pause"); return -1; } // 设置视口参数 glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); //Section1 加载模型数据 为了方便更换模型 我们从文件读取模型文件路径 Model objModels[2]; std::ifstream modelPath("./res/modelPath.txt"); if (!modelPath) { std::cerr << "Error::could not read model path file." << std::endl; glfwTerminate(); std::system("pause"); return -1; } std::string modelFilePath; for (int i = 0; i < 2; ++i) { std::getline(modelPath, modelFilePath); if (modelFilePath.empty()) { std::cerr << "Error::model path empty." << std::endl; glfwTerminate(); std::system("pause"); return -1; } if (!objModels[i].loadModel(modelFilePath)) { glfwTerminate(); std::system("pause"); return -1; } } Model& planet = objModels[0]; Model& rock = objModels[1]; // Section2 准备着色器程序 Shader shader("./Shader/vertices", "./Shader/fragement"); // Section3 为多个实例准备模型变换矩阵 std::vector<glm::mat4> modelMatrices; prepareInstanceMatrices(modelMatrices, INSTANCE_COUNT); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); // 开始游戏主循环 while (!glfwWindowShouldClose(window)) { GLfloat currentFrame = (GLfloat)glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; std::cout << " time used in this frame: " << deltaTime << " seconds." << std::endl; glfwPollEvents(); // 处理例如鼠标 键盘等事件 do_movement(); // 根据用户操作情况 更新相机属性 // 清除颜色缓冲区 重置为指定颜色 glClearColor(0.18f, 0.04f, 0.14f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 场景绘制 shader.use(); glm::mat4 projection = glm::perspective(camera.mouse_zoom, (GLfloat)(WINDOW_WIDTH) / WINDOW_HEIGHT, 1.0f, 10000.0f); // 投影矩阵 glm::mat4 view = camera.getViewMatrix(); // 视变换矩阵 glUniformMatrix4fv(glGetUniformLocation(shader.programId, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); glUniformMatrix4fv(glGetUniformLocation(shader.programId, "view"), 1, GL_FALSE, glm::value_ptr(view)); glm::mat4 model; model = glm::translate(model, glm::vec3(0.0f, -3.0f, 0.0f)); model = glm::scale(model, glm::vec3(4.0f, 4.0f, 4.0f)); glUniformMatrix4fv(glGetUniformLocation(shader.programId, "model"), 1, GL_FALSE, glm::value_ptr(model)); planet.draw(shader); // 先绘制行星 // 绘制多个小行星实例 for (std::vector<glm::mat4>::size_type i = 0; i < modelMatrices.size(); ++i) { glUniformMatrix4fv(glGetUniformLocation(shader.programId, "model"), 1, GL_FALSE, glm::value_ptr(modelMatrices[i])); rock.draw(shader); } glBindVertexArray(0); glUseProgram(0); glfwSwapBuffers(window); // 交换缓存 } // 释放资源 glfwTerminate(); return 0;}void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods){ if (key >= 0 && key < 1024) { if (action == GLFW_PRESS) keyPressedStatus[key] = true; else if (action == GLFW_RELEASE) keyPressedStatus[key] = false; } if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { glfwSetWindowShouldClose(window, GL_TRUE); // 关闭窗口 }}void mouse_move_callback(GLFWwindow* window, double xpos, double ypos){ if (firstMouseMove) // 首次鼠标移动 { lastX = xpos; lastY = ypos; firstMouseMove = false; } GLfloat xoffset = xpos - lastX; GLfloat yoffset = lastY - ypos; lastX = xpos; lastY = ypos; camera.handleMouseMove(xoffset, yoffset);}// 由相机辅助类处理鼠标滚轮控制void mouse_scroll_callback(GLFWwindow* window, double xoffset, double yoffset){ camera.handleMouseScroll(yoffset);}// 由相机辅助类处理键盘控制void do_movement(){ if (keyPressedStatus[GLFW_KEY_W]) camera.handleKeyPress(FORWARD, deltaTime); if (keyPressedStatus[GLFW_KEY_S]) camera.handleKeyPress(BACKWARD, deltaTime); if (keyPressedStatus[GLFW_KEY_A]) camera.handleKeyPress(LEFT, deltaTime); if (keyPressedStatus[GLFW_KEY_D]) camera.handleKeyPress(RIGHT, deltaTime);}// 为实例准备模型变换矩阵// 这里的细节可以不用深究void prepareInstanceMatrices(std::vector<glm::mat4>& modelMatrices, const int amount){ srand(glfwGetTime()); // 初始化随机数的种子 GLfloat radius = 50.0; GLfloat offset = 2.5f; for (GLuint i = 0; i < amount; i++) { glm::mat4 model; // 1. 平移 GLfloat angle = (GLfloat)i / (GLfloat)amount * 360.0f; GLfloat displacement = (rand() % (GLint)(2 * offset * 100)) / 100.0f - offset; GLfloat x = sin(angle) * radius + displacement; displacement = (rand() % (GLint)(2 * offset * 100)) / 100.0f - offset; GLfloat y = displacement * 0.4f; displacement = (rand() % (GLint)(2 * offset * 100)) / 100.0f - offset; GLfloat z = cos(angle) * radius + displacement; model = glm::translate(model, glm::vec3(x, y, z)); // 2. 缩放 在 0.05 和 0.25f 之间 GLfloat scale = (rand() % 20) / 100.0f + 0.05; model = glm::scale(model, glm::vec3(scale)); // 3. 旋转 GLfloat rotAngle = (rand() % 360); model = glm::rotate(model, rotAngle, glm::vec3(0.4f, 0.6f, 0.8f)); // 4. 添加作为模型变换矩阵 modelMatrices.push_back(model); }}
mesh.h
#ifndef _MESH_H_#define _MESH_H_#include <glew.h>#include <glm/glm.hpp>#include <glm/gtc/matrix_transform.hpp>#include <glm/gtx/string_cast.hpp>#include <string> #include <vector>#include <fstream>#include <sstream>#include <algorithm>#include <assimp/Importer.hpp>#include <assimp/scene.h>#include <assimp/postprocess.h>#include "shader.h"// 表示一个顶点属性struct Vertex{ glm::vec3 position; glm::vec2 texCoords; glm::vec3 normal;};// 表示一个Texturestruct Texture{ GLuint id; aiTextureType type; std::string path;};// 表示一个用于渲染的最小实体class Mesh{public: void draw(const Shader& shader) const// 绘制Mesh { if (VAOId == 0 || VBOId == 0 || EBOId == 0) { return; } glBindVertexArray(this->VAOId); int texUnitCnt = this->bindTextures(shader); glDrawElements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_INT, 0); glBindVertexArray(0); // 一个好的习惯是 在这里移除纹理绑定 this->unBindTextures(texUnitCnt); } int bindTextures(const Shader& shader) const { int diffuseCnt = 0, specularCnt = 0, texUnitCnt = 0; for (std::vector<Texture>::const_iterator it = this->textures.begin(); this->textures.end() != it; ++it) { switch (it->type) { case aiTextureType_DIFFUSE: { glActiveTexture(GL_TEXTURE0 + texUnitCnt); glBindTexture(GL_TEXTURE_2D, it->id); std::stringstream samplerNameStr; samplerNameStr << "texture_diffuse" << diffuseCnt++; glUniform1i(glGetUniformLocation(shader.programId, samplerNameStr.str().c_str()), texUnitCnt++); } break; case aiTextureType_SPECULAR: { glActiveTexture(GL_TEXTURE0 + texUnitCnt); glBindTexture(GL_TEXTURE_2D, it->id); std::stringstream samplerNameStr; samplerNameStr << "texture_specular" << specularCnt++; glUniform1i(glGetUniformLocation(shader.programId, samplerNameStr.str().c_str()), texUnitCnt++); } break; default: std::cerr << "Warning::Mesh::draw, texture type" << it->type << " current not supported." << std::endl; break; } } return texUnitCnt; } void unBindTextures(const int texUnitCnt) const { for (int i = 0; i < texUnitCnt; ++i) { glActiveTexture(GL_TEXTURE0 + i); glBindTexture(GL_TEXTURE_2D, 0); } } Mesh() :VAOId(0), VBOId(0), EBOId(0) {} Mesh(const std::vector<Vertex>& vertData, const std::vector<Texture> & textures, const std::vector<GLuint>& indices) :VAOId(0), VBOId(0), EBOId(0) // 构造一个Mesh { setData(vertData, textures, indices); } void setData(const std::vector<Vertex>& vertData, const std::vector<Texture> & textures, const std::vector<GLuint>& indices) { this->vertData = vertData; this->indices = indices; this->textures = textures; if (!vertData.empty() && !indices.empty()) { this->setupMesh(); } } void final() const { glDeleteVertexArrays(1, &this->VAOId); glDeleteBuffers(1, &this->VBOId); glDeleteBuffers(1, &this->EBOId); } ~Mesh() { // 不要再这里释放VBO等空间 因为Mesh对象传递时 临时对象销毁后这里会清理VBO等空间 } GLuint getVAOId() const { return this->VAOId; } const std::vector<Vertex>& getVertices() const { return this->vertData; } const std::vector<GLuint>& getIndices() const { return this->indices; }private: std::vector<Vertex> vertData; std::vector<GLuint> indices; std::vector<Texture> textures; GLuint VAOId, VBOId, EBOId; void setupMesh() // 建立VAO,VBO等缓冲区 { glGenVertexArrays(1, &this->VAOId); glGenBuffers(1, &this->VBOId); glGenBuffers(1, &this->EBOId); glBindVertexArray(this->VAOId); glBindBuffer(GL_ARRAY_BUFFER, this->VBOId); glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * this->vertData.size(), &this->vertData[0], GL_STATIC_DRAW); // 顶点位置属性 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)0); glEnableVertexAttribArray(0); // 顶点纹理坐标 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(3 * sizeof(GL_FLOAT))); glEnableVertexAttribArray(1); // 顶点法向量属性 glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(5 * sizeof(GL_FLOAT))); glEnableVertexAttribArray(2); // 索引数据 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->EBOId); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)* this->indices.size(), &this->indices[0], GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); }};#endif
model.h
#ifndef _MODEL_H_#define _MODEL_H_#include <map>#include <assimp/Importer.hpp>#include <assimp/scene.h>#include <assimp/postprocess.h>#include "mesh.h"#include "texture.h"/** 代表一个模型 模型可以包含一个或多个Mesh*/class Model{public: void draw(const Shader& shader) const { for (std::vector<Mesh>::const_iterator it = this->meshes.begin(); this->meshes.end() != it; ++it) { it->draw(shader); } } bool loadModel(const std::string& filePath) { Assimp::Importer importer; if (filePath.empty()) { std::cerr << "Error:Model::loadModel, empty model file path." << std::endl; return false; } const aiScene* sceneObjPtr = importer.ReadFile(filePath, aiProcess_Triangulate | aiProcess_FlipUVs); if (!sceneObjPtr || sceneObjPtr->mFlags == AI_SCENE_FLAGS_INCOMPLETE || !sceneObjPtr->mRootNode) { std::cerr << "Error:Model::loadModel, description: " << importer.GetErrorString() << std::endl; return false; } this->modelFileDir = filePath.substr(0, filePath.find_last_of('/')); if (!this->processNode(sceneObjPtr->mRootNode, sceneObjPtr)) { std::cerr << "Error:Model::loadModel, process node failed." << std::endl; return false; } return true; } ~Model() { for (std::vector<Mesh>::const_iterator it = this->meshes.begin(); this->meshes.end() != it; ++it) { it->final(); } } const std::vector<Mesh>& getMeshes() const { return this->meshes; }private: /* * 递归处理模型的结点 */ bool processNode(const aiNode* node, const aiScene* sceneObjPtr) { if (!node || !sceneObjPtr) { return false; } // 先处理自身结点 for (size_t i = 0; i < node->mNumMeshes; ++i) { // 注意node中的mesh是对sceneObject中mesh的索引 const aiMesh* meshPtr = sceneObjPtr->mMeshes[node->mMeshes[i]]; if (meshPtr) { Mesh meshObj; if (this->processMesh(meshPtr, sceneObjPtr, meshObj)) { this->meshes.push_back(meshObj); } } } // 处理孩子结点 for (size_t i = 0; i < node->mNumChildren; ++i) { this->processNode(node->mChildren[i], sceneObjPtr); } return true; } bool processMesh(const aiMesh* meshPtr, const aiScene* sceneObjPtr, Mesh& meshObj) { if (!meshPtr || !sceneObjPtr) { return false; } std::vector<Vertex> vertData; std::vector<Texture> textures; std::vector<GLuint> indices; // 从Mesh得到顶点数据、法向量、纹理数据 for (size_t i = 0; i < meshPtr->mNumVertices; ++i) { Vertex vertex; // 获取顶点位置 if (meshPtr->HasPositions()) { vertex.position.x = meshPtr->mVertices[i].x; vertex.position.y = meshPtr->mVertices[i].y; vertex.position.z = meshPtr->mVertices[i].z; } // 获取纹理数据 目前只处理0号纹理 if (meshPtr->HasTextureCoords(0)) { vertex.texCoords.x = meshPtr->mTextureCoords[0][i].x; vertex.texCoords.y = meshPtr->mTextureCoords[0][i].y; } else { vertex.texCoords = glm::vec2(0.0f, 0.0f); } // 获取法向量数据 if (meshPtr->HasNormals()) { vertex.normal.x = meshPtr->mNormals[i].x; vertex.normal.y = meshPtr->mNormals[i].y; vertex.normal.z = meshPtr->mNormals[i].z; } vertData.push_back(vertex); } // 获取索引数据 for (size_t i = 0; i < meshPtr->mNumFaces; ++i) { aiFace face = meshPtr->mFaces[i]; if (face.mNumIndices != 3) { std::cerr << "Error:Model::processMesh, mesh not transformed to triangle mesh." << std::endl; return false; } for (size_t j = 0; j < face.mNumIndices; ++j) { indices.push_back(face.mIndices[j]); } } // 获取纹理数据 if (meshPtr->mMaterialIndex >= 0) { const aiMaterial* materialPtr = sceneObjPtr->mMaterials[meshPtr->mMaterialIndex]; // 获取diffuse类型 std::vector<Texture> diffuseTexture; this->processMaterial(materialPtr, sceneObjPtr, aiTextureType_DIFFUSE, diffuseTexture); textures.insert(textures.end(), diffuseTexture.begin(), diffuseTexture.end()); // 获取specular类型 std::vector<Texture> specularTexture; this->processMaterial(materialPtr, sceneObjPtr, aiTextureType_SPECULAR, specularTexture); textures.insert(textures.end(), specularTexture.begin(), specularTexture.end()); } meshObj.setData(vertData, textures, indices); return true; } /* * 获取一个材质中的纹理 */ bool processMaterial(const aiMaterial* matPtr, const aiScene* sceneObjPtr, const aiTextureType textureType, std::vector<Texture>& textures) { textures.clear(); if (!matPtr || !sceneObjPtr) { return false; } if (matPtr->GetTextureCount(textureType) <= 0) { return true; } for (size_t i = 0; i < matPtr->GetTextureCount(textureType); ++i) { Texture text; aiString textPath; aiReturn retStatus = matPtr->GetTexture(textureType, i, &textPath); if (retStatus != aiReturn_SUCCESS || textPath.length == 0) { std::cerr << "Warning, load texture type=" << textureType << "index= " << i << " failed with return value= " << retStatus << std::endl; continue; } std::string absolutePath = this->modelFileDir + "/" + textPath.C_Str(); LoadedTextMapType::const_iterator it = this->loadedTextureMap.find(absolutePath); if (it == this->loadedTextureMap.end()) // 检查是否已经加载过了 { GLuint textId = TextureHelper::load2DTexture(absolutePath.c_str()); text.id = textId; text.path = absolutePath; text.type = textureType; textures.push_back(text); loadedTextureMap[absolutePath] = text; } else { textures.push_back(it->second); } } return true; }private: std::vector<Mesh> meshes; // 保存Mesh std::string modelFileDir; // 保存模型文件的文件夹路径 typedef std::map<std::string, Texture> LoadedTextMapType; // key = texture file path LoadedTextMapType loadedTextureMap; // 保存已经加载的纹理};#endif
Camera.h
#ifndef _CAMERA_H_#define _CAMERA_H_#include <iostream>#include <fstream>#include <glew.h>#include <glm/glm.hpp>#include <glm/gtc/matrix_transform.hpp>#include <glm/gtx/string_cast.hpp>#include <iomanip> // std::setprecision// 定义移动方向enum Camera_Movement { FORWARD, BACKWARD, LEFT, RIGHT};// 定义预设常量const GLfloat YAW = 0.0f;const GLfloat PITCH = 0.0f;const GLfloat SPEED = 3.0f;const GLfloat MOUSE_SENSITIVTY = 0.05f;const GLfloat MOUSE_ZOOM = 45.0f;const float MAX_PITCH_ANGLE = 89.0f; // 防止万向锁class Camera{public: Camera(glm::vec3 pos = glm::vec3(0.0, 0.0, 2.0), glm::vec3 up = glm::vec3(0.0, 1.0, 0.0), GLfloat yaw = YAW, GLfloat pitch = PITCH) :position(pos), forward(0.0, 0.0, -1.0), viewUp(up), moveSpeed(SPEED), mouse_zoom(MOUSE_ZOOM), mouse_sensitivity(MOUSE_SENSITIVTY), yawAngle(yaw), pitchAngle(pitch) { this->updateCameraVectors(); }public: // 获取视变换矩阵 glm::mat4 getViewMatrix() { return glm::lookAt(this->position, this->position + this->forward, this->viewUp); } // 处理键盘按键后方向移动 void handleKeyPress(Camera_Movement direction, GLfloat deltaTime) { GLfloat velocity = this->moveSpeed * deltaTime; switch (direction) { case FORWARD: this->position += this->forward * velocity; break; case BACKWARD: this->position -= this->forward * velocity; break; case LEFT: this->position -= this->side * velocity; break; case RIGHT: this->position += this->side * velocity; break; default: break; } } // 处理鼠标移动 void handleMouseMove(GLfloat xoffset, GLfloat yoffset) { xoffset *= this->mouse_sensitivity; // 用鼠标灵敏度调节角度变换 yoffset *= this->mouse_sensitivity; this->pitchAngle += yoffset; this->yawAngle += xoffset; this->normalizeAngle(); this->updateCameraVectors(); } // 处理鼠标滚轮缩放 保持在[1.0, MOUSE_ZOOM]之间 void handleMouseScroll(GLfloat yoffset) { if (this->mouse_zoom >= 1.0f && this->mouse_zoom <= MOUSE_ZOOM) this->mouse_zoom -= this->mouse_sensitivity * yoffset; if (this->mouse_zoom <= 1.0f) this->mouse_zoom = 1.0f; if (this->mouse_zoom >= 45.0f) this->mouse_zoom = 45.0f; } // 使pitch yaw角度保持在合理范围内 void normalizeAngle() { if (this->pitchAngle > MAX_PITCH_ANGLE) this->pitchAngle = MAX_PITCH_ANGLE; if (this->pitchAngle < -MAX_PITCH_ANGLE) this->pitchAngle = -MAX_PITCH_ANGLE; if (this->yawAngle < 0.0f) this->yawAngle += 360.0f; } // 计算forward side向量 void updateCameraVectors() { glm::vec3 forward; forward.x = -sin(glm::radians(this->yawAngle)) * cos(glm::radians(this->pitchAngle)); forward.y = sin(glm::radians(this->pitchAngle)); forward.z = -cos(glm::radians(this->yawAngle)) * cos(glm::radians(this->pitchAngle)); this->forward = glm::normalize(forward); glm::vec3 side; side.x = cos(glm::radians(this->yawAngle)); side.y = 0; side.z = -sin(glm::radians(this->yawAngle)); this->side = glm::normalize(side); }public: glm::vec3 forward, up, side, viewUp, position; // 相机属性 GLfloat yawAngle, pitchAngle; // 欧拉角 GLfloat moveSpeed, mouse_sensitivity, mouse_zoom; // 相机选项};#endif
texture.h
#ifndef _TEXTURE_H_#define _TEXTURE_H_#include <glew.h>#include <iostream>#include <fstream>class TextureHelper{public: /* /* 成功加载2D纹理则返回纹理对象Id 否则返回0 */ static GLuint load2DTexture(const char* filename, GLint internalFormat = GL_RGBA, GLenum picFormat = GL_RGBA, int loadChannels = SOIL_LOAD_RGBA) { // Step1 创建并绑定纹理对象 GLuint textureId = 0; glGenTextures(1, &textureId); glBindTexture(GL_TEXTURE_2D, textureId); // Step2 设定wrap参数 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Step3 设定filter参数 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // 为MipMap设定filter方法 // Step4 加载纹理 GLubyte *imageData = NULL; int picWidth, picHeight; int channels = 0; imageData = SOIL_load_image(filename, &picWidth, &picHeight, &channels, loadChannels); if (imageData == NULL) { std::cerr << "Error::Texture could not load texture file:" << filename << std::endl; return 0; } glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, picWidth, picHeight, 0, picFormat, GL_UNSIGNED_BYTE, imageData); glGenerateMipmap(GL_TEXTURE_2D); // Step5 释放纹理图片资源 SOIL_free_image_data(imageData); glBindTexture(GL_TEXTURE_2D, 0); return textureId; }#define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII#define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII#define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII static GLuint loadDDS(const char * filename) { /* try to open the file */ std::ifstream file(filename, std::ios::in | std::ios::binary); if (!file) { std::cout << "Error::loadDDs, could not open:" << filename << "for read." << std::endl; return 0; } /* verify the type of file */ char filecode[4]; file.read(filecode, 4); if (strncmp(filecode, "DDS ", 4) != 0) { std::cout << "Error::loadDDs, format is not dds :" << filename << std::endl; file.close(); return 0; } /* get the surface desc */ char header[124]; file.read(header, 124); unsigned int height = *(unsigned int*)&(header[8]); unsigned int width = *(unsigned int*)&(header[12]); unsigned int linearSize = *(unsigned int*)&(header[16]); unsigned int mipMapCount = *(unsigned int*)&(header[24]); unsigned int fourCC = *(unsigned int*)&(header[80]); char * buffer = NULL; unsigned int bufsize; /* how big is it going to be including all mipmaps? */ bufsize = mipMapCount > 1 ? linearSize * 2 : linearSize; buffer = new char[bufsize]; file.read(buffer, bufsize); /* close the file pointer */ file.close(); unsigned int components = (fourCC == FOURCC_DXT1) ? 3 : 4; unsigned int format; switch (fourCC) { case FOURCC_DXT1: format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; case FOURCC_DXT3: format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; case FOURCC_DXT5: format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; default: delete[] buffer; return 0; } // Create one OpenGL texture GLuint textureID; glGenTextures(1, &textureID); // "Bind" the newly created texture : all future texture functions will modify this texture glBindTexture(GL_TEXTURE_2D, textureID); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); unsigned int blockSize = (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16; unsigned int offset = 0; /* load the mipmaps */ for (unsigned int level = 0; level < mipMapCount && (width || height); ++level) { unsigned int size = ((width + 3) / 4)*((height + 3) / 4)*blockSize; glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height, 0, size, buffer + offset); offset += size; width /= 2; height /= 2; // Deal with Non-Power-Of-Two textures. This code is not included in the webpage to reduce clutter. if (width < 1) width = 1; if (height < 1) height = 1; } delete[] buffer; return textureID; }};#endif
Shader.h
#ifndef _SHADER_H_#define _SHADER_H_#include <glew.h>#include <iterator> // std::istreambuf_iterator#include <string> #include <vector>#include <iostream>#include <fstream>struct ShaderFile{ GLenum shaderType; const char* filePath; ShaderFile(GLenum type, const char* path) :shaderType(type), filePath(path) {}};class Shader{public: Shader(const char* vertexPath, const char* fragPath) :programId(0) { std::vector<ShaderFile> fileVec; fileVec.push_back(ShaderFile(GL_VERTEX_SHADER, vertexPath)); fileVec.push_back(ShaderFile(GL_FRAGMENT_SHADER, fragPath)); loadFromFile(fileVec); } Shader(const char* vertexPath, const char* fragPath, const char* geometryPath) :programId(0) { std::vector<ShaderFile> fileVec; fileVec.push_back(ShaderFile(GL_VERTEX_SHADER, vertexPath)); fileVec.push_back(ShaderFile(GL_FRAGMENT_SHADER, fragPath)); fileVec.push_back(ShaderFile(GL_GEOMETRY_SHADER, geometryPath)); loadFromFile(fileVec); } void use() { glUseProgram(this->programId); } ~Shader() { if (this->programId) { glDeleteProgram(this->programId); } }public: GLuint programId;private: /* * 从文件加载顶点和片元着色器 * 传递参数为 [(着色器文件类型,着色器文件路径)+] */ void loadFromFile(std::vector<ShaderFile>& shaderFileVec) { std::vector<GLuint> shaderObjectIdVec; std::string vertexSource, fragSource; std::vector<std::string> sourceVec; size_t shaderCount = shaderFileVec.size(); // 读取文件源代码 for (size_t i = 0; i < shaderCount; ++i) { std::string shaderSource; if (!loadShaderSource(shaderFileVec[i].filePath, shaderSource)) { std::cout << "Error::Shader could not load file:" << shaderFileVec[i].filePath << std::endl; return; } sourceVec.push_back(shaderSource); } bool bSuccess = true; // 编译shader object for (size_t i = 0; i < shaderCount; ++i) { GLuint shaderId = glCreateShader(shaderFileVec[i].shaderType); const char *c_str = sourceVec[i].c_str(); glShaderSource(shaderId, 1, &c_str, NULL); glCompileShader(shaderId); GLint compileStatus = 0; glGetShaderiv(shaderId, GL_COMPILE_STATUS, &compileStatus); // 检查编译状态 if (compileStatus == GL_FALSE) // 获取错误报告 { GLint maxLength = 0; glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &maxLength); std::vector<GLchar> errLog(maxLength); glGetShaderInfoLog(shaderId, maxLength, &maxLength, &errLog[0]); std::cout << "Error::Shader file [" << shaderFileVec[i].filePath << " ] compiled failed," << &errLog[0] << std::endl; bSuccess = false; } shaderObjectIdVec.push_back(shaderId); } // 链接shader program if (bSuccess) { this->programId = glCreateProgram(); for (size_t i = 0; i < shaderCount; ++i) { glAttachShader(this->programId, shaderObjectIdVec[i]); } glLinkProgram(this->programId); GLint linkStatus; glGetProgramiv(this->programId, GL_LINK_STATUS, &linkStatus); if (linkStatus == GL_FALSE) { GLint maxLength = 0; glGetProgramiv(this->programId, GL_INFO_LOG_LENGTH, &maxLength); std::vector<GLchar> errLog(maxLength); glGetProgramInfoLog(this->programId, maxLength, &maxLength, &errLog[0]); std::cout << "Error::shader link failed," << &errLog[0] << std::endl; } } // 链接完成后detach 并释放shader object for (size_t i = 0; i < shaderCount; ++i) { if (this->programId != 0) { glDetachShader(this->programId, shaderObjectIdVec[i]); } glDeleteShader(shaderObjectIdVec[i]); } } /* * 读取着色器程序源码 */ bool loadShaderSource(const char* filePath, std::string& source) { source.clear(); std::ifstream in_stream(filePath); if (!in_stream) { return false; } source.assign(std::istreambuf_iterator<char>(in_stream), std::istreambuf_iterator<char>()); // 文件流迭代器构造字符串 return true; }};#endif
GLSL Shader 部分
vertices
#version 330 corelayout(location = 0) in vec3 position;layout(location = 1) in vec2 textCoord;layout(location = 2) in vec3 normal;uniform mat4 projection;uniform mat4 view;uniform mat4 model;out vec2 TextCoord;void main(){ gl_Position = projection * view * model * vec4(position, 1.0); TextCoord = textCoord;}
fragement
#version 330 corein vec2 TextCoord;uniform sampler2D texture_diffuse0;uniform sampler2D texture_diffuse1;uniform sampler2D texture_specular0;uniform sampler2D texture_specular1;out vec4 color;void main(){ color = texture(texture_diffuse0, TextCoord);}
源码下载:
http://download.csdn.net/detail/yulinxx/9724853
用此方式,若将
const int INSTANCE_COUNT = 10000;
改为
const int INSTANCE_COUNT = 100000;
效率就很低了
0 0
- OpenGL 实例化 初探 之 实例化绘制行星带
- OpenGL 实例化 初探 之 非实例化绘制行星带
- OpenGL 实例化 初探
- OpenGL绘制旋转三角形实例
- OpenGL绘制旋转立方体实例
- OpenGL绘制旋转三角形实例
- OpenGL绘制旋转立方体实例
- OpenGL绘制旋转立方体实例
- OpenGL ES之GLSurfaceView学习二:非交互式的实例
- OpenGL ES之GLSurfaceView学习二:非交互式的实例
- OpenGL ES之GLSurfaceView学习二:非交互式的实例
- OpenGL ES之GLSurfaceView学习二:非交互式的实例
- OpenGL学习10_绘制行星系统
- OpenGL学习10_绘制行星系统
- css八大行星旋转实例
- Globe中是用OpenGL绘制图形实例
- 图解opengl 3D 图形绘制实例
- 2.6.5 实例化绘制glDrawArraysInstanced()
- CodeForces - 744A Hongcow Builds A Nation (并查集+容斥)
- IO流复制文件
- JPA 深度刘宝宝剖析版
- 制作支持OS::Heat::SoftwareConfig以及ansible组件的自定义centos7镜像
- android 动画系列:插值器-Interpolator
- OpenGL 实例化 初探 之 非实例化绘制行星带
- spring boot 配置文件后缀的一个坑
- C++的继承,多继承,虚继承的对象分布的总结
- Azkaban文档
- 【eclipse高效开发】——ASTView节点详解
- Android中的Material design animation
- python中的切片和join的妙用
- python检索特定内容的文本文件2
- php语法基础(二)- get和post请求