天天看點

改進粒子系統-動态編譯Shader

動态決定需要編譯的FX代碼

       請教了幾個朋友,最後決定用使用FX支援的宏定義解決這個問題。

       根據粒子使用的發射器和效果器定義不同的宏,在FX檔案中通過判斷相應的宏是否定義(#ifdef…#endif)來決定是否編譯某段代碼。

       FX代碼如下:

struct VS_INPUT

{

    float3 Position                : POSITION;   

    float2 Tex0                    : TEXCOORD0;   

    float3 Tex1                    : TEXCOORD1;    // UpOffset, LeftOffset, TotalTimeToLife

    float3 Tex2                    : TEXCOORD2;    // Velocity

    float3 Tex3                    : TEXCOORD3;    // Rotation

    float3 StartDiffuse            : COLOR0;       

};

struct VS_OUTPUT

{

    float4 Position                : POSITION;

    float3 Diffuse                  : COLOR0;

    float2 Tex0                    : TEXCOORD0;

    float2 Tex1                    : TEXCOORD1;

};

matrix matWorldViewProj;                        // world-view-proj matrix

float4 rightVector;                                // Right Vector

float4 upVector;                                // Up Vector

float4 time_colour;                                // Elasped Time, Delta Colour

float4 acceleration;       

float fInitParticleWidth;

float fInitParticleHeight;

//texture textureParticle;

sampler particleSampler = sampler_state

{

    //Texture = (textureParticle);

    AddressU = WRAP;       

    AddressV = WRAP;

    AddressW = WRAP;

    MinFilter = Linear;

    MagFilter = Linear;

    MipFilter = Linear;

};

#ifdef AnimationTexture

    int        iAnimTexSideLength;

    int        iAnimTexNumFrame;

    float    fAnimTexDuration;

#endif

#ifdef v3dScaleAffector

    float fScalePerSecond;

#endif

#ifdef v3dColourImageAffector

    texture textureColour;

    sampler colourSampler = sampler_state

    {

        Texture = (textureColour);

        MinFilter = Point;

        MagFilter = Point;

        MipFilter = Point;

    };

#endif

VS_OUTPUT VS(const VS_INPUT Input)

{

    VS_OUTPUT    Out = (VS_OUTPUT) 0;

    // Live Time = fmod( Elapsed Time, TotalTimeToLife )

    float fLiveTime = fmod(time_colour.x, Input.Tex1.z);

    float fParticleWidth = fInitParticleWidth;

    float fParticleHeight = fInitParticleHeight;

#ifdef v3dScaleAffector

    float fDeltaScale = fScalePerSecond * fLiveTime;

    fParticleWidth += fDeltaScale;

    fParticleHeight += fDeltaScale;

    if( fParticleWidth < 0.f || fParticleHeight < 0.f )

        fParticleWidth = fParticleHeight = 0.f;

#endif

    // Position = right + up + pos;

    float4 right = rightVector * Input.Tex1.x * fParticleWidth;

    float4 up = upVector * Input.Tex1.y * fParticleHeight;

    float4 Pos = float4(Input.Position,0) + right + up;

    // Position = Pos + vt + 1/2*v*t*t

    float4 deltaVel = mul( float4(Input.Tex2,0), fLiveTime);

#ifdef v3dLinearForceAffector

    deltaVel = deltaVel + acceleration * fLiveTime * fLiveTime;

#endif

    Pos = Pos + deltaVel;

    Pos.w = 1.0;

    Out.Position = mul( Pos, matWorldViewProj );

    // color

    Out.Diffuse = Input.StartDiffuse;

#ifdef v3dColourFaderAffector

    Out.Diffuse.x = Input.StartDiffuse.x + time_colour.y*fLiveTime;

    Out.Diffuse.y = Input.StartDiffuse.y + time_colour.z*fLiveTime;

    Out.Diffuse.z = Input.StartDiffuse.z + time_colour.w*fLiveTime;

#endif

    // texcoord

    Out.Tex0 = Input.Tex0;

#ifdef AnimationTexture

    float fAnimTexLiveTime = fmod(fLiveTime, fAnimTexDuration);

    int iAnimTexCurrFrame = (fAnimTexLiveTime/fAnimTexDuration) * iAnimTexNumFrame;

    int iCurrX = iAnimTexCurrFrame % iAnimTexSideLength;

    int iCurrY = iAnimTexCurrFrame / iAnimTexSideLength;

    float2 fAnimTexCorrdXY;

    if( Input.Tex1.x < 0.f)

    {

        fAnimTexCorrdXY.x = (float)(iCurrX) / (float)(iAnimTexSideLength);        

    }

    else if( Input.Tex1.x > 0.f)

    {

        fAnimTexCorrdXY.x = (float)(iCurrX +1)/ (float)(iAnimTexSideLength);        

    }

    if( Input.Tex1.y < 0.f)

    {

        fAnimTexCorrdXY.y = (float)(iCurrY+1) / (float)(iAnimTexSideLength);

    }

    else if( Input.Tex1.x > 0.f)

    {

        fAnimTexCorrdXY.y = (float)(iCurrY) / (float)(iAnimTexSideLength);        

    }

    Out.Tex0 = fAnimTexCorrdXY;

#endif

#ifdef v3dColourImageAffector

    Out.Tex1 = float2(fLiveTime, 0.f);

#endif

#ifdef v3dRotationAffector

    float fRotTexDataBase[8] = {

                -0.5, 0.5,

                0.5, 0.5,

                -0.5,-0.5,

                0.5,-0.5 };   

    float fRotation = Input.Tex3.x + fLiveTime * Input.Tex3.y;

    float fSinRot, fCosRot;

    sincos( fRotation, fSinRot, fCosRot );

    float2 fRotTexCorrdXY;

    int iRotTexBaseIdx = Input.Tex3.z*2;

    fRotTexCorrdXY.x = (fCosRot * fRotTexDataBase[iRotTexBaseIdx]) + (fSinRot * fRotTexDataBase[iRotTexBaseIdx+1]) + 0.5;

    fRotTexCorrdXY.y = (fSinRot * fRotTexDataBase[iRotTexBaseIdx]) - (fCosRot * fRotTexDataBase[iRotTexBaseIdx+1]) + 0.5;

    Out.Tex0 = fRotTexCorrdXY;

#endif

    return Out;

}

float4 PS_1_1( VS_OUTPUT In ) : COLOR0

{

    float4 finalColour = float4( In.Diffuse, 0.f );

#ifdef v3dColourImageAffector

    finalColour *= tex2D( colourSampler, In.Tex1 );

#endif           

    finalColour *= tex2D( particleSampler, In.Tex0 );

    finalColour.w = 1.f;

    return finalColour;

}

technique tec0

{

    pass p0

    {

        VertexShader = compile vs_1_1 VS();

#ifdef v3dColourImageAffector

       PixelShader = compile ps_1_1 PS_1_1();//NULL;

#else

       PixelShader = NULL;

#endif           

    }

}

對發射器,效果器的支援程度

       Shader渲染器支援的屬性

              1, 預設高度

              2, 預設寬度

              3, 最大粒子數                    這裡代表同時存在的粒子數

              4, 粒子朝向

              5, 面向錄影機的方式

              6, 粒子UP向量          

              7, 是否是2D粒子系統

       支援所有發射器

              8, 支援發射器特有屬性(如圓環發射器的内環大小,外環大小)

              9, 角度

              10, 起始顔色

              11, 結束顔色

              12, 方向

              13, 最小生存期

              14, 最大生存期

              15, 最小速度

              16, 最大速度

              17, 位置

       支援的效果器及屬性

              18, 顔色衰減

              19, 線性外力: "外力" 指加速度a, 滿足公式s = vt + 1/2*a*t*t, 受力模式不起作用

              20, 旋轉

              21, 縮放

              22, 顔色衰減圖

       不支援狀态無關的效果器:

1, 碰撞體

2, 随機速度

3, 各種力場(直線力場,點力場)

項目改動

1, 對需要用GPU優化或需要使用GPU增強效果的粒子,美術編輯使用“Shader渲染器”的版本。

2, Shader渲染器實作版本的命名規則是在原有Billboard渲染器的檔案名後面加上 "_shader",程式通過檔案名區分不同的版本。

3, 在遊戲中加載粒子的時候

if( (有GPU實作版本) && (顯示卡支援該粒子要求的VS、PS版本))

        加載GPU實作版本

Else

        加載CPU實作版本

截圖

1, 旋轉

改進粒子系統-動态編譯Shader

2, 縮放,此處可以看到大部分是顯示卡運算

改進粒子系統-動态編譯Shader

3, 紋理動畫

改進粒子系統-動态編譯Shader

TODO

1, 解決粒子使用GPU處理和CPU處理的效果有些不同的問題

作者:fannyfish

Blog:http://blog.csdn.net/fannyfish

[email protected]

本文來自CSDN部落格,轉載請标明出處:http://blog.csdn.net/fannyfish/archive/2006/06/22/823032.aspx