其中大部分代码是在学习LearnOpenGL过程中写的,重点在于openmesh的使用,所以只展示main.cpp的写法和Model.h
Model.h
#include <iostream>
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include"camera.h"
#include"shader.h"
#include<vector>
#include<float.h>
#include <algorithm>
#ifndef MODEL_H
#define MODEL_H
typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh;
class Model
{
public:
MyMesh mesh; //mesh
std::vector<float> vertices; //position
std::vector<float> normals; //normal
std::vector<float> texCoords; //texture coordinate
unsigned int n_vertices;
unsigned int n_normals;
public:
Model(const char* filename):n_vertices(0),n_normals(0)
{
float max=0;
//read normals
//OpenMesh::IO::Options readOpt = OpenMesh::IO::Options::VertexNormal;
mesh.request_vertex_normals();
if (!mesh.has_vertex_normals())
{
std::cout << "ERROR:NO NORMALS" << std::endl;
return;
}
OpenMesh::IO::Options opt;
if (!OpenMesh::IO::read_mesh(mesh, filename))
std::cout << "read failed" << std::endl;
if (!opt.check(OpenMesh::IO::Options::VertexNormal))
{
// 通过面法线计算顶点法线
mesh.request_face_normals();
// mesh计算出顶点法线
mesh.update_normals();
// 释放面法线
mesh.release_face_normals();
}
for (MyMesh::FaceIter f_it = mesh.faces_begin(); f_it != mesh.faces_end(); ++f_it)
{
for (MyMesh::FaceVertexIter fv_it = mesh.fv_iter(*f_it); fv_it.is_valid(); ++fv_it)
{
auto point = mesh.point(*fv_it);
auto normal = mesh.normal(*fv_it);
float* point_data = point.data();
float* normal_data = normal.data();
float temp1 = *std::max_element(point_data, point_data +2);
float temp2 = *std::min_element(point_data, point_data + 2);
float temp = std::max(abs(temp1), abs(temp2));
if (temp > max)
max = temp;
//position
vertices.push_back(point_data[0]);
vertices.push_back(point_data[1]);
vertices.push_back(point_data[2]);
//normal
normals.push_back(normal_data[0]);
normals.push_back(normal_data[1]);
normals.push_back(normal_data[2]);
n_vertices++;
n_normals++;
}
}
//想到的蠢办法,解决原obj文件坐标过大的问题,但是问题就是会比较慢
for (auto& f : vertices)
f /= max;
}
};
#endif // !MODEL_H
main.cpp
#define GLUT_DISABLE_ATEXIT_HACK
#include<glad/glad.h>
#include<GLFW/glfw3.h>
#include<glm/glm.hpp>
#include<glm/gtc/matrix_transform.hpp>
#include <iostream>
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include"camera.h"
#include"shader.h"
#include"model.h"
#define STB_IMAGE_IMPLEMENTATION
#include"std_image.h"
#include<string>
typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh;
typedef int Mode;
MyMesh mesh;
//display mode
Mode mode= GL_TRIANGLES;
//methods
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback1(GLFWwindow* window, double xposIn, double yposIn);
void mouse_callback2(GLFWwindow* window, double xposIn, double yposIn);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow* window);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
//mouse
bool lbutton_down = false;
// camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.f));
float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 2.0f;
bool firstMouse = true;
glm::mat4 model = glm::mat4(1.0f);
// timing
float deltaTime = 0.0f;
float lastFrame = 0.0f;
// lighting
glm::vec3 lightPos(glm::vec3(0.0f, 0.0f, 3.f));
//filename
const char* filename1 = "./obj/african_head.obj";
const char* filename2 = "./obj/gargoyle.obj";
const char* filename3 = "./obj/Survival_BackPack_2.obj";
int main(void)
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "3D", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetMouseButtonCallback(window, mouse_button_callback);
//glfwSetCursorPosCallback(window, mouse_callback2);
glfwSetScrollCallback(window, scroll_callback);
// tell GLFW to capture our mouse
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// configure global opengl state
// -----------------------------
glEnable(GL_DEPTH_TEST);
// build and compile our shader zprogram
// ------------------------------------
//readfile("./obj/african_head.obj");
Shader cubeShader("shaders/vshader.vs", "shaders/fshader.fs");
Model myModel(filename3);
//data
std::vector<float> vertices = myModel.vertices;
std::vector<float> normals = myModel.normals;
// first, configure the cube's VAO (and VBO)
unsigned int VBO[2];
unsigned int cubeVAO;
glGenVertexArrays(1, &cubeVAO);
glGenBuffers(2, &VBO[0]);
//glGenBuffers(1, &EBO);
glBindVertexArray(cubeVAO);
// position
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), &vertices.front(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
//normal
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), &normals.front(), GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
// per-frame time logic
// --------------------
float currentFrame = static_cast<float>(glfwGetTime());
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
// input
// -----
processInput(window);
/* Render here */
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
cubeShader.use();
//light
cubeShader.setVec3("objectColor", 0.5f, 0.5f, 0.5f);
cubeShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);
cubeShader.setVec3("lightPos", lightPos);
cubeShader.setVec3("viewPos", camera.Position);
// view/projection transformations
//transformation
glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
glm::mat4 view = camera.GetViewMatrix();
cubeShader.setMat4("projection", projection);
cubeShader.setMat4("view", view);
// world transformation
//model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f));
//model = glm::rotate(model, deltaTime, glm::vec3(0.0f, 1.0f, 0.0f));
//model = glm::scale(model, glm::vec3(0.01f, 0.01f, 0.01f));
cubeShader.setMat4("model", model);
// render the cube
glBindVertexArray(cubeVAO);
glDrawArrays(mode, 0, vertices.size() / 3);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glDeleteVertexArrays(1, &cubeVAO);
glDeleteBuffers(1, &VBO[0]);
glDeleteBuffers(1, &VBO[1]);
glfwTerminate();
return 0;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
camera.ProcessKeyboard(FORWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.ProcessKeyboard(BACKWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.ProcessKeyboard(LEFT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.ProcessKeyboard(RIGHT, deltaTime);
//对于显示模式的选择
if (glfwGetKey(window, GLFW_KEY_J) == GLFW_PRESS)
mode = GL_TRIANGLES;
if (glfwGetKey(window, GLFW_KEY_K) == GLFW_PRESS)
mode = GL_POINTS;
if (glfwGetKey(window, GLFW_KEY_L) == GLFW_PRESS)
mode = GL_LINES;
}
//鼠标点击事件
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
if (button == GLFW_MOUSE_BUTTON_LEFT)
{
if (GLFW_PRESS == action)
lbutton_down = true;
else if (GLFW_RELEASE == action)
lbutton_down = false;
}
if (lbutton_down)
{
glfwSetCursorPosCallback(window, mouse_callback2);
}
else
{
glfwSetCursorPosCallback(window, mouse_callback1);
}
}
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
// glfw: whenever the mouse moves, this callback is called
//这里可以注释掉
// -------------------------------------------------------
void mouse_callback1(GLFWwindow* window, double xposIn, double yposIn)
{
float xpos = static_cast<float>(xposIn);
float ypos = static_cast<float>(yposIn);
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
float xoffset = xpos - lastX;
float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
lastX = xpos;
lastY = ypos;
//camera.ProcessMouseMovement(xoffset, yoffset);
}
void mouse_callback2(GLFWwindow* window, double xposIn, double yposIn)
{
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_RELEASE)
return;
float xpos = static_cast<float>(xposIn);
float ypos = static_cast<float>(yposIn);
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
float xoffset = 0.05 * (xpos - lastX);
float yoffset = 0.05 * (ypos-lastY); // reversed since y-coordinates go from bottom to top
lastX = xpos;
lastY = ypos;
//旋转模型
model = glm::rotate(model, glm::radians(xoffset), glm::vec3(0.0f, 1.0f, 0.0f));
model = glm::rotate(model, glm::radians(yoffset), glm::vec3(1.0f, 0.0f, 0.0f));
}
// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
camera.ProcessMouseScroll(static_cast<float>(yoffset));
}
shader
fragment shader
#version 330 core
in vec3 Normal;
in vec3 FragPos;
out vec4 FragColor;
uniform vec3 viewPos;
uniform vec3 lightPos;
uniform vec3 lightColor;
uniform vec3 objectColor;
void main()
{
//ambient
float ambientStrength=0.1;
vec3 ambient=ambientStrength*lightColor;
//diffuse
vec3 norm=normalize(Normal);
vec3 lightDir=normalize(lightPos-FragPos);
float diff=max(dot(norm,lightDir),0.0);
vec3 diffuse=diff*lightColor;
//specular
float specularStrength=0.5;
vec3 viewDir=normalize(viewPos-FragPos);
vec3 reflectDir=reflect(-lightDir,norm);
float spec=pow(max(dot(viewDir,reflectDir),0.0),32);
vec3 specular=specularStrength*spec*lightColor;
vec3 result=(ambient+diffuse+specular)*objectColor;
FragColor = vec4(result,1.0);
}
vertex shader
#version 330 core
layout (location = 0) in vec3 aPos;
layout(location=1) in vec3 aNormal;
out vec3 Normal;
out vec3 FragPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
FragPos=vec3(model*vec4(aPos,1.0));
//这里很重要,之前旋转之后会发现光照并没有跟着旋转,是因为其法向量没有更新的原因
Normal=transpose(inverse(mat3(model)))*aNormal;
gl_Position = projection * view * vec4(FragPos, 1.0);
}
其他部分头文件的代码可以直接到
LearnOpenGL
中找到
版权声明:本文为qq_44092699原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。