Direct3D网格(一)

创建网格

我们可以用D3DXCreateMeshFVF函数创建一个"空"网格对象 ,空网格对象是指我们指定了网格的面片总数和顶点总数,然后由该函数为顶点缓存索引缓存属性缓存分配大小合适的内存,之后即可手工填入网格数据。

HRESULT WINAPI D3DXCreateMeshFVF(DWORD NumFaces,DWORD NumVertices,DWORD Options,DWORD FVF,LPDIRECT3DDEVICE9 pD3DDevice,LPD3DXMESH* ppMesh
);

NumFaces:网格将具有的面片总数,该值必须大于0

NumVertices:网格将具有的顶点总数,该值必须大于0

Options:创建网格时所使用的创建标记,枚举D3DXMESH,一些常用的标记如下
D3DXMESH_32BIT  网格将使用32位索引
D3DXMESH_MANAGED  网格数据将被存储于托管内存池中
D3DXMESH_WEITEONLY  指定网格数据为只读

FVF:存储在该网格中的顶点的灵活顶点格式

pDevice:设备指针

ppMesh:所创建的网格对象的指针

也可以用函数D3DXCreateMesh函数来创建空网格,在该函数中并未指定FVF,而是用一个D3DVERTEXELEMENT9类型的结构数组来描述顶点数据的布局方式。

HRESULT WINAPI D3DXCreateMesh(DWORD NumFaces,DWORD NumVertices,DWORD Options,CONST D3DVERTEXELEMENT9 *pDeclaration,LPDIRECT3DDEVICE9 pD3DDevice,LPD3DXMESH* ppMesh
);HRESULT WINAPI D3DXDeclaratorFromFVF(DWORD FVF,D3DVERTEXELEMENT9 pDeclarator[MAX_FVF_DECL_SIZE]
);

ID3DXBaseMesh获取几何信息接口

//获取
HRESULT ID3DXMesh::GetVertexBuffer(LPDIRECT3DVERTEXBUFFER9* ppVB);			//获取顶点缓存(用于存储网格顶点)
HRESULT ID3DXMesh::GetIndexBuffer(LPDIRECT3DINDEXBUFFER9* ppIB);			//获得索引缓存(决定顶点应以何种组合方式构成网格的三角形单元)
//锁定缓存,进行读写操作,注意这些方法锁定的是整个顶点缓存或索引缓存
//Flags参数描述了如何进行锁定,函数返回是ppData参返回指向被锁定的内存的指针的地址
HRESULT ID3DXMesh::LockVertexBuffer(DWORD Flags, BYTE** ppData);
HRESULT ID3DXMesh::LockIndexBuffer(DWORD Flags, BYTE** ppData);
//解锁
HRESULT ID3DXMesh::UnlockVertexBuffer();
HRESULT ID3DXMesh::UnlockIndexBuffer();
//获取几何信息的其他接口
DWORD GetFVF();					//返回描述顶点格式的DWORD
DWORD GetNumVertices();			//返回顶点缓存中的顶点个数
DWORD GetNumBytesPerVertex();	//返回每个顶点所占的字节数
DWORD GetNumFaces();			//返回网格中(三角形)面片的个数
DWORD GetOptions();             //返回网格的标记组合

子集和属性缓存

一个网格由一个或多个子集组成,一个子集是网格中一组可用相同属性进行绘制的三角形单元,这里属性是指材质、纹理和绘制状态

为了区分不同子集,我们为每个子集指定一个唯一的非负整数值,该值可为DWORD类型所能容纳的任何非负整数,网格中的每个三角形单元都被赋予了一个属性ID,该ID指定了该三角形单元所属的子集

这些三角形单元的属性ID被存储在网格的属性缓存中,该属性缓存实际上是一个DWORD类型的数组,由于每个面片在属性缓存中都有对应项,所以属性缓存中元素的个数与网格中面片的个数完全相等,而且属性缓存中那些项与在索引缓存中定义的三角形单元是一一对应 的,即属性缓存中的第i项对应于索引缓存中的第i个三角形,三角形单元i是有索引缓存中如下3个索引定义的。

A=i\cdot 3      B=i\cdot 3+1     C=i\cdot 3+2

属性缓存的锁定与解锁
ID3DXMesh::LockAttributeBuffer(DWORD Flags, DWORD** ppData);
ID3DXMesh::UnlockAttributeBuffer();

绘制

ID3DXMesh接口提供了方法DrawSubset用于绘制三角形单元,参数AttribId为指定的某个子集,若要绘制整个网格,必须绘制该网格的所有子集,比较方便的方法为将各子集的属性ID依次指定为0,1,2...n-1,n为子集的总数,每个子集都有一个对应的材质和纹理数组,这样通过索引i就可找到对应的材质和纹理。

ID3DXMesh::DrawSubset(DWORD AttribId);for (int i = 0; i < numSubsets; ++i)
{Device->SetMaterial(mtrls[i]);Device->SetTexture(0, textures[i]);Mesh->DrawSubset(i);
}

网格优化

为了更高效的绘制一个网格,我们可对该网格中的顶点和索引进行重组,这个重组的过程称为网格优化OptimizeInplace

HRESULT ID3DXMesh::OptimizeInplace(DWORD Flags,CONST DWORD* pAdjacencyIn,DWORD* pAdjacencyOut,DWORD* pFaceRemap,LPD3DXBUFFER *ppVertexRemap
);

Flags:优化选项标记,通知该方法所要实施的优化方案
D3DXMESHOPT_COMPACT  从网格中移除那些无用顶点和索引
D3DXMESHOPT_ATTSORT  依据属性对各三角形单元进行排序,并生成一个属性表,这样可使DrawSubset获得更高的绘制效率
D3DXMESHOPT_VERTEXCACHE  提高顶点高速缓存的命中率
D3DXMESHOPT_STRIPORDER  对索引进行重组,以使三角形单元条带尽可能的长
D3DXMESHOPT_IGNOREVERTS  仅对索引进行优化,忽略顶点
标记D3DXMESHOPT_VERTEXCACHE和D3DXMESHOPT_STRIPORDER不允许被被同时使用

pAdjacencyIn:指向未经优化的网格的邻接数组的指针

pAdjacencyOut:指向一个DWORD类型数组的指针,该数组被填充了经优化后的网格的邻接信息,该数组的维数必须为GetNumFaces()*3(每个三角形单元有3个边,所有邻接信息倍数为3倍),如果不需要该信息,可将参数赋为0

pFaceRemap:指向一个DWORD类型数组的指针,该数组填充了网格面片的重绘信息,该数组的维数应为GetNumFaces(),当对一个网格面实施优化后,其面片在索引缓存中可能发生了移动,该面片重绘信息表明了原始面片所被移动到的新位置,即pFaceRemap中的第i项保存了表示第i个原始面片被移动到哪里的面片索引,如果不需要该信息可将该参数赋为0

ppVertexRemap:指向ID3DXMesh对象指针的地址,该对象中保存了顶点的重绘信息,该缓存所包含的顶点数应为GetNumVertices(),当网格面经过优化之后,其顶点在索引缓存中的位置可能发生变动,顶点重绘信息表明了原始顶点移动到的新位置,即ppVertexRemap中的第i项保存了表示第i个原始顶点被移动到哪里的顶点索引,如果不需要该值,将该参数赋为0

DWORD adjacencyInfo[Mesh->GetNumFaces() * 3];
Mesh->GenerateAdjacency(0.0f, adjacencyInfo);
DWORD optimizedAdjacencyInfo[Mesh->GetNumFaces() * 3];
Mesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE, adjacencyInfo, optimizedAdjacencyInfo, 0, 0);

OptimizeInplace功能类似的另一个方法是Optimize该方法将输出调用该方法的网格对象优化后的版本,但是网格对象本身不会发生改变

HRESULT ID3DXMesh::Optimize(DWORD Flags,CONST DWORD* pAdjacencyIn,DWORD* pAdjacencyOut,DWORD* pFaceRemap,LPD3DXBUFFER *ppVertexRemap,LPD3DXMESH* ppOptMesh
);

