Contents |
An object is an entity that needs to be positioned in the 3d world. The class ScEng::Object is the main interface for all objects.
This class implements a few virtual methods, but it doesn't really expect anything from the objects.
SceneEngine implements many types of objects. Cameras and Lights are objects. There are objects like TriMeshObject or PolyMeshObject that store a mesh. Primitive objects can generate meshes or polylines, for example, SphereObject generates a spherical mesh. More complex objects can be defined by combining multiple objects in different ways.
Objects like TriMeshObject or PolyLineObject can be used right away. For example a TriMeshObject can be rendered by just reading its TriMesh. However, objects like BoxObject or SphereObject are just containers for attributes, and a renderer would never know how to render them. These kind of objects need to be built to generate an object that other tools can understand. For example, the SphereObject is defined only by the radius and segments atributes, so this object needs to be built to generate a spherical mesh.
All objects are built using the method ObjectModifier::BuildObject. When SphereObject::BuildObject is called for the first time, it creates a PolyMeshObject with a spherical mesh shape defined by radius and segments, and returns this PolyMeshObject.
If the radius or segments attributes don't change, the SphereObject::BuildObject method will continue returning the PolyMeshObject it created the first time. If these attributes change, the SphereObject will delete the PolyMeshObject and generate a new one with an updated representation of the spherical mesh.
ObjectModifier is pure virtual class derived from Object that defines the interface for objects that modify other objects. ObjectModifiers can modify any kind of object, even other ObjectModifiers.
The ObjectModifier works as a tool in an assembly line. It receives an object, applies a modification to this object and returns the modified object. For convinience we'll call the object that is running along the assembly line as the Product Object. ObjectModifiers can even create and return a new Product Objects.
The following images illustrate a series of Objects and ObjectModifiers working together:
{SphereObject} -> [PolyMeshObject] -> {PushObjectModifier} -> [PolyMeshObject]
{CircleObject} -> [BezierSplineObject] -> {ExtrudeModifer} -> [PolyMeshObject]
[ ] - A Product object
{ } - An object that is part of the scene.
ObjectModifier implements the method BuildObject and declares two virtual methods, ApplyModifer and RemoveModifier. ObjectModifers should apply all modifications to the Product Object in ApplyModifier, and remove these modifications in RemoveModifier.
In many cases the Base Object returns itself in BuildObject and becomes the Product Object, receiving all modifications. For example, a TriMeshObject returns itself in BuildObject, so the next ObjectModifier in the line would receive this TriMeshObject and applies the modifications to it. For this reason ObjectModifiers must remove all modifications applied to the Product Object in RemoveModifier. A simple way to do this would be to create an internal copy of the product object it receives, modify this copy and return it as a new product object. However, this would create an enormous amount of memory and waste a lot of time duplicating data inncecesarily.
To work more efficiently the ObjectModifier can create a copy of those things from the product object that will be modified in ApplyModifier, and restore the original condition of the product object in RemoveModifier using the information it stored in ApplyModifier.
To illustrate the internals of building an object with ObjectModiifers we'll use a set of examples:
Vertex Modifier
We'll start with a simple case. a TriMeshObject with a PushModifier. PushModifier deforms only the vertices by pushing them along their normals an amount defined by the PushModifier.
{TriMeshObject} -> {PushObjectModifier}
The first time PushObjectModifier::BuildObject is called, since the modifier hasn't been applied, it calls TriMeshObject::BuildObject, which returns the TriMeshObject. Then it calls ApplyModifier on this object. In ApplyModifier the PushObjectModifier stores the current position of the of all the vertices of the TriMeshObject, and then it applies its modifications by setting a new position for each vertex, and then it returns the TriMeshObject.
If the scene is saved at this point, the TriMeshObject would be saved with the modified vertices (that's why SceneEngine::SaveScene calls ObjectModifier::RemoveModifier for all nodes before actaully saving the scene.
Let's say the user changed the att_amount attribute in the PushModifier. Since the modifier change the object needs to be built again. So ObjectModifier::BuildObject now finds that the modifier has been already applied, so it calls RemoveModifier, which just sets the TriMeshObject vertices to the original state by copying their position from the vector it saved in ApplyModifier.
Next, ObjectModifier::BuildObject calls TriMeshObject::BuildObject, which returns itself again, and then calls ApplyModifier, which receives a clean copy of the TriMeshObject and does its modifications.
SceneManager has a vector of ViewportBlocks. This are the blocks that will be painted in the 3d viewports and in other windows like the UVWEditor.
The GLRenderingManager gets the ViewportBlocks directly from the SceneManager and draws them. It only draws those viewport blocks whose m_is_visible is true.
When a scene is opened, all the nodes are registered as ViewportBlocks in the SceneManager.
When a node is created in the scene, its added to SceneManager::m_viewport_blocks.
When a node is deleted from the scene, its deleted first from the SceneManager::m_viewport_blocks vector, and then deleted from the scene.
ViewportBlocks can be created by the block's user interface and added to the SceneManager to display custom elements in the viewports. For example, the LatticeModifier can create a ViewportBlock that displays the lines and points that the user selects. When the user exits the Lattice dlg, this block is removed from SceneManager::m_viewport_blocks.
The block's user interface can add ViewportBlocks to the ProductObject to add additional data that the NodeGUI can use to display things like the SubObject level or