D3D11 IASetVertexBuffers 函数与顶点数据的两种组织方式

D3D11中的 IASetVertexBuffers 函数用来向GPU传递顶点数据。
一般情况下,我都是传入一个buff,也即在0号slot上绑定了一个buff,其他slot都没有绑定buff。
我传入的这个buff,是一个存储了顶点结构体数据的数组,每个顶点结构体中都有Position成员,Color成员,UV成员等等。
用术语来描述我这种做法,就是“交错的顶点数据”,英文称呼有这些 Interleaved Vertex Data , an array of structs 。

相对应的,另外一种做法就是“非交错的顶点数据”“分离的顶点数据”,英文称呼有这些 Non-Interleaved Vertex Data , De-Interleaved Vertex Data , separate Vertex Data , a struct of arrays 。

这种做法的具体方案是,把顶点的所有的Position成员填充到buff0中,把所有的Color成员填充到buff1中,把所有的UV成员填充到buff2中,等等。

当执行 IASetVertexBuffers 函数时,0号slot绑定buff0,1号slot绑定buff1,2号slot绑定buff2,等等。

需要注意的是,当为顶点数据创建 InputLayout 时,
如果是交错的顶点数据,示例如下:
  D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
  {
    {"POSITION",    0, DXGI_FORMAT_R32G32B32_FLOAT,        0, 0,                                                               D3D11_INPUT_PER_VERTEX_DATA, 0},
    {"COLOR",         0, DXGI_FORMAT_R32G32B32A32_FLOAT,  0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
    {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,               0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
  };
如果是分离的顶点数据,要为每个成员设置正确的slot序号,示例如下:
  D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
  {
    {"POSITION",     0, DXGI_FORMAT_R32G32B32_FLOAT,        0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
    {"COLOR",         0, DXGI_FORMAT_R32G32B32A32_FLOAT,   1, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
    {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,                2, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
  };

很多编程教材里面都是使用“交错的顶点数据”这种做法,我也长期使用这种做法。
最近上网查询了一下,很多人都提倡使用“分离的顶点数据”这种做法,优点如下:
1,一个模型有Position成员,Color成员,UV成员。在某些情况下可能只需要向GPU中传递一类成员或者两类成员,本做法能够节省带宽。
     例子1,绘制ShadowMap时,只需要传递Position成员。
     例子2,做插值的骨骼动画时,在slot0中传递上一帧的Position和Normal,在slot1中传递当前帧的Position和Normal,在slot2中传递其他的顶点数据成员。
2,一个模型有Position成员,Color成员,UV成员。其中某一类成员的值需要频繁的发生变化,本做法能够降低内存拷贝的大小。例如,Position成员在每帧都要发生变化,那么只需要更改它的buff。
3,模型1和模型2有相同的Color成员,那么模型1和模型2就可以共用一个Color buff。本做法能够节省内存。
4,在GPU渲染时,当GPU需要若干个Position成员时,只需要从Position buff中读取若干个Position成员,需要多少就读多少,没有浪费,本做法能够提升GPU的工作流水线的效率。如果是交错的顶点数据,GPU必须读取若干个顶点结构体,才能拿到若干个Position成员。

参考链接

https://developer.apple.com/library/archive/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/TechniquesforWorkingwithVertexData/TechniquesforWorkingwithVertexData.html
https://anteru.net/blog/2016/storing-vertex-data-to-interleave-or-not-to-interleave/
https://gamedev.stackexchange.com/questions/66545/vertex-buffers-interleaved-or-separate
https://stackoverflow.com/questions/19822102/non-interleaved-vertex-buffers-directx11

原文地址:https://www.cnblogs.com/oilcode/p/10451785.html

时间: 2024-10-28 23:25:58

D3D11 IASetVertexBuffers 函数与顶点数据的两种组织方式的相关文章

大数据的两种处理方式

大数据的处理方式有两种:基于内存的流式处理和基于硬盘的存储处理. 流式处理就好象是在经过的数据面前建一道水闸.数据流过这里,经过闸门的时候,就进行筛选过滤,分析出有价值的内容,然后丢弃,以后也不再使用. 存储处理则是建一个储水池.数据先放进入储水池存起来,需要的时候,再进到储水池里,在里面筛选分析,找到那些有价值的内容.这个过程中,因为水还在储水池里,没放掉,所以可以供下次继续使用. 存储模式的数据处理是可以重复的,用完再用,反复使用.但是因为硬盘本身的机械特性问题,导致它处理速度慢,速率不高.

oracle删除表数据的两种的方式

转自:https://blog.csdn.net/qq_37840993/article/details/82490787 平时写sql中我们都会用到删除语句,而平时删除表数据的时候我们经常会用到两种方式: 在oracle中,truncate.delete都可以删除表数据,具体的区别以及sql语法如下: truncate table [表名]; delete from [表名]; delete与truncate的区别:delete:会产生rollback,如果删除大数据量的表速度会很慢,而且同时

1.11-1.12 Sqoop导入数据时两种增量方式导入及direct

一.增量数据的导入 1.两种方式 ## query 有一个唯一标识符,通常这个表都有一个字段,类似于插入时间createtime where createtime => 20150924000000000 and createtime < 20150925000000000 ##sqoop参数 Incremental import arguments: --check-column <column> Source column to check for incremental ch

Spring mvc返回JSON数据的两种配置方式

1.视图解析方式 依赖包:jackson-core.jackson-databind.jackson-annotationSpring配置文件内容: <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"> <property name="defaultContentTy

python package 的两种组织方式

方式一/package1/ .../__init__.py # 空文件 .../class1.py class Class1: def __init__(self): self.name = "class one" def printInfo(self): print("i am class One!") .../class2.py class Class2: def __init__(self): self.name = "class two"

DataGridView显示数据的两种方法

1.简单介绍 DataGridView空间是我们常用的显示数据的控件,它有极高的可配置性和可扩展性. 2.显示数据 DataGridView显示数据一般我们常用的有两种方法,一种是直接设置DataSoure属性就可以绑定数据.此方法不需要写任何代码操作比较简单,但是它显示出来的是整张表的数据.如果整一表数据比较多,而且我们并不需要所有的数据的情况下,我们就应该考虑第二种方法了.通过写代码连接数据库并从数据库中读取数据,最后将返回的数据传给DataGridView.这种方法貌似比较复杂,但是它只显

C++:一般情况下,设计函数的形参只需要两种形式

C++:一般情况下,设计函数的形参只需要两种形式.一,是引用形参,例如 void function (int &p_para):二,是常量引用形参,例如 void function(const int &p_para). 它们的特点如下: # 引用形参适用于需要改变变量数据的情况,常量引用形参适用于不需要改变对象.变量数据的情况. # 引用形参需要对象.变量来传递值,常量引用形参则不需要,可以直接传递表达式或者函数返回值. 通过这两种方式可以涵盖所有可能需要的设计情况,而通过这种方式实现的

C语言中数据的两种属性及static的作用

C语言中数据有两种属性:数据类型和存储类别.数据类型定义了数据格式(长度),存储类别定义了数据的作用域和生命期. 1.变量的声明 1.1 变量的声明的一般形式:存储类别 数据类型 变量名;数据类型以int为例: 自动变量:auto int i;//自动变量是局部变量 局部变量:在函数内部定义的变量,局部变量缺省存储类别时就是自动变量 作用域:从定义开始到函数结束. 生命期:从函数调用开始到函数推出为止. 外部变量/全局变量:在函数外部定义而没有指出存储类别的变量 定义外部变量:extern in

关于Mysql删除表数据的两种方式对比

1.delete from table_name 一行一行删除,只删除表数据,auto_increament仍停留在最后一天数据的下一个值. 2.truncate table_name 快捷删除表数据.先删除整个表,然后重新建表结构.auto_increament从1开始. 关于Mysql删除表数据的两种方式对比,布布扣,bubuko.com