属性表

如果一个网格对象在优化处理时使用了D3DXMESHOPT_ATTRSORT标记,则构成该网格的三角形面片就会依据其属性进行排序,这样属于特定子集的三角形面片就会被保存在顶点缓存或索引缓存中的一个连续存储空间

除了可对面片进行排序外,D3DXMESHOPT_ATTRSORT优化选项还将创建一个属性表,该属性表是一个D3DXATTRIBUTERANGE类型的结构数组,属性表中每一项都对应于网格的一个子集,并指定了该子集中面片的几何信息被存储在顶点缓存或索引缓存的哪一个存储块中。

typedef struct _D3DXATTRIBUTERANGE
{DWORD AttribId;DWORD FaceStart;DWORD FaceCount;DWORD VertexStart;DWORD VertexCount;
} D3DXATTRIBUTERANGE;

AttribId:子集的Id
FaceStart:一个大小为FaceStart*3的偏移量,表明了该子集的三角形单元在索引缓存中的起始位置
FaceCount:该子集中面片(三角形单元)的总数
VertexStart:一个表明了与子集相关的顶点在顶点缓存中起始位置的偏移量
VertexCount:该子集中的顶点总数

属性表的访问与设置

可以使用GetAttributeTable方法来访问一个网格面的属性表,该方法完成了俩项工作:返回属性表中的属性个数和属性数据填充D3DXATTRIBUTERANGE类型的结构数组。要想获取属性表中的元素个数,可将方法第一个参数取为0

HRESULT ID3DXMesh::GetAttributeTable(D3DXATTRIBUTERANGE *pAttribTable,DWORD* pAttribTableSize
);DWORD numSubsets=0;
Mesh->GetAttributeTable(0,&numSubsets);//一旦得到了属性表中的元素个数,就可以用属性数据填充结构数组
D3DXATTRIBUTERANGE table = new D3DXATTRIBUTERANGE[numSubSets];
Mesh->GetAttributeTable(table,&numSubsets);

可以使用SetAttributeTable对属性表进行设置

D3DXATTRIBUTERANGE attributeTable[12];
//填充该数组结构....//设定属性表共有12个子集
Mesh->SetAttributeTable(attributeTable,12);

邻接信息

对于某些网格运算(如网格优化),需要知道对任意给定三角形面片,哪些面片与其邻接,这些邻接信息都存储在网格的邻接数组中。邻接数组的类型为DWORD,其每一项都包含了一个标识网格中某个三角形面片的索引,如果邻接数组中某一项等于ULONG MAX=4294967295,则表明网格中某一特定边没有邻接面片,我们也可将该项赋为-1来表示此种情形。

邻接数组的维数必须为GetNumFaces()*3,网格中每个三角形面片都有3个可能的邻接面片,可用GenerateAdjacency函数来输出邻接信息。

HRESULT ID3DXMesh::GenerateAdjacency(FLOAT Epsilon,DWORD* pAdjacency
);DWORD adjacencyInfo[Mesh->GetNumFaces()*3];
Mesh->GenerateAdjacency(0.001f,adjacencyInfo);

fEpsilon:一个很小的正数值,指定了在某种距离度量下,俩个点接近到何种程度方可认为这俩点为同一点,例如俩点间距离小于该值,认为俩点为同一点
pAdjacency:指向一个DWORD类型的数组的指针,该数组中存储了邻接信息

克隆

有时需要生成网格数据的一个副本可用CloneMeshFVF方式来实现,该方法允许目标网格采用与原网格不同的创建选项和灵活顶点格式。

HRESULT ID3DXMesh::CloneMeshFVF(DWORD Options,DWORD FVF, LPDIRECT3DDEVICE9 pD3DDevice, LPD3DXMESH* ppCloneMesh
);ID3DXMesh* clone = 0;
Mesh->CloneMeshFVF(Mesh->GetOptions(), D3DFVF_XYZ | D3DFVF_NORMAL, Device, &clone);

