Normals in a triangle strip cube

Hi guys and gals,
I use DrawUserPrimitives with PrimitiveType.TriangleStrip to draw cubes with as few vertices as possible. Now my problem is, I want to light them, but setting vertex normals would be pretty useless, since the vertices belong to multiple triangles with differing triangle normals. How would I go about setting the normals in this case?

Here is the setup code for the cube:

private static VertexPositionColor[] CreateCubeMesh()
{
  // Algorithm from "Optimizing Triangle Strips for Fast Rendering"
  // by Francine Evans et al.

  var cube = new VertexPositionColor[8];

  cube[ 0 ].Position = new Vector3( .5f, .5f, .5f );
  cube[ 1 ].Position = new Vector3( -.5f, .5f, .5f );
  cube[ 2 ].Position = new Vector3( .5f, -.5f, .5f );
  cube[ 3 ].Position = new Vector3( -.5f, -.5f, .5f );
  cube[ 4 ].Position = new Vector3( .5f, .5f, -.5f );
  cube[ 5 ].Position = new Vector3( -.5f, .5f, -.5f );
  cube[ 6 ].Position = new Vector3( -.5f, -.5f, -.5f );
  cube[ 7 ].Position = new Vector3( .5f, -.5f, -.5f );

  for( var i = 0; i < 8; i++ )
  {
    cube[i].Color = Color.White;
  }

  return new[]
  {
    cube[ 3 ],
    cube[ 2 ],
    cube[ 6 ],
    cube[ 7 ],
    cube[ 4 ],
    cube[ 2 ],
    cube[ 0 ],
    cube[ 3 ],
    cube[ 1 ],
    cube[ 6 ],
    cube[ 5 ],
    cube[ 4 ],
    cube[ 1 ],
    cube[ 0 ]
  };
}

And the drawing code:

public override void Draw( Matrix viewMatrix, Matrix projectionMatrix )
{
  var effect = Entity.GetOrCreateComponent<BasicEffectComponent>().BasicEffect;

  effect.LightingEnabled = false;
  effect.View = viewMatrix;
  effect.Projection = projectionMatrix;
  effect.World = Entity.Transform.LocalToGlobalTransformation;

  foreach (var pass in effect.CurrentTechnique.Passes)
  {
    pass.Apply ();

    effect.GraphicsDevice.DrawUserPrimitives
    (
      PrimitiveType.TriangleStrip,
      Vertices,
      0,
      12
    );
  }
}

Cheers,
Georg

Edit: Or do I have to use a triangle list here, since for triangle strips per vertex normals are the only way to go?

A cube is defined by 6 points with 6 faces

Each face is two triangles and has it’s own normal

Consider a single vertex, it is part of three faces and hence needs three normals.

You need to switch to VertexPositionNormal and since a vertex cannot have more than one normal you need to duplicate vertices and set the normal accordingly

There are plenty of examples of how to do this out in the wild so you shouldn’t have any problem grabbing something you can use., for example…

https://www.dreamincode.net/forums/topic/285711-xna-draw-multiple-3d-cubes/

I had hope there would be a way to set vertices and per-face normals separately :wink:

Thanks for your answer.

You should split the vertices per normal and texture info, dont reuse them like you do.

Main rule btw: dont start prematurely spending much effort optimizing until you have actual performance issues that you can measure and study. This will give a much better solution than guessing what would run faster up front.

Further:

Issues with performance are not going to be prevented just by combining vertices like you do. If you get into performance trouble, solutions are, most of the time, to be found in the algorithmic and datastructure area. eg. If you have a huge number of cubes, you would need to split them into clusters and do frustumculling by rendering only clusters of your geometry that are currently in view of your camera. if you have a vast world that doesnt fit in videoram, you can load and unload clusters as needed (this is called world streaming) but i doubt this is your issue :slight_smile:

Also, In case of performance issues, try to prevent using DrawUserPrimitive. This will send all geometry data to the gpu each frame. Try using a VertexBuffer (and maybe an IndexBuffer) and DrawPrimitives() instead. This will push the data to the gpu only once and then reuse it each frame. Of course, changing vertexbuffer data each frame, would again send a lot of data over the bus, so you need to design your geometry data to have as much unchanging data as possible.

1 Like

Thanks for these hints :slight_smile: