A collection of geometric data is represented by the class MGeometry.
An instance of an MGeometry describes in a non-draw API specific manner a set of available data streams and any indexing for those streams. There can be one or more associated data streams and either zero or more sets of indexing.
Each item for a data stream represents a vertex (point) attribute and data streams are called vertex buffers. Indexing data, if applicable, provides the topological (connectivity) information to represent geometric primitives.
A simple example of a set of data held by an MGeometry instance is a set data streams for position, normal and color data, as required by a shader. A single set of indices could describe the set of connected triangle primitives.
Figure 18: Each item in the index list defines a data offset into a position (P), normal (N) and color (C) vertex buffer. Three indices are used per triangle.
MGeometry can hold the data and indexing required for rendering many shaders. There can thus be a complex set of data and indexing combinations depending on the requirements of a given shader.
In the previous example where an object (torus) required geometry for filled shading, wireframe draw and control point draw: the total set of data streams required are two position streams, one normal stream, one tangent stream, one bitangent stream and one color stream. Three indexing streams are also required – one for each render item.
In this example there is one MGeometry instance with P1 and P2 as positions; N, T, B as normal, tangent and bitangent; and C as a color stream. I1 is the indexing that describes the connected wireframe line segments, I2 the indexing that describes the triangle mesh for filled drawing and I3 the indexing for the control vertex points. Note in this scenario that P1 is reused for both wire and shaded drawing.
A vertex buffer is represented in the API by the class MVertexBuffer. Logically it is just a block of binary data.
The format for this data is described in a vertex buffer descriptor, which in the API is represented by the class MVertexBufferDescriptor. A buffer descriptor describes the following properties:
Unique names allow you to have multiple sets of data with the same semantic. For example, it is possible to have two sets of texture coordinates with different names.
In the torus example, for instance, there can be a set of vertex buffers, each with a different name, for example “P1” as the name of one of the position buffers.
Unlike in previous systems, only GPU side (no CPU side) data is maintained by the resource management system in the rendering framework.
For vertex buffers (and in fact for all GPU side resources) the following properties are true:
Indexing data is represented by the class MIndexBuffer. Logically it is just a block of binary data.
The interpretation and format of the indexing is provided by the class MIndexBufferDescriptor. The descriptor has basic properties such as a string name for unique identification, primitive type and a data type. The only data type currently returned from internal object types is 32-bit integer.The primitive type includes basic hardware types such as points, lines and triangles but also includes enumerations for more advanced primitives which may be created via custom indexing.
The descriptor also allows for a semantic meaning to be specified for the indexing. This semantic meaning is called the indexing type. There are a series of predefined semantics which can be used, as well as the ability to mark the indexing as being “custom” generated.
More details on custom indexing are provided in the Advanced Topics sections.
The indexing does not need to represent all the elements of a given primitive type for a renderable object. For instance, it can be used to represent the component indexing for faces on a mesh for per-face shading, or to represent selected CVs on a NURBS surface. For correspondence, a Maya DAG object component may be associated with the index descriptor.
As with vertex buffers, indexing is stored as GPU data and managed by the resource manager.
To put all of the pieces together for MGeometry, Figure 20 below illustrates an instance of MGeometry, MIndexBuffer, MVertexBuffer, MRenderItem and the internal resource manager.
Figure 21: The MRenderItem references an MGeometry instance. The MGeometry instance references one or more MVertexBuffer instances, and zero or more MIndexBuffer instances. The MRenderItem keeps information about the specific MVertexBuffers and MIndexBuffer it uses. Any Maya DAG component can correspond to a specific MIndexBuffer. The data for MVertexBuffer and MIndexBuffer is managed by the internal resource manager which interacts directly with the GPU data.
This diagram shows a series of dependencies represented as connecting lines. The direction of arrows shows the direction of dependency. Each dependency is a reference and the collection of references shows how lifetime management is handled. The resource manager always references the actual geometric data. MVertexBuffer and MIndexBuffer instances hold references to their corresponding GPU data. MGeometry holds references to all the MVertexBuffer and MIndexBuffer instances for a renderable object. MRenderItem references specific MVertexBuffer and MIndexBuffer instances it uses.
Important notes in this scheme
The previous sections have discussed static geometry data structures and their relationships to one another. During the update phase, instances of these structures need to be instantiated and filled in.
We call this step fulfilling geometry requirements.
Within the API, the corresponding class that specifies what to fulfill is an MGeometryRequirements.
An instance of this class represents the hand-shake mechanism between shaders and locations where data is filled. Each shader for a render item puts forth its requirements. The cumulative set of requirements is collected and presented in a single instance of MGeometryRequirements.
Requirements are specified by a set of vertex buffers descriptors (MVertexBufferDescriptor) and a set of index buffer descriptors (MIndexBufferDescriptor).
A round-trip update of geometric data is shown in the following diagram. Some geometry needs to be updated for a set of shaders. The requirements are gathered, fulfilled, and the geometry required for shading is updated.
Figure 22: In this example, a few render items are shown. The shader for each respective render item specifies a set of descriptors (index or data) and the descriptors are accumulated into a single MGeometryRequirements instance. When an update is required, those requirements are fulfilled and the resulting data cached and referenced by an MGeometry instance. In this particular case, all render items reference this MGeometry instance, and use this data during the rendering phase.
It is sometimes useful to be able to extract geometry from the resource manager outside the context of updating a render item, or outside the context of the rendering pipeline itself.
To do this, use the MGeometryExtractor interface. The interface is intended to provide non-renderer specific geometry data from Maya DAG objects.
It is the preferred mechanism to replace the old interface (called MGeometryManager). Though it is still possible to use either the old or the new interface or to even use functional interfaces for objects (MFn*), the existing interfaces do not take advantage of all the properties of the new interface:
Currently, only polygonal object types are supported.
Figure 23: For a given DAG path, a set of geometry requirements is passed to the extractor. From the associated DAG object, a set of index or vertex data blocks can be extracted.
For plug-in writers which have used existing geometry classes, there can be some confusion between the old and the new interfaces. This is especially true as some names have been reused. One key item to remember is that all of the new interfaces are in the same namespace: MHWRender.
In this section, a table comparing some of the key differences between the old and new classes is provided. Note that the two interfaces are not designed to be compatible with each other and it is not advisable to try and mix-and-match class usage.
As has been noted before, one key difference is that all old interfaces manage CPU side data while the new interfaces manage GPU side data.
Construct / Interface |
Old Class (key differentiation) |
Correspond New Class |
Data stream (vertex buffer) |
MGeometryData: Data types have semantics (versus indexing types for the new interface). For example, primitive center and component identifier are data types. Both can be supplied from internal data, as well as vertex blind data. There is a fixed set of supported formats and packing defined. |
MHWRender::MVertexBuffer: Has additional formats for items such as packing tangent + sign to handle winding order. Supports flexible format and custom packing. Semantics are specified at the indexing level. |
Indexing for data streams |
MGeometryPrimitive: Includes legacy quad and quad strip primitive types as well as N-gons. |
MHWRender::MIndexBuffer: Can have custom indexing and indexing semantics. Does not support legacy quad and N-gon types. |
Stream collection |
MGeometry : A collection of data and indexing ( MGeometryData and MGeometryPrimitive ) |
MHWRender::MVertexBufferList: A list of vertex buffers (without indexing). |
List of stream collections |
MGeometryList: stream / path / matrix list. |
MHWRender::MGeometry: A collection of data and indexing. |
Geometry requirements |
MGeometryRequirements: Fixed set of requirements and allowable data formats. Not expandable. |
MHWRender::MGeometryRequirements Customizable requirements via the usage of descriptor classes. (MHWRender ::MVertexBufferDescriptor, MHWRender ::MIndexBufferDescriptor) |
Geometry Manager |
MGeometryManager: Allows access to default geometry as well as extraction of MGeometry for a given Maya DAG object. |
MHWRender::MGeometryExtractor: Extraction of geometry data based on description. Can support custom data streams and custom indexing. |