Casino online









Mercato forex






B18. Increspare l'acqua


Per creare delle increspature nell'acqua non c'è bisogno di modificare la sua superficie rendendola accidentata. Basta usare qualche trucchetto per farla sembrare così. Nella pratica, useremo un Bump Map (notate quante cose finiscono in "map" XD): essa è un'immagine in cui ogni componente di colore assume un preciso significato. Le coordinate R, G e B rappresentano rispettivamente X, Z e Y. Quindi ogni pixel della bump map rappresenta un vettore e questo vettore indica la normale della superficie in quel punto, ossia quanto è "perturbata". Useremo questa bump map:


La Bump Map


Modificare la tecnica Water
Ora che sappiamo come dare l'illusione delle increspature, bisogna modificare la tecnica Water nel file shader. Aggiungiamo un parametro addizionale, la texture BumpMap, e la sua variabile di tipo sampler:
float4x4 ReflectionView;
Texture ReflectionMap;
Texture RefractionMap;
Texture BumpMap;

//...

sampler BumpSampler = sampler_state
{
    texture = <BumpMap>;
    Magfilter = Linear;
    Minfilter = Linear;
    Mipfilter = Linear;
    AddressU = Mirror;
    AddressV = Mirror;
}; 
Inoltre, dichiariamo altri due membri: WaterLength (lunghezza d'onda) e WaterHeight (ampiezza dell'onda). In questo modo potremo modificare le increspature per simulare molti tipi di onda diversi.
float WaveLength;
float WaveHeight; 
Ora occorre modificare la struttura WaterVertexToPixel, per aggiungere un nuovo float2 che contiene la coordinata texture sulla bump map:
struct WaterVertexToPixel
{
    float4 Position           : POSITION;
    float4 ReflectionPos      : TEXCOORD1;
    float2 BumpPos            : TEXCOORD2;
}; 
E, infine, le due funzioni:
WaterVertexToPixel WaterVertexShader(float4 inPos : POSITION, 
    float2 inTex: TEXCOORD)
{    
    WaterVertexToPixel Output = (WaterVertexToPixel)0;

    float4x4 ViewProjection = mul(View, Projection);
    float4x4 WorldViewProjection = mul(World, ViewProjection);
    
    float4x4 ReflectionViewProjection = mul(ReflectionView, Projection);
    float4x4 WorldReflectionViewProjection = mul(World, ReflectionViewProjection);

    Output.Position = mul(inPos, WorldViewProjection);
    Output.ReflectionPos = mul(inPos, WorldReflectionViewProjection);
    //Questa operazione intende modificare le coordinate texture sulla
    //base della lunghezza d'onda. Infatti, quando si divide per
    //WaveLength, si otterranno valori tanto più grandi quanto
    //più basso è il suo valore. Questo produce l'effetto
    //che quando le onde sono lunghe fa sembrare i riflessi più
    //distesi.
    //Dividere un float2 per un numero equivale a dividere ogni componente
    //del float2 per quel numero
    Output.BumpPos = inTex / WaveLength;

    return Output;
}

WaterPixelToFrame  WaterPixelShader(WaterVertexToPixel inPixel)
{
    WaterPixelToFrame Output = (WaterPixelToFrame )0;        
    
    float2 TexCoords;
    TexCoords.x = (inPixel.ReflectionPos.x / inPixel.ReflectionPos.w) / 2.0f + 0.5f;
    TexCoords.y = -(inPixel.ReflectionPos.y / inPixel.ReflectionPos.w) / 2.0f + 0.5f; 
    
    //Ottiene il colore dalla Bump Map
    float4 BumpColor = tex2D(BumpSampler, inPixel.BumpPos);
    //Ottiene la perturbazione, come un vettore a due dimensioni: si prendono
    //i componenti r e g poiché corrispondono alle coordinate 3D x e z.
    //Infatti, nella texture abbiamo solo lunghezza (z) e larghezza (x), ma non
    //altezza (y). L'operazione di sottrarre 0.5 e molitplicare per due trasporta
    //un numero dall'intervallo [0,1] all'intervallo [-1,1]: la bump map
    //può anche diminuire i valori standard delle coordinate texture,
    //e non solo aumentarli. Infine, si moltiplica per l'ampiezza 
    //dell'onda: più essa sarà alta, e più distanti saranno i punti
    //che essa rifletterà
    float2 Perturbation = WaveHeight * (BumpColor.rg - 0.5f) * 2.0f;
    float2 NewTexCoords = TexCoords + Perturbation;
    
    Output.Color = tex2D(ReflectionSampler, NewTexCoords);    
    
    return Output;
} 


