It is common practice to use Flash to build 3D applications. For example, papervision3D is one of the most popular 3D engines that is widely supported and easy to use for this purpose. However, all of these 3D engines are CPU-based so they can be extremely slow in terms of performance. In Flash Player 11, stage3D API allows a hardware-accelerated architecture to bring 3D performance to the next level.

Here is a brief workflow that uses Away3D 4. It is known as one of the best 3D frameworks that fully support GPU acceleration.

INSTALLATION

1. Update the Flash player and the playerglobal file.

2. Update the Flex SDK to 4.6.

3. Download the latest version of Away3D.

IMPLEMENTATION

1. Configure the viewport and the camera. The current size is 1200 x 900.

// Initialize 3D scene.

viewport = new Viewport3D(1200, 900, false, true);
viewport.interactive = true;
advancedCamera = new AdvancedCamera();
scene = new Scene3D();
renderer = new QuadrantRenderEngine();
 
this.addChildAt(viewport,0);
 
advancedCamera.x = CAMERA_INIT_X;
advancedCamera.y = CAMERA_INIT_Y;
advancedCamera.z = CAMERA_INIT_Z;

2. Configure the navigation that moves forward based on its current angle.

// Move the camera forward.

public function cameraForward():void{
	advancedCamera.x += CAMERA_MOVE_SPEED * Math.sin(advancedCamera.rotationY/180 * Math.PI);
	advancedCamera.z += CAMERA_MOVE_SPEED * Math.cos(advancedCamera.rotationY/180 * Math.PI);
}

// Move the camera backward.

public function cameraBackward():void{
	advancedCamera.x -= CAMERA_MOVE_SPEED * Math.sin(advancedCamera.rotationY/180 * Math.PI);
	advancedCamera.z -= CAMERA_MOVE_SPEED * Math.cos(advancedCamera.rotationY/180 * Math.PI);
}

// Rotate the camera to the left.

public function cameraLeft():void{
	advancedCamera.rotationY -= CAMERA_ROTATION_SPEED;
}

// Rotate the camera to the right

public function cameraRight():void{
	advancedCamera.rotationY += CAMERA_ROTATION_SPEED;
}

3. Configure the memory stack.

// Initialize the memory stack.

private function initMemoryStack():void{
	object2D = new Array();
	object3D = new Array();
}

// Clean all 3d objects in the memory stack.

private function clearMemory():void{
	while (object2D.length > 0){
		scene.removeChild(object2D.pop());
	}
	while (object3D.length > 0){
		scene.removeChild(object3D.pop());
	}
}

4. Configure the material based on the XML file.

// Initialize the material.

private function setupAllMaterial(roomsData:XML):void{		virtualMaterialLibraryArray = new Array();
	var virtualMaterialLibrary:VirtualMaterialLibrary;
 
	for(var i:int = 0; i < roomsData.room.length(); i++){
		virtualMaterialLibrary = new VirtualMaterialLibrary();
		for(var j:int = 0; j < roomsData.room[i].materials.material.length(); j++){
			virtualMaterialLibrary.push( roomsData.room[i].materials.material[j].id, roomsData.room[i].materials.material[j].source );
		}
		virtualMaterialLibraryArray.push(virtualMaterialLibrary);
	}
}

5. Create the 3D object array based on the XML file.

// Contruct the 3D map.

public function setupAllRoom(roomsData:XML):void{
 
	var virtualObject:Array;
	virtualRoomArray = new Array();
 
	for(var i:int = 0; i < roomsData.room.length(); i++){
		virtualObject = new Array();
 
		for(var j:int = 0; j < roomsData.room[i].objects.object.length(); j++){
			var cur:XML = roomsData.room[i].objects.object[j];
			virtualObject.push(new VirtualObject(cur.type,cur.texture, Number(cur.x), Number(cur.y), Number(cur.z), Number(cur.width), Number(cur.height), Number(cur.rotationX), Number(cur.rotationY), Number(cur.rotationZ)));
			if(cur.@setDisappear != "false"){
				(virtualObject[virtualObject.length-1] as VirtualObject).setDisappearOnRollOver();
			}
			if(cur.@setNavRoom != "false"){
				(virtualObject[virtualObject.length-1] as VirtualObject).setNavigationToRoom(cur.@setNavRoom);
			}
		}
		virtualRoomArray.push(virtualObject);
	}
 
}

6. Setup the camera object array based on the XML file.

// Construct the camera setting for each room.

public function setupAllCamera(roomsData:XML):void
{
	virtualCameraArray = new Array();
 
	for(var i:int = 0; i < roomsData.room.length(); i++){
		var cur:XML = roomsData.room[i];
		virtualCameraArray.push(new VirtualCamera(Numbe</blockquote>
 
r(cur.camera.animStartX),Number(cur.camera.animStartY),Number(cur.camera.animStartZ),Number(cur.camera.startRotY),Number(cur.camera.duration),Number(cur.camera.x), Number(cur.camera.y), Number(cur.camera.z), Number(cur.camera.rotY), Number(cur.camera.rotYAngle), Number(cur.camera.rotXAngle), Number(cur.camera.rotSpeed), Number(cur.camera.pan), Number(cur.camera.panSpeed)));
	}
}

7. Load a new room and camera into the 3D scene.

// Set up a room by removing the previous room and loading the new room.

