Merge remote-tracking branch 'origin/master'

This commit is contained in:
Leonid Gaev
2012-08-16 15:34:29 +06:00
17 changed files with 1736 additions and 1305 deletions

196
changelog_en.txt Normal file
View File

@@ -0,0 +1,196 @@
Changelog Alternativa3D
NEXT
----
Added:
+ Added:
+ Object3DUtils: setPosition, lookAt to Camera3D and converting between Radians and Degrees
+ Stage3D constrained profile support
+ BitmapTextureResource: auto resize for GPU option
+ MouseEvent3D: right and middle mouse buttons support (FP 11.2 and -swf-version=15 required)
+ Object3D: excludeLight()
+ OmniLightShadow: add omni radius in debug scale
+ Camera3D: light sorting
Fixed:
= Object3D.toString()
= AnimationClip: animated and loop properties in AnimationClip.slice(), AnimationClip.clone()
= Bubbling in MouseEvent3D
= ExporterA3D: export meshes without geometry as Object3D
= Box: correct tangents and binormals
= WireFrame:fix createBinormals()
= Decal: Fixed incorrect drawing with extremaly low nearClipping.
= View: Fixed bug with mouse events and postprosessing
= Several minor fixes
Removed:
-Diagram: removed CPU time
8.31.0
---
= Rendering optimizations
= Increased materials performance
= AnimationController:fixed error when using notifiers cause animation goes in infinite loop
= Camera3D: fixed a bug with duplicating diagram
8.30.0
---
Fixed:
= OmniLightShadow: fixed some errors and increased performance
= ParserCollada: loading Skin without normals and tangents
= ParserA3D: parsing scene with spot lights
= DirectionalLigthShadow, OmniLightShadow:default value of biasMultiplyer property was changed to 0.97
= StandardMaterial:removed traces
8.29.0
---
Added:
+ Possibility to use unlimited light sources and shadows count with StandardMaterial
+ A flag Object3D.useShadow which controls shadow visibility on object.
+ OmniLightShadow class
Fixed:
= Fixed issue with Skin lighting
= StandardMaterial does not throw exception about limitation number of light sources and shadows anymore.
8.27.0
----
Added:
+ Added DirectionalLightShadow class for calculation of shadow from directional light source.
+ ParserA3D: implemented import of animation, LOD objects and layers from binary format A3D.
+ ExporterA3D: implemented export of Skin class objects, animation and materials to binary format A3D.
+ Added rendering of materials with alpha-test and two-pass alpha-test.
API of materials has been changed: now, if you want to show objects with translucent textures, you must to set value of alphaThreshold.
+ Implemented EnvironmentMaterial with simulation of reflection on cube texture.
+ StandardMaterial: added ability to use pre-computed texture of light together with dynamic light.
+ Added check for maximum number of light sources influencing on object.
+ Added LOD class for switching of detail levels depending on the distance between camera and object.
+ Implemented Occluder class that removes objects, covered by obstacles from rendering.
+ Object3D: added field userData with type Object.
+ Skin, Joint: added methods of setting and calculation of bind position matrix.
+ Skin: implemented method of bound-box calculation, taking into account bone transformation.
+ Geometry: added calculateNormals() and calculateTangents() methods for calculation of normals and vertex tangents, respectively.
+ Added cloning methods at all materials and Camera3D class.
+ Added base Parser class, that is parent class for ParserA3D, ParserCollada and Parser3DS.
+ Camera3D: added display of average frame time and CPU calculation time in statistics.
+ ParserCollada: now you can import intensivity for light sources.
Fixed:
= Fixed incorrect engine work after changing of current Context3D.
= ExporterA3D: fixed the export of materials to binary format A3D.
= Fixed some problems with mouse events:
- mouse events at flash player version 11.1;
- mouse events at software rendering;
- mouse events with non-convex objects.
= VertexLightTextureMaterial: fixed incorrect light from SpotLight.
= Object3D: removed incorrect dispatch of events Event3D.ADDED, Event3D.REMOVED when you re-add object to its parent.
= AmbientLight, DirectionalLight: fixed calculation of bound-box.
= Wireframe: fixed bug with incorrect thickness of lines on some sizes of view.
= Optimized playing of animation.
= Accelerated the import and creation of animation using format parser.
= View: fixed joint work with Flash-profiler.
Removed:
- Removed support of Flash Player Incubator.
- TextureMaterial: removed parameter useDiffuseAlphaChannel.
- Skin: parameter numJoints removed from constructor.
8.17.0
----
+ ParserA3D: added the import of objects of Skin type and the import of light sources.
+ Added Parser3DS class for import models from 3DS format.
+ Added intersectRay() - The method of finding a ray intersects with an object of Mesh type.
+ Added AxisAlignedSprite class to display plane oriented along one axis to the camera.
+ Export to the binary format A3D is supported.
+ Added debug mode displaying of objects bounds.
+ Added primitive Plane.
+ GeoSphere primitive has normals and tangents of vertices after creation.
+ Normalmaps supported with left-sided system of coordinates in StandardMaterial.
= Decal: removed the offset property and changed the logic of work.
= StandardMaterial: fixed a bug with lighting of some light sources.
= FillMaterial: color in construstor is grey by default now.
= Box: constructor is optimized.
= Box: fixed a bug in the cloning of the primitive. Surfaces is not duplicated now.
= WireFrame.getResources() allows parameter resourceType now.
8.12.0
----
+ The Public version Flash Player 11 Beta 2 is now supported.
+ The orthographic mode has been added to the Camera3D.
+ The MouseEvent system has been optimized and accelerated.
+ Logo "AlternativaPltaform" has been updated.
+ Now when objects are added and removed from the parent, the event will be sent (Event3D.ADDED, Event3D.REMOVED).
+ The ability to change the property renderToBitmap into View after creating has been added.
= The height and width of the View has been limited to the minimum size of 50x50.
= Bug in mouse events system when used skins divided on surfaces by divide() was fixed.
= A bug has been fixed in Decal.
= Skin lighting algorithm changed to more precise one.
= ParserCollada: Fixed a bug when binormal vector of the vertices of the object was incorrectly parsed.
= The value of backgroundAlpha in the View constructor changed to 1.0 by default.
= VertexLightTextureMaterial now draws correctly without lights in scene.
= MouseEvent3D was moved from alternativa.engine3d.core to alternativa.engine3d.core.events.
= A bug has been fixed in Object3D.dispatchEvent().
= The offset property has been added to the constructor Decal and it is compulsory.
= Now the offset property can be copied using the clone () method of class Decal.
- The ratio property has been removed from View class.
- VertexLightTextureMaterial now can be used with skin with the maximum number of bones in surface no more than 33.
8.8.0
----
- TextureMaterial, VertexLightMaterial, LightmapMaterial now supports the map-transparency and alpha property.
- Added EllipsoidCollider class for continuous collision detection.
- Added Decal class for detalization of texture on models.
- WireFrame class was added.
- New class SkyBox was added.
- StandardMaterial supports Object-space normal maps now.
- StandardMaterial supports glossiness maps now
- Property alwaysOnTop was added in the Sprite.
- clone() method was added to Skin.
- concatenatedMatrix property was added in Object3D.
- Primitive Box contains vertex tangents now.
- ParserA3D: glossiness and opacity maps are supported now.
- Parsing of Skin with animation from collada was fixed.
- ParserCollada: a bug, when model without vertex normals parsed, was fixed.
- Lighting in StandartMaterial, VertexLightMaterial, when models have non-identity scale, was fixed.
- View can be any size now without throwing exceptions.
- Mouse events work properly now after creating the View with zero width or height.
- Bug with culling of scaled objects in camera frustum was fixed.
- A bug in dispose() method of Geometry class was fixed.
- DirectionalLight: bug with wrong light direction after parsing from Collada was fixed.
- ParserA3D: bug with wrong textures assignment was fixed.
- ParserA3D: vertex tangents are supported now.
- ParserA3D: bug, when Geometry methods worked incorrectly on a parsed model, was fixed.
- FileTextureResource: after a repeated call to upload() the resource is not destroyed now.
- FileTextureResource: you can get and set the texture data now.
- FileTextureResource renamed to ExternalTextureResource.
- ColladaMaterial renamed to ParserMaterial.
- Surface: owner property renamed to object.
- Geometry: findVertexBufferByAttribute renamed to findVertexStreamByAttribute.
- Sprite3D: StandartMaterial and VertexLightMaterial are not supported with it now.
- Fillmaterial: the color property has uint type now.
8.5.0
-----
- GPU support
- Directional, omni, spot lights
- Hierarchical exclusion of light sources
- Material with normal, specular, opacity mapping
- Lightmap Material
- Vertex light Material
- Fill Material
- Skin
- Skin subdividing
- Semi-transparent Material
- Mesh with several materials
- Sprite
- Animated Sprite
- GPU-based MouseEvents
- ATF textures loading
- Collada loading
- Binary A3D loading
- Drawing to DisplayObject mode
- Animation engine
- Hierarchical Animated blending tree

View File

