Casino online









Mercato forex






B22. Camminare sul terreno


Bene, il paesaggio sembra avviarsi sempre di più verso una conclusione. Che ne dite se dessimo uno sguardo più da vicino? Nella fattispecie, avrei intenzione di camminarci sopra.


Una bella camminata
In verità non cammineremo veramente sul terreno, ma simuleremo una camminata. L'idea di base è molto semplice: quando ci troviamo in un punto del terreno, bisogna impostare la coordinata y della telecamera poco sopra quel punto. Facile, direte. Allora sperimentiamo la cosa prima diminuendo un po' MoveSpeed e poi modificando la procedura UpdatePosition, nella regione "Gestione telecamera":
    Private Sub UpdatePosition(ByVal Motion As Vector3)
        Dim Rotation As Matrix = _
            Matrix.CreateRotationX(UpDownRotation) * _
            Matrix.CreateRotationY(LeftRightRotation)
        Dim RotMotion As Vector3 = Vector3.Transform(Motion, Rotation)

        CameraPosition += RotMotion * MoveSpeed

        'Imposta la Y prendendola dalla height map, e aggiungendo un piccolo
        'fattore che permette di capire che siamo sopra il terreno
        CameraPosition.Y = HeightData(CameraPosition.X, _ 
            CameraPosition.Y) + 0.3F

        UpdateView()
    End Sub 
Avremo subito un errore di tipo IndexOutOfRangeException. In effetti, se ci pensiamo bene, la telecamera potrebbe anche trovarsi fuori dal terreno. Beh, non è un problema: noi ci muoveremo dentro di esso, e, qualora andassimo fuori, lasceremmo la liberà di movimento che c'era prima. Basta inserire un blocco Try per fermare l'eccezione:
    Private Sub UpdatePosition(ByVal Motion As Vector3)
        Dim Rotation As Matrix = _
            Matrix.CreateRotationX(UpDownRotation) * _
            Matrix.CreateRotationY(LeftRightRotation)
        Dim RotMotion As Vector3 = Vector3.Transform(Motion, Rotation)

        CameraPosition += RotMotion * MoveSpeed

        Try
            'CInt rende intere le variabili decimali
            CameraPosition.Y = HeightData(CInt(CameraPosition.X), _ 
                CInt(-CameraPosition.Z)) + 0.3F
        Catch Ex As Exception

        End Try

        UpdateView()
    End Sub 
Fate una prova. Non otterrete niente, ma noterete che se andate nell'angolo superiore destro del terreno, la vostra posizione su y cambia. Infatti, ci siamo dimenticati che le coordinate X e Z sono modificate: il terreno è stato, infatti, traslato verso l'orgine degli assi. Per ottenere le X e Z che corrispondono ai valori in HeightData, dobbiamo effettuare una trasformazione inversa alla traslazione originaria:
    Private Sub UpdatePosition(ByVal Motion As Vector3)
        Dim Rotation As Matrix = _
            Matrix.CreateRotationX(UpDownRotation) * _
            Matrix.CreateRotationY(LeftRightRotation)
        Dim RotMotion As Vector3 = Vector3.Transform(Motion, Rotation)

        CameraPosition += RotMotion * MoveSpeed

        Try
            CameraPosition.Y = HeightData( _
                CInt(CameraPosition.X + Me.TerrainWidth / 2), _
                CInt(-CameraPosition.Z + Me.TerrainLength / 2)) + 0.5F
        Catch Ex As Exception

        End Try

        UpdateView()
    End Sub 
Ora possiamo muoverci, ma il movimento è qualitativamente molto scadente: procede a scatti e ci fa vedere attraverso il terreno. Non è molto bello. Come si fa per procedere oltre?


Interpolazione Bilineare
Esiste una funzione matematica chiamata Interpolazione Bilineare che, in una funzione a tre dimensioni, dati in input quattro punti sul piano e le loro altezze è capace di approssimare con ottima precisione l'altezza di un punto qualsiasi compreso tra i quattro forniti. È quello che fa al caso nostro, infatti noi abbiamo solo una griglia di 256x256 valori. Possiamo sapere l'altezza del punto (0,0) e del punto (1,1), perchè le leggiamo dalla height map, ma non possiamo dire niente sull'altezza del punto (0.5,0.5), ad esempio. Per calcolarla occorre proprio l'interpolazione bilineare:
    Private Sub UpdatePosition(ByVal Motion As Vector3)
        Dim Rotation As Matrix = _
            Matrix.CreateRotationX(UpDownRotation) * _
            Matrix.CreateRotationY(LeftRightRotation)
        Dim RotMotion As Vector3 = Vector3.Transform(Motion, Rotation)

        CameraPosition += RotMotion * MoveSpeed

        Try
            Dim X1, X2, Z1, Z2 As Int32

            With CameraPosition
                'Arrotonda per eccesso e per difetto X e Z, ossia
                'prende i quattro punti che circondano l'attuale
                'posizione della telecamera sul piano
                X1 = CInt(Math.Floor(.X))
                X2 = CInt(Math.Ceiling(.X))
                Z1 = CInt(Math.Floor(.Z))
                Z2 = CInt(Math.Ceiling(.Z))
            End With

            'Se la telecamera si trova su un punto esattamente coincidente
            'con un elemento di heightdata, l'interpolazione bilineare non
            'funziona (infatti il denominatore della frazione diventa 0).
            'Allora la prende direttamente dalla matrice
            If X1 <> X2 And Z1 <> Z2 Then
                Dim Q11, Q12, Q21, Q22 As Single

                'Calcola le altezze corrispondenti ai quattro punti
                'prelevati prima. Ho usato Q perchè su wikipedia
                'la formula usa un Q, ma in questo specifico caso si
                'poteva anche mettere Y
                Q11 = HeightData(X1 + Me.TerrainWidth / 2, _ 
                    -Z1 + Me.TerrainLength / 2)
                Q12 = HeightData(X1 + Me.TerrainWidth / 2, _ 
                    -Z2 + Me.TerrainLength / 2)
                Q21 = HeightData(X2 + Me.TerrainWidth / 2, _ 
                    -Z1 + Me.TerrainLength / 2)
                Q22 = HeightData(X2 + Me.TerrainWidth / 2, _ 
                    -Z2 + Me.TerrainLength / 2)

                Dim X, Y, Z As Single

                X = CameraPosition.X
                Z = CameraPosition.Z

                'Esegue l'interpolazione bilineare
                Y = (Q11 * (X2 - X) * (Z2 - Z) + _
                    Q21 * (X - X1) * (Z2 - Z) + _
                    Q12 * (X2 - X) * (Z - Z1) + _
                    Q22 * (X - X1) * (Z - Z1)) / ((X2 - X1) * (Z2 - Z1))

                CameraPosition.Y = Y + 0.5F
            Else
                CameraPosition.Y = HeightData(X1 + Me.TerrainWidth / 2, _ 
                    -Z1 + Me.TerrainLength / 2)
            End If
        Catch Ex As Exception

        End Try

        UpdateView()
    End Sub 
Nel codice alla fine del capitolo ho sostituito il Try con un If, poiché il secondo usa meno memoria.








 

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