关于OpenMesh与OpenGL

news2024/11/15 17:43:35

文章目录

  • OpenMesh官网
  • OpenMesh是什么?他能做什么?
  • 直接无源码安装
  • 测试
    • 报错:
    • 效果:
  • 学习openmesh
    • 学习openmesh的流程如下:
    • 第一步,了解openmesh库的基本概念
    • 第二步,查看openmesh的官方示例,了解简单的接口api
    • 练习,自己写一个立方体
    • 开启一个小项目,比如:如何加载output.off这个模型,修改和保存
  • OpenMesh架构
  • openflipper的安装
  • openGL库的安装
    • 为什么要安装openGL?
    • GLFW的安装
    • GLAD安装
    • 配置GLFW 和 GLAD
      • 1) 配置GLFW
      • 2) 配置 GLAD
      • 3) 测试OpenGL
  • openmesh与opengl结合使用
  • 一些感悟
  • 一些细碎知识点
    • 1.OpenGL的状态通常被称为OpenGL上下文(Context)。
    • 2.如何快速上手openmesh,照着这个教程,一共十五章,看完基本就是OK了

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了

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1116520.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【java】【MyBatisPlus】【二】MyBatisPlus常规使用

目录 一、简述 1、概述 2、特性 3、支持数据库 二、标准数据层开发 1、标准数据层CRUD功能 1.1 新增insert 1.2 删除功能deleteById 1.3 修改功能updateById 1.4 查询单个selectById 1.5 查询全部selectList 2、分页功能 2.1 设置MybatisPlus分页拦截器作为Spring管…

LSTM-Attention单维时间序列预测研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Redis基本命令和常用数据类型

文章目录 前言一、Redis简介二、基本操作1.赋值2.取值3.切换数据库4.查看数据库所有键&#xff08;key&#xff09;5.查看键值类型6.移动键值到其他数据库7.设置键值生存时间&#xff08;两种&#xff09;8.查看键值生存时间9.查看当前数据库大小10.判断键是否存在11.清空当前数…

IntelliJ IDEA 2020.2.1白票安装使用方法

先安装好idear Plugins 内手动添加第三方插件仓库地址&#xff1a;https://plugins.zhile.io 搜索&#xff1a;IDE Eval Reset插件进行安装 输入https://plugins.zhile.io 手动安装离线插件方法 安装包可以去笔者的CSDN资源库下载 安装mybaties插件

Simulink模型加密共享

1.前言 为了保护知识产权&#xff0c;有时候需要让用户能使用slx模型运行仿真&#xff0c;但是无法查看和修改模型和子系统的结构&#xff0c;这时可以用Simulink coder来生成受保护的模型。主要步骤如下&#xff1a; &#xff08;1&#xff09;将slx模型的各个子系统唯一命名…

Nginx负载均衡反向代理动静分离

文章目录 nginx负载均衡&反向代理&动静分离环境说明部署动静分离1.主机lnmp部署一个动态页面&#xff0c;在此以discuz论坛系统为例2.主机n1部署两个静态页面访问动、静态页面 配置负载均衡配置反向代理访问测试 nginx负载均衡&反向代理&动静分离 环境 主机名…

重测序基因组:Pi核酸多样性计算

如何计算核酸多样性 Pi 本期笔记分享关于核酸多样性pi计算的方法和相关技巧&#xff0c;主要包括原始数据整理、分组文件设置、计算原理、操作流程、可视化绘图等步骤。 基因组Pi核酸多样性&#xff08;Pi nucleic acid diversity&#xff09;是一种遗传学研究中用来描述种群内…

使用CDN构建读取缓存设计

在构建需要高吞吐量和最小响应时间的系统的API时&#xff0c;缓存几乎是不可避免的。每个在分布式系统上工作的开发人员都曾在某个时候使用过某种缓存机制。在本文中&#xff0c;我们将探讨如何使用CDN构建读取缓存设计&#xff0c;不仅可以优化您的API&#xff0c;还可以降低基…

JVM第十六讲:调试排错 - Java 线程分析之线程Dump分析

