This website uses cookies to improve user experience. By using our website you consent to all cookies in accordance with our Cookie Policy. X

Basics of Stage3D part II: camera movement and pointAt function [expert]

In the previous part of this article I wrote about extending an ActionScript3 Documentation example of 3D graphics to make it work with multiple objects in such way that every object could still be transformed separately. The example also has a bit about the matrix used for camera movement ("view"), which truth to be told did not work like it should because it was missing some basic set-up. And this is where it gets unpleasant for people that are new to the 3d graphics, as information available on the Internet about that set-up are rather mixed and mostly confusing, especially since proper camera movement will actually depend on 3D environment settings. That is why this part of Stage3D basics article will be dedicated to virtual camera and its construction, positioning and pointAt function usage.

Starting where we left of two weeks ago (source code from the guide's previous part: Tutorial3D.zip) is a good idea since we already have some basic camera stuff laid down. Although creating a separate class for the camera would probably be a good idea, the already existing matrix by it self is sufficient for now. In any case, the matrix is ready, however results of its transformation are somewhat… unpredictable, or at least not something we could expect (i.e. x+=-5 will actually result in movement to the right instead of left). This is related to a small omission on Adobe's part in the rendering function, which can cause some sleepless nights. What I am exactly talking about? Lets have a look how finalTransform matrix is created in render function:

finalTransform.identity();   
finalTransform.append(box.getMatrix3D());   
finalTransform.append(world);   
finalTransform.append(view);   
finalTransform.append(projection);
It doesn't seem like there is anything out of ordinary here, but if we stop for a moment and take a close look - lets say we want to move whole world to the left, and camera to the right, and for that we set world to x = -10 and view to x = 5. In perfect world there would 15 units of space between world and camera now, but of course it won't be the case in our application and everything because how finalTransform is being made. Lets take another look, world is moved by -10 and view by +5:
finalTransform.append(-10);   
finalTransform.append(5);
And what the result will be? Of course every object will be moved to the left (-10), then to the right (+5), in the end ending up on x = -5. True, it's very basic stuff, but it is very important to understand that it is not the camera that we are moving but the whole world around it. And this is that little detail thingy we were missing: we aren't moving the camera to the left, but whole to the right! Of course it could be done by just saying "simply move the camera in opposite direction", but … is bad idea - rotation and positioning could be done that way, but poinatAt function will be pretty much useless. Fortunately the solution is very simple, we just have to invert the view matrix:
var camera:Matrix3D = view.clone();  
camera.invert();
Yup, that is it. Whole render function will look like this:
private function render(event:Event):void {  
renderContext.clear(.3, .3, .3);  
var camera:Matrix3D = view.clone();  
camera.invert();  
for each(var box:Box3D in vBox) {  
finalTransform.identity();  
finalTransform.append(box.getMatrix3D());  
finalTransform.append(world);  
finalTransform.append(camera);  
finalTransform.append(projection);  
renderContext.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, finalTransform, true);  
box.render(renderContext);  
}  
renderContext.present();  
}
Those two lines of code are enough to make our camera work as intended, view translation to the left will in face move it to the left and what is most important pointAt will actually work, which I will explain shortly. Right now it is best to test out the camera movement and hopefully get something like this:
(Movement on the arrow keys)
Just in case you can always use the code available at the very and of this post.
Well, now that everything is properly set up, it is time to use pointAt function. And to think that without the knowledge about view matrix inversion prior to finalTransform construction, pointAt would never work as intended! This however doesn't solve all of the problems, there is still a question of parameters used by pointAt, because obviously default ones won't work. Those parameters are:
1. Target's position - matrix will be turned to face that point.
2. Facing direction - in other words "front" direction without any transformations; for camera it always will be Vector3D(0, 0, -1).
3. Up direction - which is the "rising" direction; by default Vector3D(0, -1, 0).
That should be enough. Properly working pointAt should look like this:
Unfortunately, translation won't be affect by the pointAt transformation - lets leave that for another day.
Source code: Tutorial3D-2.zip

Basics of Stage3D part I: displaying multiple objects [advanced]

