Casino online









Mercato forex






B16. Creare una Reflection Map


Al pari di come abbiamo fatto precedentemente per la refraction map, anche in questo caso servono una Texture2D un RenderTarget2D e un metodo che disegni la riflessione. Nonostante ciò, in questo caso il procedimento è un tantino differente.


Schema della riflessione

Come si vede dallo schema, quando la telecamera guarda la superficie dell'acqua (in azzurro), essa non vede quello che sta sotto (stiamo parlando solo della riflessione, non fraintendetemi), ma vede invece quegli oggetti la cui luce viene riflessa nell'acqua con lo stesso angolo dello sguardo dell'osservatore (in verde). Quindi, per sapere cosa si dovrebbe poter cogliere tramite il fenomeno della riflessione, dato che non possiamo simulare il raggio di luce che rimbalza sull'acqua, dobbiamo ipotizzare di porci nella posizione speculare della telecamera (in viola) rispetto alla superficie acquea: guardando da quel punto di vista, potremo riprodurre la reflection map esattamente. L'unica cosa che ce lo impedisce è il fondo dei ruscelli, ma di quello non bisogna preoccuparsi: basta tagliar via con un piano di sezione tutto ciò che sta al di sotto della superficie, ossia il contrario di ciò che abbiamo fatto nella lezione scorsa.


Disegnare la Reflection Map
Come prima cosa, dichiariamo le nuove variabili, con le stesse finalità menzionate precedentemente:
    Private ReflectionTarget As RenderTarget2D
    Private ReflectionMap As Texture2D 
inizializziamo il render target:
    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")

        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()
        CopyToBuffer()

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

        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 
creiamo la mappa di riflessione:
    'Poiché dobbiamo ribaltare il punto di vista,
    'dovremo effettuare un po' di operazioncine con
    'vettori e matrici:
    Private Sub DrawReflectionMap()
        'Crea una matrice che rappresenta la rotazione
        'della telecamera
        Dim Rotation As Matrix = _
            Matrix.CreateRotationX(UpDownRotation) * _
            Matrix.CreateRotationY(LeftRightRotation)
        'Crea due vettori che rappresentano le direzioni
        '"avanti" e "destra" standard, prive di trasformzione. Serviranno
        'in seguito per alcuni calcoli
        Dim Forward As New Vector3(0, 0, -1)
        Dim Right As New Vector3(1, 0, 0)

        'Crea il vettore che indica il bersaglio di vista.
        'Essenzialmente, stiamo ricopiando un po' del codice
        'usato per gestire la telecamera
        Dim TargetPos As Vector3 = _
            CameraPosition + Vector3.Transform(Forward, Rotation)

        'Rappresenta la posizione della telecamera ribaltata
        Dim ReflectionPos As Vector3 = CameraPosition
        'E il suo relativo obbiettivo di vista, ribaltato
        Dim ReflectionTargetPos As Vector3 = TargetPos
        'Per "ribaltare" telecamera e obbiettivo, bisogna
        'usare una semplice formula matematica, ossia l'equazione
        'della simmetria assiale. Per un approfondimento, vedere
        'la spiegazione successiva
        ReflectionPos.Y = 2 * WaterHeight - ReflectionPos.Y
        ReflectionTargetPos.Y = 2 * WaterHeight - ReflectionTargetPos.Y

        'Crea il vettore "su" trasformato e ribaltato. Per far questo
        'non si può semplicement applicare la
        'rotazione al vettore "su" standard (0,1,0), perchè non
        'tiene conto della riflessione. In questo caso, calcoliamo il
        'vettore "destra" trasformato, poichè la simmetria assiale
        'modifica solo la coordinata Y e non la X (sulla quale si trova
        'la destra). Quindi eseguiamo un prodotto vettoriale tra
        'questo vettore e il vettore "avanti" riblatato, ottenuto
        'come differenza tra l'obbiettivo di vista e la posizione
        'ribaltata della telecamera. Vedere grafico a seguire per
        'capire meglio
        Dim ReflectionUp As Vector3 = Vector3.Cross( _
            Vector3.Transform(Right, Rotation), ReflectionTargetPos - ReflectionPos)
        'Infine calcoliamo la nuova matrice di vista con questi valori
        Dim ReflectionView As Matrix = Matrix.CreateLookAt( _
            ReflectionPos, ReflectionTargetPos, ReflectionUp)

        'Memorizza la vecchia matrice di vista
        Dim OldView As Matrix = ViewMatrix

        'Per far sì che tutto venga disegnato con la nuova
        'prospettiva, è necessario reimpostare la matrice di
        'vista globale.
        ViewMatrix = ReflectionView
        
        'Procede come prima per sezionare la scena. Notate che qui
        'uso True come terzo parametro per tagliar via la parte
        'inferiore
        Dim ReflectionPlane As Plane = _
            CreatePlane(WaterHeight - 0.5, New Vector3(0, -1, 0), True)
        Me.GraphicsDevice.ClipPlanes(0).Plane = ReflectionPlane
        Me.GraphicsDevice.ClipPlanes(0).IsEnabled = True
        Me.GraphicsDevice.SetRenderTarget(0, ReflectionTarget)
        Me.GraphicsDevice.Clear(ClearOptions.Target Or _
            ClearOptions.DepthBuffer, Color.Black, 1.0F, 0)
        DrawTerrain()
        'Qui c'è anche bisogno del cielo
        DrawSky()
        Me.GraphicsDevice.ClipPlanes(0).IsEnabled = False

        Me.GraphicsDevice.SetRenderTarget(0, Nothing)
        ReflectionMap = ReflectionTarget.GetTexture()
        Me.GraphicsDevice.Clear(Color.CornflowerBlue)

        'Reimposta la vecchia matrice di vista
        ViewMatrix = OldView
    End Sub 
Questo schema riassume tutti i vettori considerati:


Schema del calcolo

Ora vediamo di spiegare la simmetria assiale:


Simmetria assiale

Ammettiamo di avere un punto P, di coordinate (x, y) e una retta di equazione x = a, che rappresenta l'asse rispetto al quale si dovrà costruire il punto simmetrico. Partiamo dalla definizione di simmetra assiale, come segue: "la simmetria assiale è una biiezione del piano in sé che, ad ogni punto P associa un punto P1, tale che il segmento PP1 è perpendicolare all'asse di simmetria e l'intersezione tra questi dà il punto M, che è punto medio del segmento PP1". Perciò, come prima cosa, dobbiamo costruire la semiretta che parte da P perpendicolare all'asse: questo ci dice che il suo simmetrico avrà coordinata Y identica. L'intersezione di tale semiretta con l'asse ci fornisce il punto medio M: consideriamo quindi PM = k. Prolungando, avremo sulla stessa semiretta il punto P1 simmetrico, che deve soddisfare la stessa condizione P1M = k. Ora, per definizione abbiamo che y1 = y, e che, per costruzione, x1 = x + 2k. Sviluppiamo quest'ultima equazione:
x1 = x + 2k
  = x + 2(a - x)
  = x + 2a - 2x
  = 2a - x 
Questa è la seconda equazione della simmetria assiale, ossia quella che abbiamo usato nel codice di sopra, con a = WaterHeight e x alternativamente uguale alla Y dei due punti (ovviamente questo è un caso particolare: la simmetria vale sia su x che su y).
Se avete fatto tutto correttamente, dopo aver messo DrawReflectionMap() nel metodo Draw(), dovreste ottenere un risultato simile a questo (poi dipende da dove state guardando quando premete M):


Solo quello che si vede riflesso nell'acqua







 

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