Microsoft? DirectX? 8.0引入了数据流的概念,用来把数据绑定到着色器使用的输入寄存器。一个数据流是一个成员数据的数组,每个成员由一个或多个元素构成,这些元素代表单个实体,如位置、法向、颜色等等。数据流使图形芯片能并行地从多个顶点缓存执行直接内存访问(DMA)操作,同时也降低了多重纹理的开销。可以这样理解数据流:

一个顶点由n个数据流组成。  
一个数据流由m个元素组成。  
一个元素是[位置、颜色、法向、纹理坐标]。

IDirect3DDevice9::SetStreamSource方法把一个顶点缓存绑定到一个设备数据流,这样就在顶点数据和一个顶点数据流端口之间建立了联系,有多个数据流端口用来给图元处理函数输入数据。对数据流中的数据的真正引用只有在调用诸如IDirect3DDevice9::DrawPrimitive之类的绘制方法时才发生,从输入顶点元素到可编程顶点着色器使用的顶点输入寄存器的映射是在着色器声明中定义的,但是输入顶点元素并没有专门的语义来描述它们的使用。对输入顶点元素的解释通过着色器指令进行编程。顶点着色器函数由一个指令数组定义,这些指令会应用于每个顶点。顶点输出寄存器用着色器函数中的指令显式地写入。

本节的讨论较少关注从元素到寄存器的语义映射,而更侧重于“为什么要使用数据流?”和“数据流可以解决什么问题?”这些问题。数据流的最大好处是消除了原来和多重纹理有关的顶点数据的开销。在引入数据流之前,为了处理单纹理和多重纹理的情况,用户要么复制两份顶点数据,每份顶点数据中都没有用不到的数据;要么在一份顶点数据中包含所有的数据元素,但其中一部分数据除了多重纹理的情况以外不会被用到。

这里是一个使用两份顶点数据的示例,一份用于单纹理,另一份用于多重纹理。

struct CUSTOMVERTEX_TEX1 

    FLOAT x, y, z;      // 未经变换的顶点位置 
    DWORD diffColor;    // 顶点的漫反射色 
    DWORD specColor;    // 顶点的镜面反射色 
    float tu_1, tv_1;   // 单纹理的纹理坐标 
};

struct CUSTOMVERTEX_TEX2 

    FLOAT x, y, z;      // 未经变换的顶点位置 
    DWORD diffColor;    // 顶点的漫反射色 
    DWORD specColor;    // 顶点的镜面反射色 
    float tu_2, tv_2;   // 多重纹理的纹理坐标 
};

另一种方法是在一个顶点元素中包含全部两组纹理坐标。

struct CUSTOMVERTEX_TEX2 

    FLOAT x, y, z;      // 未经变换的顶点位置 
    DWORD diffColor;    // 顶点的漫反射色 
    DWORD specColor;    // 顶点的镜面反射色 
    float tu_1, tv_1;   // 单纹理的纹理坐标 
    float tu_2, tv_2;   // 多重纹理的纹理坐标 
};

如果使用这份顶点数据,那么只要在内存中保存一份顶点和颜色数据,代价是在渲染过程中保存了全部两组纹理坐标,甚至在单纹理的情况下也是如此。

现在这其中的权衡已经很清楚了,数据流为这种左右为难的情况提供了一种极好的解决方案。这里提供了一套顶点定义,用来支持三个数据流:一个数据流包含位置和颜色,一个数据流包含第一组纹理坐标,另一个数据流包含第二组纹理坐标。

// 多数据流顶点 
// 数据流0, 位置, 漫反射色, 镜面反射色 
struct POSCOLORVERTEX 

    FLOAT x, y, z; 
    DWORD diffColor, specColor; 
};

#define D3DFVF_POSCOLORVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_SPECULAR)

// 数据流1, 纹理坐标组0 
struct TEXC0VERTEX 

    FLOAT tu1, tv1; 
};

#define D3DFVF_TEXC0VERTEX (D3DFVF_TEX1)

// 数据流2, 纹理坐标组1 
struct TEXC1VERTEX 

    FLOAT tu2, tv2; 
};

#define D3DFVF_TEXC1VERTEX (D3DFVF_TEX0)

顶点定义为:

// 多重纹理 – 多重数据流 
D3DVERTEXELEMENT9 dwDecl3[] =  

   { 0, 0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, 
   { 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,  0 }, 
   { 0, 28, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,  1 }, 
   { 1, 0, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, 
   { 2, 0, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, 
   D3DDECL_END() 
};

现在创建顶点声明对象,如下所示:

LPDIRECT3DVERTEXDECLARATION9 m_pVertexDeclaration; 
g_d3dDevice->CreateVertexDeclaration( dwDecl3, m_pVertexDeclaration );

组合的示例 
一个数据流,只使用漫反射色 
只用漫反射色渲染的顶点声明和数据流设置看起来会如下所示:

D3DVERTEXELEMENT9 dwDecl3[] =  

   { 0, 0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, 
   { 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,  0 }, 
   { 0, 28, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,  1 },

D3DDECL_END() 
};

m_pd3dDevice->SetStreamSource( 0, m_pVBVertexShader0, 0, sizeof(CUSTOMVERTEX) ); 
m_pd3dDevice->SetStreamSource( 1, NULL, 0, 0); 
m_pd3dDevice->SetStreamSource( 2, NULL, 0, 0);

两个数据流,使用颜色和纹理

使用单纹理进行渲染的顶点声明和数据流设置看起来会如下所示:

D3DVERTEXELEMENT9 dwDecl3[] =  

   { 0, 0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, 
   { 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,  0 }, 
   { 0, 28, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,  1 }, 
   { 1, 0, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, 
  D3DDECL_END() 
};

m_pd3dDevice->SetStreamSource( 0, m_pVBPosColor, 0, sizeof(POSCOLORVERTEX) ); 
m_pd3dDevice->SetStreamSource( 1, m_pVBTexC0, 0, sizeof(TEXC0VERTEX) ); 
m_pd3dDevice->SetStreamSource( 2, NULL, 0, 0);

三个数据流,使用颜色和两张纹理

使用两张纹理进行多重纹理渲染的顶点声明和数据流设置看起来会如下所示。

D3DVERTEXELEMENT9 dwDecl3[] =  

   { 0, 0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, 
   { 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,  0 }, 
   { 0, 28, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,  1 }, 
   { 1, 0, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, 
   { 2, 0, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, 
   D3DDECL_END() 
};

m_pd3dDevice->SetStreamSource( 0, m_pVBPosColor, 0, sizeof(POSCOLORVERTEX) ); 
m_pd3dDevice->SetStreamSource( 1, m_pVBTexC0, 0, sizeof(TEXC0VERTEX) ); 
m_pd3dDevice->SetStreamSource( 2, m_pVBTexC1, 0, sizeof(TEXC1VERTEX) );

以上所有三种情况,都可以调用以下IDirect3DDevice9::DrawPrimitive。
m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, NUM_TRIS );

这个例子显示了数据流在解决重复的数据/冗余数据在总线上的传输(也就是说,带宽的浪费)问题上的灵活性。

Direct3D中 SetStreamSource 函数与数据流的更多相关文章

  1. Direct3D中 SetTextureStageState 函数

    先说明几个概念: 1, Multipass(多通道)     将一个任务划分成几个阶段,由多个pass处理不同阶段,后续pass总是处理前一个pass的结果.例如复杂的光照方程可以分成几个pass来计 ...

  2. 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记5——Direct3D中的顶点缓存和索引缓存

    第12章 Direct3D绘制基础 1. 顶点缓存 计算机所描绘的3D图形是通过多边形网格来构成的,网网格勾勒出轮廓,然后在网格轮廓的表面上贴上相应的图片,这样就构成了一个3D模型.三角形网格是构建物 ...

  3. 《APUE》中的函数整理

    第1章 unix基础知识 1. char *strerror(int errnum) 该函数将errnum(就是errno值)映射为一个出错信息字符串,返回该字符串指针.声明在string.h文件中. ...

  4. 转载SSIS中的容器和数据流—数据转换(Transformations)

    对数据流来说按照需求将数据转换成需要的格式是数据操作中的一个关键的步骤.例如想要得到聚合排序后的运算结果,转换可以实现这种操作.和SQL Server 2000 DTS完全不同,这些操作不需要编写sc ...

  5. OpenGL中glRotatef()函数究竟对矩阵做了什么

    OpenGL中glRotatef()函数究竟对矩阵做了什么 我们知道OpenGL中维持着两套矩阵,一个是模型视图矩阵(model view matrix),另一个是投影矩阵(projection ma ...

  6. NET MVC全局异常处理(一) 【转载】网站遭遇DDoS攻击怎么办 使用 HttpRequester 更方便的发起 HTTP 请求 C#文件流。 Url的Base64编码以及解码 C#计算字符串长度,汉字算两个字符 2019周笔记(2.18-2.23) Mysql语句中当前时间不能直接使用C#中的Date.Now传输 Mysql中Count函数的正确使用

    NET MVC全局异常处理(一)   目录 .NET MVC全局异常处理 IIS配置 静态错误页配置 .NET错误页配置 程序设置 全局异常配置 .NET MVC全局异常处理 一直知道有.NET有相关 ...

  7. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第七章:在Direct3D中绘制(二)

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第七章:在Direct3D中绘制(二) 代码工程地址: https:/ ...

  8. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第六章:在Direct3D中绘制

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第六章:在Direct3D中绘制 代码工程地址: https://gi ...

  9. rxjs入门3之项目中ajax函数封装

    项目中ajax函数封装 ⽹页应⽤主要数据源有两个:⼀个是⽹页中的DOM事件,另⼀个就是通过AJAX获得的服务器资源.我们已经知道fromEvent这个操作符可以根据DOM事件产⽣Observable对 ...

随机推荐

  1. Btree并发内存回收

    在并发写Btree原理剖析 一文中提到,节点内存回收有可能导致内存突增以及影响写性能.本文将阐述最近对内存回收的改进,多线程可并行回收内存. 回收策略 采用基于版本的机制,Btree全局维护一个版本号 ...

  2. js滚轮事件

    首先,不同的浏览器有不同的滚轮事件.主要是有两种,onmousewheel(firefox不支持)和DOMMouseScroll(只有firefox支持).w3c文档已经废弃了onmousewheel ...

  3. Oracle EBS 更改物料说明后,在MTL_SYSTEM_ITEMS_B表中无变化

    需要再中文和英文环境同时修改: 程序里,可以通过初始session语言环境来解决.

  4. 原生java调用webservice的方法,不用生成客户端代码

    原生java调用webservice的方法,不用生成客户端代码 2015年10月29日 16:46:59 阅读数:1455 <span style="font-family: Aria ...

  5. C# DataGridview用NPOI导出Excel文件

    导出excel我用的是nuget 的NPOI,直接在项目中添加的,引用到项目中,下面是截图: 下面我把ExcelHelper贴出来 public static class ExcelHelper { ...

  6. SQL server数据库压缩空间

    SQL server数据库,在手动删除或者自动删除数据后,查看数据库物理文件发现占用空间并没有释放,果断采用万能的重启.(反正是自己用的一个服务器,随便玩.如果不是只有自己用的服务器,还是建议让运维或 ...

  7. 使用截图工具FastStone Capture

    使用截图工具FastStone Capture -谨以此教程献给某位上进的测试人员- FastStone Capture是本人用过的windows平台上最好用的截图工具,界面简洁,功能强大,还支持屏幕 ...

  8. 获取图片的metaData

    获取图片的metaData 获取简易的metaData较为容易,以下是测试图: 以下是本人提供的源码: UIImage+MetaData.h // // UIImage+MetaData.h // P ...

  9. [翻译] USING GIT IN XCODE [5] 在XCODE中使用GIT[5]

    USING GIT IN XCODE USING BRANCHES Branches can be a very effective tool to isolate new features or e ...

  10. 解决 锁定文件失败 打不开磁盘“D:\ubuntu\Ubuntu 64 位.vmdk”或它所依赖的某个快照磁盘。 模块 Disk”启动失败

    一次在使用虚拟机的过程中,电脑出问题强制关机后,重新打开虚拟机,出现了“文件锁定失败”,打不开虚拟机的情况. 上网百度查相关的解决方案,终于解决了问题.因为虚拟机运行的时候会创建相应的文件,即在虚拟机 ...