Quello che stiamo per fare non comporta nessun cambiamento nella visualizzazione del terreno, ma serve per alleviare il carico di
elaborazione della GPU. Anzichè passare gli array di Vertici e di Indici ogni volta come parametri del metodo di disegno, li incorporiamo
direttamente nel device grafico, per rendere più veloce il calcolo. Questo si fa utilizzando altre due semplici variabili, rispettivamente
di tipo VertexBuffer e IndexBuffer:
PublicClass Game
'...
'Dichiara i due nuovi buffer di vertici e di indiciPrivate VBuffer As VertexBuffer
Private IBuffer As IndexBuffer
'...PrivateSub CopyToBuffer()
'Inizializza il buffer di vertici. Il secondo
'parametro specifica quanta memoria occuperà il
'buffer, mentre il terzo dice alla GPU che quell'area
'è di sola scrittura
VBuffer = New VertexBuffer(Me.GraphicsDevice, _
Vertices.Length * VertexPositionNormalColor.SizeInBytes, _
BufferUsage.WriteOnly)
'E gli passa i dati veri e propri
VBuffer.SetData(Vertices)
'Inizializza il buffer di indici
IBuffer = New IndexBuffer(Me.GraphicsDevice, _
GetType(Int32), Indices.Length, BufferUsage.WriteOnly)
'E gli passa i dati veri e propri
IBuffer.SetData(Indices)
'Inserisce i buffer dentro il device graficoMe.GraphicsDevice.Indices = IBuffer
Me.GraphicsDevice.Vertices(0).SetSource( _
VBuffer, 0, VertexPositionNormalColor.SizeInBytes)
EndSub
'...ProtectedOverridesSub LoadContent()
Shader = GetEffect(AppPath & "\SimpleShader.fx")
LoadHeightMap(GetTexture(AppPath & "\HeightMap.bmp"))
SetVertices()
SetIndices()
SetNormals()
CopyToBuffer()
ViewMatrix = Matrix.CreateLookAt( _
New Vector3(70, 100, -70), _
New Vector3(0, 0, 0), _
New Vector3(0, 1, 0))
ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView( _
MathHelper.PiOver4, _
Me.GraphicsDevice.Viewport.AspectRatio, _
1, 500)
MyBase.LoadContent()
EndSub
'...ProtectedOverridesSub Draw(ByVal gameTime As GameTime)
Me.Graphics.GraphicsDevice.Clear(Color.CornflowerBlue)
Shader.CurrentTechnique = Shader.Techniques("ColoredPlus")
Shader.Parameters("View").SetValue(ViewMatrix)
Shader.Parameters("Projection").SetValue(ProjectionMatrix)
Shader.Parameters("World").SetValue( _
Matrix.CreateTranslation( _
New Vector3(-TerrainWidth / 2, 0, TerrainLength / 2)) * _
Matrix.CreateRotationY(Angle))
Dim LightDirection AsNew Vector3(-0.27, 0.33, -0.86)
LightDirection = Vector3.Transform(LightDirection, _
Matrix.CreateRotationY(Angle))
LightDirection.Normalize()
Shader.Parameters("LightEnabled").SetValue(True)
Shader.Parameters("LightDirection").SetValue(LightDirection)
Shader.Parameters("AmbientFactor").SetValue(0.1F)
Shader.Begin()
ForEach Pass As EffectPass In Shader.CurrentTechnique.Passes
Pass.Begin()
WithMe.GraphicsDevice
.VertexDeclaration = VDeclaration
'Ora che tutti i dati sono già caricati
'dentro il device, non c'è bisogno di
'passarli al metodo di disegno. Dobbiamo solo
'specificare offset e lunghezza, come facevamo
'primaMe.GraphicsDevice.DrawIndexedPrimitives( _
PrimitiveType.TriangleList, 0, 0, _
Vertices.Length, 0, Indices.Length / 3)
EndWith
Pass.End()
Next
Shader.End()
MyBase.Draw(gameTime)
EndSubEndClass
Non notere nessun cambiamento a prima vista, ma la vostra GPU vi ringrazierà!
Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Input
Imports Microsoft.Xna.Framework.Graphics
Imports System.Runtime.InteropServices
PublicClass Game
Inherits Microsoft.Xna.Framework.Game
#Region "Strutture aggiuntive"
PrivateShared DoubleSize AsByte = Marshal.SizeOf(GetType(Double))
PrivateStructure VertexPositionNormalColor
Public Position As Vector3
Public Normal As Vector3
Public Color As Color
PublicShared SizeInBytes As Int16 = 7 * 4
PublicShared VertexElements() As VertexElement = New VertexElement() _
{ _
New VertexElement(0, 0, VertexElementFormat.Vector3, _
VertexElementMethod.Default, _
VertexElementUsage.Position, 0), _
New VertexElement(0, DoubleSize * 3, _
VertexElementFormat.Color, _
VertexElementMethod.Default, _
VertexElementUsage.Color, 0), _
New VertexElement(0, DoubleSize * 4, _
VertexElementFormat.Vector3, _
VertexElementMethod.Default, _
VertexElementUsage.Normal, 0) _
}
EndStructure#End Region#Region "Variabili globali"
Private AppPath AsString = _
My.Application.Info.DirectoryPath
Private Graphics As GraphicsDeviceManager
Private Shader As Effect
Private Vertices() As VertexPositionNormalColor
Private Indices() As Int32
Private VBuffer As VertexBuffer
Private IBuffer As IndexBuffer
Private VDeclaration As VertexDeclaration
Private ViewMatrix As Matrix
Private ProjectionMatrix As Matrix
Private WorldMatrix As Matrix
Private DX, DZ AsSinglePrivate Angle AsSinglePrivate HeightData(,) AsSinglePrivateConst MinHeight AsSingle = 0
PrivateConst MaxHeight AsSingle = 30
Private TerrainWidth, TerrainLength As Int32
#End Region#Region "Funzioni utili"
PrivateFunction GetEffect(ByVal FileName AsString) As Effect
Dim CompEffect As CompiledEffect = _
Effect.CompileEffectFromFile(FileName, _
Nothing, Nothing, _
CompilerOptions.None, _
TargetPlatform.Windows)
ReturnNew Effect(Me.GraphicsDevice, _
CompEffect.GetEffectCode, _
CompilerOptions.None, Nothing)
EndFunctionPrivateFunction GetTexture(ByVal FileName AsString)
Return Texture2D.FromFile(Me.GraphicsDevice, FileName)
EndFunction#End Region#Region "Caricamento Heightmap"
PrivateSub LoadHeightMap(ByVal HeightMap As Texture2D)
TerrainWidth = HeightMap.Width
TerrainLength = HeightMap.Height '2D!Dim Colors(TerrainWidth * TerrainLength - 1) As Color
HeightMap.GetData(Colors)
For I As Int32 = 0 To TerrainWidth - 1
ReDim HeightData(I, TerrainLength - 1)
NextFor X As Int32 = 0 To TerrainWidth - 1
For Z As Int32 = 0 To TerrainLength - 1
HeightData(X, Z) = MinHeight + _
(Colors(X + Z * TerrainWidth).R / 255) * _
(MaxHeight - MinHeight)
NextNext
VDeclaration = New VertexDeclaration(Me.GraphicsDevice, _
VertexPositionNormalColor.VertexElements)
EndSubPrivateSub SetVertices()
ReDim Vertices(TerrainWidth * TerrainLength - 1)
Dim Strip AsSingle = (MaxHeight - MinHeight) / 4
For X As Int32 = 0 To TerrainWidth - 1
For Z As Int32 = 0 To TerrainLength - 1
With Vertices(X + Z * TerrainWidth)
Dim Y AsSingle = HeightData(X, Z)
.Position = New Vector3(X, Y, -Z)
If Y <= MinHeight + Strip Then
.Color = Color.LightBlue
ElseIf (Y > MinHeight + Strip) And _
(Y <= MinHeight + Strip * 2) Then
.Color = New Color(115, 171, 58)
ElseIf (Y > MinHeight + Strip * 2) And _
(Y <= MinHeight + Strip * 3) Then
.Color = New Color(125, 85, 49)
Else
.Color = Color.White
EndIfEndWithNextNextEndSubPrivateSub SetIndices()
ReDim Indices((TerrainWidth - 1) * (TerrainLength - 1) * 6 - 1)
Dim Counter As Int32 = 0
For X As Int32 = 0 To TerrainWidth - 2
For Z As Int32 = 0 To TerrainLength - 2
Dim LowerLeft As Int16 = X + Z * TerrainWidth
Dim LowerRight As Int16 = (X + 1) + Z * TerrainWidth
Dim TopLeft As Int16 = X + (Z + 1) * TerrainWidth
Dim TopRight As Int16 = (X + 1) + (Z + 1) * TerrainWidth
Indices(Counter) = TopLeft
Indices(Counter + 1) = LowerRight
Indices(Counter + 2) = LowerLeft
Counter += 3
Indices(Counter) = TopLeft
Indices(Counter + 1) = TopRight
Indices(Counter + 2) = LowerRight
Counter += 3
NextNextEndSubPrivateSub SetNormals()
For I As Int32 = 0 To Vertices.Length - 1
Vertices(I).Normal = New Vector3(0, 0, 0)
NextFor I As Int16 = 0 To (Indices.Length / 3) - 1
Dim Index1 As Int16 = Indices(I * 3)
Dim Index2 As Int16 = Indices(I * 3 + 1)
Dim Index3 As Int16 = Indices(I * 3 + 2)
Dim Side1 As Vector3 = _
Vertices(Index1).Position - Vertices(Index3).Position
Dim Side2 As Vector3 = _
Vertices(Index1).Position - Vertices(Index2).Position
Dim Normal As Vector3 = Vector3.Cross(Side1, Side2)
Vertices(Index1).Normal += Normal
Vertices(Index2).Normal += Normal
Vertices(Index3).Normal += Normal
NextForEach V As VertexPositionNormalColor In Vertices
V.Normal.Normalize()
NextEndSubPrivateSub CopyToBuffer()
VBuffer = New VertexBuffer(Me.GraphicsDevice, _
Vertices.Length * VertexPositionNormalColor.SizeInBytes, _
BufferUsage.WriteOnly)
VBuffer.SetData(Vertices)
IBuffer = New IndexBuffer(Me.GraphicsDevice, _
GetType(Int32), Indices.Length, BufferUsage.WriteOnly)
IBuffer.SetData(Indices)
Me.GraphicsDevice.Indices = IBuffer
Me.GraphicsDevice.Vertices(0).SetSource( _
VBuffer, 0, VertexPositionNormalColor.SizeInBytes)
EndSub#End Region#Region "Gestione risorse"
SubNew()
Me.Graphics = New GraphicsDeviceManager(Me)
Me.Content.RootDirectory = "content"
EndSubProtectedOverridesSub Initialize()
MyBase.Initialize()
EndSubProtectedOverridesSub LoadContent()
Shader = GetEffect(AppPath & "\SimpleShader.fx")
LoadHeightMap(GetTexture(AppPath & "\HeightMap.bmp"))
SetVertices()
SetIndices()
SetNormals()
CopyToBuffer()
ViewMatrix = Matrix.CreateLookAt( _
New Vector3(70, 100, -70), _
New Vector3(0, 0, 0), _
New Vector3(0, 1, 0))
ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView( _
MathHelper.PiOver4, _
Me.GraphicsDevice.Viewport.AspectRatio, _
1, 500)
MyBase.LoadContent()
EndSubProtectedOverridesSub UnloadContent()
MyBase.UnloadContent()
EndSub#End Region#Region "Aggiornamento mondo 3D"
ProtectedOverridesSub Update(ByVal GameTime As GameTime)
Angle += MathHelper.Pi / 600
MyBase.Update(GameTime)
EndSubProtectedOverridesSub Draw(ByVal gameTime As GameTime)
Me.Graphics.GraphicsDevice.Clear(Color.CornflowerBlue)
Shader.CurrentTechnique = Shader.Techniques("ColoredPlus")
Shader.Parameters("View").SetValue(ViewMatrix)
Shader.Parameters("Projection").SetValue(ProjectionMatrix)
Shader.Parameters("World").SetValue( _
Matrix.CreateTranslation( _
New Vector3(-TerrainWidth / 2, 0, TerrainLength / 2)) * _
Matrix.CreateRotationY(Angle))
Dim LightDirection AsNew Vector3(-0.27, 0.33, -0.86)
LightDirection = Vector3.Transform(LightDirection, _
Matrix.CreateRotationY(Angle))
LightDirection.Normalize()
Shader.Parameters("LightEnabled").SetValue(True)
Shader.Parameters("LightDirection").SetValue(LightDirection)
Shader.Parameters("AmbientFactor").SetValue(0.1F)
Shader.Begin()
ForEach Pass As EffectPass In Shader.CurrentTechnique.Passes
Pass.Begin()
WithMe.GraphicsDevice
.VertexDeclaration = VDeclaration
Me.GraphicsDevice.DrawIndexedPrimitives( _
PrimitiveType.TriangleList, 0, 0, _
Vertices.Length, 0, Indices.Length / 3)
EndWith
Pass.End()
Next
Shader.End()
MyBase.Draw(gameTime)
EndSub#End RegionEndClass
The Totem's Lair - Copyright (C) 2009
È vietata la riproduzione sia totale che parziale del sito.