• Register

Wave Engine was born on February 21, 2013 with the exciting mission of developing an engine to help the mobile game developers’ community.

Post news Report RSS What is new in WaveEngine 1.3.5 (Sea Lion)

On Wave Engine 1.3.5.0 (Sea Lion) we’re introducing new features: Linux support New Render Manager system Draw call batching (static and dynamic)

Posted by on

TEMPLATE CODE CHANGES

On Wave Engine 1.3.5.0 (Sea Lion) we’re introducing some changes in Wave project templates, and if you have an existing project using earlier versions (1.3.4.0 and before), it’s mandatory to apply the following changes.

At App.cs file, apply the following changes to solve compilation errors:

Code:
this.spriteBatch.Begin();
this.spriteBatch.Draw(this.splashScreen, this.position, Color.White);
this.spriteBatch.End();

to

Code:
this.spriteBatch.Draw(this.splashScreen, this.position, Color.White);
this.spriteBatch.Render();

The previous changes are necessary only if you have an existing project of earlier Wave versions. Once you update Wave installation, the new templates are installed too, so these changes are no longer required.

DRAW CALL BATCHING

To draw an object, Wave Engine has to issue a draw call to graphics API (DirectX or OpenGL). Each draw calls needs a significant work, causing performance overhead on the CPU and GPU side.
Now Wave Engine can combine several objects at runtime and draws them together with a single draw call. This is called "batching".

Materials
Only objects sharing the same material instance can be batched together. So, if you want to achieve good batching, you need to share material instances with different entities as possible. Because of this, it's recommended to use SpriteAtlas instead of Sprites, and combine textures in 3D objects.

Dynamic Batching
Wave Engine can automatically batch objects that share the same material into the same draw call. Dynamic batching is done automatically and does not need any changes for your part.
Batching dynamic objects has a CPU overhead per vertex. Because of this, Wave Engine only batch dynamic meshes that have less than the equivalent size of 320 vertex with position, and texture coordinate properties. So if your model has more vertex properties (such as Normal, Skinning properties or Tangent space), the number of vertex of your mesh that can be batched is reduced.

Static Batching
Static batching, in the other hand, allows Wave Engine to batch draw calls of meshes of any size (the number of vertex doesn't matter) with the condition that these meshes must be static. Static batching is more efficient that dynamic batching.
To take the benefits of static batching, you need to explicitly specify that an entity is static and will not move, rotate or scale during the entity life. To do so, you need to set the Entity.IsStatic property to true:

Code:
Entity awesomeEntity = new Entity("awesomeEntity")
{
IsStatic = true
};

This property can be set only if the entity is not initialized, and the Transform properties (such as Position, Rotation and Scale) is taken until the entity is initialized. Once the entity is initialized, it cannot be transformed anymore.

NEW RENDER MANAGER

In order to achieve the draw call batching, we have introduced big changes in the RenderManager class.

SpriteBatch
As we advanced in the template code changes, SpriteBatch has been suffered several modifications.

  • SpriteBatch.Begin(...) method has been removed.

  • SpriteBatch.End() method has been renamed to SpriteBatch.Render()

  • Now each layer has its own SpriteBatch instance, and RenderManager.SpriteBatch has been removed. In earlier versions, the Begin methods was useful to specify blending and depth modes to the sprites rendered, now this render states has been delegated to the layer, so if you want to render sprites with a specific blending property, you need to find a layer that match that properties and use its SpriteBatch instance.

LineBatch (2D & 3D)
LineBatch instances has been moved from RenderManager to each Layer. So you can use the layer properties to draw with line batches.

DRAWABLES

If you have implemented a custom drawable, you need to apply some changes.

DrawBasicUnit method is removed
In earlier versions of Wave Engine, the Drawable lifecycle was composed by two methods (Draw() and DrawBasicUnit()). In the Draw() methods you process the model meshes and select the layer to add its mesh parts. For each mesh part the drawable will receive a DrawBasicUnit() method and you will draw the mesh (draw vertexbuffers, sprites, etc...).
Now DrawBasicUnit method is removed, and this functionality must be moved to Draw() method:

In earlier versions:

Code:
class MyAwesomeDrawable : Drawable
{
...
public override void Draw(TimeSpan gameTime)
{
foreach mesh
{
meshId = mesh index;
material = GetMeshMaterial(mesh);
layer = GetMaterialLayer(material);

layer.AddDrawable(this, meshId);
}
}

public override void DrawBasicUnit(int parameter)
{
mesh = GetMeshByID(parameter); 
material = GetMeshMaterial(mesh);

material.Apply(this.RenderManager);

Draw mesh
}
}

Now:

Code:
class MyAwesomeDrawable : Drawable
{
...
public override void Draw(TimeSpan gameTime)
{
foreach mesh
{
meshId = mesh index;
material = GetMeshMaterial(mesh);

Draw mesh with material
}
}
}

How to draw meshes
With earlier versions, you need to draw yourself the vertex buffers using the method GraphicsDevice.DrawVertexBuffer(...). Now, this methods is not accesible, and you need to call RenderManager.DrawMesh(mesh, material, world, ...). We will to try what implies this change:

  • A Mesh instance is an object that specify the graphics primitives to draw. A mesh is composed of a VertexBuffer and a IndexBuffer, primitive type (triangles, lines, etc..).

  • RenderManager.DrawMesh(Mesh mesh, Material material, Matrix world, ...) draws the mesh with the specified material (in the material associated layer) and with the specified world transformation. RenderManager has now the responsability to optimize and execute all draw calls (sort, perform batching, etc..).

  • Now It's no necessary to apply the material in the Draw() method, It's done in the RenderManager.DrawMesh(...) method.

Here you can find a little example of a mesh creation and draw:

Code:
class MyAwesomeDrawable : Drawable
{
...
protected override void Initialize()
{
...
VertexBuffer vertexBuffer = new VertexBuffer(VertexPositionColor.VertexFormat);
vertexBuffer.SetData(vertices, vertices.Length);

IndexBuffer indexBuffer = new IndexBuffer(indices);

this.mesh = new Mesh(0, vertices.Length, 0, nTriangles, vertexBuffer, indexBuffer, PrimitiveType.TriangleList);
}

public override void Draw(TimeSpan gameTime)
{
this.RenderManager.DrawMesh(this.mesh, this.Material.DefaultMaterial, ref this.Transform3D.LocalWorld);
}
}

Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account: