0
\$\begingroup\$

Good afternoon,

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#?

UPDATE: RESOLVED

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.

\$\endgroup\$
3
  • 2
    \$\begingroup\$ Creating any object that uses underlying GPU resources every frame will definitely kill your performance. \$\endgroup\$ Commented Sep 8, 2013 at 23:53
  • \$\begingroup\$ You should post your solution as an answer, instead of an update to your question. \$\endgroup\$
    – House
    Commented Sep 9, 2013 at 5:28
  • \$\begingroup\$ Hi Byte56. I completely agree with you, but the site owners do not. If stack exchange would have allowed me to answer, and thus resolve, my own question, I would have. They enforce a waiting period, which I believe is now over... so here I am to take care of it. \$\endgroup\$
    – dpaz
    Commented Sep 18, 2013 at 21:30

1 Answer 1

1
\$\begingroup\$

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.

(answered after mandatory waiting period)

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .