@c -*-texinfo-*-
@node 3D Sprites, , mdl2spr, Working with Engine Content
@section 3D Sprites
@cindex 3D Sprites

@noindent
@emph{Written by Seth Galbraith, @email{sgalbrai@@linknet.kitsap.lib.wa.us}.}

3D @dfn{sprites} are triangle-based models which can be animated by
pre-calculated vertex animations.  This type of model is well suited for
detailed models which are not easily represented as heightmapped terrain or
bezier curves. 3D sprites can be used in your application through the
mesh object plugin systems (i.e. a 3D sprite is one particular type of
mesh object). @xref{MeshObject}.

@menu
* 3D Sprites Example 1:: A Simple 3D Sprite
* 3D Sprites Example 2:: Texturing
* 3D Sprites Example 3:: Shading
@end menu

@node 3D Sprites Example 1, 3D Sprites Example 2, 3D Sprites, 3D Sprites
@subsection A Simple 3D Sprite

Let us consider a simple 3D sprite---a 24 sided prism meant to look like a
cylinder.  Each side is made from two triangles, and the ends are made
from 24 polygons (you could make the ends from 23 polygons, but that's not
how artists do things :-).

@ifnotinfo
@picturess{content,sprites,cylinder}

@end ifnotinfo
This sprite has 96 triangles.  If we treat each triangle as a separate
object, it has 288 vertices.  Every frame each of those 288 vertices has
to be transformed from local coordinates to screen space coordinates.

Each vertex is also consuming some memory.  If each vertex only has
three 32 bit float coordinates, then the sprite uses 3456 bytes of memory,
but in practice each vertex also has texture alignment, color, and
surface normal data, and if the sprite has precalculated animation, that
data is multiplied by the number of frames.

However, the 3D sprite structure is compressed so that triangles can share
vertices.  Instead of 288 vertices, the cylinder sprite has 48 vertices
shared by the 96 triangles.  Each triangle is simply three indices to
to the vertex list.

@itemize @bullet
@item
Vertices
@itemize @minus
@item
3D Coordinates (X, Y, Z)
@item
Texture Coordinates (U, V)
@item
Color (R, G, B)
@item
Surface Normal (X, Y, Z)
@end itemize
@item
Triangles
@itemize @minus
@item
First Vertex Index
@item
Second Vertex Index
@item
Third Vertex Index
@end itemize
@end itemize

@node 3D Sprites Example 2, 3D Sprites Example 3, 3D Sprites Example 1, 3D Sprites
@subsection Texturing

Our next challenge is texturing the sprite.  To apply a two dimensional
texture to the 3D sprite we need to flatten it.  If we have 288 separate
vertices (@pxref{3D Sprites Example 1}), we can flatten the sprite any way we
want, but when the triangles are sharing vertices we cannot separate them,
and a flattened cylinder is sometimes difficult to texture.  Either the sides
will be curved or the ends will be flattened.

We probably want to texture the sides as a single rectangular area and
each end as a rough circle.  So we separate the ends from the sides.  This
doubles the number of vertices.  Cutting one edge of the sides so it can be
unwrapped adds two more vertices.

@ifnotinfo
@picturess{content,sprites,skin}

@end ifnotinfo
Now we have 98 vertices instead of 48.  This is a big hit, but it may be
necessary to get the artwork done fast and well.  Fortunately, we still have
only 98 vertices instead of 288, but can we do better than that?  Do we have
to duplicate the 3D coordinates just because we need more texture coordinates?

We experimented with a system where the sprite had a different set of 3D
coordinates (vertices), texture coordinates (texels) and vertex normals (for
shading).  For example: our cylinder could have each triangle connected to
any 3 of the 48 unique vertices and any 3 of the 98 texels, instead of the
current system where the triangle has 3 indices used for both vertices and
texels.  Unfortunately our approach proved awkward, slow and difficult to
optimize.

@node 3D Sprites Example 3, , 3D Sprites Example 2, 3D Sprites
@subsection Shading

Separating the ends of the cylinder sprite for texturing
(@pxref{3D Sprites Example 2}) has a fortunate side effect.  It separates the
surface normals of the vertices as well as the texture coordinates.

Surface normals are used for shading the sprite.  Light colors each vertex
based on the average normal of all of the triangles that share that vertex.
When all of the vertices in our sprite are shared, all of the edges look
smooth---even the edges between the sides and the ends of the cylinder.
With the ends separated, that edge is now sharply defined.

@ifnotinfo
@picturess{content,sprites,unseamly}

@end ifnotinfo
Unfortunately, we have also split one edge of the cylinder's sides, which
creates a sharply defined edge where we don't want it.  We could reconnect
the shared vertices along that edge, but then we would have to texture the
sides differently---the sides would either curve ackwardly or overlap.

We are stuck with an unwanted edge or a difficult texturing job until we
can find a way to connect vertex normals without connecting skin vertices.
One way we might be able to do this is by interfering with vertex normal
calculation.  We would simply mark certain vertices as needing to be blended
together during or after vertex normal calculation.  We would still have
98 vertex normals, but two pairs of them would be averaged together.

One way we might mark which vertices should be blended this way, would be
to create a special frame in the 3D Sprite where all of the blended vertices
are touching.  In the case of our cylinder, the ends would be pulled away
from the sides but the sides would form a complete loop so that vertices we
split for texturing would be blended for shading.

@ifnotinfo
@picturess{content,sprites,split}

@end ifnotinfo

The simplest way to apply the blending would be by averaging the vertex
normals after vertex normal calculation. It would probably be more accurate
to re-calculate the vertex normal by averaging the normals of all of the
triangles connected to both vertices.  Vertex normals can be pre-calculated---
especially if you are using pre-calculated vertex animation anyway.  So
the blending effect might only have to be applied once.