public function setupRoomAndCamera(room:uint):void{
 
	// Check if there is an initialization block on first load.
	if (roomPointer == -1 || (!block && room != roomPointer)){
		block =  true;
		roomPointer = room;
 
		initMaterial(room);
		if (!virtualMaterialLibrary.loadCompleted){
			virtualMaterialLibrary.addEventListener("LOADED", renderRoom);
			virtualMaterialLibrary.loadAllTexture();
		}else{
			renderRoom();
		}
 
		currentCamera = virtualCameraArray[room];
 
		// allocate camera
		camera.x = currentCamera.camera_animation_start_x;
		camera.y = currentCamera.camera_animation_start_y;
		camera.z = currentCamera.camera_animation_start_z;
		camera.rotationY = currentCamera.camera_animation_start_rotationY;
		camera.rotationX = 0;
 
	}
}

8. Create the rendering functions.

// Render the whole scene and rotate the 2D objects that will always face the camera.

public function render():void{
	for (var i:int = 0; i < object2D.length; i++){
		object2D[i].rotationY = -Math.atan2(object2D[i].x - camera.x, object2D[i].z - camera.z)* 180 / Math.PI + 180;	}		
	view.render();				
}

// Render the room with 3D and 2D objects.

public function renderRoom(event:Event = null):void{
	// Clear previous memory.
	virtualMaterialLibrary.removeEventListener("LOADED", renderRoom);
	clearMemory();
	// Virtual room.
	var virtualObject:Array = virtualRoomArray[roomPointer];
	var planeGeometry:PlaneGeometry;
	var mesh:Mesh;
 
	for (var i:uint = 0; i < virtualObject.length; i++){
		switch(virtualObject[i].type){
			case "plane":
				planeGeometry = new PlaneGeometry(virtualObject[i].width,virtualObject[i].height);
				mesh = new Mesh(planeGeometry, virtualMaterialLibrary.getMaterial(virtualObject[i].texture));
				mesh.x = virtualObject[i].x;
				mesh.y = virtualObject[i].y;
				mesh.z = virtualObject[i].z;
				mesh.rotationX = virtualObject[i].rotationX;
				mesh.rotationY = virtualObject[i].rotationY;
				mesh.rotationZ = virtualObject[i].rotationZ;
				mesh.extra = virtualObject[i];
 
				scene.addChild(mesh);
				object3D.push(mesh);		
 
				break;
 
			case "2dObject":
				planeGeometry = new PlaneGeometry(virtualObject[i].width,virtualObject[i].height);
				mesh = new Mesh(planeGeometry, virtualMaterialLibrary.getMaterial(virtualObject[i].texture));
				mesh.x = virtualObject[i].x;
				mesh.y = virtualObject[i].y;
				mesh.z = virtualObject[i].z;
				mesh.rotationX = virtualObject[i].rotationX;
				mesh.rotationY = virtualObject[i].rotationY;
				mesh.rotationZ = virtualObject[i].rotationZ;
				mesh.extra = virtualObject[i];
 
				scene.addChild(mesh);
				object2D.push(mesh);		
 
				break;
 
			case "pngObject":
				planeGeometry = new PlaneGeometry(virtualObject[i].width,virtualObject[i].height);
				mesh = new Mesh(planeGeometry, virtualMaterialLibrary.getMaterial(virtualObject[i].texture));
				mesh.x = virtualObject[i].x;
				mesh.y = virtualObject[i].y;
				mesh.z = virtualObject[i].z;
				mesh.rotationX = virtualObject[i].rotationX;
				mesh.rotationY = virtualObject[i].rotationY;
				mesh.rotationZ = virtualObject[i].rotationZ;
				if (virtualObject[i].disappearOnRollOver){
					mesh.mouseEnabled = true;
					mesh.mouseChildren = true;
					mesh.addEventListener(MouseEvent3D.MOUSE_OVER, disappearPngObject);
					mesh.addEventListener(MouseEvent3D.MOUSE_OUT, showPngObject);
				}
				if (virtualObject[i].navigationDestination != -1){
					mesh.mouseEnabled = true;
					mesh.mouseChildren = true;
					mesh.addEventListener(MouseEvent3D.MOUSE_DOWN, navigateToRoom);
					mesh.addEventListener(MouseEvent3D.MOUSE_OVER, setHandCursor);
					mesh.addEventListener(MouseEvent3D.MOUSE_OUT, hideHandCursor);
				}
				mesh.extra = virtualObject[i];
 
				scene.addChild(mesh);
				object3D.push(mesh);
				break;
		}
	}
	this.render();

// Start the camera animation.

	var tweenMax:TweenMax = TweenMax.to(camera, virtualCameraArray[roomPointer].camera_animation_duration, {x:virtualCameraArray[roomPointer].camera_start_x,y:virtualCameraArray[roomPointer].camera_start_y, z:virtualCameraArray[roomPointer].camera_start_z, rotationY:virtualCameraArray[roomPointer].camera_start_rotationY, ease:Quart.easeOut});
			tweenMax.addEventListener(TweenEvent.COMPLETE, cameraAnimationComplete);
}

9. Integrate all of the functions above.

setupAllMaterial(roomsData);
setupAllRoom(roomsData);
setupAllCamera(roomsData);
setupRoomAndCamera(4);