I have been toying with the VertexBuffer in XNA just to see what it is capable of. I have done some very minor 3D work in the past, so the concepts are not completely foreign to me; however, my knowledge and experience leave a lot to be desired.
I have run a few tests in release mode with a static vertex buffer, using VertexPositionNormalTexture, and performance has been bugging me. My initial tests involved a rotating view of 40,000 (give or take) randomly generated cubes, with vertices for edges obscured by adjacent opaque cubes not added to the buffer. The view worked fine, but performance was notably choppy, expecially when the corner of the randomized area rotated into view.
My first idea to optimize was to combine adjacent, parallel faces into single, continuous faces, and adjust the Vector2 texture coordinates to appropriately draw the repeating texture; however, when I tested a single rotating cube (36 total vertices) with each side showing 100x100 tiled repetitions of the texture, I experienced pretty much the exact same stuttering problem.
So I have to ask, what might I be doing wrong? Should I render my own pre-tiled RenderTarget2D textures to use with the static vertex buffer, so the GPU does not have to "tile" it so many times? Or does the GPU do that already on its own?
My vertex buffer is generated only once and sent to the GPU only once. My texture is loaded only once, and the same texture/effect is used for the entire vertex buffer.
I do not understand why a GTX 275 would have such a hard time drawing 12 textured triangles.
What am I missing?
From my custom Chunk class:
let construct() = _vertices <- _blocks.Values |> Seq.collect Block.vertices |> Seq.toArray let vertexCount = _vertices.Length if vertexCount > 0 then _buffer <- new VertexBuffer(device, VertexPositionNormalTexture.VertexDeclaration, vertexCount, BufferUsage.None) _buffer.SetData(_vertices) device.SetVertexBuffer(_buffer) _requiresConstruction <- false member public m.DrawToDevice(device : GraphicsDevice) = if _requiresConstruction then construct() let vertexCount = _vertices.Length if vertexCount > 0 then let triangleCount = vertexCount / 3 device.DrawPrimitives(PrimitiveType.TriangleList, 0, triangleCount)
From the Game-derived class:
override game.Draw gameTime = let skyColor = Color.CornflowerBlue game.GraphicsDevice.Clear(skyColor) let fogColor = skyColor.ToVector3() let effect = new BasicEffect(device) let cameraPosition = Vector3(0.0f, 0.0f, 125.0f) effect.World <- Matrix.CreateTranslation(chunk.ChunkPosition); effect.View <- Matrix.CreateRotationY(MathHelper.ToRadians(rotation)) * Matrix.CreateRotationX(MathHelper.ToRadians(rotation)) * Matrix.CreateLookAt(cameraPosition, chunk.ChunkPosition, Vector3.Up); let viewDistance = 250.0f effect.Projection <- Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, device.Viewport.AspectRatio, 1.0f, viewDistance); effect.FogEnabled <- true effect.FogColor <- fogColor effect.FogStart <- viewDistance / 3.0f effect.FogEnd <- viewDistance effect.TextureEnabled <- true effect.Texture <- sprite effect.EnableDefaultLighting() for pass in effect.CurrentTechnique.Passes do pass.Apply() chunk.DrawToDevice(device) base.Draw(gameTime)
sprite is a 20x20 Texture2D loaded from content
UPDATE: I tried the massive, single cube again, two ways:
- With a single, non-tiled, pre-stretched texture
- With a single, non-tiled, texture, stretched using Vector2 texture positions.
Both of them exhibit the exact same stuttering behavior I had before. Something must be wrong here. 36 vertices. Non-tiled 20x20 texture. Static vertex buffer. How on earth could this be stuttering on a machine that runs modern 3D games without issue?
Does XNA simply not play well with F#?
The problem seems to have been recreating effect each frame.
I moved all effect code except for the following into m.LoadContent:
// Set the World matrix which defines the position of the cube effect.World <- Matrix.CreateTranslation(chunk.ChunkPosition); // Set the View matrix which defines the camera and what it's looking at effect.View <- Matrix.CreateRotationY(MathHelper.ToRadians(rotation)) * Matrix.CreateRotationX(MathHelper.ToRadians(rotation)) * Matrix.CreateLookAt(cameraPosition, chunk.ChunkPosition, Vector3.Up); effect.FogColor <- fogColor
CPU use dropped from 13% while corners rotating into/out of view, to 0-4%. No more stuttering.
Thanks anyway, though I would still certainly appreciate any tips.