`
wjlgryx
  • 浏览: 306748 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

可编程数据流模式

阅读更多

本节讲述可用于可编程数据流模型的着色器。

数据流的使用

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 diffColorspecColor;

};

#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 );

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


顶点颜色着色器


本主题显示了初始化和使用一个用到了位置和漫反射色的简单顶点着色器的必须步骤。

第一步是声明用来保存位置和颜色的结构,如以下示例代码所示。

struct XYZBuffer

{

    FLOAT x, y, z;

};

 

struct ColBuffer

{

    D3DCOLOR color;

};

下一步是创建顶点着色器声明,如以下示例代码所示。

D3DVERTEXELEMENT9 decl[] =

{

    { 0, 0, D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },

    { 1, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,    0 },

    D3DDECL_END()

};

现在创建顶点声明对象:

LPDIRECT3DVERTEXDECLARATION9 m_pVertexDeclaration;
g_d3dDevice->CreateVertexDeclaration( decl, &m_pVertexDeclaration );

下一步是调用IDirect3DDevice9::CreateVertexShader方法创建顶点着色器。但首先,必须先对着色器进行汇编。

TCHAR               strVertexShaderPath[512];

LPD3DXBUFFER        pCode;

LPDIRECT3DVERTEXSHADER9    m_pVertexShader;

hr = DXUtil_FindMediaFileCbstrVertexShaderPath,

                      sizeof(strVertexShaderPath), _T("ShaderFile.vsh");

hr = D3DXAssembleShaderFromFile( strVertexShaderPath, NULL, NULL,

                      dwFlags, &pCode, NULL );

g_d3dDevice->CreateVertexShader( (DWORD*)pCode->GetBufferPointer(),

                      &m_pVertexShader );

以下示例代码显示了如何设置顶点着色器,设置数据流的源,然后渲染三角形表。

g_pd3dDevice->SetVertexDeclaration( m_pVertexDeclaration );

g_d3dDevice->SetVertexShader( m_pVertexShader );

g_d3dDevice->SetStreamSource( 0, xyzbufsizeof(XYZBuffer));

g_d3dDevice->SetStreamSource( 1, colbufsizeof(ColBuffer));

g_d3dDevice->SetIndices( pIB, 0 );

g_d3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, max - min + 1, 0, count / 3 );


单纹理着色器


本主题显示了初始化和使用一个用到了位置和一组纹理坐标的简单顶点着色器的必须步骤。

第一步是声明用来保存位置和纹理坐标的结构,如以下示例代码所示。

struct XYZBuffer

{

    float x, y, z;

};

 

struct TEX0Buffer

{

    float tutv;

};

下一步是创建顶点着色器声明,如以下示例代码所示。

D3DVERTEXELEMENT9 decl[] =

{

    { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },

    { 1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },

    D3DDECL_END()

};

下一步是调用IDirect3DDevice9::CreateVertexShader方法创建顶点着色器。但首先,必须先对着色器进行汇编。

TCHAR               strVertexShaderPath[512];

LPD3DXBUFFER        pCode;

LPDIRECT3DVERTEXSHADER9  m_pVertexShader;

hr = m_pd3dDevice->CreateVertexDeclarationdecl, &m_pVertexDeclaration );

hr = DXUtil_FindMediaFileCbstrVertexShaderPath,

                sizeof(strVertexShaderPath), _T("ShaderFile.vsh");

hr = D3DXAssembleShaderFromFile( strVertexShaderPath, NULL, NULL,

                      dwFlags, &pCode, NULL );

g_d3dDevice->CreateVertexShader( (DWORD*)pCode->GetBufferPointer(),

                                   &m_pVertexShader );

在创建完顶点缓存和顶点着色器后,就可以使用了。以下示例代码显示了如何设置顶点着色器,设置数据流的源,然后用新的顶点着色器绘制三角形表。

g_d3dDevice->SetVertexShader( m_pVertexShader );

g_d3dDevice->SetStreamSource( 0, xyzbuf, 0, sizeof(XYZBuffer));

g_d3dDevice->SetStreamSource( 1, tex0buf, 0, sizeof(TEX0Buffer));

g_d3dDevice->SetIndices( pIB, 0 );

g_d3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, max - min + 1, 0, count / 3 );


多重纹理纹理着色器


本主题显示了初始化和使用一个用到了位置和用于多重纹理的多组纹理坐标的简单顶点着色器的必须步骤。

第一步是声明用来保存位置和纹理坐标的结构,如以下示例代码所示。

struct XYZBuffer
{
    float x, y, z;
};
 
struct Tex0Buffer
{
    float tu, tv;
};
 
struct Tex1Buffer
{
    float tu2, tv2;
};

下一步是创建顶点着色器声明,如以下示例代码所示。

D3DVERTEXELEMENT9 decl[] = 
{
    { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
    { 1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
    { 2, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 },
    D3DDECL_END()
};

现在创建顶点声明对象:

LPDIRECT3DVERTEXDECLARATION9 m_pVertexDeclaration;
g_d3dDevice->CreateVertexDeclaration( decl, &m_pVertexDeclaration );

下一步是调用IDirect3DDevice9::CreateVertexShader方法创建顶点着色器。但首先,必须先对着色器进行汇编。

TCHAR               strVertexShaderPath[512];
LPD3DXBUFFER        pCode;
LPDIRECT3DVERTEXSHADER9  m_pVertexShader;
 
hr = DXUtil_FindMediaFileCb( strVertexShaderPath, 
                sizeof(strVertexShaderPath), _T("ShaderFile.vsh");
 
hr = D3DXAssembleShaderFromFile( strVertexShaderPath, NULL, NULL, 
                      

  


  
分享到:
评论

相关推荐

    Scala和Spark大数据分析函数式编程、数据流和机器学习

    对于数据流处理,Spark Streaming构建在微批处理概念之上,它可以接收实时数据流并进行处理。通过DStream(Discretized Stream)抽象,开发者可以将实时数据流视为一系列离散的批处理作业,从而利用Spark的并行处理...

    数据流计算机基本工作原理

    数据流计算机通常与函数式编程语言紧密关联,如Lapse语言,它是一种单赋值的编程语言,其语法类似Pascal,支持数组运算的完整描述。通过使用这样的高级数据流语言,程序员能够更好地利用数据流计算机的并行执行能力...

    响应式编程与设计模式.pdf

    这种编程范式特别适合处理在时间上不可预测的数据流,例如,由外部事件引起的异步数据流。 响应式宣言(Reactive Manifesto)为响应式系统定义了四个关键属性:响应性、弹性、弹性、消息驱动。响应性指系统能够及时...

    一种面向分布式数据流的闭频繁模式挖掘方法.pdf

    《一种面向分布式数据流的闭频繁模式挖掘方法》这篇论文关注的是在智能交通系统中针对分布式数据流的频繁模式挖掘问题。智能交通系统中的传感器网络数据流具有特定的特点,例如实时性、高并发性和动态性,这使得传统...

    可重构数据流SPJ查询处理器的研究.pdf

    本文研究的可重构数据流SPJ查询处理器利用了现场可编程门阵列(FPGA)技术。FPGA是一种硬件可编程芯片,可以按照需要配置成各种逻辑电路,具有高度并行处理能力,适用于高性能和低延迟的数据处理任务。当查询需求...

    Delphi模式编程第一分卷

    4.3.1 利用工厂方法模式设计可动态切换持久层机制的应用 4.3.2 范例小结 第5章 抽象工厂模式(Abstract Factory) 5.1 模式解说 5.2 结构和用法 5.2.1 模式结构 5.2.2 代码模板 5.3 范例与实践 5.3.1 用抽象...

    Delphi模式编程第二分卷

    4.3.1 利用工厂方法模式设计可动态切换持久层机制的应用 4.3.2 范例小结 第5章 抽象工厂模式(Abstract Factory) 5.1 模式解说 5.2 结构和用法 5.2.1 模式结构 5.2.2 代码模板 5.3 范例与实践 ...

    Java并发编程设计原则和模式

    本资料“Java并发编程设计原则和模式”深入探讨了如何在Java环境中有效地进行并发处理,以充分利用系统资源并避免潜在的并发问题。 一、并发编程基础 并发是指两个或多个操作在同一时间段内执行,但并不意味着这些...

    Java_挖掘数据流的算法集合.zip

    在数据流环境中,数据通常是不可预测的,并且可能以高速率到来,因此,算法需要能够高效地处理这些特性。 1. **流数据模型**:在数据流挖掘中,数据模型通常假设数据是无界的,即数据流会无限持续下去。此外,数据...

    PILZ可编程控制器手册

    此外,手册还详细解释了外围访问(Periphery access)、系统数据块(System data block)、数据块(Data block)、数据字(Data word)等概念,这些是理解和操作控制器内部数据流的关键。 ### 常量与变量 在PILZ...

    基于omnet的卫星数据流仿真

    其支持视图和文本两种运行模式,视图模式以动画形式展示模块间消息传递,而文本模式则适用于长时间大规模的数据流仿真,确保程序高效运行。 #### 3. 卫星数据流建模与仿真 卫星数据流结构涵盖星上系统与地面系统两...

    matlab开发-在Matlab中编程模式

    在Matlab中编程模式是软件开发过程中的一个重要环节,它涉及到如何高效、规范地编写代码,以实现功能的同时保持代码的可读性、可维护性和可扩展性。本主题主要探讨的是在Matlab环境中如何应用各种编程模式来优化代码...

    我的流媒体编程

    与传统的下载-播放模式不同,流媒体允许用户在数据传输过程中即可开始观看或收听,提高了内容的即时性和互动性。 2. **编码与压缩**:为了在网络上传输多媒体数据,通常需要对其进行编码和压缩。常见的视频编码标准...

    TensorFlow编程指南 graph session

    4. **可移植性**:数据流图作为计算任务的一种表示形式,不受特定编程语言的限制,这使得用不同语言编写的程序可以共享同一个计算流程。 #### 三、tf.Graph详解 在TensorFlow中,`tf.Graph`是用于表示数据流图的...

    编程语言实现模式(Language Implementation Patterns)

    1. **模式1:TokenStream** - 介绍如何创建一个字符流到词法单元流的转换过程,这是解析过程的第一步。 2. **模式2:Parser Tree** - 讲述了如何构建语法树以表示输入文本的结构。 3. **模式3:Abstract Syntax Tree...

    unidirektional,用协程展示kotlin中的无向非构造数据流.zip

    在Kotlin编程中,"无向非构造数据流"(Unidirectional Data Flow)是一种设计模式,它强调了数据在应用程序中的单向流动,避免了常见的双向绑定带来的复杂性和潜在问题。这种模式常用于响应式编程和函数式编程场景,...

    Python读取实时数据流示例

    实时数据流是当今大数据处理中不可或缺的一环,它允许系统持续不断地接收和处理数据,从而实现对动态变化信息的实时监控和分析。本篇内容将围绕Python读取实时数据流的示例进行详细介绍,包括数据处理、队列操作、...

Global site tag (gtag.js) - Google Analytics