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. 基于JVM(内存)和Tomcat性能调优

    一.总结前一天的学习 从“第三天”的性能测试一节中,我们得知了决定性能测试的几个重要指标,它们是: ü   吞吐量 ü   Responsetime ü   Cpuload ü   MemoryUsa ...

  2. java多线程读取、操作List集合

    import java.util.ArrayList; import java.util.List; import org.apache.commons.lang3.ArrayUtils;   pub ...

  3. 【 PostgreSQL】后台周期执行函数实例(shell+crontab)

    工作中常见函数后台周期执行的情况,Oracle有job实现,gp数据库可以通过shell+crontab实现.流程如下: gpadmin用户下创建函数sh脚本. 将sh挂在crontab任务上 ### ...

  4. linux centos5.8装yum安装mysql

     默认的yum安装mysql都是5.1版本的 想要安装5.7的可以进行配置rpm包进行, mysql5.7安装路径 下面是默认的5.1安装路径 首先我们在使用yum安装的的时候会默认使用最新安装的,最 ...

  5. 去除Xcode6创建工程时自带的storyboard

    去除Xcode6创建工程时自带的storyboard 1. 删除storyboard文件,并在setting里面清空加载storyboard: 2. 导入ViewController到appDeleg ...

  6. 如何在 OS X 中安装 ruby

    如何在 OS X 中安装 ruby 软件包下载 链接: http://pan.baidu.com/s/1mgMil5I 密码: tiqg 安装 http://brew.sh/ 1. 先安装 brew( ...

  7. Java 系统学习梳理_【All】

    Java基础 1. Java学习---JDK的安装和配置 2. Java学习---Java代码编写规范 2. Java学习---HashMap和HashSet的内部工作机制 3. Java学习---J ...

  8. Windows Server 2008搭建域控制器

    前言 1.为什么要建域 工作组的分散管理模式不适合大型的网络环境下工作,域模式就是针对大型的网络管理需求设计的,就是共享用户账号,计算机账号和安全策略的计算机集合.域中集中存储用户账号的计算机就是域控 ...

  9. December 03rd 2016 Week 49th Saturday

    By failing to prepare, you are preparing to fail. 不做准备,那就准备失败吧. How does the case when you had prepa ...

  10. Git 如何上传文件夹

    Github开源代码库以及版本控制系统,可以托管各种git库,并提供web访问界面.很多朋友喜欢喜欢将个人Blog或小型项目托管到github,这样既方便又简单. 下面介绍如何将本地文件上传到gith ...