I have a series of movieclips containing both bitmaps and text.
After applying some 3d transformations and moving in 3d space, my text and bitmaps are slightly blurred. This is AFTER I reset all the 3d coordinates (ie z=0, rotationX=0, rotationY=0)
Has anyone else encountered this? Is there a solution to get my crisp text and bitmaps back?
this is a very interesting error.
the blur that appears is actually improper anti-aliasing, or smoothing that is usually solved by rendering the font with fine colors along the edges. in this case, it is in fact caused by 3D transformations and can be solved by nullifying the matrix3D after the animation:
myTextContainer.transform.matrix3D = null;
you could also write:
myTextContainer.transform.matrix = new Matrix();
but with this approach you'll have to import flash.geom.Matrix.
both options will also reset to zero the x and y coordinates, and possibly other important settings of the animated display object, so you'll also have to assign those values to variables and reapply them after nullifying the transform matrix.
it seems that once a font is transformed, it loses this fine color tinting. non transformed fonts have these color details while transformed fonts become completely desaturated.
attached is a zoomed in detail of 12 point font which exhibits this loss of color detail. the top string has no 3D transformation while the bottom string was animated onto the stage via rotationY.
here is the same image saturated to 90% to show the colors more clearly:
these color details are easier to see on grey text.
i believe this error has been present since Flash Player 9 / AVM2 was first introduced. additionally, the fine color detail around the properly rendered font was much more saturated in early versions of the Flash player, which, in my opinion, made the fonts look much better - although the difference could be considered negligible by non perfectionists unlike myself.
You need to make sure you set the matrix3D property to null on any objects that you've applied 3D transformation to.
Looking up another post on 3d issues and came across the solution.
You need to remove all 3d transformations by applying a new transfrom.matrix
var tempMatrix:Matrix = new Matrix();
this.transform.matrix = tempMatrix;
An Even better answer is to use this fix. It's one I used to use all the time.
/**
* Fixes the slight distortion that occurs when an object has a 3D transform associated with it.
* #param di:DisplayObject The DisplayOjbect to fix.
*/
public function fix3DBlur(di:DisplayObject):void {
di.scaleX = di.width / (di.width - 1);
di.scaleY = di.height / (di.height - 1);
}
This function sets a slightly offset scaleX and scaleY. It seems weird, but they when you make 3d adjustments to the object using any 3d property it keep it from looking blurry. You can always remove the 3DTransform, but sometimes you need it to stay in place.
I place this function on a Utilities3D class I have.
Related
I tried looking for this in search, but it is a lot of individual things packed together. What I am looking to make for my students is an interactive display of the triangle of exposure on a camera.
It has three sliders that show what happens with different settings. One is ISO (controls dark and lightness), another is shutter speed (which controls background blur/depth of field), and aperture, which controls motion blur. I was able to make a slider that effectively changes the test image in darkness. I am currently working on the slider for shutter speed.
I am wondering if the interaction between the sliders would be better accomplished through switching between PRE-PHOTOSHOPPED images by substitution, or using AS3 to accomplish changes on the fly. For instance, if they move the sliders for shutter speed and ISO at the same time, it gets dark AND has background blur. do I need to pre-photoshop every possible option, and switch symbols, or can I do it interactively with AS3?
Here is my code:
import flash.utils.getDefinitionByName;
import fl.motion.Color;
import fl.events.SliderEvent;
var myImageName1 = "blurback.jpg";
var classRef:Class = getDefinitionByName(myImageName1) as Class;
var instance:MovieClip = new classRef();
var c:Color=new Color();
var color = "#000000";
ISO.addEventListener(SliderEvent.CHANGE, sliderChanged);
aperture.addEventListener(SliderEvent.CHANGE, apertureChanged);
function sliderChanged(evt:SliderEvent):void {
tintClip();
}
/*
The 'setTint' method of of the Color class takes two parameters: tint
multiplier,
(a number between 0 and 1), and a tint color.
The tint multiplier, is determined by the positon of the slider, 'val'
and equals val/100.
The tint color, 'color', is determined by the color selected
in the picker.
*/
function tintClip():void {
var val:Number=ISO.value;
c.setTint(color,val/10);
kitty.transform.colorTransform=c;
}
function apertureChanged(evt:SliderEvent):void {
gotoAndPlay(2);
/*kitty.addChild(instance);*/
}
I am still experimenting with the second slider, so the gotoand play is a work in progress on substituting a pre-background-blurred image when the slider is slid.
Here is a pic of the final image, with the sliders named appropriately.
link: Final image
One is ISO (controls dark and lightness), another is shutter speed (which controls background blur/depth of field), and aperture, which controls motion blur.
ahem
All of the three settings influence the exposure value, making the image lighter or darker. Additionally:
ISO has an effect on noise in the image, which can severely degrade image quality
shutter speed is actually the one influencing motion blur and visibility of camera shake
aperture (among other things) influences depth of field
I am wondering if the interaction between the sliders would be better accomplished through switching between PRE-PHOTOSHOPPED images by substitution, or using AS3 to accomplish changes on the fly.
Neither of them is a good option.
Recreating the effects of the different settings with As3
realistically will take a lot more time (if possible at all) than simply having several images.
Recreating the effects in photoshop is probably easier as it is equipped with dozens of photo editing tools, but you'd still have to create the effect realistically.
Instead of photoshopping things, show your students the real deal:
Setup a subject in front of a background to show possible changes in depth of field
Include a solid color area where noise will be easy to see. This could be the background.
Add some motion, to show motion blur. A fan as a subject comes to mind.
Then take those images by varying the settings. Sure, with 5 different values each, you get 125 images. But you get real world example photos.
Keep the resolution low, so that the image files aren't too big. Process them by reducing resolution further to a reasonable size, say 800 x 600.
With the images created load them into your swf with the Loader class. The easiest way to keep track of them is to have a three dimensional array of Loader objects. Each slider then manipulates one index to change the image.
I got some strange issues with transparency and 3d particles. A short vid to illustrate:
https://youtu.be/ZHKI1X3MjhY
As you can see I have a 3d particle effect, fire burning. Inside it is a 3 model with no alpha blending and it shows just fine. then in the far distance there is a small skeleton (with blending and alphatest turned on) and it also shows just fine through the fire. Then I turn camera and look at the warrior skeleton and it just disappear and instead you see what is behind him. I turn camera again and the mage skeleton also vanishes, but you can see the trees a bit further away just fine and they have the exact same settings for blending and alpha test. If I move the character say 20 yards away it also starts showing through the fire effect.
So it seems to have something to do with distance from the 3d particle effect...
The 3d particle batch is an extended BillboardParticleBatch like this:
protected Renderable allocRenderable(){
BlendingAttribute ba=new BlendingAttribute(GL20.GL_SRC_ALPHA, GL20.GL_ONE,1f);
Renderable r = super.allocRenderable();
r.material = new Material( ba,
// new DepthTestAttribute(GL20.GL_LEQUAL, 0.0f, 0.5f, true),
// r.material.set(new FloatAttribute(FloatAttribute.AlphaTest, 0.0f),
TextureAttribute.createDiffuse(texture));
return r;
}
All the characters and the trees are created with following attributes:
if (alpha) {
FloatAttribute floatAttribute = new FloatAttribute(FloatAttribute.AlphaTest, 0.5f);
BlendingAttribute blendingAttribute = new BlendingAttribute(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, 1f);
for (int i = 0; i < bulletEntity.modelInstance.materials.size; i++){
bulletEntity.modelInstance.materials.get(i).set(blendingAttribute);
bulletEntity.modelInstance.materials.get(i).set(floatAttribute);
}
}
The models are drawn first then the particles, I tried changing order but no difference. I have tried a lot of different setups for alphatest, depthtest and blendingattribute but can not find anything that works.
EDIT
I removed the Blending attribute from the 3d-models and now it looks as it should regarding the particle effect. However I need most materials on my character models to have blending set..
Anyone got any clue why this is happening when I enable blending?
I also tried to use the BillboardParticleBatch without extending it in case I had done something there but the effect then is even worse. All models with blending enabled appear in-front of the particle effect even though they stand behind it.
ModelBatch sorts your render calls (check this link, really, it is a must read), to avoid incorrect behavior (as you're experiencing). The actual sorting/rendering happens at the call to ModelBatch#end. By default it uses the DefaultRenderableSorter, which is a default implementation. Of course, because that implementation isn't aware of your scene, it might not fit exactly your needs.
The DefaultRenderableSorter tries to guess the location of each model based on their transformation matrix. Based on that location and the camera's location it will sort them so that:
First all opaque objects are rendered from front to back (because whatever is behind an opaque object isn't visible anyway, so that reduces unneeded calls to the fragment shader).
Secondly all transparent objects are rendered from back to front (because as soon as a transparent object is rendered then everything that is rendered after that and is behind it, will not be visible).
To decide whether an object is transparent, the BlendingAttribute#blended member is used. (So you could, if you really wanted to, set that member to false to force it to be treated (sorted) as if it was opaque)
So, the order in which you call ModelBatch#render is not necessarily the order in which they are actually executed. If you want to force to render whatever you've added to the batch in between, then call the ModelBatch#flush(). Of course, doing this a lot defeats some of the purpose of ModelBatch in the first place.
Instead you could implement your own RenderableSorter which has more knowledge about your scene and can therefor do a better job sorting than the default implementation. (however if flush() works for you and there's no other issue, then just flush might be the easiest solution for you).
That said, there a various other solutions you could try as well. E.g. the regions of the particles are fully transparent, so the fragment shader might as well discard those all together. Try adding FloatAttribute.AlphaTest with a value of 0.5f to the particles. If that messes with your blending then gradually reduce the value to e.g. 0.05f.
Also, you could add a DepthTestAttribute with depthMask set to false (new DepthTestAttribute(false)). This will prevent the particles from writing to the depth buffer. (but also might cause other things to show in front of the particles).
I'm currently doing the following when applying a mask to a MovieClip:
mc1.cacheAsBitmap = true;
_mask.cacheAsBitmap = true;
mc1.mask = _mask;
Which works great, however...
mc1 is a complex vector animation, and cacheing it as a bitmap in order to mask it has pretty big memory implications from what I can see, and have read.
Is their another way to implement masks? Or a way to optimise the usual solution?
Thanks
edit
Both the mask and mc1 are MovieClips, and they have been added to the stage, the mask is a gradient.
I am using Flash CS6, both movieclip and mask are added to the timeline, where they are being animated
You can use http://www.greensock.com/blitmask/
Quote from the documentation:
Can’t I just set the target DisplayObject’s cacheAsBitmap property to true and get the same result? Why use BlitMask?
If you set a DisplayObject’s cacheAsBitmap property to true, Flash takes a bitmap capture of that object so that when you move it (only
altering the x and/or y properties), the text and vectors don’t need
to be re-rasterized again before being rendered to the screen.
However, Flash would still need to concern itself with extra pixels on
every frame if you’re masking them to only show a small portion of the
area. BlitMask, however, only cares about that smaller masked area
(after the initial capture of course) which alleviates Flash from
having to even think about the extra pixels.
I have an imported png in a 'info_icon' symbol.
I have another imported png in a 'info_content' symbol.
I have some code that allows you to drag an instance of a 'map' symbol around. Inside this map symbol are instances of 'info_icon' and 'info_content'.
When I drag the map slowly, I can see the info_icon instances and info_content instances, jiggle ever so slightly...I think to line up to pixels.
I'm trying to figure out how to stop that. I'm looking at the pixelSnapping property and it doesn't seem to be helping...perhaps I'm using it wrong.
info_button_mc.pixelSnapping = PixelSnapping.NEVER;
Make sure to set smoothing to true on the bitmap.
Try setting scaleX to 0.999 or something like that (in other words, close enough to 1 that you can't tell it's being scaled).
For some reason smoothing doesn't seem to actually get applied unless the scale of the object is something other than 1.
Remember you should be working with bitmaps here, so make sure to export the PNG for ActionScript (right click on PNG->properties) and give it a class name and then:
var bitmap : Bitmap = new Bitmap(new YourPNG(), PixelSnapping.NEVER);
addChild(bitmap);
bitmap.smoothing = true;
bitmap.scaleX = 0.999;
Is info_button_mc a MovieClip or a Bitmap? In addition to what Pixel Elephant suggested, make sure the cacheAsBitmap property is false on the bitmap and its container (if the container is involved with the bitmap's movement). CacheAsBitmap will always pixel snap and it's worth noting that any filters you may have active automatically set cacheAsBitmap to true.
Instead of setting the scale to 0.999 which will result in a blurry image, try rendering your image at double resolution (as in the source image: png, bitmap, whatever - make it twice as big in each dimension as what you actually want in the swf) and then setting the scale to .5. In my experience, this is the best of both worlds. That said, it still may not be perfect enough for text - but it is substantially better quality than setting the scale to 0.999.
I know that there are people out there creating classes for this (ie http://coreyoneil.com/portfolio/index.php?project=5). But I want to learn how to do it myself so I can create everything I need the way I need.
I've read about BitMap and BitMapData. I should be able to .draw the MovieClips onto a BitMap so I could then cycle the pixels looking for the collisions. However, It's weird and confusing dealing with the offsets.. And it seams like the MyBitMap.rect has always x = 0 and y = 0... and I can't seam to find the original position of the things...
I'm thinking of doing a hitTestObject first, then if this was positive, I would investigate the intersection betwen the movieclips rectangles for the pixel collisions.
But then there is also another problem (the rotation of movieclips)...
...I need some enlightment here on how to do it.
Please, any help would be appreciated..
If you're using BitmapData objects with transparency you can use BitmapData.hitTest(firstPoint:Point, firstAlphaThreshold:uint, secondObject:Object, secondBitmapDataPoint:Point = null, secondAlphaThreshold:uint = 1):Boolean.
You'll have to change from global coords to the local BitmapData coords which will require a bit of math if it is rotated. That's easily achieved (look up affine transform for more info on wiki):
var coordTransform:Matrix = new Matrix();
coordTransform.rotate(rotationRadians);
coordTransform.translate(x, y);
coordTransform.transformPoint(/* your point */);
A classic reference for pixel perfect collision detection in flash is this Grant Skinner's article. It's AS2, but the logic is the same for AS3 (there are ports available if you google a bit).
If I recall correctly, this particular implementation worked as long as both tested objects had the same parent, but that can be fixed.
About BitmapData x and y values, I understand it could be confusing; however, the way it works makes sense to me. A BitmapData is just what the name implies: pixel data. It's not a display object, and cannot be in the display list; so having x or y different than 0 doesn't really make sense, if you think about it. The easiest way to deal with this is probably storing the (x,y) offset of the source object (the display object you have drawn from) and translate it to the global coordinate space so you can compare any objects, no matter what's their position in the display list (using something like var globalPoint:Point = source.parent.localToGlobal(new Point(source.x,source.y)).
I've previously used Troy Gilbert's pixel perfect collision detection class (adapted from Andre Michelle, Grant Skinner and Boulevart) which works really well (handles rotation, different parents, etc.):
http://troygilbert.com/2007/06/pixel-perfect-collision-detection-in-actionscript3/
http://troygilbert.com/2009/08/pixel-perfect-collision-detection-revisited/
and from there he has also linked to this project (which I've not used, but looks really impressive):
http://www.coreyoneil.com/portfolio/index.php?project=5
I managed to do it after all, and I already wrote my class for collision detections,/collisions angle and other extras.
The most confusing process is maybe to align the bitmaps correctly for comparing. When whe draw() a movieclip into a a BitmapData, if we addChild() the corresponding Bitmap we can see that part of it is not visible. it appears to be drawn from the center to right and down only, leaving the top and left parts away from beeing drawn. The solution is giving a transform matrix in the second argument of the draw method that aligns the bitmap and makes it all be drawn.
this is an example of a function in my class to create a bitmap for comparing:
static public function createAlignedBitmap(mc: MovieClip, mc_rect: Rectangle): BitmapData{
var mc_offset: Matrix;
var mc_bmd: BitmapData;
mc_offset = mc.transform.matrix;
mc_offset.tx = mc.x - mc_rect.x;
mc_offset.ty = mc.y - mc_rect.y;
mc_bmd = new BitmapData(mc_rect.width, mc_rect.height, true, 0);
mc_bmd.draw(mc, mc_offset);
return mc_bmd;
}
in order to use it, if you are on the timeline, you do:
className.createAlignedBitmap(myMovieClip, myMovieClip.getBounds(this))
Notice the use of getBounds which return the rectangle in which the movie clip is embedded. This allows the calculation of the offset matrix.
This method is quite similar to the on shown here http://www.mikechambers.com/blog/2009/06/24/using-bitmapdata-hittest-for-collision-detection/
By the ways, if this is an interesting matter for you, check my other question which I'll post in a few moments.