XNA水面效果

Technorati 标签: xna,water effect,C#,.net,hlsl

几乎所有的室外场景游戏都少不了水面效果的渲染,基中主要包括波浪效果、反射效果、折射效果等,在这之前我对它可是一无所知,现在总算是有了初步的了解,主要是归功于XNA的快速。当然,我的主要目的还是对算法进行学习。

原理我还是不说,Google一下,讲的很好的。我这里主要有1Water类和一个VertexMultitextured结构体,还有一个Effect

用它做法线

Water类是实现水面效果的主要类

public class Water:DrawableGameComponent
{
    #region
字段

    Camera camera;

    private VertexBuffer vb;
    private IndexBuffer ib;
    VertexMultitextured[] myVertices;
    private int myHeight = 128;
    private int myWidth = 128;

    private Vector3 myPosition;
    private Vector3 myScale;
    private Quaternion myRotation;

    Effect effect;

    private Vector3 basePosition;

    public Vector3 Position
    {
        get { return basePosition; }
        set { basePosition = value; }
    }

    private string EnvAsset;

    float bumpHeight = 0.5f;
    Vector2 textureScale = new Vector2(4, 4);
    Vector2 bumpSpeed = new Vector2(0, .05f);
    float fresnelBias = .025f;
    float fresnelPower = 1.0f;
    float hdrMultiplier = 1.0f;
    Color deepWaterColor = Color.Black;
    Color shallowWaterColor = Color.SkyBlue;
    Color reflectionColor = Color.White;
    float reflectionAmount = 0.5f;
    float waterAmount = 0f;
    float waveAmplitude = 0.5f;
    float waveFrequency = 0.1f;

    /// <summary>
    ///
水面凹凸纹理高度,最小0,最大2,默认0.5
    /// </summary>
    public float BumpHeight
    {
        get { return bumpHeight; }
        set { bumpHeight = value; }
    }
    /// <summary>
    ///
凹凸纹理缩放倍数
    /// </summary>
    public Vector2 TextureScale
    {
        get { return textureScale; }
        set { textureScale = value; }
    }
    /// <summary>
    ///
水流速度
    /// </summary>
    public Vector2 BumpSpeed
    {
        get { return bumpSpeed; }
        set { bumpSpeed = value; }
    }
    /// <summary>
    /// 0
1 默认 0.025
    /// </summary>
    public float FresnelBias
    {
        get { return fresnelBias; }
        set { fresnelBias = value; }
    }
    /// <summary>
    ///0
10 默认 1.0;
    /// </summary>
    public float FresnelPower
    {
        get { return FresnelPower; }
        set { fresnelPower = value; }
    }
    /// <summary>
    /// 0
100 默认1.0
    /// </summary>
    public float HDRMultiplier
    {
        get { return hdrMultiplier; }
        set { hdrMultiplier = value; }
    }
    /// <summary>
    ///
深水处颜色;
    /// </summary>
    public Color DeepWaterColor
    {
        get { return deepWaterColor; }
        set { deepWaterColor = value; }
    }
    /// <summary>
    ///
浅水处颜色
    /// </summary>
    public Color ShallowWaterColor
    {
        get { return shallowWaterColor; }
        set { shallowWaterColor = value; }
    }
    /// <summary>
    ///
反射默认颜色
    /// </summary>
    public Color ReflectionColor
    {
        get { return reflectionColor; }
        set { reflectionColor = value; }
    }
    /// <summary>
    /// 0.0
2.0
    /// </summary>
    public float ReflectionAmount
    {
        get { return reflectionAmount; }
        set { reflectionAmount = value; }
    }

    public float WaterAmount
    {
        get { return waterAmount; }
        set { waterAmount = value; }
    }

    public float WaveAmplitude
    {
        get { return waveAmplitude; }
        set { waveAmplitude = value; }
    }

    public float WaveFrequency
    {
        get { return waveFrequency; }
        set { waveFrequency = value; }
    }

    public int Height
    {
        get { return myHeight; }
        set { myHeight = value; }
    }

    public int Width
    {
        get { return myWidth; }
        set { myWidth = value; }
    }

    #endregion

    public Water(Game game, string Environment,Camera camera): base(game)
    {
        myWidth = 256;
        myHeight = 256;

        myPosition = new Vector3(0, 0, 0);
        myScale = new Vector3(80,1,80);
        myRotation = new Quaternion(0, 0, 0, 1);

        EnvAsset = Environment;

        this.camera = camera;
    }

