Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
Terrain - Game.vb

Game.vb

Caricato da: Totem
Scarica il programma completo

  1. Imports Microsoft.Xna.Framework
  2. Imports Microsoft.Xna.Framework.Input
  3. Imports Microsoft.Xna.Framework.Graphics
  4.  
  5. Public Class Game
  6.     Inherits Microsoft.Xna.Framework.Game
  7.  
  8.     Private Graphics As GraphicsDeviceManager
  9.     Private Batch As SpriteBatch
  10.  
  11.     Private Structure VertexPositionNormalColored
  12.         Public Position As Vector3
  13.         Public Normal As Vector3
  14.         Public Color As Color
  15.  
  16.         Public Shared SizeInBytes As Int16 = 7 * 4
  17.         Public Shared VertexElements() As VertexElement = New VertexElement() _
  18.         { _
  19.             New VertexElement(0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0), _
  20.             New VertexElement(0, System.Runtime.InteropServices.Marshal.SizeOf(GetType(Double)) * 3, VertexElementFormat.Color, VertexElementMethod.Default, VertexElementUsage.Color, 0), _
  21.             New VertexElement(0, System.Runtime.InteropServices.Marshal.SizeOf(GetType(Double)) * 4, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Normal, 0) _
  22.         }
  23.     End Structure
  24.  
  25.     'Effetti - file: effects.fx
  26.     Private Effect As Effect
  27.     'Vertici
  28.     Private Vertices As VertexPositionNormalColored()
  29.     'Dichiarazione vertici. Avverte la scheda grafica del
  30.     'tipo di vertice che potrebbe ricevere
  31.     Private VDeclaration As VertexDeclaration
  32.  
  33.     Private Angle As Single = 0
  34.     Private Indices() As Int32
  35.     Private TerrainWidth As Int16 = 4
  36.     Private TerrainHeight As Int16 = 3
  37.     Private HeightData As Single(,)
  38.     Private HeightMap As Texture2D
  39.  
  40.     Private VertexToBuffer As VertexBuffer
  41.     Private IndexToBuffer As IndexBuffer
  42.  
  43.     Private ViewMatrix As Matrix
  44.     Private ProjectionMatrix As Matrix
  45.  
  46.     Private ReadOnly Property StartupPath() As String
  47.         Get
  48.             Return My.Application.Info.DirectoryPath
  49.         End Get
  50.     End Property
  51.  
  52.     Sub New()
  53.         Me.Graphics = New GraphicsDeviceManager(Me)
  54.         Me.Content.RootDirectory = "content"
  55.     End Sub
  56.  
  57.     Protected Overrides Sub Initialize()
  58.         Batch = New SpriteBatch(Me.Graphics.GraphicsDevice)
  59.         MyBase.Initialize()
  60.     End Sub
  61.  
  62.     Protected Overrides Sub LoadContent()
  63.         MyBase.LoadContent()
  64.  
  65.         Dim CompiledEffect As CompiledEffect = Microsoft.Xna.Framework.Graphics.Effect.CompileEffectFromFile(Me.StartupPath & "\effects.fx", Nothing, Nothing, CompilerOptions.None, TargetPlatform.Windows)
  66.         Effect = New Effect(Me.GraphicsDevice, CompiledEffect.GetEffectCode(), CompilerOptions.None, Nothing)
  67.  
  68.         HeightMap = Texture2D.FromFile(Me.GraphicsDevice, Me.StartupPath & "\heightmap.bmp")
  69.  
  70.         Me.LoadHeightdata(HeightMap)
  71.         Me.SetUpVertices()
  72.         Me.SetUpCamera()
  73.         Me.SetUpIndices()
  74.         Me.CalculateNormals()
  75.         Me.CopyToBuffer()
  76.     End Sub
  77.  
  78.     Protected Overrides Sub UnloadContent()
  79.         MyBase.UnloadContent()
  80.     End Sub
  81.  
  82.     Protected Overrides Sub Update(ByVal GameTime As GameTime)
  83.         Dim KeyState As KeyboardState = Keyboard.GetState
  84.         If KeyState.IsKeyDown(Keys.Left) Then
  85.             Angle -= 0.05
  86.         End If
  87.         If KeyState.IsKeyDown(Keys.Right) Then
  88.             Angle += 0.05
  89.         End If
  90.  
  91.         MyBase.Update(GameTime)
  92.     End Sub
  93.  
  94.     Protected Overrides Sub Draw(ByVal gameTime As Microsoft.Xna.Framework.GameTime)
  95.         Me.Graphics.GraphicsDevice.Clear(ClearOptions.Target Or ClearOptions.DepthBuffer, Color.CornflowerBlue, 1, 0)
  96.  
  97.         'Seleziona la tecnica da usare
  98.         Effect.CurrentTechnique = Effect.Techniques("Colored")
  99.  
  100.         Dim WorldMatrix As Matrix = _
  101.             Matrix.CreateTranslation(-Me.TerrainWidth / 2, 0, Me.TerrainHeight / 2) * _
  102.             Matrix.CreateRotationY(Angle)
  103.  
  104.         Effect.Parameters("xView").SetValue(ViewMatrix)
  105.         Effect.Parameters("xProjection").SetValue(ProjectionMatrix)
  106.         Effect.Parameters("xWorld").SetValue(WorldMatrix)
  107.  
  108.         'Imposta la direzione della luce
  109.         Dim LightDirection As New Vector3(1, 1.0F, 1.0F)
  110.         LightDirection.Normalize()
  111.  
  112.         'Abilita la luce
  113.         Effect.Parameters("xEnableLighting").SetValue(True)
  114.         'Imposta il vettore luce negli effetti
  115.         Effect.Parameters("xLightDirection").SetValue(LightDirection)
  116.         'Introduce un po' di luce d'ambiente. Questo evita che triangoli non
  117.         'colpiti direttamente dalla luce sia invisibili
  118.         Effect.Parameters("xAmbient").SetValue(0.1F)
  119.  
  120.         'Con questa opzione, verranno disegnati tutti i triangoli.
  121.         'Normalmente, quando CullMode è impostata diversamente, solo
  122.         'i triangoli rivolti verso la telecamera vengono visualizzati.
  123.         'Per sapere se un tringolo lo è, i suoi vertici devono essere definiti
  124.         'in senso orario rispetto alla telecamera
  125.         Me.GraphicsDevice.RenderState.CullMode = CullMode.None
  126.         'Me.GraphicsDevice.RenderState.FillMode = FillMode.WireFrame
  127.  
  128.         'Inizia il rendering
  129.         Effect.Begin()
  130.  
  131.         'Itera in ogni passo della tecnica usata
  132.         For Each Pass As EffectPass In Effect.CurrentTechnique.Passes
  133.             Pass.Begin()
  134.             Me.GraphicsDevice.VertexDeclaration = VDeclaration
  135.             Me.GraphicsDevice.Indices = IndexToBuffer
  136.             Me.GraphicsDevice.Vertices(0).SetSource(VertexToBuffer, 0, VertexPositionNormalColored.SizeInBytes)
  137.             Me.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, Vertices.Length, 0, Indices.Length / 3)
  138.             'Me.GraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, Vertices, 0, Vertices.Length, Indices, 0, Indices.Length / 3)
  139.             Pass.End()
  140.         Next
  141.         Effect.End()
  142.  
  143.         MyBase.Draw(gameTime)
  144.     End Sub
  145.  
  146.     Private Sub SetUpVertices()
  147.         ReDim Vertices(TerrainWidth * TerrainHeight)
  148.  
  149.  
  150.         'Minima e massima altezza rilevate nella texture
  151.         Dim MinHeight, MaxHeight As Int16
  152.  
  153.         MaxHeight = 0
  154.         MinHeight = 255
  155.         For X As Int16 = 0 To Me.TerrainWidth - 1
  156.             For Y As Int16 = 0 To Me.TerrainHeight - 1
  157.                 If HeightData(X, Y) > MaxHeight Then
  158.                     MaxHeight = HeightData(X, Y)
  159.                 End If
  160.                 If HeightData(X, Y) < MinHeight Then
  161.                     MinHeight = HeightData(X, Y)
  162.                 End If
  163.             Next
  164.         Next
  165.  
  166.         Dim StepVal As Single = (MaxHeight - MinHeight) / 4
  167.         For X As Int16 = 0 To TerrainWidth - 1
  168.             For Y As Int16 = 0 To TerrainHeight - 1
  169.                 With Me.Vertices(X + Y * TerrainWidth)
  170.                     .Position = New Vector3(X, Me.HeightData(X, Y), -Y)
  171.                     'Colora il vertice a seconda della sua altezza
  172.                     If HeightData(X, Y) < MinHeight + StepVal Then
  173.                         .Color = Color.LightBlue
  174.                     ElseIf HeightData(X, Y) < MinHeight + StepVal * 2 Then
  175.                         .Color = New Color(115, 171, 58)
  176.                     ElseIf HeightData(X, Y) < MinHeight + StepVal * 3 Then
  177.                         .Color = New Color(125, 85, 49)
  178.                     Else
  179.                         .Color = Color.White
  180.                     End If
  181.                 End With
  182.             Next
  183.         Next
  184.  
  185.         VDeclaration = New VertexDeclaration(Me.GraphicsDevice, VertexPositionNormalColored.VertexElements)
  186.     End Sub
  187.  
  188.     Private Sub SetUpCamera()
  189.         'Crea la matrice per la telecamera:
  190.         'argomento 1: posizione della telecamera
  191.         'argomento 2: posizione dell'oggetto che si sta guardando
  192.         'argomento 3: asse verticale
  193.         ViewMatrix = Matrix.CreateLookAt(New Vector3(0, 100, 100), New Vector3(0, 0, 0), New Vector3(0, 1, 0))
  194.         'Crea la matrice per il "modo di guardare" della telecamera
  195.         'arg 1: angolo di inclinazione della telecamera (radianti)
  196.         'arg 2: proporzione tra larghezza e altezza della finestra
  197.         'arg 3: valore single che determina il "near clipping plane". Oggetti meno distanti
  198.         '       dalla telecamera di questo valore non verranno disegnati
  199.         'arg 4: valore single che determina il "far clipping plane". Oggetto più distanti
  200.         '       dalla telecamera di questo valore non verranno disegnati
  201.         ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, Me.GraphicsDevice.Viewport.AspectRatio, 1.0, 300.0F)
  202.     End Sub
  203.  
  204.     Private Sub SetUpIndices()
  205.         ReDim Indices((Me.TerrainHeight - 1) * (Me.TerrainWidth - 1) * 6)
  206.  
  207.         Dim Counter As Int32 = 0
  208.  
  209.         For X As Int16 = 0 To Me.TerrainWidth - 2
  210.             For Y As Int16 = 0 To Me.TerrainHeight - 2
  211.                 Dim lowerLeft As Int16 = X + Y * TerrainWidth
  212.                 Dim lowerRight As Int16 = (X + 1) + Y * TerrainWidth
  213.                 Dim topLeft As Int16 = X + (Y + 1) * TerrainWidth
  214.                 Dim topRight As Int16 = (X + 1) + (Y + 1) * TerrainWidth
  215.  
  216.                 '1° triangolo
  217.                 Indices(Counter) = topLeft
  218.                 Indices(Counter + 1) = lowerRight
  219.                 Indices(Counter + 2) = lowerLeft
  220.                 Counter += 3
  221.  
  222.                 '2° triangolo
  223.                 Indices(Counter) = topLeft
  224.                 Indices(Counter + 1) = topRight
  225.                 Indices(Counter + 2) = lowerRight
  226.                 Counter += 3
  227.             Next
  228.         Next
  229.     End Sub
  230.  
  231.     Private Sub LoadHeightdata(ByVal HeightMap As Texture2D)
  232.         Me.TerrainWidth = HeightMap.Width
  233.         Me.TerrainHeight = HeightMap.Height
  234.  
  235.         Dim Colors(Me.TerrainHeight * Me.TerrainWidth - 1) As Color
  236.         HeightMap.GetData(Colors)
  237.  
  238.         ReDim HeightData(Me.TerrainWidth, Me.TerrainHeight)
  239.         For I As Int16 = 0 To Me.TerrainWidth
  240.             ReDim HeightData(I, Me.TerrainHeight)
  241.         Next
  242.  
  243.         For X As Int16 = 0 To Me.TerrainWidth - 1
  244.             For Y As Int16 = 0 To Me.TerrainHeight - 1
  245.                 HeightData(X, Y) = Colors(X + Y * Me.TerrainWidth).R / 5
  246.             Next
  247.         Next
  248.     End Sub
  249.  
  250.     Private Sub CalculateNormals()
  251.         'Calcola le normali di ogni vertice
  252.  
  253.         'Prima le azzera tutte
  254.         For Each V As VertexPositionNormalColored In Vertices
  255.             V.Normal = New Vector3(0, 0, 0)
  256.         Next
  257.  
  258.         For I As Int16 = 0 To (Indices.Length / 3) - 1
  259.             Dim Index1 As Int16 = Indices(I * 3)
  260.             Dim Index2 As Int16 = Indices(I * 3 + 1)
  261.             Dim Index3 As Int16 = Indices(I * 3 + 2)
  262.  
  263.             'Calcola i vettori che rappresentano due lati del triangolo
  264.             Dim Side1 As Vector3 = Vertices(Index1).Position - Vertices(Index3).Position
  265.             Dim Side2 As Vector3 = Vertices(Index1).Position - Vertices(Index2).Position
  266.             'Esegue un prodotto vettoriale, che restituisce un momento,
  267.             'perpendicolare al piano di giacenza degli altri due: la normale
  268.             Dim Normal As Vector3 = Vector3.Cross(Side1, Side2)
  269.  
  270.             Vertices(Index1).Normal += Normal
  271.             Vertices(Index2).Normal += Normal
  272.             Vertices(Index3).Normal += Normal
  273.         Next
  274.  
  275.         For Each V As VertexPositionNormalColored In Vertices
  276.             V.Normal.Normalize()
  277.         Next
  278.     End Sub
  279.  
  280.     Private Sub CopyToBuffer()
  281.         Me.VertexToBuffer = New VertexBuffer(Me.GraphicsDevice, Vertices.Length * VertexPositionNormalColored.SizeInBytes, BufferUsage.WriteOnly)
  282.         Me.VertexToBuffer.SetData(Vertices)
  283.         Me.IndexToBuffer = New IndexBuffer(Me.GraphicsDevice, GetType(Int32), Indices.Length, BufferUsage.WriteOnly)
  284.         Me.IndexToBuffer.SetData(Indices)
  285.     End Sub
  286. End Class