Two weeks ago I've wrote about support in Flash Professional for Flash Player 11 while mentioning about using the example of 3D rendering from the documentation ( http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display3D/Context3D.html#includeExamplesSummary). However using a pre-made example is one thing and understanding it is whole different matter - that is why this time around I will write about Stage3D (as Adobe like to call there 3D acceleration in Flash).
Just in case the whole code from that example (along with additional libraries needed to run it) is available here: Context3DExample.zip

In the first part of this article I will write a bit about creating and displaying multiple objects while still allowing for separate transformations on each of them. To make this simpler I suggest making a class for 3D cubes, using the already existing code (from the example in the documentation) responsible for creating geometry: IndexBuffer and VertexBuffer. Such class might look like this:

private var vbBuffer:VertexBuffer3D;
private var ibIndex:IndexBuffer3D;
private var m3D:Matrix3D;
private var nCount:int;

public function Box3D(context:Context3D) {
			
            var triangles:Vector.<uint> = Vector.<uint>([...]);
	ibIndex = context.createIndexBuffer(triangles.length);
	ibIndex.uploadFromVector(triangles, 0, triangles.length);
			
	const dataPerVertex:int = 6;
	var vertexData:Vector.<Number> = Vector.<Number>([...]);
	vbBuffer = context.createVertexBuffer(vertexData.length / dataPerVertex, dataPerVertex);
	vbBuffer.uploadFromVector(vertexData, 0, vertexData.length / dataPerVertex);
					
	m3D = new Matrix3D();
	nCount = 12;	
}
				
public function render(context:Context3D):void {
	context.setVertexBufferAt( 0, vbBuffer, 0, Context3DVertexBufferFormat.FLOAT_3 );
	context.setVertexBufferAt( 1, vbBuffer, 3, Context3DVertexBufferFormat.FLOAT_3 );
	context.drawTriangles(ibIndex, 0, nCount);
}
				
public function getMatrix3D():Matrix3D {return m3D;}
Nothing especially complicated here - just remember that m3D matrix will hold the transformation (position, scale) so it is best to build the cube around 0,0,0 coordinates and then later move it with appendTranslation function. Also, one more thing worth pointing out is that setVertexBufferAt is used to set which VertexBuffer will be used to draw triangles (drawTriangles function) and it is called twice, because first it points out the vertexes and next the colours.
So, creating a class for cubes is pretty simple, the problems start when we decide to display them. Assuming all those boxes are stored in vBox vector, the render function used in Context3Dexample needs to be changed to this:
private function render(event:Event):void {
	renderContext.clear(.3, .3, .3);
			
	for each(var box:Box3D in vBox) {
		finalTransform.identity();
		finalTransform.append(box.getMatrix3D());
		finalTransform.append(world);
		finalTransform.append(view);
		finalTransform.append(projection);
	renderContext.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, finalTransform, true);
				
		box.render(renderContext);
	}
			
	renderContext.present();
}
Here it gets a bit more interesting thanks to the two most important things: setProgramConstantsFromMatrix function and finalTransform matrix construction. With setProgramConstantsFromMatrix function we set the matrix (transformations) for the rendered object and it cannot be skipped (or at least it won't make any sense to do this, since you won't be able to see anything on the screen), while finalTransform will be used to create that matrix.
This stuff will probably be pretty confusing to people not familiar with 3D graphics, but the basic idea to remember is that every object (cubs in our case) is actually never modified during the runtime. In other words we create our cube, define its triangles and set some colours, but by it self the cube does not have specific position in the system - we use matrices for that. But the thing is matrices also don't do anything special by themselves, until we call the setProgramConstantsFromMatrix function to combine them. Note however this works somewhat like a filter - "Program" (external code used for rendering process) takes the geometry and passes it through the matrix, displaying results to the screen while not modifying any variables.
Now as for the finalTransform - we start each animation frame by resetting this matrix (identity function) to make sure it contains absolutely no transformations. This is very important for append operations, because existing transformations affect the results, so for example a translation by 10 units to the left followed by a 90 degrees turn will place an object in different spot than by starting with 90 degrees turn and then following it with a translation to the left by 10 units. Just like in the real world the direction we will take on "move to the left" command will be different depending on the side we are already facing. In any case it is best to experiment with this, while remembering that order of matrices addition is extremely important and that is why finalTransform is created by appending other matrices in this particular order: world, view (camera) and projection (defines how we see the world).

As usual the whole code is packed and ready to download from here: Tutorial3D.zip

Publishing for Flash Player 11 in Flash Professional CS5.5 [basic]

Recently Adobe released a new version of Flash Player, this time with a number 11 that features 3D acceleration (which I will write something about soon hopefully), support for bigger bitmaps, JSON etc. However those of you who wish to check out those new functions in Flash Professional are up for an unpleasant surprise - Adobe is yet to release an update that actually allows for publishing to the newer format. There is a workaround for this problem, however it is not quite perfect, but on the other hand the only other way is to switch from Flash Professional to a different programming environment (for example: Flashdevelop which is a perfect alternative for people that are seriously thinking about programming in ActionScript).

So anyway, how to add Flash Player 11 support to Flash Professional?

1. Before anything we will need the latest Flash libraries: http://www.adobe.com/support/flashplayer/downloads.html. At the very end of "ADOBE FLASH PLAYER 11" paragraph there is a link leading to a file called: "PlayerGlobal (.swc)" which will be needed in the next step.

2. Now open your Flash Professional installation folder (on XP by default it is: "C:\Program Files\Adobe\Adobe Flash CS5.5"), then move to "Common" -> "Configuration" -> "ActionScript 3.0". In here you already should see directories like "FP9" or "AIR2.5" - we will focus on Flash Player 11 for which we will create "FP11". To this "FP11" folder put previously downloaded "playerglobal11_0.swc" and rename it to: "playerglobal.swc". The final path to the file should look something like this: "C:\Program Files\Adobe\Adobe Flash CS5.5\Common\Configuration\ActionScript 3.0\FP11\playerglobal.swc".

3. Those libraries give us access to the latest functions available in ActionScript but we still need to tell Flash Professional to actually use them. To achieve this head onto the "Players" directory (which is located within "Configuration", just few steps above our previous location) and duplicate a "FlashPlayer" file (in case there are more files like this, duplicate the one with the highest number in the name) renaming it to "FlashPlayer11" in the mean time. Proceed to open it with a text editor of your choice (Notepad will do just fine) and at the very top find lines that look like this:

  <player id="FlashPlayer10" version="10" asversion="3">
   <name>Flash Player 10 & 10.1</name>
Ten replace them with this:
  <player id="FlashPlayer11" version="13" asversion="3">
   <name>Flash Player 11</name>
("version="13"" is not a spelling error)
Further more find a line that starts with: "playerglobal.swc" which we need to modify so it points to our "FP11" directory (created in the previous step).
Or you could just download the whole profile file from here: FlashPlayer11.zip

4. Theoretically that is all you need to export SWF files in their latest version. Unfortunately it is "theoretically", because in reality Flash Professional won't be able to open them, as it is using an older version of the player. Right now I have both good and bad news: that old player can be replaced... but only for the "debugger" (the usual move testing done by CTRL+ENTER won't work). That is why this is not a perfect workaround, but perhaps still better than nothing.
To replace the old Flash Player you will first need to download a latest debug projector: http://www.adobe.com/support/flashplayer/downloads.html ("Flash Player 11.0 Projector content debugger"). Then open the "Players" folder located in the Flash Profesional installation directory (for XP it will be: "C:\Program Files\Adobe\Adobe Flash CS5.5\Players"). There you will find "Debug" and within it "FlashPlayerDebugger.exe" which is a file you will need to replace with that projector gotten off Adobe site (while at the same time renaming it to " FlashPlayerDebugger.exe" most likely).

5. Now it is only a matter of starting Flash Professional and checking whether debugging actually works (CTRL+SHIFT+ENTER by default) while using the example from the documentation: flash.display3D.Context3D - ActionScript 3.0 Reference (at the very bottom; also read the comments under the example).