    protected override void LoadContent()
    {
        effect = Game.Content.Load<Effect>("Water");

        effect.Parameters["tEnvMap"].SetValue(Game.Content.Load<TextureCube>(EnvAsset));
        effect.Parameters["tNormalMap"].SetValue(Game.Content.Load<Texture2D>("waves"));

        myPosition = new Vector3(basePosition.X - (myWidth / 2), basePosition.Y, basePosition.Z - (myHeight / 2));

        // 顶点
        myVertices = new VertexMultitextured[myWidth * myHeight];

        for (int x = 0; x < myWidth; x++)
            for (int y = 0; y < myHeight; y++)
            {
                myVertices[x + y * myWidth].Position = new Vector3(y, 0, x);
                myVertices[x + y * myWidth].Normal = new Vector3(0, -1, 0);
                myVertices[x + y * myWidth].TextureCoordinate.X = (float)x / 30.0f;
                myVertices[x + y * myWidth].TextureCoordinate.Y = (float)y / 30.0f;
            }

        // 计算切线法线
        for (int x = 0; x < myWidth; x++)
            for (int y = 0; y < myHeight; y++)
            {
                //
切线数据.
                if (x != 0 && x < myWidth - 1)
                    myVertices[x + y * myWidth].Tangent = myVertices[x - 1 + y * myWidth].Position - myVertices[x + 1 + y * myWidth].Position;
                else
                    if (x == 0)
                        myVertices[x + y * myWidth].Tangent = myVertices[x + y * myWidth].Position - myVertices[x + 1 + y * myWidth].Position;
                    else
                        myVertices[x + y * myWidth].Tangent = myVertices[x - 1 + y * myWidth].Position - myVertices[x + y * myWidth].Position;

                // 法线数据.
                if (y != 0 && y < myHeight - 1)
                    myVertices[x + y * myWidth].BiNormal = myVertices[x + (y - 1) * myWidth].Position - myVertices[x + (y + 1) * myWidth].Position;
                else
                    if (y == 0)
                        myVertices[x + y * myWidth].BiNormal = myVertices[x + y * myWidth].Position - myVertices[x + (y + 1) * myWidth].Position;
                    else
                        myVertices[x + y * myWidth].BiNormal = myVertices[x + (y - 1) * myWidth].Position - myVertices[x + y * myWidth].Position;
            }

        vb = new VertexBuffer(Game.GraphicsDevice, VertexMultitextured.SizeInBytes * myWidth * myHeight, BufferUsage.WriteOnly);
        vb.SetData(myVertices);

        short[] terrainIndices = new short[(myWidth - 1) * (myHeight - 1) * 6];
        for (short x = 0; x < myWidth - 1; x++)
        {
            for (short y = 0; y < myHeight - 1; y++)
            {
                terrainIndices[(x + y * (myWidth - 1)) * 6] = (short)((x + 1) + (y + 1) * myWidth);
                terrainIndices[(x + y * (myWidth - 1)) * 6 + 1] = (short)((x + 1) + y * myWidth);
                terrainIndices[(x + y * (myWidth - 1)) * 6 + 2] = (short)(x + y * myWidth);

                terrainIndices[(x + y * (myWidth - 1)) * 6 + 3] = (short)((x + 1) + (y + 1) * myWidth);
                terrainIndices[(x + y * (myWidth - 1)) * 6 + 4] = (short)(x + y * myWidth);
                terrainIndices[(x + y * (myWidth - 1)) * 6 + 5] = (short)(x + (y + 1) * myWidth);
            }
        }

        ib = new IndexBuffer(Game.GraphicsDevice, typeof(short), (myWidth - 1) * (myHeight - 1) * 6, BufferUsage.WriteOnly);
        ib.SetData(terrainIndices);

        Game.GraphicsDevice.VertexDeclaration = new VertexDeclaration(Game.GraphicsDevice, VertexMultitextured.VertexElements);

        base.LoadContent();
    }

