diff --git a/src/alternativa/Alternativa3D.as b/src/alternativa/Alternativa3D.as index fc704c0..d9ae176 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.29.0"; + public static const version:String = "8.30.0"; } } diff --git a/src/alternativa/engine3d/core/BoundBox.as b/src/alternativa/engine3d/core/BoundBox.as index 3b07adc..259fbed 100644 --- a/src/alternativa/engine3d/core/BoundBox.as +++ b/src/alternativa/engine3d/core/BoundBox.as @@ -3,7 +3,7 @@ * 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/ + * It is desirable to notify that Covered Software was "Powered by AlternativaPlatform" with link to http://www.alternativaplatform.com/ * */ package alternativa.engine3d.core { @@ -13,7 +13,7 @@ package alternativa.engine3d.core { import flash.geom.Vector3D; use namespace alternativa3d; - + /** * Class stores object's bounding box object's local space. Generally, position of child objects isn't considered at BoundBox calculation. * Ray intersection always made boundBox check at first, but it's possible to check on crossing boundBox only. @@ -44,7 +44,7 @@ package alternativa.engine3d.core { * Top face. */ public var maxZ:Number = -1e+22; - + /** * Resets all bounds values to its initial state. @@ -57,33 +57,40 @@ package alternativa.engine3d.core { maxY = -1e+22; maxZ = -1e+22; } - + /** - * @private + * @private */ alternativa3d function checkFrustumCulling(frustum:CullingPlane, culling:int):int { var side:int = 1; for (var plane:CullingPlane = frustum; plane != null; plane = plane.next) { if (culling & side) { - if (plane.x >= 0) if (plane.y >= 0) if (plane.z >= 0) { - if (maxX*plane.x + maxY*plane.y + maxZ*plane.z <= plane.offset) return -1; - if (minX*plane.x + minY*plane.y + minZ*plane.z > plane.offset) culling &= (63 & ~side); - } else { - if (maxX*plane.x + maxY*plane.y + minZ*plane.z <= plane.offset) return -1; - if (minX*plane.x + minY*plane.y + maxZ*plane.z > plane.offset) culling &= (63 & ~side); - } else if (plane.z >= 0) { - if (maxX*plane.x + minY*plane.y + maxZ*plane.z <= plane.offset) return -1; - if (minX*plane.x + maxY*plane.y + minZ*plane.z > plane.offset) culling &= (63 & ~side); - } else { - if (maxX*plane.x + minY*plane.y + minZ*plane.z <= plane.offset) return -1; - if (minX*plane.x + maxY*plane.y + maxZ*plane.z > plane.offset) culling &= (63 & ~side); - } else if (plane.y >= 0) if (plane.z >= 0) { - if (minX*plane.x + maxY*plane.y + maxZ*plane.z <= plane.offset) return -1; - if (maxX*plane.x + minY*plane.y + minZ*plane.z > plane.offset) culling &= (63 & ~side); - } else { - if (minX*plane.x + maxY*plane.y + minZ*plane.z <= plane.offset) return -1; - if (maxX*plane.x + minY*plane.y + maxZ*plane.z > plane.offset) culling &= (63 & ~side); - } else if (plane.z >= 0) { + if (plane.x >= 0) + if (plane.y >= 0) + if (plane.z >= 0) { + if (maxX*plane.x + maxY*plane.y + maxZ*plane.z <= plane.offset) return -1; + if (minX*plane.x + minY*plane.y + minZ*plane.z > plane.offset) culling &= (63 & ~side); + } else { + if (maxX*plane.x + maxY*plane.y + minZ*plane.z <= plane.offset) return -1; + if (minX*plane.x + minY*plane.y + maxZ*plane.z > plane.offset) culling &= (63 & ~side); + } + else + if (plane.z >= 0) { + if (maxX*plane.x + minY*plane.y + maxZ*plane.z <= plane.offset) return -1; + if (minX*plane.x + maxY*plane.y + minZ*plane.z > plane.offset) culling &= (63 & ~side); + } else { + if (maxX*plane.x + minY*plane.y + minZ*plane.z <= plane.offset) return -1; + if (minX*plane.x + maxY*plane.y + maxZ*plane.z > plane.offset) culling &= (63 & ~side); + } + else if (plane.y >= 0) + if (plane.z >= 0) { + if (minX*plane.x + maxY*plane.y + maxZ*plane.z <= plane.offset) return -1; + if (maxX*plane.x + minY*plane.y + minZ*plane.z > plane.offset) culling &= (63 & ~side); + } else { + if (minX*plane.x + maxY*plane.y + minZ*plane.z <= plane.offset) return -1; + if (maxX*plane.x + minY*plane.y + maxZ*plane.z > plane.offset) culling &= (63 & ~side); + } + else if (plane.z >= 0) { if (minX*plane.x + minY*plane.y + maxZ*plane.z <= plane.offset) return -1; if (maxX*plane.x + maxY*plane.y + minZ*plane.z > plane.offset) culling &= (63 & ~side); } else { @@ -95,9 +102,9 @@ package alternativa.engine3d.core { } return culling; } - + /** - * @private + * @private */ alternativa3d function checkOcclusion(occluders:Vector., occludersLength:int, transform:Transform3D):Boolean { var ax:Number = transform.a*minX + transform.b*minY + transform.c*minZ + transform.d; @@ -140,9 +147,9 @@ package alternativa.engine3d.core { } return false; } - + /** - * @private + * @private */ alternativa3d function checkRays(origins:Vector., directions:Vector., raysLength:int):Boolean { for (var i:int = 0; i < raysLength; i++) { @@ -269,7 +276,7 @@ package alternativa.engine3d.core { if (c >= b || d <= a) return false; return true; } - + /** * Duplicates an instance of BoundBox. * @return New BoundBox instance with same set of properties. @@ -284,7 +291,7 @@ package alternativa.engine3d.core { res.maxZ = maxZ; return res; } - + /** * Returns a string representation of BoundBox. * @return A string representation of BoundBox. @@ -292,6 +299,6 @@ package alternativa.engine3d.core { public function toString():String { return "[BoundBox " + "X:[" + minX.toFixed(2) + ", " + maxX.toFixed(2) + "] Y:[" + minY.toFixed(2) + ", " + maxY.toFixed(2) + "] Z:[" + minZ.toFixed(2) + ", " + maxZ.toFixed(2) + "]]"; } - + } } diff --git a/src/alternativa/engine3d/core/Camera3D.as b/src/alternativa/engine3d/core/Camera3D.as index e3bf0b4..4bd4c89 100644 --- a/src/alternativa/engine3d/core/Camera3D.as +++ b/src/alternativa/engine3d/core/Camera3D.as @@ -294,7 +294,7 @@ public class Camera3D extends Object3D { } occludersLength = j; occluders.length = j; - // Check light influence (?) + // Check light influence for (i = 0, j = 0; i < lightsLength; i++) { light = lights[i]; light.localToCameraTransform.calculateInversion(light.cameraToLocalTransform); @@ -303,11 +303,12 @@ 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, false); + 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) { + // TODO: Need check by occluders light.shadow.process(this); } lights[j] = light; @@ -1096,10 +1097,10 @@ public class Camera3D extends Object3D { value = 1000 * fpsUpdatePeriod / (time - previousPeriodTime); if (value > stageFrameRate) value = stageFrameRate; mod = value * 100 % 100; - fpsTextField.text = int(value) + "." + ((mod >= 10) ? mod : ((mod > 0) ? ("0" + mod) : "00")); + fpsTextField.text = int(value) + "." + ((mod >= 10) ? mod.toString() : ((mod > 0) ? ("0" + mod) : "00")); value = 1000 / value; mod = value * 100 % 100; - frameTextField.text = int(value) + "." + ((mod >= 10) ? mod : ((mod > 0) ? ("0" + mod) : "00")); + frameTextField.text = int(value) + "." + ((mod >= 10) ? mod.toString() : ((mod > 0) ? ("0" + mod) : "00")); previousPeriodTime = time; fpsUpdateCounter = 0; } @@ -1116,14 +1117,14 @@ public class Camera3D extends Object3D { if (methodTimeCount > 0) { value = methodTimeSum / methodTimeCount; mod = value * 100 % 100; - timerTextField.text = int(value) + "." + ((mod >= 10) ? mod : ((mod > 0) ? ("0" + mod) : "00")); + timerTextField.text = int(value) + "." + ((mod >= 10) ? mod.toString() : ((mod > 0) ? ("0" + mod) : "00")); } else { timerTextField.text = ""; } if (cpuTimeCount > 0) { value = cpuTimeSum / cpuTimeCount; mod = value * 100 % 100; - cpuTextField.text = int(value) + "." + ((mod >= 10) ? mod : ((mod > 0) ? ("0" + mod) : "00")); + cpuTextField.text = int(value) + "." + ((mod >= 10) ? mod.toString() : ((mod > 0) ? ("0" + mod) : "00")); } else { cpuTextField.text = ""; } @@ -1138,7 +1139,7 @@ public class Camera3D extends Object3D { var memory:int = System.totalMemory; value = memory / 1048576; mod = value * 100 % 100; - memoryTextField.text = int(value) + "." + ((mod >= 10) ? mod : ((mod > 0) ? ("0" + mod) : "00")); + memoryTextField.text = int(value) + "." + ((mod >= 10) ? mod.toString() : ((mod > 0) ? ("0" + mod) : "00")); // memory plot if (memory > maxMemory) maxMemory = memory; diff --git a/src/alternativa/engine3d/core/Light3D.as b/src/alternativa/engine3d/core/Light3D.as index d7864fa..31fae99 100644 --- a/src/alternativa/engine3d/core/Light3D.as +++ b/src/alternativa/engine3d/core/Light3D.as @@ -121,8 +121,9 @@ package alternativa.engine3d.core { * @private */ public function set shadow(value:Shadow):void { + if (_shadow != null) _shadow._light = null; _shadow = value; - _shadow._light = this; + if (value != null) value._light = this; } } } diff --git a/src/alternativa/engine3d/lights/OmniLight.as b/src/alternativa/engine3d/lights/OmniLight.as index cb9b502..ee23aec 100644 --- a/src/alternativa/engine3d/lights/OmniLight.as +++ b/src/alternativa/engine3d/lights/OmniLight.as @@ -13,8 +13,6 @@ 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; @@ -202,14 +200,5 @@ 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/materials/StandardMaterial.as b/src/alternativa/engine3d/materials/StandardMaterial.as index 12efe54..aa7f30a 100644 --- a/src/alternativa/engine3d/materials/StandardMaterial.as +++ b/src/alternativa/engine3d/materials/StandardMaterial.as @@ -467,13 +467,22 @@ package alternativa.engine3d.materials { // i3 - ambient // i2 - shadow-test - source.push("mul t0.xw, t0.xw, i2.xw"); + source.push("mul t0.xw, t0.xwww, i2.xxxx"); 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"); + +// source.push("mov o1, t1"); +// source.push("mov o1, c1"); +// source.push("mov o1, i2"); +// source.push("mov o1, i3"); +// source.push("sub o1, t0, t0"); +// +// source.push("mov o0.xyz, i2.x"); +// source.push("div o0.w, i2.x, i2.x"); } else { // Считаем вектор из точки к свету @@ -1075,6 +1084,7 @@ package alternativa.engine3d.materials { var j:int; var lightLengthInGroup:int; var isFirstGroup:Boolean = true; + var j:int; for (i = 0; i < groupsCount; i++) { var lightGroup:Vector. = groups[i]; lightLengthInGroup = lightGroup.length; diff --git a/src/alternativa/engine3d/objects/Joint.as b/src/alternativa/engine3d/objects/Joint.as index a58b7af..481b53f 100644 --- a/src/alternativa/engine3d/objects/Joint.as +++ b/src/alternativa/engine3d/objects/Joint.as @@ -24,7 +24,7 @@ package alternativa.engine3d.objects { /** * @private - * A joint transform matrix. + * A joint transform matrix. Geometry -> Joint -> Skin */ alternativa3d var jointTransform:Transform3D = new Transform3D(); diff --git a/src/alternativa/engine3d/objects/Mesh.as b/src/alternativa/engine3d/objects/Mesh.as index 72a3afa..f3f486d 100644 --- a/src/alternativa/engine3d/objects/Mesh.as +++ b/src/alternativa/engine3d/objects/Mesh.as @@ -74,6 +74,8 @@ package alternativa.engine3d.objects { } } + // TODO: Add removeSurface() method + /** * Adds Surface to Mesh object. * @param material Material of the surface. diff --git a/src/alternativa/engine3d/shadows/DirectionalLightShadow.as b/src/alternativa/engine3d/shadows/DirectionalLightShadow.as index dc76fcf..6ab2a00 100644 --- a/src/alternativa/engine3d/shadows/DirectionalLightShadow.as +++ b/src/alternativa/engine3d/shadows/DirectionalLightShadow.as @@ -30,7 +30,7 @@ package alternativa.engine3d.shadows { import alternativa.engine3d.resources.ExternalTextureResource; import alternativa.engine3d.resources.Geometry; import alternativa.engine3d.resources.TextureResource; - + import flash.display3D.Context3D; import flash.display3D.Context3DProgramType; import flash.display3D.Context3DTextureFormat; @@ -56,13 +56,12 @@ package alternativa.engine3d.shadows { private var renderer:Renderer = new Renderer(); - /** - * Debug mode. - */ /** * Degree of correcting offset of shadow map space. It need for getting rid of self-shadowing artifacts. */ - public var biasMultiplier:Number = 0.99; + public var biasMultiplier:Number = 0.97; + + private static const DIFFERENCE_MULTIPLIER:Number = 32768; // TODO: implement property parent @@ -256,6 +255,7 @@ package alternativa.engine3d.shadows { override alternativa3d function process(camera:Camera3D):void { var i:int; var object:Object3D; + // TODO: realize culling // Clipping of casters, that have shadows which are invisible. var numActualCasters:int = 0; for (i = 0; i < _casters.length; i++) { @@ -351,6 +351,8 @@ package alternativa.engine3d.shadows { shadowMap = camera.context3D.createTexture(_mapSize, _mapSize, Context3DTextureFormat.BGRA, true); debugTexture._texture = shadowMap; } + // TODO Don't clear if there was no casters + camera.context3D.setRenderToTexture(shadowMap, true); camera.context3D.clear(1, 0, 0, 0.3); @@ -369,23 +371,21 @@ package alternativa.engine3d.shadows { camera.context3D.setRenderToBackBuffer(); if (debug) { - if (numActualCasters > 0) { - if (debugPlane == null) { - debugPlane = createDebugPlane(debugMaterial, camera.context3D); - } - // Form transformation matrix for debugPlane - debugPlane.transform.compose((frustumMinX + frustumMaxX) / 2, (frustumMinY + frustumMaxY) / 2, frustumMinZ, 0, 0, 0, (frustumMaxX - frustumMinX), (frustumMaxY - frustumMinY), 1); - debugPlane.localToCameraTransform.combine(_light.localToCameraTransform, debugPlane.transform); - - // Draw - var debugSurface:Surface = debugPlane._surfaces[0]; - 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, false, -1); + if (debugPlane == null) { + debugPlane = createDebugPlane(debugMaterial, camera.context3D); } + // Form transformation matrix for debugPlane + debugPlane.transform.compose((frustumMinX + frustumMaxX) / 2, (frustumMinY + frustumMaxY) / 2, frustumMinZ, 0, 0, 0, (frustumMaxX - frustumMinX), (frustumMaxY - frustumMinY), 1); + debugPlane.localToCameraTransform.combine(_light.localToCameraTransform, debugPlane.transform); + + // Draw + var debugSurface:Surface = debugPlane._surfaces[0]; + 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, false, -1); tempBounds.minX = frustumMinX; tempBounds.maxX = frustumMaxX; @@ -718,16 +718,15 @@ package alternativa.engine3d.shadows { 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); + drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -255*DIFFERENCE_MULTIPLIER, -DIFFERENCE_MULTIPLIER, biasMultiplier*255*DIFFERENCE_MULTIPLIER, 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); + drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cDist"), 0.9999, DIFFERENCE_MULTIPLIER, 1); } private static function getVShader():Procedure { diff --git a/src/alternativa/engine3d/shadows/OmniLightShadow.as b/src/alternativa/engine3d/shadows/OmniLightShadow.as index 1b8e845..8310ece 100644 --- a/src/alternativa/engine3d/shadows/OmniLightShadow.as +++ b/src/alternativa/engine3d/shadows/OmniLightShadow.as @@ -8,13 +8,14 @@ package alternativa.engine3d.shadows { import alternativa.engine3d.alternativa3d; + import alternativa.engine3d.core.BoundBox; import alternativa.engine3d.core.Camera3D; import alternativa.engine3d.core.DrawUnit; import alternativa.engine3d.core.Object3D; import alternativa.engine3d.core.Renderer; import alternativa.engine3d.core.Transform3D; import alternativa.engine3d.core.VertexAttributes; - import alternativa.engine3d.core.View; + import alternativa.engine3d.lights.OmniLight; import alternativa.engine3d.materials.Material; import alternativa.engine3d.materials.ShaderProgram; import alternativa.engine3d.materials.TextureMaterial; @@ -41,18 +42,31 @@ package alternativa.engine3d.shadows { public class OmniLightShadow extends Shadow{ + // TODO: calculate bias automaticaly /** - * Степень корректирующего смещения пространства карты теней для избавления от артефактов самозатенения. + * Degree of correcting offset of shadow map space. It need for getting rid of self-shadowing artifacts. */ - public var biasMultiplier:Number = 0.99; + public var biasMultiplier:Number = 0.97; + private static const DIFFERENCE_MULTIPLIER:Number = 32768; + private static const DEBUG_TYPE:String = "Sphere"; // Box + /** + * @private + */ + alternativa3d static var debugRadiusScale:Number = 0.5; private var renderer:Renderer = new Renderer(); - - private var boundSize:Number = 1; + + // radius of the light source + private var radius:Number = 100; + + // cube map size private var _mapSize:Number; + private var _pcfOffset:Number; private var cubeShadowMap:CubeTexture; + + // Sides cameras private var cameras:Vector. = new Vector.(); private var debugObject:Mesh; @@ -60,17 +74,18 @@ package alternativa.engine3d.shadows { 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(); + // caster -> cube face private var casterToEdgedCameraTransform:Transform3D = new Transform3D(); + // object -> light private var objectToLightTransform:Transform3D = new Transform3D(); + // casters count in edge + private var prevActualCastersMask:int; - private var prevActualCasterCountForEdge:Vector. = new Vector.(6); + private var cachedContext:Context3D; + private var programs:Dictionary = new Dictionary(); /** * Создает экземпляр OmniLightShadow. @@ -78,25 +93,27 @@ package alternativa.engine3d.shadows { * @param pcfOffset Смягчение границ тени. */ public function OmniLightShadow(mapSize:int = 128, pcfOffset:Number = 0) { + sections = new SectionPlane(0x11, 0x22, 0xC); // RU + sections.next = new SectionPlane(0x12, 0x21, 0xC); // LU + sections.next.next = new SectionPlane(0x14, 0x28, 0x3); // FU + sections.next.next.next = new SectionPlane(0x18, 0x24, 0x3); // BU + sections.next.next.next.next = new SectionPlane(0x5, 0xA, 0x30); // RF + sections.next.next.next.next.next = new SectionPlane(0x9, 0x6, 0x30); // RB this.mapSize = mapSize; this.pcfOffset = pcfOffset; + vertexShadowProcedure = getVShader(); type = _pcfOffset > 0 ? "OS" : "os"; fragmentShadowProcedure = _pcfOffset > 0 ? getFShaderPCF() : getFShader(); debugMaterial = new ShadowDebugMaterial(); - debugMaterial.alpha = 1.0; + debugMaterial.alpha = 0.3; for (var i:int = 0; i < 6; i++) { - // создаем камеры - var cam:Camera3D = new Camera3D(1, boundSize); + var cam:Camera3D = new Camera3D(radius/1000, radius); cam.fov = 1.910633237; - cam.view = new View(boundSize, boundSize); - cam.renderer = renderer; cameras[i] = cam; - - prevActualCasterCountForEdge[i] = 0; } // Left @@ -126,264 +143,406 @@ package alternativa.engine3d.shadows { cameras[4].composeTransforms(); } + private function createDebugObject(material:Material, context:Context3D):Mesh{ + var geometry:Geometry; + var mesh:Mesh; + if (DEBUG_TYPE == "Box") { + mesh = new Mesh(); + geometry = new Geometry(8); + mesh.geometry = geometry; - /** - * @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); + var attributes:Array = new Array(); + attributes[0] = VertexAttributes.POSITION; + attributes[1] = VertexAttributes.POSITION; + attributes[2] = VertexAttributes.POSITION; + geometry.addVertexStream(attributes); + + geometry.setAttributeValues(VertexAttributes.POSITION, Vector.([ + -1, -1, -1, + 1, -1, -1, + 1, 1, -1, + -1, 1, -1, + -1, -1, 1, + 1, -1, 1, + 1, 1, 1, + -1, 1, 1])); + geometry.indices = Vector.([ + 0, 1, 2, 3, 0, 2, 2, 1, 0, 3, 2, 0, + 2, 6, 1, 1, 6, 2, 1, 6, 5, 5, 6, 1, + 6, 4, 5, 5, 4, 6, 6, 4, 7, 7, 4, 6, + 0, 7, 4, 4, 7, 0, 0, 7, 3, 3, 7, 0, + 3, 6, 2, 2, 6, 3, 3, 7, 6, 6, 7, 3, + 0, 5, 1, 1, 5, 0, 0, 4, 5, 5, 4, 0]); + mesh.addSurface(material, 0, 24); + } else { + mesh = new GeoSphere(1, 4, true); + // Create two side + var triangles:Vector. = mesh.geometry.indices; + var numTriangles:int = triangles.length; + for (var i:int = 0; i < numTriangles; i += 3) { + var a:uint = triangles[i]; + var b:uint = triangles[int(i + 1)]; + var c:uint = triangles[int(i + 2)]; + triangles.push(c, b, a); + } + mesh.geometry.indices = triangles; + mesh.getSurface(0).numTriangles = triangles.length/3; + mesh.setMaterialToAllSurfaces(material); } - } - - 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); - + mesh.geometry.upload(context); return mesh; } - - // Вычисление шедоумапы + // Draw in shadow map override alternativa3d function process(camera:Camera3D):void { var i:int; var j:int; var caster:Object3D; var context:Context3D = camera.context3D; - var castersCount:int = _casters.length; - // Отсечение кастеров, тени которых не видны - // Обработка смены контекста + // Checking changed context if (context != cachedContext) { programs = new Dictionary(); cubeShadowMap = null; cachedContext = context; - for (i = 0; i < cameras.length; i++) { - cameras[i].context3D = cachedContext; - } } + // Culling invisible casters 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); - } + prevActualCastersMask = 63; } - // предрасчитаем некоторые матрицы трансформации - 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-и камерам + // Calculate parameters + radius = OmniLight(_light).attenuationEnd; for (i = 0; i < 6; i++) { - // камера соответствующая грани куба + var cam:Camera3D = cameras[i]; + cam.nearClipping = radius/1000; + cam.farClipping = radius; + cam.calculateProjection(1, 1); + } + + var castersCount:int = _casters.length; + actualCastersCount = 0; + + for (i = 0; i < castersCount; i++) { + caster = _casters[i]; + + var visible:Boolean = caster.visible; + var parent:Object3D = caster._parent; + while (visible && parent != null) { + visible = parent.visible; + parent = parent._parent; + } + + if (visible) { + // calculate transform matrices + _light.lightToObjectTransform.combine(caster.cameraToLocalTransform, _light.localToCameraTransform); + caster.localToLightTransform.combine(_light.cameraToLocalTransform, caster.localToCameraTransform); + + // collect actualCasters for light + if (caster.boundBox == null || OmniLight(_light).checkBound(caster)){ + actualCasters[actualCastersCount] = caster; + actualCastersCount++; + + // Pack camera culling + caster.culling <<= 16; + if (caster.boundBox != null) { + // 1 - calculate planes in object space + calculatePlanes(caster.localToLightTransform); + // 2 - check object location cameras (sections) + caster.culling |= recognizeObjectCameras(caster.boundBox); + } + } + + // update Skin Joints matrices + var skin:Skin = caster as Skin; + if (skin != null) { + // Calculate joints matrices + for (var child:Object3D = skin.childrenList; child != null; child = child.next) { + if (child.transformChanged) child.composeTransforms(); + // Write transformToSkin matrix to localToGlobalTransform property + child.localToGlobalTransform.copy(child.transform); + if (child is Joint) { + Joint(child).calculateTransform(); + } + skin.calculateJointsTransforms(child); + } + } + + if (caster.childrenList != null) collectActualChildren(caster); + } + } + + // Iterate through six cameras + for (i = 0; i < 6; i++) { + // Cube side camera var edgeCamera:Camera3D = cameras[i]; - // проверяем, есть ли видимые кастеры попадающие на грань куба - 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){ + var edgeBit:int = (1< 0) { // Настройка параметров рендеринга: - renderer.camera = edgeCamera; + renderer.camera = camera; context.setRenderToTexture(cubeShadowMap, true, 0, i); context.clear(1, 0, 0, 0.0); // Пробегаемся по кастерам - for (j = 0; j >= 16; + } + if (debug) { - if (actualCastersCount > 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); + // Create debug object if needed + if (debugObject == null) { + debugObject = createDebugObject(debugMaterial, camera.context3D); } + debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = debugRadiusScale; + debugObject.composeTransforms(); + + // Формируем матрицу трансформации для debugObject + debugObject.localToCameraTransform.combine(_light.localToCameraTransform, debugObject.transform); + + // Отрисовываем + var debugSurface:Surface = debugObject._surfaces[0]; + debugMaterial.collectDraws(camera, debugSurface, debugObject.geometry, null, 0, false, -1); } + actualCasters.length = 0; } - // предрасчитывает матрицы для всех детей - // 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) { + private function collectActualChildren(root:Object3D):void{ + for (var child:Object3D = root.childrenList; child != null; child = child.next) { + if (child.visible){ + // calculate transform matrices + _light.lightToObjectTransform.combine(child.cameraToLocalTransform, _light.localToCameraTransform); + child.localToLightTransform.combine(_light.cameraToLocalTransform, child.localToCameraTransform); - // расчет матриц трансформаций для объектов - if (child.transformChanged) child.composeTransforms(); - child.localToLightTransform.combine(root.localToLightTransform, child.transform); - child.lightToLocalTransform.combine(child.inverseTransform, root.lightToLocalTransform); + // collect actualCasters for light + if (child.boundBox == null || OmniLight(_light).checkBound(child)){ + actualCasters[actualCastersCount] = child; + actualCastersCount++; - // расчет матриц трансформаций для скинов - 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(); + // Pack camera culling + child.culling <<= 16; + if (child.boundBox != null) { + // 1 - calculate planes in object space + calculatePlanes(child.localToLightTransform); + // 2 - check object location cameras (sections) + child.culling |= recognizeObjectCameras(child.boundBox); } - 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); + // update Skin Joints matrices + var skin:Skin = child as Skin; + if (skin != null) { + // Calculate joints matrices + for (var skinChild:Object3D = skin.childrenList; skinChild != null; skinChild = skinChild.next) { + if (skinChild.transformChanged) skinChild.composeTransforms(); + // Write transformToSkin matrix to localToGlobalTransform property + skinChild.localToGlobalTransform.copy(skinChild.transform); + if (skinChild is Joint) { + Joint(skinChild).calculateTransform(); } - } - // Если дочерних объектов нет - else{ - // добавляем кастер в список актуальных кастеров - actualCasters[actualCastersCount++] = root; + skin.calculateJointsTransforms(skinChild); } } + + if (child.childrenList != null) collectActualChildren(child); } } } + private var sections:SectionPlane; + + private function calculatePlanes(transform:Transform3D):void { + // DUBFLR + var planeRU:SectionPlane = sections; + var planeLU:SectionPlane = sections.next; + var planeFU:SectionPlane = sections.next.next; + var planeBU:SectionPlane = sections.next.next.next; + var planeRF:SectionPlane = sections.next.next.next.next; + var planeRB:SectionPlane = sections.next.next.next.next.next; + + // 1, 0, 1 + planeRU.x = transform.a + transform.i; + planeRU.y = transform.b + transform.j; + planeRU.z = transform.c + transform.k; + planeRU.offset = -(transform.d + transform.l); + + // -1, 0, 1 + planeLU.x = transform.i - transform.a; + planeLU.y = transform.j - transform.b; + planeLU.z = transform.k - transform.c; + planeLU.offset = transform.d - transform.l; + + // 0, 1, 1 + planeFU.x = transform.e + transform.i; + planeFU.y = transform.f + transform.j; + planeFU.z = transform.g + transform.k; + planeFU.offset = -(transform.h + transform.l); + + // 0, -1, 1 + planeBU.x = transform.i - transform.e; + planeBU.y = transform.j - transform.f; + planeBU.z = transform.k - transform.g; + planeBU.offset = transform.h - transform.l; + + // 1, 1, 0 + planeRF.x = transform.a + transform.e; + planeRF.y = transform.b + transform.f; + planeRF.z = transform.c + transform.g; + planeRF.offset = -(transform.d + transform.h); + + // 1, -1, 0 + planeRB.x = transform.a - transform.e; + planeRB.y = transform.b - transform.f; + planeRB.z = transform.c - transform.g; + planeRB.offset = transform.h - transform.d; + + // var ax:Number = transform.c - transform.a + transform.b; // E +// var ay:Number = transform.g - transform.e + transform.f; +// var az:Number = transform.k - transform.i + transform.j; +// var bx:Number = transform.c - transform.a - transform.b; // H +// var by:Number = transform.g - transform.e - transform.f; +// var bz:Number = transform.k - transform.i - transform.j; +// planeRU.x = bz * ay - by * az; +// planeRU.y = bx * az - bz * ax; +// planeRU.z = by * ax - bx * ay; +// planeRU.offset = transform.d*planeRU.x + transform.h*planeRU.y + transform.l*planeRU.z; +// +// ax = transform.c + transform.a - transform.b; // D +// ay = transform.g + transform.e - transform.f; +// az = transform.k + transform.i - transform.j; +// bx = transform.c + transform.a + transform.b; // A +// by = transform.g + transform.e + transform.f; +// bz = transform.k + transform.i + transform.j; +// planeLU.x = bz * ay - by * az; +// planeLU.y = bx * az - bz * ax; +// planeLU.z = by * ax - bx * ay; +// planeLU.offset = transform.d*planeLU.x + transform.h*planeLU.y + transform.l*planeLU.z; +// +// ax = transform.c - transform.a - transform.b; // H +// ay = transform.g - transform.e - transform.f; +// az = transform.k - transform.i - transform.j; +// bx = transform.c + transform.a - transform.b; // D +// by = transform.g + transform.e - transform.f; +// bz = transform.k + transform.i - transform.j; +// planeFU.x = bz * ay - by * az; +// planeFU.y = bx * az - bz * ax; +// planeFU.z = by * ax - bx * ay; +// planeFU.offset = transform.d*planeFU.x + transform.h*planeFU.y + transform.l*planeFU.z; +// +// ax = transform.c + transform.a + transform.b; // A +// ay = transform.g + transform.e + transform.f; +// az = transform.k + transform.i + transform.j; +// bx = transform.c - transform.a + transform.b; // E +// by = transform.g - transform.e + transform.f; +// bz = transform.k - transform.i + transform.j; +// planeBU.x = bz * ay - by * az; +// planeBU.y = bx * az - bz * ax; +// planeBU.z = by * ax - bx * ay; +// planeBU.offset = transform.d*planeBU.x + transform.h*planeBU.y + transform.l*planeBU.z; +// +// ax = transform.a - transform.b + transform.c; // D +// ay = transform.e - transform.f + transform.g; +// az = transform.i - transform.j + transform.k; +// bx = transform.a - transform.b - transform.c; // C +// by = transform.e - transform.f - transform.g; +// bz = transform.i - transform.j - transform.k; +// planeRF.x = bz * ay - by * az; +// planeRF.y = bx * az - bz * ax; +// planeRF.z = by * ax - bx * ay; +// planeRF.offset = transform.d*planeRF.x + transform.h*planeRF.y + transform.l*planeRF.z; +// +// ax = transform.a + transform.b - transform.c; // B +// ay = transform.e + transform.f - transform.g; +// az = transform.i + transform.j - transform.k; +// bx = transform.a + transform.b + transform.c; // A +// by = transform.e + transform.f + transform.g; +// bz = transform.i + transform.j + transform.k; +// planeRB.x = bz * ay - by * az; +// planeRB.y = bx * az - bz * ax; +// planeRB.z = by * ax - bx * ay; +// planeRB.offset = transform.d*planeRB.x + transform.h*planeRB.y + transform.l*planeRB.z; + } + + private function recognizeObjectCameras(bb:BoundBox):int { + var culling:int = 63; + for (var plane:SectionPlane = sections; plane != null; plane = plane.next) { + var result:int = 0; + + if (plane.x >= 0) + if (plane.y >= 0) + if (plane.z >= 0) { + if (bb.maxX*plane.x + bb.maxY*plane.y + bb.maxZ*plane.z >= plane.offset) result = plane.frontCameras; + if (bb.minX*plane.x + bb.minY*plane.y + bb.minZ*plane.z < plane.offset) result |= plane.backCameras; + } else { + if (bb.maxX*plane.x + bb.maxY*plane.y + bb.minZ*plane.z >= plane.offset) result = plane.frontCameras; + if (bb.minX*plane.x + bb.minY*plane.y + bb.maxZ*plane.z < plane.offset) result |= plane.backCameras; + } + else + if (plane.z >= 0) { + if (bb.maxX*plane.x + bb.minY*plane.y + bb.maxZ*plane.z >= plane.offset) result = plane.frontCameras; + if (bb.minX*plane.x + bb.maxY*plane.y + bb.minZ*plane.z < plane.offset) result |= plane.backCameras; + } else { + if (bb.maxX*plane.x + bb.minY*plane.y + bb.minZ*plane.z >= plane.offset) result = plane.frontCameras; + if (bb.minX*plane.x + bb.maxY*plane.y + bb.maxZ*plane.z < plane.offset) result |= plane.backCameras; + } + else if (plane.y >= 0) + if (plane.z >= 0) { + if (bb.minX*plane.x + bb.maxY*plane.y + bb.maxZ*plane.z >= plane.offset) result = plane.frontCameras; + if (bb.maxX*plane.x + bb.minY*plane.y + bb.minZ*plane.z < plane.offset) result |= plane.backCameras; + } else { + if (bb.minX*plane.x + bb.maxY*plane.y + bb.minZ*plane.z >= plane.offset) result = plane.frontCameras; + if (bb.maxX*plane.x + bb.minY*plane.y + bb.maxZ*plane.z < plane.offset) result |= plane.backCameras; + } + else if (plane.z >= 0) { + if (bb.minX*plane.x + bb.minY*plane.y + bb.maxZ*plane.z >= plane.offset) result = plane.frontCameras; + if (bb.maxX*plane.x + bb.maxY*plane.y + bb.minZ*plane.z < plane.offset) result |= plane.backCameras; + } else { + if (bb.minX*plane.x + bb.minY*plane.y + bb.minZ*plane.z >= plane.offset) result = plane.frontCameras; + if (bb.maxX*plane.x + bb.maxY*plane.y + bb.maxZ*plane.z < plane.offset) result |= plane.backCameras; + } + culling &= result | plane.unusedBits; + } + return culling; + } private function collectDraws(context:Context3D, caster:Object3D, edgeCamera:Camera3D):void{ - // если объект является мешем, собираем для него дроуколы var mesh:Mesh = caster as Mesh; if (mesh != null && mesh.geometry != null) { @@ -458,20 +617,13 @@ package alternativa.engine3d.shadows { 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); + drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cConstants"), 1 / 255, 0, 255/radius, 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 координат во фрагментный шейдер @@ -525,15 +677,10 @@ package alternativa.engine3d.shadows { } 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", + "mov v0, t0.xyzx", "m44 o0, i0, c0" ]); @@ -550,13 +697,18 @@ package alternativa.engine3d.shadows { } } 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", + "#v0=vDistance", // xyz + "#c0=cConstants", // 1/255, 0, 255/radius, 1 + // calculate distance + "dp3 t0.z, v0.xyz, v0.xyz", + "sqt t0.z, t0.z", // x: [0, radius] + "mul t0.z, t0.z, c0.z", // x: [0, 255] + // codeing + "frc t0.y, t0.z", + "sub t0.x, t0.z, t0.y", "mul t0.x, t0.x, c0.x", - "mov t0.zw, c0.zw", + "mov t0.w, c0.w", "mov o0, t0" ])); program = new ShaderProgram(vLinker, fLinker); @@ -570,7 +722,7 @@ package alternativa.engine3d.shadows { - //------------- ShadowMap Shader ---------- + //------------- ShadowMap Shader in material---------- /** * @private @@ -584,16 +736,13 @@ package alternativa.engine3d.shadows { drawUnit.setTextureAt(fragmentLinker.getVariableIndex("sCubeMap"), cubeShadowMap); // Устанавливаем коеффициенты - // TODO: сделать множитель более корректный. Возможно 65536 (разрешающая способность глубины буфера). if (_pcfOffset > 0) { - - var offset:Number = _pcfOffset*0.0175; //1 градус + var offset:Number = Math.tan(_pcfOffset/180*Math.PI)/3; drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cPCFOffsets"), -3/2, 1/16, 0, 0); - drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -1, 1, 0, offset/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); + drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -1, 1, 0, offset); + drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cDecode"), -DIFFERENCE_MULTIPLIER, -DIFFERENCE_MULTIPLIER/255, biasMultiplier*DIFFERENCE_MULTIPLIER/radius, 10); + } else { + drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -DIFFERENCE_MULTIPLIER, -DIFFERENCE_MULTIPLIER/255, biasMultiplier*DIFFERENCE_MULTIPLIER/radius, 1.0); } } @@ -602,11 +751,8 @@ package alternativa.engine3d.shadows { "#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" + "mov v0, t0.xyz" ], "OmniShadowMapVertex"); shader.assignVariableName(VariableType.CONSTANT, 0, "cObjectToLightTransform", 3); return shader; @@ -620,14 +766,20 @@ package alternativa.engine3d.shadows { ]; 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.z, v0.xyz, v0.xyz"; + shaderArr[line++] = "sqt t0.z, t0.z"; // w: [0, radius] + shaderArr[line++] = "tex t0.xy, v0, s0 "; shaderArr[line++] = "dp3 t0.x, t0.xyz, c0.xyz"; // декодируем, находим разницу между расстояниями и умножаем ее на большое число // рассчитываем значение тени - shaderArr[line++] = "sat t0, t0.x"; + shaderArr[line++] = "sat t0.x, t0.x"; shaderArr[line++] = "sub o0, c0.w, t0.x"; +// shaderArr[line++] = "sat t0.x, t0.x"; +// shaderArr[line++] = "sub t0.x, c0.w, t0.x"; +// shaderArr[line++] = "sat t0.x, t0.x"; +// shaderArr[line++] = "mov o0, t0.x"; + return Procedure.compileFromArray(shaderArr, "OmniShadowMapFragment"); } @@ -645,49 +797,51 @@ package alternativa.engine3d.shadows { // допустимо использование временных переменных t0 t1 t2 t3 // v0 - sample - // v0.w - length(sample) [0, boundSize] - // ищем 2-а перпендикулярных вектора + // calculate 2 ortogonal vectors // (-y, x, 0) shaderArr[line++] = "mov t1.xyzw, v0.yxzw"; shaderArr[line++] = "mul t1.xyzw, t1.xyzw, c1.xyzz"; shaderArr[line++] = "crs t0.xyz, v0.xyz, t1.xyz"; - // нормируем их + // normalize vectors shaderArr[line++] = "nrm t0.xyz, t0.xyz"; shaderArr[line++] = "nrm t1.xyz, t1.xyz"; - // задаем оффсеты - shaderArr[line++] = "mul t0.w, c1.w, v0.w"; // с1.w = offset/boundSize + shaderArr[line++] = "dp3 t3.z, v0.xyz, v0.xyz"; + shaderArr[line++] = "sqt t3.z, t3.z"; // distance + + // apply pcf offset + shaderArr[line++] = "mul t0.w, c1.w, t3.z"; // с1.w = offset/radius shaderArr[line++] = "mul t0.xyz, t0.xyz, t0.w"; shaderArr[line++] = "mul t1.xyz, t1.xyz, t0.w"; // --------- {13 opcode} - // t0, t1 - перпендикуляры ↑→ - // t2 - текущий вектор + // t0, t1 - ortogonals ↑→ + // t2 - current vector - // в v0.w, t3.z расстояние до объекта - // t3.xy - результат из текстуры - // t3.w - сумма sat-ов + // t3.z distance to object + // t3.xy - result from shadow map + // t3.w - summ of sat - // первая точка + // first point shaderArr[line++] = "add t2.xyz, t0.xyz, t1.xyz"; shaderArr[line++] = "mul t2.xyz, t2.xyz, c2.xxx"; shaderArr[line++] = "add t2.xyz, t2.xyz, v0.xyz"; // получаем длинну из шадоумапы [0, 1] - shaderArr[line++] = "mov t3.z, v0.w"; +// shaderArr[line++] = "mov t3.z, t0.w"; - shaderArr[line++] = "tex t3.xy, t2.xyz, s0 "; + shaderArr[line++] = "tex t3.xy, t2.xyz, s0 "; shaderArr[line++] = "dp3 o0." +componentByIndex[0] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число //----- - for (j = 1; j<4; j++){ + 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++] = "tex t3.xy, t2.xyz, s0 "; shaderArr[line++] = "dp3 o0." +componentByIndex[j] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число } @@ -696,16 +850,16 @@ package alternativa.engine3d.shadows { //----- - for (i = 0; i<3; i++){ + 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++] = "tex t3.xy, t2.xyz, s0 "; shaderArr[line++] = "dp3 o0." +componentByIndex[0] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число - for (j = 1; j<4; j++){ + for (j = 1; j < 4; j++){ shaderArr[line++] = (i%2 == 1)?("add t2.xyz, t2.xyz, t1.xyz"):("sub t2.xyz, t2.xyz, t1.xyz"); - shaderArr[line++] = "tex t3.xy, t2.xyz, s0 "; + shaderArr[line++] = "tex t3.xy, t2.xyz, s0 "; shaderArr[line++] = "dp3 o0." +componentByIndex[j] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число } shaderArr[line++] = "sat o0, o0"; @@ -715,13 +869,12 @@ package alternativa.engine3d.shadows { shaderArr[line++] = "sub o0, c1.y, t3.w"; - //--------- {73 opcode} + //--------- {73 opcodes} return Procedure.compileFromArray(shaderArr, "OmniShadowMapFragment"); } private static const componentByIndex:Array = ["x", "y", "z", "w"]; - /** * Добавляет object в список объектов, отбрасывающих тень. * @param object Добавляемый объект. @@ -732,6 +885,12 @@ package alternativa.engine3d.shadows { } } + public function removeCaster(object:Object3D):void { + var index:int = _casters.indexOf(object); + if (index < 0) throw new Error("Caster not found"); + _casters[index] = _casters.pop(); + } + /** * Очищает список объектов, отбрасывающих тень. */ @@ -754,8 +913,8 @@ package alternativa.engine3d.shadows { 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."); + } else if (value > 1024) { + throw new ArgumentError("Map size exceeds maximum value 1024."); } if ((Math.log(value)/Math.LN2 % 1) != 0) { throw new ArgumentError("Map size must be power of two."); @@ -769,6 +928,7 @@ package alternativa.engine3d.shadows { /** * Смещение Percentage Closer Filtering. Этот способ фильтрации используется для смягчения границ тени. + * 1 pcfOffset equivalent 1 degree for all blur */ public function get pcfOffset():Number { return _pcfOffset; @@ -857,7 +1017,7 @@ class ShadowDebugMaterial extends Material { 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; @@ -868,6 +1028,10 @@ class ShadowDebugMaterial extends Material { } } + private function copyDrawUnit(source:DrawUnit, dest:DrawUnit):void { + + } + private function setupProgram(object:Object3D):ShaderProgram { var vertexLinker:Linker = new Linker(Context3DProgramType.VERTEX); var positionVar:String = "aPosition"; @@ -899,3 +1063,23 @@ class ShadowDebugMaterial extends Material { } +class SectionPlane { + + public var x:Number = 0; + public var y:Number = 0; + public var z:Number = 0; + public var offset:Number = 0; + + public var next:SectionPlane; + + public var frontCameras:int; + public var backCameras:int; + public var unusedBits:int = 63; + + public function SectionPlane(frontCameras:int, backCameras:int, unused:int) { + this.frontCameras = frontCameras; + this.backCameras = backCameras; + this.unusedBits = unused; + } + +}