关于OpenMesh与OpenGL

OpenMesh官网

开放网格 - 计算机图形学和多媒体 (rwth-aachen.de)

OpenMesh是什么?他能做什么?

OpenMesh是一个C++库,OpenFlipper这个软件就是由OpenMesh开发的

在这里插入图片描述

直接无源码安装

在这里插入图片描述

非常好用,都不用cmake了

在这里插入图片描述

测试

  • 建一个cpp的空项目,项目名称叫TestOpenMesh

  • 将编译模式改为release

在这里插入图片描述

  • 建一个TestOpenMesh.cpp

在这里插入图片描述

  • 配置头文件:
    打开项目属性-VC++目录-包含目录,添加包含目录D:\vs2022\openmesh\install\OpenMesh 9.0\include如下:

在这里插入图片描述

  • 配置库文件:
    打开项目属性-链接器-常规-附加依赖库目录,添加附加库目录D:\vs2022\openmesh\install\OpenMesh 9.0\lib如下:

在这里插入图片描述

  • 配置附加依赖项.lib文件:*
    打开项目属性-链接器-输入-附加依赖项,添加附加库目录OpenMeshCored.libOpenMeshToolsd.lib如下:
OpenMeshCored.lib
OpenMeshToolsd.lib

在这里插入图片描述

  • 配置预处理器添加宏:

打开项目属性-C/C++-预处理器,添加附加宏_USE_MATH_DEFINES

在这里插入图片描述

测试代码

#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh>


typedef OpenMesh::PolyMesh_ArrayKernelT<>  MyMesh;

int main()
{
	MyMesh mesh;

	// generate vertices

	MyMesh::VertexHandle vhandle[8];

	vhandle[0] = mesh.add_vertex(MyMesh::Point(-1, -1, 1));
	vhandle[1] = mesh.add_vertex(MyMesh::Point(1, -1, 1));
	vhandle[2] = mesh.add_vertex(MyMesh::Point(1, 1, 1));
	vhandle[3] = mesh.add_vertex(MyMesh::Point(-1, 1, 1));
	vhandle[4] = mesh.add_vertex(MyMesh::Point(-1, -1, -1));
	vhandle[5] = mesh.add_vertex(MyMesh::Point(1, -1, -1));
	vhandle[6] = mesh.add_vertex(MyMesh::Point(1, 1, -1));
	vhandle[7] = mesh.add_vertex(MyMesh::Point(-1, 1, -1));


	// generate (quadrilateral) faces

	std::vector<MyMesh::VertexHandle>  face_vhandles;

	face_vhandles.clear();
	face_vhandles.push_back(vhandle[0]);
	face_vhandles.push_back(vhandle[1]);
	face_vhandles.push_back(vhandle[2]);
	face_vhandles.push_back(vhandle[3]);//逆时针
	mesh.add_face(face_vhandles);

	face_vhandles.clear();
	face_vhandles.push_back(vhandle[7]);
	face_vhandles.push_back(vhandle[6]);
	face_vhandles.push_back(vhandle[5]);
	face_vhandles.push_back(vhandle[4]);//顺时针
	mesh.add_face(face_vhandles);

	face_vhandles.clear();
	face_vhandles.push_back(vhandle[1]);
	face_vhandles.push_back(vhandle[0]);
	face_vhandles.push_back(vhandle[4]);
	face_vhandles.push_back(vhandle[5]);//顺时针
	mesh.add_face(face_vhandles);

	face_vhandles.clear();
	face_vhandles.push_back(vhandle[2]);
	face_vhandles.push_back(vhandle[1]);
	face_vhandles.push_back(vhandle[5]);
	face_vhandles.push_back(vhandle[6]);//逆时针
	mesh.add_face(face_vhandles);

	face_vhandles.clear();
	face_vhandles.push_back(vhandle[3]);
	face_vhandles.push_back(vhandle[2]);
	face_vhandles.push_back(vhandle[6]);
	face_vhandles.push_back(vhandle[7]);//逆时针
	mesh.add_face(face_vhandles);

	face_vhandles.clear();
	face_vhandles.push_back(vhandle[0]);
	face_vhandles.push_back(vhandle[3]);
	face_vhandles.push_back(vhandle[7]);
	face_vhandles.push_back(vhandle[4]);//顺时针
	mesh.add_face(face_vhandles);


	// write mesh to output.obj
	try
	{
		if (!OpenMesh::IO::write_mesh(mesh, "output.off"))
		{
			std::cerr << "Cannot write mesh to file 'output.off'" << std::endl;
			return 1;
		}
	}
	catch (std::exception& x)
	{
		std::cerr << x.what() << std::endl;
		return 1;
	}

	return 0;
}