    public override void Update(GameTime gameTime)
    {
        effect.Parameters["fTime"].SetValue((float)gameTime.TotalRealTime.TotalSeconds);

        if (Keyboard.GetState().IsKeyDown(Keys.D1))
            WaterAmount = 0;

        if (Keyboard.GetState().IsKeyDown(Keys.D2))
        {
            WaterAmount = 1;
            ShallowWaterColor = Color.DarkSeaGreen;
            DeepWaterColor = Color.Navy;
            ReflectionColor = Color.DarkGray;
        }

        if (Keyboard.GetState().IsKeyDown(Keys.D3))
        {
            WaterAmount = 1;
            ShallowWaterColor = Color.Gold;
            DeepWaterColor = Color.Red;
            ReflectionColor = Color.White;
        }

        if (Keyboard.GetState().IsKeyDown(Keys.D4))
        {
            WaveFrequency = .5f;
            WaveAmplitude = .3f;
            BumpHeight = 1f;
        }

        if (Keyboard.GetState().IsKeyDown(Keys.D5))
        {
            WaveFrequency = .1f;
            WaveAmplitude = .1f;
            BumpHeight = .1f;
        }

        if (Keyboard.GetState().IsKeyDown(Keys.D6))
        {
            WaveFrequency = .1f;
            WaveAmplitude = .5f;
            BumpHeight = .1f;
        }

        if (Keyboard.GetState().IsKeyDown(Keys.D7))
        {
            WaveFrequency = .1f;
            WaveAmplitude = 2f;
            BumpHeight = 1f;
        }

        if (Keyboard.GetState().IsKeyDown(Keys.D8))
        {
            WaveFrequency = 0;
            WaveAmplitude = 0;
            BumpHeight = 0;
        }

        if (Keyboard.GetState().IsKeyDown(Keys.D9))
        {
            WaveFrequency = 0;
            WaveAmplitude = 0;
            BumpHeight = 1;
        }
        if (Keyboard.GetState().IsKeyDown(Keys.D0))
            SetDefault();

        base.Update(gameTime);
    }

    public override void Draw(GameTime gameTime)
    {
        Matrix World = Matrix.CreateScale(myScale) *
                        Matrix.CreateFromQuaternion(myRotation) *
                        Matrix.CreateTranslation(myPosition);

        Matrix WVP = World * camera.View * camera.Projection;
        Matrix WV = World * camera.View;
        Matrix viewI = Matrix.Invert(camera.View);

        effect.Parameters["matWorldViewProj"].SetValue(WVP);
        effect.Parameters["matWorld"].SetValue(World);
        effect.Parameters["matWorldView"].SetValue(WV);
        effect.Parameters["matViewI"].SetValue(viewI);

        effect.Parameters["fBumpHeight"].SetValue(bumpHeight);
        effect.Parameters["vTextureScale"].SetValue(textureScale);
        effect.Parameters["vBumpSpeed"].SetValue(bumpSpeed);
        effect.Parameters["fFresnelBias"].SetValue(fresnelBias);
        effect.Parameters["fFresnelPower"].SetValue(fresnelPower);
        effect.Parameters["fHDRMultiplier"].SetValue(hdrMultiplier);
        effect.Parameters["vDeepColor"].SetValue(deepWaterColor.ToVector4());
        effect.Parameters["vShallowColor"].SetValue(shallowWaterColor.ToVector4());
        effect.Parameters["vReflectionColor"].SetValue(reflectionColor.ToVector4());
        effect.Parameters["fReflectionAmount"].SetValue(reflectionAmount);
        effect.Parameters["fWaterAmount"].SetValue(waterAmount);
        effect.Parameters["fWaveAmp"].SetValue(waveAmplitude);
        effect.Parameters["fWaveFreq"].SetValue(waveFrequency);

        Game.GraphicsDevice.Vertices[0].SetSource(vb, 0, VertexMultitextured.SizeInBytes);
        Game.GraphicsDevice.Indices = ib;

        //Game.GraphicsDevice.RenderState.FillMode = FillMode.WireFrame;

        effect.Begin(SaveStateMode.SaveState);
        for (int p = 0; p < effect.CurrentTechnique.Passes.Count; p++)
        {
            effect.CurrentTechnique.Passes[p].Begin();

            Game.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, myWidth * myHeight, 0, (myWidth - 1) * (myHeight - 1) * 2);

            effect.CurrentTechnique.Passes[p].End();
        }
        effect.End();

        //Game.GraphicsDevice.RenderState.FillMode = FillMode.Solid;

