使用opengl 和openmesh读取并展示obj模型

其中大部分代码是在学习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中找到

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值