Extract derived 3D scaling from a Sprite to set to a 2D billboard - actionscript-3

I am trying to get the derived position and scaling of a 3D Sprite and set them to a 2D Sprite.
I have managed to do the first part like this:
var p:Point = sprite3d.local3DToGlobal(new Vector3D(0,0,0));
billboard.x = p.x;
billboard.y = p.y;
But I can't get the scaling part correctly. I am trying this:
var mat:Matrix3D = sprite3d.transform.getRelativeMatrix3D(stage); // get derived matrix(?)
var scaleV:Vector3D = mat.decompose()[2]; // get scaling vector from derived matrix
var scale:Number = scaleV.length;
billboard.scaleX = scale;
billboard.scaleY = scale;
...but the result is apparently wrong.
PS. One might ask what I am trying to achieve. I am trying to create "billboard" 3D sprites, i.e. sprites which are affected by all 3D transformations except rotations, thus they always face the "camera".

The documentation says that you get the vector correctly, but its coefficients don't seem to be added together to form a single length value. Try first an unscaled sprite, and check if you're receiving a sqrt(3) value as its length. If yes, then you should use 0th element of the vector as X scale, and 1th as Y scale. I'm not sure what to do with 2nd element (in this case it'll be a Z scale, either divide both scales by it, or multiply by it). Hope that helped.

Related

manipulating ndarray dimension with function and adding new data to it