        base.Draw(gameTime);
    }

    public void SetDefault()
    {
        bumpHeight = 0.5f;
        textureScale = new Vector2(4, 4);
        bumpSpeed = new Vector2(0, .05f);
        fresnelBias = .025f;
        fresnelPower = 1.0f;
        hdrMultiplier = 1.0f;
        deepWaterColor = Color.Black;
        shallowWaterColor = Color.SkyBlue;
        reflectionColor = Color.White;
        reflectionAmount = 0.5f;
        waterAmount = 0f;
        waveAmplitude = 0.5f;
        waveFrequency = 0.1f;
    }
}

VertexMultitextured结构体主要是水面的数据

public struct VertexMultitextured
{
    public Vector3 Position;
    public Vector3 Normal;
    public Vector2 TextureCoordinate;
    public Vector3 Tangent;
    public Vector3 BiNormal;

    public static int SizeInBytes = (3 + 3 + 2 + 3 + 3) * 4;
    public static VertexElement[] VertexElements = new VertexElement[]
         {
             new VertexElement( 0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0 ),
             new VertexElement( 0, sizeof(float) * 3, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Normal, 0 ),
             new VertexElement( 0, sizeof(float) * 6, VertexElementFormat.Vector2, VertexElementMethod.Default, VertexElementUsage.TextureCoordinate, 0 ),
             new VertexElement( 0, sizeof(float) * 8, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Tangent, 0 ),
             new VertexElement( 0, sizeof(float) * 11, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Binormal, 0 ),
         };

}

最重要的是Shader

float fTime    : Time;

//--------------------------------------------------
//
全局变量
//--------------------------------------------------
float4x4 matWorldViewProj     : WorldViewProjection;
float4x4 matWorld             : World;
float4x4 matWorldView        : WorldView;
float4x4 matViewI             : ViewInverse;

float fBumpHeight
<
    string UIName     = "Bump Height";
    string UIWidget = "Slider";
    float  UIMin     = 0.0f;
    float  UIMax     = 2.0f;
    float  UIStep     = 0.1f;
> = 0.5f;

float2 vTextureScale
<
    string UIName     = "Texture Scale";
    string UIWidget = "Vector";
> = { 4.0f, 4.0f };

float2 vBumpSpeed
<
    string UIName     = "Bump Speed";
    string UIWidget = "Vector";
> = { -0.0f, 0.05f };

float fFresnelBias
<
    string UIName     = "Fresnel Bias";
    string UIWidget = "Slider";
    float  UIMin     = 0.0f;
    float  UIMax     = 1.0f;
    float  UIStep     = 0.1f;
> = 0.025f;

float fFresnelPower
<
    string UIName     = "Fresnel Exponent";
    string UIWidget = "Slider";
    float  UIMin     = 1.0f;
    float  UIMax     = 10.0f;
    float  UIStep     = 0.1f;
> = 1.0f;

float fHDRMultiplier
<
    string UIName     = "HDR Multiplier";
    string UIWidget = "Slider";
    float  UIMin     = 0.0f;
    float  UIMax     = 100.0f;
    float  UIStep     = 1.0f;
> = 1.0f;

float4 vDeepColor : Diffuse
<
    string UIName     = "Deep Water Color";
    string UIWidget = "Vector";
> = { 0.0f, 0.40f, 0.50f, 1.0f };

float4 vShallowColor : Diffuse
<
    string UIName     = "Shallow Water Color";
    string UIWidget = "Vector";
> = { 0.55f, 0.75f, 0.75f, 1.0f };

float4 vReflectionColor : Diffuse
<
    string UIName     = "Reflection Color";
    string UIWidget = "Vector";
> = { 1.0f, 1.0f, 1.0f, 1.0f };

float fReflectionAmount
<
    string UIName     = "Reflection Amount";
    string UIWidget = "Slider";   
    float  UIMin     = 0.0f;
    float  UIMax     = 2.0f;
    float  UIStep     = 0.1f;   
> = 0.5f;

float fWaterAmount
<
    string UIName     = "Water Color Amount";
    string UIWidget = "Slider";   
    float  UIMin     = 0.0f;
    float  UIMax     = 2.0f;
    float  UIStep     = 0.1f;   
> = 0.5f;

