diff --git a/changelog_en.txt b/changelog_en.txt
new file mode 100644
index 0000000..355dbd6
--- /dev/null
+++ b/changelog_en.txt
@@ -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
diff --git a/src/alternativa/engine3d/animation/AnimationClip.as b/src/alternativa/engine3d/animation/AnimationClip.as
index 584a6a2..12b1a66 100644
--- a/src/alternativa/engine3d/animation/AnimationClip.as
+++ b/src/alternativa/engine3d/animation/AnimationClip.as
@@ -465,6 +465,8 @@ package alternativa.engine3d.animation {
*/
public function slice(start:Number, end:Number = Number.MAX_VALUE):AnimationClip {
var sliced:AnimationClip = new AnimationClip(name);
+ sliced.animated = animated;
+ sliced.loop = loop;
sliced._objects = (_objects == null) ? null : [].concat(_objects);
for (var i:int = 0; i < _numTracks; i++) {
sliced.addTrack(_tracks[i].slice(start, end));
@@ -477,6 +479,8 @@ package alternativa.engine3d.animation {
*/
public function clone():AnimationClip {
var cloned:AnimationClip = new AnimationClip(name);
+ cloned.animated = animated;
+ cloned.loop = loop;
cloned._objects = (_objects == null) ? null : [].concat(_objects);
for (var i:int = 0; i < _numTracks; i++) {
cloned.addTrack(_tracks[i]);
diff --git a/src/alternativa/engine3d/core/Camera3D.as b/src/alternativa/engine3d/core/Camera3D.as
index e7a2d82..e69d9ee 100644
--- a/src/alternativa/engine3d/core/Camera3D.as
+++ b/src/alternativa/engine3d/core/Camera3D.as
@@ -46,6 +46,12 @@ package alternativa.engine3d.core {
*/
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.
* If viewport is not defined, the camera would not draws anything.
@@ -156,6 +162,11 @@ public class Camera3D extends Object3D {
*/
alternativa3d var context3D:Context3D;
+ /**
+ * @private
+ */
+ alternativa3d var context3DProperties:RendererContext3DProperties;
+
/**
* @private
* Camera's renderer. If is not defined, the camera will no draw anything.
@@ -195,7 +206,6 @@ public class Camera3D extends Object3D {
* @param stage3D Stage3D to which image will be rendered.
*/
public function render(stage3D:Stage3D):void {
- // TODO: don't check mouse events if no listeners
var i:int;
var j:int;
var light:Light3D;
@@ -214,13 +224,27 @@ public class Camera3D extends Object3D {
ambient[2] = 0;
ambient[3] = 1;
// 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)) {
renderer.camera = this;
// Projection argument calculating
calculateProjection(view._width, view._height);
// Preparing to rendering
- view.prepareToRender(stage3D, context3D);
+ view.configureContext3D(stage3D, context3D, this);
// Transformations calculating
if (transformChanged) composeTransforms();
localToGlobalTransform.copy(transform);
@@ -236,14 +260,12 @@ public class Camera3D extends Object3D {
// Check if object of hierarchy is visible
if (root.visible) {
- globalMouseHandlingType = 0;
-
// Calculating the matrix to transform from the camera space to local space
root.cameraToLocalTransform.combine(root.inverseTransform, localToGlobalTransform);
// Calculating the matrix to transform from local space to the camera space
root.localToCameraTransform.combine(globalToLocalTransform, root.transform);
- if (root.mouseEnabled) globalMouseHandlingType |= root.mouseHandlingType;
+ globalMouseHandlingType = root.mouseHandlingType;
// Checking the culling
if (root.boundBox != null) {
calculateFrustum(root.cameraToLocalTransform);
@@ -251,7 +273,7 @@ public class Camera3D extends Object3D {
} else {
root.culling = 63;
}
- // Calculations of conent visibility
+ // Calculations of content visibility
if (root.culling >= 0) root.calculateVisibility(this);
// Calculations visibility of children
root.calculateChildrenVisibility(this);
@@ -334,6 +356,16 @@ public class Camera3D extends Object3D {
}
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
if (root.culling >= 0 && (root.boundBox == null || occludersLength == 0 || !root.boundBox.checkOcclusion(occluders, occludersLength, root.localToCameraTransform))) {
// Check if the ray crossing the bounding box
@@ -387,7 +419,6 @@ public class Camera3D extends Object3D {
}
// Gather the draws for children
root.collectChildrenDraws(this, lights, lightsLength, root.useShadow);
-
// Mouse events prosessing
view.processMouseEvents(context3D, this);
// Render
@@ -405,7 +436,6 @@ public class Camera3D extends Object3D {
lights.length = 0;
childLights.length = 0;
occluders.length = 0;
- context3D = null;
}
/**
@@ -424,7 +454,7 @@ public class Camera3D extends Object3D {
var deltaX:Number = x - this.x;
var deltaY:Number = y - this.y;
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;
rotationY = 0;
rotationZ = - Math.atan2(deltaX,deltaY);
diff --git a/src/alternativa/engine3d/core/Object3D.as b/src/alternativa/engine3d/core/Object3D.as
index ec3d9ef..c0ae40c 100644
--- a/src/alternativa/engine3d/core/Object3D.as
+++ b/src/alternativa/engine3d/core/Object3D.as
@@ -172,26 +172,53 @@ package alternativa.engine3d.core {
*/
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
*/
- 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
*/
- 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
*/
- alternativa3d static const MOUSE_HANDLING_WHEEL:uint = 4;
+ alternativa3d static const MOUSE_HANDLING_WHEEL:uint = MOUSE_WHEEL_BIT;
/**
* @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
*/
- 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 Object3D by user.
@@ -249,12 +276,6 @@ package alternativa.engine3d.core {
*/
public var doubleClickEnabled:Boolean = false;
- /**
- * A Boolean value that indicates whether the pointing hand (hand cursor)
- * appears when the pointer rolls over a Object3D.
- */
- public var useHandCursor:Boolean = false;
-
/**
* Bounds of the object described as rectangular parallelepiped.
*/
@@ -587,6 +608,25 @@ package alternativa.engine3d.core {
transformChanged = true;
}
+ /**
+ * A Boolean value that indicates whether the pointing hand (hand cursor)
+ * appears when the pointer rolls over a Object3D.
+ */
+ 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 Object3D and given ray, defined by origin and direction.
*
@@ -739,20 +779,56 @@ package alternativa.engine3d.core {
vector = new 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) {
- 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;
+ // update mouseHandlingType bits
+ 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;
}
}
if (vector.indexOf(listener) < 0) {
@@ -781,7 +857,68 @@ package alternativa.engine3d.core {
if (length > 1) {
vector.length = length - 1;
} 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];
+
var key:*;
for (key in listeners) break;
if (!key) {
@@ -791,21 +928,6 @@ package alternativa.engine3d.core {
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
child.localToCameraTransform.combine(localToCameraTransform, child.transform);
- if (child.mouseEnabled) camera.globalMouseHandlingType |= child.mouseHandlingType;
+ camera.globalMouseHandlingType |= child.mouseHandlingType;
// Culling checking
if (child.boundBox != null) {
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 light.
+ *
+ * @param light Light which should not affect to the object
+ * @param updateChildren If true 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{
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 {
_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 Object3D.
*/
public function clone():Object3D {
@@ -1614,7 +1741,8 @@ package alternativa.engine3d.core {
*/
public function toString():String {
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 + "]";
}
}
diff --git a/src/alternativa/engine3d/core/Renderer.as b/src/alternativa/engine3d/core/Renderer.as
index ad51b11..77fae35 100644
--- a/src/alternativa/engine3d/core/Renderer.as
+++ b/src/alternativa/engine3d/core/Renderer.as
@@ -4,8 +4,8 @@
* 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/
- * */
-
+ *
+ */
package alternativa.engine3d.core {
import alternativa.engine3d.alternativa3d;
@@ -16,7 +16,6 @@ package alternativa.engine3d.core {
import flash.display3D.Context3DProgramType;
import flash.display3D.IndexBuffer3D;
import flash.display3D.Program3D;
- import flash.utils.Dictionary;
use namespace alternativa3d;
@@ -37,17 +36,13 @@ package alternativa.engine3d.core {
public static const NEXT_LAYER:int = 50;
- // Key - context, value - properties.
- protected static var properties:Dictionary = new Dictionary(true);
-
// Collector
protected var collector:DrawUnit;
alternativa3d var camera:Camera3D;
alternativa3d var drawUnits:Vector. = new Vector.();
-
- protected var _context3D:Context3D;
+
protected var _contextProperties:RendererContext3DProperties;
alternativa3d function render(context3D:Context3D):void {
@@ -59,29 +54,29 @@ package alternativa.engine3d.core {
if (list != null) {
switch (i) {
case SKY:
- _context3D.setDepthTest(false, Context3DCompareMode.ALWAYS);
+ context3D.setDepthTest(false, Context3DCompareMode.ALWAYS);
break;
case OPAQUE:
- _context3D.setDepthTest(true, Context3DCompareMode.LESS);
+ context3D.setDepthTest(true, Context3DCompareMode.LESS);
break;
case OPAQUE_OVERHEAD:
- _context3D.setDepthTest(false, Context3DCompareMode.EQUAL);
+ context3D.setDepthTest(false, Context3DCompareMode.EQUAL);
break;
case DECALS:
- _context3D.setDepthTest(false, Context3DCompareMode.LESS_EQUAL);
+ context3D.setDepthTest(false, Context3DCompareMode.LESS_EQUAL);
break;
case TRANSPARENT_SORT:
if (list.next != null) list = sortByAverageZ(list);
- _context3D.setDepthTest(false, Context3DCompareMode.LESS);
+ context3D.setDepthTest(false, Context3DCompareMode.LESS);
break;
case NEXT_LAYER:
- _context3D.setDepthTest(false, Context3DCompareMode.ALWAYS);
+ context3D.setDepthTest(false, Context3DCompareMode.ALWAYS);
break;
}
// Rendering
while (list != null) {
var next:DrawUnit = list.next;
- renderDrawUnit(list, _context3D, camera);
+ renderDrawUnit(list, context3D, camera);
// Send to collector
list.clear();
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);
// Clear
drawUnits.length = 0;
@@ -180,14 +176,7 @@ package alternativa.engine3d.core {
}
protected function updateContext3D(value:Context3D):void {
- if (_context3D != value) {
- _contextProperties = properties[value];
- if (_contextProperties == null) {
- _contextProperties = new RendererContext3DProperties();
- properties[value] = _contextProperties;
- }
- _context3D = value;
- }
+ _contextProperties = camera.context3DProperties;
}
/**
diff --git a/src/alternativa/engine3d/core/RendererContext3DProperties.as b/src/alternativa/engine3d/core/RendererContext3DProperties.as
index a92aad0..59a6502 100644
--- a/src/alternativa/engine3d/core/RendererContext3DProperties.as
+++ b/src/alternativa/engine3d/core/RendererContext3DProperties.as
@@ -8,7 +8,11 @@
package alternativa.engine3d.core {
+ import alternativa.engine3d.materials.ShaderProgram;
+ import alternativa.engine3d.resources.Geometry;
+
import flash.display3D.Program3D;
+ import flash.utils.Dictionary;
/**
* @private
@@ -16,6 +20,12 @@ package alternativa.engine3d.core {
*/
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 usedTextures:uint = 0;
@@ -24,5 +34,11 @@ package alternativa.engine3d.core {
public var blendSource: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;
+
}
}
diff --git a/src/alternativa/engine3d/core/View.as b/src/alternativa/engine3d/core/View.as
index ec25310..4d3a503 100644
--- a/src/alternativa/engine3d/core/View.as
+++ b/src/alternativa/engine3d/core/View.as
@@ -61,10 +61,6 @@ package alternativa.engine3d.core {
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 drawDistanceVertexProcedure:Procedure;
@@ -309,6 +305,11 @@ package alternativa.engine3d.core {
addEventListener(Event.REMOVED_FROM_STAGE, onRemoveFromStage);
}
+ /**
+ * If true, you will able to handle following events MouseEvent3D.RIGHT_CLICK,
+ * MouseEvent3D.RIGHT_MOUSE_DOWN, MouseEvent3D.RIGHT_MOUSE_UP.
+ * The context menu will no longer open on clicking right mouse button.
+ */
public function get rightClick3DEnabled():Boolean {
return _rightClick3DEnabled;
}
@@ -533,7 +534,7 @@ package alternativa.engine3d.core {
/**
* @private
*/
- alternativa3d function prepareToRender(stage3D:Stage3D, context:Context3D):void {
+ alternativa3d function configureContext3D(stage3D:Stage3D, context3D:Context3D, camera:Camera3D):void {
if (_canvas == null) {
var vis:Boolean = this.visible;
for (var parent:DisplayObject = this.parent; parent != null; parent = parent.parent) {
@@ -553,70 +554,55 @@ package alternativa.engine3d.core {
createRenderBitmap();
}
}
- if (context != cachedContext3D) {
- // Get properties.
- cachedContext3D = context;
- context3DProperties = properties[cachedContext3D];
- if (context3DProperties == null) {
- context3DProperties = new Context3DViewProperties();
- // Inititalize data for mouse events
- var rectGeometry:Geometry = new Geometry(4);
- rectGeometry.addVertexStream([VertexAttributes.POSITION, VertexAttributes.POSITION, VertexAttributes.POSITION, VertexAttributes.TEXCOORDS[0], VertexAttributes.TEXCOORDS[0]]);
- rectGeometry.setAttributeValues(VertexAttributes.POSITION, Vector.([0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1]));
- rectGeometry.setAttributeValues(VertexAttributes.TEXCOORDS[0], Vector.([0, 0, 0, 1, 1, 1, 1, 0]));
- rectGeometry.indices = Vector.([0, 1, 3, 2, 3, 1]);
- rectGeometry.upload(context);
- var vLinker:Linker = new Linker(Context3DProgramType.VERTEX);
- vLinker.addProcedure(Procedure.compileFromArray([
- "#a0=a0",
- "#c0=c0",
- "mul t0.x, a0.x, c0.x",
- "mul t0.y, a0.y, c0.y",
- "add o0.x, t0.x, c0.z",
- "add o0.y, t0.y, c0.w",
- "mov o0.z, a0.z",
- "mov o0.w, a0.z",
- ]));
- var fLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
- fLinker.addProcedure(Procedure.compileFromArray([
- "#c0=c0",
- "mov o0, c0",
- ]));
- var coloredRectProgram:ShaderProgram = new ShaderProgram(vLinker, fLinker);
- coloredRectProgram.upload(context);
+ var context3DProperties:RendererContext3DProperties = camera.context3DProperties;
+ if (context3DProperties.drawRectGeometry == null) {
+ // Inititalize data for mouse events
+ var rectGeometry:Geometry = new Geometry(4);
+ rectGeometry.addVertexStream([VertexAttributes.POSITION, VertexAttributes.POSITION, VertexAttributes.POSITION, VertexAttributes.TEXCOORDS[0], VertexAttributes.TEXCOORDS[0]]);
+ rectGeometry.setAttributeValues(VertexAttributes.POSITION, Vector.([0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1]));
+ rectGeometry.setAttributeValues(VertexAttributes.TEXCOORDS[0], Vector.([0, 0, 0, 1, 1, 1, 1, 0]));
+ rectGeometry.indices = Vector.([0, 1, 3, 2, 3, 1]);
+ rectGeometry.upload(context3D);
+ var vLinker:Linker = new Linker(Context3DProgramType.VERTEX);
+ vLinker.addProcedure(Procedure.compileFromArray([
+ "#a0=a0",
+ "#c0=c0",
+ "mul t0.x, a0.x, c0.x",
+ "mul t0.y, a0.y, c0.y",
+ "add o0.x, t0.x, c0.z",
+ "add o0.y, t0.y, c0.w",
+ "mov o0.z, a0.z",
+ "mov o0.w, a0.z",
+ ]));
+ var fLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
+ fLinker.addProcedure(Procedure.compileFromArray([
+ "#c0=c0",
+ "mov o0, c0",
+ ]));
+ var coloredRectProgram:ShaderProgram = new ShaderProgram(vLinker, fLinker);
+ coloredRectProgram.upload(context3D);
- context3DProperties.drawRectGeometry = rectGeometry;
- context3DProperties.drawColoredRectProgram = coloredRectProgram;
- properties[cachedContext3D] = context3DProperties;
- }
+ context3DProperties.drawRectGeometry = rectGeometry;
+ context3DProperties.drawColoredRectProgram = coloredRectProgram;
}
if (_width != context3DProperties.backBufferWidth || _height != context3DProperties.backBufferHeight || antiAlias != context3DProperties.backBufferAntiAlias) {
context3DProperties.backBufferWidth = _width;
context3DProperties.backBufferHeight = _height;
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
*/
- alternativa3d function processMouseEvents(context:Context3D, camera:Camera3D):void {
+ alternativa3d function processMouseEvents(context3D:Context3D, camera:Camera3D):void {
var i:int;
// Mouse events
if (eventsLength > 0) {
if (surfacesLength > 0) {
// Calculating the depth
- calculateSurfacesDepths(context, camera, _width, _height);
+ calculateSurfacesDepths(context3D, camera, _width, _height);
// Sorting by decreasing the depth
for (i = 0; i < raysLength; i++) {
var raySurfaces:Vector. = raysSurfaces[i];
@@ -776,8 +762,8 @@ package alternativa.engine3d.core {
context.setVertexBufferAt(6, null);
context.setVertexBufferAt(7, null);
- var drawRectGeometry:Geometry = context3DProperties.drawRectGeometry;
- var drawColoredRectProgram:ShaderProgram = context3DProperties.drawColoredRectProgram;
+ var drawRectGeometry:Geometry = camera.context3DProperties.drawRectGeometry;
+ var drawColoredRectProgram:ShaderProgram = camera.context3DProperties.drawColoredRectProgram;
// Rectangle
var vLinker:Linker, fLinker:Linker;
@@ -883,7 +869,7 @@ package alternativa.engine3d.core {
var procedure:Procedure = procedures[index];
var object:Object3D = surface.object;
// Program
- var drawDistanceProgram:ShaderProgram = context3DProperties.drawDistancePrograms[procedure];
+ var drawDistanceProgram:ShaderProgram = camera.context3DProperties.drawDistancePrograms[procedure];
if (drawDistanceProgram == null) {
// Assembling the vertex shader
var vertex:Linker = new Linker(Context3DProgramType.VERTEX);
@@ -902,7 +888,7 @@ package alternativa.engine3d.core {
drawDistanceProgram = new ShaderProgram(vertex, drawDistanceFragment);
drawDistanceProgram.fragmentShader.varyings = drawDistanceProgram.vertexShader.varyings;
drawDistanceProgram.upload(context);
- context3DProperties.drawDistancePrograms[procedure] = drawDistanceProgram;
+ camera.context3DProperties.drawDistancePrograms[procedure] = drawDistanceProgram;
}
var buffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.POSITION);
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.Sprite;
import flash.events.MouseEvent;
@@ -1415,7 +1398,6 @@ import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.net.URLRequest;
import flash.net.navigateToURL;
-import flash.utils.Dictionary;
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;
-
-}
diff --git a/src/alternativa/engine3d/materials/EnvironmentMaterial.as b/src/alternativa/engine3d/materials/EnvironmentMaterial.as
index d1e8478..24dcb83 100644
--- a/src/alternativa/engine3d/materials/EnvironmentMaterial.as
+++ b/src/alternativa/engine3d/materials/EnvironmentMaterial.as
@@ -310,6 +310,15 @@ package alternativa.engine3d.materials {
"mov v0, a0"
], "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;
/**
@@ -815,6 +824,31 @@ package alternativa.engine3d.materials {
if (_normalMap != null && _normalMap._texture == null) return;
if (_reflectionMap != null && _reflectionMap._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;
// Program
diff --git a/src/alternativa/engine3d/materials/StandardMaterial.as b/src/alternativa/engine3d/materials/StandardMaterial.as
index 7ce0217..f451c23 100644
--- a/src/alternativa/engine3d/materials/StandardMaterial.as
+++ b/src/alternativa/engine3d/materials/StandardMaterial.as
@@ -307,6 +307,15 @@ package alternativa.engine3d.materials {
"mov v0, a0"
], "passLightMapUVProcedure");
+ /**
+ * @private
+ */
+ alternativa3d static var fallbackTextureMaterial:TextureMaterial = new TextureMaterial();
+ /**
+ * @private
+ */
+ alternativa3d static var fallbackLightMapMaterial:LightMapMaterial = new LightMapMaterial();
+
/**
* Normal map.
*/
@@ -986,6 +995,30 @@ package alternativa.engine3d.materials {
// 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 (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;
// Buffers
diff --git a/src/alternativa/engine3d/materials/TextureMaterial.as b/src/alternativa/engine3d/materials/TextureMaterial.as
index 3504555..80ea821 100644
--- a/src/alternativa/engine3d/materials/TextureMaterial.as
+++ b/src/alternativa/engine3d/materials/TextureMaterial.as
@@ -34,7 +34,7 @@ package alternativa.engine3d.materials {
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.
* @see alternativa.engine3d.objects.Skin#divide()
@@ -113,19 +113,19 @@ package alternativa.engine3d.materials {
public var opacityMap:TextureResource;
/**
- * If true, perform transparent pass. Parts of surface, cumulative alpha value of which is below than alphaThreshold draw within transparent pass.
+ * If true, perform transparent pass. Parts of surface, cumulative alpha value of which is below than alphaThreshold will be drawn within transparent pass.
* @see #alphaThreshold
*/
public var transparentPass:Boolean = true;
/**
- * If true, perform opaque pass. Parts of surface, cumulative alpha value of which is greater or equal than alphaThreshold draw within opaque pass.
+ * If true, perform opaque pass. Parts of surface, cumulative alpha value of which is greater or equal than alphaThreshold will be drawn within opaque pass.
* @see #alphaThreshold
*/
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 #opaquePass
*/
diff --git a/src/alternativa/engine3d/materials/VertexLightTextureMaterial.as b/src/alternativa/engine3d/materials/VertexLightTextureMaterial.as
index 009f231..ceb0664 100644
--- a/src/alternativa/engine3d/materials/VertexLightTextureMaterial.as
+++ b/src/alternativa/engine3d/materials/VertexLightTextureMaterial.as
@@ -98,6 +98,11 @@ package alternativa.engine3d.materials {
private static const _lightsProcedures:Dictionary = new Dictionary(true);
+ /**
+ * @private
+ */
+ alternativa3d static var fallbackMaterial:TextureMaterial = new TextureMaterial();
+
/**
* 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., lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void {
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;
// Buffers
diff --git a/src/alternativa/engine3d/objects/LOD.as b/src/alternativa/engine3d/objects/LOD.as
index 27af29f..04d38a0 100644
--- a/src/alternativa/engine3d/objects/LOD.as
+++ b/src/alternativa/engine3d/objects/LOD.as
@@ -176,6 +176,7 @@ package alternativa.engine3d.objects {
* @private
*/
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);
for (level = levelList; level != null; level = level.next) {
if (distance <= level.distance) {
@@ -196,7 +197,7 @@ package alternativa.engine3d.objects {
// Calculation of transfer matrix from local space to camera.
child.localToCameraTransform.combine(parent.localToCameraTransform, child.transform);
- if (child.mouseEnabled) camera.globalMouseHandlingType |= child.mouseHandlingType;
+ camera.globalMouseHandlingType |= child.mouseHandlingType;
// Pass
child.culling = parent.culling;
// Calculating visibility of the self content
diff --git a/src/alternativa/engine3d/objects/SkyBox.as b/src/alternativa/engine3d/objects/SkyBox.as
index e047a1e..9f2299f 100644
--- a/src/alternativa/engine3d/objects/SkyBox.as
+++ b/src/alternativa/engine3d/objects/SkyBox.as
@@ -80,7 +80,7 @@ package alternativa.engine3d.objects {
private var bottomSurface:Surface;
private var topSurface:Surface;
- private var size:Number;
+ private var halfSize:Number;
/**
* Creates a new SkyBox instance.
@@ -95,10 +95,7 @@ package alternativa.engine3d.objects {
* @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) {
-
- size *= 0.5;
-
- this.size = size;
+ this.halfSize = size*0.5;
geometry = new Geometry(24);
@@ -111,35 +108,35 @@ package alternativa.engine3d.objects {
geometry.addVertexStream(attributes);
geometry.setAttributeValues(VertexAttributes.POSITION, Vector.([
- -size, -size, size,
- -size, -size, -size,
- -size, size, -size,
- -size, size, size,
+ -halfSize, -halfSize, halfSize,
+ -halfSize, -halfSize, -halfSize,
+ -halfSize, halfSize, -halfSize,
+ -halfSize, halfSize, halfSize,
+
+ halfSize, halfSize, halfSize,
+ halfSize, halfSize, -halfSize,
+ halfSize, -halfSize, -halfSize,
+ halfSize, -halfSize, halfSize,
+
+ halfSize, -halfSize, halfSize,
+ halfSize, -halfSize, -halfSize,
+ -halfSize, -halfSize, -halfSize,
+ -halfSize, -halfSize, halfSize,
- size, size, size,
- size, size, -size,
- size, -size, -size,
- size, -size, size,
+ -halfSize, halfSize, halfSize,
+ -halfSize, halfSize, -halfSize,
+ halfSize, halfSize, -halfSize,
+ halfSize, halfSize, halfSize,
- size, -size, size,
- size, -size, -size,
- -size, -size, -size,
- -size, -size, size,
+ -halfSize, halfSize, -halfSize,
+ -halfSize, -halfSize, -halfSize,
+ halfSize, -halfSize, -halfSize,
+ halfSize, halfSize, -halfSize,
- -size, size, size,
- -size, size, -size,
- size, size, -size,
- size, size, size,
-
- -size, size, -size,
- -size, -size, -size,
- size, -size, -size,
- size, size, -size,
-
- -size, -size, size,
- -size, size, size,
- size, size, size,
- size, -size, size
+ -halfSize, -halfSize, halfSize,
+ -halfSize, halfSize, halfSize,
+ halfSize, halfSize, halfSize,
+ halfSize, -halfSize, halfSize
]));
geometry.setAttributeValues(VertexAttributes.TEXCOORDS[0], Vector.([
@@ -214,44 +211,44 @@ package alternativa.engine3d.objects {
var dy:Number;
var dz:Number;
var len:Number;
- dx = -size - cameraToLocalTransform.d;
- dy = -size - cameraToLocalTransform.h;
- dz = -size - cameraToLocalTransform.l;
+ dx = -halfSize - cameraToLocalTransform.d;
+ dy = -halfSize - cameraToLocalTransform.h;
+ dz = -halfSize - cameraToLocalTransform.l;
len = dx*dx + dy*dy + dz*dz;
if (len > max) max = len;
- dx = size - cameraToLocalTransform.d;
- dy = -size - cameraToLocalTransform.h;
- dz = -size - cameraToLocalTransform.l;
+ dx = halfSize - cameraToLocalTransform.d;
+ dy = -halfSize - cameraToLocalTransform.h;
+ dz = -halfSize - cameraToLocalTransform.l;
len = dx*dx + dy*dy + dz*dz;
if (len > max) max = len;
- dx = size - cameraToLocalTransform.d;
- dy = size - cameraToLocalTransform.h;
- dz = -size - cameraToLocalTransform.l;
+ dx = halfSize - cameraToLocalTransform.d;
+ dy = halfSize - cameraToLocalTransform.h;
+ dz = -halfSize - cameraToLocalTransform.l;
len = dx*dx + dy*dy + dz*dz;
if (len > max) max = len;
- dx = -size - cameraToLocalTransform.d;
- dy = size - cameraToLocalTransform.h;
- dz = -size - cameraToLocalTransform.l;
+ dx = -halfSize - cameraToLocalTransform.d;
+ dy = halfSize - cameraToLocalTransform.h;
+ dz = -halfSize - cameraToLocalTransform.l;
len = dx*dx + dy*dy + dz*dz;
if (len > max) max = len;
- dx = -size - cameraToLocalTransform.d;
- dy = -size - cameraToLocalTransform.h;
- dz = size - cameraToLocalTransform.l;
+ dx = -halfSize - cameraToLocalTransform.d;
+ dy = -halfSize - cameraToLocalTransform.h;
+ dz = halfSize - cameraToLocalTransform.l;
len = dx*dx + dy*dy + dz*dz;
if (len > max) max = len;
- dx = size - cameraToLocalTransform.d;
- dy = -size - cameraToLocalTransform.h;
- dz = size - cameraToLocalTransform.l;
+ dx = halfSize - cameraToLocalTransform.d;
+ dy = -halfSize - cameraToLocalTransform.h;
+ dz = halfSize - cameraToLocalTransform.l;
len = dx*dx + dy*dy + dz*dz;
if (len > max) max = len;
- dx = size - cameraToLocalTransform.d;
- dy = size - cameraToLocalTransform.h;
- dz = size - cameraToLocalTransform.l;
+ dx = halfSize - cameraToLocalTransform.d;
+ dy = halfSize - cameraToLocalTransform.h;
+ dz = halfSize - cameraToLocalTransform.l;
len = dx*dx + dy*dy + dz*dz;
if (len > max) max = len;
- dx = -size - cameraToLocalTransform.d;
- dy = size - cameraToLocalTransform.h;
- dz = size - cameraToLocalTransform.l;
+ dx = -halfSize - cameraToLocalTransform.d;
+ dy = halfSize - cameraToLocalTransform.h;
+ dz = halfSize - cameraToLocalTransform.l;
len = dx*dx + dy*dy + dz*dz;
if (len > max) max = len;
drawUnit.setVertexConstantsFromNumbers(0, cameraToLocalTransform.d, cameraToLocalTransform.h, cameraToLocalTransform.l, camera.farClipping/Math.sqrt(max));
diff --git a/src/alternativa/engine3d/resources/BitmapTextureResource.as b/src/alternativa/engine3d/resources/BitmapTextureResource.as
index 76a9722..d565db3 100644
--- a/src/alternativa/engine3d/resources/BitmapTextureResource.as
+++ b/src/alternativa/engine3d/resources/BitmapTextureResource.as
@@ -45,9 +45,9 @@ package alternativa.engine3d.resources {
/**
* Uploads textures from BitmapData to GPU.
*/
- public function BitmapTextureResource(data:BitmapData, resizeToPowerOfTwo:Boolean = false) {
+ public function BitmapTextureResource(data:BitmapData, resizeForGPU:Boolean = false) {
this.data = data;
- this.resizeForGPU = resizeToPowerOfTwo;
+ this.resizeForGPU = resizeForGPU;
}
/**
@@ -58,7 +58,6 @@ package alternativa.engine3d.resources {
if (data != null) {
var source:BitmapData = data;
if (resizeForGPU) {
- // TODO: test this
var wLog2Num:Number = Math.log(data.width)/Math.LN2;
var hLog2Num:Number = Math.log(data.height)/Math.LN2;
var wLog2:int = Math.ceil(wLog2Num);
diff --git a/src/alternativa/engine3d/shadows/DirectionalLightShadow.as b/src/alternativa/engine3d/shadows/DirectionalLightShadow.as
index 4c11eb0..5c47afe 100644
--- a/src/alternativa/engine3d/shadows/DirectionalLightShadow.as
+++ b/src/alternativa/engine3d/shadows/DirectionalLightShadow.as
@@ -43,9 +43,9 @@ package alternativa.engine3d.shadows {
use namespace alternativa3d;
/**
- * Class of shadow, that is created by one source of light(DirectionalLight). Shadow is rendered in fixed volume.
+ * Class of the shadow, that is created by one source of light(DirectionalLight). Shadow is rendered in fixed volume.
* For binding of shadow to light source you need:
- * 1) to set DirectionalLightShadow as a value of property shadow of light source;
+ * 1) to set instance of the DirectionalLightShadow as a value of property shadow of light source;
* 2) to add Object3D to corresponding list, using the method 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 {
_casters.length = 0;
diff --git a/src/alternativa/engine3d/shadows/OmniLightShadow.as b/src/alternativa/engine3d/shadows/OmniLightShadow.as
index 8e0a166..511d5f0 100644
--- a/src/alternativa/engine3d/shadows/OmniLightShadow.as
+++ b/src/alternativa/engine3d/shadows/OmniLightShadow.as
@@ -1,1085 +1,1099 @@
-/**
- * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
- * If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.
- * 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/
- */
-package alternativa.engine3d.shadows {
-
- import alternativa.engine3d.alternativa3d;
- import alternativa.engine3d.core.BoundBox;
- import alternativa.engine3d.core.Camera3D;
- import alternativa.engine3d.core.DrawUnit;
- import alternativa.engine3d.core.Object3D;
- import alternativa.engine3d.core.Renderer;
- import alternativa.engine3d.core.Transform3D;
- import alternativa.engine3d.core.VertexAttributes;
- import alternativa.engine3d.lights.OmniLight;
- import alternativa.engine3d.materials.Material;
- import alternativa.engine3d.materials.ShaderProgram;
- import alternativa.engine3d.materials.TextureMaterial;
- import alternativa.engine3d.materials.compiler.Linker;
- import alternativa.engine3d.materials.compiler.Procedure;
- import alternativa.engine3d.materials.compiler.VariableType;
- import alternativa.engine3d.objects.Joint;
- import alternativa.engine3d.objects.Mesh;
- import alternativa.engine3d.objects.Skin;
- import alternativa.engine3d.objects.Surface;
- import alternativa.engine3d.primitives.GeoSphere;
- import alternativa.engine3d.resources.Geometry;
- import alternativa.engine3d.resources.TextureResource;
-
- import flash.display3D.Context3D;
- import flash.display3D.Context3DProgramType;
- import flash.display3D.Context3DTextureFormat;
- import flash.display3D.Context3DTriangleFace;
- import flash.display3D.VertexBuffer3D;
- import flash.display3D.textures.CubeTexture;
- import flash.utils.Dictionary;
-
- use namespace alternativa3d;
-
- public class OmniLightShadow extends Shadow{
-
- // TODO: calculate bias automaticaly
- /**
- * Degree of correcting offset of shadow map space. It need for getting rid of self-shadowing artifacts.
- */
- public var biasMultiplier:Number = 0.97;
- private static const DIFFERENCE_MULTIPLIER:Number = 32768;
- private static const DEBUG_TYPE:String = "Sphere"; // Box
- /**
- * @private
- */
- alternativa3d static var debugRadiusScale:Number = 0.2;
-
- private var renderer:Renderer = new Renderer();
-
- // radius of the light source
- private var radius:Number = 100;
-
- // cube map size
- private var _mapSize:Number;
-
- private var _pcfOffset:Number;
-
- private var cubeShadowMap:CubeTexture;
-
- // Sides cameras
- private var cameras:Vector. = new Vector.();
-
- private var debugObject:Mesh;
- private var debugMaterial:ShadowDebugMaterial;
-
- private var _casters:Vector. = new Vector.();
-
- private var actualCasters:Vector. = new Vector.();
- private var actualCastersCount:int;
-
- // caster -> cube face
- private var casterToEdgedCameraTransform:Transform3D = new Transform3D();
- // object -> light
- private var objectToLightTransform:Transform3D = new Transform3D();
- // casters count in edge
- private var prevActualCastersMask:int;
-
- private var cachedContext:Context3D;
- private var programs:Dictionary = new Dictionary();
-
- /**
- * Создает экземпляр OmniLightShadow.
- * @param mapSize Размер карты теней. Должен быть степенью 2.
- * @param pcfOffset Смягчение границ тени.
- */
- public function OmniLightShadow(mapSize:int = 128, pcfOffset:Number = 0) {
- sections = new SectionPlane(0x11, 0x22, 0xC); // RU
- sections.next = new SectionPlane(0x12, 0x21, 0xC); // LU
- sections.next.next = new SectionPlane(0x14, 0x28, 0x3); // FU
- sections.next.next.next = new SectionPlane(0x18, 0x24, 0x3); // BU
- sections.next.next.next.next = new SectionPlane(0x5, 0xA, 0x30); // RF
- sections.next.next.next.next.next = new SectionPlane(0x9, 0x6, 0x30); // RB
-
- this.mapSize = mapSize;
- this.pcfOffset = pcfOffset;
-
- vertexShadowProcedure = getVShader();
- type = _pcfOffset > 0 ? Shadow.PCF_MODE : Shadow.SIMPLE_MODE;
- fragmentShadowProcedure = _pcfOffset > 0 ? getFShaderPCF() : getFShader();
-
- debugMaterial = new ShadowDebugMaterial();
- debugMaterial.alpha = 0.3;
-
- for (var i:int = 0; i < 6; i++) {
- var cam:Camera3D = new Camera3D(radius/1000, radius);
- cam.fov = 1.910633237;
- cameras[i] = cam;
- }
-
- // Left
- cameras[1].rotationY = -Math.PI/2;
- cameras[1].scaleY = -1;
- cameras[1].composeTransforms();
- // Right
- cameras[0].rotationY = Math.PI/2;
- cameras[0].scaleY = -1;
- cameras[0].composeTransforms();
- // Back
- cameras[3].rotationX = -Math.PI/2;
- cameras[3].rotationZ = Math.PI;
- cameras[3].scaleX = -1;
- cameras[3].composeTransforms();
- // Front
- cameras[2].rotationX = -Math.PI/2;
- cameras[2].scaleY = -1;
- cameras[2].composeTransforms();
- // Bottom
- cameras[5].rotationX = Math.PI;
- cameras[5].scaleX = -1;
- cameras[5].composeTransforms();
- // Top
- cameras[4].rotationX = 0;
- cameras[4].scaleY = -1;
- cameras[4].composeTransforms();
- }
-
- private function createDebugObject(material:Material, context:Context3D):Mesh{
- var geometry:Geometry;
- var mesh:Mesh;
- if (DEBUG_TYPE == "Box") {
- mesh = new Mesh();
- geometry = new Geometry(8);
- mesh.geometry = geometry;
-
- var attributes:Array = new Array();
- attributes[0] = VertexAttributes.POSITION;
- attributes[1] = VertexAttributes.POSITION;
- attributes[2] = VertexAttributes.POSITION;
- geometry.addVertexStream(attributes);
-
- geometry.setAttributeValues(VertexAttributes.POSITION, Vector.([
- -1, -1, -1,
- 1, -1, -1,
- 1, 1, -1,
- -1, 1, -1,
- -1, -1, 1,
- 1, -1, 1,
- 1, 1, 1,
- -1, 1, 1]));
- geometry.indices = Vector.([
- 0, 1, 2, 3, 0, 2, 2, 1, 0, 3, 2, 0,
- 2, 6, 1, 1, 6, 2, 1, 6, 5, 5, 6, 1,
- 6, 4, 5, 5, 4, 6, 6, 4, 7, 7, 4, 6,
- 0, 7, 4, 4, 7, 0, 0, 7, 3, 3, 7, 0,
- 3, 6, 2, 2, 6, 3, 3, 7, 6, 6, 7, 3,
- 0, 5, 1, 1, 5, 0, 0, 4, 5, 5, 4, 0]);
- mesh.addSurface(material, 0, 24);
- } else {
- mesh = new GeoSphere(1, 4, true);
- // Create two side
- var triangles:Vector. = mesh.geometry.indices;
- var numTriangles:int = triangles.length;
- for (var i:int = 0; i < numTriangles; i += 3) {
- var a:uint = triangles[i];
- var b:uint = triangles[int(i + 1)];
- var c:uint = triangles[int(i + 2)];
- triangles.push(c, b, a);
- }
- mesh.geometry.indices = triangles;
- mesh.getSurface(0).numTriangles = triangles.length/3;
- mesh.setMaterialToAllSurfaces(material);
- }
- mesh.geometry.upload(context);
- return mesh;
- }
-
- // Draw in shadow map
- override alternativa3d function process(camera:Camera3D):void {
- var i:int;
- var j:int;
- var caster:Object3D;
- var context:Context3D = camera.context3D;
-
- // Checking changed context
- if (context != cachedContext) {
- programs = new Dictionary();
- cubeShadowMap = null;
- cachedContext = context;
- }
-
- // Culling invisible casters
- if (cubeShadowMap == null) {
- cubeShadowMap = context.createCubeTexture(_mapSize, Context3DTextureFormat.BGRA, true);
- debugMaterial.cubeMap = cubeShadowMap;
- prevActualCastersMask = 63;
- }
-
- // Calculate parameters
- radius = OmniLight(_light).attenuationEnd;
- for (i = 0; i < 6; i++) {
- var cam:Camera3D = cameras[i];
- cam.nearClipping = radius/1000;
- cam.farClipping = radius;
- cam.calculateProjection(1, 1);
- }
-
- var castersCount:int = _casters.length;
- actualCastersCount = 0;
-
- for (i = 0; i < castersCount; i++) {
- caster = _casters[i];
-
- var visible:Boolean = caster.visible;
- var parent:Object3D = caster._parent;
- while (visible && parent != null) {
- visible = parent.visible;
- parent = parent._parent;
- }
-
- if (visible) {
- // calculate transform matrices
- _light.lightToObjectTransform.combine(caster.cameraToLocalTransform, _light.localToCameraTransform);
- caster.localToLightTransform.combine(_light.cameraToLocalTransform, caster.localToCameraTransform);
-
- // collect actualCasters for light
- if (caster.boundBox == null || OmniLight(_light).checkBound(caster)){
- actualCasters[actualCastersCount] = caster;
- actualCastersCount++;
-
- // Pack camera culling
- caster.culling <<= 16;
- if (caster.boundBox != null) {
- // 1 - calculate planes in object space
- calculatePlanes(caster.localToLightTransform);
- // 2 - check object location cameras (sections)
- caster.culling |= recognizeObjectCameras(caster.boundBox);
- }
- }
-
- // update Skin Joints matrices
- var skin:Skin = caster as Skin;
- if (skin != null) {
- // Calculate joints matrices
- for (var child:Object3D = skin.childrenList; child != null; child = child.next) {
- if (child.transformChanged) child.composeTransforms();
- // Write transformToSkin matrix to localToGlobalTransform property
- child.localToGlobalTransform.copy(child.transform);
- if (child is Joint) {
- Joint(child).calculateTransform();
- }
- skin.calculateJointsTransforms(child);
- }
- }
-
- if (caster.childrenList != null) collectActualChildren(caster);
- }
- }
-
- // Iterate through six cameras
- for (i = 0; i < 6; i++) {
- // Cube side camera
- var edgeCamera:Camera3D = cameras[i];
-
- var edgeBit:int = (1< 0) {
- // Настройка параметров рендеринга:
- renderer.camera = camera;
- context.setRenderToTexture(cubeShadowMap, true, 0, i);
- context.clear(1, 0, 0, 0.0);
-
- // Пробегаемся по кастерам
- for (j = 0; j < actualCastersCount; j++) {
- caster = actualCasters[j];
-
- // Проверить находится ли кастер в зоне 4-х плоскостей
- if ((caster.culling & edgeBit)) {
- // собираем матрицу перевода из кастера в пространство edgeCamera
- casterToEdgedCameraTransform.combine(edgeCamera.inverseTransform, caster.localToLightTransform);
- // Собираем драуколлы для кастера и его дочерних объектов
- collectDraws(context, caster, edgeCamera);
- }
- }
-
-// if (renderer.drawUnits.length == 0) context.clear(0, 0, 0, 0.0);
-
- // Drawing
- renderer.render(context);
- prevActualCastersMask |= edgeBit;
- }
- else{
- // Если относительно одной из камер ничего не менялось, не вызываем отрисовочный вызов
-
- if ((prevActualCastersMask & edgeBit)){
- context.setRenderToTexture(cubeShadowMap, false, 0, i);
- context.clear(1, 0, 0, 0);
-
- prevActualCastersMask &= ~edgeBit;
- }
- }
- }
- context.setRenderToBackBuffer();
-
- // Unpack camera culling value
- for (j = 0; j < actualCastersCount; j++) {
- caster = actualCasters[j];
- // If there was -1, after shift it will be -1 too
- caster.culling >>= 16;
- }
-
- if (debug) {
- // Create debug object if needed
- if (debugObject == null) {
- debugObject = createDebugObject(debugMaterial, camera.context3D);
- }
- debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius*debugRadiusScale;
- debugObject.composeTransforms();
-
- // Формируем матрицу трансформации для debugObject
- debugObject.localToCameraTransform.combine(_light.localToCameraTransform, debugObject.transform);
-
- // Отрисовываем
- var debugSurface:Surface = debugObject._surfaces[0];
- debugMaterial.collectDraws(camera, debugSurface, debugObject.geometry, null, 0, false, -1);
- }
- actualCasters.length = 0;
- }
-
- private function collectActualChildren(root:Object3D):void{
- for (var child:Object3D = root.childrenList; child != null; child = child.next) {
- if (child.visible){
- // calculate transform matrices
- _light.lightToObjectTransform.combine(child.cameraToLocalTransform, _light.localToCameraTransform);
- child.localToLightTransform.combine(_light.cameraToLocalTransform, child.localToCameraTransform);
-
- // collect actualCasters for light
- if (child.boundBox == null || OmniLight(_light).checkBound(child)){
- actualCasters[actualCastersCount] = child;
- actualCastersCount++;
-
- // Pack camera culling
- child.culling <<= 16;
- if (child.boundBox != null) {
- // 1 - calculate planes in object space
- calculatePlanes(child.localToLightTransform);
- // 2 - check object location cameras (sections)
- child.culling |= recognizeObjectCameras(child.boundBox);
- }
- }
-
- // update Skin Joints matrices
- var skin:Skin = child as Skin;
- if (skin != null) {
- // Calculate joints matrices
- for (var skinChild:Object3D = skin.childrenList; skinChild != null; skinChild = skinChild.next) {
- if (skinChild.transformChanged) skinChild.composeTransforms();
- // Write transformToSkin matrix to localToGlobalTransform property
- skinChild.localToGlobalTransform.copy(skinChild.transform);
- if (skinChild is Joint) {
- Joint(skinChild).calculateTransform();
- }
- skin.calculateJointsTransforms(skinChild);
- }
- }
-
- if (child.childrenList != null) collectActualChildren(child);
- }
- }
- }
-
- private var sections:SectionPlane;
-
- private function calculatePlanes(transform:Transform3D):void {
- // DUBFLR
- var planeRU:SectionPlane = sections;
- var planeLU:SectionPlane = sections.next;
- var planeFU:SectionPlane = sections.next.next;
- var planeBU:SectionPlane = sections.next.next.next;
- var planeRF:SectionPlane = sections.next.next.next.next;
- var planeRB:SectionPlane = sections.next.next.next.next.next;
-
- // 1, 0, 1
- planeRU.x = transform.a + transform.i;
- planeRU.y = transform.b + transform.j;
- planeRU.z = transform.c + transform.k;
- planeRU.offset = -(transform.d + transform.l);
-
- // -1, 0, 1
- planeLU.x = transform.i - transform.a;
- planeLU.y = transform.j - transform.b;
- planeLU.z = transform.k - transform.c;
- planeLU.offset = transform.d - transform.l;
-
- // 0, 1, 1
- planeFU.x = transform.e + transform.i;
- planeFU.y = transform.f + transform.j;
- planeFU.z = transform.g + transform.k;
- planeFU.offset = -(transform.h + transform.l);
-
- // 0, -1, 1
- planeBU.x = transform.i - transform.e;
- planeBU.y = transform.j - transform.f;
- planeBU.z = transform.k - transform.g;
- planeBU.offset = transform.h - transform.l;
-
- // 1, 1, 0
- planeRF.x = transform.a + transform.e;
- planeRF.y = transform.b + transform.f;
- planeRF.z = transform.c + transform.g;
- planeRF.offset = -(transform.d + transform.h);
-
- // 1, -1, 0
- planeRB.x = transform.a - transform.e;
- planeRB.y = transform.b - transform.f;
- planeRB.z = transform.c - transform.g;
- planeRB.offset = transform.h - transform.d;
-
- // var ax:Number = transform.c - transform.a + transform.b; // E
-// var ay:Number = transform.g - transform.e + transform.f;
-// var az:Number = transform.k - transform.i + transform.j;
-// var bx:Number = transform.c - transform.a - transform.b; // H
-// var by:Number = transform.g - transform.e - transform.f;
-// var bz:Number = transform.k - transform.i - transform.j;
-// planeRU.x = bz * ay - by * az;
-// planeRU.y = bx * az - bz * ax;
-// planeRU.z = by * ax - bx * ay;
-// planeRU.offset = transform.d*planeRU.x + transform.h*planeRU.y + transform.l*planeRU.z;
-//
-// ax = transform.c + transform.a - transform.b; // D
-// ay = transform.g + transform.e - transform.f;
-// az = transform.k + transform.i - transform.j;
-// bx = transform.c + transform.a + transform.b; // A
-// by = transform.g + transform.e + transform.f;
-// bz = transform.k + transform.i + transform.j;
-// planeLU.x = bz * ay - by * az;
-// planeLU.y = bx * az - bz * ax;
-// planeLU.z = by * ax - bx * ay;
-// planeLU.offset = transform.d*planeLU.x + transform.h*planeLU.y + transform.l*planeLU.z;
-//
-// ax = transform.c - transform.a - transform.b; // H
-// ay = transform.g - transform.e - transform.f;
-// az = transform.k - transform.i - transform.j;
-// bx = transform.c + transform.a - transform.b; // D
-// by = transform.g + transform.e - transform.f;
-// bz = transform.k + transform.i - transform.j;
-// planeFU.x = bz * ay - by * az;
-// planeFU.y = bx * az - bz * ax;
-// planeFU.z = by * ax - bx * ay;
-// planeFU.offset = transform.d*planeFU.x + transform.h*planeFU.y + transform.l*planeFU.z;
-//
-// ax = transform.c + transform.a + transform.b; // A
-// ay = transform.g + transform.e + transform.f;
-// az = transform.k + transform.i + transform.j;
-// bx = transform.c - transform.a + transform.b; // E
-// by = transform.g - transform.e + transform.f;
-// bz = transform.k - transform.i + transform.j;
-// planeBU.x = bz * ay - by * az;
-// planeBU.y = bx * az - bz * ax;
-// planeBU.z = by * ax - bx * ay;
-// planeBU.offset = transform.d*planeBU.x + transform.h*planeBU.y + transform.l*planeBU.z;
-//
-// ax = transform.a - transform.b + transform.c; // D
-// ay = transform.e - transform.f + transform.g;
-// az = transform.i - transform.j + transform.k;
-// bx = transform.a - transform.b - transform.c; // C
-// by = transform.e - transform.f - transform.g;
-// bz = transform.i - transform.j - transform.k;
-// planeRF.x = bz * ay - by * az;
-// planeRF.y = bx * az - bz * ax;
-// planeRF.z = by * ax - bx * ay;
-// planeRF.offset = transform.d*planeRF.x + transform.h*planeRF.y + transform.l*planeRF.z;
-//
-// ax = transform.a + transform.b - transform.c; // B
-// ay = transform.e + transform.f - transform.g;
-// az = transform.i + transform.j - transform.k;
-// bx = transform.a + transform.b + transform.c; // A
-// by = transform.e + transform.f + transform.g;
-// bz = transform.i + transform.j + transform.k;
-// planeRB.x = bz * ay - by * az;
-// planeRB.y = bx * az - bz * ax;
-// planeRB.z = by * ax - bx * ay;
-// planeRB.offset = transform.d*planeRB.x + transform.h*planeRB.y + transform.l*planeRB.z;
- }
-
- private function recognizeObjectCameras(bb:BoundBox):int {
- var culling:int = 63;
- for (var plane:SectionPlane = sections; plane != null; plane = plane.next) {
- var result:int = 0;
-
- if (plane.x >= 0)
- if (plane.y >= 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.minX*plane.x + bb.minY*plane.y + bb.minZ*plane.z < plane.offset) result |= plane.backCameras;
- } else {
- 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;
- }
- 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)
- if (plane.z >= 0) {
- 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;
- } else {
- 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;
- }
- 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.maxX*plane.x + bb.maxY*plane.y + bb.minZ*plane.z < plane.offset) result |= plane.backCameras;
- } else {
- 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;
- }
- culling &= result | plane.unusedBits;
- }
- return culling;
- }
-
- private function collectDraws(context:Context3D, caster:Object3D, edgeCamera:Camera3D):void{
- // если объект является мешем, собираем для него дроуколы
- var mesh:Mesh = caster as Mesh;
- if (mesh != null && mesh.geometry != null) {
- var program:ShaderProgram;
- var programListByTransformProcedure:Vector.;
- var skin:Skin = mesh as Skin;
-
- // пробегаемся по сурфейсам
- for (var i:int = 0; i < mesh._surfacesLength; i++) {
- var surface:Surface = mesh._surfaces[i];
- if (surface.material == null) continue;
-
- var material:Material = surface.material;
- var geometry:Geometry = mesh.geometry;
- var alphaTest:Boolean;
- var useDiffuseAlpha:Boolean;
- var alphaThreshold:Number;
- var materialAlpha:Number;
- var diffuse:TextureResource;
- var opacity:TextureResource;
- var uvBuffer:VertexBuffer3D;
-
- // ловим параметры прозрачности
- if (material is TextureMaterial) {
- alphaThreshold = TextureMaterial(material).alphaThreshold;
- materialAlpha = TextureMaterial(material).alpha;
- diffuse = TextureMaterial(material).diffuseMap;
- opacity = TextureMaterial(material).opacityMap;
- alphaTest = alphaThreshold > 0;
- useDiffuseAlpha = TextureMaterial(material).opacityMap == null;
- uvBuffer = geometry.getVertexBuffer(VertexAttributes.TEXCOORDS[0]);
- if (uvBuffer == null) continue;
- } else {
- alphaTest = false;
- useDiffuseAlpha = false;
- }
-
-
- var positionBuffer:VertexBuffer3D = mesh.geometry.getVertexBuffer(VertexAttributes.POSITION);
- if (positionBuffer == null) continue;
-
- // поднимаем и кэшируем programListByTransformProcedure
- if (skin != null) {
- caster.transformProcedure = skin.surfaceTransformProcedures[i];
- }
- programListByTransformProcedure = programs[caster.transformProcedure];
- if (programListByTransformProcedure == null) {
- programListByTransformProcedure = new Vector.(3, true);
- programs[caster.transformProcedure] = programListByTransformProcedure;
- }
-
- // собираем программу и Формируем дроуюнит
- program = getProgram(caster.transformProcedure, programListByTransformProcedure, context, alphaTest, useDiffuseAlpha);
- var drawUnit:DrawUnit = renderer.createDrawUnit(caster, program.program, mesh.geometry._indexBuffer, surface.indexBegin, surface.numTriangles, program);
- drawUnit.culling = Context3DTriangleFace.BACK;
-
- // Установка стрима
- drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aPosition"), positionBuffer, mesh.geometry._attributesOffsets[VertexAttributes.POSITION], VertexAttributes.FORMATS[VertexAttributes.POSITION]);
-
- if (alphaTest) {
- drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aUV"), uvBuffer, geometry._attributesOffsets[VertexAttributes.TEXCOORDS[0]], VertexAttributes.FORMATS[VertexAttributes.TEXCOORDS[0]]);
- drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cThresholdAlpha"), alphaThreshold, 0, 0, materialAlpha);
- if (useDiffuseAlpha) {
- drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sTexture"), diffuse._texture);
- } else {
- drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sTexture"), opacity._texture);
- }
- }
-
- // Установка констант
- caster.setTransformConstants(drawUnit, surface, program.vertexShader, null);
- drawUnit.setProjectionConstants(edgeCamera, program.vertexShader.getVariableIndex("cProjMatrix"), casterToEdgedCameraTransform);
- drawUnit.setVertexConstantsFromTransform(program.vertexShader.getVariableIndex("cCasterToOmni"), caster.localToLightTransform);
-
- drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cConstants"), 1 / 255, 0, 255/radius, 1);
-
- renderer.addDrawUnit(drawUnit, Renderer.OPAQUE);
- }
- }
- }
-
- /**
- * @private
- * Процедура для передачи UV координат во фрагментный шейдер
- */
- static private const passUVProcedure:Procedure = new Procedure(["#v0=vUV", "#a0=aUV", "mov v0, a0"], "passUVProcedure");
-
- // diffuse alpha test
- private static const diffuseAlphaTestProcedure:Procedure = new Procedure([
- "#v0=vUV",
- "#s0=sTexture",
- "#c0=cThresholdAlpha",
- "tex t0, v0, s0 <2d, linear,repeat, miplinear>",
- "mul t0.w, t0.w, c0.w",
- "sub t0.w, t0.w, c0.x",
- "kil t0.w"
- ], "diffuseAlphaTestProcedure");
-
- // opacity alpha test
- private static const opacityAlphaTestProcedure:Procedure = new Procedure([
- "#v0=vUV",
- "#s0=sTexture",
- "#c0=cThresholdAlpha",
- "tex t0, v0, s0 <2d, linear,repeat, miplinear>",
- "mul t0.w, t0.x, c0.w",
- "sub t0.w, t0.w, c0.x",
- "kil t0.w"
- ], "opacityAlphaTestProcedure");
-
-
- private function getProgram(transformProcedure:Procedure, programListByTransformProcedure:Vector., context:Context3D, alphaTest:Boolean, useDiffuseAlpha:Boolean):ShaderProgram {
- var key:int = (alphaTest ? (useDiffuseAlpha ? 1 : 2) : 0);
- var program:ShaderProgram = programListByTransformProcedure[key];
-
- if (program == null) {
- var vLinker:Linker = new Linker(Context3DProgramType.VERTEX);
- var fLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
-
- var positionVar:String = "aPosition";
- vLinker.declareVariable(positionVar, VariableType.ATTRIBUTE);
-
- if (alphaTest) {
- vLinker.addProcedure(passUVProcedure);
- }
-
- if (transformProcedure != null) {
- var newPosVar:String = "tTransformedPosition";
- vLinker.declareVariable(newPosVar);
- vLinker.addProcedure(transformProcedure, positionVar);
- vLinker.setOutputParams(transformProcedure, newPosVar);
- positionVar = newPosVar;
- }
-
- var proc:Procedure = Procedure.compileFromArray([
- "#v0=vDistance",
-
- "m34 t0.xyz, i0, c2",
- "mov v0, t0.xyzx",
-
- "m44 o0, i0, c0"
- ]);
- proc.assignVariableName(VariableType.CONSTANT, 0, "cProjMatrix", 4);
- proc.assignVariableName(VariableType.CONSTANT, 2, "cCasterToOmni", 3);
-
- vLinker.addProcedure(proc, positionVar);
-
- if (alphaTest) {
- if (useDiffuseAlpha) {
- fLinker.addProcedure(diffuseAlphaTestProcedure);
- } else {
- fLinker.addProcedure(opacityAlphaTestProcedure);
- }
- }
- fLinker.addProcedure(Procedure.compileFromArray([
- "#v0=vDistance", // xyz
- "#c0=cConstants", // 1/255, 0, 255/radius, 1
- // calculate distance
- "dp3 t0.z, v0.xyz, v0.xyz",
- "sqt t0.z, t0.z", // x: [0, radius]
- "mul t0.z, t0.z, c0.z", // x: [0, 255]
- // codeing
- "frc t0.y, t0.z",
- "sub t0.x, t0.z, t0.y",
- "mul t0.x, t0.x, c0.x",
-
- "mov t0.w, c0.w",
- "mov o0, t0"
- ]));
- program = new ShaderProgram(vLinker, fLinker);
- fLinker.varyings = vLinker.varyings;
- programListByTransformProcedure[key] = program;
- program.upload(context);
-
- }
- return program;
- }
-
-
-
- //------------- ShadowMap Shader in material----------
-
- /**
- * @private
- */
- alternativa3d override function setup(drawUnit:DrawUnit, vertexLinker:Linker, fragmentLinker:Linker, surface:Surface):void {
- // Устанавливаем матрицу перевода в шедоумапу
- objectToLightTransform.combine(_light.cameraToLocalTransform, surface.object.localToCameraTransform);
- drawUnit.setVertexConstantsFromTransform(vertexLinker.getVariableIndex("cObjectToLightTransform"), objectToLightTransform);
-
- // Устанавливаем шедоумапу
- drawUnit.setTextureAt(fragmentLinker.getVariableIndex("sCubeMap"), cubeShadowMap);
-
- // Устанавливаем коеффициенты
- if (_pcfOffset > 0) {
- 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("cConstants"), -1, 1, 0, offset);
- drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cDecode"), -DIFFERENCE_MULTIPLIER, -DIFFERENCE_MULTIPLIER/255, biasMultiplier*DIFFERENCE_MULTIPLIER/radius, 10);
- } else {
- drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -DIFFERENCE_MULTIPLIER, -DIFFERENCE_MULTIPLIER/255, biasMultiplier*DIFFERENCE_MULTIPLIER/radius, 1.0);
- }
- }
-
- private static function getVShader():Procedure {
- var shader:Procedure = Procedure.compileFromArray([
- "#v0=vSample",
-
- "m34 t0.xyz, i0, c0",
-
- "mov v0, t0.xyz"
- ], "OmniShadowMapVertex");
- shader.assignVariableName(VariableType.CONSTANT, 0, "cObjectToLightTransform", 3);
- return shader;
- }
-
- private static function getFShader():Procedure {
- var shaderArr:Array = [
- "#v0=vSample",
- "#c0=cConstants",
- "#s0=sCubeMap"
- ];
- var line:int = 3;
- // Расстояние
- shaderArr[line++] = "dp3 t0.z, v0.xyz, v0.xyz";
- shaderArr[line++] = "sqt t0.z, t0.z"; // w: [0, radius]
- shaderArr[line++] = "tex t0.xy, v0, s0 ";
- shaderArr[line++] = "dp3 t0.x, t0.xyz, c0.xyz"; // декодируем, находим разницу между расстояниями и умножаем ее на большое число
-
- // рассчитываем значение тени
- shaderArr[line++] = "sat t0.x, t0.x";
- shaderArr[line++] = "sub o0, c0.w, t0.x";
-
-// shaderArr[line++] = "sat t0.x, t0.x";
-// shaderArr[line++] = "sub t0.x, c0.w, t0.x";
-// shaderArr[line++] = "sat t0.x, t0.x";
-// shaderArr[line++] = "mov o0, t0.x";
-
- return Procedure.compileFromArray(shaderArr, "OmniShadowMapFragment");
- }
-
- private static function getFShaderPCF():Procedure {
- var shaderArr:Array = [
- "#v0=vSample",
- "#c0=cDecode",
- "#c1=cConstants",
- "#c2=cPCFOffsets",
- "#s0=sCubeMap"
- ];
- var line:int = 5;
- var i:int;
- var j:int;
-
- // допустимо использование временных переменных t0 t1 t2 t3
- // v0 - sample
-
- // calculate 2 ortogonal vectors
- // (-y, x, 0)
- shaderArr[line++] = "mov t1.xyzw, v0.yxzw";
- shaderArr[line++] = "mul t1.xyzw, t1.xyzw, c1.xyzz";
-
- shaderArr[line++] = "crs t0.xyz, v0.xyz, t1.xyz";
-
- // normalize vectors
- shaderArr[line++] = "nrm t0.xyz, t0.xyz";
- shaderArr[line++] = "nrm t1.xyz, t1.xyz";
-
- shaderArr[line++] = "dp3 t3.z, v0.xyz, v0.xyz";
- shaderArr[line++] = "sqt t3.z, t3.z"; // distance
-
- // apply pcf offset
- shaderArr[line++] = "mul t0.w, c1.w, t3.z"; // с1.w = offset/radius
- shaderArr[line++] = "mul t0.xyz, t0.xyz, t0.w";
- shaderArr[line++] = "mul t1.xyz, t1.xyz, t0.w";
- // --------- {13 opcode}
-
- // t0, t1 - ortogonals ↑→
- // t2 - current vector
-
- // t3.z distance to object
- // t3.xy - result from shadow map
- // t3.w - summ of sat
-
- // first point
- shaderArr[line++] = "add t2.xyz, t0.xyz, t1.xyz";
- shaderArr[line++] = "mul t2.xyz, t2.xyz, c2.xxx";
- shaderArr[line++] = "add t2.xyz, t2.xyz, v0.xyz";
-
- // получаем длинну из шадоумапы [0, 1]
-// shaderArr[line++] = "mov t3.z, t0.w";
-
- shaderArr[line++] = "tex t3.xy, t2.xyz, s0 ";
- shaderArr[line++] = "dp3 o0." +componentByIndex[0] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
-
- //-----
-
- for (j = 1; j < 4; j++) {
- shaderArr[line++] = "add t2.xyz, t2.xyz, t1.xyz";
-
- shaderArr[line++] = "tex t3.xy, t2.xyz, s0 ";
- shaderArr[line++] = "dp3 o0." +componentByIndex[j] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
- }
-
- shaderArr[line++] = "sat o0, o0";
- shaderArr[line++] = "dp4 t3.w, o0, c2.y";
-
- //-----
-
- for (i = 0; i < 3; i++) {
- shaderArr[line++] = "add t2.xyz, t2.xyz, t0.xyz";
-
- shaderArr[line++] = "tex t3.xy, t2.xyz, s0 ";
- shaderArr[line++] = "dp3 o0." +componentByIndex[0] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
-
- 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++] = "tex t3.xy, t2.xyz, s0 ";
- shaderArr[line++] = "dp3 o0." +componentByIndex[j] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
- }
- shaderArr[line++] = "sat o0, o0";
- shaderArr[line++] = "dp4 o0.x, o0, c2.y";
- shaderArr[line++] = "add t3.w, t3.w, o0.x";
- }
-
- shaderArr[line++] = "sub o0, c1.y, t3.w";
-
- //--------- {73 opcodes}
- return Procedure.compileFromArray(shaderArr, "OmniShadowMapFragment");
- }
-
- private static const componentByIndex:Array = ["x", "y", "z", "w"];
-
- /**
- * Добавляет object в список объектов, отбрасывающих тень.
- * @param object Добавляемый объект.
- */
- public function addCaster(object:Object3D):void {
- if (_casters.indexOf(object) < 0) {
- _casters.push(object);
- }
- }
-
- public function removeCaster(object:Object3D):void {
- var index:int = _casters.indexOf(object);
- if (index < 0) throw new Error("Caster not found");
- _casters[index] = _casters.pop();
- }
-
- /**
- * Очищает список объектов, отбрасывающих тень.
- */
- public function clearCasters():void {
- _casters.length = 0;
- }
-
- /**
- * Качество тени. Задает разрешение shadowmap. Может принимать значения от 2 до 11.
- */
- public function get mapSize():int {
- return _mapSize;
- }
-
- /**
- * @private
- */
- public function set mapSize(value:int):void {
- if (value != _mapSize) {
- this._mapSize = value;
- if (value < 2) {
- throw new ArgumentError("Map size cannot be less than 2.");
- } else if (value > 1024) {
- throw new ArgumentError("Map size exceeds maximum value 1024.");
- }
- if ((Math.log(value)/Math.LN2 % 1) != 0) {
- throw new ArgumentError("Map size must be power of two.");
- }
- if (cubeShadowMap != null) {
- cubeShadowMap.dispose();
- }
- cubeShadowMap = null;
- }
- }
-
- /**
- * Смещение Percentage Closer Filtering. Этот способ фильтрации используется для смягчения границ тени.
- * 1 pcfOffset equivalent 1 degree for all blur
- */
- public function get pcfOffset():Number {
- return _pcfOffset;
- }
-
- /**
- * @private
- */
- public function set pcfOffset(value:Number):void {
- _pcfOffset = value;
- type = _pcfOffset > 0 ? Shadow.PCF_MODE : Shadow.SIMPLE_MODE;
- fragmentShadowProcedure = _pcfOffset > 0 ? getFShaderPCF() : getFShader();
- }
-
- }
-}
-
-import alternativa.engine3d.alternativa3d;
-import alternativa.engine3d.core.Camera3D;
-import alternativa.engine3d.core.DrawUnit;
-import alternativa.engine3d.core.Light3D;
-import alternativa.engine3d.core.Object3D;
-import alternativa.engine3d.core.Renderer;
-import alternativa.engine3d.core.VertexAttributes;
-import alternativa.engine3d.materials.Material;
-import alternativa.engine3d.materials.ShaderProgram;
-import alternativa.engine3d.materials.compiler.Linker;
-import alternativa.engine3d.materials.compiler.Procedure;
-import alternativa.engine3d.materials.compiler.VariableType;
-import alternativa.engine3d.objects.Surface;
-import alternativa.engine3d.resources.Geometry;
-
-import flash.display3D.Context3D;
-import flash.display3D.Context3DBlendFactor;
-import flash.display3D.Context3DProgramType;
-import flash.display3D.VertexBuffer3D;
-import flash.display3D.textures.CubeTexture;
-import flash.utils.Dictionary;
-
-class ShadowDebugMaterial extends Material {
-
- use namespace alternativa3d;
- /**
- * Прозрачность.
- * Является дополнительным множителем к прозрачности текстуры.
- * Значение по умолчанию 1.
- */
- alternativa3d var alpha:Number = 1;
-
- private var cachedContext3D:Context3D;
- private static var caches:Dictionary = new Dictionary(true);
- private var program:ShaderProgram;
-
- /**
- * Текстура.
- */
- alternativa3d var cubeMap:CubeTexture;
-
- /**
- * @private
- */
- override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector., lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void {
- var object:Object3D = surface.object;
- // Стримы
- var positionBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.POSITION);
- // Проверка на валидность
- if (positionBuffer == null) return;
-
- // Обновляем кеш программы для данного контекста
- if (camera.context3D != cachedContext3D) {
- cachedContext3D = camera.context3D;
- program = caches[cachedContext3D];
- }
-
- if (program == null) {
- program = setupProgram(object);
- program.upload(camera.context3D);
- caches[cachedContext3D] = program;
- }
-
- // Создание отрисовочного вызова
- var drawUnit:DrawUnit = camera.renderer.createDrawUnit(object, program.program, geometry._indexBuffer, surface.indexBegin, surface.numTriangles, program);
- // Установка стримов
- 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.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cDecode"), 1, 1/255, 0, alpha);
- drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sCubeMap"), cubeMap);
-
- // Отправка на отрисовку
- if (alpha < 1) {
- drawUnit.blendSource = Context3DBlendFactor.SOURCE_ALPHA;
- drawUnit.blendDestination = Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA;
- camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.TRANSPARENT_SORT);
- } else {
- camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.OPAQUE);
- }
- }
-
- private function copyDrawUnit(source:DrawUnit, dest:DrawUnit):void {
-
- }
-
- private function setupProgram(object:Object3D):ShaderProgram {
- var vertexLinker:Linker = new Linker(Context3DProgramType.VERTEX);
- var positionVar:String = "aPosition";
- vertexLinker.declareVariable(positionVar, VariableType.ATTRIBUTE);
-
- var proc:Procedure = Procedure.compileFromArray([
- "#v0=vCubeMapCoord",
- "mov v0, i0",
- "m44 o0, i0, c0"
- ]);
- proc.assignVariableName(VariableType.CONSTANT, 0, "cProjMatrix", 4);
- vertexLinker.addProcedure(proc, positionVar);
-
- var fragmentLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
- var colorProc:Procedure = Procedure.compileFromArray([
- "#v0=vCubeMapCoord",
- "#s0=sCubeMap",
- "#c0=cDecode",
-
- "tex t0.xy, v0, s0 ",
- "dp3 t0.xyz, t0.xy, c0.xy",
- "mov t0.w, c0.w",
- "mov o0, t0"
- ]);
- fragmentLinker.addProcedure(colorProc, "vCubeMapCoord");
- fragmentLinker.varyings = vertexLinker.varyings;
- return new ShaderProgram(vertexLinker, fragmentLinker);
- }
-
-}
-
-class SectionPlane {
-
- public var x:Number = 0;
- public var y:Number = 0;
- public var z:Number = 0;
- public var offset:Number = 0;
-
- public var next:SectionPlane;
-
- public var frontCameras:int;
- public var backCameras:int;
- public var unusedBits:int = 63;
-
- public function SectionPlane(frontCameras:int, backCameras:int, unused:int) {
- this.frontCameras = frontCameras;
- this.backCameras = backCameras;
- this.unusedBits = unused;
- }
-
-}
+/**
+ * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ * If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.
+ * 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/
+ */
+package alternativa.engine3d.shadows {
+
+ import alternativa.engine3d.alternativa3d;
+ import alternativa.engine3d.core.BoundBox;
+ import alternativa.engine3d.core.Camera3D;
+ import alternativa.engine3d.core.DrawUnit;
+ import alternativa.engine3d.core.Object3D;
+ import alternativa.engine3d.core.Renderer;
+ import alternativa.engine3d.core.Transform3D;
+ import alternativa.engine3d.core.VertexAttributes;
+ import alternativa.engine3d.lights.OmniLight;
+ import alternativa.engine3d.materials.Material;
+ import alternativa.engine3d.materials.ShaderProgram;
+ import alternativa.engine3d.materials.TextureMaterial;
+ import alternativa.engine3d.materials.compiler.Linker;
+ import alternativa.engine3d.materials.compiler.Procedure;
+ import alternativa.engine3d.materials.compiler.VariableType;
+ import alternativa.engine3d.objects.Joint;
+ import alternativa.engine3d.objects.Mesh;
+ import alternativa.engine3d.objects.Skin;
+ import alternativa.engine3d.objects.Surface;
+ import alternativa.engine3d.primitives.GeoSphere;
+ import alternativa.engine3d.resources.Geometry;
+ import alternativa.engine3d.resources.TextureResource;
+
+ import flash.display3D.Context3D;
+ import flash.display3D.Context3DProgramType;
+ import flash.display3D.Context3DTextureFormat;
+ import flash.display3D.Context3DTriangleFace;
+ import flash.display3D.VertexBuffer3D;
+ import flash.display3D.textures.CubeTexture;
+ import flash.utils.Dictionary;
+
+ use namespace alternativa3d;
+
+ /**
+ * Class of the shadow, that is created by one source of light(OmniLight). Shadow is rendered in fixed volume.
+ * For binding of shadow to light source you need:
+ * 1) to set instance of the OmniLight as a value of property shadow of light source;
+ * 2) to add Object3D to corresponding list, using the method addCaster().
+ *
+ * @see #addCaster()
+ * @see alternativa.engine3d.lights.OmniLight#shadow
+ * @see #farBoundPosition
+ */
+
+ public class OmniLightShadow extends Shadow {
+
+ // TODO: calculate bias automaticaly
+ /**
+ * Degree of correcting offset of shadow map space. It need for getting rid of self-shadowing artifacts.
+ */
+ public var biasMultiplier:Number = 0.97;
+ private static const DIFFERENCE_MULTIPLIER:Number = 32768;
+ private static const DEBUG_TYPE:String = "Sphere"; // Box
+ /**
+ * @private
+ */
+ alternativa3d static var debugRadiusScale:Number = 0.2;
+
+ private var renderer:Renderer = new Renderer();
+
+ // radius of the light source
+ private var radius:Number = 100;
+
+ // cube map size
+ private var _mapSize:Number;
+
+ private var _pcfOffset:Number;
+
+ private var cubeShadowMap:CubeTexture;
+
+ // Sides cameras
+ private var cameras:Vector. = new Vector.();
+
+ private var debugObject:Mesh;
+ private var debugMaterial:ShadowDebugMaterial;
+
+ private var _casters:Vector. = new Vector.();
+
+ private var actualCasters:Vector. = new Vector.();
+ private var actualCastersCount:int;
+
+ // caster -> cube face
+ private var casterToEdgedCameraTransform:Transform3D = new Transform3D();
+ // object -> light
+ private var objectToLightTransform:Transform3D = new Transform3D();
+ // casters count in edge
+ private var prevActualCastersMask:int;
+
+ private var cachedContext:Context3D;
+ private var programs:Dictionary = new Dictionary();
+
+ /**
+ * Создает экземпляр OmniLightShadow.
+ * @param mapSize Размер карты теней. Должен быть степенью 2.
+ * @param pcfOffset Смягчение границ тени.
+ */
+ public function OmniLightShadow(mapSize:int = 128, pcfOffset:Number = 0) {
+ sections = new SectionPlane(0x11, 0x22, 0xC); // RU
+ sections.next = new SectionPlane(0x12, 0x21, 0xC); // LU
+ sections.next.next = new SectionPlane(0x14, 0x28, 0x3); // FU
+ sections.next.next.next = new SectionPlane(0x18, 0x24, 0x3); // BU
+ sections.next.next.next.next = new SectionPlane(0x5, 0xA, 0x30); // RF
+ sections.next.next.next.next.next = new SectionPlane(0x9, 0x6, 0x30); // RB
+
+ this.mapSize = mapSize;
+ this.pcfOffset = pcfOffset;
+
+ vertexShadowProcedure = getVShader();
+ type = _pcfOffset > 0 ? Shadow.PCF_MODE : Shadow.SIMPLE_MODE;
+ fragmentShadowProcedure = _pcfOffset > 0 ? getFShaderPCF() : getFShader();
+
+ debugMaterial = new ShadowDebugMaterial();
+ debugMaterial.alpha = 0.3;
+
+ for (var i:int = 0; i < 6; i++) {
+ var cam:Camera3D = new Camera3D(radius / 1000, radius);
+ cam.fov = 1.910633237;
+ cameras[i] = cam;
+ }
+
+ // Left
+ cameras[1].rotationY = -Math.PI / 2;
+ cameras[1].scaleY = -1;
+ cameras[1].composeTransforms();
+ // Right
+ cameras[0].rotationY = Math.PI / 2;
+ cameras[0].scaleY = -1;
+ cameras[0].composeTransforms();
+ // Back
+ cameras[3].rotationX = -Math.PI / 2;
+ cameras[3].rotationZ = Math.PI;
+ cameras[3].scaleX = -1;
+ cameras[3].composeTransforms();
+ // Front
+ cameras[2].rotationX = -Math.PI / 2;
+ cameras[2].scaleY = -1;
+ cameras[2].composeTransforms();
+ // Bottom
+ cameras[5].rotationX = Math.PI;
+ cameras[5].scaleX = -1;
+ cameras[5].composeTransforms();
+ // Top
+ cameras[4].rotationX = 0;
+ cameras[4].scaleY = -1;
+ cameras[4].composeTransforms();
+ }
+
+ private function createDebugObject(material:Material, context:Context3D):Mesh {
+ var geometry:Geometry;
+ var mesh:Mesh;
+ if (DEBUG_TYPE == "Box") {
+ mesh = new Mesh();
+ geometry = new Geometry(8);
+ mesh.geometry = geometry;
+
+ var attributes:Array = new Array();
+ attributes[0] = VertexAttributes.POSITION;
+ attributes[1] = VertexAttributes.POSITION;
+ attributes[2] = VertexAttributes.POSITION;
+ geometry.addVertexStream(attributes);
+
+ geometry.setAttributeValues(VertexAttributes.POSITION, Vector.([
+ -1, -1, -1,
+ 1, -1, -1,
+ 1, 1, -1,
+ -1, 1, -1,
+ -1, -1, 1,
+ 1, -1, 1,
+ 1, 1, 1,
+ -1, 1, 1]));
+ geometry.indices = Vector.([
+ 0, 1, 2, 3, 0, 2, 2, 1, 0, 3, 2, 0,
+ 2, 6, 1, 1, 6, 2, 1, 6, 5, 5, 6, 1,
+ 6, 4, 5, 5, 4, 6, 6, 4, 7, 7, 4, 6,
+ 0, 7, 4, 4, 7, 0, 0, 7, 3, 3, 7, 0,
+ 3, 6, 2, 2, 6, 3, 3, 7, 6, 6, 7, 3,
+ 0, 5, 1, 1, 5, 0, 0, 4, 5, 5, 4, 0]);
+ mesh.addSurface(material, 0, 24);
+ } else {
+ mesh = new GeoSphere(1, 4, true);
+ // Create two side
+ var triangles:Vector. = mesh.geometry.indices;
+ var numTriangles:int = triangles.length;
+ for (var i:int = 0; i < numTriangles; i += 3) {
+ var a:uint = triangles[i];
+ var b:uint = triangles[int(i + 1)];
+ var c:uint = triangles[int(i + 2)];
+ triangles.push(c, b, a);
+ }
+ mesh.geometry.indices = triangles;
+ mesh.getSurface(0).numTriangles = triangles.length / 3;
+ mesh.setMaterialToAllSurfaces(material);
+ }
+ mesh.geometry.upload(context);
+ return mesh;
+ }
+
+ // Draw in shadow map
+ override alternativa3d function process(camera:Camera3D):void {
+ var i:int;
+ var j:int;
+ var caster:Object3D;
+ var context:Context3D = camera.context3D;
+
+ // Checking changed context
+ if (context != cachedContext) {
+ programs = new Dictionary();
+ cubeShadowMap = null;
+ cachedContext = context;
+ }
+
+ // Culling invisible casters
+ if (cubeShadowMap == null) {
+ cubeShadowMap = context.createCubeTexture(_mapSize, Context3DTextureFormat.BGRA, true);
+ debugMaterial.cubeMap = cubeShadowMap;
+ prevActualCastersMask = 63;
+ }
+
+ // Calculate parameters
+ radius = OmniLight(_light).attenuationEnd;
+ for (i = 0; i < 6; i++) {
+ var cam:Camera3D = cameras[i];
+ cam.nearClipping = radius / 1000;
+ cam.farClipping = radius;
+ cam.calculateProjection(1, 1);
+ }
+
+ var castersCount:int = _casters.length;
+ actualCastersCount = 0;
+
+ for (i = 0; i < castersCount; i++) {
+ caster = _casters[i];
+
+ var visible:Boolean = caster.visible;
+ var parent:Object3D = caster._parent;
+ while (visible && parent != null) {
+ visible = parent.visible;
+ parent = parent._parent;
+ }
+
+ if (visible) {
+ // calculate transform matrices
+ _light.lightToObjectTransform.combine(caster.cameraToLocalTransform, _light.localToCameraTransform);
+ caster.localToLightTransform.combine(_light.cameraToLocalTransform, caster.localToCameraTransform);
+
+ // collect actualCasters for light
+ if (caster.boundBox == null || OmniLight(_light).checkBound(caster)) {
+ actualCasters[actualCastersCount] = caster;
+ actualCastersCount++;
+
+ // Pack camera culling
+ caster.culling <<= 16;
+ if (caster.boundBox != null) {
+ // 1 - calculate planes in object space
+ calculatePlanes(caster.localToLightTransform);
+ // 2 - check object location cameras (sections)
+ caster.culling |= recognizeObjectCameras(caster.boundBox);
+ }
+ }
+
+ // update Skin Joints matrices
+ var skin:Skin = caster as Skin;
+ if (skin != null) {
+ // Calculate joints matrices
+ for (var child:Object3D = skin.childrenList; child != null; child = child.next) {
+ if (child.transformChanged) child.composeTransforms();
+ // Write transformToSkin matrix to localToGlobalTransform property
+ child.localToGlobalTransform.copy(child.transform);
+ if (child is Joint) {
+ Joint(child).calculateTransform();
+ }
+ skin.calculateJointsTransforms(child);
+ }
+ }
+
+ if (caster.childrenList != null) collectActualChildren(caster);
+ }
+ }
+
+ // Iterate through six cameras
+ for (i = 0; i < 6; i++) {
+ // Cube side camera
+ var edgeCamera:Camera3D = cameras[i];
+
+ var edgeBit:int = (1 << i);
+ if (actualCastersCount > 0) {
+ // Настройка параметров рендеринга:
+ renderer.camera = camera;
+ context.setRenderToTexture(cubeShadowMap, true, 0, i);
+ context.clear(1, 0, 0, 0.0);
+
+ // Пробегаемся по кастерам
+ for (j = 0; j < actualCastersCount; j++) {
+ caster = actualCasters[j];
+
+ // Проверить находится ли кастер в зоне 4-х плоскостей
+ if ((caster.culling & edgeBit)) {
+ // собираем матрицу перевода из кастера в пространство edgeCamera
+ casterToEdgedCameraTransform.combine(edgeCamera.inverseTransform, caster.localToLightTransform);
+ // Собираем драуколлы для кастера и его дочерних объектов
+ collectDraws(context, caster, edgeCamera);
+ }
+ }
+
+// if (renderer.drawUnits.length == 0) context.clear(0, 0, 0, 0.0);
+
+ // Drawing
+ renderer.render(context);
+ prevActualCastersMask |= edgeBit;
+ }
+ else {
+ // Если относительно одной из камер ничего не менялось, не вызываем отрисовочный вызов
+
+ if ((prevActualCastersMask & edgeBit)) {
+ context.setRenderToTexture(cubeShadowMap, false, 0, i);
+ context.clear(1, 0, 0, 0);
+
+ prevActualCastersMask &= ~edgeBit;
+ }
+ }
+ }
+ context.setRenderToBackBuffer();
+
+ // Unpack camera culling value
+ for (j = 0; j < actualCastersCount; j++) {
+ caster = actualCasters[j];
+ // If there was -1, after shift it will be -1 too
+ caster.culling >>= 16;
+ }
+
+ if (debug) {
+ // Create debug object if needed
+ if (debugObject == null) {
+ debugObject = createDebugObject(debugMaterial, camera.context3D);
+ }
+ debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius * debugRadiusScale;
+ debugObject.composeTransforms();
+
+ // Формируем матрицу трансформации для debugObject
+ debugObject.localToCameraTransform.combine(_light.localToCameraTransform, debugObject.transform);
+
+ // Отрисовываем
+ var debugSurface:Surface = debugObject._surfaces[0];
+ debugMaterial.collectDraws(camera, debugSurface, debugObject.geometry, null, 0, false, -1);
+ }
+ actualCasters.length = 0;
+ }
+
+ private function collectActualChildren(root:Object3D):void {
+ for (var child:Object3D = root.childrenList; child != null; child = child.next) {
+ if (child.visible) {
+ // calculate transform matrices
+ _light.lightToObjectTransform.combine(child.cameraToLocalTransform, _light.localToCameraTransform);
+ child.localToLightTransform.combine(_light.cameraToLocalTransform, child.localToCameraTransform);
+
+ // collect actualCasters for light
+ if (child.boundBox == null || OmniLight(_light).checkBound(child)) {
+ actualCasters[actualCastersCount] = child;
+ actualCastersCount++;
+
+ // Pack camera culling
+ child.culling <<= 16;
+ if (child.boundBox != null) {
+ // 1 - calculate planes in object space
+ calculatePlanes(child.localToLightTransform);
+ // 2 - check object location cameras (sections)
+ child.culling |= recognizeObjectCameras(child.boundBox);
+ }
+ }
+
+ // update Skin Joints matrices
+ var skin:Skin = child as Skin;
+ if (skin != null) {
+ // Calculate joints matrices
+ for (var skinChild:Object3D = skin.childrenList; skinChild != null; skinChild = skinChild.next) {
+ if (skinChild.transformChanged) skinChild.composeTransforms();
+ // Write transformToSkin matrix to localToGlobalTransform property
+ skinChild.localToGlobalTransform.copy(skinChild.transform);
+ if (skinChild is Joint) {
+ Joint(skinChild).calculateTransform();
+ }
+ skin.calculateJointsTransforms(skinChild);
+ }
+ }
+
+ if (child.childrenList != null) collectActualChildren(child);
+ }
+ }
+ }
+
+ private var sections:SectionPlane;
+
+ private function calculatePlanes(transform:Transform3D):void {
+ // DUBFLR
+ var planeRU:SectionPlane = sections;
+ var planeLU:SectionPlane = sections.next;
+ var planeFU:SectionPlane = sections.next.next;
+ var planeBU:SectionPlane = sections.next.next.next;
+ var planeRF:SectionPlane = sections.next.next.next.next;
+ var planeRB:SectionPlane = sections.next.next.next.next.next;
+
+ // 1, 0, 1
+ planeRU.x = transform.a + transform.i;
+ planeRU.y = transform.b + transform.j;
+ planeRU.z = transform.c + transform.k;
+ planeRU.offset = -(transform.d + transform.l);
+
+ // -1, 0, 1
+ planeLU.x = transform.i - transform.a;
+ planeLU.y = transform.j - transform.b;
+ planeLU.z = transform.k - transform.c;
+ planeLU.offset = transform.d - transform.l;
+
+ // 0, 1, 1
+ planeFU.x = transform.e + transform.i;
+ planeFU.y = transform.f + transform.j;
+ planeFU.z = transform.g + transform.k;
+ planeFU.offset = -(transform.h + transform.l);
+
+ // 0, -1, 1
+ planeBU.x = transform.i - transform.e;
+ planeBU.y = transform.j - transform.f;
+ planeBU.z = transform.k - transform.g;
+ planeBU.offset = transform.h - transform.l;
+
+ // 1, 1, 0
+ planeRF.x = transform.a + transform.e;
+ planeRF.y = transform.b + transform.f;
+ planeRF.z = transform.c + transform.g;
+ planeRF.offset = -(transform.d + transform.h);
+
+ // 1, -1, 0
+ planeRB.x = transform.a - transform.e;
+ planeRB.y = transform.b - transform.f;
+ planeRB.z = transform.c - transform.g;
+ planeRB.offset = transform.h - transform.d;
+
+ // var ax:Number = transform.c - transform.a + transform.b; // E
+// var ay:Number = transform.g - transform.e + transform.f;
+// var az:Number = transform.k - transform.i + transform.j;
+// var bx:Number = transform.c - transform.a - transform.b; // H
+// var by:Number = transform.g - transform.e - transform.f;
+// var bz:Number = transform.k - transform.i - transform.j;
+// planeRU.x = bz * ay - by * az;
+// planeRU.y = bx * az - bz * ax;
+// planeRU.z = by * ax - bx * ay;
+// planeRU.offset = transform.d*planeRU.x + transform.h*planeRU.y + transform.l*planeRU.z;
+//
+// ax = transform.c + transform.a - transform.b; // D
+// ay = transform.g + transform.e - transform.f;
+// az = transform.k + transform.i - transform.j;
+// bx = transform.c + transform.a + transform.b; // A
+// by = transform.g + transform.e + transform.f;
+// bz = transform.k + transform.i + transform.j;
+// planeLU.x = bz * ay - by * az;
+// planeLU.y = bx * az - bz * ax;
+// planeLU.z = by * ax - bx * ay;
+// planeLU.offset = transform.d*planeLU.x + transform.h*planeLU.y + transform.l*planeLU.z;
+//
+// ax = transform.c - transform.a - transform.b; // H
+// ay = transform.g - transform.e - transform.f;
+// az = transform.k - transform.i - transform.j;
+// bx = transform.c + transform.a - transform.b; // D
+// by = transform.g + transform.e - transform.f;
+// bz = transform.k + transform.i - transform.j;
+// planeFU.x = bz * ay - by * az;
+// planeFU.y = bx * az - bz * ax;
+// planeFU.z = by * ax - bx * ay;
+// planeFU.offset = transform.d*planeFU.x + transform.h*planeFU.y + transform.l*planeFU.z;
+//
+// ax = transform.c + transform.a + transform.b; // A
+// ay = transform.g + transform.e + transform.f;
+// az = transform.k + transform.i + transform.j;
+// bx = transform.c - transform.a + transform.b; // E
+// by = transform.g - transform.e + transform.f;
+// bz = transform.k - transform.i + transform.j;
+// planeBU.x = bz * ay - by * az;
+// planeBU.y = bx * az - bz * ax;
+// planeBU.z = by * ax - bx * ay;
+// planeBU.offset = transform.d*planeBU.x + transform.h*planeBU.y + transform.l*planeBU.z;
+//
+// ax = transform.a - transform.b + transform.c; // D
+// ay = transform.e - transform.f + transform.g;
+// az = transform.i - transform.j + transform.k;
+// bx = transform.a - transform.b - transform.c; // C
+// by = transform.e - transform.f - transform.g;
+// bz = transform.i - transform.j - transform.k;
+// planeRF.x = bz * ay - by * az;
+// planeRF.y = bx * az - bz * ax;
+// planeRF.z = by * ax - bx * ay;
+// planeRF.offset = transform.d*planeRF.x + transform.h*planeRF.y + transform.l*planeRF.z;
+//
+// ax = transform.a + transform.b - transform.c; // B
+// ay = transform.e + transform.f - transform.g;
+// az = transform.i + transform.j - transform.k;
+// bx = transform.a + transform.b + transform.c; // A
+// by = transform.e + transform.f + transform.g;
+// bz = transform.i + transform.j + transform.k;
+// planeRB.x = bz * ay - by * az;
+// planeRB.y = bx * az - bz * ax;
+// planeRB.z = by * ax - bx * ay;
+// planeRB.offset = transform.d*planeRB.x + transform.h*planeRB.y + transform.l*planeRB.z;
+ }
+
+ private function recognizeObjectCameras(bb:BoundBox):int {
+ var culling:int = 63;
+ for (var plane:SectionPlane = sections; plane != null; plane = plane.next) {
+ var result:int = 0;
+
+ if (plane.x >= 0)
+ if (plane.y >= 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.minX * plane.x + bb.minY * plane.y + bb.minZ * plane.z < plane.offset) result |= plane.backCameras;
+ } else {
+ 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;
+ }
+ 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)
+ if (plane.z >= 0) {
+ 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;
+ } else {
+ 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;
+ }
+ 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.maxX * plane.x + bb.maxY * plane.y + bb.minZ * plane.z < plane.offset) result |= plane.backCameras;
+ } else {
+ 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;
+ }
+ culling &= result | plane.unusedBits;
+ }
+ return culling;
+ }
+
+ private function collectDraws(context:Context3D, caster:Object3D, edgeCamera:Camera3D):void {
+ // если объект является мешем, собираем для него дроуколы
+ var mesh:Mesh = caster as Mesh;
+ if (mesh != null && mesh.geometry != null) {
+ var program:ShaderProgram;
+ var programListByTransformProcedure:Vector.;
+ var skin:Skin = mesh as Skin;
+
+ // пробегаемся по сурфейсам
+ for (var i:int = 0; i < mesh._surfacesLength; i++) {
+ var surface:Surface = mesh._surfaces[i];
+ if (surface.material == null) continue;
+
+ var material:Material = surface.material;
+ var geometry:Geometry = mesh.geometry;
+ var alphaTest:Boolean;
+ var useDiffuseAlpha:Boolean;
+ var alphaThreshold:Number;
+ var materialAlpha:Number;
+ var diffuse:TextureResource;
+ var opacity:TextureResource;
+ var uvBuffer:VertexBuffer3D;
+
+ // ловим параметры прозрачности
+ if (material is TextureMaterial) {
+ alphaThreshold = TextureMaterial(material).alphaThreshold;
+ materialAlpha = TextureMaterial(material).alpha;
+ diffuse = TextureMaterial(material).diffuseMap;
+ opacity = TextureMaterial(material).opacityMap;
+ alphaTest = alphaThreshold > 0;
+ useDiffuseAlpha = TextureMaterial(material).opacityMap == null;
+ uvBuffer = geometry.getVertexBuffer(VertexAttributes.TEXCOORDS[0]);
+ if (uvBuffer == null) continue;
+ } else {
+ alphaTest = false;
+ useDiffuseAlpha = false;
+ }
+
+
+ var positionBuffer:VertexBuffer3D = mesh.geometry.getVertexBuffer(VertexAttributes.POSITION);
+ if (positionBuffer == null) continue;
+
+ // поднимаем и кэшируем programListByTransformProcedure
+ if (skin != null) {
+ caster.transformProcedure = skin.surfaceTransformProcedures[i];
+ }
+ programListByTransformProcedure = programs[caster.transformProcedure];
+ if (programListByTransformProcedure == null) {
+ programListByTransformProcedure = new Vector.(3, true);
+ programs[caster.transformProcedure] = programListByTransformProcedure;
+ }
+
+ // собираем программу и Формируем дроуюнит
+ program = getProgram(caster.transformProcedure, programListByTransformProcedure, context, alphaTest, useDiffuseAlpha);
+ var drawUnit:DrawUnit = renderer.createDrawUnit(caster, program.program, mesh.geometry._indexBuffer, surface.indexBegin, surface.numTriangles, program);
+ drawUnit.culling = Context3DTriangleFace.BACK;
+
+ // Установка стрима
+ drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aPosition"), positionBuffer, mesh.geometry._attributesOffsets[VertexAttributes.POSITION], VertexAttributes.FORMATS[VertexAttributes.POSITION]);
+
+ if (alphaTest) {
+ drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aUV"), uvBuffer, geometry._attributesOffsets[VertexAttributes.TEXCOORDS[0]], VertexAttributes.FORMATS[VertexAttributes.TEXCOORDS[0]]);
+ drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cThresholdAlpha"), alphaThreshold, 0, 0, materialAlpha);
+ if (useDiffuseAlpha) {
+ drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sTexture"), diffuse._texture);
+ } else {
+ drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sTexture"), opacity._texture);
+ }
+ }
+
+ // Установка констант
+ caster.setTransformConstants(drawUnit, surface, program.vertexShader, null);
+ drawUnit.setProjectionConstants(edgeCamera, program.vertexShader.getVariableIndex("cProjMatrix"), casterToEdgedCameraTransform);
+ drawUnit.setVertexConstantsFromTransform(program.vertexShader.getVariableIndex("cCasterToOmni"), caster.localToLightTransform);
+
+ drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cConstants"), 1 / 255, 0, 255 / radius, 1);
+
+ renderer.addDrawUnit(drawUnit, Renderer.OPAQUE);
+ }
+ }
+ }
+
+ /**
+ * @private
+ * Процедура для передачи UV координат во фрагментный шейдер
+ */
+ static private const passUVProcedure:Procedure = new Procedure(["#v0=vUV", "#a0=aUV", "mov v0, a0"], "passUVProcedure");
+
+ // diffuse alpha test
+ private static const diffuseAlphaTestProcedure:Procedure = new Procedure([
+ "#v0=vUV",
+ "#s0=sTexture",
+ "#c0=cThresholdAlpha",
+ "tex t0, v0, s0 <2d, linear,repeat, miplinear>",
+ "mul t0.w, t0.w, c0.w",
+ "sub t0.w, t0.w, c0.x",
+ "kil t0.w"
+ ], "diffuseAlphaTestProcedure");
+
+ // opacity alpha test
+ private static const opacityAlphaTestProcedure:Procedure = new Procedure([
+ "#v0=vUV",
+ "#s0=sTexture",
+ "#c0=cThresholdAlpha",
+ "tex t0, v0, s0 <2d, linear,repeat, miplinear>",
+ "mul t0.w, t0.x, c0.w",
+ "sub t0.w, t0.w, c0.x",
+ "kil t0.w"
+ ], "opacityAlphaTestProcedure");
+
+
+ private function getProgram(transformProcedure:Procedure, programListByTransformProcedure:Vector., context:Context3D, alphaTest:Boolean, useDiffuseAlpha:Boolean):ShaderProgram {
+ var key:int = (alphaTest ? (useDiffuseAlpha ? 1 : 2) : 0);
+ var program:ShaderProgram = programListByTransformProcedure[key];
+
+ if (program == null) {
+ var vLinker:Linker = new Linker(Context3DProgramType.VERTEX);
+ var fLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
+
+ var positionVar:String = "aPosition";
+ vLinker.declareVariable(positionVar, VariableType.ATTRIBUTE);
+
+ if (alphaTest) {
+ vLinker.addProcedure(passUVProcedure);
+ }
+
+ if (transformProcedure != null) {
+ var newPosVar:String = "tTransformedPosition";
+ vLinker.declareVariable(newPosVar);
+ vLinker.addProcedure(transformProcedure, positionVar);
+ vLinker.setOutputParams(transformProcedure, newPosVar);
+ positionVar = newPosVar;
+ }
+
+ var proc:Procedure = Procedure.compileFromArray([
+ "#v0=vDistance",
+
+ "m34 t0.xyz, i0, c2",
+ "mov v0, t0.xyzx",
+
+ "m44 o0, i0, c0"
+ ]);
+ proc.assignVariableName(VariableType.CONSTANT, 0, "cProjMatrix", 4);
+ proc.assignVariableName(VariableType.CONSTANT, 2, "cCasterToOmni", 3);
+
+ vLinker.addProcedure(proc, positionVar);
+
+ if (alphaTest) {
+ if (useDiffuseAlpha) {
+ fLinker.addProcedure(diffuseAlphaTestProcedure);
+ } else {
+ fLinker.addProcedure(opacityAlphaTestProcedure);
+ }
+ }
+ fLinker.addProcedure(Procedure.compileFromArray([
+ "#v0=vDistance", // xyz
+ "#c0=cConstants", // 1/255, 0, 255/radius, 1
+ // calculate distance
+ "dp3 t0.z, v0.xyz, v0.xyz",
+ "sqt t0.z, t0.z", // x: [0, radius]
+ "mul t0.z, t0.z, c0.z", // x: [0, 255]
+ // codeing
+ "frc t0.y, t0.z",
+ "sub t0.x, t0.z, t0.y",
+ "mul t0.x, t0.x, c0.x",
+
+ "mov t0.w, c0.w",
+ "mov o0, t0"
+ ]));
+ program = new ShaderProgram(vLinker, fLinker);
+ fLinker.varyings = vLinker.varyings;
+ programListByTransformProcedure[key] = program;
+ program.upload(context);
+
+ }
+ return program;
+ }
+
+
+ //------------- ShadowMap Shader in material----------
+
+ /**
+ * @private
+ */
+ alternativa3d override function setup(drawUnit:DrawUnit, vertexLinker:Linker, fragmentLinker:Linker, surface:Surface):void {
+ // Устанавливаем матрицу перевода в шедоумапу
+ objectToLightTransform.combine(_light.cameraToLocalTransform, surface.object.localToCameraTransform);
+ drawUnit.setVertexConstantsFromTransform(vertexLinker.getVariableIndex("cObjectToLightTransform"), objectToLightTransform);
+
+ // Устанавливаем шедоумапу
+ drawUnit.setTextureAt(fragmentLinker.getVariableIndex("sCubeMap"), cubeShadowMap);
+
+ // Устанавливаем коеффициенты
+ if (_pcfOffset > 0) {
+ 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("cConstants"), -1, 1, 0, offset);
+ drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cDecode"), -DIFFERENCE_MULTIPLIER, -DIFFERENCE_MULTIPLIER / 255, biasMultiplier * DIFFERENCE_MULTIPLIER / radius, 10);
+ } else {
+ drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -DIFFERENCE_MULTIPLIER, -DIFFERENCE_MULTIPLIER / 255, biasMultiplier * DIFFERENCE_MULTIPLIER / radius, 1.0);
+ }
+ }
+
+ private static function getVShader():Procedure {
+ var shader:Procedure = Procedure.compileFromArray([
+ "#v0=vSample",
+
+ "m34 t0.xyz, i0, c0",
+
+ "mov v0, t0.xyz"
+ ], "OmniShadowMapVertex");
+ shader.assignVariableName(VariableType.CONSTANT, 0, "cObjectToLightTransform", 3);
+ return shader;
+ }
+
+ private static function getFShader():Procedure {
+ var shaderArr:Array = [
+ "#v0=vSample",
+ "#c0=cConstants",
+ "#s0=sCubeMap"
+ ];
+ var line:int = 3;
+ // Расстояние
+ shaderArr[line++] = "dp3 t0.z, v0.xyz, v0.xyz";
+ shaderArr[line++] = "sqt t0.z, t0.z"; // w: [0, radius]
+ shaderArr[line++] = "tex t0.xy, v0, s0 ";
+ shaderArr[line++] = "dp3 t0.x, t0.xyz, c0.xyz"; // декодируем, находим разницу между расстояниями и умножаем ее на большое число
+
+ // рассчитываем значение тени
+ shaderArr[line++] = "sat t0.x, t0.x";
+ shaderArr[line++] = "sub o0, c0.w, t0.x";
+
+// shaderArr[line++] = "sat t0.x, t0.x";
+// shaderArr[line++] = "sub t0.x, c0.w, t0.x";
+// shaderArr[line++] = "sat t0.x, t0.x";
+// shaderArr[line++] = "mov o0, t0.x";
+
+ return Procedure.compileFromArray(shaderArr, "OmniShadowMapFragment");
+ }
+
+ private static function getFShaderPCF():Procedure {
+ var shaderArr:Array = [
+ "#v0=vSample",
+ "#c0=cDecode",
+ "#c1=cConstants",
+ "#c2=cPCFOffsets",
+ "#s0=sCubeMap"
+ ];
+ var line:int = 5;
+ var i:int;
+ var j:int;
+
+ // допустимо использование временных переменных t0 t1 t2 t3
+ // v0 - sample
+
+ // calculate 2 ortogonal vectors
+ // (-y, x, 0)
+ shaderArr[line++] = "mov t1.xyzw, v0.yxzw";
+ shaderArr[line++] = "mul t1.xyzw, t1.xyzw, c1.xyzz";
+
+ shaderArr[line++] = "crs t0.xyz, v0.xyz, t1.xyz";
+
+ // normalize vectors
+ shaderArr[line++] = "nrm t0.xyz, t0.xyz";
+ shaderArr[line++] = "nrm t1.xyz, t1.xyz";
+
+ shaderArr[line++] = "dp3 t3.z, v0.xyz, v0.xyz";
+ shaderArr[line++] = "sqt t3.z, t3.z"; // distance
+
+ // apply pcf offset
+ shaderArr[line++] = "mul t0.w, c1.w, t3.z"; // с1.w = offset/radius
+ shaderArr[line++] = "mul t0.xyz, t0.xyz, t0.w";
+ shaderArr[line++] = "mul t1.xyz, t1.xyz, t0.w";
+ // --------- {13 opcode}
+
+ // t0, t1 - ortogonals ↑→
+ // t2 - current vector
+
+ // t3.z distance to object
+ // t3.xy - result from shadow map
+ // t3.w - summ of sat
+
+ // first point
+ shaderArr[line++] = "add t2.xyz, t0.xyz, t1.xyz";
+ shaderArr[line++] = "mul t2.xyz, t2.xyz, c2.xxx";
+ shaderArr[line++] = "add t2.xyz, t2.xyz, v0.xyz";
+
+ // получаем длинну из шадоумапы [0, 1]
+// shaderArr[line++] = "mov t3.z, t0.w";
+
+ shaderArr[line++] = "tex t3.xy, t2.xyz, s0 ";
+ shaderArr[line++] = "dp3 o0." + componentByIndex[0] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
+
+ //-----
+
+ for (j = 1; j < 4; j++) {
+ shaderArr[line++] = "add t2.xyz, t2.xyz, t1.xyz";
+
+ shaderArr[line++] = "tex t3.xy, t2.xyz, s0 ";
+ shaderArr[line++] = "dp3 o0." + componentByIndex[j] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
+ }
+
+ shaderArr[line++] = "sat o0, o0";
+ shaderArr[line++] = "dp4 t3.w, o0, c2.y";
+
+ //-----
+
+ for (i = 0; i < 3; i++) {
+ shaderArr[line++] = "add t2.xyz, t2.xyz, t0.xyz";
+
+ shaderArr[line++] = "tex t3.xy, t2.xyz, s0 ";
+ shaderArr[line++] = "dp3 o0." + componentByIndex[0] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
+
+ 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++] = "tex t3.xy, t2.xyz, s0 ";
+ shaderArr[line++] = "dp3 o0." + componentByIndex[j] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
+ }
+ shaderArr[line++] = "sat o0, o0";
+ shaderArr[line++] = "dp4 o0.x, o0, c2.y";
+ shaderArr[line++] = "add t3.w, t3.w, o0.x";
+ }
+
+ shaderArr[line++] = "sub o0, c1.y, t3.w";
+
+ //--------- {73 opcodes}
+ return Procedure.compileFromArray(shaderArr, "OmniShadowMapFragment");
+ }
+
+ private static const componentByIndex:Array = ["x", "y", "z", "w"];
+
+ /**
+ * Adds given object to list of objects, that cast shadow.
+ * @param object Added object.
+ */
+ public function addCaster(object:Object3D):void {
+ if (_casters.indexOf(object) < 0) {
+ _casters.push(object);
+ }
+ }
+
+ /**
+ * Removes given object from shadow casters list.
+ * @param object Object which should be removed from shadow casters list.
+ */
+ public function removeCaster(object:Object3D):void {
+ var index:int = _casters.indexOf(object);
+ if (index < 0) throw new Error("Caster not found");
+ _casters[index] = _casters.pop();
+ }
+
+ /**
+ * Clears the list of objects, that cast shadow.
+ */
+ public function clearCasters():void {
+ _casters.length = 0;
+ }
+
+ /**
+ * 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 {
+ return _mapSize;
+ }
+
+ /**
+ * @private
+ */
+ public function set mapSize(value:int):void {
+ if (value != _mapSize) {
+ this._mapSize = value;
+ if (value < 2) {
+ throw new ArgumentError("Map size cannot be less than 2.");
+ } else if (value > 1024) {
+ throw new ArgumentError("Map size exceeds maximum value 1024.");
+ }
+ if ((Math.log(value) / Math.LN2 % 1) != 0) {
+ throw new ArgumentError("Map size must be power of two.");
+ }
+ if (cubeShadowMap != null) {
+ cubeShadowMap.dispose();
+ }
+ cubeShadowMap = null;
+ }
+ }
+
+ /**
+ * Offset of Percentage Closer Filtering. This way of filtering is used for mitigation of shadow bounds.
+ */
+ public function get pcfOffset():Number {
+ return _pcfOffset;
+ }
+
+ /**
+ * @private
+ */
+ public function set pcfOffset(value:Number):void {
+ _pcfOffset = value;
+ type = _pcfOffset > 0 ? Shadow.PCF_MODE : Shadow.SIMPLE_MODE;
+ fragmentShadowProcedure = _pcfOffset > 0 ? getFShaderPCF() : getFShader();
+ }
+
+ }
+}
+
+import alternativa.engine3d.alternativa3d;
+import alternativa.engine3d.core.Camera3D;
+import alternativa.engine3d.core.DrawUnit;
+import alternativa.engine3d.core.Light3D;
+import alternativa.engine3d.core.Object3D;
+import alternativa.engine3d.core.Renderer;
+import alternativa.engine3d.core.VertexAttributes;
+import alternativa.engine3d.materials.Material;
+import alternativa.engine3d.materials.ShaderProgram;
+import alternativa.engine3d.materials.compiler.Linker;
+import alternativa.engine3d.materials.compiler.Procedure;
+import alternativa.engine3d.materials.compiler.VariableType;
+import alternativa.engine3d.objects.Surface;
+import alternativa.engine3d.resources.Geometry;
+
+import flash.display3D.Context3D;
+import flash.display3D.Context3DBlendFactor;
+import flash.display3D.Context3DProgramType;
+import flash.display3D.VertexBuffer3D;
+import flash.display3D.textures.CubeTexture;
+import flash.utils.Dictionary;
+
+class ShadowDebugMaterial extends Material {
+
+ use namespace alternativa3d;
+
+ /**
+ * Прозрачность.
+ * Является дополнительным множителем к прозрачности текстуры.
+ * Значение по умолчанию 1.
+ */
+ alternativa3d var alpha:Number = 1;
+
+ private var cachedContext3D:Context3D;
+ private static var caches:Dictionary = new Dictionary(true);
+ private var program:ShaderProgram;
+
+ /**
+ * Текстура.
+ */
+ alternativa3d var cubeMap:CubeTexture;
+
+ /**
+ * @private
+ */
+ override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector., lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void {
+ var object:Object3D = surface.object;
+ // Стримы
+ var positionBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.POSITION);
+ // Проверка на валидность
+ if (positionBuffer == null) return;
+
+ // Обновляем кеш программы для данного контекста
+ if (camera.context3D != cachedContext3D) {
+ cachedContext3D = camera.context3D;
+ program = caches[cachedContext3D];
+ }
+
+ if (program == null) {
+ program = setupProgram(object);
+ program.upload(camera.context3D);
+ caches[cachedContext3D] = program;
+ }
+
+ // Создание отрисовочного вызова
+ var drawUnit:DrawUnit = camera.renderer.createDrawUnit(object, program.program, geometry._indexBuffer, surface.indexBegin, surface.numTriangles, program);
+ // Установка стримов
+ 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.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cDecode"), 1, 1 / 255, 0, alpha);
+ drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sCubeMap"), cubeMap);
+
+ // Отправка на отрисовку
+ if (alpha < 1) {
+ drawUnit.blendSource = Context3DBlendFactor.SOURCE_ALPHA;
+ drawUnit.blendDestination = Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA;
+ camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.TRANSPARENT_SORT);
+ } else {
+ camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.OPAQUE);
+ }
+ }
+
+ private function copyDrawUnit(source:DrawUnit, dest:DrawUnit):void {
+
+ }
+
+ private function setupProgram(object:Object3D):ShaderProgram {
+ var vertexLinker:Linker = new Linker(Context3DProgramType.VERTEX);
+ var positionVar:String = "aPosition";
+ vertexLinker.declareVariable(positionVar, VariableType.ATTRIBUTE);
+
+ var proc:Procedure = Procedure.compileFromArray([
+ "#v0=vCubeMapCoord",
+ "mov v0, i0",
+ "m44 o0, i0, c0"
+ ]);
+ proc.assignVariableName(VariableType.CONSTANT, 0, "cProjMatrix", 4);
+ vertexLinker.addProcedure(proc, positionVar);
+
+ var fragmentLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
+ var colorProc:Procedure = Procedure.compileFromArray([
+ "#v0=vCubeMapCoord",
+ "#s0=sCubeMap",
+ "#c0=cDecode",
+
+ "tex t0.xy, v0, s0 ",
+ "dp3 t0.xyz, t0.xy, c0.xy",
+ "mov t0.w, c0.w",
+ "mov o0, t0"
+ ]);
+ fragmentLinker.addProcedure(colorProc, "vCubeMapCoord");
+ fragmentLinker.varyings = vertexLinker.varyings;
+ return new ShaderProgram(vertexLinker, fragmentLinker);
+ }
+
+}
+
+class SectionPlane {
+
+ public var x:Number = 0;
+ public var y:Number = 0;
+ public var z:Number = 0;
+ public var offset:Number = 0;
+
+ public var next:SectionPlane;
+
+ public var frontCameras:int;
+ public var backCameras:int;
+ public var unusedBits:int = 63;
+
+ public function SectionPlane(frontCameras:int, backCameras:int, unused:int) {
+ this.frontCameras = frontCameras;
+ this.backCameras = backCameras;
+ this.unusedBits = unused;
+ }
+
+}
diff --git a/src/alternativa/utils/Utils.as b/src/alternativa/utils/Utils.as
index 8711c5b..8713b85 100644
--- a/src/alternativa/utils/Utils.as
+++ b/src/alternativa/utils/Utils.as
@@ -42,8 +42,13 @@ package alternativa.utils {
}
/**
- * @private
- * Performs calculation of bound box of objects hierarchy branch.
+ * Calculates a BoundBox of hierarchy of objects.
+ *
+ * @param object Container which contains the hierarchy.
+ * @param boundBoxSpace Object3D in coordinates of which the BoundBox will be calculated.
+ * @param result Instance of BoundBox to which calculated properties will be set.
+ *
+ * @return Instance given as result property with properties updated according to calculations. If result property was not set, new instance of BoundBox will be created.
*/
public static function calculateHierarchyBoundBox(object:Object3D, boundBoxSpace:Object3D = null, result:BoundBox = null):BoundBox {
if (result == null) result = new BoundBox();