From 3D Studio MAX to Direct 3D: Introduction to Plugin Development Post A Comment |
|
|
|
|
|
|
|
If a programmer can translate an artist's work into a real-time 3D environment, the game will be that much better. For many programmers, 3D Studio MAX is the tool of choice for pre-calculating and real-time 3d scenes. And, in the opinion of this author, Microsoft's DirectX API is the most efficient API for games on Windows platforms Introduction to MAX plugin Development 3DS MAX primarily deals with meshes concerning the realization of 3d objects. Patches and NURBS are also managed, but because the powerful geometry pipeline makes it possible to convert them into meshes, it shouldn't be a problem. The exportation of NURBS-based objects would have made things very difficult and inappropriate for real-time 3D. This flexibility is the reason why 3DS MAX is becoming the standard as far as game development is concerned. If you already own the second version, you'll enjoy its performance compared to the first version. Many changes were made in this second version, and as a result, there is an incompatibility of plugins between the two versions. Getting around this incompatibility requires only a recompilation and maybe a few changes. So, with that in mind, techniques explained in this article will work, regardless of the MAX SDK version you have. What do I need? On the software side, you'll need Microsoft Visual C++. While the 4.0 version is good enough to create plugins for the first version of 3DS MAX, you'll imperatively need the 5.0 version if you use the MAX2 SDK. As for APIs, you'll of course need a version of MAX's SDK and DirectX 5. MAX Philosophy As a MAX plug-ins developer you'll have to understand MAX's internal structure. The rest of this article will introduce you to fundamental concepts such as the geometry pipeline, the manipulation of the scene's nodes, calculus implementation and the plugins' interface. If you like Oriented Object Programming, you'll love MAX's API: everything has been made according to the OOP philosophy, you'll find classes for almost everything you can think about (Mesh, Face, Point, Matrix…). Nodes Manipulation What's a node? In MAX, a node is a visual representation of an object (here, the term 'object' means 3D object, light, camera, shape, etc…). Nodes are linked to each other to make a hierarchy. The root node of this hierarchy is the MAX scene. To realize a MAX exporter plugin, it's important to be familiarized with the manipulation of nodes, as they're the starting point of your conversion. The Geometry Pipeline This is the most fundamental concept and innovation of MAX. If you have already worked with 3D Studio/DOS, you know how the creation of meshes work. You could start by creating many 2D shapes with the 2D shaper and then create a 3D object based on those shapes using the 3D lofter. To apply modifications (vertices displacement, Boolean operations, mapping, etc…) on it you could use the 3D editor. Each time you made a modification on a 2D shape or 3D object, the previous state was lost as the modification was directly applied on the entities (faces, vertices, 2d spline) that made up the 2D shape or 3D object. |
In step two, a Taper Modifier was applied on our node, you can see the result in Figure 2 (I've also assigned a texture map). The node now points on what we call the 'Derived Object'. This Derived Object is the result of the node's pipeline interpreted by the geometry pipeline.
Following the Derived Object is the Taper Modifier, and finally, our Base Object: the sphere.
Suppose that you apply a bend to the object. This Modifier will appear in the pipeline right after Derived Object and before the Taper. With the help of MAX's Modifier Stack you can change parameters of any Modifiers you want (even the base object). You can also remove or insert modifiers anywhere you want in the Stack. Anytime the object's World Space State will be recomposed: that's the job of the geometry pipeline.
The World Space State object of a node can be evaluated using the INode::EvalWorldState() method. This method returns a C++ object of the class ObjecState. From this object, you can retrieve the object evaluated by the geometry pipeline. The evaluated object is also a C++ object of a class that is derived from the Object class. MAX implements many classes that are derived from the Object class.
Later in this series, we will see classes such as:
TriObject: defines a mesh object made of triangles
CameraObject: defines either a Free or Target Camera
LightObject: defines either an Omni, Directional, Target Spot or Free Spot Light
A Bit of Calculus
MAX's API offers a set of classes and functions to make the utilization of matrices, points and quaternions easier. Since the manipulation of points is not really a big challenge, I'm not going to overview the Point3 class. Talking about quaternions would go beyond the scope of this article, as they are mostly used when dealing with animation. So only fundamentals of matrices are explained. Here we go.
Transformation Matrices. Transformation matrices are used to switch from one given coordinate system to another; for example, to transfer the coordinates of an object's vertices from local to the world space coordinate system. Transformation matrices are also used to position nodes in the scene. The transformations provided by these matrices are: translation, rotation and scaling. Such matrices can be created and used with the Matrix3 class of MAX.
In MAX, matrices have 4 rows of 3 columns. Usually, 3D matrices are 4x4 instead of 4x3. It's also the case for MAX, but as the last column is always [0 0 0 1] for such matrices, it's implicitly managed by the class and functions dealing with it.
The coordinate system used by max is a right-handed one, with counter-clockwise angles when looking to the positive way of an axis, as shown in Figure 3 below.
Now let's see how the identity, translation, rotation and scaling are encoded. An identity matrix has the property to keep a vector or a matrix unchanged during a vector/matrix or matrix/matrix multiplication. It's encoded as follows:
You can initialize a matrix to the identity by passing 1 to the constructor of Matrix3 class or by calling the method Matrix3::IdentityMatrix().
Translation is stored in the matrix this way:
Translation can be set using Matrix3::SetTrans(), retrieved using Matrix3::GetTrans(), set to null using Matrix3::NoTrans().
The matrices for rotations around the three axes are shown below. The rotation's angle is always given in radians.
X rotation:
Y rotation:
Z rotation:
These matrices can be created using global functions RotateXMatrix(), RotateYMatrix(), RotateZMatrix(). An incremental rotation around one specific axis can be performed using the Matrix3's methods Matrix3::RotateX(), Matrix3::RotateY(), Matrix3::RotateZ().
A method of the Matrix3 class is also provided to create a Yaw/Pitch/Roll angles matrix (using the rule of Euler's angles) : Matrix3::RotateYPRMatrix().
Scale factors are encoded like this:
Scaling factor can be set using Matrix3::SetScale(), or reset to 1 using Matrix3::NoScale().
For the last part of this article we're going to take a brief look at how the plugin can get access to MAX features.
The Plugin's Interface
The Plugin's Interface is a C++ Interface retrieved during the plugin's initialization. The term Interface signifies that a C++ object contains methods only. The Plugin's Interface is used to provide APIs that the MAX offers to the plugin. From the list of APIs it provides, the following pertains to our exporter.
Command Panel - Rollup Page Method
As the plugin's type we will use is a Utility Plugin, we'll have to design a dialog that will appear during the plugin's initialization in the Utility Plugin's Pan. This dialog will appear under the form of a Rollup Page. Methods of the Plugin's Interface will be used to Add and Delete this Rollup Page dialog.
Nodes Related Methods
By using functions of this API, we can access the Root Node of the scene, accessing a Node from its name.
Node picking
Provides functions to call the Interactive Nodes Selection Dialog of MAX. Useful to select Nodes we want to export.
Standard MAX dialog
The Track View Pick Dialog, Material Browse Dialog can be called using this API.
Last Words
Next time, we'll see how to create a Plugin's Project, how to integrate MFC inside the plugin, how to debug it, and check out a simple example of a Utility Plugin.