Options:创建某网格副本时的创建标记或标记组合,枚举D3DXMESH
D3DXMESH_32BIT  网格将使用32位索引
D3DXMESH_MANAGED  网格数据将被存储于托管内存池中
D3DXMESH_WRITEONLY 指定网格数据为只读
D3DXMESH_DYNAMIC  网格缓存将使用动态内存

FVF:所要创建的克隆网格的灵活顶点格式

pDevice:设备指针

ppCloneMesh:输出所创建的克隆网格

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机专业毕业设计项目推荐14-文档编辑平台(SpringBoot+Vue+Mysql)

文档编辑平台&#xff08;SpringBootVueMysql&#xff09; **介绍****各部分模块实现** 介绍 本系列(后期可能博主会统一为专栏)博文献给即将毕业的计算机专业同学们,因为博主自身本科和硕士也是科班出生,所以也比较了解计算机专业的毕业设计流程以及模式&#xff0c;在编写的…

【C++设计模式之解释器模式:行为型】分析及示例

简介 解释器模式&#xff08;Interpreter Pattern&#xff09;是一种行为型设计模式&#xff0c;它提供了一种解决问题的方法&#xff0c;通过定义语言的文法规则&#xff0c;解释并执行特定的语言表达式。 解释器模式通过使用表达式和解释器&#xff0c;将文法规则中的句子逐…

提高工作效率!本地部署Stackedit Markdown编辑器,并实现远程访问

文章目录 1. docker部署Stackedit2. 本地访问3. Linux 安装cpolar4. 配置Stackedit公网访问地址5. 公网远程访问Stackedit6. 固定Stackedit公网地址 StackEdit是一个受欢迎的Markdown编辑器&#xff0c;在GitHub上拥有20.7k Star&#xff01;&#xff0c;它支持将Markdown笔记保…

【计算机基础】Git系列3:常用操作

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…

C语言之动态内存管理_柔性数组篇(2)

目录 柔性数组的特点 柔性数组的使用 动态内存函数增容柔性数组模拟实现 柔性数组的优势 今天接着来讲解一下柔性数组知识。 柔性数组的特点 C99中&#xff0c;结构中的最后一个元素允许是未知大小的数组&#xff0c;这就叫做【柔性数组】成员。 结构体中最后一个成员未…

node中的crypto模块指南

node中的crypto模块指南 加密操作可能很棘手&#xff0c;以至于付费的加密服务公司的存在只是为了确保在代码库中正确实现加密操作。好消息是&#xff0c;只需学习一些知识&#xff0c;我们就可以使用 Node 的内置加密模块免费进行适当的加密。 在本指南中&#xff0c;我们将…

网络是什么?(网络零基础入门篇)

1.如何理解局域网和广域网&#xff1f; 2.路由器和交换机是怎么样工作的&#xff1f; 3.三层交换机能不能代替路由器&#xff1f; -- 局域网 广域网 -- 企业网架构&#xff0c;运营商架构&#xff0c;数据中心架构 -- 局域网 通过 交换机连接的 转发 相同的ip地址…

弹性资源组件elastic-resource设计(四)-任务管理器和资源消费者规范

简介 弹性资源组件提供动态资源能力&#xff0c;是分布式系统关键基础设施&#xff0c;分布式datax&#xff0c;分布式索引&#xff0c;事件引擎都需要集群和资源的弹性资源能力&#xff0c;提高伸缩性和作业处理能力。 本文介绍弹性资源组件的设计&#xff0c;包括架构设计和详…

基于AlexNet深度学习网络的智能垃圾分类系统matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1、基于AlexNet深度学习网络的智能垃圾分类系统概述 4.2、基于AlexNet深度学习网络的智能垃圾分类系统主要原理 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab20…

Linux基础指令大全

Linux基础指令大全 1. ls 指令2. pwd命令3. cd 指令4. touch指令5. mkdir指令6. rmdir指令 && rm 指令7. man指令8.cp指令9. mv指令10. cat 指令11. more指令12. less指令13. head指令14. tail指令15. 时间相关的指令1. **在显示方面&#xff0c;使用者可以设定欲显示的…

【bug日记】spring项目使用配置类和测试类操作数据库

最近学校课程要求使用spring操作数据库&#xff0c;时间有点久了&#xff0c;操作都不太熟悉了&#xff0c;遇到了很多坑&#xff0c;特此记录一下。 导入依赖 <!-- Spring Framework --> <dependency><groupId>org.springframework</groupId><ar…

windows redis 自启动 Redis服务无法启动报错1067问题

如果你的系统服务里面已经有redis服务并且无法启动&#xff0c;则使用下面的命令卸载此服务 ! 1、停止Redis服务&#xff1a; redis-server --service-uninstall 2、删除系统服务 sc delete redis 进入到你的Redis安装目录&#xff0c;我的在以下目录&#xff0c;谨记此时不…

仅用61行代码,你也能从零训练大模型

本文并非基于微调训练模型&#xff0c;而是从头开始训练出一个全新的大语言模型的硬核教程。看完本篇&#xff0c;你将了解训练出一个大模型的环境准备、数据准备&#xff0c;生成分词&#xff0c;模型训练、测试模型等环节分别需要做什么。AI 小白友好~文中代码可以直接实操运…

王道考研计算机组成原理——计算机硬件的基础知识

计算机组成原理的基本概念 计算机硬件的针脚都是用来传递信息&#xff0c;传递数据用的&#xff1a; 服务程序包含一些调试程序&#xff1a; 计算机硬件的基本组成 控制器通过电信号来协调其他部件的工作&#xff0c;同时负责解析存储器里存放的程序指令&#xff0c;然后指挥…

Reactor 模式网络服务器【I/O多路复用】(C++实现)

前导&#xff1a;本文是 I/O 多路复用的升级和实践&#xff0c;如果想实现一个类似的服务器的话&#xff0c;需要事先学习 epoll 服务器的编写。 友情链接&#xff1a; 高级 I/O【Linux】 I/O 多路复用【Linux/网络】&#xff08;C实现 epoll、select 和 epoll 服务器&#x…

vue启动项目,npm run dev出现error:0308010C:digital envelope routines::unsupported

运行vue项目&#xff0c;npm run dev的时候出现不支持错误error:0308010C:digital envelope routines::unsupported。 在网上找了很多&#xff0c;大部分都是因为版本问题&#xff0c;修改环境之类的&#xff0c;原因是对的但是大多还是没能解决。经过摸索终于解决了。 方法如…

【广州华锐互动】车辆零部件检修AR远程指导系统有效提高维修效率和准确性

在快速发展的科技时代&#xff0c;我们的生活和工作方式正在被重新定义。这种变化在许多领域都有所体现&#xff0c;尤其是在汽车维修行业。近年来&#xff0c;AR&#xff08;增强现实&#xff09;技术的进步为这个行业带来了前所未有的可能性。通过将AR技术与远程协助系统相结…

Mac 文件设置默认展示和排列方式

点击 现在默认展示方式是分栏方式&#xff0c;因我我勾选了 点击这里就可以修改 始终以xx打开&#xff0c;这里我选择了图标视图。 有快捷键 commandJ 修改默认配置。

Qt/C++原创推流工具/支持多种流媒体服务/ZLMediaKit/srs/mediamtx等

一、前言 1.1 功能特点 支持各种本地视频文件和网络视频文件。支持各种网络视频流&#xff0c;网络摄像头&#xff0c;协议包括rtsp、rtmp、http。支持将本地摄像头设备推流&#xff0c;可指定分辨率和帧率等。支持将本地桌面推流&#xff0c;可指定屏幕区域和帧率等。自动启…

Spring中的设计模式

目录 工厂模式 组合模式 适配器模式 代理模式 单例模式 观察者模式 模板方法模式 责任链模式 Spring有着非常优雅的设计&#xff0c;很多地方都遵循SOLID原则&#xff0c;里面的设计模式更是数不胜数大概有以下几种&#xff1a; 工厂模式 所谓的工厂模式&#xff0c;核…