如何使用Effect

                                                                          如何使用effect
 
这篇文章将教你如何构建和使用effect。它将介绍effect一些强大有趣的细节。

.创建一个effect

下面是dx sdk例子 BasicHLSL Sample里的代码

ID3DXEffect* g_pEffect = NULL;
DWORD dwShaderFlags = 0;
    //设置flag
    dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
    dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
    dwShaderFlags |= D3DXSHADER_NO_PRESHADER;

    // Read the D3DX effect file
    WCHAR str[MAX_PATH];
    DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"BasicHLSL.fx" );

    D3DXCreateEffectFromFile(
  1      pd3dDevice,
  2      str,
  3      NULL, // CONST D3DXMACRO* pDefines,
  4      NULL, // LPD3DXINCLUDE pInclude,
  5      dwShaderFlags,
  6  NULL, // EFFECT POOL
  7      &g_pEffect,
  8      NULL );

参数6:effect pool.如果多个effect使用指向同一内存的pool指针,那么这些effect将共用这些变量。
如果是NULL将不具有这功能。其他参数具体含义可以参考sdk。

. 渲染effect

使用effect渲染的一般步骤是:
  Begin          设置当前的 techinque
  BeginPass      设置当前的 pass
  CommitChanges  在一个pass内改变effect状态,要在渲染代码前。
  EndPass        结束pass
  End            结束tuchinque

Effect渲染代码往往比相应的不用effect的代码简单,下面是一个例子:

// Apply the technique contained in the effect
g_pEffect->Begin(&cPasses, 0);

for (iPass = 0; iPass < cPasses; iPass++)
{
    g_pEffect->BeginPass(iPass);

    // Only call CommitChanges if any state changes have happened
    // after BeginPass is called
    g_pEffect->CommitChanges();

    // Render the mesh with the applied technique
    g_pMesh->DrawSubset(0);

    g_pEffect->EndPass();
}
g_pEffect->End();

在渲染循环中可以有多个technique,一个technique中也可以有多个pass。

.effect 的语义(semantic)

Effect可以根据Semantics(语义)来找到相应的变量。一个变量最多有一个semantic,semantic以:型

式跟在变量后面:
 float4x4 matWorldViewProj : WORLDVIEWPROJ;
effect接口可以这样根据semantic来得到变量句柄:
 D3DHANDLE handle =
    m_pEffect->GetParameterBySemantic(NULL, "WORLDVIEWPROJ");
effect也有其他的方法来查询变量。
  
.变量注释


我们可以对effect中的变量,pass 和 techinque加注释。

对变量很容易加上注释,而且这些信息可以读取和作他用。注释可以使任何数据类型,可以被动态添加
注释的声明便限制在<>,一个注释应包括:
     1.类型
     2.变量名
     3.=号
     4.数值
     5. ;号
比如: texture Tex0 < string name = "tiger.bmp"; >;
<>内就是一个annotation,它仅仅是作为一个用户注释附加在变量后面。通过 GetAnnotation 或

GetAnnotationByName函数来得到。annotation也可以通过应用程序来添加,
但要注意以下几点:
 Must be either numeric or strings.
 Must always be initialized with a default value.
 Can be associated with Techniques and Passes and top-level Effect Parameters.
 Can be written to and read from with either ID3DXEffect or ID3DXEffectCompiler.
 Can be added with ID3DXEffect.
 Cannot be referenced inside the effect.
 Cannot have sub-semantics or sub-annotations.

.共享Effect的变量

Effect parameters 是一些在effect中声明的非static 变量。这些包括全局变量和注释annotations。
Effect Parameters 可以在不同的effect中共用,但前提是声明这些parameters是加上"shared"关键字

,而且要相同的名字,类型和语义。effect pool 包含了共享的effect parameter。通过

D3DXCreateEffectPool 创建pool:

 ID3DXEffectPool* g_pEffectPool = NULL;   // Effect pool for sharing parameters
        D3DXCreateEffectPool( &g_pEffectPool );
Effect中这些共享参数必须用同样的设备。当effect release 共享参数时,同时也在pool中删掉了这些

参数。如果没有必要共享参数,那么在创建effect时把pool参数设为NULL。


.编译Effect

在application中,当你调用 D3DXCreateEffect时就已经包含了对effect的编译。也可以用sdk提供的工

具进行离线编译。
 fxc.exe Compiles HLSL shaders.
 flink.exe Links HLSL fragments.
 vsa.exe Compiles assembly vertex shaders.
 psa.exe Compiles assembly pixel shaders.
这些工具在(SDK root)/Utilities/Bin/x86/目录下。


.通过预渲染来提高性能。

preshader 通过预计算常表达式来提高shader 效率。effect 编译器会自动的把它从shader主体抽出来

让cup预处理,这种情况跟把static 表达式从一个循环代码中提出来一样。preshader只在effect中起作

用。preshader能够减少每遍渲染所要的指令数和寄存器数,从而提高shader代码的执行效率。

可以把effect 编译器想象成一个两个编译器的集合:一个编译cpu类型,一个编译gpu类型。当作

preshader时,相当于把部分gpu计算让cpu来代劳。


.Parameter Blocks
parameter blocks可以保存effect的状态。

    m_pEffect->SetTechnique( "RenderScene" );

    m_pEffect->BeginParameterBlock();
    D3DXVECTOR4 v4( Diffuse.r, Diffuse.g, Diffuse.b, Diffuse.a );
    m_pEffect->SetVector( "g_vDiffuse", &v4 );
    m_pEffect->SetFloat( "g_fReflectivity", fReflectivity );
    m_pEffect->SetFloat( "g_fAnimSpeed", fAnimSpeed );
    m_pEffect->SetFloat( "g_fSizeMul", fSize );
    m_hParameters = m_pEffect->EndParameterBlock();
 上面代码保存了4个parameter值,并返回一个句柄。可以调用api ApplyParameterBlock来得到保持的

状态。如下面代码:
    CObj g_aObj[NUM_OBJS];       // Object instances

    if( SUCCEEDED( pd3dDevice->BeginScene() ) )
    {
        // Set the shared parameters using the first mesh's effect.

        // Render the mesh objects
        for( int i = 0; i < NUM_OBJS; ++i )
        {
            ID3DXEffect *pEffect = g_aObj[i].m_pEffect;

            // Apply the parameters
            pEffect->ApplyParameterBlock( g_aObj[i].m_hParameters );

   ...

            pEffect->Begin( &cPasses, 0 );
            for( iPass = 0; iPass < cPasses; iPass++ )
            {
              ...
            }
            pEffect->End();
        }

  ...
        pd3dDevice->EndScene();
    }
以上代码直观上最大的有点是用一行代码设置N个parameters。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值