Modificare il programma
Prima carichiamo la Bump Map (ricordatevi di copiarla nella cartella bin/Debug del progetto):
    Private BumpMap As Texture2D

    '...
    
    Protected Overrides Sub LoadContent()
        Shader = GetEffect(AppPath & "\SimpleShader.fx")
        Grass = GetTexture(AppPath & "\grass.dds")
        Sand = GetTexture(AppPath & "\sand.dds")
        Rock = GetTexture(AppPath & "\rock.dds")
        Snow = GetTexture(AppPath & "\snow.dds")
        BumpMap = GetTexture(AppPath & "\BumpMap.jpg")

        For I As Byte = 0 To 4
            SkyFaces(I) = GetTexture(AppPath & "\skyface" & (I + 1) & ".png")
        Next

        Dim Params As PresentationParameters = _
            Me.GraphicsDevice.PresentationParameters

        RefractionTarget = New RenderTarget2D(Me.GraphicsDevice, _
            Params.BackBufferWidth, Params.BackBufferHeight, 1, _
            Me.GraphicsDevice.DisplayMode.Format)

        ReflectionTarget = New RenderTarget2D(Me.GraphicsDevice, _
            Params.BackBufferWidth, Params.BackBufferHeight, 1, _
            Me.GraphicsDevice.DisplayMode.Format)

        LoadHeightMap(GetTexture(AppPath & "\HeightMap.bmp"))
        LoadSkyDome()
        SetVertices()
        SetIndices()
        SetNormals()
        SetWaterVertices()
        CopyToBuffer()

        ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView( _
            MathHelper.PiOver4, _
            Me.GraphicsDevice.Viewport.AspectRatio, _
            1, 1000)

        CameraPosition = New Vector3(0, 40, TerrainLength / 2)
        Mouse.SetPosition(Me.GraphicsDevice.Viewport.Width / 2, _
                Me.GraphicsDevice.Viewport.Height / 2)
        PrevMouseState = Mouse.GetState
        UpdateView()

        MyBase.LoadContent()
    End Sub 
E poi la nuova tecnica DrawWater:
    Private Sub DrawWater(ByVal Time As Single)
        Shader.CurrentTechnique = Shader.Techniques("Water")

        Shader.Parameters("View").SetValue(ViewMatrix)
        Shader.Parameters("Projection").SetValue(ProjectionMatrix)
        Shader.Parameters("World").SetValue(Matrix.Identity)
        Shader.Parameters("ReflectionView").SetValue(ReflectionViewMatrix)
        Shader.Parameters("RefractionMap").SetValue(RefractionMap)
        Shader.Parameters("ReflectionMap").SetValue(ReflectionMap)
        'Imposta la bump map
        Shader.Parameters("BumpMap").SetValue(BumpMap)
        'La lunghezza d'onda
        Shader.Parameters("WaveLength").SetValue(0.1F)
        'E l'ampiezza dell'onda
        Shader.Parameters("WaveHeight").SetValue(0.3F)

        Dim Prev As CullMode = Me.GraphicsDevice.RenderState.CullMode
        Me.GraphicsDevice.RenderState.CullMode = CullMode.None

        Me.GraphicsDevice.Vertices(0).SetSource( _
            WaterVBuffer, 0, VertexPositionTexture.SizeInBytes)

        Shader.Begin()
        For Each Pass As EffectPass In Shader.CurrentTechnique.Passes
            Pass.Begin()
            With Me.GraphicsDevice
                .VertexDeclaration = WDeclaration
                Me.GraphicsDevice.DrawPrimitives( _ 
                    PrimitiveType.TriangleList, 0, WaterVertices.Length / 3)
            End With
            Pass.End()
        Next
        Shader.End()

        Me.GraphicsDevice.RenderState.CullMode = Prev
    End Sub 
Ed ecco il risultato:


Le onde nell'acqua







 

The Totem's Lair - Copyright (C) 2009
È vietata la riproduzione sia totale che parziale del sito.