wayland(xdg_wm_base) + egl + opengles 使用 Assimp 加载3D model 最简实例(十三)

本文主要是介绍wayland(xdg_wm_base) + egl + opengles 使用 Assimp 加载3D model 最简实例(十三),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 前言
  • 一、3D model 文件介绍
    • 1. 3d model 介绍
      • 1.1 如何获取3d model 文件
      • 1.2 3d model 的文件格式
      • 1.3 obj模型数据格式
    • 2. 3d 立方体 model 实例——cube.obj
  • 二、Assimp 介绍
    • 1. Assimp 简介
    • 2.ubuntu 上安装libassimp
    • 3. 使用Assimp 解析 cube.obj 文件
      • 3.1 assimp_load_cube.cpp 文件内容如下
      • 3.2 编译
      • 3.3 运行
  • 三、opengles 使用 Assimp 加载 3D 立方体 model 实例
    • 1. egl_wayland_assimp_cube.c
    • 2. xdg-shell-client-protocol.h 和 xdg-shell-protocol.c
    • 3. 编译
    • 4. 运行
  • 总结
  • 参考资料


前言

`本文主要介绍opengles 如何使用 第三方库Assimp(基于C++) 加载一个最简当的3d 立方体model
软硬件环境:
硬件:PC
软件:ubuntu22.04 egl1.4 weston9.0 opengles3.0 libassimp.so.5.2.0


一、3D model 文件介绍

1. 3d model 介绍

1.1 如何获取3d model 文件

模型通常都是通过Blender、3DS Max或者Maya这样的3D建模工具(3D Modeling Tool)精心制作出来的

1.2 3d model 的文件格式

模型的文件格式有很多种,每一种都会以它们自己的方式来导出模型数据。像是Wavefront的.obj这样的模型格式,只包含了模型数据以及材质信息,像是模型颜色和漫反射/镜面光贴图。而以XML为基础的Collada文件格式则非常的丰富,包含模型、光照、多种材质、动画数据、摄像机、完整的场景信息等等。Wavefront的.obj格式通常被认为是一个易于解析的模型格式

1.3 obj模型数据格式

  • 以#开始的行为注释行
  • usemtl 和 mtllib表示的材质相关数据
  • o 引入一个新的object
  • v 表示顶点坐标
  • vt 表示顶点纹理坐标
  • vn 表示顶点法线
  • f 表示一个面,面使用1/2/8这样格式,表示顶点坐标/纹理坐标/法线的索引,这里索引的是前面用v,vt,vn定义的数据

2. 3d 立方体 model 实例——cube.obj

最简单的3d 立方体model 文件 cube.obj 内容如下
cube.obj

# Number of vertices: 8
v -0.5 0.5 0.5
v -0.5 -0.5 0.5
v 0.5 -0.5 0.5
v 0.5 0.5 0.5
v 0.5 0.5 -0.5
v 0.5 -0.5 -0.5
v -0.5 -0.5 -0.5
v -0.5 0.5 -0.5# Number of Polygons: 12
f 1 2 3
f 1 3 4
f 4 3 6
f 4 6 5
f 5 6 7
f 5 7 8
f 8 7 2
f 8 2 1
f 2 7 6
f 2 6 3
f 8 1 4
f 8 4 5

在PC 上使用3D 查看器打开cube.obj 文件,如下图所示
在这里插入图片描述

二、Assimp 介绍

1. Assimp 简介

一个非常流行的模型导入库是Assimp,它是Open Asset Import Library(开放的资产导入库)的缩写。Assimp能够导入很多种不同的模型文件格式(并也能够导出部分的格式),它会将所有的模型数据加载至Assimp的通用数据结构中。当Assimp加载完模型之后,我们就能够从Assimp的数据结构中提取我们所需的所有数据了。由于Assimp的数据结构保持不变,不论导入的是什么种类的文件格式,它都能够将我们从这些不同的文件格式中抽象出来,用同一种方式访问我们需要的数据。
当使用Assimp导入一个模型的时候,它通常会将整个模型加载进一个场景(Scene)对象,它会包含导入的模型/场景中的所有数据。Assimp会将场景载入为一系列的节点(Node),每个节点包含了场景对象中所储存数据的索引,每个节点都可以有任意数量的子节点。Assimp数据结构的(简化)模型如下:
在这里插入图片描述

  • 一个Mesh对象本身包含了渲染所需要的所有相关数据,像是顶点位置、法向量、纹理坐标、面(Face)和物体的材质;
  • 一个网格包含了多个面。Face代表的是物体的渲染图元(Primitive)(三角形、方形、点)。一个面包含了组成图元的顶点的索引。由于顶点和索引是分开的,使用一个索引缓冲来渲染是非常简单的;
  • 一个网格也包含了一个Material对象,它包含了一些函数能让我们获取物体的材质属性,比如说颜色和纹理贴图(比如漫反射和镜面光贴图);
  • 当使用建模工具对物体建模的时候,艺术家通常不会用单个形状创建出整个模型。通常每个模型都由几个子模型/形状组合而成。组合模型的每个单独的形状就叫做一个网格(Mesh)。比如说有一个人形的角色:艺术家通常会将头部、四肢、衣服、武器建模为分开的组件,并将这些网格组合而成的结果表现为最终的模型。一个网格是我们在OpenGL中绘制物体所需的最小单位(顶点数据、索引和材质属性)。一个模型(通常)会包括多个网格;

所以,我们需要做的第一件事是将一个物体加载到Scene对象中,遍历节点,获取对应的Mesh对象(我们需要递归搜索每个节点的子节点),并处理每个Mesh对象来获取顶点数据、索引以及它的材质属性。最终的结果是一系列的网格数据,我们会将它们包含在一个Model对象中

2.ubuntu 上安装libassimp

使用如下命令可以在ubuntu 上安装 libassimp
sudo apt install libassimp-dev
安装完成后,在/usr/lib/x86_64-linux-gnu/目录下就能看到libassimp相关的库文件,如下图所示
在这里插入图片描述

3. 使用Assimp 解析 cube.obj 文件

3.1 assimp_load_cube.cpp 文件内容如下

#include <iostream>
#include <stdio.h>
#include <GLES3/gl3.h>// 使用 Assimp 加载模型文件
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>int main()
{Assimp::Importer importer;const aiScene* scene = importer.ReadFile("./cube.obj", aiProcess_Triangulate | aiProcess_FlipUVs);if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {// 加载模型失败printf("cube.obj load failed\n");return -1;}aiMesh* mesh = scene->mMeshes[0];printf("mesh->mNumVertices = %d\n", mesh->mNumVertices);printf("mesh->mNumFaces = %d\n", mesh->mNumFaces);// 获取顶点坐标数据printf("cube vVertices : \n");GLfloat* vVertices = new GLfloat[mesh->mNumVertices * 3];for (unsigned int i = 0; i < mesh->mNumVertices; i++) {vVertices[i * 3] = mesh->mVertices[i].x;vVertices[i * 3 + 1] = mesh->mVertices[i].y;vVertices[i * 3 + 2] = mesh->mVertices[i].z;printf("%.1f, %.1f, %.1f,\n", vVertices[i * 3], vVertices[i * 3 + 1], vVertices[i * 3 + 2]);}// 获取面索引数据printf("cube indices : \n");GLushort* indices = new GLushort[mesh->mNumFaces * 3];for (unsigned int i = 0; i < mesh->mNumFaces; i++) {for (unsigned int j = 0; j < 3; j++) {indices[i * 3 + j] = mesh->mFaces[i].mIndices[j];}printf("%d, %d, %d,\n", indices[i * 3], indices[i * 3 + 1], indices[i * 3 + 2]);}return 0;
}

3.2 编译

使用如下命令对 assimp_load_cube.cpp 文件进行编译
g++ assimp_load_cube.cpp -o assimp_load_cube -lassimp
编译成功会在当前目录下得到可执行文件 assimp_load_cube

3.3 运行

将cube.obj 和 可执行文件 assimp_load_cube 放到同一个目录下,执行 ./assimp_load_cube 命令,打印解析出来的顶点坐标和顶点索引信息如下:

lkh@ubuntu:~/lkh2024/opengles_test$ ./assimp_load_cube 
mesh->mNumVertices = 36
mesh->mNumFaces = 12
cube vVertices : 
-0.5, 0.5, 0.5,
-0.5, -0.5, 0.5,
0.5, -0.5, 0.5,
-0.5, 0.5, 0.5,
0.5, -0.5, 0.5,
0.5, 0.5, 0.5,
0.5, 0.5, 0.5,
0.5, -0.5, 0.5,
0.5, -0.5, -0.5,
0.5, 0.5, 0.5,
0.5, -0.5, -0.5,
0.5, 0.5, -0.5,
0.5, 0.5, -0.5,
0.5, -0.5, -0.5,
-0.5, -0.5, -0.5,
0.5, 0.5, -0.5,
-0.5, -0.5, -0.5,
-0.5, 0.5, -0.5,
-0.5, 0.5

这篇关于wayland(xdg_wm_base) + egl + opengles 使用 Assimp 加载3D model 最简实例(十三)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/754731

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

k8s按需创建PV和使用PVC详解

《k8s按需创建PV和使用PVC详解》Kubernetes中,PV和PVC用于管理持久存储,StorageClass实现动态PV分配,PVC声明存储需求并绑定PV,通过kubectl验证状态,注意回收... 目录1.按需创建 PV(使用 StorageClass)创建 StorageClass2.创建 PV

Redis 基本数据类型和使用详解

《Redis基本数据类型和使用详解》String是Redis最基本的数据类型,一个键对应一个值,它的功能十分强大,可以存储字符串、整数、浮点数等多种数据格式,本文给大家介绍Redis基本数据类型和... 目录一、Redis 入门介绍二、Redis 的五大基本数据类型2.1 String 类型2.2 Hash

MyBatis延迟加载与多级缓存全解析

《MyBatis延迟加载与多级缓存全解析》文章介绍MyBatis的延迟加载与多级缓存机制,延迟加载按需加载关联数据提升性能,一级缓存会话级默认开启,二级缓存工厂级支持跨会话共享,增删改操作会清空对应缓... 目录MyBATis延迟加载策略一对多示例一对多示例MyBatis框架的缓存一级缓存二级缓存MyBat

Redis中Hash从使用过程到原理说明

《Redis中Hash从使用过程到原理说明》RedisHash结构用于存储字段-值对,适合对象数据,支持HSET、HGET等命令,采用ziplist或hashtable编码,通过渐进式rehash优化... 目录一、开篇:Hash就像超市的货架二、Hash的基本使用1. 常用命令示例2. Java操作示例三