GPU编程--hlsl--06--效果(effect)基础2

来源:百度文库 编辑:神马文学网 时间:2024/07/06 20:18:55
前面简单的介绍了一下vetex shader和pixel shader,这里简单的介绍一下效果(effect)效果(effect)就是用一个文件来综合管理vetex shader和pixel shader的框架。通过使用effect,可以将vetex shader和pixel shader统筹起来,所以主程序中只需要加载effect文件就可以了。Effect文件一般保存在.fx文件中,当然,也可以想前面介绍vetex shader和pixel shader一样保存在.txt文件中。一般来说,效果(effect),技术(technique),过程(pass)是一起使用的,也就是说,一般的,一个effect至少要有一个technique,一个technique至少有一个pass,而具体数目上限是没有限制的这么说的话其实effect很简单的,就是简单的用technique和pass把vetex shader和pixel shader的一个逻辑步骤,没有什么新的东西,不过优点却是明显的,方便嘛,而且提高了程序的兼容性,具体的用了就知道了(其实我时钟认为在没有告诉人家一个东西是什么的情况下说优点是和愚蠢的事情…..汗’’)下面是如何编写效果,其实很简单,我写出来,大家一看就都明白了,不用过多的解释的:technique [id] []
...{
    pass [id] []
    ...{
        .....//程序语句
    }
    ......//可以有多个psss
}
.....//可以有多个technique

这就是一个典型的effect框架,有人问,那effect呢?整个不就是个effect嘛。。。。

下面解释下,technique 就是关键字,[id]是 technique的名称,然后 []是注释啦,我这么写不会有人认为[ ]是不需的吧,这个就是说[id]这整个用名字代替掉。。。(觉得自己好白痴 寒‘’)不过注意,注释是一定要在<>也就是我们所说的尖括号里头的,这么做嘛,简单说就是规定了,具体说就是,呃,抄一段人家的,注释是用户指定的数据,他可以链接到任何技术,过程或参数。注释是为当个参数添加信息的一种灵活方式,这些信息可以通过应用程序选择任意方式读取和使用,也就是说,注释是有用的,一个注释包括,一个数据类型,一个变量名,一个等号,数据的值,最后用分号(;)结尾例如:

texture Tex0 

汗吧?我也汗,具体想了解的可以参考directx的帮助,这里要是说的话要说好久,反正就是可以通过GetAnnotation()或者是GetAnnotationByName()的到,具体怎么用,讲到的时候再说

上面就是effect的编写了,一般简单的effect只要把vetex shader和pixel shader分别封装在一个pass里头就可以了,复杂的因为有好多的vetex shader和pixel shader,所以需要好好组织

      下面是怎样来使用效果,第一步自然是从效果文件中创建效果接口对象,一般在DXUT框架中在OnCreateDevice()函数中通过调用D3DXCreateEffectFromFile()来创建,函数如下:

HRESULT D3DXCreateEffectFromFile
(
    LPDIRECT3DDEVICE9 pDevice,   //设备指针
    LPCTSTR           pSrcFile,  //效果文件名
    CONST D3DXMACRO * pDfines,   //可选,指向一组预定义的宏,用于效果文件的预编译,不需要时设为NULL
    LPD3DXINCLUDE     pInclude,  //可选,用来指向ID3DXInclude接口,处理#include命令
    DWORD             Flags,     //编译标志
  LPD3DXEFFECTPOOL  pPool,    //指向一个ID3DXEffectPool对象,用来存放共享数据,后面用一个例子给出
  LPD3DXEFFECT    * ppEffect //指向编译好的effect效果指针
  LPD3DXBUFFER    * ppCompilationErrors //指向编译错误的指针
)

至于设置全局变量,查找参数和前面vetex shader一样的,这里就不说了

如果效果包含多个technique,在渲染是可以通过 ID3DXEffect :: SetTechnique( D3DXHANDLE hTechnique)来激活不同的technique.

使用效果渲染是下面一系列调用的结果:

调用Begin()设置激活的technique,

接着是BeginPass()设置激活的pass,

对用通道中的状态设置,通过CommitChanges()更新变换,

然后是EndPass()和End()函数的调用,具体例子:

//g_pEffect是指向编译好effect对象的指针
UINT nPasses //记录一个technique中的pass总数
g_pEffect->Begin(&nPasses , 0); //得到pass总数,保存在nPasses中
for (ipass = 0;ipass < nPasses; ipass ++)
...{
    g_pEffect->BeginPass(ipass);
    g_pEffect->CommitChanges();
    g_pMesh->DrawSubset(0);
    g_pEffect->EndPass();
}
g_pEffect->End();

好了,到这里就完了,下面给出一个用effect实现简单光照的例子,看代码吧,加上注释,应该不用多少解释吧:

//全局变量

float4x4 matWroldViewProj;
float4x4 matWrold;
float4   vecLightDir;
float4   vecEye;
float4   materialAmbient;
float4   materialDiffuse;
float4   materialSpecular;

//顶点渲染输出结构
struct vs_output
...{
float4 position   :POSITION;
float4 color      :COLOR;

}

//顶点渲染主函数
 vs_output main(float4 pos : POSITION, float3 normal : NORMAL)
 ...{
     vs_output out = (vs_output)0;
     out.position = mul(pos,matWroldViewProj);
     float3 lightDir = normalize(vecLightDir);//单位化
     float3 posWorld = normalize(mul(pos,matWorld));
     float3 veiwDir = normalize(vecEye-posWorld);
     float3 normalWorld = normalize(mul(normal,matWorld));//法向量
     float4 diff = saturate (dot(normalWorld,lightDir));//漫反射强度
     float3 reflect = normalize(2*diff*normalWorld-lightDir);//计算放射光方向
     float3 specu = pow(staturate(dot(reflect,viewDir)),0.5);//镜面放射强度
     
     //顶点颜色
     float4 diffuseColor = ...{1.0f,1.0f,1.0f,1.0f};
     float4 ambientColor = ...{1.0f,1.0f,1.0f,1.0f};
     float4 specularColor = ...{1.0f,1.0f,1.0f,1.0f};
     out.color=ambientColor*materialAmbient+
                 diffuseColor*materialDiffuse+
                 specularColor*materialSpecular;
     return out;
 }  
 
 //技术
 technique T
 ...{
   pass P
   ...{
       //着色器类型        版本  入口函数
    VertexShader = compile vs_1_1 main();
   }
 }