diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..574e920
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,57 @@
+
+ 4.0.0
+ platform.clients.fp11.libraries
+ Alternativa3D
+ swc
+ 8.30.0-SNAPSHOT
+
+ platform.clients.fp11.tools.maven
+ BasePom
+ 2.58.0
+
+
+
+ scm:git:https://github.com/AlternativaPlatform/Alternativa3D/master/
+
+
+
+
+
+
+ platform.client.formats
+ A3DModelsBase
+ 2.5.2
+ swc
+ external
+
+
+ platform.clients.fp10.libraries
+ AlternativaProtocol
+ 2.53.0
+ swc
+ external
+
+
+
+
+
+
+ platform.client.formats
+ A3DModelsBase
+ swc
+ external
+
+
+ platform.clients.fp10
+ OSGiBase
+ swc
+ external
+
+
+ platform.clients.fp10.libraries
+ AlternativaProtocol
+ swc
+ external
+
+
+
diff --git a/src/alternativa/Alternativa3D.as b/src/alternativa/Alternativa3D.as
index a18bba8..fc704c0 100644
--- a/src/alternativa/Alternativa3D.as
+++ b/src/alternativa/Alternativa3D.as
@@ -17,6 +17,6 @@ package alternativa {
/**
* Library version in the format: generation.feature-version.fix-version.
*/
- public static const version:String = "8.27.0";
+ public static const version:String = "8.29.0";
}
}
diff --git a/src/alternativa/engine3d/core/Camera3D.as b/src/alternativa/engine3d/core/Camera3D.as
index dad6962..e3bf0b4 100644
--- a/src/alternativa/engine3d/core/Camera3D.as
+++ b/src/alternativa/engine3d/core/Camera3D.as
@@ -220,6 +220,7 @@ public class Camera3D extends Object3D {
if (transformChanged) composeTransforms();
localToGlobalTransform.copy(transform);
globalToLocalTransform.copy(inverseTransform);
+ // Searching for upper hierarchy point
var root:Object3D = this;
while (root.parent != null) {
root = root.parent;
@@ -227,6 +228,8 @@ public class Camera3D extends Object3D {
localToGlobalTransform.append(root.transform);
globalToLocalTransform.prepend(root.inverseTransform);
}
+ var excludedLightLength:int = root.excludedLights.length;
+
// Calculating the rays of mouse events
view.calculateRays(this);
for (i = origins.length; i < view.raysLength; i++) {
@@ -283,7 +286,7 @@ public class Camera3D extends Object3D {
occluder = occluders[i];
if (occluder.enabled) {
// Debug
- occluder.collectDraws(this, null, 0);
+ occluder.collectDraws(this, null, 0, false);
if (debug && occluder.boundBox != null && (checkInDebug(occluder) & Debug.BOUNDS)) Debug.drawBoundBox(this, occluder.boundBox, occluder.localToCameraTransform);
occluders[j] = occluder;
j++;
@@ -300,12 +303,11 @@ public class Camera3D extends Object3D {
light.green = ((light.color >> 8) & 0xFF) * light.intensity / 255;
light.blue = (light.color & 0xFF) * light.intensity / 255;
// Debug
- light.collectDraws(this, null, 0);
+ light.collectDraws(this, null, 0, false);
if (debug && light.boundBox != null && (checkInDebug(light) & Debug.BOUNDS)) Debug.drawBoundBox(this, light.boundBox, light.localToCameraTransform);
// Shadows preparing
if (light.shadow != null) {
- light.shadow._light = light;
light.shadow.process(this);
}
lights[j] = light;
@@ -327,10 +329,15 @@ public class Camera3D extends Object3D {
// Check if object needs in lightning
if (lightsLength > 0 && root.useLights) {
// Pass the lights to children and calculate appropriate transformations
+ var childLightsLength:int = 0;
if (root.boundBox != null) {
- var childLightsLength:int = 0;
for (i = 0; i < lightsLength; i++) {
light = lights[i];
+ // Checking light source for existing in excludedLights
+ j = 0;
+ while (j = new Vector.();
+
/**
* @private
*/
@@ -282,6 +287,16 @@ package alternativa.engine3d.core {
*/
alternativa3d var globalToLocalTransform:Transform3D = new Transform3D();
+ /**
+ * @private
+ */
+ alternativa3d var localToLightTransform:Transform3D = new Transform3D();
+
+ /**
+ * @private
+ */
+ alternativa3d var lightToLocalTransform:Transform3D = new Transform3D();
+
/**
* @private
*/
@@ -1272,6 +1287,7 @@ package alternativa.engine3d.core {
*/
alternativa3d function calculateChildrenVisibility(camera:Camera3D):void {
for (var child:Object3D = childrenList; child != null; child = child.next) {
+ // Checking visibility flag
if (child.visible) {
// Compose matrix and inverse matrix
if (child.transformChanged) child.composeTransforms();
@@ -1297,16 +1313,19 @@ package alternativa.engine3d.core {
/**
* @private
*/
- alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int):void {
+ alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int, useShadow:Boolean):void {
}
/**
* @private
*/
- alternativa3d function collectChildrenDraws(camera:Camera3D, lights:Vector., lightsLength:int):void {
+ alternativa3d function collectChildrenDraws(camera:Camera3D, lights:Vector., lightsLength:int, useShadow:Boolean):void {
var i:int;
var light:Light3D;
+ var excludedLightLength:int = excludedLights.length;
+
for (var child:Object3D = childrenList; child != null; child = child.next) {
+ // Checking visibility flag
if (child.visible) {
// Check getting in frustum and occluding
if (child.culling >= 0 && (child.boundBox == null || camera.occludersLength == 0 || !child.boundBox.checkOcclusion(camera.occluders, camera.occludersLength, child.localToCameraTransform))) {
@@ -1320,10 +1339,16 @@ package alternativa.engine3d.core {
// Check if object needs in lightning
if (lightsLength > 0 && child.useLights) {
// Pass the lights to children and calculate appropriate transformations
+ var childLightsLength:int = 0;
+ var j:int;
if (child.boundBox != null) {
- var childLightsLength:int = 0;
for (i = 0; i < lightsLength; i++) {
light = lights[i];
+ // Checking object for existing in excludedLights
+ j = 0;
+ while (jObject3D.
+ * Toggle off light source from litting this object
+ */
+ public function excludeLight(light:Light3D):void{
+ excludedLights.push(light);
+ }
+
+ /**
+ * Resets list of lights excluded from litting this object
+ */
+ public function resetLights():void{
+ excludedLights.length = 0;
+ }
+
+ /**
+ * Returns a copy of object
* @return A copy of this Object3D.
*/
public function clone():Object3D {
diff --git a/src/alternativa/engine3d/core/Occluder.as b/src/alternativa/engine3d/core/Occluder.as
index 8e87e33..7e55335 100644
--- a/src/alternativa/engine3d/core/Occluder.as
+++ b/src/alternativa/engine3d/core/Occluder.as
@@ -133,7 +133,7 @@ package alternativa.engine3d.core {
/**
* @private
*/
- override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int):void {
+ override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int, useShadow:Boolean):void {
// Debug
if (camera.debug) {
if (camera.checkInDebug(this) & Debug.CONTENT) {
@@ -145,7 +145,7 @@ package alternativa.engine3d.core {
debugWire.geometry.upload(camera.context3D);
}
debugWire.localToCameraTransform.copy(localToCameraTransform);
- debugWire.collectDraws(camera, null, 0);
+ debugWire.collectDraws(camera, null, 0, false);
}
}
}
@@ -567,9 +567,9 @@ package alternativa.engine3d.core {
island[i] = newFace;
island[j] = null;
face = newFace;
+ // TODO: comment to ENG
// Если, то собираться будет парами, иначе к одной прицепляется максимально (это чуть быстрее)
//if (pairWeld) break;
-
}
}
}
diff --git a/src/alternativa/engine3d/core/Renderer.as b/src/alternativa/engine3d/core/Renderer.as
index 3838ee8..0dec821 100644
--- a/src/alternativa/engine3d/core/Renderer.as
+++ b/src/alternativa/engine3d/core/Renderer.as
@@ -29,6 +29,8 @@ package alternativa.engine3d.core {
public static const OPAQUE:int = 20;
+ public static const OPAQUE_OVERHEAD:int = 25;
+
public static const DECALS:int = 30;
public static const TRANSPARENT_SORT:int = 40;
@@ -62,6 +64,9 @@ package alternativa.engine3d.core {
case OPAQUE:
_context3D.setDepthTest(true, Context3DCompareMode.LESS);
break;
+ case OPAQUE_OVERHEAD:
+ _context3D.setDepthTest(false, Context3DCompareMode.EQUAL);
+ break;
case DECALS:
_context3D.setDepthTest(false, Context3DCompareMode.LESS_EQUAL);
break;
diff --git a/src/alternativa/engine3d/effects/ParticlePrototype.as b/src/alternativa/engine3d/effects/ParticlePrototype.as
index cf3bda9..0c85c9d 100644
--- a/src/alternativa/engine3d/effects/ParticlePrototype.as
+++ b/src/alternativa/engine3d/effects/ParticlePrototype.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.effects {
import alternativa.engine3d.alternativa3d;
diff --git a/src/alternativa/engine3d/effects/ParticleSystem.as b/src/alternativa/engine3d/effects/ParticleSystem.as
index f0c7f42..70c469d 100644
--- a/src/alternativa/engine3d/effects/ParticleSystem.as
+++ b/src/alternativa/engine3d/effects/ParticleSystem.as
@@ -126,7 +126,7 @@ package alternativa.engine3d.effects {
return pause ? (stopTime - subtractiveTime) : (getTimer()*0.001 - subtractiveTime);
}
- override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int):void {
+ override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int, useShadow:Boolean):void {
// Create geometry and program
if (vertexBuffer == null) createAndUpload(camera.context3D);
// Average size
diff --git a/src/alternativa/engine3d/lights/OmniLight.as b/src/alternativa/engine3d/lights/OmniLight.as
index ee23aec..cb9b502 100644
--- a/src/alternativa/engine3d/lights/OmniLight.as
+++ b/src/alternativa/engine3d/lights/OmniLight.as
@@ -13,6 +13,8 @@ package alternativa.engine3d.lights {
import alternativa.engine3d.core.Light3D;
import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.core.Transform3D;
+ import alternativa.engine3d.shadows.OmniLightShadow;
+ import alternativa.engine3d.shadows.Shadow;
use namespace alternativa3d;
@@ -200,5 +202,14 @@ package alternativa.engine3d.lights {
return res;
}
+ /**
+ * @private
+ */
+ override public function set shadow(value:Shadow):void {
+ _shadow = value;
+ _shadow._light = this;
+ var omniShadow:OmniLightShadow = value as OmniLightShadow;
+ if (omniShadow!=null) omniShadow.setBoundSize(this.attenuationEnd*1.5);
+ }
}
}
diff --git a/src/alternativa/engine3d/loaders/Parser.as b/src/alternativa/engine3d/loaders/Parser.as
index d5aca3c..c3364c2 100644
--- a/src/alternativa/engine3d/loaders/Parser.as
+++ b/src/alternativa/engine3d/loaders/Parser.as
@@ -436,7 +436,6 @@ package alternativa.engine3d.loaders {
for each(a3DDirLight in a3d.directionalLights) {
var resDirLight:DirectionalLight = new DirectionalLight(a3DDirLight.color);
- resDirLight.intensity = resDirLight.intensity;
resDirLight.visible = a3DDirLight.visible;
resDirLight.name = a3DDirLight.name;
parents[resDirLight] = a3DDirLight.parentId;
diff --git a/src/alternativa/engine3d/loaders/Parser3DS.as b/src/alternativa/engine3d/loaders/Parser3DS.as
index d148da3..115bbea 100644
--- a/src/alternativa/engine3d/loaders/Parser3DS.as
+++ b/src/alternativa/engine3d/loaders/Parser3DS.as
@@ -44,7 +44,9 @@ package alternativa.engine3d.loaders {
private static const CHUNK_FACESMATERIAL:int = 0x4130;
private static const CHUNK_FACESSMOOTHGROUPS:int = 0x4150;
private static const CHUNK_MAPPINGCOORDS:int = 0x4140;
+ //private static const CHUNK_OBJECTCOLOR:int = 0x4165;
private static const CHUNK_TRANSFORMATION:int = 0x4160;
+ //private static const CHUNK_MESHANIMATION:int = 0xB002;
private static const CHUNK_MATERIAL:int = 0xAFFF;
private var data:ByteArray;
diff --git a/src/alternativa/engine3d/loaders/ParserMaterial.as b/src/alternativa/engine3d/loaders/ParserMaterial.as
index 0c12f7b..a41172a 100644
--- a/src/alternativa/engine3d/loaders/ParserMaterial.as
+++ b/src/alternativa/engine3d/loaders/ParserMaterial.as
@@ -81,7 +81,7 @@ package alternativa.engine3d.loaders {
/**
* @private
*/
- override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector., lightsLength:int, objectRenderPriority:int = -1):void {
+ override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector., lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void {
var colorO:Object = colors[renderChannel];
var map:ExternalTextureResource;
if (colorO != null) {
@@ -90,14 +90,14 @@ package alternativa.engine3d.loaders {
} else {
fillMaterial.color = int(colorO);
}
- fillMaterial.collectDraws(camera, surface, geometry, lights, lightsLength, objectRenderPriority);
+ fillMaterial.collectDraws(camera, surface, geometry, lights, lightsLength, false, objectRenderPriority);
} else if ((map = textures[renderChannel]) != null) {
if(textureMaterial == null) {
textureMaterial = new TextureMaterial(map);
} else {
textureMaterial.diffuseMap = map;
}
- textureMaterial.collectDraws(camera, surface, geometry, lights, lightsLength, objectRenderPriority);
+ textureMaterial.collectDraws(camera, surface, geometry, lights, lightsLength, false, objectRenderPriority);
}
}
diff --git a/src/alternativa/engine3d/loaders/collada/DaeController.as b/src/alternativa/engine3d/loaders/collada/DaeController.as
index c04600c..f6401da 100644
--- a/src/alternativa/engine3d/loaders/collada/DaeController.as
+++ b/src/alternativa/engine3d/loaders/collada/DaeController.as
@@ -138,6 +138,10 @@ package alternativa.engine3d.loaders.collada {
private function transformVertices(geometry:Geometry):void {
var data:ByteArray = geometry._vertexStreams[0].data;
var numMappings:int = geometry._vertexStreams[0].attributes.length;
+
+ var normalOffset:uint = geometry.getAttributeOffset(VertexAttributes.NORMAL);
+ var tangentOffset:uint = geometry.getAttributeOffset(VertexAttributes.TANGENT4);
+
for (var i:int = 0; i < geometry._numVertices; i++) {
data.position = 4*numMappings*i;
var x:Number = data.readFloat();
@@ -147,6 +151,26 @@ package alternativa.engine3d.loaders.collada {
data.writeFloat(x*bindShapeMatrix[0] + y*bindShapeMatrix[1] + z*bindShapeMatrix[2] + bindShapeMatrix[3]);
data.writeFloat(x*bindShapeMatrix[4] + y*bindShapeMatrix[5] + z*bindShapeMatrix[6] + bindShapeMatrix[7]);
data.writeFloat(x*bindShapeMatrix[8] + y*bindShapeMatrix[9] + z*bindShapeMatrix[10] + bindShapeMatrix[11]);
+
+ data.position = 4*(numMappings*i + normalOffset);
+ var normalX:Number = data.readFloat();
+ var normalY:Number = data.readFloat();
+ var normalZ:Number = data.readFloat();
+ data.position -= 12;
+
+ data.writeFloat(normalX*bindShapeMatrix[0] + normalY*bindShapeMatrix[1] + normalZ*bindShapeMatrix[2]);
+ data.writeFloat(normalX*bindShapeMatrix[4] + normalY*bindShapeMatrix[5] + normalZ*bindShapeMatrix[6]);
+ data.writeFloat(normalX*bindShapeMatrix[8] + normalY*bindShapeMatrix[9] + normalZ*bindShapeMatrix[10]);
+
+ data.position = 4*(numMappings*i + tangentOffset);
+ var tangentX:Number = data.readFloat();
+ var tangentY:Number = data.readFloat();
+ var tangentZ:Number = data.readFloat();
+ data.position -= 12;
+ data.writeFloat(tangentX*bindShapeMatrix[0] + tangentY*bindShapeMatrix[1] + tangentZ*bindShapeMatrix[2]);
+ data.writeFloat(tangentX*bindShapeMatrix[4] + tangentY*bindShapeMatrix[5] + tangentZ*bindShapeMatrix[6]);
+ data.writeFloat(tangentX*bindShapeMatrix[8] + tangentY*bindShapeMatrix[9] + tangentZ*bindShapeMatrix[10]);
+
}
}
@@ -399,7 +423,6 @@ package alternativa.engine3d.loaders.collada {
* Auxiliary joints will be added to the end of the vector, if it's necessary.
* @param parentNode Node of parent joint
* @param nodes Dictionary. Key is a node of joint. And value is an index of joint in animatedJoints vector
- *
*/
private function addJointChildren(parent:Joint, animatedJoints:Vector., parentNode:DaeNode, nodes:Dictionary):void {
var object:DaeObject;
@@ -462,7 +485,6 @@ package alternativa.engine3d.loaders.collada {
* Returns true if joint hasn't parent joint.
* @param node Joint node
* @param nodes Dictionary. It items are the nodes keys.
- *
*/
private function isRootJointNode(node:DaeNode, nodes:Dictionary):Boolean {
for (var parent:DaeNode = node.parent; parent != null; parent = parent.parent) {
diff --git a/src/alternativa/engine3d/loaders/collada/DaeVertices.as b/src/alternativa/engine3d/loaders/collada/DaeVertices.as
index 2cc81ca..ba37e37 100644
--- a/src/alternativa/engine3d/loaders/collada/DaeVertices.as
+++ b/src/alternativa/engine3d/loaders/collada/DaeVertices.as
@@ -21,7 +21,7 @@ package alternativa.engine3d.loaders.collada {
/**
* Source of vertex coordinates data. Stores coordinates in numbers array.
- *stride property of source is not less than three.
+ * stride property of source is not less than three.
* Call parse() before using.
*/
public var positions:DaeSource;
diff --git a/src/alternativa/engine3d/materials/EnvironmentMaterial.as b/src/alternativa/engine3d/materials/EnvironmentMaterial.as
index 02c7ec8..d1e8478 100644
--- a/src/alternativa/engine3d/materials/EnvironmentMaterial.as
+++ b/src/alternativa/engine3d/materials/EnvironmentMaterial.as
@@ -189,6 +189,7 @@ package alternativa.engine3d.materials {
crsInSpace,
"mul t1.xyz, t1.xyz, i0.w",
// Transpose normal matrix
+ // TODO: can be optimized like in StandardMaterial
"mov v0.x, i0.x",
"mov v0.y, t1.x",
"mov v0.z, i1.x",
@@ -807,7 +808,7 @@ package alternativa.engine3d.materials {
/**
* @private
*/
- override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector., lightsLength:int, objectRenderPriority:int = -1):void {
+ 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) return;
if (_environmentMap == null || _environmentMap._texture == null || !(_environmentMap._texture is CubeTexture)) return;
if (opacityMap != null && opacityMap._texture == null) return;
diff --git a/src/alternativa/engine3d/materials/FillMaterial.as b/src/alternativa/engine3d/materials/FillMaterial.as
index b8383ca..9a031bf 100644
--- a/src/alternativa/engine3d/materials/FillMaterial.as
+++ b/src/alternativa/engine3d/materials/FillMaterial.as
@@ -96,7 +96,7 @@ package alternativa.engine3d.materials {
/**
* @private
*/
- override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector., lightsLength:int, objectRenderPriority:int = -1):void {
+ 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;
// Strams
var positionBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.POSITION);
diff --git a/src/alternativa/engine3d/materials/LightMapMaterial.as b/src/alternativa/engine3d/materials/LightMapMaterial.as
index e90e7f2..c48c978 100644
--- a/src/alternativa/engine3d/materials/LightMapMaterial.as
+++ b/src/alternativa/engine3d/materials/LightMapMaterial.as
@@ -186,7 +186,7 @@ package alternativa.engine3d.materials {
/**
* @private
*/
- override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector., lightsLength:int, objectRenderPriority:int = -1):void {
+ override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector., lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void {
if (diffuseMap == null || lightMap == null || diffuseMap._texture == null || lightMap._texture == null) return;
if (opacityMap != null && opacityMap._texture == null) return;
diff --git a/src/alternativa/engine3d/materials/Material.as b/src/alternativa/engine3d/materials/Material.as
index 6f8d74f..47a34e3 100644
--- a/src/alternativa/engine3d/materials/Material.as
+++ b/src/alternativa/engine3d/materials/Material.as
@@ -89,7 +89,7 @@ package alternativa.engine3d.materials {
/**
* @private
*/
- alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector., lightsLength:int, objectRenderPriority:int = -1):void {
+ alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector., lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void {
}
/**
diff --git a/src/alternativa/engine3d/materials/StandardMaterial.as b/src/alternativa/engine3d/materials/StandardMaterial.as
index 34b5198..018a952 100644
--- a/src/alternativa/engine3d/materials/StandardMaterial.as
+++ b/src/alternativa/engine3d/materials/StandardMaterial.as
@@ -56,6 +56,7 @@ package alternativa.engine3d.materials {
private static var caches:Dictionary = new Dictionary(true);
private var cachedContext3D:Context3D;
private var programsCache:Dictionary;
+ private var groups:Vector.> = new Vector.>();
/**
* @private
@@ -133,19 +134,16 @@ package alternativa.engine3d.materials {
// Calculate binormal
crsInSpace,
"mul t1.xyz, t1.xyz, i0.w",
- // Transpose normal matrix
+ // Транспонируем матрицу нормалей
+ "mov v0.xyzw, i1.xyxw",
"mov v0.x, i0.x",
"mov v0.y, t1.x",
- "mov v0.z, i1.x",
- "mov v0.w, i1.w",
+ "mov v1.xyzw, i1.xyyw",
"mov v1.x, i0.y",
"mov v1.y, t1.y",
- "mov v1.z, i1.y",
- "mov v1.w, i1.w",
+ "mov v2.xyzw, i1.xyzw",
"mov v2.x, i0.z",
- "mov v2.y, t1.z",
- "mov v2.z, i1.z",
- "mov v2.w, i1.w"
+ "mov v2.y, t1.z"
], "passTBNProcedure");
}
@@ -427,10 +425,9 @@ package alternativa.engine3d.materials {
"sat t0.x, t0.x",
];
if (useShadow) {
- source.push("mul t0.x, t0.x, i2.x");
+ source.push("mul t0.xw, t0.xw, i2.x");
source.push("mul t0.xyz, c1.xyz, t0.xxx");
source.push("add o0.xyz, t0.xyz, i3.xyz");
- source.push("mul t0.w, i2.x, t0.w");
source.push("mul o1.xyz, c1.xyz, t0.www");
} else {
// Apply calculated values
@@ -442,16 +439,89 @@ package alternativa.engine3d.materials {
procedure.compileFromArray(source);
}
+ private function formOmniProcedure(procedure:Procedure, light:Light3D, useShadow:Boolean):void {
+// fragmentLinker.setInputParams(omniMulShadowProcedure, "tNormal", "tViewVector", "tTotalLight", "cAmbientColor");
+ var source:Array = [
+ "#c0=c" + light.lightID + "Position",
+ "#c1=c" + light.lightID + "Color",
+ "#c2=c" + light.lightID + "Radius",
+ "#v0=vPosition"
+ ];
+ if (useShadow) {
+ // Считаем вектор из точки к свету
+ source.push("sub t0, c0, v0"); // L = lightPos - PointPos
+ source.push("dp3 t0.w, t0.xyz, t0.xyz"); // lenSqr
+ source.push("nrm t0.xyz, t0.xyz"); // L = normalize(L)
+ // Считаем half-way вектор
+ source.push("add t1.xyz, i1.xyz, t0.xyz");
+ source.push("nrm t1.xyz, t1.xyz");
+ // Считаем блик
+ source.push("dp3 t1.w, t1.xyz, i0.xyz");
+ source.push("pow t1.w, t1.w, o1.w");
+ // Считаем расстояние до источника света
+ source.push("sqt t1.x, t0.w"); // len = sqt(lensqr)
+ // Считаем свет
+ source.push("dp3 t0.w, t0.xyz, i0.xyz"); // dot = dot(normal, L)
+ // Считаем затухание
+ source.push("sub t0.x, t1.x, c2.z"); // len = len - atenuationBegin
+ source.push("div t0.y, t0.x, c2.y"); // att = len/radius
+ source.push("sub t0.x, c2.x, t0.y"); // att = 1 - len/radius
+ source.push("sat t0.xw, t0.xw"); // t = max(t, 0)
+
+ // i3 - ambient
+ // i2 - shadow-test
+
+ source.push("mul t0.xw, t0.xw, i2.xw");
+ source.push("mul t0.xyz, c1.xyz, t0.xxx"); // t = color*t
+ source.push("mul t1.xyz, t0.xyz, t1.w");
+ source.push("add o1.xyz, o1.xyz, t1.xyz");
+ source.push("mul t0.xyz, t0.xyz, t0.www");
+ source.push("add o0.xyz, t0.xyz, i3.xyz");
+
+ } else {
+
+ // Считаем вектор из точки к свету
+ source.push("sub t0, c0, v0"); // L = lightPos - PointPos
+ source.push("dp3 t0.w, t0.xyz, t0.xyz"); // lenSqr
+ source.push("nrm t0.xyz, t0.xyz"); // L = normalize(L)
+ // Считаем half-way вектор
+ source.push("add t1.xyz, i1.xyz, t0.xyz");
+ source.push("mov t1.w, c0.w");
+ source.push("nrm t1.xyz, t1.xyz");
+ // Считаем блик
+ source.push("dp3 t1.w, t1.xyz, i0.xyz");
+ source.push("pow t1.w, t1.w, o1.w"); //!!!
+ // Считаем расстояние до источника света
+ source.push("sqt t1.x, t0.w"); // len = sqt(lensqr)
+ // Считаем свет
+ source.push("dp3 t0.w, t0.xyz, i0.xyz"); // dot = dot(normal, L)
+ // Считаем затухание
+ source.push("sub t0.x, t1.x, c2.z"); // len = len - atenuationBegin
+ source.push("div t0.y, t0.x, c2.y"); // att = len/radius
+ source.push("sub t0.x, c2.x, t0.y"); // att = 1 - len/radius
+ source.push("sat t0.xw, t0.xw"); // t = max(t, 0)
+
+ // Перемножаем цвет источника с затуханием
+ source.push("mul t0.xyz, c1.xyz, t0.xxx"); // t = color*t
+ source.push("mul t1.xyz, t0.xyz, t1.w");
+ source.push("add o1.xyz, o1.xyz, t1.xyz");
+ source.push("mul t0.xyz, t0.xyz, t0.www");
+ source.push("add o0.xyz, o0.xyz, t0.xyz");
+ }
+
+ procedure.compileFromArray(source);
+ }
+
/**
* @param object
* @param materialKey
* @param opacityMap
* @param alphaTest 0:disabled 1:alpha-test 2:contours
- * @param lights
+ * @param lightsGroup
* @param directionalLight
* @param lightsLength
*/
- private function getProgram(object:Object3D, programs:Dictionary, camera:Camera3D, materialKey:String, opacityMap:TextureResource, alphaTest:int, lights:Vector., lightsLength:int, shadowedLight:Light3D):ShaderProgram {
+ private function getProgram(object:Object3D, programs:Dictionary, camera:Camera3D, materialKey:String, opacityMap:TextureResource, alphaTest:int, lightsGroup:Vector., lightsLength:int, isFirstGroup:Boolean, shadowedLight:Light3D):ShaderProgram {
var key:String = materialKey + (opacityMap != null ? "O" : "o") + alphaTest.toString();
var program:ShaderProgram = programs[key];
if (program == null) {
@@ -459,13 +529,34 @@ package alternativa.engine3d.materials {
var fragmentLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
var i:int;
+ // Merge program using lightsGroup
+ // add property useShadow
+
fragmentLinker.declareVariable("tTotalLight");
fragmentLinker.declareVariable("tTotalHighLight");
fragmentLinker.declareVariable("tNormal");
- fragmentLinker.declareVariable("cAmbientColor", VariableType.CONSTANT);
- fragmentLinker.addProcedure(_ambientLightProcedure);
- fragmentLinker.setInputParams(_ambientLightProcedure, "cAmbientColor");
- fragmentLinker.setOutputParams(_ambientLightProcedure, "tTotalLight", "tTotalHighLight");
+
+ if (isFirstGroup){
+ fragmentLinker.declareVariable("cAmbientColor", VariableType.CONSTANT);
+ fragmentLinker.addProcedure(_ambientLightProcedure);
+ fragmentLinker.setInputParams(_ambientLightProcedure, "cAmbientColor");
+ fragmentLinker.setOutputParams(_ambientLightProcedure, "tTotalLight", "tTotalHighLight");
+
+ if (lightMap != null) {
+ vertexLinker.addProcedure(_passLightMapUVProcedure);
+ fragmentLinker.addProcedure(_addLightMapProcedure);
+ fragmentLinker.setInputParams(_addLightMapProcedure, "tTotalLight");
+ fragmentLinker.setOutputParams(_addLightMapProcedure, "tTotalLight");
+ }
+ }
+ else{
+ // сбросить tTotalLight tTotalHighLight
+ fragmentLinker.declareVariable("cAmbientColor", VariableType.CONSTANT);
+ fragmentLinker.addProcedure(_ambientLightProcedure);
+ fragmentLinker.setInputParams(_ambientLightProcedure, "cAmbientColor");
+ fragmentLinker.setOutputParams(_ambientLightProcedure, "tTotalLight", "tTotalHighLight");
+ }
+
var positionVar:String = "aPosition";
var normalVar:String = "aNormal";
var tangentVar:String = "aTangent";
@@ -488,7 +579,8 @@ package alternativa.engine3d.materials {
fragmentLinker.addProcedure(_setGlossinessFromConstantProcedure);
fragmentLinker.setOutputParams(_setGlossinessFromConstantProcedure, "tTotalHighLight");
}
- if (lightsLength > 0) {
+
+ if (lightsLength > 0 || shadowedLight) {
var procedure:Procedure;
if (object.deltaTransformProcedure != null) {
vertexLinker.declareVariable("tTransformedNormal");
@@ -519,25 +611,44 @@ package alternativa.engine3d.materials {
fragmentLinker.addProcedure(_getNormalAndViewObjectProcedure);
fragmentLinker.setOutputParams(_getNormalAndViewObjectProcedure, "tNormal", "tViewVector");
}
- if (shadowedLight != null && shadowedLight is DirectionalLight) {
- vertexLinker.addProcedure(shadowedLight.shadow.vertexShadowProcedure, positionVar);
- var shadowProc:Procedure = shadowedLight.shadow.fragmentShadowProcedure;
- fragmentLinker.addProcedure(shadowProc);
- fragmentLinker.setOutputParams(shadowProc, "tTotalLight");
+ if (shadowedLight != null) {
+ var shadowProc:Procedure;
+ if (shadowedLight is DirectionalLight){
+ vertexLinker.addProcedure(shadowedLight.shadow.vertexShadowProcedure, positionVar);
+ shadowProc = shadowedLight.shadow.fragmentShadowProcedure;
+ fragmentLinker.addProcedure(shadowProc);
+ fragmentLinker.setOutputParams(shadowProc, "tTotalLight");
- var dirMulShadowProcedure:Procedure = _lightFragmentProcedures[shadowedLight.shadow];
- if (dirMulShadowProcedure == null) {
- dirMulShadowProcedure = new Procedure();
- formDirectionalProcedure(dirMulShadowProcedure, shadowedLight, true);
+ var dirMulShadowProcedure:Procedure = _lightFragmentProcedures[shadowedLight.shadow];
+ if (dirMulShadowProcedure == null) {
+ dirMulShadowProcedure = new Procedure();
+ formDirectionalProcedure(dirMulShadowProcedure, shadowedLight, true);
+ }
+ fragmentLinker.addProcedure(dirMulShadowProcedure);
+ fragmentLinker.setInputParams(dirMulShadowProcedure, "tNormal", "tViewVector", "tTotalLight", "cAmbientColor");
+ fragmentLinker.setOutputParams(dirMulShadowProcedure, "tTotalLight", "tTotalHighLight");
+ }
+
+ if (shadowedLight is OmniLight){
+ vertexLinker.addProcedure(shadowedLight.shadow.vertexShadowProcedure, positionVar);
+ shadowProc = shadowedLight.shadow.fragmentShadowProcedure;
+ fragmentLinker.addProcedure(shadowProc);
+ fragmentLinker.setOutputParams(shadowProc, "tTotalLight");
+
+ var omniMulShadowProcedure:Procedure = _lightFragmentProcedures[shadowedLight.shadow];
+ if (omniMulShadowProcedure == null) {
+ omniMulShadowProcedure= new Procedure();
+ formOmniProcedure(omniMulShadowProcedure, shadowedLight, true);
+ }
+ fragmentLinker.addProcedure(omniMulShadowProcedure);
+ fragmentLinker.setInputParams(omniMulShadowProcedure, "tNormal", "tViewVector", "tTotalLight", "cAmbientColor");
+ fragmentLinker.setOutputParams(omniMulShadowProcedure, "tTotalLight", "tTotalHighLight");
}
- fragmentLinker.addProcedure(dirMulShadowProcedure);
- fragmentLinker.setInputParams(dirMulShadowProcedure, "tNormal", "tViewVector", "tTotalLight", "cAmbientColor");
- fragmentLinker.setOutputParams(dirMulShadowProcedure, "tTotalLight", "tTotalHighLight");
}
for (i = 0; i < lightsLength; i++) {
- var light:Light3D = lights[i];
- if (light == shadowedLight) continue;
+ var light:Light3D = lightsGroup[i];
+ if (light == shadowedLight && (shadowedLight is DirectionalLight || shadowedLight is OmniLight)) continue;
var lightFragmentProcedure:Procedure = _lightFragmentProcedures[light];
if (lightFragmentProcedure == null) {
lightFragmentProcedure = new Procedure();
@@ -546,38 +657,7 @@ package alternativa.engine3d.materials {
formDirectionalProcedure(lightFragmentProcedure, light, false);
lightFragmentProcedure.name += "Directional";
} else if (light is OmniLight) {
- lightFragmentProcedure.compileFromArray([
- "#c0=c" + light.lightID + "Position",
- "#c1=c" + light.lightID + "Color",
- "#c2=c" + light.lightID + "Radius",
- "#v0=vPosition",
- // Calculate vector from the point to light
- "sub t0, c0, v0", // L = lightPos - PointPos
- "dp3 t0.w, t0.xyz, t0.xyz", // lenSqr
- "nrm t0.xyz, t0.xyz", // L = normalize(L)
- // Calculate half-way vector
- "add t1.xyz, i1.xyz, t0.xyz",
- "mov t1.w, c0.w",
- "nrm t1.xyz, t1.xyz",
- // Calculate a flare
- "dp3 t1.w, t1.xyz, i0.xyz",
- "pow t1.w, t1.w, o1.w",
- // Calculate distance to the light source
- "sqt t1.x, t0.w", // len = sqt(lensqr)
- // Calculate light
- "dp3 t0.w, t0.xyz, i0.xyz", // dot = dot(normal, L)
- // Calculate decay
- "sub t0.x, t1.x, c2.z", // len = len - atenuationBegin
- "div t0.y, t0.x, c2.y", // att = len/radius
- "sub t0.x, c2.x, t0.y", // att = 1 - len/radius
- "sat t0.xw, t0.xw", // t = max(t, 0)
- // Multiply light color with the decay value
- "mul t0.xyz, c1.xyz, t0.xxx", // t = color*t
- "mul t1.xyz, t0.xyz, t1.w",
- "add o1.xyz, o1.xyz, t1.xyz",
- "mul t0.xyz, t0.xyz, t0.www",
- "add o0.xyz, o0.xyz, t0.xyz"
- ]);
+ formOmniProcedure(lightFragmentProcedure, light, false);
lightFragmentProcedure.name += "Omni";
} else if (light is SpotLight) {
lightFragmentProcedure.compileFromArray([
@@ -628,13 +708,7 @@ package alternativa.engine3d.materials {
fragmentLinker.setOutputParams(_applySpecularProcedure, "tTotalHighLight");
outputProcedure = _applySpecularProcedure;
}
- if (lightMap != null) {
- vertexLinker.addProcedure(_passLightMapUVProcedure);
- fragmentLinker.addProcedure(_addLightMapProcedure);
- fragmentLinker.setInputParams(_addLightMapProcedure, "tTotalLight");
- fragmentLinker.setOutputParams(_addLightMapProcedure, "tTotalLight");
- }
-
+
fragmentLinker.declareVariable("tColor");
outputProcedure = opacityMap != null ? getDiffuseOpacityProcedure : getDiffuseProcedure;
fragmentLinker.addProcedure(outputProcedure);
@@ -648,37 +722,37 @@ package alternativa.engine3d.materials {
fragmentLinker.addProcedure(_mulLightingProcedure, "tColor", "tTotalLight", "tTotalHighLight");
-
- if (fogMode == SIMPLE || fogMode == ADVANCED) {
- fragmentLinker.setOutputParams(_mulLightingProcedure, "tColor");
- }
- if (fogMode == SIMPLE) {
- vertexLinker.addProcedure(passSimpleFogConstProcedure);
- vertexLinker.setInputParams(passSimpleFogConstProcedure, positionVar);
- fragmentLinker.addProcedure(outputWithSimpleFogProcedure);
- fragmentLinker.setInputParams(outputWithSimpleFogProcedure, "tColor");
- outputProcedure = outputWithSimpleFogProcedure;
- } else if (fogMode == ADVANCED) {
- vertexLinker.declareVariable("tProjected");
- vertexLinker.setOutputParams(_projectProcedure, "tProjected");
- vertexLinker.addProcedure(postPassAdvancedFogConstProcedure);
- vertexLinker.setInputParams(postPassAdvancedFogConstProcedure, positionVar, "tProjected");
- fragmentLinker.addProcedure(outputWithAdvancedFogProcedure);
- fragmentLinker.setInputParams(outputWithAdvancedFogProcedure, "tColor");
- outputProcedure = outputWithAdvancedFogProcedure;
- }
+
+// if (fogMode == SIMPLE || fogMode == ADVANCED) {
+// fragmentLinker.setOutputParams(_mulLightingProcedure, "tColor");
+// }
+// if (fogMode == SIMPLE) {
+// vertexLinker.addProcedure(passSimpleFogConstProcedure);
+// vertexLinker.setInputParams(passSimpleFogConstProcedure, positionVar);
+// fragmentLinker.addProcedure(outputWithSimpleFogProcedure);
+// fragmentLinker.setInputParams(outputWithSimpleFogProcedure, "tColor");
+// outputProcedure = outputWithSimpleFogProcedure;
+// } else if (fogMode == ADVANCED) {
+// vertexLinker.declareVariable("tProjected");
+// vertexLinker.setOutputParams(_projectProcedure, "tProjected");
+// vertexLinker.addProcedure(postPassAdvancedFogConstProcedure);
+// vertexLinker.setInputParams(postPassAdvancedFogConstProcedure, positionVar, "tProjected");
+// fragmentLinker.addProcedure(outputWithAdvancedFogProcedure);
+// fragmentLinker.setInputParams(outputWithAdvancedFogProcedure, "tColor");
+// outputProcedure = outputWithAdvancedFogProcedure;
+// }
fragmentLinker.varyings = vertexLinker.varyings;
program = new ShaderProgram(vertexLinker, fragmentLinker);
-
program.upload(camera.context3D);
programs[key] = program;
}
return program;
}
- private function getDrawUnit(program:ShaderProgram, camera:Camera3D, surface:Surface, geometry:Geometry, opacityMap:TextureResource, lights:Vector., lightsLength:int, shadowedLight:Light3D):DrawUnit {
+ // TODO: return not neccessary more
+ private function getDrawUnit(program:ShaderProgram, camera:Camera3D, surface:Surface, geometry:Geometry, opacityMap:TextureResource, lights:Vector., lightsLength:int, isFirstGroup:Boolean, shadowedLight:Light3D, opaqueOption:Boolean, transparentOption:Boolean, objectRenderPriority:int):DrawUnit {
// Buffers
var positionBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.POSITION);
var uvBuffer:VertexBuffer3D = geometry.getVertexBuffer(VertexAttributes.TEXCOORDS[0]);
@@ -701,7 +775,7 @@ package alternativa.engine3d.materials {
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cSurface"), 0, glossiness, specularPower, 1);
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cThresholdAlpha"), alphaThreshold, 0, 0, alpha);
- if (lightsLength > 0) {
+ if (lightsLength > 0 || shadowedLight) {
if (_normalMapSpace == NormalMapSpace.TANGENT_RIGHT_HANDED || _normalMapSpace == NormalMapSpace.TANGENT_LEFT_HANDED) {
drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aNormal"), normalsBuffer, geometry._attributesOffsets[VertexAttributes.NORMAL], VertexAttributes.FORMATS[VertexAttributes.NORMAL]);
drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aTangent"), tangentsBuffer, geometry._attributesOffsets[VertexAttributes.TANGENT4], VertexAttributes.FORMATS[VertexAttributes.TANGENT4]);
@@ -750,6 +824,40 @@ package alternativa.engine3d.materials {
}
}
+ if (shadowedLight){
+ var light:Light3D = shadowedLight;
+ if (light is DirectionalLight) {
+ transform = light.lightToObjectTransform;
+ var len:Number = Math.sqrt(transform.c*transform.c + transform.g*transform.g + transform.k*transform.k);
+ drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + light.lightID + "Direction"), -transform.c/len, -transform.g/len, -transform.k/len, 1);
+ drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + light.lightID + "Color"), light.red, light.green, light.blue);
+ } else if (light is OmniLight) {
+ var omni:OmniLight = light as OmniLight;
+ transform = light.lightToObjectTransform;
+ rScale = Math.sqrt(transform.a*transform.a + transform.e*transform.e + transform.i*transform.i);
+ rScale += Math.sqrt(transform.b*transform.b + transform.f*transform.f + transform.j*transform.j);
+ rScale += Math.sqrt(transform.c*transform.c + transform.g*transform.g + transform.k*transform.k);
+ rScale /= 3;
+ drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + light.lightID + "Position"), transform.d, transform.h, transform.l);
+ drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + light.lightID + "Radius"), 1, omni.attenuationEnd*rScale - omni.attenuationBegin*rScale, omni.attenuationBegin*rScale);
+ drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + light.lightID + "Color"), light.red, light.green, light.blue);
+ } else if (light is SpotLight) {
+ var spot:SpotLight = light as SpotLight;
+ transform = light.lightToObjectTransform;
+ rScale = Math.sqrt(transform.a*transform.a + transform.e*transform.e + transform.i*transform.i);
+ rScale += Math.sqrt(transform.b*transform.b + transform.f*transform.f + transform.j*transform.j);
+ rScale += len = Math.sqrt(transform.c*transform.c + transform.g*transform.g + transform.k*transform.k);
+ rScale /= 3;
+ var falloff:Number = Math.cos(spot.falloff*0.5);
+ var hotspot:Number = Math.cos(spot.hotspot*0.5);
+
+ drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + light.lightID + "Position"), transform.d, transform.h, transform.l);
+ drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + light.lightID + "Axis"), -transform.c/len, -transform.g/len, -transform.k/len);
+ drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + light.lightID + "Radius"), spot.attenuationEnd*rScale - spot.attenuationBegin*rScale, spot.attenuationBegin*rScale, hotspot == falloff ? 0.000001 : hotspot - falloff, falloff);
+ drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + light.lightID + "Color"), light.red, light.green, light.blue);
+ }
+ }
+
// Textures
drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sDiffuse"), diffuseMap._texture);
if (opacityMap != null) {
@@ -762,69 +870,104 @@ package alternativa.engine3d.materials {
drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sSpecular"), specularMap._texture);
}
- if (lightMap != null) {
- drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aUV1"),
- geometry.getVertexBuffer(VertexAttributes.TEXCOORDS[lightMapChannel]),
- geometry._attributesOffsets[VertexAttributes.TEXCOORDS[lightMapChannel]],
- Context3DVertexBufferFormat.FLOAT_2);
+
+ if (isFirstGroup){
+ if (lightMap != null) {
+ drawUnit.setVertexBufferAt(program.vertexShader.getVariableIndex("aUV1"),
+ geometry.getVertexBuffer(VertexAttributes.TEXCOORDS[lightMapChannel]),
+ geometry._attributesOffsets[VertexAttributes.TEXCOORDS[lightMapChannel]],
+ Context3DVertexBufferFormat.FLOAT_2);
+ drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cAmbientColor"), 0,0,0, 1);
+ drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sLightMap"), lightMap._texture);
+ } else {
+ drawUnit.setFragmentConstantsFromVector(program.fragmentShader.getVariableIndex("cAmbientColor"), camera.ambient, 1);
+ }
+ }
+ else{
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cAmbientColor"), 0,0,0, 1);
- drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sLightMap"), lightMap._texture);
- } else {
- drawUnit.setFragmentConstantsFromVector(program.fragmentShader.getVariableIndex("cAmbientColor"), camera.ambient, 1);
}
setPassUVProcedureConstants(drawUnit, program.vertexShader);
- if (shadowedLight != null && shadowedLight is DirectionalLight) {
+ if (shadowedLight != null && ((shadowedLight is DirectionalLight)||(shadowedLight is OmniLight))) {
shadowedLight.shadow.setup(drawUnit, program.vertexShader, program.fragmentShader, surface);
}
- if (fogMode == SIMPLE || fogMode == ADVANCED) {
- var lm:Transform3D = object.localToCameraTransform;
- var dist:Number = fogFar - fogNear;
- drawUnit.setVertexConstantsFromNumbers(program.vertexShader.getVariableIndex("cFogSpace"), lm.i/dist, lm.j/dist, lm.k/dist, (lm.l - fogNear)/dist);
- drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cFogRange"), fogMaxDensity, 1, 0, 1 - fogMaxDensity);
- }
- if (fogMode == SIMPLE) {
- drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cFogColor"), fogColorR, fogColorG, fogColorB);
- }
- if (fogMode == ADVANCED) {
- if (fogTexture == null) {
- var bmd:BitmapData = new BitmapData(32, 1, false, 0xFF0000);
- for (i = 0; i < 32; i++) {
- bmd.setPixel(i, 0, ((i/32)*255) << 16);
- }
- fogTexture = new BitmapTextureResource(bmd);
- fogTexture.upload(camera.context3D);
- }
- var cLocal:Transform3D = camera.localToGlobalTransform;
- var halfW:Number = camera.view.width/2;
- var leftX:Number = -halfW*cLocal.a + camera.focalLength*cLocal.c;
- var leftY:Number = -halfW*cLocal.e + camera.focalLength*cLocal.g;
- var rightX:Number = halfW*cLocal.a + camera.focalLength*cLocal.c;
- var rightY:Number = halfW*cLocal.e + camera.focalLength*cLocal.g;
- // Finding UV
- var angle:Number = (Math.atan2(leftY, leftX) - Math.PI/2);
- if (angle < 0) angle += Math.PI*2;
- var dx:Number = rightX - leftX;
- var dy:Number = rightY - leftY;
- var lens:Number = Math.sqrt(dx*dx + dy*dy);
- leftX /= lens;
- leftY /= lens;
- rightX /= lens;
- rightY /= lens;
- var uScale:Number = Math.acos(leftX*rightX + leftY*rightY)/Math.PI/2;
- var uRight:Number = angle/Math.PI/2;
- drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cFogConsts"), 0.5*uScale, 0.5 - uRight, 0);
- drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sFogTexture"), fogTexture._texture);
+ // Inititalizing render properties
+ if (opaqueOption)
+ // Use z-buffer within DrawCall, draws without blending
+ if (isFirstGroup){
+ drawUnit.blendSource = Context3DBlendFactor.ONE;
+ drawUnit.blendDestination = Context3DBlendFactor.ZERO;
+ camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.OPAQUE);
+ }
+ else{
+ drawUnit.blendSource = Context3DBlendFactor.ONE;
+ drawUnit.blendDestination = Context3DBlendFactor.ONE;
+ camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.OPAQUE_OVERHEAD);
+ }
+
+ if (transparentOption){
+ // Do not use z-buffer, draws with blending
+ if (isFirstGroup){
+ drawUnit.blendSource = Context3DBlendFactor.SOURCE_ALPHA;
+ drawUnit.blendDestination = Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA;
+ }
+ else{
+ drawUnit.blendSource = Context3DBlendFactor.SOURCE_ALPHA;
+ drawUnit.blendDestination = Context3DBlendFactor.ONE;
+ }
+ camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.TRANSPARENT_SORT);
}
+
+
+// if (fogMode == SIMPLE || fogMode == ADVANCED) {
+// var lm:Transform3D = object.localToCameraTransform;
+// var dist:Number = fogFar - fogNear;
+// drawUnit.setVertexConstantsFromNumbers(program.vertexShader.getVariableIndex("cFogSpace"), lm.i/dist, lm.j/dist, lm.k/dist, (lm.l - fogNear)/dist);
+// drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cFogRange"), fogMaxDensity, 1, 0, 1 - fogMaxDensity);
+// }
+// if (fogMode == SIMPLE) {
+// drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cFogColor"), fogColorR, fogColorG, fogColorB);
+// }
+// if (fogMode == ADVANCED) {
+// if (fogTexture == null) {
+// var bmd:BitmapData = new BitmapData(32, 1, false, 0xFF0000);
+// for (i = 0; i < 32; i++) {
+// bmd.setPixel(i, 0, ((i/32)*255) << 16);
+// }
+// fogTexture = new BitmapTextureResource(bmd);
+// fogTexture.upload(camera.context3D);
+// }
+// var cLocal:Transform3D = camera.localToGlobalTransform;
+// var halfW:Number = camera.view.width/2;
+// var leftX:Number = -halfW*cLocal.a + camera.focalLength*cLocal.c;
+// var leftY:Number = -halfW*cLocal.e + camera.focalLength*cLocal.g;
+// var rightX:Number = halfW*cLocal.a + camera.focalLength*cLocal.c;
+// var rightY:Number = halfW*cLocal.e + camera.focalLength*cLocal.g;
+// // Finding UV
+// var angle:Number = (Math.atan2(leftY, leftX) - Math.PI/2);
+// if (angle < 0) angle += Math.PI*2;
+// var dx:Number = rightX - leftX;
+// var dy:Number = rightY - leftY;
+// var lens:Number = Math.sqrt(dx*dx + dy*dy);
+// leftX /= lens;
+// leftY /= lens;
+// rightX /= lens;
+// rightY /= lens;
+// var uScale:Number = Math.acos(leftX*rightX + leftY*rightY)/Math.PI/2;
+// var uRight:Number = angle/Math.PI/2;
+//
+// drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cFogConsts"), 0.5*uScale, 0.5 - uRight, 0);
+// drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sFogTexture"), fogTexture._texture);
+// }
return drawUnit;
}
/**
* @private
*/
- override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector., lightsLength:int, objectRenderPriority:int = -1):void {
+ override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector., lightsLength:int, useShadow:Boolean, objectRenderPriority:int = -1):void {
if (diffuseMap == null || normalMap == null || diffuseMap._texture == null || normalMap._texture == null) return;
// 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;
@@ -839,26 +982,12 @@ package alternativa.engine3d.materials {
if (positionBuffer == null || uvBuffer == null) return;
+ var i:int;
+
if (lightsLength > 0 && (_normalMapSpace == NormalMapSpace.TANGENT_RIGHT_HANDED || _normalMapSpace == NormalMapSpace.TANGENT_LEFT_HANDED)) {
if (normalsBuffer == null || tangentsBuffer == null) return;
}
- // Make shared part of the key.
- var materialKey:String = (fogMode.toString()) +
- ((lightMap != null) ? "L" : "l") +
- (_normalMapSpace.toString()) +
- ((glossinessMap != null) ? "G" : "g") +
- ((specularMap != null) ? "S" : "s");
- var shadowedLight:Light3D;
- for (var i:int = 0; i < lightsLength; i++) {
- var light:Light3D = lights[i];
- if (light.shadow != null && shadowedLight == null) {
- shadowedLight = light;
- materialKey += light.shadow.type;
- }
- materialKey += light.lightID;
- }
-
// Refresh programs for this context.
if (camera.context3D != cachedContext3D) {
cachedContext3D = camera.context3D;
@@ -875,40 +1004,170 @@ package alternativa.engine3d.materials {
programsCache[object.transformProcedure] = optionsPrograms;
}
+
+ // Form groups
+ var groupsCount:int = groups.length = 0;
+ var firstGroup:Vector. = new Vector.();
+ var shadowGroup:Vector. = new Vector.();
+ var firstGroupLength:int = 0;
+ for (i = 0; i < lightsLength; i++) {
+ var light:Light3D = lights[i];
+ if (light.shadow!=null && useShadow){
+ shadowGroup.push(light);
+ }
+ else{
+ if (firstGroupLength==6){
+ groups[groupsCount++] = firstGroup;
+ firstGroup = new Vector.();
+ firstGroupLength = 0;
+ }
+ firstGroup[firstGroupLength++] = light;
+ }
+ }
+ if (firstGroupLength!=0){
+ groups[groupsCount++] = firstGroup;
+ }
+ var shadowGroupLength:int = shadowGroup.length;
+
+ // Iterate groups
+ var materialKey:String;
var program:ShaderProgram;
var drawUnit:DrawUnit;
- // Opaque pass
- if (opaquePass && alphaThreshold <= alpha) {
- if (alphaThreshold > 0) {
- // Alpha test
+
+ if (groupsCount==0 && shadowGroupLength==0){
+ // There is only Ambient light on the scene
+ // Form key
+ materialKey = (lightMap != null) ? "L" : "l"+
+ ((glossinessMap != null) ? "G" : "g") +
+ ((specularMap != null) ? "S" : "s");
+
+ if (opaquePass && alphaThreshold <= alpha) {
+ if (alphaThreshold > 0) {
+ // Alpha test
+ // use opacityMap if it is presented
+ program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 1, null, 0, true, null);
+ drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, null, 0, true, null, true, false, objectRenderPriority);
+ } else {
+ // do not use opacityMap at all
+ program = getProgram(object, optionsPrograms, camera, materialKey, null, 0, null, 0, true, null);
+ drawUnit = getDrawUnit(program, camera, surface, geometry, null, null, 0, true, null, true, false, objectRenderPriority);
+ }
+ }
+ // Transparent pass
+ if (transparentPass && alphaThreshold > 0 && alpha > 0) {
// use opacityMap if it is presented
- program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 1, lights, lightsLength, shadowedLight);
- drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, lights, lightsLength, shadowedLight);
- } else {
- // do not use opacityMap at all
- program = getProgram(object, optionsPrograms, camera, materialKey, null, 0, lights, lightsLength, shadowedLight);
- drawUnit = getDrawUnit(program, camera, surface, geometry, null, lights, lightsLength, shadowedLight);
+ if (alphaThreshold <= alpha && !opaquePass) {
+ // Alpha threshold
+ program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 2, null, 0, true, null);
+ drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, null, 0, true, null, false, true, objectRenderPriority);
+ } else {
+ // There is no Alpha threshold or check z-buffer by previous pass
+ program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 0, null, 0, true, null);
+ drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, null, 0, true, null, false, true, objectRenderPriority);
+ }
}
- // Use z-buffer within DrawCall, draws without blending
- camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.OPAQUE);
}
- // Transparent pass
- if (transparentPass && alphaThreshold > 0 && alpha > 0) {
- // use opacityMap if it is presented
- if (alphaThreshold <= alpha && !opaquePass) {
- // Alpha threshold
- program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 2, lights, lightsLength, shadowedLight);
- drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, lights, lightsLength, shadowedLight);
- } else {
- // There is no Alpha threshold or check z-buffer by previous pass
- program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 0, lights, lightsLength, shadowedLight);
- drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, lights, lightsLength, shadowedLight);
+ else{
+ var lightLengthInGroup:int;
+ var isFirstGroup:Boolean = true;
+ for (i = 0; i < groupsCount; i++) {
+ var lightGroup:Vector. = groups[i];
+ lightLengthInGroup = lightGroup.length;
+
+ // Group of lights without shadow
+ // Form key
+ materialKey = (isFirstGroup)?((lightMap != null) ? "L" : "l"):"";
+ materialKey +=
+ (_normalMapSpace.toString()) +
+ ((glossinessMap != null) ? "G" : "g") +
+ ((specularMap != null) ? "S" : "s");
+ for (var j:int = 0; j < lightLengthInGroup; j++) {
+ var light:Light3D = lightGroup[j];
+ materialKey += light.lightID;
+ }
+
+ // Create program and drawUnit for group
+ // Opaque pass
+ if (opaquePass && alphaThreshold <= alpha) {
+ if (alphaThreshold > 0) {
+ // Alpha test
+ // use opacityMap if it is presented
+ program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 1, lightGroup, lightLengthInGroup, isFirstGroup, null);
+ drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, lightGroup, lightLengthInGroup, isFirstGroup, null, true, false, objectRenderPriority);
+ } else {
+ // do not use opacityMap at all
+ program = getProgram(object, optionsPrograms, camera, materialKey, null, 0, lightGroup, lightLengthInGroup, isFirstGroup, null);
+ drawUnit = getDrawUnit(program, camera, surface, geometry, null, lightGroup, lightLengthInGroup, isFirstGroup, null, true, false, objectRenderPriority);
+ }
+ }
+ // Transparent pass
+ if (transparentPass && alphaThreshold > 0 && alpha > 0) {
+ // use opacityMap if it is presented
+ if (alphaThreshold <= alpha && !opaquePass) {
+ // Alpha threshold
+ program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 2, lightGroup, lightLengthInGroup, isFirstGroup, null);
+ drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, lightGroup, lightLengthInGroup, isFirstGroup, null, false, true, objectRenderPriority);
+ } else {
+ // There is no Alpha threshold or check z-buffer by previous pass
+ program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 0, lightGroup, lightLengthInGroup, isFirstGroup, null);
+ drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, lightGroup, lightLengthInGroup, isFirstGroup, null, false, true, objectRenderPriority);
+ }
+ }
+ isFirstGroup = false;
+ lightGroup.length = 0;
}
- // Do not use z-buffer, draws with blending
- drawUnit.blendSource = Context3DBlendFactor.SOURCE_ALPHA;
- drawUnit.blendDestination = Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA;
- camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.TRANSPARENT_SORT);
+
+ if (shadowGroupLength>0){
+ // Group of ligths with shadow
+ // For each light we will create new drawUnit
+ for (var j:int = 0; j < shadowGroupLength; j++) {
+
+ var light:Light3D = shadowGroup[j];
+ // Form key
+ materialKey = (isFirstGroup)?((lightMap != null) ? "L" : "l"):"";
+ materialKey +=
+ (_normalMapSpace.toString()) +
+ ((glossinessMap != null) ? "G" : "g") +
+ ((specularMap != null) ? "S" : "s");
+ materialKey += light.shadow.type;
+ materialKey += light.lightID;
+
+ // Для группы создаем программу и дроуюнит
+ // Opaque pass
+ if (opaquePass && alphaThreshold <= alpha) {
+ if (alphaThreshold > 0) {
+ // Alpha test
+ // use opacityMap if it is presented
+ program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 1, null, 0, isFirstGroup, light);
+ drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, null, 0, isFirstGroup, light, true, false, objectRenderPriority);
+ } else {
+ // do not use opacityMap at all
+ program = getProgram(object, optionsPrograms, camera, materialKey, null, 0, null, 0, isFirstGroup, light);
+ drawUnit = getDrawUnit(program, camera, surface, geometry, null, null, 0, isFirstGroup, light, true, false, objectRenderPriority);
+ }
+ trace(program.vertexShader.describeLinkageInfo());
+ trace(program.fragmentShader.describeLinkageInfo());
+
+ }
+ // Transparent pass
+ if (transparentPass && alphaThreshold > 0 && alpha > 0) {
+ // use opacityMap if it is presented
+ if (alphaThreshold <= alpha && !opaquePass) {
+ // Alpha threshold
+ program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 2, null, 0, isFirstGroup, light);
+ drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, null, 0, isFirstGroup, light, false, true, objectRenderPriority);
+ } else {
+ // There is no Alpha threshold or check z-buffer by previous pass
+ program = getProgram(object, optionsPrograms, camera, materialKey, opacityMap, 0, null, 0, isFirstGroup, light);
+ drawUnit = getDrawUnit(program, camera, surface, geometry, opacityMap, null, 0, isFirstGroup, light, false, true, objectRenderPriority);
+ }
+ }
+ isFirstGroup = false;
+ }
+ }
+ shadowGroup.length = 0;
}
+ groups.length = 0;
}
/**
diff --git a/src/alternativa/engine3d/materials/TextureMaterial.as b/src/alternativa/engine3d/materials/TextureMaterial.as
index 012ca27..e8f1805 100644
--- a/src/alternativa/engine3d/materials/TextureMaterial.as
+++ b/src/alternativa/engine3d/materials/TextureMaterial.as
@@ -243,7 +243,7 @@ package alternativa.engine3d.materials {
/**
* @private
*/
- override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector., lightsLength:int, objectRenderPriority:int = -1):void {
+ 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;
// Buffers
diff --git a/src/alternativa/engine3d/materials/VertexLightTextureMaterial.as b/src/alternativa/engine3d/materials/VertexLightTextureMaterial.as
index 477b950..d75a601 100644
--- a/src/alternativa/engine3d/materials/VertexLightTextureMaterial.as
+++ b/src/alternativa/engine3d/materials/VertexLightTextureMaterial.as
@@ -279,7 +279,7 @@ package alternativa.engine3d.materials {
/**
* @private
*/
- override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector., lightsLength:int, objectRenderPriority:int = -1):void {
+ 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;
var object:Object3D = surface.object;
diff --git a/src/alternativa/engine3d/objects/AxisAlignedSprite.as b/src/alternativa/engine3d/objects/AxisAlignedSprite.as
index 44cdbdc..52f046b 100644
--- a/src/alternativa/engine3d/objects/AxisAlignedSprite.as
+++ b/src/alternativa/engine3d/objects/AxisAlignedSprite.as
@@ -151,9 +151,9 @@ package alternativa.engine3d.objects {
/**
* @private
*/
- override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int):void {
+ override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int, useShadow:Boolean):void {
var geometry:Geometry = getGeometry(camera.context3D);
- if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength);
+ if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow, -1);
// Mouse events
if (listening) camera.view.addSurfaceToMouseEvents(surface, geometry, transformProcedure);
}
diff --git a/src/alternativa/engine3d/objects/Decal.as b/src/alternativa/engine3d/objects/Decal.as
index db0745e..baa8832 100644
--- a/src/alternativa/engine3d/objects/Decal.as
+++ b/src/alternativa/engine3d/objects/Decal.as
@@ -71,10 +71,10 @@ package alternativa.engine3d.objects {
/**
* @private
*/
- override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int):void {
+ override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int, useShadow:Boolean):void {
for (var i:int = 0; i < _surfacesLength; i++) {
var surface:Surface = _surfaces[i];
- if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, Renderer.DECALS);
+ if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow, Renderer.DECALS);
// Mouse events
if (listening) camera.view.addSurfaceToMouseEvents(surface, geometry, transformProcedure);
}
diff --git a/src/alternativa/engine3d/objects/LOD.as b/src/alternativa/engine3d/objects/LOD.as
index ea48ef5..7f0bcac 100644
--- a/src/alternativa/engine3d/objects/LOD.as
+++ b/src/alternativa/engine3d/objects/LOD.as
@@ -172,11 +172,11 @@ package alternativa.engine3d.objects {
/**
* @private
*/
- override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int):void {
+ override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int, useShadow:Boolean):void {
var distance:Number = Math.sqrt(localToCameraTransform.d*localToCameraTransform.d + localToCameraTransform.h*localToCameraTransform.h + localToCameraTransform.l*localToCameraTransform.l);
for (var level:Object3D = levelList; level != null; level = level.next) {
if (distance <= level.distance) {
- collectChildDraws(level, this, camera, lights, lightsLength);
+ collectChildDraws(level, this, camera, lights, lightsLength, useShadow);
break;
}
}
@@ -185,7 +185,7 @@ package alternativa.engine3d.objects {
/**
* @private
*/
- alternativa3d function collectChildDraws(child:Object3D, parent:Object3D, camera:Camera3D, lights:Vector., lightsLength:int):void {
+ alternativa3d function collectChildDraws(child:Object3D, parent:Object3D, camera:Camera3D, lights:Vector., lightsLength:int, useShadow:Boolean):void {
// Composing direct and reverse matrices
if (child.transformChanged) child.composeTransforms();
// Calculation of transfer matrix from camera to local space.
@@ -198,17 +198,25 @@ package alternativa.engine3d.objects {
// If object needs on light sources.
if (lightsLength > 0 && child.useLights) {
// Calculation of transfer matrices from sources to object.
+ var excludedLightLength:int = excludedLights.length;
+ var childLightsLength:int = 0;
for (var i:int = 0; i < lightsLength; i++) {
var light:Light3D = lights[i];
+ var j:int = 0;
+ while (j, lightsLength:int):void {
+ override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int, useShadow:Boolean):void {
for (var i:int = 0; i < _surfacesLength; i++) {
var surface:Surface = _surfaces[i];
- if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength);
+ if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow, -1);
// Mouse events
if (listening) camera.view.addSurfaceToMouseEvents(surface, geometry, transformProcedure);
}
diff --git a/src/alternativa/engine3d/objects/MeshSet.as b/src/alternativa/engine3d/objects/MeshSet.as
index bad4766..1eb604f 100644
--- a/src/alternativa/engine3d/objects/MeshSet.as
+++ b/src/alternativa/engine3d/objects/MeshSet.as
@@ -73,14 +73,14 @@ package alternativa.engine3d.objects {
}
}
- override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int):void {
+ override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int, useShadow:Boolean):void {
if (geometry == null) return;
// Calculation of joints matrices.
for (var i:int = 0; i < _surfacesLength; i++) {
var surface:Surface = _surfaces[i];
transformProcedure = surfaceTransformProcedures[i];
deltaTransformProcedure = surfaceDeltaTransformProcedures[i];
- if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength);
+ if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow);
// Mouse events
if (listening) camera.view.addSurfaceToMouseEvents(surface, geometry, transformProcedure);
}
diff --git a/src/alternativa/engine3d/objects/Skin.as b/src/alternativa/engine3d/objects/Skin.as
index 268e286..df4972b 100644
--- a/src/alternativa/engine3d/objects/Skin.as
+++ b/src/alternativa/engine3d/objects/Skin.as
@@ -565,7 +565,7 @@ package alternativa.engine3d.objects {
/**
* @private
*/
- override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int):void {
+ override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int, useShadow:Boolean):void {
if (geometry == null) return;
// Calculate joints matrices
for (var child:Object3D = childrenList; child != null; child = child.next) {
@@ -582,7 +582,7 @@ package alternativa.engine3d.objects {
var surface:Surface = _surfaces[i];
transformProcedure = surfaceTransformProcedures[i];
deltaTransformProcedure = surfaceDeltaTransformProcedures[i];
- if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength);
+ if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow);
/*var destination:DrawUnit = surface.getDrawUnit(camera, geometry, lights, lightsLength);
if (destination == null) continue;
diff --git a/src/alternativa/engine3d/objects/SkyBox.as b/src/alternativa/engine3d/objects/SkyBox.as
index 14c899e..e047a1e 100644
--- a/src/alternativa/engine3d/objects/SkyBox.as
+++ b/src/alternativa/engine3d/objects/SkyBox.as
@@ -196,10 +196,10 @@ package alternativa.engine3d.objects {
/**
* @private
*/
- override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int):void {
+ override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int, useShadow:Boolean):void {
for (var i:int = 0; i < _surfacesLength; i++) {
var surface:Surface = _surfaces[i];
- if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, Renderer.SKY);
+ if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow, Renderer.SKY);
//Mouse events
if (listening) camera.view.addSurfaceToMouseEvents(surface, geometry, transformProcedure);
}
diff --git a/src/alternativa/engine3d/objects/Sprite3D.as b/src/alternativa/engine3d/objects/Sprite3D.as
index c10a870..4397f70 100644
--- a/src/alternativa/engine3d/objects/Sprite3D.as
+++ b/src/alternativa/engine3d/objects/Sprite3D.as
@@ -182,9 +182,9 @@ package alternativa.engine3d.objects {
/**
* @private
*/
- override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int):void {
+ override alternativa3d function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int, useShadow:Boolean):void {
var geometry:Geometry = getGeometry(camera.context3D);
- if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, alwaysOnTop ? Renderer.NEXT_LAYER : -1);
+ if (surface.material != null) surface.material.collectDraws(camera, surface, geometry, lights, lightsLength, useShadow, alwaysOnTop ? Renderer.NEXT_LAYER : -1);
// Mouse events.
if (listening) camera.view.addSurfaceToMouseEvents(surface, geometry, transformProcedure);
}
diff --git a/src/alternativa/engine3d/objects/WireFrame.as b/src/alternativa/engine3d/objects/WireFrame.as
index 22763ec..b19da9f 100644
--- a/src/alternativa/engine3d/objects/WireFrame.as
+++ b/src/alternativa/engine3d/objects/WireFrame.as
@@ -171,7 +171,7 @@ package alternativa.engine3d.objects {
/**
* @private
*/
- alternativa3d override function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int):void {
+ alternativa3d override function collectDraws(camera:Camera3D, lights:Vector., lightsLength:int, useShadow:Boolean):void {
if (camera.context3D != cachedContext3D) {
cachedContext3D = camera.context3D;
shaderProgram = cachedPrograms[cachedContext3D];
diff --git a/src/alternativa/engine3d/shadows/DirectionalLightShadow.as b/src/alternativa/engine3d/shadows/DirectionalLightShadow.as
index 78ebeb4..dc76fcf 100644
--- a/src/alternativa/engine3d/shadows/DirectionalLightShadow.as
+++ b/src/alternativa/engine3d/shadows/DirectionalLightShadow.as
@@ -5,7 +5,6 @@
*
* 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;
@@ -60,8 +59,6 @@ package alternativa.engine3d.shadows {
/**
* Debug mode.
*/
- public var debug:Boolean = false;
-
/**
* Degree of correcting offset of shadow map space. It need for getting rid of self-shadowing artifacts.
*/
@@ -164,6 +161,7 @@ package alternativa.engine3d.shadows {
* Enable/disable automatic calculation of shadow zone parameters on specified bound-box at shadowBoundBox property.
*/
public var calculateParametersByVolume:Boolean = false;
+
public var volume:BoundBox = null;
// TODO: implement special shader for display of shadowmap in debug (black-and-white).
@@ -217,7 +215,7 @@ package alternativa.engine3d.shadows {
this._mapSize = mapSize;
this._pcfOffset = pcfOffset;
- this.type = _pcfOffset > 0 ? "S" : "s";
+ this.type = _pcfOffset > 0 ? "DS" : "ds";
vertexShadowProcedure = getVShader();
fragmentShadowProcedure = _pcfOffset > 0 ? getFShaderPCF() : getFShader();
@@ -381,12 +379,12 @@ package alternativa.engine3d.shadows {
// Draw
var debugSurface:Surface = debugPlane._surfaces[0];
- debugSurface.material.collectDraws(camera, debugSurface, debugPlane.geometry, emptyLightVector, 0, -1);
+ debugSurface.material.collectDraws(camera, debugSurface, debugPlane.geometry, emptyLightVector, 0, false, -1);
// Form transformation matrix for debugPlane
debugPlane.transform.compose((frustumMinX + frustumMaxX) / 2, (frustumMinY + frustumMaxY) / 2, frustumMaxZ, 0, 0, 0, (frustumMaxX - frustumMinX), (frustumMaxY - frustumMinY), 1);
debugPlane.localToCameraTransform.combine(_light.localToCameraTransform, debugPlane.transform);
- debugSurface.material.collectDraws(camera, debugSurface, debugPlane.geometry, emptyLightVector, 0, -1);
+ debugSurface.material.collectDraws(camera, debugSurface, debugPlane.geometry, emptyLightVector, 0, false, -1);
}
tempBounds.minX = frustumMinX;
@@ -567,7 +565,6 @@ package alternativa.engine3d.shadows {
fLinker.addProcedure(Procedure.compileFromArray([
"#v0=vDistance",
"#c0=cConstants",
- "mov t0.xy, v0.zz",
"frc t0.y, v0.z",
"sub t0.x, v0.z, t0.y",
"mul t0.x, t0.x, c0.x",
@@ -711,6 +708,28 @@ package alternativa.engine3d.shadows {
//------------- ShadowMap Shader ----------
+ /**
+ * @private
+ */
+ alternativa3d override function setup(drawUnit:DrawUnit, vertexLinker:Linker, fragmentLinker:Linker, surface:Surface):void {
+ // Устанавливаем матрицу перевода в шедоумапу
+ objectToShadowMapTransform.combine(cameraToShadowMapUVProjection, surface.object.localToCameraTransform);
+
+ drawUnit.setVertexConstantsFromTransform(vertexLinker.getVariableIndex("cUVProjection"), objectToShadowMapTransform);
+ // Устанавливаем шедоумапу
+ drawUnit.setTextureAt(fragmentLinker.getVariableIndex("sShadowMap"), shadowMap);
+ // TODO: сделать множитель более корректный. Возможно 65536 (разрешающая способность глубины буфера).
+ // Устанавливаем коеффициенты
+ drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -255*10000, -10000, biasMultiplier*255*10000, 1/16);
+ if (_pcfOffset > 0) {
+ var offset1:Number = _pcfOffset/_mapSize;
+ var offset2:Number = offset1/3;
+
+ drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cPCFOffsets"), -offset1, -offset2, offset2, offset1);
+ }
+ drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cDist"), 0.9999, 10000, 1);
+ }
+
private static function getVShader():Procedure {
var shader:Procedure = Procedure.compileFromArray([
"#v0=vSample",
@@ -737,6 +756,7 @@ package alternativa.engine3d.shadows {
// Clipping by distance.
shaderArr[line++] = "sub t0.y, c1.x, t0.z"; // maxDist - z
shaderArr[line++] = "mul t0.y, t0.y, c1.y"; // mul 10000
+
shaderArr[line++] = "sat t0.xy, t0.xy";
shaderArr[line++] = "mul t0.x, t0.x, t0.y";
shaderArr[line++] = "sub o0, c1.z, t0.x";
@@ -790,28 +810,6 @@ package alternativa.engine3d.shadows {
return Procedure.compileFromArray(shaderArr, "DirectionalShadowMapFragment");
}
- /**
- * @private
- */
- alternativa3d override function setup(drawUnit:DrawUnit, vertexLinker:Linker, fragmentLinker:Linker, surface:Surface):void {
- // Set transfer matrix to shadowmap.
- objectToShadowMapTransform.combine(cameraToShadowMapUVProjection, surface.object.localToCameraTransform);
-
- drawUnit.setVertexConstantsFromTransform(vertexLinker.getVariableIndex("cUVProjection"), objectToShadowMapTransform);
- // Set shadowmap.
- drawUnit.setTextureAt(fragmentLinker.getVariableIndex("sShadowMap"), shadowMap);
- // TODO: set multiplier more correct. It is possible that 65536 (resolution of the buffer depth).
- // Set coefficients.
- drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -255*10000, -10000, biasMultiplier*255*10000, 1/16);
- if (_pcfOffset > 0) {
- var offset1:Number = _pcfOffset/_mapSize;
- var offset2:Number = offset1/3;
-
- drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cPCFOffsets"), -offset1, -offset2, offset2, offset1);
- }
- drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cDist"), 0.9999, 10000, 1);
- }
-
/**
* Adds given object to list of objects, that cast shadow.
* @param object Added object.
diff --git a/src/alternativa/engine3d/shadows/OmniLightShadow.as b/src/alternativa/engine3d/shadows/OmniLightShadow.as
new file mode 100644
index 0000000..caf9a0f
--- /dev/null
+++ b/src/alternativa/engine3d/shadows/OmniLightShadow.as
@@ -0,0 +1,903 @@
+/**
+ * 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.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.core.View;
+ 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{
+
+ /**
+ * Степень корректирующего смещения пространства карты теней для избавления от артефактов самозатенения.
+ */
+ public var biasMultiplier:Number = 0.99;
+
+ private var renderer:Renderer = new Renderer();
+
+ private var boundSize:Number = 1;
+ private var _mapSize:Number;
+ private var _pcfOffset:Number;
+
+ private var cubeShadowMap:CubeTexture;
+ private var cameras:Vector. = new Vector.();
+
+ private var debugObject:Mesh;
+ private var debugMaterial:ShadowDebugMaterial;
+
+ private var _casters:Vector. = new Vector.();
+
+ private var cachedContext:Context3D;
+ private var programs:Dictionary = new Dictionary();
+
+ private var actualCasters:Vector. = new Vector.();
+ private var actualCastersCount:int;
+
+ private var edgeCameraToCasterTransform:Transform3D = new Transform3D();
+ private var casterToEdgedCameraTransform:Transform3D = new Transform3D();
+ private var objectToLightTransform:Transform3D = new Transform3D();
+
+ private var prevActualCasterCountForEdge:Vector. = new Vector.(6);
+
+ /**
+ * Создает экземпляр OmniLightShadow.
+ * @param mapSize Размер карты теней. Должен быть степенью 2.
+ * @param pcfOffset Смягчение границ тени.
+ */
+ public function OmniLightShadow(mapSize:int = 128, pcfOffset:Number = 0) {
+
+ this.mapSize = mapSize;
+ this.pcfOffset = pcfOffset;
+ vertexShadowProcedure = getVShader();
+ type = _pcfOffset > 0 ? "OS" : "os";
+ fragmentShadowProcedure = _pcfOffset > 0 ? getFShaderPCF() : getFShader();
+
+ debugMaterial = new ShadowDebugMaterial();
+ debugMaterial.alpha = 1.0;
+
+ for (var i:int = 0; i < 6; i++) {
+ // создаем камеры
+ var cam:Camera3D = new Camera3D(1, boundSize);
+ cam.fov = 1.910633237;
+ cam.view = new View(boundSize, boundSize);
+ cam.renderer = renderer;
+ cameras[i] = cam;
+
+ prevActualCasterCountForEdge[i] = 0;
+ }
+
+ // 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
+ */
+ alternativa3d function setBoundSize(value:Number):void{
+ this.boundSize = value;
+ for (var i:int = 0; i < 6; i++) {
+ var cam:Camera3D = cameras[i];
+ cam.view.width = cam.view.height = int (value);
+ cam.farClipping = value;
+ cam.calculateProjection(value,value);
+ }
+ }
+
+ private function createDebugCube(material:Material, context:Context3D):Mesh{
+ var mesh:Mesh = new Mesh();
+ // TODO: определиться куб или сфера
+// var geometry: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.([-0.5, -0.5, -0.5,
+// 0.5, -0.5, -0.5,
+// 0.5, 0.5, -0.5,
+// -0.5, 0.5, -0.5,
+// -0.5, -0.5, 0.5,
+// 0.5, -0.5, 0.5,
+// 0.5, 0.5, 0.5,
+// -0.5, 0.5, 0.5]));
+//
+// 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);
+ var sphere:GeoSphere = new GeoSphere(1, 4, false);
+ var geometry:Geometry = sphere.geometry;
+ mesh.geometry = geometry;
+ mesh.addSurface(material, 0, geometry.numTriangles);
+
+ geometry.upload(context);
+
+ return mesh;
+ }
+
+
+ // Вычисление шедоумапы
+ override alternativa3d function process(camera:Camera3D):void {
+ var i:int;
+ var j:int;
+ var caster:Object3D;
+ var context:Context3D = camera.context3D;
+ var castersCount:int = _casters.length;
+ // Отсечение кастеров, тени которых не видны
+
+ // Обработка смены контекста
+ if (context != cachedContext) {
+ programs = new Dictionary();
+ cubeShadowMap = null;
+ cachedContext = context;
+ for (i = 0; i < cameras.length; i++) {
+ cameras[i].context3D = cachedContext;
+ }
+ }
+
+ if (cubeShadowMap == null) {
+ cubeShadowMap = context.createCubeTexture(_mapSize, Context3DTextureFormat.BGRA, true);
+ debugMaterial.cubeMap = cubeShadowMap;
+ for (i = 0; i < 6; i++) {
+ context.setRenderToTexture(cubeShadowMap, true, 0, i);
+ context.clear(1, 0, 0, 0.3);
+ }
+ }
+
+ // предрасчитаем некоторые матрицы трансформации
+ for (j = 0; j < castersCount; j++) {
+ caster = _casters[j];
+
+ if (caster.transformChanged) caster.composeTransforms();
+ caster.lightToLocalTransform.combine(caster.cameraToLocalTransform, _light.localToCameraTransform);
+ caster.localToLightTransform.combine(_light.cameraToLocalTransform, caster.localToCameraTransform);
+
+ var skin:Skin = caster as Skin;
+ if (skin != null) {
+ // Расчет матриц джоинтов
+ for (var child:Object3D = skin.childrenList; child != null; child = child.next) {
+ if (child.transformChanged) child.composeTransforms();
+ // Записываем в localToGlobalTransform матрицу перевода в скин
+ child.localToGlobalTransform.copy(child.transform);
+ if (child is Joint) {
+ Joint(child).calculateTransform();
+ }
+ skin.calculateJointsTransforms(child);
+ }
+ }
+ else{
+ if (caster.childrenList)
+ calculateChildrenTransforms(caster);
+ }
+ }
+
+
+ // Пробегаемся по 6-и камерам
+ for (i = 0; i < 6; i++) {
+ // камера соответствующая грани куба
+ var edgeCamera:Camera3D = cameras[i];
+
+ // проверяем, есть ли видимые кастеры попадающие на грань куба
+ actualCastersCount = 0;
+ for (j = 0; j < castersCount; j++) {
+ caster = _casters[j];
+
+ var visible:Boolean = caster.visible;
+ var parent:Object3D = caster._parent;
+ while (visible && parent != null) {
+ visible = parent.visible;
+ parent = parent._parent;
+ }
+ if (visible) {
+ // Проверка куллинга
+ // формируем actualCasters
+ calculateVisibility(caster, edgeCamera);
+ }
+ }
+
+ if (actualCastersCount>0){
+ // Настройка параметров рендеринга:
+ renderer.camera = edgeCamera;
+ context.setRenderToTexture(cubeShadowMap, true, 0, i);
+ context.clear(1, 0, 0, 0.0);
+
+ // Пробегаемся по кастерам
+ for (j = 0; j 0) {
+ // Создаем дебаговый объект, если он не создан
+ if (debugObject == null) {
+ debugObject = createDebugCube(debugMaterial, camera.context3D);
+ debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = boundSize/12;
+ 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);
+ }
+ }
+ }
+
+ // предрасчитывает матрицы для всех детей
+ // localToLightTransform, lightToLocalTransform, transform, и calculateTransform для Joint
+ private function calculateChildrenTransforms(root:Object3D):void{
+ var childrenList:Object3D = root.childrenList;
+
+ for (var child:Object3D = childrenList; child != null; child = child.next) {
+
+ // расчет матриц трансформаций для объектов
+ if (child.transformChanged) child.composeTransforms();
+ child.localToLightTransform.combine(root.localToLightTransform, child.transform);
+ child.lightToLocalTransform.combine(child.inverseTransform, root.lightToLocalTransform);
+
+ // расчет матриц трансформаций для скинов
+ var skin:Skin = child as Skin;
+ if (skin != null) {
+ // Расчет матриц джоинтов
+ for (var skinChild:Object3D = skin.childrenList; skinChild != null; skinChild = skinChild.next) {
+ if (skinChild.transformChanged) skinChild.composeTransforms();
+ // Записываем в localToGlobalTransform матрицу перевода в скин
+ skinChild.localToGlobalTransform.copy(skinChild.transform);
+ if (skinChild is Joint) {
+ Joint(skinChild).calculateTransform();
+ }
+ skin.calculateJointsTransforms(skinChild);
+ }
+ }
+ else{
+ if (child.childrenList)
+ calculateChildrenTransforms(child);
+ }
+ }
+ }
+
+ // собирает список actualCasters для одной из 6-и камер
+ private function calculateVisibility(root:Object3D, camera:Camera3D):void{
+ var casterCulling:int;
+
+ if (root.visible) {
+ var skin:Skin = root as Skin;
+
+ // Вычисляем результат кулинга для объекта
+ if (root.boundBox != null) {
+ edgeCameraToCasterTransform.combine(root.lightToLocalTransform, camera.transform);
+ camera.calculateFrustum(edgeCameraToCasterTransform);
+ casterCulling = root.boundBox.checkFrustumCulling(camera.frustum, 63);
+ } else {
+ casterCulling = 63;
+ }
+
+ // Если Кулинг кастера дает положительный результат, тогда
+ if (casterCulling){
+ if (skin){
+ actualCasters[actualCastersCount++] = root;
+ }
+ else{
+ var childrenList:Object3D = root.childrenList;
+ // Если есть дочерние объекты,
+ if(childrenList!=null){
+ // Проверяем их на кулинг
+ for (var child:Object3D = childrenList; child != null; child = child.next) {
+ calculateVisibility(child, camera);
+ }
+ }
+ // Если дочерних объектов нет
+ else{
+ // добавляем кастер в список актуальных кастеров
+ actualCasters[actualCastersCount++] = root;
+ }
+ }
+ }
+ }
+ }
+
+
+ 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.setVertexConstantsFromNumbers(program.vertexShader.getVariableIndex("cScale"), 255/boundSize, 0, 0, 1);
+ drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cConstants"), 1 / 255, 0, 0, 1);
+
+ renderer.addDrawUnit(drawUnit, Renderer.OPAQUE);
+ }
+ }
+
+ var child:Object3D;
+ for (child = caster.childrenList; child != null; child = child.next) {
+ if (!(child as Joint) && child.visible) collectDraws(context, child, edgeCamera);
+ }
+ }
+
+
+ /**
+ * @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([
+ "#c1=cScale",
+ "#v0=vDistance",
+
+ "m34 t0.xyz, i0, c2",
+ "dp3 t0.x, t0.xyz, t0.xyz",
+ "sqt t0.x, t0.x", // x: [0, boundSize]
+ "mul t0.x, t0.x, c1.x", // x: [0, 255]
+ "mov t0.w, c1.w",
+ "mov v0, t0",
+
+ "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", // x: [0, 255]
+ "#c0=cConstants", // 1/255, 0, 0, 1
+ "frc t0.y, v0.x",
+ "sub t0.x, v0.x, t0.y",
+ "mul t0.x, t0.x, c0.x",
+ "mov t0.zw, c0.zw",
+
+ "mov o0, t0"
+ ]));
+ program = new ShaderProgram(vLinker, fLinker);
+ fLinker.varyings = vLinker.varyings;
+ programListByTransformProcedure[key] = program;
+ program.upload(context);
+
+ }
+ return program;
+ }
+
+
+
+ //------------- ShadowMap Shader ----------
+
+ /**
+ * @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);
+
+ // Устанавливаем коеффициенты
+ // TODO: сделать множитель более корректный. Возможно 65536 (разрешающая способность глубины буфера).
+ if (_pcfOffset > 0) {
+
+ var offset:Number = _pcfOffset*0.0175; //1 градус
+ drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cPCFOffsets"), -3/2, 1/16, 0, 0);
+ drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -1, 1, 0, offset/boundSize);
+ drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cDecode"), -10000, -10000/255, biasMultiplier*10000/boundSize, 10);
+ }
+ else{
+ drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -10000, -10000/255, biasMultiplier*10000/boundSize, 1);
+ }
+ }
+
+ private static function getVShader():Procedure {
+ var shader:Procedure = Procedure.compileFromArray([
+ "#v0=vSample",
+
+ "m34 t0.xyz, i0, c0",
+ "dp3 t0.w, t0.xyz, t0.xyz",
+ "sqt t0.w, t0.w", // w: [0, boundSize]
+// "div t0.xyz, t0.xyz, t0.w", // norm
+
+ "mov v0, t0"
+ ], "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++] = "mov t0.z, v0.w"; // w: [0, boundSize]
+ shaderArr[line++] = "tex t0.xy, v0, s0 ";
+ shaderArr[line++] = "dp3 t0.x, t0.xyz, c0.xyz"; // декодируем, находим разницу между расстояниями и умножаем ее на большое число
+
+ // рассчитываем значение тени
+ shaderArr[line++] = "sat t0, t0.x";
+ shaderArr[line++] = "sub o0, c0.w, 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
+ // v0.w - length(sample) [0, boundSize]
+
+ // ищем 2-а перпендикулярных вектора
+ // (-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";
+
+ // нормируем их
+ shaderArr[line++] = "nrm t0.xyz, t0.xyz";
+ shaderArr[line++] = "nrm t1.xyz, t1.xyz";
+
+ // задаем оффсеты
+ shaderArr[line++] = "mul t0.w, c1.w, v0.w"; // с1.w = offset/boundSize
+ shaderArr[line++] = "mul t0.xyz, t0.xyz, t0.w";
+ shaderArr[line++] = "mul t1.xyz, t1.xyz, t0.w";
+ // --------- {13 opcode}
+
+ // t0, t1 - перпендикуляры ↑→
+ // t2 - текущий вектор
+
+ // в v0.w, t3.z расстояние до объекта
+ // t3.xy - результат из текстуры
+ // t3.w - сумма sat-ов
+
+ // первая точка
+ 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, v0.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 opcode}
+ 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 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 > 2048) {
+ throw new ArgumentError("Map size exceeds maximum value 2048.");
+ }
+ 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. Этот способ фильтрации используется для смягчения границ тени.
+ */
+ public function get pcfOffset():Number {
+ return _pcfOffset;
+ }
+
+ /**
+ * @private
+ */
+ public function set pcfOffset(value:Number):void {
+ _pcfOffset = value;
+ type = _pcfOffset > 0 ? "OS" : "os";
+ 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.Program3D;
+
+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 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);
+ }
+
+}
+
diff --git a/src/alternativa/engine3d/shadows/Shadow.as b/src/alternativa/engine3d/shadows/Shadow.as
index 24648e3..8b67f97 100644
--- a/src/alternativa/engine3d/shadows/Shadow.as
+++ b/src/alternativa/engine3d/shadows/Shadow.as
@@ -23,6 +23,11 @@ package alternativa.engine3d.shadows {
*/
public class Shadow {
+ /**
+ * Debug mode.
+ */
+ public var debug:Boolean = false;
+
/**
* @private
* Key for processing in materials.