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

2.3用顶点着色器实现渐变动画

阅读更多

2.3用顶点着色器实现渐变动画

2.3.1渐变动画(Morphing

Morphing渐变是20世纪90年代出现的一种革命性的计算机图形技术,该技术使得动画序列平滑且易于处理,即使在低档配置的计算机系统上也能正常运行。

渐变是指随时间的变化把一个形状改变为另一个形状。对我们而言,这些形状就是Mesh网格模型。渐变网格模型的处理就是以时间轴为基准,逐渐地改变网格模型顶点的坐标,从一个网格模型的形状渐变到另外一个。请看图2.3

2.3

我们在程序中使用两个网格模型——源网格模型和目标网格模型,设源网格模型中顶点1的坐标为AAxAyAz),目标网格模型中对应顶点1的坐标为BBxByBz),要计算渐变过程中时间点t所对应的顶点1的坐标CCxCyCz),我们使用如下方法:

T为源网格模型到目标网格模型渐变所花费的全部时间,得到时间点t占整个过程T的比例为:

S = t / T

那么顶点1t时刻对应的坐标C为:

C = A * (1-S+ B * S

这样,在渲染过程中我们根据时间不断调整S的值,就得到了从源网格模型(形状一)到目标网格模型(形状二)的平滑过渡。

接下来将在程序里使用顶点着色器实现我们的渐变动画。

2.3.2渐变动画中的顶点声明

程序中,我们设定一个顶点对应两个数据流,这两个数据流分别包含了源网格模型的数据和目标网格模型的数据。渲染过程中,我们在着色器里根据两个数据流中的顶点数据以及时间值确定最终的顶点信息。

个数据流包含分量如下:

源网格模型数据流:顶点位置、顶点法线、纹理坐标;

目标网格模型数据流:顶点位置、顶点法线;

注意目标网格模型数据流没有包含纹理坐标,因为纹理对于两个网格模型都是一样的,所以仅使用源网格模型的纹理就可以了。

顶点声明指定如下:

D3DVERTEXELEMENT9 decl[] =

{

//源网格模型数据流,包含分量位置、法线、纹理坐标

{ 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 },

//目标网格模型数据流,包含分量位置、法线

{ 1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_

POSITION, 1 },

{ 1, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_

NORMAL, 1 },

D3DDECL_END()

};

2.3.3渐变动画中的顶点着色器

下面给出顶点着色器源码,代码存储于vs.txt中,该顶点着色器根据源网格模型数据流和目标网格模型数据流中的信息以及时间标尺值计算出顶点最终位置信息,并对顶点做了坐标变换和光照处理。代码中给出了详细的注释,帮助读者理解。

//全局变量

//世界矩阵、观察矩阵、投影矩阵的合矩阵,用于顶点的坐标变换

matrix WVPMatrix;

//光照方向

vector LightDirection;

//存储2.3.1小节提到的公式S = t / T中的时间标尺S

//注意到Scalar是一个vector类型,我们在Scalar.x中存储了S值,Scalar.y中存储的则是(1-S)值

vector Scalar;

//输入

struct VS_INPUT

{

//对应源网格模型数据流中的顶点分量:位置、法线、纹理坐标

vector position : POSITION;

vector normal : NORMAL;

float2 uvCoords : TEXCOORD;

//对应目标网格模型数据流中的顶点分量:位置、法线

vector position1 : POSITION1;

vector normal1 : NORMAL1;

};

//输出

struct VS_OUTPUT

{

vector position : POSITION;

vector diffuse : COLOR;

float2 uvCoords : TEXCOORD;

};

//入口函数

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;

return output;

}

以上是本例用到的顶点着色器,在接下来的应用程序中,我们将给三个着色器全局变量赋值:

² WVPMatrix;

世界矩阵、观察矩阵、投影矩阵的合矩阵,用于顶点的坐标变换;

² LightDirection

光照方向;

² Scalar

存储2.3.1小节提到的公式S = t / T中的时间标尺S值;

注意到Scalar是一个vector类型,我们在Scalar.x中存储了S值,Scalar.y中存储的则是(1-S)值;

2.3.4应用程序

