6. Specifying Vertex Positions
When we use transformations to manipulate the world
matrix, this resulting matrix is applied to each individual vertex when
rendering, which causes the object to actually move onscreen. Because
the coordinate system has been moved, rotated, and scaled relative to
the world, all the vertex positions are transformed in exactly the same
way. We can, therefore, define any shape we like using these vertex
coordinates, and it will move around the screen as specified by our
matrix transformations.
7. Drawing Multiple Objects at Different Positions
The example code in the projects we have looked at
has always set the world matrix before looping through the effect
passes and calling the Apply method on each. This is important because it is the world matrix that is present at the point of calling Apply that will be used for the subsequently rendered objects.
If you want to draw multiple objects within the same call to Draw (as you will undoubtedly want to!), you need to ensure that a call to the effect pass's Apply
is made after each object's world matrix is set into the effect. Any
changes made to the world matrix after this will be ignored.
There are two sequences with which this can be
implemented. The first is to loop for the effect passes for each
object, repeating the loop for each subsequent object. The second is to
loop through the passes just once, applying each one multiple times and
drawing each object after its matrix has been applied.
The first of these approaches can be seen in Listing 5. The effect loop is present twice, once for each of the objects being rendered. Each effect pass is applied once per loop.
Example 5. Drawing multiple objects with an effect pass loop per object
// Draw the first object foreach (EffectPass pass in _effect.CurrentTechnique.Passes) { // Set the world matrix _effect.World = Matrix.CreateRotationZ(_angle); // Apply the pass and draw pass.Apply(); GraphicsDevice.DrawUserPrimitives (PrimitiveType.TriangleStrip, _vertices, 0, 2); }
// Draw the second object foreach (EffectPass pass in _effect.CurrentTechnique.Passes) { // Set the world matrix _effect.World = Matrix.CreateRotationZ(_angle * 2); // Apply and draw pass.Apply(); GraphicsDevice.DrawUserPrimitives (PrimitiveType.TriangleStrip, _vertices, 0, 2); }
|
The second approach is shown in Listing 6. It loops through the effect passes just once, but applies each one multiple times (once per object being rendered).
Example 6. Drawing multiple objects with a single effect pass loop
// Draw the objects foreach (EffectPass pass in _effect.CurrentTechnique.Passes) { // Set the world matrix for the first object _effect.World = Matrix.CreateRotationZ(_angle); // Apply the pass and draw pass.Apply(); GraphicsDevice.DrawUserPrimitives (PrimitiveType.TriangleStrip, _vertices, 0, 2);
// Set the world matrix for the second object _effect.World = Matrix.CreateRotationZ(_angle * 2); // Apply the pass and draw pass.Apply(); GraphicsDevice.DrawUserPrimitives (PrimitiveType.TriangleStrip, _vertices, 0, 2); }
|
These code samples produce exactly the same visual
results. The one you use is entirely up to you; you might find that one
approach or another better fits in with the object structure that you
are rendering. The important thing to remember is that the pass.Apply method needs to be called each time an updated world matrix needs to be observed.
There is one area where the two approaches will
result in a performance difference, however. When we begin to apply
textures to our objects , we will need to pass the texture
graphics to the graphics hardware each time we draw an object. Moving
the graphic around in memory is a relatively expensive process because
graphic files can be quite large.
We can therefore optimize our rendering by loading
each texture into the graphics hardware just once and then drawing all
objects that use that texture together. The next texture can then be
loaded and its objects drawn. This way, we load each texture only once
per draw, rather than potentially once per object.
The second rendering approach, shown in Listing 6,
is potentially less efficient for textured objects. If we have multiple
passes in our effect and each of the objects rendered has a different
texture, we will end up alternating between the two textures. The first
approach in Listing 5
deals with the object in its entirety before moving on to the next
object, allowing its texture to be used by all the passes without
needing it to be reloaded.