首页 > 学院 > 开发设计 > 正文

OpenGL 视差贴图 基础 Parallax Mapping

2019-11-11 06:13:55
字体:
来源:转载
供稿:网友

main.cpp

#include <string>#define GLEW_STATIC#include <GL/glew.h>#include <GLFW/glfw3.h>#include "shader.h"#include "Camera.h"#include "model.h"#include <glm/glm.hpp>#include <glm/gtc/matrix_transform.hpp>#include <glm/gtc/type_ptr.hpp>#include <SOIL/SOIL.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")const GLuint SCR_WIDTH = 800, SCR_HEIGHT = 600;void key_callback(GLFWwindow* pWnd, int key, int scancode, int action, int mode);void scroll_callback(GLFWwindow* pWnd, double xoffset, double yoffset);void mouse_callback(GLFWwindow* pWnd, double xpos, double ypos);void Do_Movement();void RenderQuad();GLuint loadTexture(GLchar* path);Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));GLfloat deltaTime = 0.0f;GLfloat lastFrame = 0.0f;GLboolean parallax_mapping = true;GLfloat height_scale = 0.1;/*************************************************************************/int main(){ // Init GLFW 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); GLFWwindow* pWnd = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "OGLParallaxMapping", nullptr, nullptr); glfwMakeContextCurrent(pWnd); glfwSetKeyCallback(pWnd, key_callback); //glfwSetCursorPosCallback(pWnd, mouse_callback); // 禁用鼠标 glfwSetScrollCallback(pWnd, scroll_callback); //glfwSetInputMode(pWnd, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glewExperimental = GL_TRUE; glewInit(); glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); glEnable(GL_DEPTH_TEST);#if 1 GLuint diffuseMap = loadTexture("./img/bricks2.jpg"); GLuint normalMap = loadTexture("./img/bricks2_normal.jpg"); GLuint heightMap = loadTexture("./img/bricks2_disp.jpg");#else GLuint diffuseMap = loadTexture("./img/toy_box_diffuse.png"); GLuint normalMap = loadTexture("./img/toy_box_normal.png"); GLuint heightMap = loadTexture("./img/toy_box_disp.png");#endif Shader shader("./Shader/parallax_mapping.vs", "./Shader/parallax_mapping.frag"); shader.useShaderPrograme(); glUniform1i(glGetUniformLocation(shader.getPrograme(), "diffuseMap"), 0); glUniform1i(glGetUniformLocation(shader.getPrograme(), "normalMap"), 1); glUniform1i(glGetUniformLocation(shader.getPrograme(), "depthMap"), 2); shader.useShaderPrograme(); glm::vec3 lightPos(0.5f, 1.0f, 0.3f); // 灯光位置 glm::mat4 view = camera.GetViewMatrix(); glm::mat4 projection = glm::perspective(camera.Zoom, (GLfloat)SCR_WIDTH / (GLfloat)SCR_HEIGHT, 0.1f, 100.0f); while (!glfwWindowShouldClose(pWnd)) { GLfloat currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; glfwPollEvents(); Do_Movement(); glClearColor(0.1f, 0.2f, 0.23f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUniformMatrix4fv(glGetUniformLocation(shader.getPrograme(), "view"), 1, GL_FALSE, glm::value_ptr(view)); glUniformMatrix4fv(glGetUniformLocation(shader.getPrograme(), "projection"), 1, GL_FALSE, glm::value_ptr(projection)); // 1 绘制旋转中的物体 glm::mat4 model; model = glm::rotate(model, (GLfloat)glfwGetTime() * -1, glm::normalize(glm::vec3(1.0, 0.0, 1.0))); glUniformMatrix4fv(glGetUniformLocation(shader.getPrograme(), "model"), 1, GL_FALSE, glm::value_ptr(model)); glUniform3fv(glGetUniformLocation(shader.getPrograme(), "lightPos"), 1, &lightPos[0]); glUniform3fv(glGetUniformLocation(shader.getPrograme(), "viewPos"), 1, &camera.Position[0]); glUniform1f(glGetUniformLocation(shader.getPrograme(), "height_scale"), height_scale); glUniform1i(glGetUniformLocation(shader.getPrograme(), "parallax"), parallax_mapping); glActiveTexture(GL_TEXTURE0); // 纹理0 glBindTexture(GL_TEXTURE_2D, diffuseMap); glActiveTexture(GL_TEXTURE1); // 纹理1 glBindTexture(GL_TEXTURE_2D, normalMap); glActiveTexture(GL_TEXTURE2); // 纹理2 glBindTexture(GL_TEXTURE_2D, heightMap); RenderQuad(); // 2 绘制小灯泡 model = glm::mat4(); model = glm::translate(model, lightPos); model = glm::scale(model, glm::vec3(0.1f)); glUniformMatrix4fv(glGetUniformLocation(shader.getPrograme(), "model"), 1, GL_FALSE, glm::value_ptr(model)); RenderQuad(); glfwSwapBuffers(pWnd); } glfwTerminate(); return 0;}/*************************************************************************/GLuint quadVAO = 0;GLuint quadVBO;void RenderQuad(){ if (quadVAO == 0) { // positions glm::vec3 pos1(-1.0, 1.0, 0.0); glm::vec3 pos2(-1.0, -1.0, 0.0); glm::vec3 pos3(1.0, -1.0, 0.0); glm::vec3 pos4(1.0, 1.0, 0.0); // texture coordinates glm::vec2 uv1(0.0, 1.0); glm::vec2 uv2(0.0, 0.0); glm::vec2 uv3(1.0, 0.0); glm::vec2 uv4(1.0, 1.0); // normal vector glm::vec3 nm(0.0, 0.0, 1.0); // calculate tangent/bitangent vectors of both triangles glm::vec3 tangent1, bitangent1; glm::vec3 tangent2, bitangent2; // - triangle 1 glm::vec3 edge1 = pos2 - pos1; glm::vec3 edge2 = pos3 - pos1; glm::vec2 deltaUV1 = uv2 - uv1; glm::vec2 deltaUV2 = uv3 - uv1; GLfloat f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y); tangent1.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x); tangent1.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y); tangent1.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z); tangent1 = glm::normalize(tangent1); bitangent1.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x); bitangent1.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y); bitangent1.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z); bitangent1 = glm::normalize(bitangent1); // - triangle 2 edge1 = pos3 - pos1; edge2 = pos4 - pos1; deltaUV1 = uv3 - uv1; deltaUV2 = uv4 - uv1; f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y); tangent2.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x); tangent2.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y); tangent2.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z); tangent2 = glm::normalize(tangent2); bitangent2.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x); bitangent2.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y); bitangent2.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z); bitangent2 = glm::normalize(bitangent2); GLfloat quadVertices[] = { // Positions // normal // TexCoords // Tangent // Bitangent pos1.x, pos1.y, pos1.z, nm.x, nm.y, nm.z, uv1.x, uv1.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z, pos2.x, pos2.y, pos2.z, nm.x, nm.y, nm.z, uv2.x, uv2.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z, pos3.x, pos3.y, pos3.z, nm.x, nm.y, nm.z, uv3.x, uv3.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z, pos1.x, pos1.y, pos1.z, nm.x, nm.y, nm.z, uv1.x, uv1.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z, pos3.x, pos3.y, pos3.z, nm.x, nm.y, nm.z, uv3.x, uv3.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z, pos4.x, pos4.y, pos4.z, nm.x, nm.y, nm.z, uv4.x, uv4.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z }; glGenVertexArrays(1, &quadVAO); glBindVertexArray(quadVAO); // VAO { glGenBuffers(1, &quadVBO); // VBO glBindBuffer(GL_ARRAY_BUFFER, quadVBO); { glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 14 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat))); glEnableVertexAttribArray(3); glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(GLfloat), (GLvoid*)(8 * sizeof(GLfloat))); glEnableVertexAttribArray(4); glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(GLfloat), (GLvoid*)(11 * sizeof(GLfloat))); } glBindBuffer(GL_ARRAY_BUFFER, 0); } glBindVertexArray(0); } glBindVertexArray(quadVAO); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0);}/*************************************************************************/GLuint loadTexture(GLchar* path){ GLuint textureID; glGenTextures(1, &textureID); int width, height; unsigned char* image = SOIL_load_image(path, &width, &height, 0, SOIL_LOAD_RGB); glBindTexture(GL_TEXTURE_2D, textureID); { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); glGenerateMipmap(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } glBindTexture(GL_TEXTURE_2D, 0); SOIL_free_image_data(image); return textureID;}/*************************************************************************/bool keys[1024];bool keysPressed[1024];void Do_Movement(){ if (keys[GLFW_KEY_W]) camera.ProcessKeyboard(FORWARD, deltaTime); if (keys[GLFW_KEY_S]) camera.ProcessKeyboard(BACKWARD, deltaTime); if (keys[GLFW_KEY_A]) camera.ProcessKeyboard(LEFT, deltaTime); if (keys[GLFW_KEY_D]) camera.ProcessKeyboard(RIGHT, deltaTime); if (keys[GLFW_KEY_Q]) height_scale -= 0.001; else if (keys[GLFW_KEY_E]) height_scale += 0.001; if (keys[GLFW_KEY_SPACE] && !keysPressed[GLFW_KEY_SPACE]) { parallax_mapping = !parallax_mapping; keysPressed[GLFW_KEY_SPACE] = true; }}/*************************************************************************/void key_callback(GLFWwindow* pWnd, int key, int scancode, int action, int mode){ if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(pWnd, GL_TRUE); if (key >= 0 && key <= 1024) { if (action == GLFW_PRESS) keys[key] = true; else if (action == GLFW_RELEASE) { keys[key] = false; keysPressed[key] = false; } }}/*************************************************************************/GLfloat lastX = 400, lastY = 300;bool firstMouse = true;void mouse_callback(GLFWwindow* pWnd, double xpos, double ypos){ if (firstMouse) { lastX = xpos; lastY = ypos; firstMouse = false; } GLfloat xoffset = xpos - lastX; GLfloat yoffset = lastY - ypos; lastX = xpos; lastY = ypos; camera.ProcessMouseMovement(xoffset, yoffset);}/*************************************************************************/void scroll_callback(GLFWwindow* pWnd, double xoffset, double yoffset){ camera.ProcessMouseScroll(yoffset);}

Camera.h

//Camera.h #pragma once// Std. Includes#include <vector>// GL Includes#include <GL/glew.h>#include <glm/glm.hpp>#include <glm/gtc/matrix_transform.hpp>// 摄像机移动方向 程序中用WSAD控制enum Camera_Movement { FORWARD, BACKWARD, LEFT, RIGHT};// Default camera valuesconst GLfloat YAW = -90.0f;const GLfloat PITCH = 0.0f;const GLfloat SPEED = 3.0f;const GLfloat SENSITIVTY = 0.25f;const GLfloat ZOOM = 45.0f;class Camera{public: // Camera Attributes glm::vec3 Position; glm::vec3 Front; glm::vec3 Up; glm::vec3 Right; glm::vec3 WorldUp; // Eular Angles GLfloat Yaw; GLfloat Pitch; // Camera options GLfloat MovementSpeed; GLfloat MouseSensitivity; GLfloat Zoom; // Constructor with vectors Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), GLfloat yaw = YAW, GLfloat pitch = PITCH) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVTY), Zoom(ZOOM) { this->Position = position; this->WorldUp = up; this->Yaw = yaw; this->Pitch = pitch; this->updateCameraVectors(); } // Constructor with scalar values Camera(GLfloat posX, GLfloat posY, GLfloat posZ, GLfloat upX, GLfloat upY, GLfloat upZ, GLfloat yaw, GLfloat pitch) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVTY), Zoom(ZOOM) { this->Position = glm::vec3(posX, posY, posZ); this->WorldUp = glm::vec3(upX, upY, upZ); this->Yaw = yaw; this->Pitch = pitch; this->updateCameraVectors(); } // Returns the view matrix calculated using Eular Angles and the LookAt Matrix glm::mat4 GetViewMatrix() { return glm::lookAt(this->Position, this->Position + this->Front, this->Up); } // 按键处理 void ProcessKeyboard(Camera_Movement direction, GLfloat deltaTime) { GLfloat velocity = this->MovementSpeed * deltaTime; if (direction == FORWARD) this->Position +=0.5; if (direction == BACKWARD) this->Position -= 0.5; if (direction == LEFT) this->Position -= 0.5; if (direction == RIGHT) this->Position += 0.5; //GLfloat velocity = this->MovementSpeed * deltaTime; //if (direction == FORWARD) // this->Position += this->Front * velocity; //if (direction == BACKWARD) // this->Position -= this->Front * velocity; //if (direction == LEFT) // this->Position -= this->Right * velocity; //if (direction == RIGHT) // this->Position += this->Right * velocity; } // 鼠标移动处理 void ProcessMouseMovement(GLfloat xoffset, GLfloat yoffset, GLboolean constrainPitch = true) { xoffset *= this->MouseSensitivity; yoffset *= this->MouseSensitivity; this->Yaw += xoffset; this->Pitch += yoffset; // Make sure that when pitch is out of bounds, screen doesn't get flipped if (constrainPitch) { if (this->Pitch > 89.0f) this->Pitch = 89.0f; if (this->Pitch < -89.0f) this->Pitch = -89.0f; } // Update Front, Right and Up Vectors using the updated Eular angles this->updateCameraVectors(); } // Processes input received from a mouse scroll-wheel event. // Only requires input on the vertical wheel-axis void ProcessMouseScroll(GLfloat yoffset) { if (this->Zoom >= 1.0f && this->Zoom <= 45.0f) this->Zoom -= yoffset; if (this->Zoom <= 1.0f) this->Zoom = 1.0f; if (this->Zoom >= 45.0f) this->Zoom = 45.0f; }private: // Calculates the front vector from the Camera's (updated) Eular Angles void updateCameraVectors() { // Calculate the new Front vector glm::vec3 front; front.x = cos(glm::radians(this->Yaw)) * cos(glm::radians(this->Pitch)); front.y = sin(glm::radians(this->Pitch)); front.z = sin(glm::radians(this->Yaw)) * cos(glm::radians(this->Pitch)); this->Front = glm::normalize(front); // Also re-calculate the Right and Up vector // Normalize the vectors, because their length gets closer to 0 the more // you look up or down which results in slower movement. this->Right = glm::normalize(glm::cross(this->Front, this->WorldUp)); this->Up = glm::normalize(glm::cross(this->Right, this->Front)); }};

mesh.h

#pragma once// 网格类:#include <string>#include <fstream>#include <sstream>#include <iostream>#include <vector>using namespace std;#include <GL/glew.h>#include <glm/glm.hpp>#include <glm/gtc/matrix_transform.hpp>#include "Shader.h"#pragma comment (lib, "assimp-vc140-mt.lib")// ********************************************************************//// 用来索引每个顶点属性struct Vertex { glm::vec3 Position; glm::vec3 Normal; glm::vec2 TexCoords;};// ********************************************************************//// 储存纹理的id和它的类型struct Texture { GLuint id; string type; aiString path;};// ********************************************************************//class Mesh {public: vector<Vertex> vertices; // 顶点 vector<GLuint> indices; // vector<Texture> textures; // 纹理 Mesh(vector<Vertex> vertices, vector<GLuint> indices, vector<Texture> textures) { this->vertices = vertices; this->indices = indices; this->textures = textures; this->setupMesh(); } void Draw(Shader shader) { // Bind appropriate textures GLuint diffuseNr = 1; GLuint specularNr = 1; for (GLuint i = 0; i < this->textures.size(); i++) { glActiveTexture(GL_TEXTURE0 + i); // 激活纹理 stringstream ss; string number; string name = this->textures[i].type; if (name == "texture_diffuse") ss << diffuseNr++; // Transfer GLuint to stream else if (name == "texture_specular") ss << specularNr++; // Transfer GLuint to stream number = ss.str(); // Now set the sampler to the correct texture unit glUniform1i(glGetUniformLocation(shader.getPrograme(), (name + number).c_str()), i); // And finally bind the texture glBindTexture(GL_TEXTURE_2D, this->textures[i].id); } // Also set each mesh's shininess property to a default value (if you want you could extend this to another mesh property and possibly change this value) glUniform1f(glGetUniformLocation(shader.getPrograme(), "material.shininess"), 16.0f); // Draw mesh glBindVertexArray(this->VAO); glDrawElements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_INT, 0); glBindVertexArray(0); // Always good practice to set everything back to defaults once configured. for (GLuint i = 0; i < this->textures.size(); i++) { glActiveTexture(GL_TEXTURE0 + i); glBindTexture(GL_TEXTURE_2D, 0); } }private: /* Render data */ GLuint VAO, VBO, EBO; // 初始化所有的顶点数据等 void setupMesh() { glGenVertexArrays(1, &this->VAO); glGenBuffers(1, &this->VBO); glGenBuffers(1, &this->EBO); glBindVertexArray(this->VAO); glBindBuffer(GL_ARRAY_BUFFER, this->VBO); // A great thing about structs is that their memory layout is sequential for all its items. // The effect is that we can simply pass a pointer to the struct and it translates perfectly to a glm::vec3/2 array which // again translates to 3/2 floats which translates to a byte array. glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(Vertex), &this->vertices[0], GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(GLuint), &this->indices[0], GL_STATIC_DRAW); // 设置顶点坐标指针 glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)0); // 设置法线指针 glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Normal)); // 设置顶点的纹理坐标 glEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, TexCoords)); glBindVertexArray(0); }};// ********************************************************************//