我们在应用程序中执行以下操作:

· 加载两个两个Mesh模型:源网格模型,目标网格模型;

· 创建、设置顶点声明;

· 创建、设置顶点着色器;

· 为着色器全局赋值;

· 把两个Mesh模型数据分别绑定到两个数据流中;

· 渲染Mesh模型;

下面是应用程序代码:

/*********************声明变量*****************/

//两个指向LPD3DXMESH的指针,分别用于存储源网格模型和目标网格模型;

LPD3DXMESH g_SourceMesh;

LPD3DXMESH g_TargetMesh;

//顶点声明指针

IDirect3DVertexDeclaration9 *g_Decl = NULL;

//顶点着色器

IDirect3DVertexShader9 *g_VS = NULL;

//常量表

ID3DXConstantTable* ConstTable = NULL;

//常量句柄

D3DXHANDLE WVPMatrixHandle = 0;

D3DXHANDLE ScalarHandle = 0;

D3DXHANDLE LightDirHandle = 0;

/***************程序初始化*****************/

//加载源、目标网格模型

Load_Meshes();

//顶点声明

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 },

D3DDECL_END()

};

//创建顶点着色器

ID3DXBuffer* shader = NULL;

ID3DXBuffer* errorBuffer = NULL;

D3DXCompileShaderFromFile("vs.txt",

0,

0,

"Main", // entry point function name

"vs_1_1",

D3DXSHADER_DEBUG,

&shader,

&errorBuffer,

&ConstTable);

if(errorBuffer)

{

::MessageBox(0, (char*)errorBuffer->GetBufferPointer(), 0, 0);

ReleaseCOM(errorBuffer);

}

//创建顶点着色器

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

//为着色器全局变量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 );

g_pd3dDevice->BeginScene();

//为着色器全局变量WVPMatrix赋值

D3DXMATRIX matWorld, matView, matProj;

g_pd3dDevice->GetTransform(D3DTS_WORLD, &matWorld);

g_pd3dDevice->GetTransform(D3DTS_VIEW, &matView);

g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &matProj);

D3DXMATRIX matWVP;

matWVP = matWorld * matView * matProj;

ConstTable->SetMatrix(g_pd3dDevice, WVPMatrixHandle, &matWVP);

//为着色器全局变量Scalar赋值,注意程序中获取时间标尺值Scalar的方法

float DolphinTimeFactor = (float)(timeGetTime() % 501) / 250.0f;

float Scalar =

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

ReleaseCOM(pVB);

//绑定源网格模型的顶点缓存到第一个数据流中

g_SourceMesh->GetVertexBuffer(&pVB);

g_pd3dDevice->SetStreamSource(0, pVB, 0,

D3DXGetFVFVertexSize(g_TargetMesh->GetFVF()));

ReleaseCOM(pVB);

//绘制Mesh网格模型

DrawMesh(g_SourceMesh, g_pMeshTextures0, g_VS, g_Decl);

g_pd3dDevice->EndScene();

g_pd3dDevice->Present( NULL, NULL, NULL, NULL );

2.3.5对应用程序的一点说明

程序中我们使用SetStreamSource方法把源网格模型和目标网格模型中的顶点缓存分别绑定到两个设备数据流,但是Direct3D对数据流中的数据的真正引用只有在调用诸如DrawPrimitive<span

分享到:
评论

