Casino online









Mercato forex






B3. Trasformazioni del mondo 3D


Spesso è utile modificare la posizione di tutti gli oggetti della scena per dare particolari effetti. Questo viene fatto manipolando la matrice dedicata al mondo, che, nel tutorial precedente, abbiamo chiamato World.


Traslazioni
Ora proveremo a spostare il triangolo disegnato poco fa, eseguendo una traslazione sulla matrice World, che però non è stata ancora dichiarata. Allora, sotto a View e Projection, mettiamo anche World:
Private ViewMatrix As Matrix
Private ProjectionMatrix As Matrix
Private WorldMatrix As Matrix 
Ora vorremmo che, premendo i pulsanti direzionali il triangolo si sposti nelle relative direzioni. Per far questo c'è bisogno di memorizzare di quanto bisogna traslare, quindi servono altre due variabili: una per lo spostamento su X e una per quello su Z (ricordate che noi stiamo guardando dall'alto dritto verso il piano xz). Inoltre bisogna scrivere del codice nel metodo Update che controlli i tasti premuti, proprio come si faceva nella sezione A col 2D, e inoltre modificare Draw:
Public Class Game
    '...
    
    Private DX, DZ As Single
    
    '...
    
    Protected Overrides Sub Update(ByVal GameTime As GameTime)
        Dim KeyState As KeyboardState = Keyboard.GetState

        'Controlla i tasti premuti e modifica gli spostamenti di
        'conseguenza.
        'Ho messo 0.01 perchè il triangolo è molto
        'piccolo: infatti i suoi cateti misurano solo un'unità.
        If KeyState.IsKeyDown(Keys.Up) Then
            DZ -= 0.01
        End If
        If KeyState.IsKeyDown(Keys.Down) Then
            DZ += 0.01
        End If
        If KeyState.IsKeyDown(Keys.Left) Then
            DX -= 0.01
        End If
        If KeyState.IsKeyDown(Keys.Right) Then
            DX += 0.01
        End If

        MyBase.Update(GameTime)
    End Sub
    
    '...
    
    Protected Overrides Sub Draw(ByVal gameTime As GameTime)
        Me.Graphics.GraphicsDevice.Clear(Color.CornflowerBlue)

        Shader.Parameters("View").SetValue(ViewMatrix)
        Shader.Parameters("Projection").SetValue(ProjectionMatrix)
        'Ora la matrice World non sarà più inutile come
        'prima. Dato che dobbiamo spostare il triangolo, creeremo
        'una matrice di traslazione con la funzione statica
        'Matrix.CreateTranslation. Essa accetta un unico parametro
        'di tipo Vector3. In questo caso, siccome lo spostamento
        'avviene sul piano xz, la coordinata y sarà nulla.
        Shader.Parameters("World").SetValue( _ 
            Matrix.CreateTranslation(New Vector3(DX, 0, DZ)))

        Me.GraphicsDevice.RenderState.CullMode = CullMode.None

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

        MyBase.Draw(gameTime)
    End Sub
End Class 


Rotazioni
È anche possibile fare ruotare tutto. Le rotazioni avvengono sempre intorno al punto di origine (0,0,0) o, se si tratta di rotazioni su un solo asse, attorno al corrispondente asse cartesiano. Tutti gli angoli devono essere specificati in radianti. Per chi non conoscesse cos'è un radiante, lo spiego brevemente.
In trigonometria, si è soliti misurare tutti gli angoli in radianti poichè i valori così ottenuti sono particolarmente comodi per l'uso di funzioni quali seno, coseno, tangente, eccetera... Basti sapere che un angolo di 180 gradi equivale a un angolo di π radianti, perciò è possibile eseguire delle conversioni con una semplice proporzione: 180 : π = x(gradi) : y(radianti). In particolare, ci sono alcuni angoli usati molto di frequente, che sono: Ora faremo ruotare automaticamente il triangolo attorno all'asse Y:
Public Class Game
    '...
    
    'L'angolo di rotazione
    Private Angle As Single
    
    '...
    
    Protected Overrides Sub Update(ByVal GameTime As GameTime)
        Dim KeyState As KeyboardState = Keyboard.GetState

        If KeyState.IsKeyDown(Keys.Up) Then
            DZ -= 0.01
        End If
        If KeyState.IsKeyDown(Keys.Down) Then
            DZ += 0.01
        End If
        If KeyState.IsKeyDown(Keys.Left) Then
            DX -= 0.01
        End If
        If KeyState.IsKeyDown(Keys.Right) Then
            DX += 0.01
        End If

        'Aumentiamo automaticamente l'angolo. Con questo valore,
        'il triangolo dovrebbe eseguire una rotazione di 180°
        'in un secondo. Infatti la funzione Update viene
        'chiamata circa 60 volte al secondo
        Angle += MathHelper.Pi / 60
        MyBase.Update(GameTime)
    End Sub
    
    '...
    
    Protected Overrides Sub Draw(ByVal gameTime As GameTime)
        Me.Graphics.GraphicsDevice.Clear(Color.CornflowerBlue)

        Shader.CurrentTechnique = Shader.Techniques("Colored")
        Shader.Parameters("View").SetValue(ViewMatrix)
        Shader.Parameters("Projection").SetValue(ProjectionMatrix)
        'Trasliamo e ruotiamo insieme. La composizione di due
        'trasformazioni si effettua mediante moltiplicazione
        'delle due matrici
        Shader.Parameters("World").SetValue( _
            Matrix.CreateRotationY(Angle) * _
            Matrix.CreateTranslation(New Vector3(DX, 0, DZ)))

        Me.GraphicsDevice.RenderState.CullMode = CullMode.None

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

        MyBase.Draw(gameTime)
    End Sub
End Class 
Ora dovreste vedere il triangolo che ruota attorno al vertice rosso e, nel contempo, può ancora essere spostato con le frecce direzionali. A questo punto è necessario introdurre una essenziale chiarificazione.
Nei commenti del codice ho scritto che la composizione di due trasformazioni avviene mediante prodotto delle matrici che rapresentano tali trasformazioni. Non è necessario sapere come viene eseguita l'operazione, ma è importante essere al corrente del fatto che il prodotto matriciale NON è commutativo. In pratica, scrivere Rotazione*Traslazione e Traslazione*Rotazione dà due risultati diversi. Infatti, provate a scambiare le due operazioni: se il triangolo si trova esattamente al centro dello schermo, non c'è differenza, ma se viene traslato, non ruoterà più intorno al suo vertice rosso, ma descriverà una circonferenza intorno all'origine degli assi. Potete vedere la differenza in questi due video: In generale, le trasformazioni vengono eseguite nello stesso ordine in cui vengono scritte.


Similitudini
La similitudine è la definizione "matematica" della più comune scala. È possibile ridurre o ingrandire tutto il mondo o anche solo un particolare oggetto, proprio come abbiamo fatto con traslazioni e rotazioni. Non scriverò un nuovo codice anche per le trasformazioni di scala, poiché mi sembra di aver già chiarito tutti i punti chiave delle trasformazioni mediante matrici. L'unica cosa che c'è da sapere è che la funzione usata per creare un fattore di scala è Matrix.CreateScale(X, Y, Z), dove X, Y e Z sono i diversi fattori di zoom per ogni asse. Infatti è possibile "allungare" o "ridurre" qualsiasi oggetto 3D anche in una sola direzione, come se si trovasse su un foglio di gomma tirato alle estremità.



Per questi tutorial metterò, alla fine del capitolo, il codice completo degli esempi.







 

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