Casino online









Mercato forex






B4. Gli Indici


Fin'ora ci siamo limitati a disegnare un solo triangolo. Proviamo ad aumentare un po' il numero.


Quattro triangoli, dodici vertici
Ora che abbiamo finito di sondare le matrici, ripartiamo dai triangoli e, anziché disegnarne uno solo, definiamo 12 vertici, per 4 triangoli, in modo da formare due quadrati adiacenti:
Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Input
Imports Microsoft.Xna.Framework.Graphics

Public Class Game
    Inherits Microsoft.Xna.Framework.Game

    Private AppPath As String = _
        My.Application.Info.DirectoryPath

    Private Graphics As GraphicsDeviceManager

    Private Shader As Effect
    Private Vertices(11) As VertexPositionColor
    Private VDeclaration As VertexDeclaration

    Private ViewMatrix As Matrix
    Private ProjectionMatrix As Matrix
    Private WorldMatrix As Matrix

    Private DX, DZ As Single
    Private Angle As Single

    Private Function GetEffect(ByVal FileName As String) As Effect
        Dim CompEffect As CompiledEffect = _
            Effect.CompileEffectFromFile(FileName, _
            Nothing, Nothing, _
            CompilerOptions.None, _
            TargetPlatform.Windows)

        Return New Effect(Me.GraphicsDevice, _
            CompEffect.GetEffectCode, _
            CompilerOptions.None, Nothing)
    End Function

    Private Sub SetVertices()
        'Per questo esempio, disegneremo solo i contorni dei
        'triangoli, tutti in bianco. Perciò imposteremo
        'il colore di tutti i vertici alla fine

        'Primo triangolo
        Vertices(0).Position = New Vector3(0, 0, 0)
        Vertices(1).Position = New Vector3(1, 0, -1)
        Vertices(2).Position = New Vector3(0, 0, -1)

        'Secondo triangolo
        Vertices(3).Position = New Vector3(0, 0, 0)
        Vertices(4).Position = New Vector3(1, 0, -1)
        Vertices(5).Position = New Vector3(1, 0, 0)

        'Terzo triangolo
        Vertices(6).Position = New Vector3(1, 0, 0)
        Vertices(7).Position = New Vector3(1, 0, -1)
        Vertices(8).Position = New Vector3(2, 0, -1)

        'Quarto triangolo
        Vertices(9).Position = New Vector3(1, 0, 0)
        Vertices(10).Position = New Vector3(2, 0, -1)
        Vertices(11).Position = New Vector3(2, 0, 0)

        'Imposta il colore di tutti
        For I As Byte = 0 To 11
            Vertices(I).Color = Color.White
        Next

        VDeclaration = New VertexDeclaration(Me.GraphicsDevice, _
            VertexPositionColor.VertexElements)
    End Sub

    Sub New()
        Me.Graphics = New GraphicsDeviceManager(Me)
        Me.Content.RootDirectory = "content"
    End Sub

    Protected Overrides Sub Initialize()
        MyBase.Initialize()
    End Sub

    Protected Overrides Sub LoadContent()
        Shader = GetEffect(AppPath & "\SimpleShader.fx")
        SetVertices()

        'Per questo esempi ci spostiamo un po' più in alto
        'e inoltre guardiamo i triangoli di sbieco
        ViewMatrix = Matrix.CreateLookAt( _
            New Vector3(-3, 6, 3), _
            New Vector3(0, 0, 0), _
            New Vector3(0, 1, 0))

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

        MyBase.LoadContent()
    End Sub

    Protected Overrides Sub UnloadContent()
        MyBase.UnloadContent()
    End Sub

    Protected Overrides Sub Update(ByVal GameTime As GameTime)
        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)
        'Per ora teniamo l'identità
        Shader.Parameters("World").SetValue(Matrix.Identity)

        Me.GraphicsDevice.RenderState.CullMode = CullMode.None
        'Ora vogliamo vedere solo i bordi dei triangoli. Questo
        'si fa attivando l'opzione wireframe ("telaio di fili",
        'o, più liberamente, "fil di ferro")
        Me.GraphicsDevice.RenderState.FillMode = FillMode.WireFrame

        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 
E dovreste ottenere questo risltato:


I quattro triangoli

Prima di procedere vorrei spiegare il primo parametro di DrawUserPrimitives, che non avevo spiegato nei tutorial precedenti. In sostanza è un enumeratore che descrive come devono essere trattati i vertici per disegnare i triangoli, e può assumere questi valori:


Esempi di primitive

Bene, ora andiamo avanti: 6 triangoli, 18 vertici; 10 triangoli, 30 vertici; 100 triangoli, 300 vertici... Anche se forse è un po' eccessivo. Dobbiamo trovare una soluzione di qualche tipo per ridurre il numero dei vertici, se ne esiste una...


Uso degli indici
La soluzione c'è e va sotto il nome di Indici. Infatti, avrete notato che per dichiarare dei triangoli così attaccati, abbiamo utilizzato più volte le stesse coordinate. Quindi, se riuscissimo a eliminare i doppioni avremmo bisogno di solo 6 vertici per definire 4 triangoli, ossia la metà di quelli che usavamo prima. Per far questo, si assegna un numero intero (indice) ad ogni vertice e invece di dire da quali vertici è formato un triangolo, diciamo da quali indici sono contrassegnati i suoi vertici. Ad esempio, nel caso di prima possiamo prendere questa figura:


L'indice di ogni vertice è semplicemente il suo indice nell'array

Allora il primo triangolo sarà formato dai vertici 1, 0, 2; il secondo da 2, 0, 3, eccetera... (notare che li ho dichiarati in senso orario stavolta). Allora iniziamo a scrivere il codice, modificando i vecchi metodi:
Public Class Game
    
    '...
    
    'Ora ci servono solo 6 vertici
    Private Vertices(5) As VertexPositionColor
    'Ma dato che dovremo pur sempre definire tre
    'punti per ogni triangolo, saranno necessari
    'sempre 12 indici
    Private Indices(11) As Int32
    
    Private Sub SetVertices()
        'Imposta i sei vertici
        
        Vertices(0).Position = New Vector3(0, 0, -1)
        Vertices(1).Position = New Vector3(0, 0, 0)
        Vertices(2).Position = New Vector3(1, 0, 0)
        Vertices(3).Position = New Vector3(1, 0, -1)
        Vertices(4).Position = New Vector3(2, 0, -1)
        Vertices(5).Position = New Vector3(2, 0, 0)

        'Imposta il colore di tutti
        For I As Byte = 0 To 5
            Vertices(I).Color = Color.White
        Next

        'Primo triangolo
        Indices(0) = 1
        Indices(1) = 0
        Indices(2) = 2

        'Secondo triangolo
        Indices(3) = 2
        Indices(4) = 0
        Indices(5) = 3

        'Terzo triangolo
        Indices(6) = 2
        Indices(7) = 3
        Indices(8) = 4

        'Quarto triangolo
        Indices(9) = 2
        Indices(10) = 4
        Indices(11) = 5

        VDeclaration = New VertexDeclaration(Me.GraphicsDevice, _
            VertexPositionColor.VertexElements)
    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)
        'Per ora teniamo l'identità
        Shader.Parameters("World").SetValue(Matrix.Identity)

        Me.GraphicsDevice.RenderState.CullMode = CullMode.None
        Me.GraphicsDevice.RenderState.FillMode = FillMode.WireFrame

        Shader.Begin()
        For Each Pass As EffectPass In Shader.CurrentTechnique.Passes
            Pass.Begin()
            With Me.GraphicsDevice
                .VertexDeclaration = VDeclaration
                'Dato che ora usiamo gli indici, dobbiamo cambiare
                'metodo: sostituiamo quello vecchio con questo.
                'I primi tre parametri sono uguali. Il quarto
                'definisce quanti vertici siano da considerare (noi
                'li prendiamo tutti). Il quinto specifica l'array
                'da cui estrarre gli indici (Indices), mentre il
                'sesto imposta l'offset, che è sempre 0.
                'L'ultimo richiede il numero di triangoli da disegnare:
                'dato che ogni triangolo è determinato da tre
                'indici, il numero di triangoli sarà
                '1/3 di quello degli indici.
                .DrawUserIndexedPrimitives(PrimitiveType.TriangleList, _
                    Vertices, 0, Vertices.Length, _
                    Indices, 0, Indices.Length / 3)
            End With
            Pass.End()
        Next
        Shader.End()

        MyBase.Draw(gameTime)
    End Sub
End Class 
Potete anche provare a togliere questa riga di codice:
Me.GraphicsDevice.RenderState.CullMode = CullMode.None 
e vedrete che il risultato è lo stesso: infatti, nella definizione degli indici, ho di proposito messo tutti i numeri in senso orario, in modo che vengano visualizzati dalla telecamera anche senza l'opzione CullMode=None.
Adesso, se anche volessimo cambiare un vertice, potremmo anche stare tranquilli che verrebbe tutto renderizzato nel migliore dei modi. Ad esempio, alziamone uno (l'ultimo) di un'unità. Senza cambiare niente otteniamo un bel risultato:


Un vertice alzato

Il nostro obbiettivo è disegnare un intero paesaggio usando queste tecniche, ma farlo a mano è un po' (molto) noioso. Nel prossimo tutorial cercheremo di automatizzare il tutto.









 

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