调试排错 - Java 线程分析之线程Dump分析 本文是JVM第十六讲&#xff0c;Java 线程分析之线程Dump分析。Thread Dump是非常有用的诊断Java应用问题的工具。 文章目录 调试排错 - Java 线程分析之线程Dump分析1、Thread Dump介绍1.1、什么是Thread Dump1.2、Thread Dump特点1.3、…

maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories

前言 略 说明 新设备上安装了mvn 3.8.5&#xff0c;编译新项目出错&#xff1a; [ERROR] Non-resolvable parent POM for com.admin.project:1.0: Could not transfer artifact com.extend.parent:pom:1.6.9 from/to maven-default-http-blocker (http://0.0.0.0/): Bl…

【LeetCode】 387. 字符串中的第一个唯一字符

题目链接 文章目录 所有方法 复杂度 ( O ( n ) O(n) O(n)、 O ( ∣ Σ ∣ ) O(|\Sigma|) O(∣Σ∣)) Python3方法一&#xff1a;collections.Counter() 统计频次方法二&#xff1a;哈希映射 { key字符&#xff1a;value【首次出现的索引 or -1 出现多次】}方法三&#xff1a; c…

账号合租平台源码Thinkphp6.1|内置详细搭建教程

小白账号合租平台说明 系统采用的是常见的租号平台模式,现在网络上流出的这种类型的源码还很少 平台介绍 1.租号模式,用户可自行选择单独租号或采用合租的模式。 2.支付,采用易支付通用接口 3.邀请返利,为了站长能更好推广推荐了邀请返利功能 4.用户提现功能 5.工单…

社会网络分析软件

UCINET UCINET 6 for Windows

vue3中弹框中的el-select下拉组件显示value而不显示label

1.场景 使用element-ui中的el-select&#xff0c;给选择框赋值时显示的值是value不是label 2.原因分析 3.解决方法 在点击编辑按钮后将获取到的对象中的os属性值改为string类型 <el-select v-model"form.os" clearable placeholder"请选择" style&qu…

【Java】正则表达式,校验数据格式的合法性。

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ 正则表达式 正则表达式&#xff1a; ①可以校…

互联网Java工程师面试题·Java 面试篇·第一弹

目录 1、Java 中能创建 volatile 数组吗&#xff1f; 2、volatile 能使得一个非原子操作变成原子操作吗&#xff1f; 3、volatile 修饰符的有过什么实践&#xff1f; 4、volatile 类型变量提供什么保证&#xff1f; 5、10 个线程和 2 个线程的同步代码&#xff0c;哪个更容…

MPI并行编程技术

MPI并行编程技术 MPI含义及环境搭建安装点对点通信阻塞型接口MPI_SendMPI_Recv 阻塞式示例tag雅可比迭代示例死锁 MPI含义及环境搭建安装 MPICH官网 Github地址 MPI历史版本下载地址 安装教程 MPI介绍 MPI课程 点对点通信 阻塞型接口 MPI_Send MPI_Recv 阻塞式示例 tag 雅…

贪心算法(1)--经典贪心算法

目录 一、活动安排问题 二、最优装载问题 三、分数背包问题 四、多机调度问题 一、活动安排问题 1、策略 活动安排问题&#xff1a;设有n个活动的集合E{1,2,...,n}&#xff0c;每个活动i都有一个使用该资源的起始时间和一个结束时间&#xff0c;且。如果选择了活动i则它在…

新年学新语言Go之五

一、前言 Go虽然不算是面向对象语言&#xff0c;但它支持面向对象一些特性&#xff0c;面向接口编程是Go一个很重要的特性&#xff0c;而Go的接口与Java的接口区别很大&#xff0c;Go的接口比较复杂&#xff0c;这里仅用一个最简单例子做介绍&#xff0c;复杂的我也还没学。 …

VMware中安装centos无网络,配置教程

VMware虚拟机中装了centos7,装完之后一直无法联网&#xff0c;网上的教程都试了也没用&#xff0c;这里记录一下最后的解决方案。 VMware配置 1. 点击 虚拟机-》设置 windows配置 打开电脑网络连接 共享选项选中我们虚拟机网络中包含的VMnet8的 VMnet8网络就自动变成这样了&a…