报错:

1>OpenMeshCored.lib(BaseProperty.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(BaseProperty.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(ArrayKernel.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(ArrayKernel.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(OMWriter.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(OMWriter.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(PLYReader.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(PLYReader.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(OMReader.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(OMReader.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(VTKWriter.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(VTKWriter.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(PLYWriter.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(PLYWriter.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(OBJWriter.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(OBJWriter.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(STLWriter.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(STLWriter.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(STLReader.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(STLReader.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(IOManager.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(IOManager.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(OFFWriter.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(OFFWriter.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(OBJReader.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(OBJReader.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(OFFReader.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(OFFReader.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(PolyConnectivity.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(PolyConnectivity.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(omstream.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(omstream.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(OMFormat.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(OMFormat.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(BaseWriter.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(BaseWriter.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(BaseReader.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(BaseReader.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(PropertyCreator.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(PropertyCreator.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(BinaryHelper.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0(TestOpenMesh.obj 中)
1>OpenMeshCored.lib(BinaryHelper.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”(TestOpenMesh.obj 中)
1>LINK : warning LNK4098: 默认库“MSVCRTD”与其他库的使用冲突;请使用 /NODEFAULTLIB:library
1>OpenMeshCored.lib(BaseWriter.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(BaseReader.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(PropertyCreator.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(OFFReader.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(PolyConnectivity.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(omstream.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(OMFormat.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(STLReader.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(IOManager.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(OFFWriter.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(OBJReader.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(VTKWriter.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(PLYWriter.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(OBJWriter.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(STLWriter.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(ArrayKernel.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(OMWriter.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(PLYReader.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(OMReader.obj) : error LNK2001: 无法解析的外部符号 __imp__invalid_parameter
1>OpenMeshCored.lib(BaseWriter.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(BaseReader.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(PropertyCreator.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(OFFReader.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(PolyConnectivity.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(omstream.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(OMFormat.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(STLReader.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(IOManager.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(OFFWriter.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(OBJReader.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(VTKWriter.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(PLYWriter.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(OBJWriter.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(STLWriter.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(ArrayKernel.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(OMWriter.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(PLYReader.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(OMReader.obj) : error LNK2001: 无法解析的外部符号 __imp__CrtDbgReport
1>OpenMeshCored.lib(OMWriter.obj) : error LNK2001: 无法解析的外部符号 __imp__calloc_dbg
1>OpenMeshCored.lib(OMReader.obj) : error LNK2001: 无法解析的外部符号 __imp__calloc_dbg
1>OpenMeshCored.lib(OMFormat.obj) : error LNK2001: 无法解析的外部符号 __imp__calloc_dbg
1>D:\vs2022\code\TestOpenMesh\x64\Release\TestOpenMesh.exe : fatal error LNK1120: 3 个无法解析的外部命令

产生这个问题的原因是:当前工程是Release版本,而引用的库文件时Debug版本,所以你需要重复配置一下上面的操作,在Debug模式下!

效果:

在这里插入图片描述

在这里插入图片描述

学习openmesh

好了,我们现在已经成功搭建了openmesh的运行环境,现在我们来根据一些流程来学习openmesh,

在开启学习openmesh的流程之前,我们需要了解两个重要的资料:

一,openmesh的介绍网址:

https://www.graphics.rwth-aachen.de/software/openmesh/intro/

如下:这个自己去看

在这里插入图片描述

二,openmesh的文档网址:

如下:这个自己去看

https://www.graphics.rwth-aachen.de/media/openmesh_static/Documentations/OpenMesh-Doc-Latest/index.html

在这里插入图片描述

学习openmesh的流程如下:

第一步,了解openmesh库的基本概念

顶点、边、面

  1. 顶点 (Vertices):

    • 顶点是在三维空间中定义的一个点。在OpenMesh中,每个顶点通常包含一个或多个坐标==(x、y、z)==来表示其位置。
    • 顶点是模型的基本构成单元之一,它们可以用来描述物体的各个特征点。
  2. 边 (Edges):

    • 边是两个顶点之间的连接。在OpenMesh中,边也可以具有附加的属性,如权重或方向。
    • 一条边连接两个顶点,形成一个线段或曲线。
  3. 面 (Faces):

    • 面是由三个更多相邻的顶点组成的多边形,通常是一个平面的一部分。在OpenMesh中,常用的面是三角形和四边形。
    • 面定义了模型的表面。

第二步,查看openmesh的官方示例,了解简单的接口api

在这里插入图片描述

练习,自己写一个立方体

报错:

PolyMeshT::add_face: complex edge

解决方法:

https://www.coder.work/article/1725293

在这里插入图片描述

openmesh的顶点顺序要看半边结构的顺序

在这里插入图片描述

再来看一下stl文件格式:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

我们可以看到:stl文件格式也是遵循半边结构的

openmesh与stl文件的不同点是:如果你没有遵循半边结构,openmesh直接判断你是错的;

stl文件则不会,只是发亮面会反.

开启一个小项目,比如:如何加载output.off这个模型,修改和保存

#if 1
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>

typedef OpenMesh::TriMesh_ArrayKernelT<>  MyMesh;

int main()
{
	MyMesh mesh;

	// 从文件中加载模型
	if (!OpenMesh::IO::read_mesh(mesh, "triangle.off"))
	{
		std::cerr << "Error: Cannot read mesh from file 'output.off'" << std::endl;
		return 1;
	}

	// 获取第一个顶点的句柄
	MyMesh::VertexHandle vh = *(mesh.vertices_begin());

	// 获取顶点的当前位置
	MyMesh::Point current_pos = mesh.point(vh);

	// 修改顶点的位置
	mesh.set_point(vh, MyMesh::Point(current_pos[0] - 1.0, current_pos[1], current_pos[2]));

	// 保存模型
	if (!OpenMesh::IO::write_mesh(mesh, "modified_output.off"))
	{
		std::cerr << "Error: Cannot write mesh to file 'modified_output.off'" << std::endl;
		return 1;
	}

	return 0;
}

#else

#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh>


typedef OpenMesh::PolyMesh_ArrayKernelT<>  MyMesh;

int main()
{
	// 创建一个Mesh对象
	MyMesh mesh;

	// 添加顶点
	MyMesh::VertexHandle vhandle[4];
	vhandle[0] = mesh.add_vertex(MyMesh::Point(0.0, 0.0, 0.0));//0
	vhandle[1] = mesh.add_vertex(MyMesh::Point(1.0, 0.0, 0.0));//1
	vhandle[2] = mesh.add_vertex(MyMesh::Point(0.0, 1.0, 0.0));//2
	vhandle[3] = mesh.add_vertex(MyMesh::Point(0.0, 0.0, 1.0));//3


	// 添加面
	std::vector<MyMesh::VertexHandle> face_vhandles;

	 
	face_vhandles.clear();
	face_vhandles.push_back(vhandle[1]);
	face_vhandles.push_back(vhandle[0]);
	face_vhandles.push_back(vhandle[2]);
	mesh.add_face(face_vhandles);

	 
	face_vhandles.clear();
	face_vhandles.push_back(vhandle[1]);
	face_vhandles.push_back(vhandle[2]);
	face_vhandles.push_back(vhandle[3]);
	mesh.add_face(face_vhandles);

	 
	face_vhandles.clear();
	face_vhandles.push_back(vhandle[0]);
	face_vhandles.push_back(vhandle[1]);
	face_vhandles.push_back(vhandle[3]);
	mesh.add_face(face_vhandles);


	face_vhandles.clear();
	face_vhandles.push_back(vhandle[2]);
	face_vhandles.push_back(vhandle[0]);
	face_vhandles.push_back(vhandle[3]);
	mesh.add_face(face_vhandles);

	
	// 保存网格到文件
	OpenMesh::IO::write_mesh(mesh, "triangle.off");

	return 0;
}


#endif

也就是说,stl文件格式要求的顺序和openmesh要求的顺序都是一致的,网格结构的顺序!!!

OpenMesh架构

OpenMesh架构允许自定义网格:用户可以以顶点,边和面指定任意特征,也可以从一组预定义的属性中进行选择,然后将这些属性传播到网格内核.内核负责网格元素的内部存储,可以选择使用数组或双链表作为容器类型.由于具有不同属性的网格将导致不同的cpp类型,OPenMesh使用泛型编程来实现这些网格上操作的算法

在这里插入图片描述

openflipper的安装

https://www.graphics.rwth-aachen.de/software/openflipper/download/

在这里插入图片描述

openGL库的安装

为什么要安装openGL?

在计算机上显示三维模型,通常需要使用OpenGL或其他图形库来实现图形渲染。OpenMesh本身并不包含用于渲染图形的功能。

OpenGL小游戏教程

科普一下:OpenGL本身是一个图形渲染API,并不是一个库。要使用OpenGL,你需要安装GLFW库和GLAD库,来协助你管理窗口和处理OpenGL的扩展。

我一开始以为:OpenGL是一个库

GLFW的安装

https://www.glfw.org/download.html

在这里插入图片描述

然后解压就好了,我们应该用的是lib-vc2022(我猜的,具体应该如何后面会有具体操作的)

在这里插入图片描述

GLAD安装

https://glad.dav1d.de/

gl要选4.0以上的

在这里插入图片描述

在这里插入图片描述

配置GLFW 和 GLAD

1) 配置GLFW

1.使用vs2022创建一个空项目testOpenGL,并在项目下新建testOpenGL.cpp文件

在这里插入图片描述

2.右击testOpenGL.cpp,打开项目所在文件夹,在openGL的文件夹下创建includes和libs两个文件夹;

在这里插入图片描述

在这里插入图片描述

3.copy库

  • glfw解压文件lib-vc2022文件夹下的==.lib文件拷贝进刚刚创建的libs==下(说明刚才猜的没错),
  • 同时将glfw解压文件include下的==.h文件拷贝进刚刚创建的includes==下

开始拷贝:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.在项目名处右键->属性->VC++目录->引用目录->编辑:粘贴项目文件夹下的.h文件所在目录地址

在这里插入图片描述

5.库目录->编辑:粘贴项目文件夹下的.lib文件所在目录

在这里插入图片描述

6.为项目添加依赖项:仍然是属性->链接器->输入->附加依赖项->编辑,将opengl32.lib,glfw3.lib,msvcrt.lib添加进去

opengl32.lib
glfw3.lib
msvcrt.lib

注意!!!这里一定要看!是关于msvcrt.lib的!!!

这里我踩过一个坑:msvcrt.lib 是Microsoft Visual C++ 运行时库,它是用于处理C++程序的标准运行时库。

在使用 Visual Studio 时,通常会自动链接到相应的运行时库,因此不需要显式地将 msvcrt.lib 添加到附加依赖项中。

如果你手动将 msvcrt.lib 添加到附加依赖项中,可能会导致链接错误,因为这样做可能会引起运行时库的冲突。

所以,如果你的项目没有特殊的需求,最好不要手动添加 msvcrt.lib 到附加依赖项中,让 Visual Studio 自动处理运行时库的链接。如果你对运行时库有特殊的需求,可能需要谨慎处理,以避免引起冲突。

所以,不要加msvcrt.lib这个库(既然如此,为什么我上面步骤还写了,这个教程是看其他教程一步一步实操的,我不知道那个人为啥要这么写,一步一步的循序渐进的更好一点),不然你看,把编译器整不会了,你还不知道啥错误,如下:

在这里插入图片描述

在这里插入图片描述

2) 配置 GLAD

  1. GLAD的include下,

    glad文件夹和KHP文件夹

    拷贝进

    项目文件夹下的includes下,

    并将GLAD的src下的glad.c拷贝进项目文件夹下

  2. 进入vs,添加源文件->现有项,将glad.c添加进项目

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3) 测试OpenGL

//测试代码
#include"glad/glad.h"
#include"includes/glfw3.h"
#include <iostream>

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window); // settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

int main() {
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    // uncomment this statement to fix compilation on OS X
#endif
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "I love OpenGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl; return -1;
    }
    while (!glfwWindowShouldClose(window))
    {
        processInput(window);
        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    glfwTerminate(); return 0;
}
void processInput(GLFWwindow* window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

在这里插入图片描述

openmesh与opengl结合使用

在这里插入图片描述

#if 1
#include "glad/glad.h"
#include "includes/glfw3.h"
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>

typedef OpenMesh::TriMesh_ArrayKernelT<>  MyMesh;

int main()
{
	MyMesh mesh;

	// 从文件中加载模型
	if (!OpenMesh::IO::read_mesh(mesh, "triangle.off"))
	{
		std::cerr << "Error: Cannot read mesh from file 'output.off'" << std::endl;
		return 1;
	}

	// 获取第一个顶点的句柄
	MyMesh::VertexHandle vh = *(mesh.vertices_begin());

	// 获取顶点的当前位置
	MyMesh::Point current_pos = mesh.point(vh);

	// 修改顶点的位置
	mesh.set_point(vh, MyMesh::Point(current_pos[0] - 1.0, current_pos[1], current_pos[2]));

	// 保存模型
	/*if (!OpenMesh::IO::write_mesh(mesh, "modified_output.off"))
	{
		std::cerr << "Error: Cannot write mesh to file 'modified_output.off'" << std::endl;
		return 1;
	}*/

	// 初始化GLFW
	if (!glfwInit())
	{
		return -1;
	}

	// 创建一个OpenGL窗口
	GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Window", NULL, NULL);
	if (!window)
	{
		glfwTerminate();
		return -1;
	}

	glfwMakeContextCurrent(window);

	// 初始化GLAD
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		return -1;
	}

	// 设置OpenGL渲染环境
	glViewport(0, 0, 800, 600);

	// ... (设置投影矩阵和视图矩阵,创建VBO,编写着色器等)
	// 创建顶点缓冲对象 (VBO)
	GLuint vbo;
	glGenBuffers(1, &vbo);

	// 绑定VBO
	glBindBuffer(GL_ARRAY_BUFFER, vbo);

	// 将模型的顶点数据传输到VBO
	glBufferData(GL_ARRAY_BUFFER, mesh.n_vertices() * sizeof(MyMesh::Point),
		&mesh.points()[0], GL_STATIC_DRAW);

	// 创建顶点数组对象 (VAO)
	GLuint vao;
	glGenVertexArrays(1, &vao);

	// 绑定VAO
	glBindVertexArray(vao);

	// 启用顶点属性数组
	glEnableVertexAttribArray(0);

	// 设置顶点属性指针
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

	// 解绑VAO
	glBindVertexArray(0);


	// 顶点着色器代码
	const char* vertexShaderSource = R"(
	#version 330 core
	layout (location = 0) in vec3 position;
	void main()
	{
		gl_Position = vec4(position, 1.0);
	}
)";

	// 片段着色器代码
	const char* fragmentShaderSource = R"(
	#version 330 core
	out vec4 FragColor;
	void main()
	{
		FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 红色
	}
)";

	// 创建着色器程序对象
	GLuint shaderProgram = glCreateProgram();

	// 创建顶点着色器对象并编译
	GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);

	// 创建片段着色器对象并编译
	GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentShader);

	// 将顶点着色器和片段着色器附加到着色器程序
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentShader);

	// 链接着色器程序
	glLinkProgram(shaderProgram);

	// 删除着色器对象(已经链接到程序中)
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);

	// 渲染循环
	while (!glfwWindowShouldClose(window))
	{
		glClear(GL_COLOR_BUFFER_BIT);

		// 渲染模型
		// 绑定VAO和着色器程序
		glUseProgram(shaderProgram);
		glBindVertexArray(vao);

		// 绘制模型
		glDrawArrays(GL_TRIANGLES, 0, mesh.n_vertices());

		// 解绑VAO
		glBindVertexArray(0);


		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	glfwTerminate();

	return 0;
}

#else

#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh>


typedef OpenMesh::PolyMesh_ArrayKernelT<>  MyMesh;

int main()
{
	// 创建一个Mesh对象
	MyMesh mesh;

	// 添加顶点
	MyMesh::VertexHandle vhandle[4];
	vhandle[0] = mesh.add_vertex(MyMesh::Point(0.0, 0.0, 0.0));//0
	vhandle[1] = mesh.add_vertex(MyMesh::Point(1.0, 0.0, 0.0));//1
	vhandle[2] = mesh.add_vertex(MyMesh::Point(0.0, 1.0, 0.0));//2
	vhandle[3] = mesh.add_vertex(MyMesh::Point(0.0, 0.0, 1.0));//3


	// 添加面
	std::vector<MyMesh::VertexHandle> face_vhandles;

	 
	face_vhandles.clear();
	face_vhandles.push_back(vhandle[1]);
	face_vhandles.push_back(vhandle[0]);
	face_vhandles.push_back(vhandle[2]);
	mesh.add_face(face_vhandles);

	 
	face_vhandles.clear();
	face_vhandles.push_back(vhandle[1]);
	face_vhandles.push_back(vhandle[2]);
	face_vhandles.push_back(vhandle[3]);
	mesh.add_face(face_vhandles);

	 
	face_vhandles.clear();
	face_vhandles.push_back(vhandle[0]);
	face_vhandles.push_back(vhandle[1]);
	face_vhandles.push_back(vhandle[3]);
	mesh.add_face(face_vhandles);


	face_vhandles.clear();
	face_vhandles.push_back(vhandle[2]);
	face_vhandles.push_back(vhandle[0]);
	face_vhandles.push_back(vhandle[3]);
	mesh.add_face(face_vhandles);

	
	// 保存网格到文件
	OpenMesh::IO::write_mesh(mesh, "triangle.off");

	return 0;
}


#endif

一些感悟

我发现一个很简单但是很实用的规律:在是OpenMesh编辑一个3D图像时,除了底部应该是顺时针,其他面都应该是逆时针。

要验证也很容易验证:在OpenMesh中编辑3D图像时,通常会遵循==“右手法则”==。这意味着当你站在多边形的外侧时,如果你用右手的拇指指向多边形的法线方向(也就是垂直于多边形的方向),那么其他手指的方向就是多边形的边缘顺时针方向。

所以,对于底部而言,它的法线方向应该是朝向多边形内部,所以多边形的边缘顺时针方向是正确的。对于其他面,法线方向应该朝向外部,因此多边形的边缘顺时针方向是逆时针的。

我一开始不管是尝试用stl去写一个3d图像,还是尝试使用OpenMesh来写一个3d图像,总是一次性写不对,总要来回改一下,知道了这个简单的规律就不会再犯错了

一些细碎知识点

1.OpenGL的状态通常被称为OpenGL上下文(Context)。

我常常在一些大佬的代码中看到xxx上下文,我常常为此感到不解,现在看来,上下文就可以理解为状态

而OpenGL自身是一个巨大的状态机(State Machine)。所以,上下文和状态,状态机的概念相关!

2.如何快速上手openmesh,照着这个教程,一共十五章,看完基本就是OK了

在这里插入图片描述

2023-11-28 补充:

现在是下班时刻,又是被demo折磨的一天!
当前时间:
在这里插入图片描述

补充1:

认真看了上面文章的,你可能会记得我在运行openmesh测试demo时报错,我还说过:

当前工程是Release版本,而引用的库文件时Debug版本,所以你需要重复配置一下上面的操作,在Debug模式下!所以使用下载器下载的库文件就是debug版本的!

当时说出上面这段话纯粹是以前的那个我,认知不行!

想想也知道,官方给的下载器怎么可能只给debug版本呢?
现在我查了一下,官方确实也给了release版本
在这里插入图片描述
但为什么我的release版本会报错呢?
再次追根溯源:

因为我只加了 OpenMeshCored.lib和OpenMeshToolsd.lib(这两个都是debug版本!)
所以,真相大白了!你要同时支持release和debug版本,你需要把下面这个四个库都加上!
OpenMeshCored.lib
OpenMeshToolsd.lib
OpenMeshCore.lib
OpenMeshTools.lib

在这里插入图片描述

在这里插入图片描述

补充2:

我自己想要尝试一下编译源码:
https://www.graphics.rwth-aachen.de/software/openmesh/download/
在这里插入图片描述
ok,下载好了,我们就解压:
在这里插入图片描述
欧克,新建一个build文件
在这里插入图片描述
然后打开我们的cmakeGUI
在这里插入图片描述
在这里插入图片描述

# 我们直接在最后面加上这几句话,让库文件生成在同一个lib目录下!
message(${CMAKE_BINARY_DIR}/lib)
set_target_properties(OpenMeshTools PROPERTIES
    ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
    LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
)
set_target_properties(OpenMeshCore PROPERTIES
    ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
    LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
)

在这里插入图片描述
在这里插入图片描述
下面我们来看结果:
其实在cmake中我们已经给出了lib的路径:D:\vs2022\openmesh\OpenMesh-10.0.0\build\lib
在这里插入图片描述
在这里插入图片描述

Debug:
在这里插入图片描述
Release:
在这里插入图片描述


突然发现:
下面这个目录刚好存放了,我们生成的所有需要的库目录!
D:\vs2022\openmesh\OpenMesh-10.0.0\build\Build\lib
在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

踏过山河,踏过海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值