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