float fWaveAmp
<
    string UIName     = "Wave Amplitude";
    string UIWidget = "Slider";
    float  UIMin     = 0.0f;
    float  UIMax     = 10.0f;
    float  UIStep     = 0.1f;
> = 0.5f;

float fWaveFreq
<
    string UIName     = "Wave Frequency";
    string UIWidget = "Slider";
    float  UIMin     = 0.0f;
    float  UIMax     = 1.0f;
    float  UIStep     = 0.001f;
> = 0.1f;

texture tNormalMap : Normal
<
    string UIName        = "Normal Map";
    string ResourceName = "waves2.dds";
    string TextureType = "2D";
>;

texture tEnvMap : Environment
<
    string UIName        = "Environment Map";
    string ResourceName = "CloudyHillsCubemap2.dds";
    string TextureType     = "Cube";
>;

sampler2D s0 = sampler_state {
    Texture = (tNormalMap);
    MipFilter     = Linear;
    MinFilter     = Linear;
    MagFilter     = Linear;
};

samplerCUBE s1 = sampler_state {
    Texture = (tEnvMap);
    MinFilter     = Linear;
    MagFilter     = Linear;
    MipFilter     = Linear;
};

//--------------------------------------------------
// Vertex shader
//--------------------------------------------------
struct VSOUTPUT {
    float4 vPos                : POSITION;
    float2 vTex                : TEXCOORD0;
    float3 vTanToCube[3]    : TEXCOORD1;
    float2 vBump0            : TEXCOORD4;
    float2 vBump1            : TEXCOORD5;
    float2 vBump2            : TEXCOORD6;
    float3 vView            : TEXCOORD7;
};

// 水波
struct Wave {
    float    fFreq;    //
频率 (2PI / 波长)
    float    fAmp;    //
振幅
    float    fPhase;    //
相伴 (速度 * 2PI / 波长)
    float2    vDir;    //
方向
};

#define NUMWAVES    3
Wave Waves[NUMWAVES] = {
    { 1.0f, 1.00f, 0.50f, float2( -1.0f, 0.0f ) },
    { 2.0f, 0.50f, 1.30f, float2( -0.7f, 0.7f ) },
    { .50f, .50f, 0.250f, float2( 0.2f, 0.1f ) },
};

float EvaluateWave( Wave w, float2 vPos, float fTime ) {
    return w.fAmp * sin( dot( w.vDir, vPos ) * w.fFreq + fTime * w.fPhase );
}

float EvaluateWaveDifferential( Wave w, float2 vPos, float fTime ) {
    return w.fAmp * w.fFreq * cos( dot( w.vDir, vPos ) * w.fFreq + fTime * w.fPhase );
}

float EvaluateWaveSharp( Wave w, float2 vPos, float fTime, float fK )
{
  return w.fAmp * pow( sin( dot( w.vDir, vPos ) * w.fFreq + fTime * w.fPhase )* 0.5 + 0.5 , fK );
}

float EvaluateWaveSharpDifferential( Wave w, float2 vPos, float fTime, float fK )
{
  return fK * w.fFreq * w.fAmp * pow( sin( dot( w.vDir, vPos ) * w.fFreq + fTime * w.fPhase )* 0.5 + 0.5 , fK - 1 ) * cos( dot( w.vDir, vPos ) * w.fFreq + fTime * w.fPhase );
}

