Table of Contents

Cloning 3D Objects Application Sample

This example is based on a previos interactive scene tutorial sample. Most of the steps are the same.

Here we are going to discuss only additional step that demonstrates cloning of 3D objects.

Cast3D and import utilities version 0.96 or later is required for this sample.

Cloning 3D objects

* Additional call to makeClone function to interactive sample code would create a new instance of a character. This function also sets up navigation controller for a new instance.

 		/**
		 * This functin make a clone of Model node and sets Navigaion Contraller
		 */		
      private function makeClone():void
       {
       	    // First lets find the root node of a character
       	    // we know in advance it's Id is 'Cube'
       	    var nodename:String = "Cube";
	        var model_node:Node3d = this.animator.source.find(nodename) as Node3d;
	        if (!model_node)
	        {
		   		statusText.visible = true;
	        	statusText.text = "Failed to make clone. Not found node: " + nodename;
	            return;
	        }
 
       	    // next step is to make a clone instance of a character node
             var cloned_model_node:Node3d = model_node.clone();            
 
       	    // A cloned instance of a node if not attached is handing in the air
       	    // To make it visible we need to add it to a scene, whic is KeyFrame
       	    // There is only one KeyFrame ( with infinite duration) and we know Id 
       	    // in advance by looking at the file.
       	    var kfname:String = "Scene_kf";
 	        var kf:KeyFrame3d = this.animator.source.find(kfname) as KeyFrame3d;
	        if (!kf)
	        {
		   		statusText.visible = true;
	        	statusText.text = "Failed to make clone. Not found keyframe: " + kfname;
	            return;
	        }
	        // adding cloned node to Keyframe
            kf.addNode(cloned_model_node);
            // This step is also importan to understand.
            // Although we added node to a scene, the actual rendering is taking place
            // in Rendering engine, in this case papervision3D. So Cast3d is just manupulating 
            // with transforms and geometry. This step populates rendering engine with newly created 
            // node's data. Xc3 file loader does it for you, after it's done, you need to do that explicitly.
            cloned_model_node.register(this.animator, kf);
 
            // lets create navigation conrloller for new node.
	        var nc:NavigationController = new NavigationController(cloned_model_node,"navigator");
	        _navigations.push(nc); 
 
           // We know that "cube" node actually represents Skined geometry, which means
           // the motion is controlled by another skeleton node(s), in this case "lowerBack" node is
           // root skeleton node( see source file)
	        nodename = "lowerBack";
	        var skeleton_node:Node3d = this.animator.source.find(nodename) as Node3d;
 
	        // lets make a clone of that too. Otherwise both original chatecter skin and cloned one  
	        // will be controlled by same skeleton node(s). 
	        var cloned_skeleton_node:Node3d = skeleton_node.clone();
	        if (!cloned_skeleton_node)
	        {
		   		statusText.visible = true;
	        	statusText.text = "Failed to set Cloning for node: " + nodename;
	            return;
	        }
	        // add to same scene 
            kf.addNode(cloned_skeleton_node);
	        // populate rendering engine 
            cloned_skeleton_node.register(this.animator, kf);
 
 			// This step required only for Skin 			
            var skin:Skin3d = cloned_model_node.part as Skin3d;
 	        if (skin)
	        {
	        	// The cloned version of skinned node holds the references to original skeleton bones
	        	// Now we need to reassign to the bones of new ( cloned) skeleton nodes
	        	// binding works in the way that it tries to find matching id of old bone in provided skeleton bone branhes
	        	// once it finds it does the replacement. If fails to find any single bone, the whole process fails.
		        if (!skin.bindBones(cloned_skeleton_node))
		        {
			   		statusText.visible = true;
		        	statusText.text = "Failed to make clone. Clould not bind skin: " + skin.id + " to node: " + cloned_skeleton_node.id;
		            return;	        
		        }
	        }
 
	        var tarck_id:String;
	        var motionAlias:String;
 
	        // now we add a 'walking' motion which is represented by MotionGroup class instance with id == "lowerBack_motion"
	        // again, we know that by looking at source file.
	        tarck_id = "lowerBack_motion";
	        motionAlias = "walk";	        
	        if (!nc.addMotion(cloned_skeleton_node, tarck_id, motionAlias))
	        {
		   		statusText.visible = true;
	        	statusText.text = "Failed to add Motion " + motionAlias + " for track: " + tarck_id;
	            return;
	        }
 
	        // another motion is a 'jump' motion  with id == "lowerBack_motionjump"
	        motionAlias = "jump";
	        tarck_id = "lowerBack_motionjump";
	        if (!nc.addMotion(cloned_skeleton_node, tarck_id, motionAlias))
	        {
		   		statusText.visible = true;
	        	statusText.text = "Failed to add Motion " + motionAlias + " for track: " + tarck_id;
	            return;
	        }
 
	        // lets move the newly created model away from intial position so it does not interlap with original
	        nc.position.x += 5.0; 
	        nc.rotation.x = 0; nc.rotation.y = 0; nc.rotation.z = 1; nc.rotation.w = 60 * Math.PI/180.0 ; 
		    this.stage.addEventListener(KeyboardEvent.KEY_DOWN, this.keyDownHandler);
      }
 

results

So, if done it right you should see something like these:

Use <TAB> to switch control between instances.


Complete source code of this sample.