Model.h

#pragma once// Std. Includes#include <string>#include <fstream>#include <sstream>#include <iostream>#include <map>#include <vector>using namespace std;// GL Includes#include <GL/glew.h> // Contains all the necessery OpenGL includes#include <glm/glm.hpp>#include <glm/gtc/matrix_transform.hpp>#include <SOIL/SOIL.h>#include <assimp/Importer.hpp>#include <assimp/scene.h>#include <assimp/postprocess.h>#include "Mesh.h"GLint TextureFromFile(const char* path, string directory);class Model{public: Model(GLchar* path) { this->loadModel(path); } void Draw(Shader shader) { for (GLuint i = 0; i < this->meshes.size(); i++) this->meshes[i].Draw(shader); }private: vector<Mesh> meshes; // 一个模型包含多个Mesh string directory; /* Functions */ // Loads a model with supported ASSIMP extensions from file and stores the resulting meshes in the meshes vector. // 加载模型 void loadModel(string path) { // Read file via ASSIMP Assimp::Importer importer; const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs); // Check for errors if (!scene || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) // if is Not Zero { cout << "ERROR::ASSIMP:: " << importer.GetErrorString() << endl; return; } // Retrieve the directory path of the filepath this->directory = path.substr(0, path.find_last_of('/')); // Process ASSIMP's root node recursively this->processNode(scene->mRootNode, scene); } // Processes a node in a recursive fashion. Processes each individual mesh located at the node and repeats this process on its children nodes (if any). void processNode(aiNode* node, const aiScene* scene) { // Process each mesh located at the current node for (GLuint i = 0; i < node->mNumMeshes; i++) { // The node object only contains indices to index the actual objects in the scene. // The scene contains all the data, node is just to keep stuff organized (like relations between nodes). aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; this->meshes.push_back(this->processMesh(mesh, scene)); // 存储Mesh } // After we've processed all of the meshes (if any) we then recursively process each of the children nodes for (GLuint i = 0; i < node->mNumChildren; i++) { this->processNode(node->mChildren[i], scene); } } Mesh processMesh(aiMesh* mesh, const aiScene* scene) { // Data to fill vector<Vertex> vertices; vector<GLuint> indices; vector<Texture> textures; // Walk through each of the mesh's vertices for (GLuint i = 0; i < mesh->mNumVertices; i++) { Vertex vertex; glm::vec3 vector; // We declare a placeholder vector since assimp uses its own vector class that doesn't directly convert to glm's vec3 class so we transfer the data to this placeholder glm::vec3 first. // Positions vector.x = mesh->mVertices[i].x; vector.y = mesh->mVertices[i].y; vector.z = mesh->mVertices[i].z; vertex.Position = vector; // Normals vector.x = mesh->mNormals[i].x; vector.y = mesh->mNormals[i].y; vector.z = mesh->mNormals[i].z; vertex.Normal = vector; // Texture Coordinates if (mesh->mTextureCoords[0]) // Does the mesh contain texture coordinates? { glm::vec2 vec; // A vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't // use models where a vertex can have multiple texture coordinates so we always take the first set (0). vec.x = mesh->mTextureCoords[0][i].x; vec.y = mesh->mTextureCoords[0][i].y; vertex.TexCoords = vec; } else vertex.TexCoords = glm::vec2(0.0f, 0.0f); vertices.push_back(vertex); } // Now wak through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices. for (GLuint i = 0; i < mesh->mNumFaces; i++) { aiFace face = mesh->mFaces[i]; // Retrieve all indices of the face and store them in the indices vector for (GLuint j = 0; j < face.mNumIndices; j++) indices.push_back(face.mIndices[j]); } // Process materials if (mesh->mMaterialIndex >= 0) { aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex]; // We assume a convention for sampler names in the shaders. Each diffuse texture should be named // as 'texture_diffuseN' where N is a sequential number ranging from 1 to MAX_SAMPLER_NUMBER. // Same applies to other texture as the following list summarizes: // Diffuse: texture_diffuseN // Specular: texture_specularN // Normal: texture_normalN // 1. Diffuse maps vector<Texture> diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse"); textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end()); // 2. Specular maps vector<Texture> specularMaps = this->loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular"); textures.insert(textures.end(), specularMaps.begin(), specularMaps.end()); } // Return a mesh object created from the extracted mesh data return Mesh(vertices, indices, textures); } // Checks all material textures of a given type and loads the textures if they're not loaded yet. // The required info is returned as a Texture struct. vector<Texture> loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName) { vector<Texture> textures; for (GLuint i = 0; i < mat->GetTextureCount(type); i++) { aiString str; mat->GetTexture(type, i, &str); // Check if texture was loaded before and if so, continue to next iteration: skip loading a new texture Texture texture; texture.id = TextureFromFile(str.C_Str(), this->directory); texture.type = typeName; texture.path = str; textures.push_back(texture); } return textures; }};GLint TextureFromFile(const char* path, string directory){ //Generate texture ID and load texture data string filename = string(path); filename = directory + '/' + filename; GLuint textureID; glGenTextures(1, &textureID); int width, height; unsigned char* image = SOIL_load_image(filename.c_str(), &width, &height, 0, SOIL_LOAD_RGB); // Assign texture to ID glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); glGenerateMipmap(GL_TEXTURE_2D); // Parameters glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); SOIL_free_image_data(image); return textureID;}

Shader.h

//Shader.h #pragma once#ifndef TEXTURE_SHADER_H_#define TEXTURE_SHADER_H_#include <string>#include <fstream>#include <sstream>#include <iostream>#include <gl/glew.h>#include <string>#include <fstream>#include <sstream>#include <iostream>#include <GL/glew.h>class Shader{public: Shader(const GLchar* vertexPath, const GLchar* fragmentPath); ~Shader();public: void useShaderPrograme(); GLuint getPrograme() { return this->m_nProgram; }private: GLuint m_nProgram;};Shader::Shader(const GLchar* vertexPath, const GLchar* fragmentPath){ std::string vertexCode; std::string fragmentCode; std::ifstream vertexShaderF; std::ifstream fragementShaderF; vertexShaderF.exceptions(std::ifstream::badbit); fragementShaderF.exceptions(std::ifstream::badbit); try { vertexShaderF.open(vertexPath); // 打开文件 fragementShaderF.open(fragmentPath); std::stringstream vertexShaderStream, fragementShaderStream; vertexShaderStream << vertexShaderF.rdbuf(); // 读取文件至stringstream中 fragementShaderStream << fragementShaderF.rdbuf(); vertexShaderF.close(); fragementShaderF.close(); vertexCode = vertexShaderStream.str(); // 转换成string类型 fragmentCode = fragementShaderStream.str(); } catch (std::ifstream::failure e) { std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ:" << std::endl; } const GLchar* pVertexCode = vertexCode.c_str(); // string 转 char* const GLchar* pFragementCode = fragmentCode.c_str(); GLuint nVertexShader, nFragementShader; GLint nRes = 0; GLchar chLogInfo[512] = { '/0' }; // 创建顶点着色器 nVertexShader = glCreateShader(GL_VERTEX_SHADER); // 将顶点着色程序的源代码字符数组绑定到顶点着色器对象 glShaderSource(nVertexShader, 1, &pVertexCode, nullptr); glCompileShader(nVertexShader); // compile shader 编译着色器 // 获取编译结果 glGetShaderiv(nVertexShader, GL_COMPILE_STATUS, &nRes); if (!nRes) { glGetShaderInfoLog(nVertexShader, 512, nullptr, chLogInfo); std::cout << "ERROR::SHADEF::VERTEX::COMPILATION_FAILED:" << chLogInfo << std::endl; } // 创建片断着色器 nFragementShader = glCreateShader(GL_FRAGMENT_SHADER); // 将片段着色程序的源代码字符数组绑定到片段着色器对象 glShaderSource(nFragementShader, 1, &pFragementCode, nullptr); glCompileShader(nFragementShader); glGetShaderiv(nFragementShader, GL_COMPILE_STATUS, &nRes); if (!nRes) { glGetShaderInfoLog(nFragementShader, 512, nullptr, chLogInfo); std::cout << "ERROR::SHADEF::FRAGEMENT::COMPILATION_FAILED:" << chLogInfo << std::endl; } this->m_nProgram = glCreateProgram(); // 创建GLSL程序 glAttachShader(this->m_nProgram, nVertexShader); // 绑定shader到program glAttachShader(this->m_nProgram, nFragementShader); // glLinkProgram操作产生最后的可执行程序,它包含最后可以在硬件上执行的硬件指令 glLinkProgram(this->m_nProgram); // 链接 glGetProgramiv(this->m_nProgram, GL_LINK_STATUS, &nRes); if (!nRes) { glGetProgramInfoLog(this->m_nProgram, 512, nullptr, chLogInfo); std::cout << "ERROR::SHADEF::FRAGEMENT::LINK_FAILED:" << chLogInfo << std::endl; } glDeleteShader(nVertexShader); glDeleteShader(nFragementShader);}Shader::~Shader(){}#include <glm/glm.hpp>#include <glm/gtc/matrix_transform.hpp>#include <glm/gtc/type_ptr.hpp>void Shader::useShaderPrograme(){ glUseProgram(this->m_nProgram); // 使用porgram}#endif

OpenGL Shader 部分 GLSL

顶点着色器 parallax_mapping.vs

#version 330 corelayout (location = 0) in vec3 position;layout (location = 1) in vec3 normal;layout (location = 2) in vec2 texCoords;layout (location = 3) in vec3 tangent;layout (location = 4) in vec3 bitangent;out VS_OUT { vec3 FragPos; vec2 TexCoords; vec3 TangentLightPos; vec3 TangentViewPos; vec3 TangentFragPos;} vs_out;uniform mat4 projection;uniform mat4 view;uniform mat4 model;uniform vec3 lightPos;uniform vec3 viewPos;void main(){ gl_Position = projection * view * model * vec4(position, 1.0f); vs_out.FragPos = vec3(model * vec4(position, 1.0)); vs_out.TexCoords = texCoords; vec3 T = normalize(mat3(model) * tangent); vec3 B = normalize(mat3(model) * bitangent); vec3 N = normalize(mat3(model) * normal); mat3 TBN = transpose(mat3(T, B, N)); vs_out.TangentLightPos = TBN * lightPos; vs_out.TangentViewPos = TBN * viewPos; vs_out.TangentFragPos = TBN * vs_out.FragPos;}

片断着色器 parallax_mapping.frag

#version 330 coreout vec4 FragColor;in VS_OUT { vec3 FragPos; vec2 TexCoords; vec3 TangentLightPos; vec3 TangentViewPos; vec3 TangentFragPos;} fs_in;uniform sampler2D diffuseMap;uniform sampler2D normalMap;uniform sampler2D depthMap;uniform bool parallax;uniform float height_scale;vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir){ float height = texture(depthMap, texCoords).r; return texCoords - viewDir.xy / viewDir.z * (height * height_scale); }void main(){ // Offset texture coordinates with Parallax Mapping vec3 viewDir = normalize(fs_in.TangentViewPos - fs_in.TangentFragPos); vec2 texCoords = fs_in.TexCoords; if(parallax) texCoords = ParallaxMapping(fs_in.TexCoords, viewDir); // Obtain normal from normal map vec3 normal = texture(normalMap, texCoords).rgb; normal = normalize(normal * 2.0 - 1.0); // Get diffuse color vec3 color = texture(diffuseMap, texCoords).rgb; // Ambient vec3 ambient = 0.1 * color; // Diffuse vec3 lightDir = normalize(fs_in.TangentLightPos - fs_in.TangentFragPos); float diff = max(dot(lightDir, normal), 0.0); vec3 diffuse = diff * color; // Specular vec3 reflectDir = reflect(-lightDir, normal); vec3 halfwayDir = normalize(lightDir + viewDir); float spec = pow(max(dot(normal, halfwayDir), 0.0), 32.0); vec3 specular = vec3(0.2) * spec; FragColor = vec4(ambient + diffuse + specular, 1.0f);}

这里写图片描述

这里写图片描述

源码下载: VS2015 http://download.csdn.net/detail/yulinxx/9747841


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表