TGEA中材质的使用(三)
3.CustomMaterial对象
前面已经介绍过,CustomMaterial是用于使用程序员自己开发的shader,首先看一下如何指定要使用的shader。
仍旧以box为例:
new CustomMaterial(Two)
{
mapTo = six;
version = 2.0;
shader = Waves;
texture[0] = "two";
texture[2] = "~/data/interiors/test/metalcrate_bump";
specular[0] = "1.0 1.0 1.0 1.0";
specularPower[0] = 16;
fallback = TwoFallback;
};
其中shader = Waves;就指定了使用Waves这个ShaderData渲染这个面。
再打开example\demo\client\scripts下的shaders.cs文件,其中有如下代码:
new ShaderData(Waves)
{
DXVertexShaderFile = "shaders/wavesV.hlsl";
DXPixelShaderFile = "shaders/wavesP.hlsl";
pixVersion = 2.0;
};
这里有一个新的对象ShaderData,是TGEA新引入的,用于指定材质使用的顶点着色器和像素着色器。具体的vertex shader和pix shader的代码位于目录example\shaders中。
3.1. 修改相应的shader
使用CustomMaterial较Material复杂,需根据TGEA的要求对相应的shader做一些修改。
以TGEA1.0.3中的DEMO为例。
在example\demo\data\shapes\test\materials.cs中,有如下的材质定义,这是box的一个面的材质:
new CustomMaterial(SixBump)
{
mapTo = two;
texture[0] = "~/data/interiors/test/metalcrate_bump";
texture[1] = "six";
texture[3] = "$cubemap";
cubemap = Garage;
shader = BumpCubeDiff;
specular = "1.0 1.0 1.0 0.0";
specularPower = 20.0;
version = 2.0;
fallback = SixBumpFallback;
};
相应的ShaderDate定义位于example\demo\client\scripts\shaders.cs中:
new ShaderData( BumpCubeDiff )
{
DXVertexShaderFile = "shaders/bumpCubeDiffuseV.hlsl";
DXPixelShaderFile = "shaders/bumpCubeDiffuseP.hlsl";
pixVersion = 2.0;
};
这两个HLSL文件位于example\shaders\中,首先来看bumpCubeDiffuseV.hlsl。
3.1.1. bumpCubeDiffuseV.hlsl (vertex shader)
相应的代码如下:
#include "shdrConsts.h"
struct Appdata
{
float4 position : POSITION;
float4 normal : NORMAL;
float4 baseTex : TEXCOORD0;
float4 lmTex : TEXCOORD1;
float3 T : TEXCOORD2;
float3 B : TEXCOORD3;
float3 N : TEXCOORD4;
};
struct Conn
{
float4 HPOS : POSITION;
float4 TEX0 : TEXCOORD0;
float4 tangentToCube0 : TEXCOORD1;
float4 tangentToCube1 : TEXCOORD2;
float4 tangentToCube2 : TEXCOORD3;
float4 outLightVec : TEXCOORD4;
float3 pos : TEXCOORD5;
float3 outEyePos : TEXCOORD6;
};
Conn main( Appdata In,
uniform float4x4 modelview : register(VC_WORLD_PROJ),
uniform float3x3 cubeTrans : register(VC_CUBE_TRANS),
uniform float4 cubeEyePos : register(VC_CUBE_EYE_POS),
uniform float3 inLightVec : register(VC_LIGHT_DIR1),
uniform float3 eyePos : register(VC_EYE_POS)
){
Conn Out;
。。。。。。
return Out;
}
开头是vertex shader的输入输出结构的定义。
输入结构(Appdata)即vertex declaration,注意,TGEA中的顶点声明是有规则的。如那纹理坐标寄存器,TEXCOORD2~4指定的即是纹理空间的三个基向量T,B,N,用于bump mapping(bump mapping可以参考《The Cg Tutorial》,《OpenGL Shading Language》等书籍)。具体的顶点声明可以参考引擎源码中的GFXVertexPNTTBN结构的定义,位于engine\gfx\gfxStructs.h,另在engin\ts\tsMesh.h中,GFXVertexPNTTBN也被typedef为MeshVertex(网格的顶点格式)。
输出结构(Conn)则无特殊的限制。
接下来的是VS的main函数,与普通的并无多大的差别,但是要注意main函数的参数。
Vertex Shader必须要与应用程序(引擎)交互,传递相应的数据,如变换矩阵,光源位置,摄像机位置等,DX使用常量表来往VS中传递数据。TGEA在此基础上封装好了大部分的操作,见main函数的参数:
uniform float4x4 modelview : register(VC_WORLD_PROJ)
uniform float3x3 cubeTrans : register(VC_CUBE_TRANS)
uniform float4 cubeEyePos : register(VC_CUBE_EYE_POS)
uniform float3 inLightVec : register(VC_LIGHT_DIR1)
uniform float3 eyePos : register(VC_EYE_POS)
类型符后的modelview指定了变量名,在“:”号后指定了它使用的顶点寄存器, VC_WORLD_PROJ是一个宏,参example\shaders\shdrConsts.h:
#define VC_WORLD_PROJ C0
这里指定C0用于存储世界投影变换矩阵,不管是对于应用程序(引擎)还是你自己开发的shader而言,所以如果你要使用引擎中当前的世界投影变换矩阵,只需声明变量时指定相应的寄存器号(: register(VC_WORLD_PROJ))。shdrConsts.h中还有大量的寄存器宏定义,可以参考。
3.1.2. bumpCubeDiffuseP.hlsl (pixel shader)
PS与VS大部分相似。不同的是PS需要使用纹理,因此需要将相应纹理信息传递至PS中。
首先看一下CustomMaterial(SixBump)的定义,有如下语句:
texture[0] = "~/data/interiors/test/metalcrate_bump";
texture[1] = "six";
texture[3] = "$cubemap";
可以看出它使用了三张纹理。
再在bumpCubeDiffuseP.hlsl的main函数的参数中有如下语句:
uniform sampler2D bumpMap : register(S0)
uniform sampler2D diffMap : register(S1)
uniform samplerCUBE cubeMap : register(S3)
可见它指定的三个纹理寄存器,寄存器号正好与texture的下标一致。TGEA就是用这种方式来传递纹理信息的。注意此处它没有使用2号寄存器,并不意味着2号寄存器不可用。可以随意使用,只是不要超过shader model指定的最大纹理寄存器数。
3.2. CustomMaterial的其他注意事项
(1) mapTo
在Material中,如果不指定mapto属性,则将材质自动mapTo至baseTex的那张纹理,但是CustomMaterial一定要指定mapTo属性。
(2) 在CustomMaterial可以使用来自SceneGraph的一些纹理,如:
$lightmap 内景的光照贴图
$fog 由scenegraph 生成的表示雾的纹理
$cubemap 立方体贴图
$backbuff 后缓冲区(用于制作折射效果)
例如:
CustomMaterial(SixBump)
“texture[3] = "$cubemap";”这条语句就指定了将在PS中使用SceneGraph生成的立方体贴图。