相关推荐

    HLSL初级教程-着色器

    ##### 2.3 用顶点着色器实现渐变动画 通过顶点着色器,可以轻松地实现各种动画效果。例如,可以通过修改顶点位置来实现顶点在空间中的平移、旋转或缩放,进而产生动态变化的效果。 #### 3. 像素着色器 ##### 3.1 ...

    HLSL初级教程.pdf

    **2.3 用顶点着色器实现渐变动画** 通过顶点着色器可以实现一些动态效果,比如渐变动画。这种效果通常涉及到顶点位置或颜色随时间的变化。例如,可以使用一个随时间变化的参数来修改顶点位置或颜色,从而产生平移或...

    HLSL 入門教學

    ##### 2.3 用顶点着色器实现渐变动画 - **2.3.1 渐变动画(Morphing)**:通过修改顶点的位置来实现动画效果。 - **2.3.2 渐变动画中的顶点声明**:需要包含原始顶点位置和变形后的顶点位置。 - **2.3.3 渐变动画中...

    HLSL(微软高级着色语言)初级教程

    ##### 2.3 用顶点着色器实现渐变动画 通过修改顶点着色器中的顶点位置,可以实现各种动态效果,例如渐变动画。渐变动画可以通过改变顶点位置来模拟物体的运动或变形。 #### 3. 像素着色器 ##### 3.1 多纹理化 多纹...

    HLSL初级教程HLSL初级教程

    ##### 2.3 用顶点着色器实现渐变动画 通过顶点着色器,可以实现复杂的顶点位置变换,进而实现动态效果,如渐变动画。渐变动画可以通过改变顶点的位置或颜色来实现,例如根据时间变化来更新顶点的位置。 #### 3. ...

    Unity着色器和屏幕特效开发秘笈PDF高清完全版

    顶点魔法7.1 引言7.2 在表面着色器中访问顶点颜色7.2.1 准备工作7.2.2 如何操作7.2.3 实现原理7.2.4 更多内容7.3 表面着色器的顶点动画7.3.1 准备工作7.3.2 如何操作7.3.3 实现原理7.4 在地形中使用顶点...

    Android 3D游戏开发技术宝典-OpenGL ES 2.0 (吴亚峰) 源代码

    第13章 顶点着色器的妙用 345 13.1 飘扬的旗帜 345 13.1.1 基本原理 345 13.1.2 开发步骤 346 13.2 扭动的软糖 349 13.2.1 基本原理 349 13.2.2 开发步骤 350 13.3 风吹椰林场景的开发 351 ...

    Qt5入门教程

    - 展示如何使用顶点着色器修改几何形状。 - **9.6 Curtain Effect** - 介绍如何使用着色器实现窗帘效果。 - 实例展示窗帘效果的具体实现。 - **9.7 Qt Graphics Effect Library** - 介绍Qt提供的图形效果库。 -...

    OGRE 3D v1.4.0中文手册

    支持顶点着色器和片段着色器的使用;定义了透明度、深度测试等渲染状态。 - **3.1.3 纹理单元** - **定义**: 纹理单元用于描述如何将纹理应用于几何体。 - **功能**: 支持多种纹理混合模式;允许设置UV坐标和坐标...

    粒子系统编辑器

    2.3 动画曲线:通过动画曲线编辑器,可以为粒子的属性定义随时间变化的轨迹,实现更为细腻的动态效果。 2.4 图形化编程:某些高级粒子系统编辑器支持图形化编程,通过节点连接实现逻辑控制,如条件判断、循环等,...

    Qt 5 QML中文版

    - **顶点着色器**:介绍如何编写顶点着色器来处理顶点数据。 ##### 10.3 波浪效果 - **波浪效果实现**:通过实例说明如何使用着色器来实现波浪效果。 - **参数调整**:讲解如何通过调整参数来优化波浪效果。 #####...

    NITRO_graphics_primer

    - **动画效果**:支持简单的动画效果,通过改变对象的帧序列来实现动态效果。 ##### 3.3 BG特性 - **层叠层次**:可以定义多个背景层,每个层都可以独立移动,从而创建出丰富的视觉效果。 - **滚动速度**:不同的...

    PowerPoint.2007宝典 3/10

    12.5.2 使用“剪辑管理器”插入剪贴画 241 12.5.3 创建和删除文件夹 242 12.5.4 在收藏集之间移动剪辑 242 12.5.5 分类剪辑 242 12.5.6 自动将剪辑添加到“剪辑管理器” 243 12.5.7 手动将剪辑添加到...

    PowerPoint.2007宝典 10/10

    12.5.2 使用“剪辑管理器”插入剪贴画 241 12.5.3 创建和删除文件夹 242 12.5.4 在收藏集之间移动剪辑 242 12.5.5 分类剪辑 242 12.5.6 自动将剪辑添加到“剪辑管理器” 243 12.5.7 手动将剪辑添加到...

Global site tag (gtag.js) - Google Analytics