From 3e4183293ab130461b065f4e5c9cfe2b8c51f024 Mon Sep 17 00:00:00 2001 From: Leonid Gaev Date: Thu, 26 Apr 2012 15:02:38 +0600 Subject: [PATCH 1/9] true calculation of distance --- src/alternativa/engine3d/lights/OmniLight.as | 16 +- .../engine3d/materials/StandardMaterial.as | 11 +- .../engine3d/shadows/OmniLightShadow.as | 178 ++++++++---------- 3 files changed, 107 insertions(+), 98 deletions(-) diff --git a/src/alternativa/engine3d/lights/OmniLight.as b/src/alternativa/engine3d/lights/OmniLight.as index cb9b502..c9db019 100644 --- a/src/alternativa/engine3d/lights/OmniLight.as +++ b/src/alternativa/engine3d/lights/OmniLight.as @@ -32,7 +32,7 @@ package alternativa.engine3d.lights { /** * Distance from at which falloff is complete. */ - public var attenuationEnd:Number; + public var _attenuationEnd:Number; /** * Creates a OmniLight object. @@ -211,5 +211,19 @@ package alternativa.engine3d.lights { var omniShadow:OmniLightShadow = value as OmniLightShadow; if (omniShadow!=null) omniShadow.setBoundSize(this.attenuationEnd*1.5); } + + public function get attenuationEnd():Number{ + return _attenuationEnd; + } + + /** + * @private + */ + public function set attenuationEnd(value:Number):void{ + // TODO: recalculate BoundBox + _attenuationEnd = value; + var omniShadow:OmniLightShadow = shadow as OmniLightShadow; + if (omniShadow!=null) omniShadow.setBoundSize(this._attenuationEnd*1.0); + } } } diff --git a/src/alternativa/engine3d/materials/StandardMaterial.as b/src/alternativa/engine3d/materials/StandardMaterial.as index 4459e88..8431c8b 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 { // Считаем вектор из точки к свету diff --git a/src/alternativa/engine3d/shadows/OmniLightShadow.as b/src/alternativa/engine3d/shadows/OmniLightShadow.as index caf9a0f..3397742 100644 --- a/src/alternativa/engine3d/shadows/OmniLightShadow.as +++ b/src/alternativa/engine3d/shadows/OmniLightShadow.as @@ -48,7 +48,7 @@ package alternativa.engine3d.shadows { private var renderer:Renderer = new Renderer(); - private var boundSize:Number = 1; + private var radius:Number = 1; private var _mapSize:Number; private var _pcfOffset:Number; @@ -90,9 +90,9 @@ package alternativa.engine3d.shadows { for (var i:int = 0; i < 6; i++) { // создаем камеры - var cam:Camera3D = new Camera3D(1, boundSize); + var cam:Camera3D = new Camera3D(10, radius); cam.fov = 1.910633237; - cam.view = new View(boundSize, boundSize); + cam.view = new View(radius, radius); cam.renderer = renderer; cameras[i] = cam; @@ -131,7 +131,7 @@ package alternativa.engine3d.shadows { * @private */ alternativa3d function setBoundSize(value:Number):void{ - this.boundSize = value; + this.radius = value; for (var i:int = 0; i < 6; i++) { var cam:Camera3D = cameras[i]; cam.view.width = cam.view.height = int (value); @@ -216,23 +216,23 @@ package alternativa.engine3d.shadows { 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); - } + if (caster.childrenList) + calculateChildrenTransforms(caster); + +// 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); +// } +// } + } @@ -294,7 +294,7 @@ package alternativa.engine3d.shadows { // Создаем дебаговый объект, если он не создан if (debugObject == null) { debugObject = createDebugCube(debugMaterial, camera.context3D); - debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = boundSize/12; + debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius/12; debugObject.composeTransforms(); } @@ -320,24 +320,23 @@ package alternativa.engine3d.shadows { 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); - } + if (child.childrenList) + calculateChildrenTransforms(child); + +// // расчет матриц трансформаций для скинов +// 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); +// } +// } } } @@ -357,26 +356,14 @@ package alternativa.engine3d.shadows { 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; - } - } + // добавляем кастер в список актуальных кастеров + if (casterCulling) + actualCasters[actualCastersCount++] = root; + + // Если есть дочерние объекты, + // Проверяем их на кулинг + for (var child:Object3D = root.childrenList; child != null; child = child.next) { + calculateVisibility(child, camera); } } } @@ -458,17 +445,11 @@ 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); - } } @@ -525,15 +506,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 +526,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 +551,7 @@ package alternativa.engine3d.shadows { - //------------- ShadowMap Shader ---------- + //------------- ShadowMap Shader in material---------- /** * @private @@ -587,13 +568,14 @@ package alternativa.engine3d.shadows { // TODO: сделать множитель более корректный. Возможно 65536 (разрешающая способность глубины буфера). if (_pcfOffset > 0) { - var offset:Number = _pcfOffset*0.0175; //1 градус + var offset:Number = _pcfOffset*0.0175; //TODO: make equivalent 1 offset ~ 1 degree 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); + drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -1, 1, 0, offset/radius); + drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cDecode"), -10000, -10000/255, biasMultiplier*10000/radius, 10); } else{ - drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -10000, -10000/255, biasMultiplier*10000/boundSize, 1); + drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -10000, -10000/255, biasMultiplier*10000/radius, 1.0); +// drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -100000, -100000/255, 1/radius, 1); } } @@ -602,11 +584,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 +599,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++] = "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,7 +630,6 @@ package alternativa.engine3d.shadows { // допустимо использование временных переменных t0 t1 t2 t3 // v0 - sample - // v0.w - length(sample) [0, boundSize] // ищем 2-а перпендикулярных вектора // (-y, x, 0) @@ -659,7 +643,9 @@ package alternativa.engine3d.shadows { 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"; // w: [0, radius] + 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} @@ -677,9 +663,9 @@ package alternativa.engine3d.shadows { 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"; // декодируем, вычитаем, умножаем на большое число //----- @@ -687,7 +673,7 @@ package alternativa.engine3d.shadows { 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"; // декодируем, вычитаем, умножаем на большое число } @@ -699,13 +685,13 @@ package alternativa.engine3d.shadows { 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++){ 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"; From 1268c217cc55f8a65f77c2ffa2afcfe7aae89366 Mon Sep 17 00:00:00 2001 From: Yaski Date: Thu, 26 Apr 2012 17:07:31 +0600 Subject: [PATCH 2/9] Some refactorings --- src/alternativa/engine3d/core/Camera3D.as | 10 +- .../shadows/DirectionalLightShadow.as | 5 +- .../engine3d/shadows/OmniLightShadow.as | 191 +++++++++--------- 3 files changed, 105 insertions(+), 101 deletions(-) diff --git a/src/alternativa/engine3d/core/Camera3D.as b/src/alternativa/engine3d/core/Camera3D.as index e3bf0b4..3e2eba1 100644 --- a/src/alternativa/engine3d/core/Camera3D.as +++ b/src/alternativa/engine3d/core/Camera3D.as @@ -1096,10 +1096,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 +1116,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 +1138,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/shadows/DirectionalLightShadow.as b/src/alternativa/engine3d/shadows/DirectionalLightShadow.as index dc76fcf..1e34ea2 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,9 +56,6 @@ 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. */ diff --git a/src/alternativa/engine3d/shadows/OmniLightShadow.as b/src/alternativa/engine3d/shadows/OmniLightShadow.as index 3397742..f4d6f4a 100644 --- a/src/alternativa/engine3d/shadows/OmniLightShadow.as +++ b/src/alternativa/engine3d/shadows/OmniLightShadow.as @@ -14,14 +14,12 @@ package alternativa.engine3d.shadows { 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; @@ -42,17 +40,22 @@ package alternativa.engine3d.shadows { public class OmniLightShadow extends Shadow{ /** - * Степень корректирующего смещения пространства карты теней для избавления от артефактов самозатенения. + * Degree of correcting offset of shadow map space. It need for getting rid of self-shadowing artifacts. */ public var biasMultiplier:Number = 0.99; private var renderer:Renderer = new Renderer(); - - private var radius: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,27 +63,30 @@ 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; + // cube face -> caster 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 prevActualCasterCountForEdge:Vector. = new Vector.(6); + private var cachedContext:Context3D; + private var programs:Dictionary = new Dictionary(); + /** * Создает экземпляр OmniLightShadow. * @param mapSize Размер карты теней. Должен быть степенью 2. * @param pcfOffset Смягчение границ тени. */ public function OmniLightShadow(mapSize:int = 128, pcfOffset:Number = 0) { - this.mapSize = mapSize; this.pcfOffset = pcfOffset; + vertexShadowProcedure = getVShader(); type = _pcfOffset > 0 ? "OS" : "os"; fragmentShadowProcedure = _pcfOffset > 0 ? getFShaderPCF() : getFShader(); @@ -89,11 +95,10 @@ package alternativa.engine3d.shadows { debugMaterial.alpha = 1.0; for (var i:int = 0; i < 6; i++) { - // создаем камеры + // Create cameras + // TODO: recalculate nearClipping var cam:Camera3D = new Camera3D(10, radius); cam.fov = 1.910633237; - cam.view = new View(radius, radius); - cam.renderer = renderer; cameras[i] = cam; prevActualCasterCountForEdge[i] = 0; @@ -124,9 +129,12 @@ package alternativa.engine3d.shadows { cameras[4].rotationX = 0; cameras[4].scaleY = -1; cameras[4].composeTransforms(); - } + // TODO: boundBox of light? + // TODO: remove setBoundSize + } + /** * @private */ @@ -134,91 +142,89 @@ package alternativa.engine3d.shadows { this.radius = 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(); + private function createDebugObject(material:Material, context:Context3D):Mesh{ + var geometry:Geometry; + var mesh: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); + var isBox:Boolean = false; + if (isBox) { + mesh = new Mesh(); + geometry = new Geometry(8); + mesh.geometry = geometry; - geometry.upload(context); + 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); + } else { + mesh = new GeoSphere(1, 4, false); + mesh.setMaterialToAllSurfaces(material); + } + mesh.geometry.upload(context); return mesh; } - - // Вычисление шедоумапы + // Draw in shadow map override alternativa3d function process(camera:Camera3D):void { var i:int; var j:int; var caster:Object3D; var context:Context3D = camera.context3D; - 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; + // TODO: not clear here 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]; + var castersCount:int = _casters.length; + // calculating some transformation matrices + for (i = 0; i < castersCount; i++) { + caster = _casters[i]; if (caster.transformChanged) caster.composeTransforms(); caster.lightToLocalTransform.combine(caster.cameraToLocalTransform, _light.localToCameraTransform); caster.localToLightTransform.combine(_light.cameraToLocalTransform, caster.localToCameraTransform); - if (caster.childrenList) - calculateChildrenTransforms(caster); + if (caster.childrenList != null) calculateChildrenTransforms(caster); + // TODO: repair skin // var skin:Skin = caster as Skin; // if (skin != null) { // // Расчет матриц джоинтов @@ -235,10 +241,9 @@ package alternativa.engine3d.shadows { } - - // Пробегаемся по 6-и камерам + // Iterate through six cameras for (i = 0; i < 6; i++) { - // камера соответствующая грани куба + // Cube side camera var edgeCamera:Camera3D = cameras[i]; // проверяем, есть ли видимые кастеры попадающие на грань куба @@ -259,9 +264,9 @@ package alternativa.engine3d.shadows { } } - if (actualCastersCount>0){ + if (actualCastersCount > 0) { // Настройка параметров рендеринга: - renderer.camera = edgeCamera; + renderer.camera = camera; context.setRenderToTexture(cubeShadowMap, true, 0, i); context.clear(1, 0, 0, 0.0); @@ -293,7 +298,7 @@ package alternativa.engine3d.shadows { if (actualCastersCount > 0) { // Создаем дебаговый объект, если он не создан if (debugObject == null) { - debugObject = createDebugCube(debugMaterial, camera.context3D); + debugObject = createDebugObject(debugMaterial, camera.context3D); debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius/12; debugObject.composeTransforms(); } @@ -308,21 +313,19 @@ package alternativa.engine3d.shadows { } } - // предрасчитывает матрицы для всех детей + // Precalculate children matrices // 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) { + for (var child:Object3D = root.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); - if (child.childrenList) - calculateChildrenTransforms(child); - + if (child.childrenList != null) calculateChildrenTransforms(child); + + // TODO: repair skin // // расчет матриц трансформаций для скинов // var skin:Skin = child as Skin; // if (skin != null) { @@ -605,7 +608,7 @@ package alternativa.engine3d.shadows { 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"; @@ -631,33 +634,34 @@ package alternativa.engine3d.shadows { // допустимо использование временных переменных t0 t1 t2 t3 // v0 - sample - // ищем 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++] = "dp3 t3.z, v0.xyz, v0.xyz"; - shaderArr[line++] = "sqt t3.z, t3.z"; // w: [0, radius] + 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"; @@ -670,7 +674,7 @@ package alternativa.engine3d.shadows { //----- - 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 "; @@ -682,13 +686,13 @@ 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++] = "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 "; @@ -701,13 +705,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 Добавляемый объект. @@ -718,6 +721,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(); + } + /** * Очищает список объектов, отбрасывающих тень. */ @@ -790,8 +799,6 @@ 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; From 9da1b800049cff50651556084e53dfc5ae1d67a6 Mon Sep 17 00:00:00 2001 From: Yaski Date: Thu, 26 Apr 2012 18:31:17 +0600 Subject: [PATCH 3/9] omni shadows: Skin joints matrices calculation --- src/alternativa/Alternativa3D.as | 2 +- src/alternativa/engine3d/core/Camera3D.as | 5 +- src/alternativa/engine3d/objects/Joint.as | 2 +- .../engine3d/shadows/OmniLightShadow.as | 64 +++++++++---------- 4 files changed, 36 insertions(+), 37 deletions(-) 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/Camera3D.as b/src/alternativa/engine3d/core/Camera3D.as index 3e2eba1..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; 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/shadows/OmniLightShadow.as b/src/alternativa/engine3d/shadows/OmniLightShadow.as index f4d6f4a..624f7d3 100644 --- a/src/alternativa/engine3d/shadows/OmniLightShadow.as +++ b/src/alternativa/engine3d/shadows/OmniLightShadow.as @@ -20,6 +20,7 @@ package alternativa.engine3d.shadows { 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; @@ -215,30 +216,30 @@ package alternativa.engine3d.shadows { var castersCount:int = _casters.length; // calculating some transformation matrices + // TODO: not transform invisible objects for (i = 0; i < castersCount; i++) { caster = _casters[i]; 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) { + // 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) calculateChildrenTransforms(caster); - - // TODO: repair skin -// 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); -// } -// } - } // Iterate through six cameras @@ -323,23 +324,21 @@ package alternativa.engine3d.shadows { child.localToLightTransform.combine(root.localToLightTransform, child.transform); child.lightToLocalTransform.combine(child.inverseTransform, root.lightToLocalTransform); - if (child.childrenList != null) calculateChildrenTransforms(child); + var skin:Skin = child as Skin; + if (skin != null) { + // Calculate joints matrices + for (var skinChild:Object3D = skin.childrenList; skinChild != null; skinChild = skinChild.next) { + if (skinChild.transformChanged) skinChild.composeTransforms(); + // Write transformToSkin matrix to localToGlobalTransform property + skinChild.localToGlobalTransform.copy(skinChild.transform); + if (skinChild is Joint) { + Joint(skinChild).calculateTransform(); + } + skin.calculateJointsTransforms(skinChild); + } + } - // TODO: repair skin -// // расчет матриц трансформаций для скинов -// 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); -// } -// } + if (child.childrenList != null) calculateChildrenTransforms(child); } } @@ -373,7 +372,6 @@ package alternativa.engine3d.shadows { private function collectDraws(context:Context3D, caster:Object3D, edgeCamera:Camera3D):void{ - // если объект является мешем, собираем для него дроуколы var mesh:Mesh = caster as Mesh; if (mesh != null && mesh.geometry != null) { From 24dc612ae56d5bfbde20c54b5a7ed12f0457a95f Mon Sep 17 00:00:00 2001 From: Yaski Date: Fri, 27 Apr 2012 17:10:10 +0600 Subject: [PATCH 4/9] Omni cull catch --- .../engine3d/shadows/OmniLightShadow.as | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/alternativa/engine3d/shadows/OmniLightShadow.as b/src/alternativa/engine3d/shadows/OmniLightShadow.as index 624f7d3..87086e7 100644 --- a/src/alternativa/engine3d/shadows/OmniLightShadow.as +++ b/src/alternativa/engine3d/shadows/OmniLightShadow.as @@ -216,7 +216,7 @@ package alternativa.engine3d.shadows { var castersCount:int = _casters.length; // calculating some transformation matrices - // TODO: not transform invisible objects + // TODO: skip invisible objects for (i = 0; i < castersCount; i++) { caster = _casters[i]; @@ -249,6 +249,14 @@ package alternativa.engine3d.shadows { // проверяем, есть ли видимые кастеры попадающие на грань куба actualCastersCount = 0; + numCulled = 0; + + var flipX:Boolean = edgeCamera.scaleX < 0; + var flipY:Boolean = edgeCamera.scaleY < 0; + edgeCamera.scaleX = 1; + edgeCamera.scaleY = 1; + edgeCamera.composeTransforms(); + for (j = 0; j < castersCount; j++) { caster = _casters[j]; @@ -264,6 +272,11 @@ package alternativa.engine3d.shadows { calculateVisibility(caster, edgeCamera); } } +// trace("face:" + i + " culled:" + numCulled + " rest:" + actualCastersCount); + + if (flipX) edgeCamera.scaleX = -1; + if (flipY) edgeCamera.scaleY = -1; + edgeCamera.composeTransforms(); if (actualCastersCount > 0) { // Настройка параметров рендеринга: @@ -272,7 +285,7 @@ package alternativa.engine3d.shadows { context.clear(1, 0, 0, 0.0); // Пробегаемся по кастерам - for (j = 0; j = 0) { + actualCasters[actualCastersCount] = root; + actualCastersCount++ + } // Если есть дочерние объекты, // Проверяем их на кулинг @@ -370,7 +390,6 @@ package alternativa.engine3d.shadows { } } - private function collectDraws(context:Context3D, caster:Object3D, edgeCamera:Camera3D):void{ // если объект является мешем, собираем для него дроуколы var mesh:Mesh = caster as Mesh; From 38b6af446b98572bd0af679a627c3cbefb71141a Mon Sep 17 00:00:00 2001 From: Leonid Gaev Date: Thu, 3 May 2012 18:05:45 +0600 Subject: [PATCH 5/9] OmniShadowLight - new culling --- src/alternativa/engine3d/core/BoundBox.as | 69 +-- src/alternativa/engine3d/core/Object3D.as | 2 + src/alternativa/engine3d/lights/OmniLight.as | 20 +- src/alternativa/engine3d/loaders/ParserA3D.as | 10 +- .../shadows/DirectionalLightShadow.as | 2 + .../engine3d/shadows/OmniLightShadow.as | 486 +++++++++++++----- 6 files changed, 398 insertions(+), 191 deletions(-) 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/Object3D.as b/src/alternativa/engine3d/core/Object3D.as index 460e642..4b1a003 100644 --- a/src/alternativa/engine3d/core/Object3D.as +++ b/src/alternativa/engine3d/core/Object3D.as @@ -302,6 +302,8 @@ package alternativa.engine3d.core { */ alternativa3d var culling:int; + public var cameras:uint; + /** * @private */ diff --git a/src/alternativa/engine3d/lights/OmniLight.as b/src/alternativa/engine3d/lights/OmniLight.as index c9db019..abb1e2c 100644 --- a/src/alternativa/engine3d/lights/OmniLight.as +++ b/src/alternativa/engine3d/lights/OmniLight.as @@ -32,7 +32,7 @@ package alternativa.engine3d.lights { /** * Distance from at which falloff is complete. */ - public var _attenuationEnd:Number; + public var attenuationEnd:Number; /** * Creates a OmniLight object. @@ -207,23 +207,7 @@ package alternativa.engine3d.lights { */ 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); + if (_shadow!=null) _shadow._light = this; } - - public function get attenuationEnd():Number{ - return _attenuationEnd; - } - - /** - * @private - */ - public function set attenuationEnd(value:Number):void{ - // TODO: recalculate BoundBox - _attenuationEnd = value; - var omniShadow:OmniLightShadow = shadow as OmniLightShadow; - if (omniShadow!=null) omniShadow.setBoundSize(this._attenuationEnd*1.0); - } } } diff --git a/src/alternativa/engine3d/loaders/ParserA3D.as b/src/alternativa/engine3d/loaders/ParserA3D.as index 15a6e8c..873bca4 100644 --- a/src/alternativa/engine3d/loaders/ParserA3D.as +++ b/src/alternativa/engine3d/loaders/ParserA3D.as @@ -58,7 +58,7 @@ public class ParserA3D extends Parser { * @param input ByteArray consists of A3D data. */ public function parse(input:ByteArray):void { - try { +// try { input.position = 0; var version:int = input.readByte(); if (version == 0) { @@ -69,10 +69,10 @@ public class ParserA3D extends Parser { // Bit of packing. It always equal to 1, because version 2 and above is always packed. parseVersionOver1(input); } - } catch (e:Error) { - e.message = "Parsing failed: " + e.message; - throw e; - } +// } catch (e:Error) { +// e.message = "Parsing failed: " + e.message; +// throw e; +// } } diff --git a/src/alternativa/engine3d/shadows/DirectionalLightShadow.as b/src/alternativa/engine3d/shadows/DirectionalLightShadow.as index 1e34ea2..b7563d4 100644 --- a/src/alternativa/engine3d/shadows/DirectionalLightShadow.as +++ b/src/alternativa/engine3d/shadows/DirectionalLightShadow.as @@ -348,6 +348,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); diff --git a/src/alternativa/engine3d/shadows/OmniLightShadow.as b/src/alternativa/engine3d/shadows/OmniLightShadow.as index 87086e7..4c471f0 100644 --- a/src/alternativa/engine3d/shadows/OmniLightShadow.as +++ b/src/alternativa/engine3d/shadows/OmniLightShadow.as @@ -8,13 +8,17 @@ package alternativa.engine3d.shadows { import alternativa.engine3d.alternativa3d; - import alternativa.engine3d.core.Camera3D; - import alternativa.engine3d.core.DrawUnit; +import alternativa.engine3d.core.BoundBox; +import alternativa.engine3d.core.Camera3D; +import alternativa.engine3d.core.CullingPlane; +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.materials.Material; +import alternativa.engine3d.lights.OmniLight; +import alternativa.engine3d.lights.OmniLight; +import alternativa.engine3d.materials.Material; import alternativa.engine3d.materials.ShaderProgram; import alternativa.engine3d.materials.TextureMaterial; import alternativa.engine3d.materials.compiler.Linker; @@ -36,7 +40,9 @@ package alternativa.engine3d.shadows { import flash.display3D.textures.CubeTexture; import flash.utils.Dictionary; - use namespace alternativa3d; +import spark.effects.easing.Elastic; + +use namespace alternativa3d; public class OmniLightShadow extends Shadow{ @@ -52,6 +58,7 @@ package alternativa.engine3d.shadows { // cube map size private var _mapSize:Number; + private var _pcfOffset:Number; private var cubeShadowMap:CubeTexture; @@ -64,6 +71,9 @@ package alternativa.engine3d.shadows { private var _casters:Vector. = new Vector.(); + + private var castersInLight:Vector. = new Vector.(); + private var castersInLightCount:int; private var actualCasters:Vector. = new Vector.(); private var actualCastersCount:int; @@ -74,7 +84,7 @@ package alternativa.engine3d.shadows { // object -> light private var objectToLightTransform:Transform3D = new Transform3D(); // casters count in edge - private var prevActualCasterCountForEdge:Vector. = new Vector.(6); + private var prevActualCastersMask:int; private var cachedContext:Context3D; private var programs:Dictionary = new Dictionary(); @@ -85,6 +95,13 @@ package alternativa.engine3d.shadows { * @param pcfOffset Смягчение границ тени. */ public function OmniLightShadow(mapSize:int = 128, pcfOffset:Number = 0) { + sections = new SectionPlane(); + sections.next = new SectionPlane(); + sections.next.next = new SectionPlane(); + sections.next.next.next = new SectionPlane(); + sections.next.next.next.next = new SectionPlane(); + sections.next.next.next.next.next = new SectionPlane(); + this.mapSize = mapSize; this.pcfOffset = pcfOffset; @@ -93,7 +110,7 @@ package alternativa.engine3d.shadows { fragmentShadowProcedure = _pcfOffset > 0 ? getFShaderPCF() : getFShader(); debugMaterial = new ShadowDebugMaterial(); - debugMaterial.alpha = 1.0; + debugMaterial.alpha = 0.3; for (var i:int = 0; i < 6; i++) { // Create cameras @@ -101,8 +118,6 @@ package alternativa.engine3d.shadows { var cam:Camera3D = new Camera3D(10, radius); cam.fov = 1.910633237; cameras[i] = cam; - - prevActualCasterCountForEdge[i] = 0; } // Left @@ -131,27 +146,16 @@ package alternativa.engine3d.shadows { cameras[4].scaleY = -1; cameras[4].composeTransforms(); + // DUBFLR - // TODO: boundBox of light? - // TODO: remove setBoundSize + + // TODO: overwrite calculateFrustum function or setTransformConstants function + // TODO: 2 step culling. 1-culling by radius for light. 2-culling for current camera by 4 planes } - /** - * @private - */ - alternativa3d function setBoundSize(value:Number):void{ - this.radius = value; - for (var i:int = 0; i < 6; i++) { - var cam:Camera3D = cameras[i]; - cam.farClipping = value; - cam.calculateProjection(value,value); - } - } - private function createDebugObject(material:Material, context:Context3D):Mesh{ var geometry:Geometry; var mesh:Mesh; - // TODO: определиться куб или сфера var isBox:Boolean = false; if (isBox) { mesh = new Mesh(); @@ -207,77 +211,89 @@ package alternativa.engine3d.shadows { if (cubeShadowMap == null) { cubeShadowMap = context.createCubeTexture(_mapSize, Context3DTextureFormat.BGRA, true); debugMaterial.cubeMap = cubeShadowMap; - // TODO: not clear here - for (i = 0; i < 6; i++) { - context.setRenderToTexture(cubeShadowMap, true, 0, i); - context.clear(1, 0, 0, 0.3); - } + prevActualCastersMask = 63; } + // Calculate parameters + radius = OmniLight(_light).attenuationEnd; + for (i = 0; i < 6; i++) { + var cam:Camera3D = cameras[i]; + cam.farClipping = radius; + cam.calculateProjection(radius, radius); + } + + var castersCount:int = _casters.length; - // calculating some transformation matrices - // TODO: skip invisible objects + actualCastersCount = 0; + for (i = 0; i < castersCount; i++) { caster = _casters[i]; - 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) { - // 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); - } + var visible:Boolean = caster.visible; + var parent:Object3D = caster._parent; + while (visible && parent != null) { + visible = parent.visible; + parent = parent._parent; } - if (caster.childrenList != null) calculateChildrenTransforms(caster); + 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++; + + if (caster.boundBox != null) { + // 1 - calculate planes in object space + calculatePlanes(_light.lightToObjectTransform); + // 2 - check object location cameras (sections) + caster.cameras = recognizeObjectCameras(caster.boundBox); + } + } else { + caster.cameras = 63; + } + + // 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; - numCulled = 0; +// var flipX:Boolean = edgeCamera.scaleX < 0; +// var flipY:Boolean = edgeCamera.scaleY < 0; +// edgeCamera.scaleX = 1; +// edgeCamera.scaleY = 1; +// edgeCamera.composeTransforms(); - var flipX:Boolean = edgeCamera.scaleX < 0; - var flipY:Boolean = edgeCamera.scaleY < 0; - edgeCamera.scaleX = 1; - edgeCamera.scaleY = 1; - edgeCamera.composeTransforms(); - - 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); - } - } -// trace("face:" + i + " culled:" + numCulled + " rest:" + actualCastersCount); - - if (flipX) edgeCamera.scaleX = -1; - if (flipY) edgeCamera.scaleY = -1; - edgeCamera.composeTransforms(); +// if (flipX) edgeCamera.scaleX = -1; +// if (flipY) edgeCamera.scaleY = -1; +// edgeCamera.composeTransforms(); + var edgeBit:int = (1< 0) { // Настройка параметров рендеринга: renderer.camera = camera; @@ -287,33 +303,59 @@ package alternativa.engine3d.shadows { // Пробегаемся по кастерам for (j = 0; j < actualCastersCount; j++) { caster = actualCasters[j]; - // собираем матрицу перевода из кастера в пространство edgeCamera - casterToEdgedCameraTransform.combine(edgeCamera.inverseTransform, caster.localToLightTransform); - // Собираем драуколлы для кастера и его дочерних объектов - collectDraws(context, caster, edgeCamera); + + // Проверить находится ли кастер в зоне 4-х плоскостей + if (caster.cameras & edgeBit) { + // собираем матрицу перевода из кастера в пространство edgeCamera + casterToEdgedCameraTransform.combine(edgeCamera.inverseTransform, caster.localToLightTransform); + // Собираем драуколлы для кастера и его дочерних объектов + collectDraws(context, caster, edgeCamera); + } } + if (renderer.drawUnits.length == 0) context.clear(0, 0, 0, 0.0); + // Отрисовка дроуколов renderer.render(context); + prevActualCastersMask |= edgeBit; } else{ // Если относительно одной из камер ничего не менялось, не вызываем отрисовочный вызов - if (prevActualCasterCountForEdge[i]!=0){ + + if (prevActualCastersMask & edgeBit){ context.setRenderToTexture(cubeShadowMap, false, 0, i); - context.clear(1, 0, 0, 0); + context.clear(0, 0, 0, 0); + + prevActualCastersMask &= ~edgeBit; } } - prevActualCasterCountForEdge[i] = actualCastersCount; } context.setRenderToBackBuffer(); +// // Пробегаемся по кастерам +// for (j = 0; j < actualCastersCount; j++) { +// caster = actualCasters[j]; +// caster.culling &= 0x8000003F; +// +// // Проверить находится ли кастер в зоне 4-х плоскостей +// if (caster.culling & (edgeBit << 8)) { +// // собираем матрицу перевода из кастера в пространство edgeCamera +// casterToEdgedCameraTransform.combine(edgeCamera.inverseTransform, caster.localToLightTransform); +// // Собираем драуколлы для кастера и его дочерних объектов +// collectDraws(context, caster, edgeCamera); +// } +// } if (debug) { - if (actualCastersCount > 0) { + if (actualCastersCount > 0 || true) { + // TODO: draw debug mesh always (DirectionalLightShadow) + // Создаем дебаговый объект, если он не создан if (debugObject == null) { debugObject = createDebugObject(debugMaterial, camera.context3D); - debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius/12; + // TODO: select wright radius +// debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius/12; + debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius; debugObject.composeTransforms(); } @@ -327,69 +369,205 @@ package alternativa.engine3d.shadows { } } - // Precalculate children matrices - // localToLightTransform, lightToLocalTransform, transform, и calculateTransform для Joint - private function calculateChildrenTransforms(root:Object3D):void{ - for (var child:Object3D = root.childrenList; child != null; child = child.next) { + private var sections:SectionPlane; - // расчет матриц трансформаций для объектов -// if (child.transformChanged) child.composeTransforms(); -// child.localToLightTransform.combine(root.localToLightTransform, child.transform); -// child.lightToLocalTransform.combine(child.inverseTransform, root.lightToLocalTransform); + private function calculatePlanes(lightToObjectTransform:Transform3D):void { + var planeRU:SectionPlane = sections; + var planeLU:SectionPlane = sections.next; - child.lightToLocalTransform.combine(child.cameraToLocalTransform, _light.localToCameraTransform); - child.localToLightTransform.combine(_light.cameraToLocalTransform, child.localToCameraTransform); + sections.x = 0.707; + sections.z = 0.707; + sections.offset = sections.x*lightToObjectTransform.d + sections.z*lightToObjectTransform.l; - 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(); + //var RIGHT_SIDE:int = 0; + + sections.frontCameras = 0x11; + sections.backCameras = 0x22; +// sections.unused = 0x33; + sections.unused = 0xC; + + planeLU.x = -0.707; + planeLU.z = 0.707; + planeLU.offset = planeLU.x*lightToObjectTransform.d + planeLU.z*lightToObjectTransform.l; + + planeLU.frontCameras = 0x12; + planeLU.backCameras = 0x21; + planeLU.unused = 0xC; + +// var nearPlane:CullingPlane = sections; +// var farPlane:CullingPlane = nearPlane.next; +// var leftPlane:CullingPlane = farPlane.next; +// var rightPlane:CullingPlane = leftPlane.next; +// var topPlane:CullingPlane = rightPlane.next; +// var bottomPlane:CullingPlane = topPlane.next; +// +// var fa:Number = transform.a * correctionX; +// var fe:Number = transform.e * correctionX; +// var fi:Number = transform.i * correctionX; +// var fb:Number = transform.b * correctionY; +// var ff:Number = transform.f * correctionY; +// var fj:Number = transform.j * correctionY; +// +// var ax:Number = -fa - fb + transform.c; +// var ay:Number = -fe - ff + transform.g; +// var az:Number = -fi - fj + transform.k; +// var bx:Number = fa - fb + transform.c; +// var by:Number = fe - ff + transform.g; +// var bz:Number = fi - fj + transform.k; +// topPlane.x = bz * ay - by * az; +// topPlane.y = bx * az - bz * ax; +// topPlane.z = by * ax - bx * ay; +// topPlane.offset = transform.d * topPlane.x + transform.h * topPlane.y + transform.l * topPlane.z; +// // Right plane. +// ax = bx; +// ay = by; +// az = bz; +// bx = fa + fb + transform.c; +// by = fe + ff + transform.g; +// bz = fi + fj + transform.k; +// rightPlane.x = bz * ay - by * az; +// rightPlane.y = bx * az - bz * ax; +// rightPlane.z = by * ax - bx * ay; +// rightPlane.offset = transform.d * rightPlane.x + transform.h * rightPlane.y + transform.l * rightPlane.z; +// // Bottom plane. +// ax = bx; +// ay = by; +// az = bz; +// bx = -fa + fb + transform.c; +// by = -fe + ff + transform.g; +// bz = -fi + fj + transform.k; +// bottomPlane.x = bz*ay - by*az; +// bottomPlane.y = bx*az - bz*ax; +// bottomPlane.z = by*ax - bx*ay; +// bottomPlane.offset = transform.d*bottomPlane.x + transform.h*bottomPlane.y + transform.l*bottomPlane.z; +// // Left plane. +// ax = bx; +// ay = by; +// az = bz; +// bx = -fa - fb + transform.c; +// by = -fe - ff + transform.g; +// bz = -fi - fj + transform.k; +// leftPlane.x = bz*ay - by*az; +// leftPlane.y = bx*az - bz*ax; +// leftPlane.z = by*ax - bx*ay; +// leftPlane.offset = transform.d*leftPlane.x + transform.h*leftPlane.y + transform.l*leftPlane.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; } - skin.calculateJointsTransforms(skinChild); + 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; } - } - - if (child.childrenList != null) calculateChildrenTransforms(child); - } - } - - private static var numCulled:int; - - // собирает список actualCasters для одной из 6-и камер - private function calculateVisibility(root:Object3D, camera:Camera3D):void{ - var casterCulling:int; - - if (root.visible) { - // Вычисляем результат кулинга для объекта - if (root.boundBox != null) { - edgeCameraToCasterTransform.combine(root.lightToLocalTransform, camera.transform); - camera.calculateFrustum(edgeCameraToCasterTransform); - casterCulling = root.boundBox.checkFrustumCulling(camera.frustum, 63); + 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 { - casterCulling = 63; + 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.unused; + } + return culling; + } - if (casterCulling <= 0) numCulled++; + 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 (casterCulling >= 0) { - actualCasters[actualCastersCount] = root; - actualCastersCount++ - } + // collect actualCasters for light + if (child.boundBox == null || OmniLight(_light).checkBound(child)){ + actualCasters[actualCastersCount] = child; + actualCastersCount++; - // Если есть дочерние объекты, - // Проверяем их на кулинг - for (var child:Object3D = root.childrenList; child != null; child = child.next) { - calculateVisibility(child, camera); + if (child.boundBox != null) { + // 1 - calculate planes in object space + calculatePlanes(_light.lightToObjectTransform); + // 2 - check object location cameras (sections) + child.cameras = recognizeObjectCameras(child.boundBox); + } + } else { + child.cameras = 63; + } + + // update Skin Joints matrices + var skin:Skin = child as Skin; + if (skin != null) { + // Calculate joints matrices + for (var skinChild:Object3D = skin.childrenList; skinChild != null; skinChild = skinChild.next) { + if (skinChild.transformChanged) skinChild.composeTransforms(); + // Write transformToSkin matrix to localToGlobalTransform property + skinChild.localToGlobalTransform.copy(skinChild.transform); + if (skinChild is Joint) { + Joint(skinChild).calculateTransform(); + } + skin.calculateJointsTransforms(skinChild); + } + } + + if (child.childrenList != null) collectActualChildren(child); } } } + +// // собирает список actualCasters для одной из 6-и камер +// private function calculateVisibility(root:Object3D, camera:Camera3D):void{ +// var casterCulling:int; +// +// if (root.visible) { +// // Вычисляем результат кулинга для объекта +// 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 <= 0) numCulled++; +// +// // добавляем кастер в список актуальных кастеров +// if (casterCulling >= 0) { +// actualCasters[actualCastersCount] = root; +// actualCastersCount++ +// } +// +// // Если есть дочерние объекты, +// // Проверяем их на кулинг +// for (var child:Object3D = root.childrenList; child != null; child = child.next) { +// calculateVisibility(child, camera); +// } +// } +// } + private function collectDraws(context:Context3D, caster:Object3D, edgeCamera:Camera3D):void{ // если объект является мешем, собираем для него дроуколы var mesh:Mesh = caster as Mesh; @@ -587,10 +765,10 @@ package alternativa.engine3d.shadows { // Устанавливаем коеффициенты // TODO: сделать множитель более корректный. Возможно 65536 (разрешающая способность глубины буфера). if (_pcfOffset > 0) { + var offset:Number = Math.tan(_pcfOffset/180*Math.PI)/3; - var offset:Number = _pcfOffset*0.0175; //TODO: make equivalent 1 offset ~ 1 degree drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cPCFOffsets"), -3/2, 1/16, 0, 0); - drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -1, 1, 0, offset/radius); + drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -1, 1, 0, offset); drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cDecode"), -10000, -10000/255, biasMultiplier*10000/radius, 10); } else{ @@ -781,6 +959,7 @@ package alternativa.engine3d.shadows { /** * Смещение Percentage Closer Filtering. Этот способ фильтрации используется для смягчения границ тени. + * 1 pcfOffset equivalent 1 degree for all blur */ public function get pcfOffset():Number { return _pcfOffset; @@ -816,6 +995,7 @@ import alternativa.engine3d.resources.Geometry; import flash.display3D.Context3D; import flash.display3D.Context3DBlendFactor; import flash.display3D.Context3DProgramType; +import flash.display3D.Context3DTriangleFace; import flash.display3D.VertexBuffer3D; import flash.display3D.textures.CubeTexture; import flash.utils.Dictionary; @@ -869,17 +1049,35 @@ 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); - + + // TODO: draw two-sided debug mesh + var drawUnit2:DrawUnit = camera.renderer.createDrawUnit(object, program.program, geometry._indexBuffer, surface.indexBegin, surface.numTriangles, program); + // Установка стримов + drawUnit2.setVertexBufferAt(program.vertexShader.getVariableIndex("aPosition"), positionBuffer, geometry._attributesOffsets[VertexAttributes.POSITION], VertexAttributes.FORMATS[VertexAttributes.POSITION]); + // Установка констант + drawUnit2.setProjectionConstants(camera, program.vertexShader.getVariableIndex("cProjMatrix"), object.localToCameraTransform); + drawUnit2.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cDecode"), 1, 1/255, 0, alpha); + drawUnit2.setTextureAt(program.fragmentShader.getVariableIndex("sCubeMap"), cubeMap); + drawUnit2.culling = Context3DTriangleFace.BACK; + // Отправка на отрисовку if (alpha < 1) { drawUnit.blendSource = Context3DBlendFactor.SOURCE_ALPHA; drawUnit.blendDestination = Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA; + drawUnit2.blendSource = Context3DBlendFactor.SOURCE_ALPHA; + drawUnit2.blendDestination = Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA; + camera.renderer.addDrawUnit(drawUnit2, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.TRANSPARENT_SORT); camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.TRANSPARENT_SORT); } else { + camera.renderer.addDrawUnit(drawUnit2, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.OPAQUE); camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.OPAQUE); } } + private function copyDrawUnit(source:DrawUnit, dest:DrawUnit):void { + + } + private function setupProgram(object:Object3D):ShaderProgram { var vertexLinker:Linker = new Linker(Context3DProgramType.VERTEX); var positionVar:String = "aPosition"; @@ -911,3 +1109,17 @@ 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 unused:int = 63; + +} From 441d463d93f1616806de32725cbca91595f05fed Mon Sep 17 00:00:00 2001 From: Yaski Date: Thu, 3 May 2012 20:55:13 +0600 Subject: [PATCH 6/9] Good culling of objects for CubeMap --- src/alternativa/engine3d/core/Light3D.as | 3 +- src/alternativa/engine3d/lights/OmniLight.as | 9 - src/alternativa/engine3d/loaders/ParserA3D.as | 10 +- .../engine3d/shadows/OmniLightShadow.as | 247 +++++++----------- 4 files changed, 101 insertions(+), 168 deletions(-) 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 abb1e2c..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,12 +200,5 @@ package alternativa.engine3d.lights { return res; } - /** - * @private - */ - override public function set shadow(value:Shadow):void { - _shadow = value; - if (_shadow!=null) _shadow._light = this; - } } } diff --git a/src/alternativa/engine3d/loaders/ParserA3D.as b/src/alternativa/engine3d/loaders/ParserA3D.as index 873bca4..15a6e8c 100644 --- a/src/alternativa/engine3d/loaders/ParserA3D.as +++ b/src/alternativa/engine3d/loaders/ParserA3D.as @@ -58,7 +58,7 @@ public class ParserA3D extends Parser { * @param input ByteArray consists of A3D data. */ public function parse(input:ByteArray):void { -// try { + try { input.position = 0; var version:int = input.readByte(); if (version == 0) { @@ -69,10 +69,10 @@ public class ParserA3D extends Parser { // Bit of packing. It always equal to 1, because version 2 and above is always packed. parseVersionOver1(input); } -// } catch (e:Error) { -// e.message = "Parsing failed: " + e.message; -// throw e; -// } + } catch (e:Error) { + e.message = "Parsing failed: " + e.message; + throw e; + } } diff --git a/src/alternativa/engine3d/shadows/OmniLightShadow.as b/src/alternativa/engine3d/shadows/OmniLightShadow.as index 4c471f0..de82472 100644 --- a/src/alternativa/engine3d/shadows/OmniLightShadow.as +++ b/src/alternativa/engine3d/shadows/OmniLightShadow.as @@ -8,17 +8,15 @@ package alternativa.engine3d.shadows { import alternativa.engine3d.alternativa3d; -import alternativa.engine3d.core.BoundBox; -import alternativa.engine3d.core.Camera3D; -import alternativa.engine3d.core.CullingPlane; -import alternativa.engine3d.core.DrawUnit; + import alternativa.engine3d.core.BoundBox; + import alternativa.engine3d.core.Camera3D; + import alternativa.engine3d.core.DrawUnit; import alternativa.engine3d.core.Object3D; import alternativa.engine3d.core.Renderer; import alternativa.engine3d.core.Transform3D; import alternativa.engine3d.core.VertexAttributes; -import alternativa.engine3d.lights.OmniLight; -import alternativa.engine3d.lights.OmniLight; -import alternativa.engine3d.materials.Material; + import alternativa.engine3d.lights.OmniLight; + import alternativa.engine3d.materials.Material; import alternativa.engine3d.materials.ShaderProgram; import alternativa.engine3d.materials.TextureMaterial; import alternativa.engine3d.materials.compiler.Linker; @@ -40,9 +38,7 @@ import alternativa.engine3d.materials.Material; import flash.display3D.textures.CubeTexture; import flash.utils.Dictionary; -import spark.effects.easing.Elastic; - -use namespace alternativa3d; + use namespace alternativa3d; public class OmniLightShadow extends Shadow{ @@ -71,14 +67,9 @@ use namespace alternativa3d; private var _casters:Vector. = new Vector.(); - - private var castersInLight:Vector. = new Vector.(); - private var castersInLightCount:int; private var actualCasters:Vector. = new Vector.(); private var actualCastersCount:int; - // cube face -> caster - private var edgeCameraToCasterTransform:Transform3D = new Transform3D(); // caster -> cube face private var casterToEdgedCameraTransform:Transform3D = new Transform3D(); // object -> light @@ -95,12 +86,12 @@ use namespace alternativa3d; * @param pcfOffset Смягчение границ тени. */ public function OmniLightShadow(mapSize:int = 128, pcfOffset:Number = 0) { - sections = new SectionPlane(); - sections.next = new SectionPlane(); - sections.next.next = new SectionPlane(); - sections.next.next.next = new SectionPlane(); - sections.next.next.next.next = new SectionPlane(); - sections.next.next.next.next.next = new SectionPlane(); + 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; @@ -145,12 +136,6 @@ use namespace alternativa3d; cameras[4].rotationX = 0; cameras[4].scaleY = -1; cameras[4].composeTransforms(); - - // DUBFLR - - - // TODO: overwrite calculateFrustum function or setTransformConstants function - // TODO: 2 step culling. 1-culling by radius for light. 2-culling for current camera by 4 planes } private function createDebugObject(material:Material, context:Context3D):Mesh{ @@ -222,7 +207,6 @@ use namespace alternativa3d; cam.calculateProjection(radius, radius); } - var castersCount:int = _casters.length; actualCastersCount = 0; @@ -236,6 +220,7 @@ use namespace alternativa3d; parent = parent._parent; } + // TODO: remove Object3D.cameras, use something another if (visible) { // calculate transform matrices _light.lightToObjectTransform.combine(caster.cameraToLocalTransform, _light.localToCameraTransform); @@ -255,7 +240,7 @@ use namespace alternativa3d; } else { caster.cameras = 63; } - + // update Skin Joints matrices var skin:Skin = caster as Skin; if (skin != null) { @@ -275,24 +260,11 @@ use namespace alternativa3d; } } - // Iterate through six cameras for (i = 0; i < 6; i++) { // Cube side camera var edgeCamera:Camera3D = cameras[i]; - - // проверяем, есть ли видимые кастеры попадающие на грань куба -// var flipX:Boolean = edgeCamera.scaleX < 0; -// var flipY:Boolean = edgeCamera.scaleY < 0; -// edgeCamera.scaleX = 1; -// edgeCamera.scaleY = 1; -// edgeCamera.composeTransforms(); - -// if (flipX) edgeCamera.scaleX = -1; -// if (flipY) edgeCamera.scaleY = -1; -// edgeCamera.composeTransforms(); - var edgeBit:int = (1< 0) { // Настройка параметров рендеринга: @@ -305,7 +277,7 @@ use namespace alternativa3d; caster = actualCasters[j]; // Проверить находится ли кастер в зоне 4-х плоскостей - if (caster.cameras & edgeBit) { + if ((caster.cameras & edgeBit)) { // собираем матрицу перевода из кастера в пространство edgeCamera casterToEdgedCameraTransform.combine(edgeCamera.inverseTransform, caster.localToLightTransform); // Собираем драуколлы для кастера и его дочерних объектов @@ -313,7 +285,7 @@ use namespace alternativa3d; } } - if (renderer.drawUnits.length == 0) context.clear(0, 0, 0, 0.0); +// if (renderer.drawUnits.length == 0) context.clear(0, 0, 0, 0.0); // Отрисовка дроуколов renderer.render(context); @@ -322,9 +294,9 @@ use namespace alternativa3d; else{ // Если относительно одной из камер ничего не менялось, не вызываем отрисовочный вызов - if (prevActualCastersMask & edgeBit){ + if ((prevActualCastersMask & edgeBit)){ context.setRenderToTexture(cubeShadowMap, false, 0, i); - context.clear(0, 0, 0, 0); + context.clear(1, 0, 0, 0); prevActualCastersMask &= ~edgeBit; } @@ -347,13 +319,13 @@ use namespace alternativa3d; // } if (debug) { - if (actualCastersCount > 0 || true) { + if (actualCastersCount > 0) { // TODO: draw debug mesh always (DirectionalLightShadow) - // Создаем дебаговый объект, если он не создан + // Create debug object if needed if (debugObject == null) { debugObject = createDebugObject(debugMaterial, camera.context3D); - // TODO: select wright radius + // TODO: select right radius // debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius/12; debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius; debugObject.composeTransforms(); @@ -371,86 +343,81 @@ use namespace alternativa3d; private var sections:SectionPlane; - private function calculatePlanes(lightToObjectTransform:Transform3D):void { + 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; - sections.x = 0.707; - sections.z = 0.707; - sections.offset = sections.x*lightToObjectTransform.d + sections.z*lightToObjectTransform.l; + // TODO: reuse points + var ax:Number = transform.c - transform.a + transform.b; + 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; + 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; - //var RIGHT_SIDE:int = 0; + ax = transform.c + transform.a - transform.b; + ay = transform.g + transform.e - transform.f; + az = transform.k + transform.i - transform.j; + bx = transform.c + transform.a + transform.b; + 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; - sections.frontCameras = 0x11; - sections.backCameras = 0x22; -// sections.unused = 0x33; - sections.unused = 0xC; + ax = transform.c - transform.a - transform.b; + ay = transform.g - transform.e - transform.f; + az = transform.k - transform.i - transform.j; + bx = transform.c + transform.a - transform.b; + 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; - planeLU.x = -0.707; - planeLU.z = 0.707; - planeLU.offset = planeLU.x*lightToObjectTransform.d + planeLU.z*lightToObjectTransform.l; + ax = transform.c + transform.a + transform.b; + ay = transform.g + transform.e + transform.f; + az = transform.k + transform.i + transform.j; + bx = transform.c - transform.a + transform.b; + 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; - planeLU.frontCameras = 0x12; - planeLU.backCameras = 0x21; - planeLU.unused = 0xC; + ax = transform.a - transform.b + transform.c; + ay = transform.e - transform.f + transform.g; + az = transform.i - transform.j + transform.k; + bx = transform.a - transform.b - transform.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; -// var nearPlane:CullingPlane = sections; -// var farPlane:CullingPlane = nearPlane.next; -// var leftPlane:CullingPlane = farPlane.next; -// var rightPlane:CullingPlane = leftPlane.next; -// var topPlane:CullingPlane = rightPlane.next; -// var bottomPlane:CullingPlane = topPlane.next; -// -// var fa:Number = transform.a * correctionX; -// var fe:Number = transform.e * correctionX; -// var fi:Number = transform.i * correctionX; -// var fb:Number = transform.b * correctionY; -// var ff:Number = transform.f * correctionY; -// var fj:Number = transform.j * correctionY; -// -// var ax:Number = -fa - fb + transform.c; -// var ay:Number = -fe - ff + transform.g; -// var az:Number = -fi - fj + transform.k; -// var bx:Number = fa - fb + transform.c; -// var by:Number = fe - ff + transform.g; -// var bz:Number = fi - fj + transform.k; -// topPlane.x = bz * ay - by * az; -// topPlane.y = bx * az - bz * ax; -// topPlane.z = by * ax - bx * ay; -// topPlane.offset = transform.d * topPlane.x + transform.h * topPlane.y + transform.l * topPlane.z; -// // Right plane. -// ax = bx; -// ay = by; -// az = bz; -// bx = fa + fb + transform.c; -// by = fe + ff + transform.g; -// bz = fi + fj + transform.k; -// rightPlane.x = bz * ay - by * az; -// rightPlane.y = bx * az - bz * ax; -// rightPlane.z = by * ax - bx * ay; -// rightPlane.offset = transform.d * rightPlane.x + transform.h * rightPlane.y + transform.l * rightPlane.z; -// // Bottom plane. -// ax = bx; -// ay = by; -// az = bz; -// bx = -fa + fb + transform.c; -// by = -fe + ff + transform.g; -// bz = -fi + fj + transform.k; -// bottomPlane.x = bz*ay - by*az; -// bottomPlane.y = bx*az - bz*ax; -// bottomPlane.z = by*ax - bx*ay; -// bottomPlane.offset = transform.d*bottomPlane.x + transform.h*bottomPlane.y + transform.l*bottomPlane.z; -// // Left plane. -// ax = bx; -// ay = by; -// az = bz; -// bx = -fa - fb + transform.c; -// by = -fe - ff + transform.g; -// bz = -fi - fj + transform.k; -// leftPlane.x = bz*ay - by*az; -// leftPlane.y = bx*az - bz*ax; -// leftPlane.z = by*ax - bx*ay; -// leftPlane.offset = transform.d*leftPlane.x + transform.h*leftPlane.y + transform.l*leftPlane.z; + ax = transform.a + transform.b - transform.c; + ay = transform.e + transform.f - transform.g; + az = transform.i + transform.j - transform.k; + bx = transform.a + transform.b + transform.c; + 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 { @@ -537,37 +504,6 @@ use namespace alternativa3d; } } - -// // собирает список actualCasters для одной из 6-и камер -// private function calculateVisibility(root:Object3D, camera:Camera3D):void{ -// var casterCulling:int; -// -// if (root.visible) { -// // Вычисляем результат кулинга для объекта -// 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 <= 0) numCulled++; -// -// // добавляем кастер в список актуальных кастеров -// if (casterCulling >= 0) { -// actualCasters[actualCastersCount] = root; -// actualCastersCount++ -// } -// -// // Если есть дочерние объекты, -// // Проверяем их на кулинг -// for (var child:Object3D = root.childrenList; child != null; child = child.next) { -// calculateVisibility(child, camera); -// } -// } -// } - private function collectDraws(context:Context3D, caster:Object3D, edgeCamera:Camera3D):void{ // если объект является мешем, собираем для него дроуколы var mesh:Mesh = caster as Mesh; @@ -650,7 +586,6 @@ use namespace alternativa3d; } } - /** * @private * Процедура для передачи UV координат во фрагментный шейдер @@ -1122,4 +1057,10 @@ class SectionPlane { public var backCameras:int; public var unused:int = 63; + public function SectionPlane(frontCameras:int, backCameras:int, unused:int) { + this.frontCameras = frontCameras; + this.backCameras = backCameras; + this.unused = unused; + } + } From 23aaee2f75fc52176b35f11a95e3b71f2837bdbf Mon Sep 17 00:00:00 2001 From: Yaski Date: Fri, 4 May 2012 16:04:01 +0600 Subject: [PATCH 7/9] Final refactorings --- src/alternativa/engine3d/core/Object3D.as | 2 - src/alternativa/engine3d/objects/Mesh.as | 2 + .../shadows/DirectionalLightShadow.as | 38 ++-- .../engine3d/shadows/OmniLightShadow.as | 166 ++++++++---------- 4 files changed, 97 insertions(+), 111 deletions(-) diff --git a/src/alternativa/engine3d/core/Object3D.as b/src/alternativa/engine3d/core/Object3D.as index 4b1a003..460e642 100644 --- a/src/alternativa/engine3d/core/Object3D.as +++ b/src/alternativa/engine3d/core/Object3D.as @@ -302,8 +302,6 @@ package alternativa.engine3d.core { */ alternativa3d var culling:int; - public var cameras:uint; - /** * @private */ 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 b7563d4..9b73941 100644 --- a/src/alternativa/engine3d/shadows/DirectionalLightShadow.as +++ b/src/alternativa/engine3d/shadows/DirectionalLightShadow.as @@ -61,6 +61,8 @@ package alternativa.engine3d.shadows { */ public var biasMultiplier:Number = 0.99; + private static const DIFFERENCE_MULTIPLIER:Number = 32768; + // TODO: implement property parent /** @@ -253,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++) { @@ -368,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; @@ -717,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 de82472..c206ac9 100644 --- a/src/alternativa/engine3d/shadows/OmniLightShadow.as +++ b/src/alternativa/engine3d/shadows/OmniLightShadow.as @@ -46,6 +46,7 @@ package alternativa.engine3d.shadows { * Degree of correcting offset of shadow map space. It need for getting rid of self-shadowing artifacts. */ public var biasMultiplier:Number = 0.99; + private static const DIFFERENCE_MULTIPLIER:Number = 32768; private var renderer:Renderer = new Renderer(); @@ -104,9 +105,7 @@ package alternativa.engine3d.shadows { debugMaterial.alpha = 0.3; for (var i:int = 0; i < 6; i++) { - // Create cameras - // TODO: recalculate nearClipping - var cam:Camera3D = new Camera3D(10, radius); + var cam:Camera3D = new Camera3D(radius/1000, radius); cam.fov = 1.910633237; cameras[i] = cam; } @@ -154,14 +153,14 @@ package alternativa.engine3d.shadows { 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])); + -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, @@ -171,7 +170,18 @@ package alternativa.engine3d.shadows { 0, 5, 1, 1, 5, 0, 0, 4, 5, 5, 4, 0]); mesh.addSurface(material, 0, 24); } else { - mesh = new GeoSphere(1, 4, false); + mesh = new GeoSphere(1, 4, true); + // Create two side + var triangles:Vector. = mesh.geometry.indices; + var numTriangles:int = triangles.length; + for (var i:int = 0; i < numTriangles; i += 3) { + var a:uint = triangles[i]; + var b:uint = triangles[int(i + 1)]; + var c:uint = triangles[int(i + 2)]; + triangles.push(c, b, a); + } + mesh.geometry.indices = triangles; + mesh.getSurface(0).numTriangles = triangles.length/3; mesh.setMaterialToAllSurfaces(material); } mesh.geometry.upload(context); @@ -203,8 +213,9 @@ package alternativa.engine3d.shadows { radius = OmniLight(_light).attenuationEnd; for (i = 0; i < 6; i++) { var cam:Camera3D = cameras[i]; + cam.nearClipping = radius/1000; cam.farClipping = radius; - cam.calculateProjection(radius, radius); + cam.calculateProjection(1, 1); } var castersCount:int = _casters.length; @@ -220,12 +231,13 @@ package alternativa.engine3d.shadows { parent = parent._parent; } - // TODO: remove Object3D.cameras, use something another if (visible) { // calculate transform matrices _light.lightToObjectTransform.combine(caster.cameraToLocalTransform, _light.localToCameraTransform); caster.localToLightTransform.combine(_light.cameraToLocalTransform, caster.localToCameraTransform); + // Pack camera culling + caster.culling <<= 16; // collect actualCasters for light if (caster.boundBox == null || OmniLight(_light).checkBound(caster)){ actualCasters[actualCastersCount] = caster; @@ -235,10 +247,10 @@ package alternativa.engine3d.shadows { // 1 - calculate planes in object space calculatePlanes(_light.lightToObjectTransform); // 2 - check object location cameras (sections) - caster.cameras = recognizeObjectCameras(caster.boundBox); + caster.culling |= recognizeObjectCameras(caster.boundBox); } } else { - caster.cameras = 63; + caster.culling |= 63; } // update Skin Joints matrices @@ -277,7 +289,7 @@ package alternativa.engine3d.shadows { caster = actualCasters[j]; // Проверить находится ли кастер в зоне 4-х плоскостей - if ((caster.cameras & edgeBit)) { + if ((caster.culling & edgeBit)) { // собираем матрицу перевода из кастера в пространство edgeCamera casterToEdgedCameraTransform.combine(edgeCamera.inverseTransform, caster.localToLightTransform); // Собираем драуколлы для кастера и его дочерних объектов @@ -285,6 +297,7 @@ package alternativa.engine3d.shadows { } } + // TODO: remove debug culling rendering // if (renderer.drawUnits.length == 0) context.clear(0, 0, 0, 0.0); // Отрисовка дроуколов @@ -304,41 +317,31 @@ package alternativa.engine3d.shadows { } context.setRenderToBackBuffer(); -// // Пробегаемся по кастерам -// for (j = 0; j < actualCastersCount; j++) { -// caster = actualCasters[j]; -// caster.culling &= 0x8000003F; -// -// // Проверить находится ли кастер в зоне 4-х плоскостей -// if (caster.culling & (edgeBit << 8)) { -// // собираем матрицу перевода из кастера в пространство edgeCamera -// casterToEdgedCameraTransform.combine(edgeCamera.inverseTransform, caster.localToLightTransform); -// // Собираем драуколлы для кастера и его дочерних объектов -// collectDraws(context, caster, edgeCamera); -// } -// } - - if (debug) { - if (actualCastersCount > 0) { - // TODO: draw debug mesh always (DirectionalLightShadow) - - // Create debug object if needed - if (debugObject == null) { - debugObject = createDebugObject(debugMaterial, camera.context3D); - // TODO: select right radius -// debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius/12; - debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius; - 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); - } + // Unpack camera culling value + for (j = 0; j < actualCastersCount; j++) { + caster = actualCasters[j]; + // If there was -1, after shift it will be -1 too + caster.culling >>= 16; } + + if (debug) { + // Create debug object if needed + if (debugObject == null) { + debugObject = createDebugObject(debugMaterial, camera.context3D); + // TODO: select right radius + } +// debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius/12; + debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius; + debugObject.composeTransforms(); + + // Формируем матрицу трансформации для debugObject + debugObject.localToCameraTransform.combine(_light.localToCameraTransform, debugObject.transform); + + // Отрисовываем + var debugSurface:Surface = debugObject._surfaces[0]; + debugMaterial.collectDraws(camera, debugSurface, debugObject.geometry, null, 0, false, -1); + } + actualCasters.length = 0; } private var sections:SectionPlane; @@ -353,10 +356,10 @@ package alternativa.engine3d.shadows { var planeRB:SectionPlane = sections.next.next.next.next.next; // TODO: reuse points - var ax:Number = transform.c - transform.a + transform.b; + 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; + 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; @@ -364,10 +367,10 @@ package alternativa.engine3d.shadows { 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; + 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; + 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; @@ -375,10 +378,10 @@ package alternativa.engine3d.shadows { 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; + 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; + 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; @@ -386,10 +389,10 @@ package alternativa.engine3d.shadows { 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; + 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; + 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; @@ -397,10 +400,10 @@ package alternativa.engine3d.shadows { 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; + 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; + 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; @@ -408,10 +411,10 @@ package alternativa.engine3d.shadows { 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; + 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; + 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; @@ -457,7 +460,7 @@ package alternativa.engine3d.shadows { 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.unused; + culling &= result | plane.unusedBits; } return culling; } @@ -469,6 +472,8 @@ package alternativa.engine3d.shadows { _light.lightToObjectTransform.combine(child.cameraToLocalTransform, _light.localToCameraTransform); child.localToLightTransform.combine(_light.cameraToLocalTransform, child.localToCameraTransform); + // Pack camera culling + child.culling <<= 16; // collect actualCasters for light if (child.boundBox == null || OmniLight(_light).checkBound(child)){ actualCasters[actualCastersCount] = child; @@ -478,10 +483,10 @@ package alternativa.engine3d.shadows { // 1 - calculate planes in object space calculatePlanes(_light.lightToObjectTransform); // 2 - check object location cameras (sections) - child.cameras = recognizeObjectCameras(child.boundBox); + child.culling |= recognizeObjectCameras(child.boundBox); } } else { - child.cameras = 63; + child.culling |= 63; } // update Skin Joints matrices @@ -698,17 +703,13 @@ package alternativa.engine3d.shadows { drawUnit.setTextureAt(fragmentLinker.getVariableIndex("sCubeMap"), cubeShadowMap); // Устанавливаем коеффициенты - // TODO: сделать множитель более корректный. Возможно 65536 (разрешающая способность глубины буфера). if (_pcfOffset > 0) { var offset:Number = Math.tan(_pcfOffset/180*Math.PI)/3; - drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cPCFOffsets"), -3/2, 1/16, 0, 0); drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -1, 1, 0, offset); - drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cDecode"), -10000, -10000/255, biasMultiplier*10000/radius, 10); - } - else{ - drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -10000, -10000/255, biasMultiplier*10000/radius, 1.0); -// drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -100000, -100000/255, 1/radius, 1); + 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); } } @@ -930,7 +931,6 @@ import alternativa.engine3d.resources.Geometry; import flash.display3D.Context3D; import flash.display3D.Context3DBlendFactor; import flash.display3D.Context3DProgramType; -import flash.display3D.Context3DTriangleFace; import flash.display3D.VertexBuffer3D; import flash.display3D.textures.CubeTexture; import flash.utils.Dictionary; @@ -985,26 +985,12 @@ class ShadowDebugMaterial extends Material { drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cDecode"), 1, 1/255, 0, alpha); drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sCubeMap"), cubeMap); - // TODO: draw two-sided debug mesh - var drawUnit2:DrawUnit = camera.renderer.createDrawUnit(object, program.program, geometry._indexBuffer, surface.indexBegin, surface.numTriangles, program); - // Установка стримов - drawUnit2.setVertexBufferAt(program.vertexShader.getVariableIndex("aPosition"), positionBuffer, geometry._attributesOffsets[VertexAttributes.POSITION], VertexAttributes.FORMATS[VertexAttributes.POSITION]); - // Установка констант - drawUnit2.setProjectionConstants(camera, program.vertexShader.getVariableIndex("cProjMatrix"), object.localToCameraTransform); - drawUnit2.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cDecode"), 1, 1/255, 0, alpha); - drawUnit2.setTextureAt(program.fragmentShader.getVariableIndex("sCubeMap"), cubeMap); - drawUnit2.culling = Context3DTriangleFace.BACK; - // Отправка на отрисовку if (alpha < 1) { drawUnit.blendSource = Context3DBlendFactor.SOURCE_ALPHA; drawUnit.blendDestination = Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA; - drawUnit2.blendSource = Context3DBlendFactor.SOURCE_ALPHA; - drawUnit2.blendDestination = Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA; - camera.renderer.addDrawUnit(drawUnit2, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.TRANSPARENT_SORT); camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.TRANSPARENT_SORT); } else { - camera.renderer.addDrawUnit(drawUnit2, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.OPAQUE); camera.renderer.addDrawUnit(drawUnit, objectRenderPriority >= 0 ? objectRenderPriority : Renderer.OPAQUE); } } @@ -1055,12 +1041,12 @@ class SectionPlane { public var frontCameras:int; public var backCameras:int; - public var unused:int = 63; + public var unusedBits:int = 63; public function SectionPlane(frontCameras:int, backCameras:int, unused:int) { this.frontCameras = frontCameras; this.backCameras = backCameras; - this.unused = unused; + this.unusedBits = unused; } } From f48bbd16cefd3bf16196a1517d9e499eab90841c Mon Sep 17 00:00:00 2001 From: Yaski Date: Fri, 4 May 2012 18:45:49 +0600 Subject: [PATCH 8/9] OmniShadows tuned and finished --- .../engine3d/shadows/OmniLightShadow.as | 172 +++++++++++------- 1 file changed, 102 insertions(+), 70 deletions(-) diff --git a/src/alternativa/engine3d/shadows/OmniLightShadow.as b/src/alternativa/engine3d/shadows/OmniLightShadow.as index c206ac9..1b2020c 100644 --- a/src/alternativa/engine3d/shadows/OmniLightShadow.as +++ b/src/alternativa/engine3d/shadows/OmniLightShadow.as @@ -47,6 +47,7 @@ package alternativa.engine3d.shadows { */ public var biasMultiplier:Number = 0.99; private static const DIFFERENCE_MULTIPLIER:Number = 32768; + private static const DEBUG_TYPE:String = "Sphere"; // Box private var renderer:Renderer = new Renderer(); @@ -140,8 +141,7 @@ package alternativa.engine3d.shadows { private function createDebugObject(material:Material, context:Context3D):Mesh{ var geometry:Geometry; var mesh:Mesh; - var isBox:Boolean = false; - if (isBox) { + if (DEBUG_TYPE == "Box") { mesh = new Mesh(); geometry = new Geometry(8); mesh.geometry = geometry; @@ -245,7 +245,7 @@ package alternativa.engine3d.shadows { if (caster.boundBox != null) { // 1 - calculate planes in object space - calculatePlanes(_light.lightToObjectTransform); + calculatePlanes(caster.localToLightTransform); // 2 - check object location cameras (sections) caster.culling |= recognizeObjectCameras(caster.boundBox); } @@ -297,10 +297,9 @@ package alternativa.engine3d.shadows { } } - // TODO: remove debug culling rendering -// if (renderer.drawUnits.length == 0) context.clear(0, 0, 0, 0.0); +// if (renderer.drawUnits.length == 0) context.clear(0, 0, 0, 0.0); - // Отрисовка дроуколов + // Drawing renderer.render(context); prevActualCastersMask |= edgeBit; } @@ -328,9 +327,7 @@ package alternativa.engine3d.shadows { // Create debug object if needed if (debugObject == null) { debugObject = createDebugObject(debugMaterial, camera.context3D); - // TODO: select right radius } -// debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius/12; debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius; debugObject.composeTransforms(); @@ -355,72 +352,107 @@ package alternativa.engine3d.shadows { var planeRF:SectionPlane = sections.next.next.next.next; var planeRB:SectionPlane = sections.next.next.next.next.next; - // TODO: reuse points - 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; + // 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); - 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; + // -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; - 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; + // 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); - 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; + // 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; - 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; + // 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); - 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; + // 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 { @@ -481,7 +513,7 @@ package alternativa.engine3d.shadows { if (child.boundBox != null) { // 1 - calculate planes in object space - calculatePlanes(_light.lightToObjectTransform); + calculatePlanes(child.localToLightTransform); // 2 - check object location cameras (sections) child.culling |= recognizeObjectCameras(child.boundBox); } From faa14a3b0aa232ac0c208e48135544c826ee65b8 Mon Sep 17 00:00:00 2001 From: Yaski Date: Thu, 10 May 2012 16:47:08 +0600 Subject: [PATCH 9/9] Remove dup variable. Changed biasMultiplyer=0.97. Fixed few bug with culling. --- .../engine3d/materials/StandardMaterial.as | 5 +- .../shadows/DirectionalLightShadow.as | 2 +- .../engine3d/shadows/OmniLightShadow.as | 105 +++++++++--------- 3 files changed, 57 insertions(+), 55 deletions(-) diff --git a/src/alternativa/engine3d/materials/StandardMaterial.as b/src/alternativa/engine3d/materials/StandardMaterial.as index 8431c8b..7bb11f2 100644 --- a/src/alternativa/engine3d/materials/StandardMaterial.as +++ b/src/alternativa/engine3d/materials/StandardMaterial.as @@ -1084,6 +1084,7 @@ package alternativa.engine3d.materials { else{ var lightLengthInGroup:int; var isFirstGroup:Boolean = true; + var j:int; for (i = 0; i < groupsCount; i++) { var lightGroup:Vector. = groups[i]; lightLengthInGroup = lightGroup.length; @@ -1095,7 +1096,7 @@ package alternativa.engine3d.materials { (_normalMapSpace.toString()) + ((glossinessMap != null) ? "G" : "g") + ((specularMap != null) ? "S" : "s"); - for (var j:int = 0; j < lightLengthInGroup; j++) { + for (j = 0; j < lightLengthInGroup; j++) { light = lightGroup[j]; materialKey += light.lightID; } @@ -1134,7 +1135,7 @@ package alternativa.engine3d.materials { if (shadowGroupLength>0){ // Group of ligths with shadow // For each light we will create new drawUnit - for (var j:int = 0; j < shadowGroupLength; j++) { + for (j = 0; j < shadowGroupLength; j++) { light = shadowGroup[j]; // Form key diff --git a/src/alternativa/engine3d/shadows/DirectionalLightShadow.as b/src/alternativa/engine3d/shadows/DirectionalLightShadow.as index 9b73941..6ab2a00 100644 --- a/src/alternativa/engine3d/shadows/DirectionalLightShadow.as +++ b/src/alternativa/engine3d/shadows/DirectionalLightShadow.as @@ -59,7 +59,7 @@ package alternativa.engine3d.shadows { /** * 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; diff --git a/src/alternativa/engine3d/shadows/OmniLightShadow.as b/src/alternativa/engine3d/shadows/OmniLightShadow.as index 1b2020c..8310ece 100644 --- a/src/alternativa/engine3d/shadows/OmniLightShadow.as +++ b/src/alternativa/engine3d/shadows/OmniLightShadow.as @@ -42,12 +42,17 @@ 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(); @@ -236,21 +241,19 @@ package alternativa.engine3d.shadows { _light.lightToObjectTransform.combine(caster.cameraToLocalTransform, _light.localToCameraTransform); caster.localToLightTransform.combine(_light.cameraToLocalTransform, caster.localToCameraTransform); - // Pack camera culling - caster.culling <<= 16; // 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); } - } else { - caster.culling |= 63; } // update Skin Joints matrices @@ -328,7 +331,7 @@ package alternativa.engine3d.shadows { if (debugObject == null) { debugObject = createDebugObject(debugMaterial, camera.context3D); } - debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius; + debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = debugRadiusScale; debugObject.composeTransforms(); // Формируем матрицу трансформации для debugObject @@ -341,6 +344,48 @@ package alternativa.engine3d.shadows { actualCasters.length = 0; } + private function collectActualChildren(root:Object3D):void{ + for (var child:Object3D = root.childrenList; child != null; child = child.next) { + if (child.visible){ + // calculate transform matrices + _light.lightToObjectTransform.combine(child.cameraToLocalTransform, _light.localToCameraTransform); + child.localToLightTransform.combine(_light.cameraToLocalTransform, child.localToCameraTransform); + + // collect actualCasters for light + if (child.boundBox == null || OmniLight(_light).checkBound(child)){ + actualCasters[actualCastersCount] = child; + actualCastersCount++; + + // Pack camera culling + child.culling <<= 16; + if (child.boundBox != null) { + // 1 - calculate planes in object space + calculatePlanes(child.localToLightTransform); + // 2 - check object location cameras (sections) + child.culling |= recognizeObjectCameras(child.boundBox); + } + } + + // update Skin Joints matrices + var skin:Skin = child as Skin; + if (skin != null) { + // Calculate joints matrices + for (var skinChild:Object3D = skin.childrenList; skinChild != null; skinChild = skinChild.next) { + if (skinChild.transformChanged) skinChild.composeTransforms(); + // Write transformToSkin matrix to localToGlobalTransform property + skinChild.localToGlobalTransform.copy(skinChild.transform); + if (skinChild is Joint) { + Joint(skinChild).calculateTransform(); + } + skin.calculateJointsTransforms(skinChild); + } + } + + if (child.childrenList != null) collectActualChildren(child); + } + } + } + private var sections:SectionPlane; private function calculatePlanes(transform:Transform3D):void { @@ -497,50 +542,6 @@ package alternativa.engine3d.shadows { return culling; } - 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); - - // Pack camera culling - child.culling <<= 16; - // collect actualCasters for light - if (child.boundBox == null || OmniLight(_light).checkBound(child)){ - actualCasters[actualCastersCount] = child; - actualCastersCount++; - - if (child.boundBox != null) { - // 1 - calculate planes in object space - calculatePlanes(child.localToLightTransform); - // 2 - check object location cameras (sections) - child.culling |= recognizeObjectCameras(child.boundBox); - } - } else { - child.culling |= 63; - } - - // update Skin Joints matrices - var skin:Skin = child as Skin; - if (skin != null) { - // Calculate joints matrices - for (var skinChild:Object3D = skin.childrenList; skinChild != null; skinChild = skinChild.next) { - if (skinChild.transformChanged) skinChild.composeTransforms(); - // Write transformToSkin matrix to localToGlobalTransform property - skinChild.localToGlobalTransform.copy(skinChild.transform); - if (skinChild is Joint) { - Joint(skinChild).calculateTransform(); - } - skin.calculateJointsTransforms(skinChild); - } - } - - if (child.childrenList != null) collectActualChildren(child); - } - } - } - private function collectDraws(context:Context3D, caster:Object3D, edgeCamera:Camera3D):void{ // если объект является мешем, собираем для него дроуколы var mesh:Mesh = caster as Mesh; @@ -912,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.");