@@ -465,6 +465,8 @@ package alternativa.engine3d.animation {
*/ */
public function slice(start:Number, end:Number = Number.MAX_VALUE):AnimationClip { public function slice(start:Number, end:Number = Number.MAX_VALUE):AnimationClip {
var sliced:AnimationClip = new AnimationClip(name); var sliced:AnimationClip = new AnimationClip(name);
sliced.animated = animated;
sliced.loop = loop;
sliced._objects = (_objects == null) ? null : [].concat(_objects); sliced._objects = (_objects == null) ? null : [].concat(_objects);
for (var i:int = 0; i < _numTracks; i++) { for (var i:int = 0; i < _numTracks; i++) {
sliced.addTrack(_tracks[i].slice(start, end)); sliced.addTrack(_tracks[i].slice(start, end));
@@ -477,6 +479,8 @@ package alternativa.engine3d.animation {
*/ */
public function clone():AnimationClip { public function clone():AnimationClip {
var cloned:AnimationClip = new AnimationClip(name); var cloned:AnimationClip = new AnimationClip(name);
cloned.animated = animated;
cloned.loop = loop;
cloned._objects = (_objects == null) ? null : [].concat(_objects); cloned._objects = (_objects == null) ? null : [].concat(_objects);
for (var i:int = 0; i < _numTracks; i++) { for (var i:int = 0; i < _numTracks; i++) {
cloned.addTrack(_tracks[i]); cloned.addTrack(_tracks[i]);

View File

@@ -46,6 +46,12 @@ package alternativa.engine3d.core {
*/ */
public class Camera3D extends Object3D { public class Camera3D extends Object3D {
/**
* @private
* Key - context, value - properties.
*/
alternativa3d static var context3DPropertiesPool:Dictionary = new Dictionary(true);
/** /**
* The viewport defines part of screen to which renders image seen by the camera. * The viewport defines part of screen to which renders image seen by the camera.
* If viewport is not defined, the camera would not draws anything. * If viewport is not defined, the camera would not draws anything.
@@ -156,6 +162,11 @@ public class Camera3D extends Object3D {
*/ */
alternativa3d var context3D:Context3D; alternativa3d var context3D:Context3D;
/**
* @private
*/
alternativa3d var context3DProperties:RendererContext3DProperties;
/** /**
* @private * @private
* Camera's renderer. If is not defined, the camera will no draw anything. * Camera's renderer. If is not defined, the camera will no draw anything.
@@ -195,7 +206,6 @@ public class Camera3D extends Object3D {
* @param stage3D <code>Stage3D</code> to which image will be rendered. * @param stage3D <code>Stage3D</code> to which image will be rendered.
*/ */
public function render(stage3D:Stage3D):void { public function render(stage3D:Stage3D):void {
// TODO: don't check mouse events if no listeners
var i:int; var i:int;
var j:int; var j:int;
var light:Light3D; var light:Light3D;
@@ -214,13 +224,27 @@ public class Camera3D extends Object3D {
ambient[2] = 0; ambient[2] = 0;
ambient[3] = 1; ambient[3] = 1;
// Receiving the context // Receiving the context
context3D = stage3D.context3D; var currentContext3D:Context3D = stage3D.context3D;
if (currentContext3D != context3D) {
if (currentContext3D != null) {
context3DProperties = context3DPropertiesPool[currentContext3D];
if (context3DProperties == null) {
context3DProperties = new RendererContext3DProperties();
context3DProperties.isConstrained = currentContext3D.driverInfo.lastIndexOf("(Baseline Constrained)") >= 0;
context3DPropertiesPool[currentContext3D] = context3DProperties;
}
context3D = currentContext3D;
} else {
context3D = null;
context3DProperties = null;
}
}
if (context3D != null && view != null && renderer != null && (view.stage != null || view._canvas != null)) { if (context3D != null && view != null && renderer != null && (view.stage != null || view._canvas != null)) {
renderer.camera = this; renderer.camera = this;
// Projection argument calculating // Projection argument calculating
calculateProjection(view._width, view._height); calculateProjection(view._width, view._height);
// Preparing to rendering // Preparing to rendering
view.prepareToRender(stage3D, context3D); view.configureContext3D(stage3D, context3D, this);
// Transformations calculating // Transformations calculating
if (transformChanged) composeTransforms(); if (transformChanged) composeTransforms();
localToGlobalTransform.copy(transform); localToGlobalTransform.copy(transform);
@@ -236,14 +260,12 @@ public class Camera3D extends Object3D {
// Check if object of hierarchy is visible // Check if object of hierarchy is visible
if (root.visible) { if (root.visible) {
globalMouseHandlingType = 0;
// Calculating the matrix to transform from the camera space to local space // Calculating the matrix to transform from the camera space to local space
root.cameraToLocalTransform.combine(root.inverseTransform, localToGlobalTransform); root.cameraToLocalTransform.combine(root.inverseTransform, localToGlobalTransform);
// Calculating the matrix to transform from local space to the camera space // Calculating the matrix to transform from local space to the camera space
root.localToCameraTransform.combine(globalToLocalTransform, root.transform); root.localToCameraTransform.combine(globalToLocalTransform, root.transform);
if (root.mouseEnabled) globalMouseHandlingType |= root.mouseHandlingType; globalMouseHandlingType = root.mouseHandlingType;
// Checking the culling // Checking the culling
if (root.boundBox != null) { if (root.boundBox != null) {
calculateFrustum(root.cameraToLocalTransform); calculateFrustum(root.cameraToLocalTransform);
@@ -251,7 +273,7 @@ public class Camera3D extends Object3D {
} else { } else {
root.culling = 63; root.culling = 63;
} }
// Calculations of conent visibility // Calculations of content visibility
if (root.culling >= 0) root.calculateVisibility(this); if (root.culling >= 0) root.calculateVisibility(this);
// Calculations visibility of children // Calculations visibility of children
root.calculateChildrenVisibility(this); root.calculateChildrenVisibility(this);
@@ -334,6 +356,16 @@ public class Camera3D extends Object3D {
} }
raysLength = view.raysLength; raysLength = view.raysLength;
var r:Number = ((view.backgroundColor >> 16) & 0xff)/0xff;
var g:Number = ((view.backgroundColor >> 8) & 0xff)/0xff;
var b:Number = (view.backgroundColor & 0xff)/0xff;
if (view._canvas != null) {
r *= view.backgroundAlpha;
g *= view.backgroundAlpha;
b *= view.backgroundAlpha;
}
context3D.clear(r, g, b, view.backgroundAlpha);
// Check getting in frustum and occluding // Check getting in frustum and occluding
if (root.culling >= 0 && (root.boundBox == null || occludersLength == 0 || !root.boundBox.checkOcclusion(occluders, occludersLength, root.localToCameraTransform))) { if (root.culling >= 0 && (root.boundBox == null || occludersLength == 0 || !root.boundBox.checkOcclusion(occluders, occludersLength, root.localToCameraTransform))) {
// Check if the ray crossing the bounding box // Check if the ray crossing the bounding box
@@ -387,7 +419,6 @@ public class Camera3D extends Object3D {
} }
// Gather the draws for children // Gather the draws for children
root.collectChildrenDraws(this, lights, lightsLength, root.useShadow); root.collectChildrenDraws(this, lights, lightsLength, root.useShadow);
// Mouse events prosessing // Mouse events prosessing
view.processMouseEvents(context3D, this); view.processMouseEvents(context3D, this);
// Render // Render
@@ -405,7 +436,6 @@ public class Camera3D extends Object3D {
lights.length = 0; lights.length = 0;
childLights.length = 0; childLights.length = 0;
occluders.length = 0; occluders.length = 0;
context3D = null;
} }
/** /**
@@ -424,7 +454,7 @@ public class Camera3D extends Object3D {
var deltaX:Number = x - this.x; var deltaX:Number = x - this.x;
var deltaY:Number = y - this.y; var deltaY:Number = y - this.y;
var deltaZ:Number = z - this.z; var deltaZ:Number = z - this.z;
var rotX = Math.atan2(deltaZ, Math.sqrt(deltaX * deltaX + deltaY * deltaY)); var rotX:Number = Math.atan2(deltaZ, Math.sqrt(deltaX * deltaX + deltaY * deltaY));
rotationX = rotX - 0.5 * Math.PI; rotationX = rotX - 0.5 * Math.PI;
rotationY = 0; rotationY = 0;
rotationZ = - Math.atan2(deltaX,deltaY); rotationZ = - Math.atan2(deltaX,deltaY);

View File

@@ -172,26 +172,53 @@ package alternativa.engine3d.core {
*/ */
public class Object3D implements IEventDispatcher { public class Object3D implements IEventDispatcher {
// Mouse moving
private static const MOUSE_MOVE_BIT:uint = 1;
private static const MOUSE_OVER_BIT:uint = 2;
private static const MOUSE_OUT_BIT:uint = 4;
private static const ROLL_OVER_BIT:uint = 0x8;
private static const ROLL_OUT_BIT:uint = 0x10;
private static const USE_HAND_CURSOR_BIT:uint = 0x20;
// Mouse pressing
private static const MOUSE_DOWN_BIT:uint = 0x40;
private static const MOUSE_UP_BIT:uint = 0x80;
private static const CLICK_BIT:uint = 0x100;
private static const DOUBLE_CLICK_BIT:uint = 0x200;
// Mouse wheel
private static const MOUSE_WHEEL_BIT:uint = 0x400;
// Mouse middle button
private static const MIDDLE_CLICK_BIT:uint = 0x800;
private static const MIDDLE_MOUSE_DOWN_BIT:uint = 0x1000;
private static const MIDDLE_MOUSE_UP_BIT:uint = 0x2000;
// Mouse right button
private static const RIGHT_CLICK_BIT:uint = 0x4000;
private static const RIGHT_MOUSE_DOWN_BIT:uint = 0x8000;
private static const RIGHT_MOUSE_UP_BIT:uint = 0x10000;
/** /**
* @private * @private
*/ */
alternativa3d static const MOUSE_HANDLING_MOVING:uint = 1; alternativa3d static const MOUSE_HANDLING_MOVING:uint = MOUSE_MOVE_BIT | MOUSE_OVER_BIT | MOUSE_OUT_BIT | ROLL_OVER_BIT | ROLL_OUT_BIT | USE_HAND_CURSOR_BIT;
/** /**
* @private * @private
*/ */
alternativa3d static const MOUSE_HANDLING_PRESSING:uint = 2; alternativa3d static const MOUSE_HANDLING_PRESSING:uint = MOUSE_DOWN_BIT | MOUSE_UP_BIT | CLICK_BIT | DOUBLE_CLICK_BIT;
/** /**
* @private * @private
*/ */
alternativa3d static const MOUSE_HANDLING_WHEEL:uint = 4; alternativa3d static const MOUSE_HANDLING_WHEEL:uint = MOUSE_WHEEL_BIT;
/** /**
* @private * @private
*/ */
alternativa3d static const MOUSE_HANDLING_MIDDLE_BUTTON:uint = 8; alternativa3d static const MOUSE_HANDLING_MIDDLE_BUTTON:uint = MIDDLE_CLICK_BIT | MIDDLE_MOUSE_DOWN_BIT | MIDDLE_MOUSE_UP_BIT;
/** /**
* @private * @private
*/ */
alternativa3d static const MOUSE_HANDLING_RIGHT_BUTTON:uint = 16; alternativa3d static const MOUSE_HANDLING_RIGHT_BUTTON:uint = RIGHT_CLICK_BIT | RIGHT_MOUSE_DOWN_BIT | RIGHT_MOUSE_UP_BIT;
/** /**
* Custom data available to store within <code>Object3D</code> by user. * Custom data available to store within <code>Object3D</code> by user.
@@ -249,12 +276,6 @@ package alternativa.engine3d.core {
*/ */
public var doubleClickEnabled:Boolean = false; public var doubleClickEnabled:Boolean = false;
/**
* A Boolean value that indicates whether the pointing hand (hand cursor)
* appears when the pointer rolls over a <code>Object3D</code>.
*/
public var useHandCursor:Boolean = false;
/** /**
* Bounds of the object described as rectangular parallelepiped. * Bounds of the object described as rectangular parallelepiped.
*/ */
@@ -587,6 +608,25 @@ package alternativa.engine3d.core {
transformChanged = true; transformChanged = true;
} }
/**
* A Boolean value that indicates whether the pointing hand (hand cursor)
* appears when the pointer rolls over a <code>Object3D</code>.
*/
public function get useHandCursor():Boolean {
return (mouseHandlingType & USE_HAND_CURSOR_BIT) != 0;
}
/**
* @private
*/
public function set useHandCursor(value:Boolean):void {
if (value) {
mouseHandlingType |= USE_HAND_CURSOR_BIT;
} else {
mouseHandlingType &= ~USE_HAND_CURSOR_BIT;
}
}
/** /**
* Searches for the intersection of an <code>Object3D</code> and given ray, defined by <code>origin</code> and <code>direction</code>. * Searches for the intersection of an <code>Object3D</code> and given ray, defined by <code>origin</code> and <code>direction</code>.
* *
@@ -739,20 +779,56 @@ package alternativa.engine3d.core {
vector = new Vector.<Function>(); vector = new Vector.<Function>();
listeners[type] = vector; listeners[type] = vector;
if (type == MouseEvent3D.MOUSE_MOVE || type == MouseEvent3D.MOUSE_OVER || type == MouseEvent3D.MOUSE_OUT || type == MouseEvent3D.ROLL_OVER || type == MouseEvent3D.ROLL_OUT) { // update mouseHandlingType bits
mouseHandlingType |= MOUSE_HANDLING_MOVING; switch (type) {
} case MouseEvent3D.MOUSE_MOVE:
if (type == MouseEvent3D.MOUSE_DOWN || type == MouseEvent3D.MOUSE_UP || type == MouseEvent3D.CLICK || type == MouseEvent3D.DOUBLE_CLICK) { mouseHandlingType |= MOUSE_MOVE_BIT;
mouseHandlingType |= MOUSE_HANDLING_PRESSING; break;
} case MouseEvent3D.MOUSE_OVER:
if (type == MouseEvent3D.MOUSE_WHEEL) { mouseHandlingType |= MOUSE_OVER_BIT;
mouseHandlingType |= MOUSE_HANDLING_WHEEL; break;
} case MouseEvent3D.MOUSE_OUT:
if (type == MouseEvent3D.MIDDLE_CLICK || type == MouseEvent3D.MIDDLE_MOUSE_DOWN || type == MouseEvent3D.MIDDLE_MOUSE_UP) { mouseHandlingType |= MOUSE_OUT_BIT;
mouseHandlingType |= MOUSE_HANDLING_MIDDLE_BUTTON; break;
} case MouseEvent3D.ROLL_OVER:
if (type == MouseEvent3D.RIGHT_CLICK || type == MouseEvent3D.RIGHT_MOUSE_DOWN || type == MouseEvent3D.RIGHT_MOUSE_UP) { mouseHandlingType |= ROLL_OVER_BIT;
mouseHandlingType |= MOUSE_HANDLING_RIGHT_BUTTON; break;
case MouseEvent3D.ROLL_OUT:
mouseHandlingType |= ROLL_OUT_BIT;
break;
case MouseEvent3D.MOUSE_DOWN:
mouseHandlingType |= MOUSE_DOWN_BIT;
break;
case MouseEvent3D.MOUSE_UP:
mouseHandlingType |= MOUSE_UP_BIT;
break;
case MouseEvent3D.CLICK:
mouseHandlingType |= CLICK_BIT;
break;
case MouseEvent3D.DOUBLE_CLICK:
mouseHandlingType |= DOUBLE_CLICK_BIT;
break;
case MouseEvent3D.MOUSE_WHEEL:
mouseHandlingType |= MOUSE_WHEEL_BIT;
break;
case MouseEvent3D.MIDDLE_CLICK:
mouseHandlingType |= MIDDLE_CLICK_BIT;
break;
case MouseEvent3D.MIDDLE_MOUSE_DOWN:
mouseHandlingType |= MIDDLE_MOUSE_DOWN_BIT;
break;
case MouseEvent3D.MIDDLE_MOUSE_UP:
mouseHandlingType |= MIDDLE_MOUSE_UP_BIT;
break;
case MouseEvent3D.RIGHT_CLICK:
mouseHandlingType |= RIGHT_CLICK_BIT;
break;
case MouseEvent3D.RIGHT_MOUSE_DOWN:
mouseHandlingType |= RIGHT_MOUSE_DOWN_BIT;
break;
case MouseEvent3D.RIGHT_MOUSE_UP:
mouseHandlingType |= RIGHT_MOUSE_UP_BIT;
break;
} }
} }
if (vector.indexOf(listener) < 0) { if (vector.indexOf(listener) < 0) {
@@ -781,7 +857,68 @@ package alternativa.engine3d.core {
if (length > 1) { if (length > 1) {
vector.length = length - 1; vector.length = length - 1;
} else { } else {
// update mouseHandlingType bits
var noListeners:Boolean;
if (listeners == captureListeners) {
noListeners = (bubbleListeners == null || bubbleListeners[type] == null);
} else {
noListeners = (captureListeners == null || captureListeners[type] == null);
}
if (noListeners) {
switch (type) {
case MouseEvent3D.MOUSE_MOVE:
mouseHandlingType &= ~MOUSE_MOVE_BIT;
break;
case MouseEvent3D.MOUSE_OVER:
mouseHandlingType &= ~MOUSE_OVER_BIT;
break;
case MouseEvent3D.MOUSE_OUT:
mouseHandlingType &= ~MOUSE_OUT_BIT;
break;
case MouseEvent3D.ROLL_OVER:
mouseHandlingType &= ~ROLL_OVER_BIT;
break;
case MouseEvent3D.ROLL_OUT:
mouseHandlingType &= ~ROLL_OUT_BIT;
break;
case MouseEvent3D.MOUSE_DOWN:
mouseHandlingType &= ~MOUSE_DOWN_BIT;
break;
case MouseEvent3D.MOUSE_UP:
mouseHandlingType &= ~MOUSE_UP_BIT;
break;
case MouseEvent3D.CLICK:
mouseHandlingType &= ~CLICK_BIT;
break;
case MouseEvent3D.DOUBLE_CLICK:
mouseHandlingType &= ~DOUBLE_CLICK_BIT;
break;
case MouseEvent3D.MOUSE_WHEEL:
mouseHandlingType &= ~MOUSE_WHEEL_BIT;
break;
case MouseEvent3D.MIDDLE_CLICK:
mouseHandlingType &= ~MIDDLE_CLICK_BIT;
break;
case MouseEvent3D.MIDDLE_MOUSE_DOWN:
mouseHandlingType &= ~MIDDLE_MOUSE_DOWN_BIT;
break;
case MouseEvent3D.MIDDLE_MOUSE_UP:
mouseHandlingType &= ~MIDDLE_MOUSE_UP_BIT;
break;
case MouseEvent3D.RIGHT_CLICK:
mouseHandlingType &= ~RIGHT_CLICK_BIT;
break;
case MouseEvent3D.RIGHT_MOUSE_DOWN:
mouseHandlingType &= ~RIGHT_MOUSE_DOWN_BIT;
break;
case MouseEvent3D.RIGHT_MOUSE_UP:
mouseHandlingType &= ~RIGHT_MOUSE_UP_BIT;
break;
}
}
delete listeners[type]; delete listeners[type];
var key:*; var key:*;
for (key in listeners) break; for (key in listeners) break;
if (!key) { if (!key) {
@@ -791,21 +928,6 @@ package alternativa.engine3d.core {
bubbleListeners = null; bubbleListeners = null;
} }
} }
if (type == MouseEvent3D.MOUSE_MOVE || type == MouseEvent3D.MOUSE_OVER || type == MouseEvent3D.MOUSE_OUT || type == MouseEvent3D.ROLL_OVER || type == MouseEvent3D.ROLL_OUT) {
mouseHandlingType &= ~MOUSE_HANDLING_MOVING;
}
if (type == MouseEvent3D.MOUSE_DOWN || type == MouseEvent3D.MOUSE_UP || type == MouseEvent3D.CLICK || type == MouseEvent3D.DOUBLE_CLICK) {
mouseHandlingType &= ~MOUSE_HANDLING_PRESSING;
}
if (type == MouseEvent3D.MOUSE_WHEEL) {
mouseHandlingType &= ~MOUSE_HANDLING_WHEEL;
}
if (type == MouseEvent3D.MIDDLE_CLICK || type == MouseEvent3D.MIDDLE_MOUSE_DOWN || type == MouseEvent3D.MIDDLE_MOUSE_UP) {
mouseHandlingType &= ~MOUSE_HANDLING_MIDDLE_BUTTON;
}
if (type == MouseEvent3D.RIGHT_CLICK || type == MouseEvent3D.RIGHT_MOUSE_DOWN || type == MouseEvent3D.RIGHT_MOUSE_UP) {
mouseHandlingType &= ~MOUSE_HANDLING_RIGHT_BUTTON;
}
} }
} }
} }
@@ -1401,7 +1523,7 @@ package alternativa.engine3d.core {
// Calculating matrix for converting from local coordinates to camera coordinates // Calculating matrix for converting from local coordinates to camera coordinates
child.localToCameraTransform.combine(localToCameraTransform, child.transform); child.localToCameraTransform.combine(localToCameraTransform, child.transform);
if (child.mouseEnabled) camera.globalMouseHandlingType |= child.mouseHandlingType; camera.globalMouseHandlingType |= child.mouseHandlingType;
// Culling checking // Culling checking
if (child.boundBox != null) { if (child.boundBox != null) {
camera.calculateFrustum(child.cameraToLocalTransform); camera.calculateFrustum(child.cameraToLocalTransform);
@@ -1531,7 +1653,12 @@ package alternativa.engine3d.core {
/** /**
* Toggle off light source from litting this object * Disables lighting of the object by given <code>light</code>.
*
* @param light Light which should not affect to the object
* @param updateChildren If <code>true</code> all children of this object will be also shielded from the given light.
* @see #excludedLights()
* @see #clearExcludedLights()
*/ */
public function excludeLight(light:Light3D, updateChildren:Boolean = false):void{ public function excludeLight(light:Light3D, updateChildren:Boolean = false):void{
if (_excludedLights.indexOf(light) < 0) { if (_excludedLights.indexOf(light) < 0) {
@@ -1552,7 +1679,7 @@ package alternativa.engine3d.core {
} }
/** /**
* Resets list of lights excluded from litting this object * Resets list of lights excluded from lighting this object.
*/ */
public function clearExcludedLights(updateChildren:Boolean = false):void { public function clearExcludedLights(updateChildren:Boolean = false):void {
_excludedLights.length = 0; _excludedLights.length = 0;
@@ -1564,7 +1691,7 @@ package alternativa.engine3d.core {
} }
/** /**
* Returns a copy of object * Returns a copy of object.
* @return A copy of this <code>Object3D</code>. * @return A copy of this <code>Object3D</code>.
*/ */
public function clone():Object3D { public function clone():Object3D {
@@ -1614,7 +1741,8 @@ package alternativa.engine3d.core {
*/ */
public function toString():String { public function toString():String {
var className:String = getQualifiedClassName(this); var className:String = getQualifiedClassName(this);
return "[" + className.substr(className.indexOf("::") + 2) + " " + name + "]"; var start:int = className.indexOf("::");
return "[" + (start < 0 ? className : className.substr(start + 2)) + " " + name + "]";
} }
} }

View File

@@ -4,8 +4,8 @@
* You may add additional accurate notices of copyright ownership. * You may add additional accurate notices of copyright ownership.
* *
* It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/ * It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/
* */ *
*/
package alternativa.engine3d.core { package alternativa.engine3d.core {
import alternativa.engine3d.alternativa3d; import alternativa.engine3d.alternativa3d;
@@ -16,7 +16,6 @@ package alternativa.engine3d.core {
import flash.display3D.Context3DProgramType; import flash.display3D.Context3DProgramType;
import flash.display3D.IndexBuffer3D; import flash.display3D.IndexBuffer3D;
import flash.display3D.Program3D; import flash.display3D.Program3D;
import flash.utils.Dictionary;
use namespace alternativa3d; use namespace alternativa3d;
@@ -37,9 +36,6 @@ package alternativa.engine3d.core {
public static const NEXT_LAYER:int = 50; public static const NEXT_LAYER:int = 50;
// Key - context, value - properties.
protected static var properties:Dictionary = new Dictionary(true);
// Collector // Collector
protected var collector:DrawUnit; protected var collector:DrawUnit;
@@ -47,7 +43,6 @@ package alternativa.engine3d.core {
alternativa3d var drawUnits:Vector.<DrawUnit> = new Vector.<DrawUnit>(); alternativa3d var drawUnits:Vector.<DrawUnit> = new Vector.<DrawUnit>();
protected var _context3D:Context3D;
protected var _contextProperties:RendererContext3DProperties; protected var _contextProperties:RendererContext3DProperties;
alternativa3d function render(context3D:Context3D):void { alternativa3d function render(context3D:Context3D):void {
@@ -59,29 +54,29 @@ package alternativa.engine3d.core {
if (list != null) { if (list != null) {
switch (i) { switch (i) {
case SKY: case SKY:
_context3D.setDepthTest(false, Context3DCompareMode.ALWAYS); context3D.setDepthTest(false, Context3DCompareMode.ALWAYS);
break; break;
case OPAQUE: case OPAQUE:
_context3D.setDepthTest(true, Context3DCompareMode.LESS); context3D.setDepthTest(true, Context3DCompareMode.LESS);
break; break;
case OPAQUE_OVERHEAD: case OPAQUE_OVERHEAD:
_context3D.setDepthTest(false, Context3DCompareMode.EQUAL); context3D.setDepthTest(false, Context3DCompareMode.EQUAL);
break; break;
case DECALS: case DECALS:
_context3D.setDepthTest(false, Context3DCompareMode.LESS_EQUAL); context3D.setDepthTest(false, Context3DCompareMode.LESS_EQUAL);
break; break;
case TRANSPARENT_SORT: case TRANSPARENT_SORT:
if (list.next != null) list = sortByAverageZ(list); if (list.next != null) list = sortByAverageZ(list);
_context3D.setDepthTest(false, Context3DCompareMode.LESS); context3D.setDepthTest(false, Context3DCompareMode.LESS);
break; break;
case NEXT_LAYER: case NEXT_LAYER:
_context3D.setDepthTest(false, Context3DCompareMode.ALWAYS); context3D.setDepthTest(false, Context3DCompareMode.ALWAYS);
break; break;
} }
// Rendering // Rendering
while (list != null) { while (list != null) {
var next:DrawUnit = list.next; var next:DrawUnit = list.next;
renderDrawUnit(list, _context3D, camera); renderDrawUnit(list, context3D, camera);
// Send to collector // Send to collector
list.clear(); list.clear();
list.next = collector; list.next = collector;
@@ -90,6 +85,7 @@ package alternativa.engine3d.core {
} }
} }
} }
// TODO: not free buffers and textures in each renderer, only when full camera cycle finishes.
freeContext3DProperties(context3D); freeContext3DProperties(context3D);
// Clear // Clear
drawUnits.length = 0; drawUnits.length = 0;
@@ -180,14 +176,7 @@ package alternativa.engine3d.core {
} }
protected function updateContext3D(value:Context3D):void { protected function updateContext3D(value:Context3D):void {
if (_context3D != value) { _contextProperties = camera.context3DProperties;
_contextProperties = properties[value];
if (_contextProperties == null) {
_contextProperties = new RendererContext3DProperties();
properties[value] = _contextProperties;
}
_context3D = value;
}
} }
/** /**

View File

@@ -8,7 +8,11 @@
package alternativa.engine3d.core { package alternativa.engine3d.core {
import alternativa.engine3d.materials.ShaderProgram;
import alternativa.engine3d.resources.Geometry;
import flash.display3D.Program3D; import flash.display3D.Program3D;
import flash.utils.Dictionary;
/** /**
* @private * @private
@@ -16,6 +20,12 @@ package alternativa.engine3d.core {
*/ */
public class RendererContext3DProperties { public class RendererContext3DProperties {
public var isConstrained:Boolean = false;
public var backBufferWidth:int = -1;
public var backBufferHeight:int = -1;
public var backBufferAntiAlias:int = -1;
public var usedBuffers:uint = 0; public var usedBuffers:uint = 0;
public var usedTextures:uint = 0; public var usedTextures:uint = 0;
@@ -24,5 +34,11 @@ package alternativa.engine3d.core {
public var blendSource:String; public var blendSource:String;
public var blendDestination:String; public var blendDestination:String;
// View: mouse events
// Key - vertex program of object, value - program.
public var drawDistancePrograms:Dictionary = new Dictionary();
public var drawColoredRectProgram:ShaderProgram;
public var drawRectGeometry:Geometry;
} }
} }

View File

@@ -61,10 +61,6 @@ package alternativa.engine3d.core {
private static const renderEvent:MouseEvent = new MouseEvent("render"); private static const renderEvent:MouseEvent = new MouseEvent("render");
private static var properties:Dictionary = new Dictionary(true);
private var cachedContext3D:Context3D;
private var context3DProperties:Context3DViewProperties;
static private var drawDistanceFragment:Linker; static private var drawDistanceFragment:Linker;
static private var drawDistanceVertexProcedure:Procedure; static private var drawDistanceVertexProcedure:Procedure;
@@ -309,6 +305,11 @@ package alternativa.engine3d.core {
addEventListener(Event.REMOVED_FROM_STAGE, onRemoveFromStage); addEventListener(Event.REMOVED_FROM_STAGE, onRemoveFromStage);
} }
/**
* If <code>true</code>, you will able to handle following events <code>MouseEvent3D.RIGHT_CLICK</code>,
* <code>MouseEvent3D.RIGHT_MOUSE_DOWN</code>, <code>MouseEvent3D.RIGHT_MOUSE_UP</code>.
* The context menu will no longer open on clicking right mouse button.
*/
public function get rightClick3DEnabled():Boolean { public function get rightClick3DEnabled():Boolean {
return _rightClick3DEnabled; return _rightClick3DEnabled;
} }
@@ -533,7 +534,7 @@ package alternativa.engine3d.core {
/** /**
* @private * @private
*/ */
alternativa3d function prepareToRender(stage3D:Stage3D, context:Context3D):void { alternativa3d function configureContext3D(stage3D:Stage3D, context3D:Context3D, camera:Camera3D):void {
if (_canvas == null) { if (_canvas == null) {
var vis:Boolean = this.visible; var vis:Boolean = this.visible;
for (var parent:DisplayObject = this.parent; parent != null; parent = parent.parent) { for (var parent:DisplayObject = this.parent; parent != null; parent = parent.parent) {
@@ -553,70 +554,55 @@ package alternativa.engine3d.core {
createRenderBitmap(); createRenderBitmap();
} }
} }
if (context != cachedContext3D) { var context3DProperties:RendererContext3DProperties = camera.context3DProperties;
// Get properties. if (context3DProperties.drawRectGeometry == null) {
cachedContext3D = context; // Inititalize data for mouse events
context3DProperties = properties[cachedContext3D]; var rectGeometry:Geometry = new Geometry(4);
if (context3DProperties == null) { rectGeometry.addVertexStream([VertexAttributes.POSITION, VertexAttributes.POSITION, VertexAttributes.POSITION, VertexAttributes.TEXCOORDS[0], VertexAttributes.TEXCOORDS[0]]);
context3DProperties = new Context3DViewProperties(); rectGeometry.setAttributeValues(VertexAttributes.POSITION, Vector.<Number>([0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1]));
// Inititalize data for mouse events rectGeometry.setAttributeValues(VertexAttributes.TEXCOORDS[0], Vector.<Number>([0, 0, 0, 1, 1, 1, 1, 0]));
var rectGeometry:Geometry = new Geometry(4); rectGeometry.indices = Vector.<uint>([0, 1, 3, 2, 3, 1]);
rectGeometry.addVertexStream([VertexAttributes.POSITION, VertexAttributes.POSITION, VertexAttributes.POSITION, VertexAttributes.TEXCOORDS[0], VertexAttributes.TEXCOORDS[0]]); rectGeometry.upload(context3D);
rectGeometry.setAttributeValues(VertexAttributes.POSITION, Vector.<Number>([0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1])); var vLinker:Linker = new Linker(Context3DProgramType.VERTEX);
rectGeometry.setAttributeValues(VertexAttributes.TEXCOORDS[0], Vector.<Number>([0, 0, 0, 1, 1, 1, 1, 0])); vLinker.addProcedure(Procedure.compileFromArray([
rectGeometry.indices = Vector.<uint>([0, 1, 3, 2, 3, 1]); "#a0=a0",
rectGeometry.upload(context); "#c0=c0",
var vLinker:Linker = new Linker(Context3DProgramType.VERTEX); "mul t0.x, a0.x, c0.x",
vLinker.addProcedure(Procedure.compileFromArray([ "mul t0.y, a0.y, c0.y",
"#a0=a0", "add o0.x, t0.x, c0.z",
"#c0=c0", "add o0.y, t0.y, c0.w",
"mul t0.x, a0.x, c0.x", "mov o0.z, a0.z",
"mul t0.y, a0.y, c0.y", "mov o0.w, a0.z",
"add o0.x, t0.x, c0.z", ]));
"add o0.y, t0.y, c0.w", var fLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
"mov o0.z, a0.z", fLinker.addProcedure(Procedure.compileFromArray([
"mov o0.w, a0.z", "#c0=c0",
])); "mov o0, c0",
var fLinker:Linker = new Linker(Context3DProgramType.FRAGMENT); ]));
fLinker.addProcedure(Procedure.compileFromArray([ var coloredRectProgram:ShaderProgram = new ShaderProgram(vLinker, fLinker);
"#c0=c0", coloredRectProgram.upload(context3D);
"mov o0, c0",
]));
var coloredRectProgram:ShaderProgram = new ShaderProgram(vLinker, fLinker);
coloredRectProgram.upload(context);
context3DProperties.drawRectGeometry = rectGeometry; context3DProperties.drawRectGeometry = rectGeometry;
context3DProperties.drawColoredRectProgram = coloredRectProgram; context3DProperties.drawColoredRectProgram = coloredRectProgram;
properties[cachedContext3D] = context3DProperties;
}
} }
if (_width != context3DProperties.backBufferWidth || _height != context3DProperties.backBufferHeight || antiAlias != context3DProperties.backBufferAntiAlias) { if (_width != context3DProperties.backBufferWidth || _height != context3DProperties.backBufferHeight || antiAlias != context3DProperties.backBufferAntiAlias) {
context3DProperties.backBufferWidth = _width; context3DProperties.backBufferWidth = _width;
context3DProperties.backBufferHeight = _height; context3DProperties.backBufferHeight = _height;
context3DProperties.backBufferAntiAlias = antiAlias; context3DProperties.backBufferAntiAlias = antiAlias;
context.configureBackBuffer(_width, _height, antiAlias); context3D.configureBackBuffer(_width, _height, antiAlias);
} }
var r:Number = ((backgroundColor >> 16) & 0xff)/0xff;
var g:Number = ((backgroundColor >> 8) & 0xff)/0xff;
var b:Number = (backgroundColor & 0xff)/0xff;
if (canvas != null) {
r *= backgroundAlpha;
g *= backgroundAlpha;
b *= backgroundAlpha;
}
context.clear(r, g, b, backgroundAlpha);
} }
/** /**
* @private * @private
*/ */
alternativa3d function processMouseEvents(context:Context3D, camera:Camera3D):void { alternativa3d function processMouseEvents(context3D:Context3D, camera:Camera3D):void {
var i:int; var i:int;
// Mouse events // Mouse events
if (eventsLength > 0) { if (eventsLength > 0) {
if (surfacesLength > 0) { if (surfacesLength > 0) {
// Calculating the depth // Calculating the depth
calculateSurfacesDepths(context, camera, _width, _height); calculateSurfacesDepths(context3D, camera, _width, _height);
// Sorting by decreasing the depth // Sorting by decreasing the depth
for (i = 0; i < raysLength; i++) { for (i = 0; i < raysLength; i++) {
var raySurfaces:Vector.<Surface> = raysSurfaces[i]; var raySurfaces:Vector.<Surface> = raysSurfaces[i];
@@ -776,8 +762,8 @@ package alternativa.engine3d.core {
context.setVertexBufferAt(6, null); context.setVertexBufferAt(6, null);
context.setVertexBufferAt(7, null); context.setVertexBufferAt(7, null);
var drawRectGeometry:Geometry = context3DProperties.drawRectGeometry; var drawRectGeometry:Geometry = camera.context3DProperties.drawRectGeometry;
var drawColoredRectProgram:ShaderProgram = context3DProperties.drawColoredRectProgram; var drawColoredRectProgram:ShaderProgram = camera.context3DProperties.drawColoredRectProgram;
// Rectangle // Rectangle
var vLinker:Linker, fLinker:Linker; var vLinker:Linker, fLinker:Linker;
@@ -883,7 +869,7 @@ package alternativa.engine3d.core {
var procedure:Procedure = procedures[index]; var procedure:Procedure = procedures[index];
var object:Object3D = surface.object; var object:Object3D = surface.object;
// Program // Program
var drawDistanceProgram:ShaderProgram = context3DProperties.drawDistancePrograms[procedure]; var drawDistanceProgram:ShaderProgram = camera.context3DProperties.drawDistancePrograms[procedure];
if (drawDistanceProgram == null) { if (drawDistanceProgram == null) {
// Assembling the vertex shader // Assembling the vertex shader
var vertex:Linker = new Linker(Context3DProgramType.VERTEX); var vertex:Linker = new Linker(Context3DProgramType.VERTEX);
@@ -902,7 +888,7 @@ package alternativa.engine3d.core {
drawDistanceProgram = new ShaderProgram(vertex, drawDistanceFragment); drawDistanceProgram = new ShaderProgram(vertex, drawDistanceFragment);
drawDistanceProgram.fragmentShader.varyings = drawDistanceProgram.vertexShader.varyings; drawDistanceProgram.fragmentShader.varyings = drawDistanceProgram.vertexShader.varyings;
drawDistanceProgram.upload(context); drawDistanceProgram.upload(context);
context3DProperties.drawDistancePrograms[procedure] = drawDistanceProgram; camera.context3DProperties.drawDistancePrograms[procedure] = drawDistanceProgram;
} }
var buffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.POSITION); var buffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.POSITION);
if (buffer == null) return; if (buffer == null) return;
@@ -1405,9 +1391,6 @@ package alternativa.engine3d.core {
} }
} }
import alternativa.engine3d.materials.ShaderProgram;
import alternativa.engine3d.resources.Geometry;
import flash.display.BitmapData; import flash.display.BitmapData;
import flash.display.Sprite; import flash.display.Sprite;
import flash.events.MouseEvent; import flash.events.MouseEvent;
@@ -1415,7 +1398,6 @@ import flash.geom.ColorTransform;
import flash.geom.Matrix; import flash.geom.Matrix;
import flash.net.URLRequest; import flash.net.URLRequest;
import flash.net.navigateToURL; import flash.net.navigateToURL;
import flash.utils.Dictionary;
class Logo extends Sprite { class Logo extends Sprite {
@@ -1513,17 +1495,3 @@ class Logo extends Sprite {
} }
} }
class Context3DViewProperties {
public var backBufferWidth:int = -1;
public var backBufferHeight:int = -1;
public var backBufferAntiAlias:int = -1;
// Mouse events
// Key - vertex program of object, value - program.
public var drawDistancePrograms:Dictionary = new Dictionary();
public var drawColoredRectProgram:ShaderProgram;
public var drawRectGeometry:Geometry;
}

View File

@@ -310,6 +310,15 @@ package alternativa.engine3d.materials {
"mov v0, a0" "mov v0, a0"
], "passLightMapUVProcedure"); ], "passLightMapUVProcedure");
/**
* @private
*/
alternativa3d static var fallbackTextureMaterial:TextureMaterial = new TextureMaterial();
/**
* @private
*/
alternativa3d static var fallbackLightMapMaterial:LightMapMaterial = new LightMapMaterial();
private var _normalMapSpace:int = NormalMapSpace.TANGENT_RIGHT_HANDED; private var _normalMapSpace:int = NormalMapSpace.TANGENT_RIGHT_HANDED;
/** /**
@@ -815,6 +824,31 @@ package alternativa.engine3d.materials {
if (_normalMap != null && _normalMap._texture == null) return; if (_normalMap != null && _normalMap._texture == null) return;
if (_reflectionMap != null && _reflectionMap._texture == null) return; if (_reflectionMap != null && _reflectionMap._texture == null) return;
if (_lightMap != null && _lightMap._texture == null) return; if (_lightMap != null && _lightMap._texture == null) return;
if (camera.context3DProperties.isConstrained) {
// fallback to simpler material
if (lightMap == null) {
fallbackTextureMaterial.diffuseMap = diffuseMap;
fallbackTextureMaterial.opacityMap = opacityMap;
fallbackTextureMaterial.alphaThreshold = alphaThreshold;
fallbackTextureMaterial.alpha = alpha;
fallbackTextureMaterial.opaquePass = opaquePass;
fallbackTextureMaterial.transparentPass = transparentPass;
fallbackTextureMaterial.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow, objectRenderPriority);
} else {
fallbackLightMapMaterial.diffuseMap = diffuseMap;
fallbackLightMapMaterial.lightMap = lightMap;
fallbackLightMapMaterial.lightMapChannel = lightMapChannel;
fallbackLightMapMaterial.opacityMap = opacityMap;
fallbackLightMapMaterial.alphaThreshold = alphaThreshold;
fallbackLightMapMaterial.alpha = alpha;
fallbackLightMapMaterial.opaquePass = opaquePass;
fallbackLightMapMaterial.transparentPass = transparentPass;
fallbackLightMapMaterial.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow, objectRenderPriority);
}
return;
}
var object:Object3D = surface.object; var object:Object3D = surface.object;
// Program // Program

View File

@@ -307,6 +307,15 @@ package alternativa.engine3d.materials {
"mov v0, a0" "mov v0, a0"
], "passLightMapUVProcedure"); ], "passLightMapUVProcedure");
/**
* @private
*/
alternativa3d static var fallbackTextureMaterial:TextureMaterial = new TextureMaterial();
/**
* @private
*/
alternativa3d static var fallbackLightMapMaterial:LightMapMaterial = new LightMapMaterial();
/** /**
* Normal map. * Normal map.
*/ */
@@ -986,6 +995,30 @@ package alternativa.engine3d.materials {
// Check if textures uploaded in to the context. // Check if textures uploaded in to the context.
if (opacityMap != null && opacityMap._texture == null || glossinessMap != null && glossinessMap._texture == null || specularMap != null && specularMap._texture == null || lightMap != null && lightMap._texture == null) return; if (opacityMap != null && opacityMap._texture == null || glossinessMap != null && glossinessMap._texture == null || specularMap != null && specularMap._texture == null || lightMap != null && lightMap._texture == null) return;
if (camera.context3DProperties.isConstrained) {
// fallback to simpler material
if (lightMap == null) {
fallbackTextureMaterial.diffuseMap = diffuseMap;
fallbackTextureMaterial.opacityMap = opacityMap;
fallbackTextureMaterial.alphaThreshold = alphaThreshold;
fallbackTextureMaterial.alpha = alpha;
fallbackTextureMaterial.opaquePass = opaquePass;
fallbackTextureMaterial.transparentPass = transparentPass;
fallbackTextureMaterial.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow, objectRenderPriority);
} else {
fallbackLightMapMaterial.diffuseMap = diffuseMap;
fallbackLightMapMaterial.lightMap = lightMap;
fallbackLightMapMaterial.lightMapChannel = lightMapChannel;
fallbackLightMapMaterial.opacityMap = opacityMap;
fallbackLightMapMaterial.alphaThreshold = alphaThreshold;
fallbackLightMapMaterial.alpha = alpha;
fallbackLightMapMaterial.opaquePass = opaquePass;
fallbackLightMapMaterial.transparentPass = transparentPass;
fallbackLightMapMaterial.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow, objectRenderPriority);
}
return;
}
var object:Object3D = surface.object; var object:Object3D = surface.object;
// Buffers // Buffers

View File

@@ -34,7 +34,7 @@ package alternativa.engine3d.materials {
use namespace alternativa3d; use namespace alternativa3d;
/** /**
* The materiall fills surface with bitmap image in light-independent manner. Can draw a Skin with no more than 41 Joints per surface. See Skin.divide() for more details. * The material fills surface with bitmap image in light-independent manner. Can draw a Skin with no more than 41 Joints per surface. See Skin.divide() for more details.
* *
* To be drawn with this material, geometry shoud have UV coordinates. * To be drawn with this material, geometry shoud have UV coordinates.
* @see alternativa.engine3d.objects.Skin#divide() * @see alternativa.engine3d.objects.Skin#divide()
@@ -113,19 +113,19 @@ package alternativa.engine3d.materials {
public var opacityMap:TextureResource; public var opacityMap:TextureResource;
/** /**
* If <code>true</code>, perform transparent pass. Parts of surface, cumulative alpha value of which is below than <code>alphaThreshold</code> draw within transparent pass. * If <code>true</code>, perform transparent pass. Parts of surface, cumulative alpha value of which is below than <code>alphaThreshold</code> will be drawn within transparent pass.
* @see #alphaThreshold * @see #alphaThreshold
*/ */
public var transparentPass:Boolean = true; public var transparentPass:Boolean = true;
/** /**
* If <code>true</code>, perform opaque pass. Parts of surface, cumulative alpha value of which is greater or equal than <code>alphaThreshold</code> draw within opaque pass. * If <code>true</code>, perform opaque pass. Parts of surface, cumulative alpha value of which is greater or equal than <code>alphaThreshold</code> will be drawn within opaque pass.
* @see #alphaThreshold * @see #alphaThreshold
*/ */
public var opaquePass:Boolean = true; public var opaquePass:Boolean = true;
/** /**
* alphaThreshold defines starts from which value of alpha a fragment of surface will get into transparent pass. * alphaThreshold defines starts from which value of alpha a fragment of the surface will get into transparent pass.
* @see #transparentPass * @see #transparentPass
* @see #opaquePass * @see #opaquePass
*/ */

View File

@@ -98,6 +98,11 @@ package alternativa.engine3d.materials {
private static const _lightsProcedures:Dictionary = new Dictionary(true); private static const _lightsProcedures:Dictionary = new Dictionary(true);
/**
* @private
*/
alternativa3d static var fallbackMaterial:TextureMaterial = new TextureMaterial();
/** /**
* Creates a new VertexLightTextureMaterial instance. * Creates a new VertexLightTextureMaterial instance.
* *
@@ -282,6 +287,18 @@ package alternativa.engine3d.materials {
override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void { override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void {
if (diffuseMap == null || diffuseMap._texture == null || opacityMap != null && opacityMap._texture == null) return; if (diffuseMap == null || diffuseMap._texture == null || opacityMap != null && opacityMap._texture == null) return;
if (camera.context3DProperties.isConstrained) {
// fallback to texture material
fallbackMaterial.diffuseMap = diffuseMap;
fallbackMaterial.opacityMap = opacityMap;
fallbackMaterial.alphaThreshold = alphaThreshold;
fallbackMaterial.alpha = alpha;
fallbackMaterial.opaquePass = opaquePass;
fallbackMaterial.transparentPass = transparentPass;
fallbackMaterial.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow, objectRenderPriority);
return;
}
var object:Object3D = surface.object; var object:Object3D = surface.object;
// Buffers // Buffers

View File

@@ -176,6 +176,7 @@ package alternativa.engine3d.objects {
* @private * @private
*/ */
override alternativa3d function calculateVisibility(camera:Camera3D):void { override alternativa3d function calculateVisibility(camera:Camera3D):void {
// TODO: optimize - use square of distance
var distance:Number = Math.sqrt(localToCameraTransform.d*localToCameraTransform.d + localToCameraTransform.h*localToCameraTransform.h + localToCameraTransform.l*localToCameraTransform.l); var distance:Number = Math.sqrt(localToCameraTransform.d*localToCameraTransform.d + localToCameraTransform.h*localToCameraTransform.h + localToCameraTransform.l*localToCameraTransform.l);
for (level = levelList; level != null; level = level.next) { for (level = levelList; level != null; level = level.next) {
if (distance <= level.distance) { if (distance <= level.distance) {
@@ -196,7 +197,7 @@ package alternativa.engine3d.objects {
// Calculation of transfer matrix from local space to camera. // Calculation of transfer matrix from local space to camera.
child.localToCameraTransform.combine(parent.localToCameraTransform, child.transform); child.localToCameraTransform.combine(parent.localToCameraTransform, child.transform);
if (child.mouseEnabled) camera.globalMouseHandlingType |= child.mouseHandlingType; camera.globalMouseHandlingType |= child.mouseHandlingType;
// Pass // Pass
child.culling = parent.culling; child.culling = parent.culling;
// Calculating visibility of the self content // Calculating visibility of the self content

View File

@@ -80,7 +80,7 @@ package alternativa.engine3d.objects {
private var bottomSurface:Surface; private var bottomSurface:Surface;
private var topSurface:Surface; private var topSurface:Surface;
private var size:Number; private var halfSize:Number;
/** /**
* Creates a new SkyBox instance. * Creates a new SkyBox instance.
@@ -95,10 +95,7 @@ package alternativa.engine3d.objects {
* @see alternativa.engine3d.materials.Material * @see alternativa.engine3d.materials.Material
*/ */
public function SkyBox(size:Number, left:Material = null, right:Material = null, back:Material = null, front:Material = null, bottom:Material = null, top:Material = null, uvPadding:Number = 0) { public function SkyBox(size:Number, left:Material = null, right:Material = null, back:Material = null, front:Material = null, bottom:Material = null, top:Material = null, uvPadding:Number = 0) {
this.halfSize = size*0.5;
size *= 0.5;
this.size = size;
geometry = new Geometry(24); geometry = new Geometry(24);
@@ -111,35 +108,35 @@ package alternativa.engine3d.objects {
geometry.addVertexStream(attributes); geometry.addVertexStream(attributes);
geometry.setAttributeValues(VertexAttributes.POSITION, Vector.<Number>([ geometry.setAttributeValues(VertexAttributes.POSITION, Vector.<Number>([
-size, -size, size, -halfSize, -halfSize, halfSize,
-size, -size, -size, -halfSize, -halfSize, -halfSize,
-size, size, -size, -halfSize, halfSize, -halfSize,
-size, size, size, -halfSize, halfSize, halfSize,
size, size, size, halfSize, halfSize, halfSize,
size, size, -size, halfSize, halfSize, -halfSize,
size, -size, -size, halfSize, -halfSize, -halfSize,
size, -size, size, halfSize, -halfSize, halfSize,
size, -size, size, halfSize, -halfSize, halfSize,
size, -size, -size, halfSize, -halfSize, -halfSize,
-size, -size, -size, -halfSize, -halfSize, -halfSize,
-size, -size, size, -halfSize, -halfSize, halfSize,
-size, size, size, -halfSize, halfSize, halfSize,
-size, size, -size, -halfSize, halfSize, -halfSize,
size, size, -size, halfSize, halfSize, -halfSize,
size, size, size, halfSize, halfSize, halfSize,
-size, size, -size, -halfSize, halfSize, -halfSize,
-size, -size, -size, -halfSize, -halfSize, -halfSize,
size, -size, -size, halfSize, -halfSize, -halfSize,
size, size, -size, halfSize, halfSize, -halfSize,
-size, -size, size, -halfSize, -halfSize, halfSize,
-size, size, size, -halfSize, halfSize, halfSize,
size, size, size, halfSize, halfSize, halfSize,
size, -size, size halfSize, -halfSize, halfSize
])); ]));
geometry.setAttributeValues(VertexAttributes.TEXCOORDS[0], Vector.<Number>([ geometry.setAttributeValues(VertexAttributes.TEXCOORDS[0], Vector.<Number>([
@@ -214,44 +211,44 @@ package alternativa.engine3d.objects {
var dy:Number; var dy:Number;
var dz:Number; var dz:Number;
var len:Number; var len:Number;
dx = -size - cameraToLocalTransform.d; dx = -halfSize - cameraToLocalTransform.d;
dy = -size - cameraToLocalTransform.h; dy = -halfSize - cameraToLocalTransform.h;
dz = -size - cameraToLocalTransform.l; dz = -halfSize - cameraToLocalTransform.l;
len = dx*dx + dy*dy + dz*dz; len = dx*dx + dy*dy + dz*dz;
if (len > max) max = len; if (len > max) max = len;
dx = size - cameraToLocalTransform.d; dx = halfSize - cameraToLocalTransform.d;
dy = -size - cameraToLocalTransform.h; dy = -halfSize - cameraToLocalTransform.h;
dz = -size - cameraToLocalTransform.l; dz = -halfSize - cameraToLocalTransform.l;
len = dx*dx + dy*dy + dz*dz; len = dx*dx + dy*dy + dz*dz;
if (len > max) max = len; if (len > max) max = len;
dx = size - cameraToLocalTransform.d; dx = halfSize - cameraToLocalTransform.d;
dy = size - cameraToLocalTransform.h; dy = halfSize - cameraToLocalTransform.h;
dz = -size - cameraToLocalTransform.l; dz = -halfSize - cameraToLocalTransform.l;
len = dx*dx + dy*dy + dz*dz; len = dx*dx + dy*dy + dz*dz;
if (len > max) max = len; if (len > max) max = len;
dx = -size - cameraToLocalTransform.d; dx = -halfSize - cameraToLocalTransform.d;
dy = size - cameraToLocalTransform.h; dy = halfSize - cameraToLocalTransform.h;
dz = -size - cameraToLocalTransform.l; dz = -halfSize - cameraToLocalTransform.l;
len = dx*dx + dy*dy + dz*dz; len = dx*dx + dy*dy + dz*dz;
if (len > max) max = len; if (len > max) max = len;
dx = -size - cameraToLocalTransform.d; dx = -halfSize - cameraToLocalTransform.d;
dy = -size - cameraToLocalTransform.h; dy = -halfSize - cameraToLocalTransform.h;
dz = size - cameraToLocalTransform.l; dz = halfSize - cameraToLocalTransform.l;
len = dx*dx + dy*dy + dz*dz; len = dx*dx + dy*dy + dz*dz;
if (len > max) max = len; if (len > max) max = len;
dx = size - cameraToLocalTransform.d; dx = halfSize - cameraToLocalTransform.d;
dy = -size - cameraToLocalTransform.h; dy = -halfSize - cameraToLocalTransform.h;
dz = size - cameraToLocalTransform.l; dz = halfSize - cameraToLocalTransform.l;
len = dx*dx + dy*dy + dz*dz; len = dx*dx + dy*dy + dz*dz;
if (len > max) max = len; if (len > max) max = len;
dx = size - cameraToLocalTransform.d; dx = halfSize - cameraToLocalTransform.d;
dy = size - cameraToLocalTransform.h; dy = halfSize - cameraToLocalTransform.h;
dz = size - cameraToLocalTransform.l; dz = halfSize - cameraToLocalTransform.l;
len = dx*dx + dy*dy + dz*dz; len = dx*dx + dy*dy + dz*dz;
if (len > max) max = len; if (len > max) max = len;
dx = -size - cameraToLocalTransform.d; dx = -halfSize - cameraToLocalTransform.d;
dy = size - cameraToLocalTransform.h; dy = halfSize - cameraToLocalTransform.h;
dz = size - cameraToLocalTransform.l; dz = halfSize - cameraToLocalTransform.l;
len = dx*dx + dy*dy + dz*dz; len = dx*dx + dy*dy + dz*dz;
if (len > max) max = len; if (len > max) max = len;
drawUnit.setVertexConstantsFromNumbers(0, cameraToLocalTransform.d, cameraToLocalTransform.h, cameraToLocalTransform.l, camera.farClipping/Math.sqrt(max)); drawUnit.setVertexConstantsFromNumbers(0, cameraToLocalTransform.d, cameraToLocalTransform.h, cameraToLocalTransform.l, camera.farClipping/Math.sqrt(max));

View File

@@ -45,9 +45,9 @@ package alternativa.engine3d.resources {
/** /**
* Uploads textures from <code>BitmapData</code> to GPU. * Uploads textures from <code>BitmapData</code> to GPU.
*/ */
public function BitmapTextureResource(data:BitmapData, resizeToPowerOfTwo:Boolean = false) { public function BitmapTextureResource(data:BitmapData, resizeForGPU:Boolean = false) {
this.data = data; this.data = data;
this.resizeForGPU = resizeToPowerOfTwo; this.resizeForGPU = resizeForGPU;
} }
/** /**
@@ -58,7 +58,6 @@ package alternativa.engine3d.resources {
if (data != null) { if (data != null) {
var source:BitmapData = data; var source:BitmapData = data;
if (resizeForGPU) { if (resizeForGPU) {
// TODO: test this
var wLog2Num:Number = Math.log(data.width)/Math.LN2; var wLog2Num:Number = Math.log(data.width)/Math.LN2;
var hLog2Num:Number = Math.log(data.height)/Math.LN2; var hLog2Num:Number = Math.log(data.height)/Math.LN2;
var wLog2:int = Math.ceil(wLog2Num); var wLog2:int = Math.ceil(wLog2Num);

View File

@@ -43,9 +43,9 @@ package alternativa.engine3d.shadows {
use namespace alternativa3d; use namespace alternativa3d;
/** /**
* Class of shadow, that is created by one source of light(<code>DirectionalLight</code>). Shadow is rendered in fixed volume. * Class of the shadow, that is created by one source of light(<code>DirectionalLight</code>). Shadow is rendered in fixed volume.
* For binding of shadow to light source you need: * For binding of shadow to light source you need:
* 1) to set <code>DirectionalLightShadow</code> as a value of property <code>shadow</code> of light source; * 1) to set instance of the <code>DirectionalLightShadow</code> as a value of property <code>shadow</code> of light source;
* 2) to add <code>Object3D</code> to corresponding list, using the method <code>addCaster()</code>. * 2) to add <code>Object3D</code> to corresponding list, using the method <code>addCaster()</code>.
* *
* @see #addCaster() * @see #addCaster()
@@ -820,7 +820,7 @@ package alternativa.engine3d.shadows {
} }
/** /**
* Clears the list of objects, that cast shadow. * Clears the list of objects, which cast shadow.
*/ */
public function clearCasters():void { public function clearCasters():void {
_casters.length = 0; _casters.length = 0;

View File

@@ -40,7 +40,18 @@ package alternativa.engine3d.shadows {
use namespace alternativa3d; use namespace alternativa3d;
public class OmniLightShadow extends Shadow{ /**
* Class of the shadow, that is created by one source of light(<code>OmniLight</code>). Shadow is rendered in fixed volume.
* For binding of shadow to light source you need:
* 1) to set instance of the <code>OmniLight</code> as a value of property <code>shadow</code> of light source;
* 2) to add <code>Object3D</code> to corresponding list, using the method <code>addCaster()</code>.
*
* @see #addCaster()
* @see alternativa.engine3d.lights.OmniLight#shadow
* @see #farBoundPosition
*/
public class OmniLightShadow extends Shadow {
// TODO: calculate bias automaticaly // TODO: calculate bias automaticaly
/** /**
@@ -70,7 +81,7 @@ package alternativa.engine3d.shadows {
private var cameras:Vector.<Camera3D> = new Vector.<Camera3D>(); private var cameras:Vector.<Camera3D> = new Vector.<Camera3D>();
private var debugObject:Mesh; private var debugObject:Mesh;
private var debugMaterial:ShadowDebugMaterial; private var debugMaterial:ShadowDebugMaterial;
private var _casters:Vector.<Object3D> = new Vector.<Object3D>(); private var _casters:Vector.<Object3D> = new Vector.<Object3D>();
@@ -111,26 +122,26 @@ package alternativa.engine3d.shadows {
debugMaterial.alpha = 0.3; debugMaterial.alpha = 0.3;
for (var i:int = 0; i < 6; i++) { for (var i:int = 0; i < 6; i++) {
var cam:Camera3D = new Camera3D(radius/1000, radius); var cam:Camera3D = new Camera3D(radius / 1000, radius);
cam.fov = 1.910633237; cam.fov = 1.910633237;
cameras[i] = cam; cameras[i] = cam;
} }
// Left // Left
cameras[1].rotationY = -Math.PI/2; cameras[1].rotationY = -Math.PI / 2;
cameras[1].scaleY = -1; cameras[1].scaleY = -1;
cameras[1].composeTransforms(); cameras[1].composeTransforms();
// Right // Right
cameras[0].rotationY = Math.PI/2; cameras[0].rotationY = Math.PI / 2;
cameras[0].scaleY = -1; cameras[0].scaleY = -1;
cameras[0].composeTransforms(); cameras[0].composeTransforms();
// Back // Back
cameras[3].rotationX = -Math.PI/2; cameras[3].rotationX = -Math.PI / 2;
cameras[3].rotationZ = Math.PI; cameras[3].rotationZ = Math.PI;
cameras[3].scaleX = -1; cameras[3].scaleX = -1;
cameras[3].composeTransforms(); cameras[3].composeTransforms();
// Front // Front
cameras[2].rotationX = -Math.PI/2; cameras[2].rotationX = -Math.PI / 2;
cameras[2].scaleY = -1; cameras[2].scaleY = -1;
cameras[2].composeTransforms(); cameras[2].composeTransforms();
// Bottom // Bottom
@@ -143,7 +154,7 @@ package alternativa.engine3d.shadows {
cameras[4].composeTransforms(); cameras[4].composeTransforms();
} }
private function createDebugObject(material:Material, context:Context3D):Mesh{ private function createDebugObject(material:Material, context:Context3D):Mesh {
var geometry:Geometry; var geometry:Geometry;
var mesh:Mesh; var mesh:Mesh;
if (DEBUG_TYPE == "Box") { if (DEBUG_TYPE == "Box") {
@@ -186,7 +197,7 @@ package alternativa.engine3d.shadows {
triangles.push(c, b, a); triangles.push(c, b, a);
} }
mesh.geometry.indices = triangles; mesh.geometry.indices = triangles;
mesh.getSurface(0).numTriangles = triangles.length/3; mesh.getSurface(0).numTriangles = triangles.length / 3;
mesh.setMaterialToAllSurfaces(material); mesh.setMaterialToAllSurfaces(material);
} }
mesh.geometry.upload(context); mesh.geometry.upload(context);
@@ -218,7 +229,7 @@ package alternativa.engine3d.shadows {
radius = OmniLight(_light).attenuationEnd; radius = OmniLight(_light).attenuationEnd;
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++) {
var cam:Camera3D = cameras[i]; var cam:Camera3D = cameras[i];
cam.nearClipping = radius/1000; cam.nearClipping = radius / 1000;
cam.farClipping = radius; cam.farClipping = radius;
cam.calculateProjection(1, 1); cam.calculateProjection(1, 1);
} }
@@ -242,7 +253,7 @@ package alternativa.engine3d.shadows {
caster.localToLightTransform.combine(_light.cameraToLocalTransform, caster.localToCameraTransform); caster.localToLightTransform.combine(_light.cameraToLocalTransform, caster.localToCameraTransform);
// collect actualCasters for light // collect actualCasters for light
if (caster.boundBox == null || OmniLight(_light).checkBound(caster)){ if (caster.boundBox == null || OmniLight(_light).checkBound(caster)) {
actualCasters[actualCastersCount] = caster; actualCasters[actualCastersCount] = caster;
actualCastersCount++; actualCastersCount++;
@@ -280,7 +291,7 @@ package alternativa.engine3d.shadows {
// Cube side camera // Cube side camera
var edgeCamera:Camera3D = cameras[i]; var edgeCamera:Camera3D = cameras[i];
var edgeBit:int = (1<<i); var edgeBit:int = (1 << i);
if (actualCastersCount > 0) { if (actualCastersCount > 0) {
// Настройка параметров рендеринга: // Настройка параметров рендеринга:
renderer.camera = camera; renderer.camera = camera;
@@ -306,10 +317,10 @@ package alternativa.engine3d.shadows {
renderer.render(context); renderer.render(context);
prevActualCastersMask |= edgeBit; prevActualCastersMask |= edgeBit;
} }
else{ else {
// Если относительно одной из камер ничего не менялось, не вызываем отрисовочный вызов // Если относительно одной из камер ничего не менялось, не вызываем отрисовочный вызов
if ((prevActualCastersMask & edgeBit)){ if ((prevActualCastersMask & edgeBit)) {
context.setRenderToTexture(cubeShadowMap, false, 0, i); context.setRenderToTexture(cubeShadowMap, false, 0, i);
context.clear(1, 0, 0, 0); context.clear(1, 0, 0, 0);
@@ -331,7 +342,7 @@ package alternativa.engine3d.shadows {
if (debugObject == null) { if (debugObject == null) {
debugObject = createDebugObject(debugMaterial, camera.context3D); debugObject = createDebugObject(debugMaterial, camera.context3D);
} }
debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius*debugRadiusScale; debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius * debugRadiusScale;
debugObject.composeTransforms(); debugObject.composeTransforms();
// Формируем матрицу трансформации для debugObject // Формируем матрицу трансформации для debugObject
@@ -344,15 +355,15 @@ package alternativa.engine3d.shadows {
actualCasters.length = 0; actualCasters.length = 0;
} }
private function collectActualChildren(root:Object3D):void{ private function collectActualChildren(root:Object3D):void {
for (var child:Object3D = root.childrenList; child != null; child = child.next) { for (var child:Object3D = root.childrenList; child != null; child = child.next) {
if (child.visible){ if (child.visible) {
// calculate transform matrices // calculate transform matrices
_light.lightToObjectTransform.combine(child.cameraToLocalTransform, _light.localToCameraTransform); _light.lightToObjectTransform.combine(child.cameraToLocalTransform, _light.localToCameraTransform);
child.localToLightTransform.combine(_light.cameraToLocalTransform, child.localToCameraTransform); child.localToLightTransform.combine(_light.cameraToLocalTransform, child.localToCameraTransform);
// collect actualCasters for light // collect actualCasters for light
if (child.boundBox == null || OmniLight(_light).checkBound(child)){ if (child.boundBox == null || OmniLight(_light).checkBound(child)) {
actualCasters[actualCastersCount] = child; actualCasters[actualCastersCount] = child;
actualCastersCount++; actualCastersCount++;
@@ -508,46 +519,45 @@ package alternativa.engine3d.shadows {
if (plane.x >= 0) if (plane.x >= 0)
if (plane.y >= 0) if (plane.y >= 0)
if (plane.z >= 0) { if (plane.z >= 0) {
if (bb.maxX*plane.x + bb.maxY*plane.y + bb.maxZ*plane.z >= plane.offset) result = plane.frontCameras; if (bb.maxX * plane.x + bb.maxY * plane.y + bb.maxZ * plane.z >= plane.offset) result = plane.frontCameras;
if (bb.minX*plane.x + bb.minY*plane.y + bb.minZ*plane.z < plane.offset) result |= plane.backCameras; if (bb.minX * plane.x + bb.minY * plane.y + bb.minZ * plane.z < plane.offset) result |= plane.backCameras;
} else { } else {
if (bb.maxX*plane.x + bb.maxY*plane.y + bb.minZ*plane.z >= plane.offset) result = plane.frontCameras; if (bb.maxX * plane.x + bb.maxY * plane.y + bb.minZ * plane.z >= plane.offset) result = plane.frontCameras;
if (bb.minX*plane.x + bb.minY*plane.y + bb.maxZ*plane.z < plane.offset) result |= plane.backCameras; if (bb.minX * plane.x + bb.minY * plane.y + bb.maxZ * plane.z < plane.offset) result |= plane.backCameras;
}
else
if (plane.z >= 0) {
if (bb.maxX*plane.x + bb.minY*plane.y + bb.maxZ*plane.z >= plane.offset) result = plane.frontCameras;
if (bb.minX*plane.x + bb.maxY*plane.y + bb.minZ*plane.z < plane.offset) result |= plane.backCameras;
} else {
if (bb.maxX*plane.x + bb.minY*plane.y + bb.minZ*plane.z >= plane.offset) result = plane.frontCameras;
if (bb.minX*plane.x + bb.maxY*plane.y + bb.maxZ*plane.z < plane.offset) result |= plane.backCameras;
} }
else if (plane.z >= 0) {
if (bb.maxX * plane.x + bb.minY * plane.y + bb.maxZ * plane.z >= plane.offset) result = plane.frontCameras;
if (bb.minX * plane.x + bb.maxY * plane.y + bb.minZ * plane.z < plane.offset) result |= plane.backCameras;
} else {
if (bb.maxX * plane.x + bb.minY * plane.y + bb.minZ * plane.z >= plane.offset) result = plane.frontCameras;
if (bb.minX * plane.x + bb.maxY * plane.y + bb.maxZ * plane.z < plane.offset) result |= plane.backCameras;
}
else if (plane.y >= 0) else if (plane.y >= 0)
if (plane.z >= 0) { if (plane.z >= 0) {
if (bb.minX*plane.x + bb.maxY*plane.y + bb.maxZ*plane.z >= plane.offset) result = plane.frontCameras; if (bb.minX * plane.x + bb.maxY * plane.y + bb.maxZ * plane.z >= plane.offset) result = plane.frontCameras;
if (bb.maxX*plane.x + bb.minY*plane.y + bb.minZ*plane.z < plane.offset) result |= plane.backCameras; if (bb.maxX * plane.x + bb.minY * plane.y + bb.minZ * plane.z < plane.offset) result |= plane.backCameras;
} else { } else {
if (bb.minX*plane.x + bb.maxY*plane.y + bb.minZ*plane.z >= plane.offset) result = plane.frontCameras; if (bb.minX * plane.x + bb.maxY * plane.y + bb.minZ * plane.z >= plane.offset) result = plane.frontCameras;
if (bb.maxX*plane.x + bb.minY*plane.y + bb.maxZ*plane.z < plane.offset) result |= plane.backCameras; if (bb.maxX * plane.x + bb.minY * plane.y + bb.maxZ * plane.z < plane.offset) result |= plane.backCameras;
} }
else if (plane.z >= 0) { else if (plane.z >= 0) {
if (bb.minX*plane.x + bb.minY*plane.y + bb.maxZ*plane.z >= plane.offset) result = plane.frontCameras; if (bb.minX * plane.x + bb.minY * plane.y + bb.maxZ * plane.z >= plane.offset) result = plane.frontCameras;
if (bb.maxX*plane.x + bb.maxY*plane.y + bb.minZ*plane.z < plane.offset) result |= plane.backCameras; if (bb.maxX * plane.x + bb.maxY * plane.y + bb.minZ * plane.z < plane.offset) result |= plane.backCameras;
} else { } else {
if (bb.minX*plane.x + bb.minY*plane.y + bb.minZ*plane.z >= plane.offset) result = plane.frontCameras; if (bb.minX * plane.x + bb.minY * plane.y + bb.minZ * plane.z >= plane.offset) result = plane.frontCameras;
if (bb.maxX*plane.x + bb.maxY*plane.y + bb.maxZ*plane.z < plane.offset) result |= plane.backCameras; if (bb.maxX * plane.x + bb.maxY * plane.y + bb.maxZ * plane.z < plane.offset) result |= plane.backCameras;
} }
culling &= result | plane.unusedBits; culling &= result | plane.unusedBits;
} }
return culling; return culling;
} }
private function collectDraws(context:Context3D, caster:Object3D, edgeCamera:Camera3D):void{ private function collectDraws(context:Context3D, caster:Object3D, edgeCamera:Camera3D):void {
// если объект является мешем, собираем для него дроуколы // если объект является мешем, собираем для него дроуколы
var mesh:Mesh = caster as Mesh; var mesh:Mesh = caster as Mesh;
if (mesh != null && mesh.geometry != null) { if (mesh != null && mesh.geometry != null) {
var program:ShaderProgram; var program:ShaderProgram;
var programListByTransformProcedure:Vector.<ShaderProgram>; var programListByTransformProcedure:Vector.<ShaderProgram>;
var skin:Skin = mesh as Skin; var skin:Skin = mesh as Skin;
// пробегаемся по сурфейсам // пробегаемся по сурфейсам
@@ -617,7 +627,7 @@ package alternativa.engine3d.shadows {
drawUnit.setProjectionConstants(edgeCamera, program.vertexShader.getVariableIndex("cProjMatrix"), casterToEdgedCameraTransform); drawUnit.setProjectionConstants(edgeCamera, program.vertexShader.getVariableIndex("cProjMatrix"), casterToEdgedCameraTransform);
drawUnit.setVertexConstantsFromTransform(program.vertexShader.getVariableIndex("cCasterToOmni"), caster.localToLightTransform); drawUnit.setVertexConstantsFromTransform(program.vertexShader.getVariableIndex("cCasterToOmni"), caster.localToLightTransform);
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cConstants"), 1 / 255, 0, 255/radius, 1); drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cConstants"), 1 / 255, 0, 255 / radius, 1);
renderer.addDrawUnit(drawUnit, Renderer.OPAQUE); renderer.addDrawUnit(drawUnit, Renderer.OPAQUE);
} }
@@ -654,74 +664,73 @@ package alternativa.engine3d.shadows {
private function getProgram(transformProcedure:Procedure, programListByTransformProcedure:Vector.<ShaderProgram>, context:Context3D, alphaTest:Boolean, useDiffuseAlpha:Boolean):ShaderProgram { private function getProgram(transformProcedure:Procedure, programListByTransformProcedure:Vector.<ShaderProgram>, context:Context3D, alphaTest:Boolean, useDiffuseAlpha:Boolean):ShaderProgram {
var key:int = (alphaTest ? (useDiffuseAlpha ? 1 : 2) : 0); var key:int = (alphaTest ? (useDiffuseAlpha ? 1 : 2) : 0);
var program:ShaderProgram = programListByTransformProcedure[key]; var program:ShaderProgram = programListByTransformProcedure[key];
if (program == null) { if (program == null) {
var vLinker:Linker = new Linker(Context3DProgramType.VERTEX); var vLinker:Linker = new Linker(Context3DProgramType.VERTEX);
var fLinker:Linker = new Linker(Context3DProgramType.FRAGMENT); var fLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
var positionVar:String = "aPosition"; var positionVar:String = "aPosition";
vLinker.declareVariable(positionVar, VariableType.ATTRIBUTE); vLinker.declareVariable(positionVar, VariableType.ATTRIBUTE);
if (alphaTest) { if (alphaTest) {
vLinker.addProcedure(passUVProcedure); vLinker.addProcedure(passUVProcedure);
} }
if (transformProcedure != null) { if (transformProcedure != null) {
var newPosVar:String = "tTransformedPosition"; var newPosVar:String = "tTransformedPosition";
vLinker.declareVariable(newPosVar); vLinker.declareVariable(newPosVar);
vLinker.addProcedure(transformProcedure, positionVar); vLinker.addProcedure(transformProcedure, positionVar);
vLinker.setOutputParams(transformProcedure, newPosVar); vLinker.setOutputParams(transformProcedure, newPosVar);
positionVar = newPosVar; positionVar = newPosVar;
} }
var proc:Procedure = Procedure.compileFromArray([ var proc:Procedure = Procedure.compileFromArray([
"#v0=vDistance", "#v0=vDistance",
"m34 t0.xyz, i0, c2", "m34 t0.xyz, i0, c2",
"mov v0, t0.xyzx", "mov v0, t0.xyzx",
"m44 o0, i0, c0" "m44 o0, i0, c0"
]); ]);
proc.assignVariableName(VariableType.CONSTANT, 0, "cProjMatrix", 4); proc.assignVariableName(VariableType.CONSTANT, 0, "cProjMatrix", 4);
proc.assignVariableName(VariableType.CONSTANT, 2, "cCasterToOmni", 3); proc.assignVariableName(VariableType.CONSTANT, 2, "cCasterToOmni", 3);
vLinker.addProcedure(proc, positionVar); vLinker.addProcedure(proc, positionVar);
if (alphaTest) { if (alphaTest) {
if (useDiffuseAlpha) { if (useDiffuseAlpha) {
fLinker.addProcedure(diffuseAlphaTestProcedure); fLinker.addProcedure(diffuseAlphaTestProcedure);
} else { } else {
fLinker.addProcedure(opacityAlphaTestProcedure); fLinker.addProcedure(opacityAlphaTestProcedure);
} }
} }
fLinker.addProcedure(Procedure.compileFromArray([ fLinker.addProcedure(Procedure.compileFromArray([
"#v0=vDistance", // xyz "#v0=vDistance", // xyz
"#c0=cConstants", // 1/255, 0, 255/radius, 1 "#c0=cConstants", // 1/255, 0, 255/radius, 1
// calculate distance // calculate distance
"dp3 t0.z, v0.xyz, v0.xyz", "dp3 t0.z, v0.xyz, v0.xyz",
"sqt t0.z, t0.z", // x: [0, radius] "sqt t0.z, t0.z", // x: [0, radius]
"mul t0.z, t0.z, c0.z", // x: [0, 255] "mul t0.z, t0.z, c0.z", // x: [0, 255]
// codeing // codeing
"frc t0.y, t0.z", "frc t0.y, t0.z",
"sub t0.x, t0.z, t0.y", "sub t0.x, t0.z, t0.y",
"mul t0.x, t0.x, c0.x", "mul t0.x, t0.x, c0.x",
"mov t0.w, c0.w", "mov t0.w, c0.w",
"mov o0, t0" "mov o0, t0"
])); ]));
program = new ShaderProgram(vLinker, fLinker); program = new ShaderProgram(vLinker, fLinker);
fLinker.varyings = vLinker.varyings; fLinker.varyings = vLinker.varyings;
programListByTransformProcedure[key] = program; programListByTransformProcedure[key] = program;
program.upload(context); program.upload(context);
} }
return program; return program;
} }
//------------- ShadowMap Shader in material---------- //------------- ShadowMap Shader in material----------
/** /**
@@ -737,12 +746,12 @@ package alternativa.engine3d.shadows {
// Устанавливаем коеффициенты // Устанавливаем коеффициенты
if (_pcfOffset > 0) { if (_pcfOffset > 0) {
var offset:Number = Math.tan(_pcfOffset/180*Math.PI)/3; var offset:Number = Math.tan(_pcfOffset / 180 * Math.PI) / 3;
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cPCFOffsets"), -3/2, 1/16, 0, 0); drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cPCFOffsets"), -3 / 2, 1 / 16, 0, 0);
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -1, 1, 0, offset); drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -1, 1, 0, offset);
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cDecode"), -DIFFERENCE_MULTIPLIER, -DIFFERENCE_MULTIPLIER/255, biasMultiplier*DIFFERENCE_MULTIPLIER/radius, 10); drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cDecode"), -DIFFERENCE_MULTIPLIER, -DIFFERENCE_MULTIPLIER / 255, biasMultiplier * DIFFERENCE_MULTIPLIER / radius, 10);
} else { } else {
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -DIFFERENCE_MULTIPLIER, -DIFFERENCE_MULTIPLIER/255, biasMultiplier*DIFFERENCE_MULTIPLIER/radius, 1.0); drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -DIFFERENCE_MULTIPLIER, -DIFFERENCE_MULTIPLIER / 255, biasMultiplier * DIFFERENCE_MULTIPLIER / radius, 1.0);
} }
} }
@@ -834,7 +843,7 @@ package alternativa.engine3d.shadows {
// shaderArr[line++] = "mov t3.z, t0.w"; // shaderArr[line++] = "mov t3.z, t0.w";
shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, nearest>"; shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, nearest>";
shaderArr[line++] = "dp3 o0." +componentByIndex[0] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число shaderArr[line++] = "dp3 o0." + componentByIndex[0] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
//----- //-----
@@ -842,7 +851,7 @@ package alternativa.engine3d.shadows {
shaderArr[line++] = "add t2.xyz, t2.xyz, t1.xyz"; shaderArr[line++] = "add t2.xyz, t2.xyz, t1.xyz";
shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, nearest>"; shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, nearest>";
shaderArr[line++] = "dp3 o0." +componentByIndex[j] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число shaderArr[line++] = "dp3 o0." + componentByIndex[j] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
} }
shaderArr[line++] = "sat o0, o0"; shaderArr[line++] = "sat o0, o0";
@@ -854,13 +863,13 @@ package alternativa.engine3d.shadows {
shaderArr[line++] = "add t2.xyz, t2.xyz, t0.xyz"; shaderArr[line++] = "add t2.xyz, t2.xyz, t0.xyz";
shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, nearest>"; shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, nearest>";
shaderArr[line++] = "dp3 o0." +componentByIndex[0] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число shaderArr[line++] = "dp3 o0." + componentByIndex[0] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
for (j = 1; j < 4; j++){ for (j = 1; j < 4; j++) {
shaderArr[line++] = (i%2 == 1)?("add t2.xyz, t2.xyz, t1.xyz"):("sub t2.xyz, t2.xyz, t1.xyz"); shaderArr[line++] = (i % 2 == 1) ? ("add t2.xyz, t2.xyz, t1.xyz") : ("sub t2.xyz, t2.xyz, t1.xyz");
shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, nearest>"; shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, nearest>";
shaderArr[line++] = "dp3 o0." +componentByIndex[j] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число shaderArr[line++] = "dp3 o0." + componentByIndex[j] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
} }
shaderArr[line++] = "sat o0, o0"; shaderArr[line++] = "sat o0, o0";
shaderArr[line++] = "dp4 o0.x, o0, c2.y"; shaderArr[line++] = "dp4 o0.x, o0, c2.y";
@@ -876,8 +885,8 @@ package alternativa.engine3d.shadows {
private static const componentByIndex:Array = ["x", "y", "z", "w"]; private static const componentByIndex:Array = ["x", "y", "z", "w"];
/** /**
* Добавляет <code>object</code> в список объектов, отбрасывающих тень. * Adds given object to list of objects, that cast shadow.
* @param object Добавляемый объект. * @param object Added object.
*/ */
public function addCaster(object:Object3D):void { public function addCaster(object:Object3D):void {
if (_casters.indexOf(object) < 0) { if (_casters.indexOf(object) < 0) {
@@ -885,6 +894,10 @@ package alternativa.engine3d.shadows {
} }
} }
/**
* Removes given object from shadow casters list.
* @param object Object which should be removed from shadow casters list.
*/
public function removeCaster(object:Object3D):void { public function removeCaster(object:Object3D):void {
var index:int = _casters.indexOf(object); var index:int = _casters.indexOf(object);
if (index < 0) throw new Error("Caster not found"); if (index < 0) throw new Error("Caster not found");
@@ -892,14 +905,15 @@ package alternativa.engine3d.shadows {
} }
/** /**
* Очищает список объектов, отбрасывающих тень. * Clears the list of objects, that cast shadow.
*/ */
public function clearCasters():void { public function clearCasters():void {
_casters.length = 0; _casters.length = 0;
} }
/** /**
* Качество тени. Задает разрешение shadowmap. Может принимать значения от <code>2</code> до <code>11</code>. * Set resolution of shadow map. This property can get value of power of 2 (up to 2048).
* OmniLightShadow uses 6 shadow maps.
*/ */
public function get mapSize():int { public function get mapSize():int {
return _mapSize; return _mapSize;
@@ -916,7 +930,7 @@ package alternativa.engine3d.shadows {
} else if (value > 1024) { } else if (value > 1024) {
throw new ArgumentError("Map size exceeds maximum value 1024."); throw new ArgumentError("Map size exceeds maximum value 1024.");
} }
if ((Math.log(value)/Math.LN2 % 1) != 0) { if ((Math.log(value) / Math.LN2 % 1) != 0) {
throw new ArgumentError("Map size must be power of two."); throw new ArgumentError("Map size must be power of two.");
} }
if (cubeShadowMap != null) { if (cubeShadowMap != null) {
@@ -927,8 +941,7 @@ package alternativa.engine3d.shadows {
} }
/** /**
* Смещение Percentage Closer Filtering. Этот способ фильтрации используется для смягчения границ тени. * Offset of Percentage Closer Filtering. This way of filtering is used for mitigation of shadow bounds.
* 1 pcfOffset equivalent 1 degree for all blur
*/ */
public function get pcfOffset():Number { public function get pcfOffset():Number {
return _pcfOffset; return _pcfOffset;
@@ -971,6 +984,7 @@ import flash.utils.Dictionary;
class ShadowDebugMaterial extends Material { class ShadowDebugMaterial extends Material {
use namespace alternativa3d; use namespace alternativa3d;
/** /**
* Прозрачность. * Прозрачность.
* Является дополнительным множителем к прозрачности текстуры. * Является дополнительным множителем к прозрачности текстуры.
@@ -1015,7 +1029,7 @@ class ShadowDebugMaterial extends Material {
drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aPosition"), positionBuffer, geometry._attributesOffsets[VertexAttributes.POSITION], VertexAttributes.FORMATS[VertexAttributes.POSITION]); drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aPosition"), positionBuffer, geometry._attributesOffsets[VertexAttributes.POSITION], VertexAttributes.FORMATS[VertexAttributes.POSITION]);
// Установка констант // Установка констант
drawUnit.setProjectionConstants(camera, program.vertexShader.getVariableIndex("cProjMatrix"), object.localToCameraTransform); drawUnit.setProjectionConstants(camera, program.vertexShader.getVariableIndex("cProjMatrix"), object.localToCameraTransform);
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cDecode"), 1, 1/255, 0, alpha); drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cDecode"), 1, 1 / 255, 0, alpha);
drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sCubeMap"), cubeMap); drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sCubeMap"), cubeMap);
// Отправка на отрисовку // Отправка на отрисовку

View File

@@ -42,8 +42,13 @@ package alternativa.utils {
} }
/** /**
* @private * Calculates a BoundBox of hierarchy of objects.
* Performs calculation of bound box of objects hierarchy branch. *
* @param object Container which contains the hierarchy.
* @param boundBoxSpace <code>Object3D</code> in coordinates of which the BoundBox will be calculated.
* @param result Instance of <code>BoundBox</code> to which calculated properties will be set.
*
* @return Instance given as <code>result</code> property with properties updated according to calculations. If <code>result</code> property was not set, new instance of <code>BoundBox</code> will be created.
*/ */
public static function calculateHierarchyBoundBox(object:Object3D, boundBoxSpace:Object3D = null, result:BoundBox = null):BoundBox { public static function calculateHierarchyBoundBox(object:Object3D, boundBoxSpace:Object3D = null, result:BoundBox = null):BoundBox {
if (result == null) result = new BoundBox(); if (result == null) result = new BoundBox();