




已阅读5页,还剩22页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
定点着色器入门(续)2008-08-10 12:35:49|分类: 游戏 |标签: |字号大中小订阅 顶点着色器(vertex shader)是一个在图形卡的GPU上执行的程序,它替换了固定功能管线(fixed function pipeline)中的变换(transformation)和光照(lighting)阶段。(这不是百分之百的正确,因为顶点着色器可以被Direct3D运行时(Direct3D runtime)以软件模拟,如果硬件不支持顶点着色器的话)。图17.1说明了管线中顶点着色器替换的部件。从图17.1,我们知道,顶点以局部坐标输入到顶点着色器,并且必须输出齐次剪裁空间的有颜色的顶点。(经投影矩阵变换顶点后的空间称作齐次剪裁空间(homogeneous clip space)。因此,要把一个顶点从局部空间变换到齐次坐标空间,我们必须应用下列变换序列:世界变换(world transformation),视图变换(view transformation)和投影变换(projection transformation),它们分别由世界矩阵,视图矩阵和投影矩阵来完成。)对于点元(point primitive),顶点着色器也被用于操作每个顶点的顶点大小。由于顶点着色器是我们(在HLSL中)写的一个自定义程序,因此我们在图形效果方面获得了极大的自由性。我们不再受限于Direct3D的固定光照算法。此外,应用程序操纵顶点位置的能力也有了多样性,例如:cloth simulation,粒子系统的点大小操纵,还有顶点混合/morphing。此外,我们的顶点数据结构更自由了,并且可以在可编程管线中包含比在固定功能管线中多得多的数据。顶点着色器仍然是相对新的特性,并且许多图形卡不支持它们,特别是随DirectX 9发布的较新版本的顶点着色器。通过检查D3DCAPS9结构的VertexShaderVersion成员,可以测试顶点着色器的版本。下列代码段展示了这一点:/ If the devices supported version is less than version 2.0if( caps.VertexShaderVersion CreateVertexDeclaration(decl, &_decl);17.1.3 使用一个顶点声明回忆一下:自由顶点格式是一个方便的特性并且在内部转换成了顶点声明。因此,当直接使用顶点声明,我们不再需要调用:Device-SetFVF( fvf );相反,我们调用:Device-SetVertexDeclaration( _decl );其中,_decl是一个IDirect3DVertexDeclaration9接口指针。17.2顶点数据用途考虑这个顶点声明:D3DVERTEXELEMENT9 decl =0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0,0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0,0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 1,0, 36, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 2,D3DDECL_END();我们需要一种方式,来定义一个顶点声明的元素到顶点着色器的Input结构的数据成员的映射。我们在Input结构中通过指定每个数据成员的语义(: usage-type usage-index)定义这个映射。语义通过元素的用途类型和用途索引标识顶点声明中的一个元素。由数据成员的语义标识的顶点元素是得以映射到数据成员的元素。例如,对应于前面的顶点声明的输入结构是:struct VS_INPUT vector position : POSITION; vector normal : NORMAL0; vector faceNormal1 : NORMAL1; vector faceNormal2 : NORMAL2;注意:如果我们遗漏了用途索引,就意味着用途索引为零。例如,POSITION和POSITION0是同一样东西。这里decl中的元素0,由用途POSITION和用途索引0标识,它映射到position。decl中的元素1,由用途NORMAL和用途索引0标识,它映射到normal。decl中的元素2,由NORMAL和用途索引1标识,它映射到faceNormal1。decl中的元素3,由用途NORMAL和用途索引2标识,它映射到faceNormal2。受支持的顶点着色器输入用途(input usage)是:POSITION n位置BLENDWEIGHTS n混合权重BLENDINDICES n混合索引NORMAL n法线向量PSIZEn顶点大小DIFFUSE n散射颜色SPECULAR n镜面颜色TEXCOORD n纹理坐标其中,n是一个位于区间0, 15的可选整数。此外,对于输出结构,我们必须指定每个成员是用来做什么的。例如,数据成员应该被作为位置向量、颜色、纹理坐标等对待吗?图形卡没主意,除非你强制的告诉它。这也需要通过语法的语义来完成:struct VS_OUTPUT vector position : POSITION; vector diffuse : COLOR0; vector specular : COLOR1;受支持的顶点着色器输出用途是:POSITION位置PSIZE顶点大小FOG雾混合值COLOR n顶点颜色。注意:可以有多个顶点颜色被输出,并且这些颜色可以被混合在一起以产生最终的颜色。TEXCOORD n顶点纹理坐标。注意:多个顶点纹理坐标可以被输出。其中,n是一个位于区间0, 15的可选整数。17.3使用顶点着色器的步骤下面的列表概括了创建和使用顶点着色器的必须步骤:1.编写并编译顶点着色器2.创建一个IDirect3DVertexShader9接口以引用已编译的着色器代码上的顶点着色器。3.用IDirect3DDevice9: SetVertexShader方法使用这个顶点着色器。当然,在我们做完这些之后,我们还得销毁这个顶点着色器。17.3.1 编写并编译顶点着色器首先,我们必须编写一个顶点着色器程序。一旦着色器代码写好之后,我们就使用D3DXCompileShaderFromFile函数编译这个着色器。回忆一下,这个函数返回一个ID3DXBuffer指针,它包含已编译的着色器代码。17.3.2 创建顶点着色器一旦我们拥有了编译好的着色器代码,我们就能够获得一个IDirect3DVertexShader9接口的指针,它代表一个顶点着色器通过使用下面的方法: HRESULT IDirect3DDevice9:CreateVertexShader( const DWORD *pFunction, IDirect3DVertexShader9* ppShader ); pFunction已编译着色器代码的指针ppShader返回一个IDirect3DVertexShader9接口的指针例如,假设变量shader是一个包含已编译的,着色器代码的ID3DXBuffer指针。然后要获得一个IDirect3DVertexShader9接口,我们可以写: IDirect3DVertexShader9* ToonShader = 0; hr = Device-CreateVertexShader( (DWORD*)shader-GetBufferPointer(), &ToonShader); 注意:重申一遍,D3DXCompileShaderFromFile是一个函数,它将返回已编译着色器的代码(shader)。17.3.3 建立顶点着色器在我们获得了一个代表我们的顶点着色器的IDirect3DVertexShader9接口的指针之后,我们就能够使用下面的方法使用它: HRESULT IDirect3DDevice9:SetVertexShader( IDirect3DVertexShader9* pShader ); 这个方法仅接受一个参数,我们在其中传递一个想要使用的顶点着色器的指针。要使用这个着色器,我们可以写:Device-SetVertexShader(ToonShader);17.3.4 销毁顶点着色器和所有的Direc3D接口一样,要清除他们,我们就必须在用完它们之后调用其的Release方法。17.4应用程序:散射光照作为创建并使用顶点着色器的热身,我们写一个顶点着色器,它用一个方向(平行)光对每个顶点进行标准的散射光照。简而言之,散射光照根据顶点法线和光线向量(它朝向光源方向)的角度计算顶点接收到的光线的数量。角度越小,则顶点接收到的光线就越多;而角度越大,则顶点接收到的光线就越少。如果角度大于等于90度,顶点就接收不到光线了。我们以检阅着色器代码作为开始: /* Vertexshaderthatdoesdiffuselighting. */ matrixg_view_matrix; matrixg_view_proj_matrix; vectorg_ambient_material; vectorg_diffuse_material; vectorg_dir_to_light;/thedirectiontothelightsource /Globalvariablesusedtoholdtheambientlightintensity(ambientlightthelight /sourceemits)andthediffuselightintensity(diffuselightthelightsourceemits). /Thesevariablesareinitializedhereintheshader. constvectorDIFFUSE_LIGHT_INTENSITY=0.5f,0.5f,0.5f,1.0f; constvectorAMBIENT_LIGHT_INTENSITY=2.0f,2.0f,1.0f,1.0f; structsVertexInput vectorposition:POSITION; vectornormal:NORMAL; ; structsVertexOutput vectorposition:POSITION; vectordiffuse:COLOR; ; / sVertexOutputmain(sVertexInputvertex_input) sVertexOutputvertex_output=(sVertexOutput)0; /transformpositiontohomogeneousclipspace vertex_output.position=mul(vertex_input.position,g_view_proj_matrix); /Transformlightsandnormalstoviewspace. /Setwcomponentstozerosinceweretransformingvectorshereandnotpoints. g_dir_to_light.w=0.0f; vertex_input.normal.w=0.0f; g_dir_to_light=mul(g_dir_to_light,g_view_matrix); vertex_input.normal=mul(vertex_input.normal,g_view_matrix); /computecosineoftheanglebetweenlightandnormal floatscalar=dot(g_dir_to_light,vertex_input.normal); /Recallthatiftheanglebetweenthesurfaceandlightisgreaterthan90degrees /thesurfacerecievesnolight.Thus,iftheangleisgreaterthan90degreesweset /scalartozerosothatthesurfacewillnotbelit. if(scalarGetBufferPointer(),ERROR,MB_OK); safe_release(error_buffer); if(FAILED(hr) MessageBox(NULL,D3DXCreateEffectFromFile()-FAILED,ERROR,MB_OK); returnfalse; hr=g_device-CreateVertexShader(DWORD*)shader_buffer-GetBufferPointer(),&g_vertex_shader); if(FAILED(hr) MessageBox(NULL,CreateVertexShader-FAILED,ERROR,MB_OK); returnfalse; safe_release(shader_buffer); /gethandles g_view_matrix_handle=g_constant_table-GetConstantByName(NULL,g_view_matrix); g_view_proj_matrix_handle=g_constant_table-GetConstantByName(NULL,g_view_proj_matrix); g_ambient_material_handle=g_constant_table-GetConstantByName(NULL,g_ambient_material); g_diffuse_material_handle=g_constant_table-GetConstantByName(NULL,g_diffuse_material); g_dir_to_light_handle=g_constant_table-GetConstantByName(NULL,g_light_direction); / /setshaderconstants / /lightdirection D3DXVECTOR4dir_to_light(-0.57f,0.57f,-0.57f,0.0f); g_constant_table-SetVector(g_device,g_dir_to_light_handle,&dir_to_light); /materials D3DXVECTOR4ambient_material(1.0f,1.0f,0.5f,1.0f); D3DXVECTOR4diffuse_material(1.0f,1.0f,0.5f,1.0f); g_constant_table-SetVector(g_device,g_ambient_material_handle,&ambient_material); g_constant_table-SetVector(g_device,g_diffuse_material_handle,&diffuse_material); g_constant_table-SetDefaults(g_device); /settheprojectionmatrix D3DXMatrixPerspectiveFovLH(&g_proj_matrix,D3DX_PI/4.0f,(float)WIDTH/HEIGHT,1.0f,1000.0f); /g_device-SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME); returntrue; / voidcleanup() safe_release(g_teapot_mesh); safe_release(g_vertex_shader); safe_release(g_constant_table); / booldisplay(floattime_delta) staticfloatangle=(3.0f*D3DX_PI)/2.0f; staticfloatheight=3.0f; if(GetAsyncKeyState(VK_LEFT)&0x8000f) angle-=0.5f*time_delta; if(GetAsyncKeyState(VK_RIGHT)&0x8000f) angle+=0.5f*time_delta; if(GetAsyncKeyState(VK_UP)&0x8000f) height+=5.0f*time_delta; if(GetAsyncKeyState(VK_DOWN)&0x8000f) height-=5.0f*time_delta; D3DXVECTOR3position(cosf(angle)*7.0f,height,sinf(angle)*7.0f); D3DXVECTOR3target(0.0f,0.0f,0.0f); D3DXVECTOR3up(0.0f,1.0f,0.0f); D3DXMATRIXview_matrix; D3DXMatrixLookAtLH(&view_matrix,&position,&target,&up); D3DXMATRIXview_proj_matrix=view_matrix*g_proj_matrix; g_constant_table-SetMatrix(g_device,g_view_proj_matrix_handle,&view_proj_matrix); /rendernow g_device-Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,0x00000000,1.0f,0); g_device-BeginScene(); g_device-SetVertexShader(g_vertex_shader); g_teapot_mesh-DrawSubset(0); g_device-EndScene(); g_device-Present(NULL,NULL,NULL,NULL); returntrue; / LRESULTCALLBACKwnd_proc(HWNDhwnd,UINTmsg,WPARAMword_param,LPARAMlong_param) switch(msg) caseWM_DESTROY: PostQuitMessage(0); break; caseWM_KEYDOWN: if(word_param=VK_ESCAPE) DestroyWindow(hwnd); break; returnDefWindowProc(hwnd,msg,word_param,long_param); / intWINAPIWinMain(HINSTANCEinst,HINSTANCE,PSTRcmd_line,intcmd_show) if(!init_d3d(inst,WIDTH,HEIGHT,true,D3DDEVTYPE_HAL,&g_device) MessageBox(NULL,init_d3d()-failed.,0,MB_OK); return0; if(!setup() MessageBox(NULL,Steup()-failed.,0,MB_OK); return0; enter_msg_loop(display); cleanup(); g_device-Release(); return0; 运行截图: setup函数执行下列任务:创建茶壶网格编译顶点着色器根据已编译代码创建顶点着色器通过常量表获取着色器程序中的几个变量的句柄通过常量表初始化着色器的这几个变量注意:对于本应用程序,我们的顶点结构不需要任何自由顶点格式没有的额外的分量。 display函数非常简单。它检测用户输入(这里指的是用户输入的传入着色器程序的变量),并相应的更新视图矩阵。但是,因为我们在着色器中执行这个视图矩阵变换,所以我们还必须更新着色器中的视图矩阵变量。我们用常量表完成这件事情。下载源程序作为第二个顶点着色器的例子,让我们编写两个顶点着色器,它们以卡通风格的绘画方式对网格着色(shade)和轮廓勾勒(outline)。图17.2展示了这一点: 注意:卡通渲染是一种特定类型的非写实渲染(non-photorealistic rendering),有时被称作风格化渲染(stylistic rendering)。虽然卡通渲染不适用于所有游戏,例如激烈的第一人称射击游戏,但是它仍然可以增强一些希望表现卡通感觉类型游戏的气氛。此外,卡通渲染是漂亮的,并易于实现。让我们好好的演示一个顶点着色器。我们将卡通渲染分为两步:1.卡通绘画的特点是:在一个顶点到下一个顶点的强烈转换时,有少量的阴影强度级别;我们看一下这个卡通阴影(cartoon shading)。在图17.2(a)中,我们看到网络着色使用了三种阴影强度(亮、中、暗),而且其间的过渡是不平滑的不像图17.2(c),其明暗过渡是平滑的。2.
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 叮当健康:2023年环境、社会及管治报告
- 一线配电安规标准复习测试卷
- 大气环境风险评估重点基础知识点
- 【沙利文】中国汽车零部件市场研究报告
- 人教版物理第二册第七章7.3 万有引力理论的成就【含答案】
- 六年级行为习惯塑造
- 2025届高三物理一模试卷【含答案】
- 立春文化与自然认知
- 2025年代理化妆品产品销售合同
- 2025劳动合同签订后何时需提交社保资料
- 水资源利用知到章节答案智慧树2023年西安理工大学
- 名著导读 西游记
- 静脉给药错误演练脚本
- IE动作MOD法培训资料
- 一汽解放维修手册说明书
- 禽流感人流感人间禽流感培训课件
- MT 191-1989煤矿井下用橡胶管安全性能检验规范
- JJF 1319-2011傅立叶变换红外光谱仪校准规范
- GB/T 4857.4-2008包装运输包装件基本试验第4部分:采用压力试验机进行的抗压和堆码试验方法
- GB/T 25174-2010饲料添加剂4,7-二羟基异黄酮
- GB/T 17421.2-2000机床检验通则第2部分:数控轴线的定位精度和重复定位精度的确定
评论
0/150
提交评论