fvf采用另外一种方式渲染
if (FAILED(hr = getActiveD3D9Device()->SetVertexDeclaration(d3ddecl->getD3DVertexDeclaration(getGlobalInstanceVertexBufferVertexDeclaration(), useGlobalInstancingVertexBufferIsAvailable))))
HLSL初级教程2
2.顶点着色器
DirectX 8.0引入了数据流的概念,可以这样理解数据流(图2.2):
程序中使用IDirect3DDevice9::SetStreamSource方法把一个顶点缓存绑定到一个设备数据流。
该小节对顶点声明的描述绝大多数都取自翁云兵的《着色器和效果》,该文对顶点声明的描述是我所见到最详尽最透彻的,这里向作者表示敬意:)
注意:我们仍然可以在可编程管线中使用FVF——如果我们的顶点格式可以这样描述。不管怎样,这只是为了方便,因为FVF会在内部被转换为一个顶点声明。
typedef struct _D3DVERTEXELEMENT9 {
² Offset——偏移,按字节,相对于顶点结构成员的顶点分量的开始。例如,如果顶点结构是:
……pos分量的偏移是0,因为它是第一个分量;normal分量的偏移是12,因为sizeof(pos) == 12。换句话说,normal分量以Vertex的第12个字节为开始。
² Type——指定数据类型。它可以是D3DDECLTYPE枚举类型的任意成员;完整列表请参见文档。常用类型如下:
D3DDECLTYPE_D3DCOLOR—D3DCOLOR类型,它扩展为RGBA浮点颜色向量(r, g, b, a),其每一分量都是归一化到区间[0, 1]了的。
² Method——指定网格化方法。我们认为这个参数是高级的,因此我们使用默认值,标识为D3DDECLMETHOD_DEFAULT。
² Usage——指定已计划的对顶点分量的使用。例如,它是否准备用于一个位置向量、法线向量、纹理坐标等,有效的用途标识符(usage identifier)是D3DDECLUSAGE枚举类型的:
D3DDECLUSAGE_POSITION = 0, // Position.
D3DDECLUSAGE_BLENDWEIGHTS = 1, // Blending weights.
D3DDECLUSAGE_BLENDINDICES = 2, // Blending indices.
D3DDECLUSAGE_NORMAL = 3, // Normal vector.
D3DDECLUSAGE_PSIZE = 4, // Vertex point size.
D3DDECLUSAGE_TEXCOORD = 5, // Texture coordinates.
D3DDECLUSAGE_TANGENT = 6, // Tangent vector.
D3DDECLUSAGE_BINORMAL = 7, // Binormal vector.
D3DDECLUSAGE_TESSFACTOR = 8, // Tessellation factor.
D3DDECLUSAGE_POSITIONT = 9, // Transformed position.
D3DDECLUSAGE_COLOR = 10, // Color.
D3DDECLUSAGE_FOG = 11, // Fog blend value.
D3DDECLUSAGE_DEPTH = 12, // Depth value.
D3DDECLUSAGE_SAMPLE = 13 // Sampler data.
例:假设我们想要描述的顶点格式由两个数据流组成,第一个数据流包含位置、法线、纹理坐标3个分量,第二个数据流包含位置和纹理坐标2个分量,顶点声明可以指定如下:
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,D3DDECLUSAGE_
{ 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_
{ 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_
{ 1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_
{ 1, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_
D3DDECL_END宏用于初始化D3DVERTEXELEMENT9数组的最后一个顶点元素。
IDirect3DVertexDeclaration9 *g_Decl = NULL;
g_pd3dDevice->CreateVertexDeclaration(decl ,&g_Decl);
g_pd3dDevice->SetVertexDeclaration(g_Decl);
至此,可编程数据流模型、顶点声明介绍完毕,在下面的例子中读者将会有更连贯的理解。
Morphing渐变是20世纪90年代出现的一种革命性的计算机图形技术,该技术使得动画序列平滑且易于处理,即使在低档配置的计算机系统上也能正常运行。
图2.3
我们在程序中使用两个网格模型——源网格模型和目标网格模型,设源网格模型中顶点1的坐标为A(Ax,Ay,Az),目标网格模型中对应顶点1的坐标为B(Bx,By,Bz),要计算渐变过程中时间点t所对应的顶点1的坐标C(Cx,Cy,Cz),我们使用如下方法:
T为源网格模型到目标网格模型渐变所花费的全部时间,得到时间点t占整个过程T的比例为:
S = t / T
那么顶点1在t时刻对应的坐标C为:
C = A * (1-S)+ B * S
这样,在渲染过程中我们根据时间不断调整S的值,就得到了从源网格模型(形状一)到目标网格模型(形状二)的平滑过渡。
接下来将在程序里使用顶点着色器实现我们的渐变动画。
程序中,我们设定一个顶点对应两个数据流,这两个数据流分别包含了源网格模型的数据和目标网格模型的数据。渲染过程中,我们在着色器里根据两个数据流中的顶点数据以及时间值确定最终的顶点信息。
注意目标网格模型数据流没有包含纹理坐标,因为纹理对于两个网格模型都是一样的,所以仅使用源网格模型的纹理就可以了。
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,D3DDECLUSAGE_
{ 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_
{ 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_
{ 1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_
{ 1, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_
//世界矩阵、观察矩阵、投影矩阵的合矩阵,用于顶点的坐标变换
//存储2.3.1小节提到的公式S = t / T中的时间标尺S值
//注意到Scalar是一个vector类型,我们在Scalar.x中存储了S值,Scalar.y中存储的则是(1-S)值
VS_OUTPUT Main(VS_INPUT input)
VS_OUTPUT output = (VS_OUTPUT)0;
//顶点最终位置output.position取决于源网格模型数据流中位置信息input.position和目标网格模型数据流中位置信息input.position1以及时间标尺Scalar的值
//对应2.3.1小节中的公式C = A * (1-S)+ B * S
output.position = input.position*Scalar.x + input.position1*Scalar.y;
output.position = mul(output.position, WVPMatrix);
vector normal = input.normal*Scalar.x + input.normal1*Scalar.y;
output.diffuse = dot((-LightDirection), normal);
output.uvCoords = input.uvCoords;
以上是本例用到的顶点着色器,在接下来的应用程序中,我们将给三个着色器全局变量赋值:
存储2.3.1小节提到的公式S = t / T中的时间标尺S值;
注意到Scalar是一个vector类型,我们在Scalar.x中存储了S值,Scalar.y中存储的则是(1-S)值;
/*********************声明变量*****************/
//两个指向LPD3DXMESH的指针,分别用于存储源网格模型和目标网格模型;
IDirect3DVertexDeclaration9 *g_Decl = NULL;
IDirect3DVertexShader9 *g_VS = NULL;
ID3DXConstantTable* ConstTable = NULL;
D3DXHANDLE WVPMatrixHandle = 0;
D3DXHANDLE LightDirHandle = 0;
/***************程序初始化*****************/
D3DVERTEXELEMENT9 MorphMeshDecl[] =
//1st stream is for source mesh - position, normal, texcoord
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },
{ 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
//2nd stream is for target mesh - position, normal
{ 1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 1 },
{ 1, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 1 },
ID3DXBuffer* errorBuffer = NULL;
D3DXCompileShaderFromFile("vs.txt",
"Main", // entry point function name
::MessageBox(0, (char*)errorBuffer->GetBufferPointer(), 0, 0);
g_pd3dDevice->CreateVertexShader((DWORD*)shader->GetBufferPointer(), &g_VS);
g_pd3dDevice->CreateVertexDeclaration(MorphMeshDecl ,&g_Decl);
WVPMatrixHandle = ConstTable->GetConstantByName(0, "WVPMatrix");
ScalarHandle = ConstTable->GetConstantByName(0, "Scalar");
LightDirHandle = ConstTable->GetConstantByName(0, "LightDirection");
ConstTable->SetVector(g_pd3dDevice, LightDirHandle, &D3DXVECTOR4(0.0f, -1.0f, 0.0f, 0.0f));
ConstTable->SetDefaults(g_pd3dDevice);
/*******************渲染*******************/
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(153,153,153), 1.0f, 0 );
D3DXMATRIX matWorld, matView, matProj;
g_pd3dDevice->GetTransform(D3DTS_WORLD, &matWorld);
g_pd3dDevice->GetTransform(D3DTS_VIEW, &matView);
g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &matProj);
matWVP = matWorld * matView * matProj;
ConstTable->SetMatrix(g_pd3dDevice, WVPMatrixHandle, &matWVP);
//为着色器全局变量Scalar赋值,注意程序中获取时间标尺值Scalar的方法
float DolphinTimeFactor = (float)(timeGetTime() % 501) / 250.0f;
(DolphinTimeFactor<=1.0f)?DolphinTimeFactor:(2.0f-DolphinTimeFactor);
ConstTable->SetVector(g_pd3dDevice,ScalarHandle,&D3DXVECTOR4(1.0f-Scalar, Scalar, 0.0f, 0.0f));
g_pd3dDevice->SetVertexShader(g_VS);
g_pd3dDevice->SetVertexDeclaration(g_Decl);
IDirect3DVertexBuffer9 *pVB = NULL;
g_TargetMesh->GetVertexBuffer(&pVB);
g_pd3dDevice->SetStreamSource(1, pVB, 0,
D3DXGetFVFVertexSize(g_TargetMesh->GetFVF()));
g_SourceMesh->GetVertexBuffer(&pVB);
g_pd3dDevice->SetStreamSource(0, pVB, 0,
D3DXGetFVFVertexSize(g_TargetMesh->GetFVF()));
DrawMesh(g_SourceMesh, g_pMeshTextures0, g_VS, g_Decl);
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
使用DrawIndexedPrimitive绘制Mesh模型的步骤如下:
1. 加载网格模型后使用OptimizeInPlace方法对Mesh进行优化;
2. 一旦优化了网格模型,你就可以查询ID3DXMesh对象,得到一个D3DXATTRIBUTERANGE数据类型的数组,我们称之为属性列表,该数据类型被定义如下:
typedef struct_D3DXATTRIBUTERANGE{
DWORD FaceStart; //这两个变量用于圈定本子集中的多边形
DWORD VertexStart; //这两个变量用于圈定本子集中的顶点
我们属性列表中的每一项都代表一个被优化后Mesh的一个子集,D3DXATTRIBUTERANGE结构的各字段描述了该子集的信息。
1. 得到属性数据后,我们就调用DrawIndexedPrimitive方法可以精美地渲染子集了。
在Load_Meshes()函数的最后,我们使用OptimizeInPlace方法对源网格模型和目标网格模型进行优化,其他加载材质和纹理的操作和之前一样,相信大家能够理解:
g_SourceMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL);
g_TargetMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL);
在Draw_Mesh()函数中,渲染模型,注意程序是如何配合属性表调用DrawIndexedPrimitive方法进行绘制的:
IDirect3DVertexBuffer9 *pVB = NULL;
IDirect3DIndexBuffer9 *pIB = NULL;
D3DXATTRIBUTERANGE *pAttributes = NULL;
pMesh->GetAttributeTable(NULL, &NumAttributes);
pAttributes = new D3DXATTRIBUTERANGE[NumAttributes];
pMesh->GetAttributeTable(pAttributes, &NumAttributes);
g_pd3dDevice->SetVertexShader(pShader);
g_pd3dDevice->SetVertexDeclaration(pDecl);
g_pd3dDevice->SetStreamSource(0, pVB, 0, D3DXGetFVFVertexSize(pMesh->GetFVF()));
g_pd3dDevice->SetIndices(pIB);
//遍历属性列表并配合其中的信息调用DrawIndexPrimitive绘制各个子集
for(DWORD i=0;i<NumAttributes;i++)
DWORD MatNum = pAttributes[i].AttribId;
g_pd3dDevice->SetTexture(0, pTextures[MatNum]);
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0,
编译运行程序,效果如图2.4所示,你将看到屏幕上白色的海豚上下翻腾,同时感受到顶点着色器为渲染效果所带来的巨大改善。
posted on 2008-08-04 12:30 狂烂球 阅读(491) 评论(0) 编辑 收藏 引用
fvf采用另外一种方式渲染相关推荐
- .NET下,你采用的哪种方式来操作数据库
.NET下,你采用的哪种方式来操作数据库 说了6类方式,这6类的分类,不太恰当,是顺手写的,但还是希望大家能帮忙看看,指正一些谬误之处. 这几类方式中,哪一种或如何结合才能更高效率地编写代码呢?思考中 ...
- c .net ajax,Asp.net mvc 2中使用Ajax的三种方式
在Asp.net MVC中,我们能非常方便的使用Ajax.这篇文章将介绍三种Ajax使用的方式,分别为原始的Ajax调用.Jquery.Ajax Helper.分别采用这三种方式结合asp.net m ...
- 在一个JSP页面中包含另一个JSP页面的三种方式
转载自://http://blog.163.com/neu_lxb/blog/static/179417010201121343132918/ (1)include指令 include指令告诉容器:复 ...
- C#实现的三种方式实现模拟键盘按键
1.System.Windows.Forms.SendKeys 组合键:Ctrl = ^ .Shift = + .Alt = % 模拟按键:A private void button1_Click( ...
- Java中遍历HashMap的5种方式
From: https://blog.csdn.net/w605283073/article/details/80708943 本教程将为你展示Java中HashMap的几种典型遍历方式. 如果你使用 ...
- JavaScript定义类的几种方式
1.工厂方式 javaScript中创建自己的类和对象,我们应该是必须掌握的,我们都知道javaScript中对象的属性可以在对象创建后动态定义,比如下面的代码: <script type=&q ...
- SpringBoot - 配置 Filter 的几种方式
前言 在 SpringMVC - 对于如何配置 Filter 的深度剖析 这篇文章中,我们知道了在 SpringMVC 环境中如何配置 Filter,接下来我们看一下如何在 SpringBoot 中配 ...
- JavaScript中定义对象的几种方式
JavaScript中没有类的概念,只有对象. 在JavaScript中定义对象可以采用以下5种方式(附加改进方式): 1.基于已有对象扩充其属性和方法 2.工厂方式 3.构造函数方式 4.原型(&q ...
- MES系统读取MySQL数据_MES系统数据采集的四种方式
MES系统数据采集的四种方式 MES系统的最大特点,就是能实时收集生产过程中的各类信息.数据,然后汇集到数据库中,作数据分析及供管理层查询.如何高效的采集车间的各类数据,是决定一个MES系统软件项目实 ...
- C# 三种方式实现模拟键盘按键
模拟按键在.Net中有三种方式实现. 第一种方式:System.Windows.Forms.SendKeys 组合键:Ctrl = ^ .Shift = + .Alt = % 模拟按键:A priva ...
最新文章
- 中国自动化学会平行智能专业委员会成立
- Oracle hang 之sqlplus -prelim使用方法
- [POJ 1330] Nearest Common Ancestors (倍增法)
- 【二分法】- leetcode
- vs ajax工具包引用,vs2008中使用AJAX Control Tookit工具的问题?
- C++11统一初始化形式,使用{}
- 工单发料,退料等一些物料的移动
- 软件测试项目案例.pdf,最经典软件测试案例.pdf
- 等比数列求和公式的推导
- Laravel 数据库 - 数据填充
- FDTD Solutions时域有限差分法仿真学习相关操作(一)——GDS导出
- 深度学习读书笔记:DeepLearningBook - Chapter 9 - Conventional Networks
- C# 图片位深度转至8位灰度图像,8位灰度图像转为1位灰度图像
- 程序人生:扒一扒程序员为什么总在加班?拿生命敲代码?
- GDP大跳水,“溢价阶层,春招我借这份PDF的复习思路
- 操作系统实验:存储管理(C++)
- python人机交互_人机交互程序 python实现人机对话
- ctfshow-命令执行-web38
- 机器人 大战 android,机器人未来大战
- 神策数据微信小程序 SDK 功能介绍 | 数据采集