I'm using this to control the color scale on a fractal drawing program. I was wondering if there was a way to eliminate the r,g,b variable and insert the result right into the img ndarray? I have fiddled with adding a new dimension with np.expand_dims, but the shape turns into (5,5,1) instead of (5,5,3) like I need. reshaping it seems to be a nightmare.
import numpy as np
#img is an array of values to be converted into RGB from another process
img = np.arange(25)
img = np.reshape(img,(5,5))
#simplified example of original process
r = img*2
g = img*3
b = img*4
#creating new array to accomidate the higher dimension
img = np.array([r,g,b], dtype = np.uint8)
#no longer needed
del r,g,b
#rolling axis for PIL Image.fromarray compatibily
img = np.rollaxis(img,0,3)
img = np.rollaxis(img,0,2)
print(img)
img starts as a (5,5) array. That's one value for each of the 25 pixels.
The new array after joining the r,g,b arrays is (3,5,5).
The first rollaxis changes that into a (5,5,3) array.
np.stack([r,g,b], axis=2)
would have done the same.
The second rollaxis swaps the first two dimensions, in effect transposing the original image. (in fact both rollaxis could be replaced with one img.transpose().
Even when you use expand_dims you still make a new array (though it does share the databuffer with the original). But (5,5,1) still doesn't have space to store the 3 color values. The original has 25 values, the new image has 75. You have to make a new array in one way or the other.
To better understand the rollaxis part, I suggest playing with an array like
arr = np.arange(24).reshape(3,2,4)
different sizes in all 3 dimensions make it easier to see the changes in shape.

HTML5 Canvas save() and restore() performance

So the issue that I'm having is that in developing an HTML5 canvas app I need to use a lot of transformations (i.e. translate, rotate, scale) and therefore a lot of calls being made to context.save() and context.restore(). The performance drops very quickly even with drawing very little (because the save() and restore() are being called as many times as possible in the loop). Is there an alternative to using these methods but still be able to use the transformations? Thank you!
Animation and Game performance tips.
Avoid save restore
Use setTransform as that will negate the need for save and restore.
There are many reasons that save an restore will slow things down and these are dependent on the current GPU && 2D context state. If you have the current fill and/or stroke styles set to a large pattern, or you have a complex font / gradient, or you are using filters (if available) then the save and restore process can take longer than rendering the image.
When writing for animations and games performance is everything, for me it is about sprite counts. The more sprites I can draw per frame (60th second) the more FX I can add, the more detailed the environment, and the better the game.
I leave the state open ended, that is I do not keep a detailed track of the current 2D context state. This way I never have to use save and restore.
ctx.setTransform rather than ctx.transform
Because the transforms functions transform, rotate, scale, translate multiply the current transform, they are seldom used, as i do not know what the transform state is.
To deal with the unknown I use setTransform that completely replaces the current transformation matrix. This also allows me to set the scale and translation in one call without needing to know what the current state is.
ctx.setTransform(scaleX,0,0,scaleY,posX,posY); // scale and translate in one call
I could also add the rotation but the javascript code to find the x,y axis vectors (the first 4 numbers in setTransform) is slower than rotate.
Sprites and rendering them
Below is an expanded sprite function. It draws a sprite from a sprite sheet, the sprite has x & y scale, position, and center, and as I always use alpha so set alpha as well
// image is the image. Must have an array of sprites
// image.sprites = [{x:0,y:0,w:10,h:10},{x:20,y:0,w:30,h:40},....]
// where the position and size of each sprite is kept
// spriteInd is the index of the sprite
// x,y position on sprite center
// cx,cy location of sprite center (I also have that in the sprite list for some situations)
// sx,sy x and y scales
// r rotation in radians
// a alpha value
function drawSprite(image, spriteInd, x, y, cx, cy, sx, sy, r, a){
var spr = image.sprites[spriteInd];
var w = spr.w;
var h = spr.h;
ctx.setTransform(sx,0,0,sy,x,y); // set scale and position
ctx.rotate(r);
ctx.globalAlpha = a;
ctx.drawImage(image,spr.x,spr.y,w,h,-cx,-cy,w,h); // render the subimage
}
On just an average machine you can render 1000 +sprites at full frame rate with that function. On Firefox (at time of writing) I am getting 2000+ for that function (sprites are randomly selected sprites from a 1024 by 2048 sprite sheet) max sprite size 256 * 256
But I have well over 15 such functions, each with the minimum functionality to do what I want. If it is never rotated, or scaled (ie for UI) then
function drawSprite(image, spriteInd, x, y, a){
var spr = image.sprites[spriteInd];
var w = spr.w;
var h = spr.h;
ctx.setTransform(1,0,0,1,x,y); // set scale and position
ctx.globalAlpha = a;
ctx.drawImage(image,spr.x,spr.y,w,h,0,0,w,h); // render the subimage
}
Or the simplest play sprite, particle, bullets, etc
function drawSprite(image, spriteInd, x, y,s,r,a){
var spr = image.sprites[spriteInd];
var w = spr.w;
var h = spr.h;
ctx.setTransform(s,0,0,s,x,y); // set scale and position
ctx.rotate(r);
ctx.globalAlpha = a;
ctx.drawImage(image,spr.x,spr.y,w,h,-w/2,-h/2,w,h); // render the subimage
}
if it is a background image
function drawSprite(image){
var s = Math.max(image.width / canvasWidth, image.height / canvasHeight); // canvasWidth and height are globals
ctx.setTransform(s,0,0,s,0,0); // set scale and position
ctx.globalAlpha = 1;
ctx.drawImage(image,0,0); // render the subimage
}
It is common that the playfield can be zoomed, panned, and rotated. For this I maintain a closure transform state (all globals above are closed over variables and part of the render object)
// all coords are relative to the global transfrom
function drawGlobalSprite(image, spriteInd, x, y, cx, cy, sx, sy, r, a){
var spr = image.sprites[spriteInd];
var w = spr.w;
var h = spr.h;
// m1 to m6 are the global transform
ctx.setTransform(m1,m2,m3,m4,m5,m6); // set playfield
ctx.transform(sx,0,0,sy,x,y); // set scale and position
ctx.rotate(r);
ctx.globalAlpha = a * globalAlpha; (a real global alpha)
ctx.drawImage(image,spr.x,spr.y,w,h,-cx,-cy,w,h); // render the subimage
}
All the above are about as fast as you can get for practical game sprite rendering.
General tips
Never use any of the vector type rendering methods (unless you have the spare frame time) like, fill, stroke, filltext, arc, rect, moveTo, lineTo as they are an instant slowdown. If you need to render text create a offscreen canvas, render once to that, and display as a sprite or image.
Image sizes and GPU RAM
When creating content, always use the power rule for image sizes. GPU handle images in sizes that are powers of 2. (2,4,8,16,32,64,128....) so the width and height have to be a power of two. ie 1024 by 512, or 2048 by 128 are good sizes.
When you do not use these sizes the 2D context does not care, what it does is expand the image to fit the closest power. So if I have an image that is 300 by 300 to fit that on the GPU the image has to be expanded to the closest power, which is 512 by 512. So the actual memory footprint is over 2.5 times greater than the pixels you are able to display. When the GPU runs out of local memory it will start switching memory from mainboard RAM, when this happens your frame rate drops to unusable.
Ensuring that you size images so that you do not waste RAM will mean you can pack a lot more into you game before you hit the RAM wall (which for smaller devices is not much at all).
GC is a major frame theef
One last optimisation is to make sure that the GC (garbage collector) has little to nothing to do. With in the main loop, avoid using new (reuse and object rather than dereference it and create another), avoid pushing and popping from arrays (keep their lengths from falling) keep a separate count of active items. Create a custom iterator and push functions that are item context aware (know if an array item is active or not). When you push you don't push a new item unless there are no inactive items, when an item becomes inactive, leave it in the array and use it later if one is needed.
There is a simple strategy that I call a fast stack that is beyond the scope of this answer but can handle 1000s of transient (short lived) gameobjects with ZERO GC load. Some of the better game engines use a similar approch (pool arrays that provide a pool of inactive items).
GC should be less than 5% of your game activity, if not you need to find where you are needlessly creating and dereferencing.

ActionScript 3: Zoom into movieclip while not scaling its childrens

I've included a zoom functionality similar to the one explained at this website:
http://www.flashandmath.com/howtos/zoom/
This works perfectly on my background image(a map, that is), but I want to keep the symbols on my map the same size while zooming in.
I probably could work this out by changing all the children's size when calling the zoom-function, but I am hoping there is some kind of easy code adapt in my children class to make the size of the instances unchangable. Is there?
Thanks!
One crude way, so you don't have to calculate the symbols scale, would be to remove the symbols from the mapDisplayObject so they're no longer a child and instead put symbol placeholders. Then match each symbol's x and y to each place holder, using localToGlobal...
If your children are not scaled or skewed or rotated you can iterate all of them and set transformation matrix to 1/parentScale. Something like:
for each (var child:DisplayObject in parent) {
var matrix:Matrix = child.transform.matrix;
matrix.a = 1/parentScale;
matrix.d = 1/parentScale;
child.transform.matrix = marix;
}

AS3 MovieClip getRealBounds

As you well know in as3 we have a getBounds() method which returns the exact dimension and coordinates of the movieclip in the DisplayObject container we want.
Fact is that these data are calculated based on the graphics in their state in the MC at the frame it is while getBounds() is called.
What I want is the REAL bounds rectangle, that is the larger rectangle that the WHOLE animated movieclip will take in its container.
I thought of two ways:
1 - a flash built-in method that I don't know
2 - going through every frame always getting the bounds and finally returning the biggest (but what if it's a long animation? should I wait for it to play completely before I can get what I want?)
I hope I've been clear. If you need examples, let me know!
You can iterate through each frame without having to wait for the animation to play:
Let's say your clip is called bob:
var lifetimeBounds:Rectangle = new Rectangle();
bob.gotoAndStop(1);
for(var i:int=1;i<=bob.totalFrames;i++){
lifetimeBounds.width = Math.max(lifetimeBounds.width, bob.width);
lifetimeBounds.height = Math.max(lifetimeBounds.height, bob.height);
lifetimeBounds.x = Math.min(lifetimeBounds.x, bob.x);
lifetimeBounds.y = Math.min(lifetimeBounds.y, bob.y);
bob.nextFrame();
}
bob.gotoAndStop(1); //reset bob back to the beginning
It's more CPU taxing (so I'd recommend not using it if the above works for your situation), but you could also use getBounds() in the example above and compare the returned rectangle against the lifetimeBounds rectangle:
var tempRect:Rectangle;
var lifetimeBounds:Rectangle = new Rectangle();
bob.gotoAndStop(1);
for(var i:int=1;i<=bob.totalFrames;i++){
tmpRect = bob.getBounds(this);
lifetimeBounds.width = Math.max(lifetimeBounds.width, tempRect.width);
lifetimeBounds.height = Math.max(lifetimeBounds.height, tempRect.height);
lifetimeBounds.x = Math.min(lifetimeBounds.x, tempRect.x);
lifetimeBounds.y = Math.min(lifetimeBounds.y, tempRect.y);
bob.nextFrame();
}
I had this issue when converting animations to bitmapData frames, as I wanted all the resulting frames to be a uniform size and match the largest frame dimensions.
I basically had to loop through the animation 1 frame at a time and compare the bounding box to the current largest dimensions. I too thought it was a less than an ideal solution, but it worked.
So #2 is your best bet, as there is no flash built in method that provides what you seek.

AS3 - geometry - perspective projection of a point on a 2D plane

I'm currently struggling on a problem that seems far beyond my maths capacities (been a long time since I've made some proper maths...) and I would appreciate some help on that.
Here's my setting :
I got some simple shapes (rectangles), and I "project" their bottom points on a line, coming from an Origin point.
Up to this point everything is fine.
But now I'd like to draw the original shape distorted as if it was projected with some perspective on a plane.
Please consider that I have nothing related to any rotation, isometric or any 3D or fake 2D perspective in my code, I'm only trying to draw some shapes using the graphics library to only have a feeling of something real.
Here's a quick drawing of what I'm trying to do :
What I know :
Origin point coordinates
the rect position & sizes
the red line position
the A & B points coordinates
What I want to determine is the coordinates of the C & D points, thing that could be easy if I wasn't struggling to find the "Origin bis" coordinates.
What I'm trying to do is to fake the projection of my rectangle on something that can be considered as a "floor" (related to the plane where my original rectangle is that can be seen as a wall).
Maybe I'm over-complicating the problem or maybe I fail to see any other easier way to do it, but I'm really not good anymore in any geometry or maths thing... :-(
Thanks a lot for your answers !
hmm i don't know if I undestood it correctly but I think you have too few input parameters:
you said the following information is given:
Origin point coordinates
the rect position & sizes
the red line position
the A & B points coordinates
I don't think it is possible to get your projected rectangle with this information alone.
Additionally, I think your green lines and the 'origin Bis' aren't helpful as well.
Perhaps, try this:
Supose, a blue line going through the points C & D is given as well.
Then you could find your projected rectangle by projecting the top of the rectangle onto that blue line.
So in summary:
You define an origin + two parallel lines, a red and a blue one.
Then you can project the top of the rect onto the blue line and the bottom of the rect onto the red line, yielding the points A,B,C,D
I hope this helps.
If I'm right, this code will show what you wanted to see.
First of all, I've ignored your initial setup of objects and information, and focused on the example situation itself; fake-projecting shadow for a "monolith" (any object is possible with the example below, even textured)
My reason was that it's really quite easy with the Matrix class of ActionScript, a handy tool worth learning.
Solution:
You can use the built-in Matrix class to do skew transform on DisplayObjects.
Try this example:
(The "useful" part lies in the _EF EnterFrame handler ;) )
import flash.display.MovieClip;
import flash.geom.Matrix;
import flash.events.Event;
import flash.display.BitmapData;
const PIP180:Number = Math.PI / 180;
const MAX_SHADOW_HEIGHT_MULTIPLIER:Number = 0.25; // you can also calculate this from an angle, like ... = Math.sin(angle * PIP180);
const ANIM_DEG_PER_FRAME:Number = 1.0 * PIP180; // the shadow creeps at a +1 degree per frame rate
var tx:BitmapData = new MonolithTexture(); // define this BitmapData in the library
var skew:Number = -10 * PIP180; // initial
var mono:MovieClip = new MovieClip();
mono.graphics.beginBitmapFill(tx);
// drawn that way the registration point is 0,0, so it's standing on the ground
mono.graphics.drawRect(0, -tx.height, tx.width, tx.height);
mono.graphics.endFill();
// align monolith to the "ground"
mono.x = stage.stageWidth / 2;
mono.y = stage.stageHeight - 100;
// make it be 100x300 pixel
mono.width = 100;
mono.height = 300;
var shad:MovieClip = new MovieClip();
// colored:
shad.graphics.beginFill(0x000000);
// or textured:
//shad.graphics.beginBitmapFill(tx);
shad.graphics.drawRect(0, -tx.height, tx.width, tx.height);
shad.graphics.endFill();
addChild(shad); // shadow first
addChild(mono); // then the caster object
addEventListener(Event.ENTER_FRAME, _EF);
function _EF(e:Event):void {
// animate skew on the positive half circle
skew = (skew + ANIM_DEG_PER_FRAME) % Math.PI;
// Matrix takes 6 parameters: a, b, c, d, x, y
// for this shadow trick, use them as follows:
// a = width scaling (as mono and shad are drawn in the same way, copy mono.scaleX for a perfect fit
// b = 0, because we don't want to project the vertical axis of transformation to the horizontal
// c = horizontal skew
// d = height scaling * skew * making it a bit flat using the constant
// x = mono.x, ...
// y = mono.y since originally mono and shad look alike, only the Matrix makes shad render differently
var mtx:Matrix = new Matrix(mono.scaleX, 0, Math.cos(skew), mono.scaleY * Math.sin(skew) * MAX_SHADOW_HEIGHT_MULTIPLIER, mono.x, mono.y);
shad.transform.matrix = mtx;
}
Now all you got to know to utilize this in your case, is the following N factors:
Q1: from what angle you want to project the shadow?
A1: horizontal factor is the skew variable itself, while vertical angle is stored as constant here, called MAX_SHADOW_HEIGHT_MULTIPLIER
Q2: do you want to project shadow only "upwards", or freely?
A2: if "upwards" is fine, keep skew in the positive range, otherwise let it take negative values as well for a "downward" shadow
P.S.: if you render the internals of the objects that they don't snap to 0 y as a base point, you can make them seem float/sink, or offset both objects vertically with a predefined value, with the opposite sign.
You face 1 very simple problem, as you said:
'What I want to determine is the coordinates of the C & D points, thing that could be easy if I wasn't struggling to find the "Origin bis" coordinates.'
But these co-ordinates relate to each other, so without one (or another value such as an angle) you cannot have the other. If you are to try this in 3D you are simply allowing the 3D engine to define 'Origin bis' and do your calculating for C and D itself.
So regardless you will need an 'Original bis', another value relating to the redline or your Rect for which to calculate the placement of C and D.
I remember making stuff like this and sometimes it's better to just stick with simple, you either make an 'Original bis' defines by yourself (it can be either stationary or move with the player/background) and get C and D the way you got A and B only that you use a lower line than the red line, or as I would of done, once you have A and B, simple skew/rotate your projection from those points down a bit further, and you get something the same as an 'Original bis' that follows the player. This works fine at simulating 'feeling of something real' but sadly as has been said, it looking real depends on what you are portraying. We do not know what the areas above or below the red line are (sky/ground, ground/water) and whether 'Origin' and 'Origin bis' is your light source, vanishing point, etc.