VSOUTPUT VS_Water( float4 inPos : POSITION, float3 inNor : NORMAL, float2 inTex : TEXCOORD0,
                   float3 inTan : TANGENT, float3 inBin : BINORMAL ) {
    VSOUTPUT OUT = (VSOUTPUT)0;
    //
产生水波
    Waves[0].fFreq     = fWaveFreq;
    Waves[0].fAmp     = fWaveAmp;

    Waves[1].fFreq     = fWaveFreq * 2.0f;
    Waves[1].fAmp     = fWaveAmp * 0.5f;
    Waves[2].fFreq     = fWaveFreq * 3.0f;
    Waves[2].fAmp     = fWaveAmp * 1.0f;

    // 水波总数
    inPos.y = 0.0f;
    float ddx = 0.0f, ddy = 0.0f;
    for( int i = 0; i < NUMWAVES; i++ ) {
        inPos.y += EvaluateWave( Waves[i], inPos.xz, fTime );
        float diff = EvaluateWaveDifferential( Waves[i], inPos.xz, fTime);
        ddx += diff * Waves[i].vDir.x;
        ddy += diff * Waves[i].vDir.y;
    }

    // 输出position
    OUT.vPos = mul( inPos, matWorldViewProj );
    //
门生法线图texture coordinates
    OUT.vTex = inTex * vTextureScale;

    fTime = fmod( fTime, 100.0 );
    OUT.vBump0 = inTex * vTextureScale + fTime * vBumpSpeed;
    OUT.vBump1 = inTex * vTextureScale * 2.0f + fTime * vBumpSpeed * 4.0;
    OUT.vBump2 = inTex * vTextureScale * 4.0f + fTime * vBumpSpeed * 8.0;

    // 计算切线
    float3 vB = float3( 1,  ddx, 0 );
    float3 vT = float3( 0,  ddy, 1 );
    float3 vN = float3( -ddx, 1, -ddy );

    // Compute the tangent space to object space matrix
    float3x3 matTangent = float3x3( fBumpHeight * normalize( vT ),
                                    fBumpHeight * normalize( vB ),
                                    normalize( vN ) );
    OUT.vTanToCube[0] = mul( matTangent, matWorld[0].xyz );
    OUT.vTanToCube[1] = mul( matTangent, matWorld[1].xyz );
    OUT.vTanToCube[2] = mul( matTangent, matWorld[2].xyz );

    // 计算世界空间向量
    float4 vWorldPos = mul( inPos, matWorld );
    OUT.vView = matViewI[3].xyz - vWorldPos;
    return OUT;
}

//--------------------------------------------------
// Pixel shader
//--------------------------------------------------
float3 Refract( float3 vI, float3 vN, float fRefIndex, out bool fail )
{
    float fIdotN = dot( vI, vN );
    float k = 1 - fRefIndex * fRefIndex * ( 1 - fIdotN * fIdotN );
    fail = k < 0;
    return fRefIndex * vI - ( fRefIndex * fIdotN + sqrt(k) )* vN;
}

float4 PS_Water( VSOUTPUT IN ) : COLOR0 {

    // Fetch the normal maps (with signed scaling)
    float4 t0 = tex2D( s0, IN.vBump0 ) * 2.0f - 1.0f;
    float4 t1 = tex2D( s0, IN.vBump1 ) * 2.0f - 1.0f;
    float4 t2 = tex2D( s0, IN.vBump2 ) * 2.0f - 1.0f;

    float3 vN = t0.xyz + t1.xyz + t2.xyz;  

    // Compute the tangent to world matrix
    float3x3 matTanToWorld;
    matTanToWorld[0] = IN.vTanToCube[0];
    matTanToWorld[1] = IN.vTanToCube[1];
    matTanToWorld[2] = IN.vTanToCube[2];
    float3 vWorldNormal = mul( matTanToWorld, vN );
    vWorldNormal = normalize( vWorldNormal );

    // 计算反射向量
    IN.vView = normalize( IN.vView );
    float3 vR = reflect( -IN.vView, vWorldNormal );
    // Sample the cube map
    float4 vReflect = texCUBE( s1, vR.zyx );   
    vReflect = texCUBE( s1, vR );
    // Exaggerate the HDR effect
    vReflect.rgb *= ( 1.0 + vReflect.a * fHDRMultiplier );

    // Compute the Fresnel term
    float fFacing  = 1.0 - max( dot( IN.vView, vWorldNormal ), 0 );
    float fFresnel = fFresnelBias + ( 1.0 - fFresnelBias ) * pow( fFacing, fFresnelPower);

    // 计算最终颜色
    float4 vWaterColor = lerp( vDeepColor, vShallowColor, fFacing );

    return vWaterColor * fWaterAmount + vReflect * vReflectionColor * fReflectionAmount * fFresnel;
}

//--------------------------------------------------
// Techniques
//--------------------------------------------------
technique techDefault {
    pass p0 {
        CullMode        = None;
        VertexShader    = compile vs_2_0 VS_Water();
        PixelShader        = compile ps_2_0 PS_Water();
    }
}  

好了,代码出来了,下面可以看下实现后的效果。

   

有波浪的水面

平静的水面

这里也只算是一个比较基本的水面效果,而且出不够真实。还可以去完善一下。

posted @ 2008-10-10 05:23  齐.net  阅读(9111)  评论(8编辑  收藏  举报