Merge remote-tracking branch 'origin/8.29.BugOmniShadow'

This commit is contained in:
Yaski
2012-05-10 18:35:02 +06:00
10 changed files with 541 additions and 348 deletions

View File

@@ -17,6 +17,6 @@ package alternativa {
/** /**
* Library version in the format: generation.feature-version.fix-version. * 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";
} }
} }

View File

@@ -65,25 +65,32 @@ package alternativa.engine3d.core {
var side:int = 1; var side:int = 1;
for (var plane:CullingPlane = frustum; plane != null; plane = plane.next) { for (var plane:CullingPlane = frustum; plane != null; plane = plane.next) {
if (culling & side) { if (culling & side) {
if (plane.x >= 0) if (plane.y >= 0) 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 (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); if (minX*plane.x + minY*plane.y + minZ*plane.z > plane.offset) culling &= (63 & ~side);
} else { } else {
if (maxX*plane.x + maxY*plane.y + minZ*plane.z <= plane.offset) return -1; 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); if (minX*plane.x + minY*plane.y + maxZ*plane.z > plane.offset) culling &= (63 & ~side);
} else if (plane.z >= 0) { }
else
if (plane.z >= 0) {
if (maxX*plane.x + minY*plane.y + maxZ*plane.z <= plane.offset) return -1; 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); if (minX*plane.x + maxY*plane.y + minZ*plane.z > plane.offset) culling &= (63 & ~side);
} else { } else {
if (maxX*plane.x + minY*plane.y + minZ*plane.z <= plane.offset) return -1; 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); if (minX*plane.x + maxY*plane.y + maxZ*plane.z > plane.offset) culling &= (63 & ~side);
} else if (plane.y >= 0) if (plane.z >= 0) { }
else if (plane.y >= 0)
if (plane.z >= 0) {
if (minX*plane.x + maxY*plane.y + maxZ*plane.z <= plane.offset) return -1; 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); if (maxX*plane.x + minY*plane.y + minZ*plane.z > plane.offset) culling &= (63 & ~side);
} else { } else {
if (minX*plane.x + maxY*plane.y + minZ*plane.z <= plane.offset) return -1; 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); if (maxX*plane.x + minY*plane.y + maxZ*plane.z > plane.offset) culling &= (63 & ~side);
} else if (plane.z >= 0) { }
else if (plane.z >= 0) {
if (minX*plane.x + minY*plane.y + maxZ*plane.z <= plane.offset) return -1; 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); if (maxX*plane.x + maxY*plane.y + minZ*plane.z > plane.offset) culling &= (63 & ~side);
} else { } else {

View File

@@ -294,7 +294,7 @@ public class Camera3D extends Object3D {
} }
occludersLength = j; occludersLength = j;
occluders.length = j; occluders.length = j;
// Check light influence (?) // Check light influence
for (i = 0, j = 0; i < lightsLength; i++) { for (i = 0, j = 0; i < lightsLength; i++) {
light = lights[i]; light = lights[i];
light.localToCameraTransform.calculateInversion(light.cameraToLocalTransform); light.localToCameraTransform.calculateInversion(light.cameraToLocalTransform);
@@ -308,6 +308,7 @@ public class Camera3D extends Object3D {
// Shadows preparing // Shadows preparing
if (light.shadow != null) { if (light.shadow != null) {
// TODO: Need check by occluders
light.shadow.process(this); light.shadow.process(this);
} }
lights[j] = light; lights[j] = light;
@@ -1096,10 +1097,10 @@ public class Camera3D extends Object3D {
value = 1000 * fpsUpdatePeriod / (time - previousPeriodTime); value = 1000 * fpsUpdatePeriod / (time - previousPeriodTime);
if (value > stageFrameRate) value = stageFrameRate; if (value > stageFrameRate) value = stageFrameRate;
mod = value * 100 % 100; 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; value = 1000 / value;
mod = value * 100 % 100; 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; previousPeriodTime = time;
fpsUpdateCounter = 0; fpsUpdateCounter = 0;
} }
@@ -1116,14 +1117,14 @@ public class Camera3D extends Object3D {
if (methodTimeCount > 0) { if (methodTimeCount > 0) {
value = methodTimeSum / methodTimeCount; value = methodTimeSum / methodTimeCount;
mod = value * 100 % 100; 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 { } else {
timerTextField.text = ""; timerTextField.text = "";
} }
if (cpuTimeCount > 0) { if (cpuTimeCount > 0) {
value = cpuTimeSum / cpuTimeCount; value = cpuTimeSum / cpuTimeCount;
mod = value * 100 % 100; 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 { } else {
cpuTextField.text = ""; cpuTextField.text = "";
} }
@@ -1138,7 +1139,7 @@ public class Camera3D extends Object3D {
var memory:int = System.totalMemory; var memory:int = System.totalMemory;
value = memory / 1048576; value = memory / 1048576;
mod = value * 100 % 100; 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 // memory plot
if (memory > maxMemory) maxMemory = memory; if (memory > maxMemory) maxMemory = memory;

View File

@@ -121,8 +121,9 @@ package alternativa.engine3d.core {
* @private * @private
*/ */
public function set shadow(value:Shadow):void { public function set shadow(value:Shadow):void {
if (_shadow != null) _shadow._light = null;
_shadow = value; _shadow = value;
_shadow._light = this; if (value != null) value._light = this;
} }
} }
} }

View File

@@ -13,8 +13,6 @@ package alternativa.engine3d.lights {
import alternativa.engine3d.core.Light3D; import alternativa.engine3d.core.Light3D;
import alternativa.engine3d.core.Object3D; import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.core.Transform3D; import alternativa.engine3d.core.Transform3D;
import alternativa.engine3d.shadows.OmniLightShadow;
import alternativa.engine3d.shadows.Shadow;
use namespace alternativa3d; use namespace alternativa3d;
@@ -202,14 +200,5 @@ package alternativa.engine3d.lights {
return res; return res;
} }
/**
* @private
*/
override public function set shadow(value:Shadow):void {
_shadow = value;
_shadow._light = this;
var omniShadow:OmniLightShadow = value as OmniLightShadow;
if (omniShadow!=null) omniShadow.setBoundSize(this.attenuationEnd*1.5);
}
} }
} }

View File

@@ -467,13 +467,22 @@ package alternativa.engine3d.materials {
// i3 - ambient // i3 - ambient
// i2 - shadow-test // 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 t0.xyz, c1.xyz, t0.xxx"); // t = color*t
source.push("mul t1.xyz, t0.xyz, t1.w"); source.push("mul t1.xyz, t0.xyz, t1.w");
source.push("add o1.xyz, o1.xyz, t1.xyz"); source.push("add o1.xyz, o1.xyz, t1.xyz");
source.push("mul t0.xyz, t0.xyz, t0.www"); source.push("mul t0.xyz, t0.xyz, t0.www");
source.push("add o0.xyz, t0.xyz, i3.xyz"); 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 { } else {
// Считаем вектор из точки к свету // Считаем вектор из точки к свету
@@ -1075,6 +1084,7 @@ package alternativa.engine3d.materials {
var j:int; var j:int;
var lightLengthInGroup:int; var lightLengthInGroup:int;
var isFirstGroup:Boolean = true; var isFirstGroup:Boolean = true;
var j:int;
for (i = 0; i < groupsCount; i++) { for (i = 0; i < groupsCount; i++) {
var lightGroup:Vector.<Light3D> = groups[i]; var lightGroup:Vector.<Light3D> = groups[i];
lightLengthInGroup = lightGroup.length; lightLengthInGroup = lightGroup.length;

View File

@@ -24,7 +24,7 @@ package alternativa.engine3d.objects {
/** /**
* @private * @private
* A joint transform matrix. * A joint transform matrix. Geometry -> Joint -> Skin
*/ */
alternativa3d var jointTransform:Transform3D = new Transform3D(); alternativa3d var jointTransform:Transform3D = new Transform3D();

View File

@@ -74,6 +74,8 @@ package alternativa.engine3d.objects {
} }
} }
// TODO: Add removeSurface() method
/** /**
* Adds <code>Surface</code> to <code>Mesh</code> object. * Adds <code>Surface</code> to <code>Mesh</code> object.
* @param material Material of the surface. * @param material Material of the surface.

View File

@@ -56,13 +56,12 @@ package alternativa.engine3d.shadows {
private var renderer:Renderer = new Renderer(); 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. * Degree of correcting offset of shadow map space. It need for getting rid of self-shadowing artifacts.
*/ */
public var biasMultiplier:Number = 0.99; public var biasMultiplier:Number = 0.97;
private static const DIFFERENCE_MULTIPLIER:Number = 32768;
// TODO: implement property parent // TODO: implement property parent
@@ -256,6 +255,7 @@ package alternativa.engine3d.shadows {
override alternativa3d function process(camera:Camera3D):void { override alternativa3d function process(camera:Camera3D):void {
var i:int; var i:int;
var object:Object3D; var object:Object3D;
// TODO: realize culling
// Clipping of casters, that have shadows which are invisible. // Clipping of casters, that have shadows which are invisible.
var numActualCasters:int = 0; var numActualCasters:int = 0;
for (i = 0; i < _casters.length; i++) { for (i = 0; i < _casters.length; i++) {
@@ -351,6 +351,8 @@ package alternativa.engine3d.shadows {
shadowMap = camera.context3D.createTexture(_mapSize, _mapSize, Context3DTextureFormat.BGRA, true); shadowMap = camera.context3D.createTexture(_mapSize, _mapSize, Context3DTextureFormat.BGRA, true);
debugTexture._texture = shadowMap; debugTexture._texture = shadowMap;
} }
// TODO Don't clear if there was no casters
camera.context3D.setRenderToTexture(shadowMap, true); camera.context3D.setRenderToTexture(shadowMap, true);
camera.context3D.clear(1, 0, 0, 0.3); camera.context3D.clear(1, 0, 0, 0.3);
@@ -369,7 +371,6 @@ package alternativa.engine3d.shadows {
camera.context3D.setRenderToBackBuffer(); camera.context3D.setRenderToBackBuffer();
if (debug) { if (debug) {
if (numActualCasters > 0) {
if (debugPlane == null) { if (debugPlane == null) {
debugPlane = createDebugPlane(debugMaterial, camera.context3D); debugPlane = createDebugPlane(debugMaterial, camera.context3D);
} }
@@ -385,7 +386,6 @@ package alternativa.engine3d.shadows {
debugPlane.transform.compose((frustumMinX + frustumMaxX) / 2, (frustumMinY + frustumMaxY) / 2, frustumMaxZ, 0, 0, 0, (frustumMaxX - frustumMinX), (frustumMaxY - frustumMinY), 1); 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); debugPlane.localToCameraTransform.combine(_light.localToCameraTransform, debugPlane.transform);
debugSurface.material.collectDraws(camera, debugSurface, debugPlane.geometry, emptyLightVector, 0, false, -1); debugSurface.material.collectDraws(camera, debugSurface, debugPlane.geometry, emptyLightVector, 0, false, -1);
}
tempBounds.minX = frustumMinX; tempBounds.minX = frustumMinX;
tempBounds.maxX = frustumMaxX; tempBounds.maxX = frustumMaxX;
@@ -718,16 +718,15 @@ package alternativa.engine3d.shadows {
drawUnit.setVertexConstantsFromTransform(vertexLinker.getVariableIndex("cUVProjection"), objectToShadowMapTransform); drawUnit.setVertexConstantsFromTransform(vertexLinker.getVariableIndex("cUVProjection"), objectToShadowMapTransform);
// Устанавливаем шедоумапу // Устанавливаем шедоумапу
drawUnit.setTextureAt(fragmentLinker.getVariableIndex("sShadowMap"), shadowMap); 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) { if (_pcfOffset > 0) {
var offset1:Number = _pcfOffset/_mapSize; var offset1:Number = _pcfOffset/_mapSize;
var offset2:Number = offset1/3; var offset2:Number = offset1/3;
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cPCFOffsets"), -offset1, -offset2, offset2, offset1); 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 { private static function getVShader():Procedure {

View File

@@ -8,13 +8,14 @@
package alternativa.engine3d.shadows { package alternativa.engine3d.shadows {
import alternativa.engine3d.alternativa3d; import alternativa.engine3d.alternativa3d;
import alternativa.engine3d.core.BoundBox;
import alternativa.engine3d.core.Camera3D; import alternativa.engine3d.core.Camera3D;
import alternativa.engine3d.core.DrawUnit; import alternativa.engine3d.core.DrawUnit;
import alternativa.engine3d.core.Object3D; import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.core.Renderer; import alternativa.engine3d.core.Renderer;
import alternativa.engine3d.core.Transform3D; import alternativa.engine3d.core.Transform3D;
import alternativa.engine3d.core.VertexAttributes; import alternativa.engine3d.core.VertexAttributes;
import alternativa.engine3d.core.View; import alternativa.engine3d.lights.OmniLight;
import alternativa.engine3d.materials.Material; import alternativa.engine3d.materials.Material;
import alternativa.engine3d.materials.ShaderProgram; import alternativa.engine3d.materials.ShaderProgram;
import alternativa.engine3d.materials.TextureMaterial; import alternativa.engine3d.materials.TextureMaterial;
@@ -41,18 +42,31 @@ package alternativa.engine3d.shadows {
public class OmniLightShadow extends Shadow{ public class OmniLightShadow extends Shadow{
// TODO: calculate bias automaticaly
/** /**
* Степень корректирующего смещения пространства карты теней для избавления от артефактов самозатенения. * Degree of correcting offset of shadow map space. It need for getting rid of self-shadowing artifacts.
*/ */
public var biasMultiplier:Number = 0.99; public var biasMultiplier:Number = 0.97;
private static const DIFFERENCE_MULTIPLIER:Number = 32768;
private static const DEBUG_TYPE:String = "Sphere"; // Box
/**
* @private
*/
alternativa3d static var debugRadiusScale:Number = 0.5;
private var renderer:Renderer = new Renderer(); private var renderer:Renderer = new Renderer();
private var boundSize:Number = 1; // radius of the light source
private var radius:Number = 100;
// cube map size
private var _mapSize:Number; private var _mapSize:Number;
private var _pcfOffset:Number; private var _pcfOffset:Number;
private var cubeShadowMap:CubeTexture; private var cubeShadowMap:CubeTexture;
// Sides cameras
private var cameras:Vector.<Camera3D> = new Vector.<Camera3D>(); private var cameras:Vector.<Camera3D> = new Vector.<Camera3D>();
private var debugObject:Mesh; private var debugObject:Mesh;
@@ -60,17 +74,18 @@ package alternativa.engine3d.shadows {
private var _casters:Vector.<Object3D> = new Vector.<Object3D>(); private var _casters:Vector.<Object3D> = new Vector.<Object3D>();
private var cachedContext:Context3D;
private var programs:Dictionary = new Dictionary();
private var actualCasters:Vector.<Object3D> = new Vector.<Object3D>(); private var actualCasters:Vector.<Object3D> = new Vector.<Object3D>();
private var actualCastersCount:int; private var actualCastersCount:int;
private var edgeCameraToCasterTransform:Transform3D = new Transform3D(); // caster -> cube face
private var casterToEdgedCameraTransform:Transform3D = new Transform3D(); private var casterToEdgedCameraTransform:Transform3D = new Transform3D();
// object -> light
private var objectToLightTransform:Transform3D = new Transform3D(); private var objectToLightTransform:Transform3D = new Transform3D();
// casters count in edge
private var prevActualCastersMask:int;
private var prevActualCasterCountForEdge:Vector.<int> = new Vector.<int>(6); private var cachedContext:Context3D;
private var programs:Dictionary = new Dictionary();
/** /**
* Создает экземпляр OmniLightShadow. * Создает экземпляр OmniLightShadow.
@@ -78,25 +93,27 @@ package alternativa.engine3d.shadows {
* @param pcfOffset Смягчение границ тени. * @param pcfOffset Смягчение границ тени.
*/ */
public function OmniLightShadow(mapSize:int = 128, pcfOffset:Number = 0) { public function OmniLightShadow(mapSize:int = 128, pcfOffset:Number = 0) {
sections = new SectionPlane(0x11, 0x22, 0xC); // RU
sections.next = new SectionPlane(0x12, 0x21, 0xC); // LU
sections.next.next = new SectionPlane(0x14, 0x28, 0x3); // FU
sections.next.next.next = new SectionPlane(0x18, 0x24, 0x3); // BU
sections.next.next.next.next = new SectionPlane(0x5, 0xA, 0x30); // RF
sections.next.next.next.next.next = new SectionPlane(0x9, 0x6, 0x30); // RB
this.mapSize = mapSize; this.mapSize = mapSize;
this.pcfOffset = pcfOffset; this.pcfOffset = pcfOffset;
vertexShadowProcedure = getVShader(); vertexShadowProcedure = getVShader();
type = _pcfOffset > 0 ? "OS" : "os"; type = _pcfOffset > 0 ? "OS" : "os";
fragmentShadowProcedure = _pcfOffset > 0 ? getFShaderPCF() : getFShader(); fragmentShadowProcedure = _pcfOffset > 0 ? getFShaderPCF() : getFShader();
debugMaterial = new ShadowDebugMaterial(); debugMaterial = new ShadowDebugMaterial();
debugMaterial.alpha = 1.0; debugMaterial.alpha = 0.3;
for (var i:int = 0; i < 6; i++) { for (var i:int = 0; i < 6; i++) {
// создаем камеры var cam:Camera3D = new Camera3D(radius/1000, radius);
var cam:Camera3D = new Camera3D(1, boundSize);
cam.fov = 1.910633237; cam.fov = 1.910633237;
cam.view = new View(boundSize, boundSize);
cam.renderer = renderer;
cameras[i] = cam; cameras[i] = cam;
prevActualCasterCountForEdge[i] = 0;
} }
// Left // Left
@@ -126,125 +143,91 @@ package alternativa.engine3d.shadows {
cameras[4].composeTransforms(); cameras[4].composeTransforms();
} }
private function createDebugObject(material:Material, context:Context3D):Mesh{
/** var geometry:Geometry;
* @private var mesh:Mesh;
*/ if (DEBUG_TYPE == "Box") {
alternativa3d function setBoundSize(value:Number):void{ mesh = new Mesh();
this.boundSize = value; geometry = new Geometry(8);
for (var i:int = 0; i < 6; i++) {
var cam:Camera3D = cameras[i];
cam.view.width = cam.view.height = int (value);
cam.farClipping = value;
cam.calculateProjection(value,value);
}
}
private function createDebugCube(material:Material, context:Context3D):Mesh{
var mesh:Mesh = new Mesh();
// TODO: определиться куб или сфера
// var geometry:Geometry = new Geometry(8);
// mesh.geometry = geometry;
//
// var attributes:Array = new Array();
// attributes[0] = VertexAttributes.POSITION;
// attributes[1] = VertexAttributes.POSITION;
// attributes[2] = VertexAttributes.POSITION;
// geometry.addVertexStream(attributes);
//
// geometry.setAttributeValues(VertexAttributes.POSITION, Vector.<Number>([-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.<uint>([ 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.geometry = geometry;
mesh.addSurface(material, 0, geometry.numTriangles);
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.<Number>([
-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.<uint>([
0, 1, 2, 3, 0, 2, 2, 1, 0, 3, 2, 0,
2, 6, 1, 1, 6, 2, 1, 6, 5, 5, 6, 1,
6, 4, 5, 5, 4, 6, 6, 4, 7, 7, 4, 6,
0, 7, 4, 4, 7, 0, 0, 7, 3, 3, 7, 0,
3, 6, 2, 2, 6, 3, 3, 7, 6, 6, 7, 3,
0, 5, 1, 1, 5, 0, 0, 4, 5, 5, 4, 0]);
mesh.addSurface(material, 0, 24);
} else {
mesh = new GeoSphere(1, 4, true);
// Create two side
var triangles:Vector.<uint> = mesh.geometry.indices;
var numTriangles:int = triangles.length;
for (var i:int = 0; i < numTriangles; i += 3) {
var a:uint = triangles[i];
var b:uint = triangles[int(i + 1)];
var c:uint = triangles[int(i + 2)];
triangles.push(c, b, a);
}
mesh.geometry.indices = triangles;
mesh.getSurface(0).numTriangles = triangles.length/3;
mesh.setMaterialToAllSurfaces(material);
}
mesh.geometry.upload(context);
return mesh; return mesh;
} }
// Draw in shadow map
// Вычисление шедоумапы
override alternativa3d function process(camera:Camera3D):void { override alternativa3d function process(camera:Camera3D):void {
var i:int; var i:int;
var j:int; var j:int;
var caster:Object3D; var caster:Object3D;
var context:Context3D = camera.context3D; var context:Context3D = camera.context3D;
var castersCount:int = _casters.length;
// Отсечение кастеров, тени которых не видны
// Обработка смены контекста // Checking changed context
if (context != cachedContext) { if (context != cachedContext) {
programs = new Dictionary(); programs = new Dictionary();
cubeShadowMap = null; cubeShadowMap = null;
cachedContext = context; cachedContext = context;
for (i = 0; i < cameras.length; i++) {
cameras[i].context3D = cachedContext;
}
} }
// Culling invisible casters
if (cubeShadowMap == null) { if (cubeShadowMap == null) {
cubeShadowMap = context.createCubeTexture(_mapSize, Context3DTextureFormat.BGRA, true); cubeShadowMap = context.createCubeTexture(_mapSize, Context3DTextureFormat.BGRA, true);
debugMaterial.cubeMap = cubeShadowMap; debugMaterial.cubeMap = cubeShadowMap;
prevActualCastersMask = 63;
}
// Calculate parameters
radius = OmniLight(_light).attenuationEnd;
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++) {
context.setRenderToTexture(cubeShadowMap, true, 0, i); var cam:Camera3D = cameras[i];
context.clear(1, 0, 0, 0.3); cam.nearClipping = radius/1000;
} cam.farClipping = radius;
cam.calculateProjection(1, 1);
} }
// предрасчитаем некоторые матрицы трансформации var castersCount:int = _casters.length;
for (j = 0; j < castersCount; j++) {
caster = _casters[j];
if (caster.transformChanged) caster.composeTransforms();
caster.lightToLocalTransform.combine(caster.cameraToLocalTransform, _light.localToCameraTransform);
caster.localToLightTransform.combine(_light.cameraToLocalTransform, caster.localToCameraTransform);
var skin:Skin = caster as Skin;
if (skin != null) {
// Расчет матриц джоинтов
for (var child:Object3D = skin.childrenList; child != null; child = child.next) {
if (child.transformChanged) child.composeTransforms();
// Записываем в localToGlobalTransform матрицу перевода в скин
child.localToGlobalTransform.copy(child.transform);
if (child is Joint) {
Joint(child).calculateTransform();
}
skin.calculateJointsTransforms(child);
}
}
else{
if (caster.childrenList)
calculateChildrenTransforms(caster);
}
}
// Пробегаемся по 6-и камерам
for (i = 0; i < 6; i++) {
// камера соответствующая грани куба
var edgeCamera:Camera3D = cameras[i];
// проверяем, есть ли видимые кастеры попадающие на грань куба
actualCastersCount = 0; actualCastersCount = 0;
for (j = 0; j < castersCount; j++) {
caster = _casters[j]; for (i = 0; i < castersCount; i++) {
caster = _casters[i];
var visible:Boolean = caster.visible; var visible:Boolean = caster.visible;
var parent:Object3D = caster._parent; var parent:Object3D = caster._parent;
@@ -252,51 +235,104 @@ package alternativa.engine3d.shadows {
visible = parent.visible; visible = parent.visible;
parent = parent._parent; parent = parent._parent;
} }
if (visible) { if (visible) {
// Проверка куллинга // calculate transform matrices
// формируем actualCasters _light.lightToObjectTransform.combine(caster.cameraToLocalTransform, _light.localToCameraTransform);
calculateVisibility(caster, edgeCamera); caster.localToLightTransform.combine(_light.cameraToLocalTransform, caster.localToCameraTransform);
// collect actualCasters for light
if (caster.boundBox == null || OmniLight(_light).checkBound(caster)){
actualCasters[actualCastersCount] = caster;
actualCastersCount++;
// Pack camera culling
caster.culling <<= 16;
if (caster.boundBox != null) {
// 1 - calculate planes in object space
calculatePlanes(caster.localToLightTransform);
// 2 - check object location cameras (sections)
caster.culling |= recognizeObjectCameras(caster.boundBox);
} }
} }
if (actualCastersCount>0){ // update Skin Joints matrices
var skin:Skin = caster as Skin;
if (skin != null) {
// Calculate joints matrices
for (var child:Object3D = skin.childrenList; child != null; child = child.next) {
if (child.transformChanged) child.composeTransforms();
// Write transformToSkin matrix to localToGlobalTransform property
child.localToGlobalTransform.copy(child.transform);
if (child is Joint) {
Joint(child).calculateTransform();
}
skin.calculateJointsTransforms(child);
}
}
if (caster.childrenList != null) collectActualChildren(caster);
}
}
// Iterate through six cameras
for (i = 0; i < 6; i++) {
// Cube side camera
var edgeCamera:Camera3D = cameras[i];
var edgeBit:int = (1<<i);
if (actualCastersCount > 0) {
// Настройка параметров рендеринга: // Настройка параметров рендеринга:
renderer.camera = edgeCamera; renderer.camera = camera;
context.setRenderToTexture(cubeShadowMap, true, 0, i); context.setRenderToTexture(cubeShadowMap, true, 0, i);
context.clear(1, 0, 0, 0.0); context.clear(1, 0, 0, 0.0);
// Пробегаемся по кастерам // Пробегаемся по кастерам
for (j = 0; j <actualCastersCount; j++) { for (j = 0; j < actualCastersCount; j++) {
caster = actualCasters[j]; caster = actualCasters[j];
// Проверить находится ли кастер в зоне 4-х плоскостей
if ((caster.culling & edgeBit)) {
// собираем матрицу перевода из кастера в пространство edgeCamera // собираем матрицу перевода из кастера в пространство edgeCamera
casterToEdgedCameraTransform.combine(edgeCamera.inverseTransform, caster.localToLightTransform); casterToEdgedCameraTransform.combine(edgeCamera.inverseTransform, caster.localToLightTransform);
// Собираем драуколлы для кастера и его дочерних объектов // Собираем драуколлы для кастера и его дочерних объектов
collectDraws(context, caster, edgeCamera); collectDraws(context, caster, edgeCamera);
} }
}
// Отрисовка дроуколов // if (renderer.drawUnits.length == 0) context.clear(0, 0, 0, 0.0);
// Drawing
renderer.render(context); renderer.render(context);
prevActualCastersMask |= edgeBit;
} }
else{ else{
// Если относительно одной из камер ничего не менялось, не вызываем отрисовочный вызов // Если относительно одной из камер ничего не менялось, не вызываем отрисовочный вызов
if (prevActualCasterCountForEdge[i]!=0){
if ((prevActualCastersMask & edgeBit)){
context.setRenderToTexture(cubeShadowMap, false, 0, i); context.setRenderToTexture(cubeShadowMap, false, 0, i);
context.clear(1, 0, 0, 0); context.clear(1, 0, 0, 0);
prevActualCastersMask &= ~edgeBit;
} }
} }
prevActualCasterCountForEdge[i] = actualCastersCount;
} }
context.setRenderToBackBuffer(); context.setRenderToBackBuffer();
// Unpack camera culling value
for (j = 0; j < actualCastersCount; j++) {
caster = actualCasters[j];
// If there was -1, after shift it will be -1 too
caster.culling >>= 16;
}
if (debug) { if (debug) {
if (actualCastersCount > 0) { // Create debug object if needed
// Создаем дебаговый объект, если он не создан
if (debugObject == null) { if (debugObject == null) {
debugObject = createDebugCube(debugMaterial, camera.context3D); debugObject = createDebugObject(debugMaterial, camera.context3D);
debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = boundSize/12;
debugObject.composeTransforms();
} }
debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = debugRadiusScale;
debugObject.composeTransforms();
// Формируем матрицу трансформации для debugObject // Формируем матрицу трансформации для debugObject
debugObject.localToCameraTransform.combine(_light.localToCameraTransform, debugObject.transform); debugObject.localToCameraTransform.combine(_light.localToCameraTransform, debugObject.transform);
@@ -305,28 +341,38 @@ package alternativa.engine3d.shadows {
var debugSurface:Surface = debugObject._surfaces[0]; var debugSurface:Surface = debugObject._surfaces[0];
debugMaterial.collectDraws(camera, debugSurface, debugObject.geometry, null, 0, false, -1); debugMaterial.collectDraws(camera, debugSurface, debugObject.geometry, null, 0, false, -1);
} }
actualCasters.length = 0;
}
private function collectActualChildren(root:Object3D):void{
for (var child:Object3D = root.childrenList; child != null; child = child.next) {
if (child.visible){
// calculate transform matrices
_light.lightToObjectTransform.combine(child.cameraToLocalTransform, _light.localToCameraTransform);
child.localToLightTransform.combine(_light.cameraToLocalTransform, child.localToCameraTransform);
// collect actualCasters for light
if (child.boundBox == null || OmniLight(_light).checkBound(child)){
actualCasters[actualCastersCount] = child;
actualCastersCount++;
// Pack camera culling
child.culling <<= 16;
if (child.boundBox != null) {
// 1 - calculate planes in object space
calculatePlanes(child.localToLightTransform);
// 2 - check object location cameras (sections)
child.culling |= recognizeObjectCameras(child.boundBox);
} }
} }
// предрасчитывает матрицы для всех детей // update Skin Joints matrices
// localToLightTransform, lightToLocalTransform, transform, и calculateTransform для Joint
private function calculateChildrenTransforms(root:Object3D):void{
var childrenList:Object3D = root.childrenList;
for (var child:Object3D = childrenList; child != null; child = child.next) {
// расчет матриц трансформаций для объектов
if (child.transformChanged) child.composeTransforms();
child.localToLightTransform.combine(root.localToLightTransform, child.transform);
child.lightToLocalTransform.combine(child.inverseTransform, root.lightToLocalTransform);
// расчет матриц трансформаций для скинов
var skin:Skin = child as Skin; var skin:Skin = child as Skin;
if (skin != null) { if (skin != null) {
// Расчет матриц джоинтов // Calculate joints matrices
for (var skinChild:Object3D = skin.childrenList; skinChild != null; skinChild = skinChild.next) { for (var skinChild:Object3D = skin.childrenList; skinChild != null; skinChild = skinChild.next) {
if (skinChild.transformChanged) skinChild.composeTransforms(); if (skinChild.transformChanged) skinChild.composeTransforms();
// Записываем в localToGlobalTransform матрицу перевода в скин // Write transformToSkin matrix to localToGlobalTransform property
skinChild.localToGlobalTransform.copy(skinChild.transform); skinChild.localToGlobalTransform.copy(skinChild.transform);
if (skinChild is Joint) { if (skinChild is Joint) {
Joint(skinChild).calculateTransform(); Joint(skinChild).calculateTransform();
@@ -334,56 +380,169 @@ package alternativa.engine3d.shadows {
skin.calculateJointsTransforms(skinChild); skin.calculateJointsTransforms(skinChild);
} }
} }
else{
if (child.childrenList) if (child.childrenList != null) collectActualChildren(child);
calculateChildrenTransforms(child);
} }
} }
} }
// собирает список actualCasters для одной из 6-и камер private var sections:SectionPlane;
private function calculateVisibility(root:Object3D, camera:Camera3D):void{
var casterCulling:int;
if (root.visible) { private function calculatePlanes(transform:Transform3D):void {
var skin:Skin = root as Skin; // DUBFLR
var planeRU:SectionPlane = sections;
var planeLU:SectionPlane = sections.next;
var planeFU:SectionPlane = sections.next.next;
var planeBU:SectionPlane = sections.next.next.next;
var planeRF:SectionPlane = sections.next.next.next.next;
var planeRB:SectionPlane = sections.next.next.next.next.next;
// Вычисляем результат кулинга для объекта // 1, 0, 1
if (root.boundBox != null) { planeRU.x = transform.a + transform.i;
edgeCameraToCasterTransform.combine(root.lightToLocalTransform, camera.transform); planeRU.y = transform.b + transform.j;
camera.calculateFrustum(edgeCameraToCasterTransform); planeRU.z = transform.c + transform.k;
casterCulling = root.boundBox.checkFrustumCulling(camera.frustum, 63); planeRU.offset = -(transform.d + transform.l);
// -1, 0, 1
planeLU.x = transform.i - transform.a;
planeLU.y = transform.j - transform.b;
planeLU.z = transform.k - transform.c;
planeLU.offset = transform.d - transform.l;
// 0, 1, 1
planeFU.x = transform.e + transform.i;
planeFU.y = transform.f + transform.j;
planeFU.z = transform.g + transform.k;
planeFU.offset = -(transform.h + transform.l);
// 0, -1, 1
planeBU.x = transform.i - transform.e;
planeBU.y = transform.j - transform.f;
planeBU.z = transform.k - transform.g;
planeBU.offset = transform.h - transform.l;
// 1, 1, 0
planeRF.x = transform.a + transform.e;
planeRF.y = transform.b + transform.f;
planeRF.z = transform.c + transform.g;
planeRF.offset = -(transform.d + transform.h);
// 1, -1, 0
planeRB.x = transform.a - transform.e;
planeRB.y = transform.b - transform.f;
planeRB.z = transform.c - transform.g;
planeRB.offset = transform.h - transform.d;
// var ax:Number = transform.c - transform.a + transform.b; // E
// var ay:Number = transform.g - transform.e + transform.f;
// var az:Number = transform.k - transform.i + transform.j;
// var bx:Number = transform.c - transform.a - transform.b; // H
// var by:Number = transform.g - transform.e - transform.f;
// var bz:Number = transform.k - transform.i - transform.j;
// planeRU.x = bz * ay - by * az;
// planeRU.y = bx * az - bz * ax;
// planeRU.z = by * ax - bx * ay;
// planeRU.offset = transform.d*planeRU.x + transform.h*planeRU.y + transform.l*planeRU.z;
//
// ax = transform.c + transform.a - transform.b; // D
// ay = transform.g + transform.e - transform.f;
// az = transform.k + transform.i - transform.j;
// bx = transform.c + transform.a + transform.b; // A
// by = transform.g + transform.e + transform.f;
// bz = transform.k + transform.i + transform.j;
// planeLU.x = bz * ay - by * az;
// planeLU.y = bx * az - bz * ax;
// planeLU.z = by * ax - bx * ay;
// planeLU.offset = transform.d*planeLU.x + transform.h*planeLU.y + transform.l*planeLU.z;
//
// ax = transform.c - transform.a - transform.b; // H
// ay = transform.g - transform.e - transform.f;
// az = transform.k - transform.i - transform.j;
// bx = transform.c + transform.a - transform.b; // D
// by = transform.g + transform.e - transform.f;
// bz = transform.k + transform.i - transform.j;
// planeFU.x = bz * ay - by * az;
// planeFU.y = bx * az - bz * ax;
// planeFU.z = by * ax - bx * ay;
// planeFU.offset = transform.d*planeFU.x + transform.h*planeFU.y + transform.l*planeFU.z;
//
// ax = transform.c + transform.a + transform.b; // A
// ay = transform.g + transform.e + transform.f;
// az = transform.k + transform.i + transform.j;
// bx = transform.c - transform.a + transform.b; // E
// by = transform.g - transform.e + transform.f;
// bz = transform.k - transform.i + transform.j;
// planeBU.x = bz * ay - by * az;
// planeBU.y = bx * az - bz * ax;
// planeBU.z = by * ax - bx * ay;
// planeBU.offset = transform.d*planeBU.x + transform.h*planeBU.y + transform.l*planeBU.z;
//
// ax = transform.a - transform.b + transform.c; // D
// ay = transform.e - transform.f + transform.g;
// az = transform.i - transform.j + transform.k;
// bx = transform.a - transform.b - transform.c; // C
// by = transform.e - transform.f - transform.g;
// bz = transform.i - transform.j - transform.k;
// planeRF.x = bz * ay - by * az;
// planeRF.y = bx * az - bz * ax;
// planeRF.z = by * ax - bx * ay;
// planeRF.offset = transform.d*planeRF.x + transform.h*planeRF.y + transform.l*planeRF.z;
//
// ax = transform.a + transform.b - transform.c; // B
// ay = transform.e + transform.f - transform.g;
// az = transform.i + transform.j - transform.k;
// bx = transform.a + transform.b + transform.c; // A
// by = transform.e + transform.f + transform.g;
// bz = transform.i + transform.j + transform.k;
// planeRB.x = bz * ay - by * az;
// planeRB.y = bx * az - bz * ax;
// planeRB.z = by * ax - bx * ay;
// planeRB.offset = transform.d*planeRB.x + transform.h*planeRB.y + transform.l*planeRB.z;
}
private function recognizeObjectCameras(bb:BoundBox):int {
var culling:int = 63;
for (var plane:SectionPlane = sections; plane != null; plane = plane.next) {
var result:int = 0;
if (plane.x >= 0)
if (plane.y >= 0)
if (plane.z >= 0) {
if (bb.maxX*plane.x + bb.maxY*plane.y + bb.maxZ*plane.z >= plane.offset) result = plane.frontCameras;
if (bb.minX*plane.x + bb.minY*plane.y + bb.minZ*plane.z < plane.offset) result |= plane.backCameras;
} else { } else {
casterCulling = 63; if (bb.maxX*plane.x + bb.maxY*plane.y + bb.minZ*plane.z >= plane.offset) result = plane.frontCameras;
if (bb.minX*plane.x + bb.minY*plane.y + bb.maxZ*plane.z < plane.offset) result |= plane.backCameras;
} }
else
// Если Кулинг кастера дает положительный результат, тогда if (plane.z >= 0) {
if (casterCulling){ if (bb.maxX*plane.x + bb.minY*plane.y + bb.maxZ*plane.z >= plane.offset) result = plane.frontCameras;
if (skin){ if (bb.minX*plane.x + bb.maxY*plane.y + bb.minZ*plane.z < plane.offset) result |= plane.backCameras;
actualCasters[actualCastersCount++] = root; } 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{ else if (plane.y >= 0)
var childrenList:Object3D = root.childrenList; if (plane.z >= 0) {
// Если есть дочерние объекты, if (bb.minX*plane.x + bb.maxY*plane.y + bb.maxZ*plane.z >= plane.offset) result = plane.frontCameras;
if(childrenList!=null){ if (bb.maxX*plane.x + bb.minY*plane.y + bb.minZ*plane.z < plane.offset) result |= plane.backCameras;
// Проверяем их на кулинг } else {
for (var child:Object3D = childrenList; child != null; child = child.next) { if (bb.minX*plane.x + bb.maxY*plane.y + bb.minZ*plane.z >= plane.offset) result = plane.frontCameras;
calculateVisibility(child, camera); if (bb.maxX*plane.x + bb.minY*plane.y + bb.maxZ*plane.z < plane.offset) result |= plane.backCameras;
} }
else if (plane.z >= 0) {
if (bb.minX*plane.x + bb.minY*plane.y + bb.maxZ*plane.z >= plane.offset) result = plane.frontCameras;
if (bb.maxX*plane.x + bb.maxY*plane.y + bb.minZ*plane.z < plane.offset) result |= plane.backCameras;
} else {
if (bb.minX*plane.x + bb.minY*plane.y + bb.minZ*plane.z >= plane.offset) result = plane.frontCameras;
if (bb.maxX*plane.x + bb.maxY*plane.y + bb.maxZ*plane.z < plane.offset) result |= plane.backCameras;
} }
// Если дочерних объектов нет culling &= result | plane.unusedBits;
else{
// добавляем кастер в список актуальных кастеров
actualCasters[actualCastersCount++] = root;
} }
return culling;
} }
}
}
}
private function collectDraws(context:Context3D, caster:Object3D, edgeCamera:Camera3D):void{ private function collectDraws(context:Context3D, caster:Object3D, edgeCamera:Camera3D):void{
// если объект является мешем, собираем для него дроуколы // если объект является мешем, собираем для него дроуколы
var mesh:Mesh = caster as Mesh; var mesh:Mesh = caster as Mesh;
if (mesh != null && mesh.geometry != null) { if (mesh != null && mesh.geometry != null) {
@@ -458,19 +617,12 @@ package alternativa.engine3d.shadows {
drawUnit.setProjectionConstants(edgeCamera, program.vertexShader.getVariableIndex("cProjMatrix"), casterToEdgedCameraTransform); drawUnit.setProjectionConstants(edgeCamera, program.vertexShader.getVariableIndex("cProjMatrix"), casterToEdgedCameraTransform);
drawUnit.setVertexConstantsFromTransform(program.vertexShader.getVariableIndex("cCasterToOmni"), caster.localToLightTransform); drawUnit.setVertexConstantsFromTransform(program.vertexShader.getVariableIndex("cCasterToOmni"), caster.localToLightTransform);
drawUnit.setVertexConstantsFromNumbers(program.vertexShader.getVariableIndex("cScale"), 255/boundSize, 0, 0, 1); drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cConstants"), 1 / 255, 0, 255/radius, 1);
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("cConstants"), 1 / 255, 0, 0, 1);
renderer.addDrawUnit(drawUnit, Renderer.OPAQUE); renderer.addDrawUnit(drawUnit, Renderer.OPAQUE);
} }
} }
var child:Object3D;
for (child = caster.childrenList; child != null; child = child.next) {
if (!(child as Joint) && child.visible) collectDraws(context, child, edgeCamera);
} }
}
/** /**
* @private * @private
@@ -525,15 +677,10 @@ package alternativa.engine3d.shadows {
} }
var proc:Procedure = Procedure.compileFromArray([ var proc:Procedure = Procedure.compileFromArray([
"#c1=cScale",
"#v0=vDistance", "#v0=vDistance",
"m34 t0.xyz, i0, c2", "m34 t0.xyz, i0, c2",
"dp3 t0.x, t0.xyz, t0.xyz", "mov v0, t0.xyzx",
"sqt t0.x, t0.x", // x: [0, boundSize]
"mul t0.x, t0.x, c1.x", // x: [0, 255]
"mov t0.w, c1.w",
"mov v0, t0",
"m44 o0, i0, c0" "m44 o0, i0, c0"
]); ]);
@@ -550,13 +697,18 @@ package alternativa.engine3d.shadows {
} }
} }
fLinker.addProcedure(Procedure.compileFromArray([ fLinker.addProcedure(Procedure.compileFromArray([
"#v0=vDistance", // x: [0, 255] "#v0=vDistance", // xyz
"#c0=cConstants", // 1/255, 0, 0, 1 "#c0=cConstants", // 1/255, 0, 255/radius, 1
"frc t0.y, v0.x", // calculate distance
"sub t0.x, v0.x, t0.y", "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", "mul t0.x, t0.x, c0.x",
"mov t0.zw, c0.zw",
"mov t0.w, c0.w",
"mov o0, t0" "mov o0, t0"
])); ]));
program = new ShaderProgram(vLinker, fLinker); program = new ShaderProgram(vLinker, fLinker);
@@ -570,7 +722,7 @@ package alternativa.engine3d.shadows {
//------------- ShadowMap Shader ---------- //------------- ShadowMap Shader in material----------
/** /**
* @private * @private
@@ -584,16 +736,13 @@ package alternativa.engine3d.shadows {
drawUnit.setTextureAt(fragmentLinker.getVariableIndex("sCubeMap"), cubeShadowMap); drawUnit.setTextureAt(fragmentLinker.getVariableIndex("sCubeMap"), cubeShadowMap);
// Устанавливаем коеффициенты // Устанавливаем коеффициенты
// TODO: сделать множитель более корректный. Возможно 65536 (разрешающая способность глубины буфера).
if (_pcfOffset > 0) { if (_pcfOffset > 0) {
var offset:Number = Math.tan(_pcfOffset/180*Math.PI)/3;
var offset:Number = _pcfOffset*0.0175; //1 градус
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cPCFOffsets"), -3/2, 1/16, 0, 0); drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cPCFOffsets"), -3/2, 1/16, 0, 0);
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -1, 1, 0, offset/boundSize); drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -1, 1, 0, offset);
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cDecode"), -10000, -10000/255, biasMultiplier*10000/boundSize, 10); drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cDecode"), -DIFFERENCE_MULTIPLIER, -DIFFERENCE_MULTIPLIER/255, biasMultiplier*DIFFERENCE_MULTIPLIER/radius, 10);
} } else {
else{ drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -DIFFERENCE_MULTIPLIER, -DIFFERENCE_MULTIPLIER/255, biasMultiplier*DIFFERENCE_MULTIPLIER/radius, 1.0);
drawUnit.setFragmentConstantsFromNumbers(fragmentLinker.getVariableIndex("cConstants"), -10000, -10000/255, biasMultiplier*10000/boundSize, 1);
} }
} }
@@ -602,11 +751,8 @@ package alternativa.engine3d.shadows {
"#v0=vSample", "#v0=vSample",
"m34 t0.xyz, i0, c0", "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"); ], "OmniShadowMapVertex");
shader.assignVariableName(VariableType.CONSTANT, 0, "cObjectToLightTransform", 3); shader.assignVariableName(VariableType.CONSTANT, 0, "cObjectToLightTransform", 3);
return shader; return shader;
@@ -620,14 +766,20 @@ package alternativa.engine3d.shadows {
]; ];
var line:int = 3; var line:int = 3;
// Расстояние // Расстояние
shaderArr[line++] = "mov t0.z, v0.w"; // w: [0, boundSize] shaderArr[line++] = "dp3 t0.z, v0.xyz, v0.xyz";
shaderArr[line++] = "tex t0.xy, v0, s0 <cube, linear>"; shaderArr[line++] = "sqt t0.z, t0.z"; // w: [0, radius]
shaderArr[line++] = "tex t0.xy, v0, s0 <cube, nearest>";
shaderArr[line++] = "dp3 t0.x, t0.xyz, c0.xyz"; // декодируем, находим разницу между расстояниями и умножаем ее на большое число 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++] = "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"); return Procedure.compileFromArray(shaderArr, "OmniShadowMapFragment");
} }
@@ -645,49 +797,51 @@ package alternativa.engine3d.shadows {
// допустимо использование временных переменных t0 t1 t2 t3 // допустимо использование временных переменных t0 t1 t2 t3
// v0 - sample // v0 - sample
// v0.w - length(sample) [0, boundSize]
// ищем 2-а перпендикулярных вектора // calculate 2 ortogonal vectors
// (-y, x, 0) // (-y, x, 0)
shaderArr[line++] = "mov t1.xyzw, v0.yxzw"; shaderArr[line++] = "mov t1.xyzw, v0.yxzw";
shaderArr[line++] = "mul t1.xyzw, t1.xyzw, c1.xyzz"; shaderArr[line++] = "mul t1.xyzw, t1.xyzw, c1.xyzz";
shaderArr[line++] = "crs t0.xyz, v0.xyz, t1.xyz"; shaderArr[line++] = "crs t0.xyz, v0.xyz, t1.xyz";
// нормируем их // normalize vectors
shaderArr[line++] = "nrm t0.xyz, t0.xyz"; shaderArr[line++] = "nrm t0.xyz, t0.xyz";
shaderArr[line++] = "nrm t1.xyz, t1.xyz"; shaderArr[line++] = "nrm t1.xyz, t1.xyz";
// задаем оффсеты shaderArr[line++] = "dp3 t3.z, v0.xyz, v0.xyz";
shaderArr[line++] = "mul t0.w, c1.w, v0.w"; // с1.w = offset/boundSize 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 t0.xyz, t0.xyz, t0.w";
shaderArr[line++] = "mul t1.xyz, t1.xyz, t0.w"; shaderArr[line++] = "mul t1.xyz, t1.xyz, t0.w";
// --------- {13 opcode} // --------- {13 opcode}
// t0, t1 - перпендикуляры ↑→ // t0, t1 - ortogonals ↑→
// t2 - текущий вектор // t2 - current vector
// в v0.w, t3.z расстояние до объекта // t3.z distance to object
// t3.xy - результат из текстуры // t3.xy - result from shadow map
// t3.w - сумма sat-ов // t3.w - summ of sat
// первая точка // first point
shaderArr[line++] = "add t2.xyz, t0.xyz, t1.xyz"; shaderArr[line++] = "add t2.xyz, t0.xyz, t1.xyz";
shaderArr[line++] = "mul t2.xyz, t2.xyz, c2.xxx"; shaderArr[line++] = "mul t2.xyz, t2.xyz, c2.xxx";
shaderArr[line++] = "add t2.xyz, t2.xyz, v0.xyz"; shaderArr[line++] = "add t2.xyz, t2.xyz, v0.xyz";
// получаем длинну из шадоумапы [0, 1] // получаем длинну из шадоумапы [0, 1]
shaderArr[line++] = "mov t3.z, v0.w"; // shaderArr[line++] = "mov t3.z, t0.w";
shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, linear>"; shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, nearest>";
shaderArr[line++] = "dp3 o0." +componentByIndex[0] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число shaderArr[line++] = "dp3 o0." +componentByIndex[0] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
//----- //-----
for (j = 1; j<4; j++){ for (j = 1; j < 4; j++) {
shaderArr[line++] = "add t2.xyz, t2.xyz, t1.xyz"; shaderArr[line++] = "add t2.xyz, t2.xyz, t1.xyz";
shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, linear>"; shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, nearest>";
shaderArr[line++] = "dp3 o0." +componentByIndex[j] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число shaderArr[line++] = "dp3 o0." +componentByIndex[j] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
} }
@@ -696,16 +850,16 @@ package alternativa.engine3d.shadows {
//----- //-----
for (i = 0; i<3; i++){ for (i = 0; i < 3; i++) {
shaderArr[line++] = "add t2.xyz, t2.xyz, t0.xyz"; shaderArr[line++] = "add t2.xyz, t2.xyz, t0.xyz";
shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, linear>"; shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, nearest>";
shaderArr[line++] = "dp3 o0." +componentByIndex[0] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число shaderArr[line++] = "dp3 o0." +componentByIndex[0] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
for (j = 1; j<4; j++){ for (j = 1; j < 4; j++){
shaderArr[line++] = (i%2 == 1)?("add t2.xyz, t2.xyz, t1.xyz"):("sub t2.xyz, t2.xyz, t1.xyz"); shaderArr[line++] = (i%2 == 1)?("add t2.xyz, t2.xyz, t1.xyz"):("sub t2.xyz, t2.xyz, t1.xyz");
shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, linear>"; shaderArr[line++] = "tex t3.xy, t2.xyz, s0 <cube, nearest>";
shaderArr[line++] = "dp3 o0." +componentByIndex[j] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число shaderArr[line++] = "dp3 o0." +componentByIndex[j] + ", t3.xyz, c0.xyz"; // декодируем, вычитаем, умножаем на большое число
} }
shaderArr[line++] = "sat o0, o0"; shaderArr[line++] = "sat o0, o0";
@@ -715,13 +869,12 @@ package alternativa.engine3d.shadows {
shaderArr[line++] = "sub o0, c1.y, t3.w"; shaderArr[line++] = "sub o0, c1.y, t3.w";
//--------- {73 opcode} //--------- {73 opcodes}
return Procedure.compileFromArray(shaderArr, "OmniShadowMapFragment"); return Procedure.compileFromArray(shaderArr, "OmniShadowMapFragment");
} }
private static const componentByIndex:Array = ["x", "y", "z", "w"]; private static const componentByIndex:Array = ["x", "y", "z", "w"];
/** /**
* Добавляет <code>object</code> в список объектов, отбрасывающих тень. * Добавляет <code>object</code> в список объектов, отбрасывающих тень.
* @param object Добавляемый объект. * @param object Добавляемый объект.
@@ -732,6 +885,12 @@ package alternativa.engine3d.shadows {
} }
} }
public function removeCaster(object:Object3D):void {
var index:int = _casters.indexOf(object);
if (index < 0) throw new Error("Caster not found");
_casters[index] = _casters.pop();
}
/** /**
* Очищает список объектов, отбрасывающих тень. * Очищает список объектов, отбрасывающих тень.
*/ */
@@ -754,8 +913,8 @@ package alternativa.engine3d.shadows {
this._mapSize = value; this._mapSize = value;
if (value < 2) { if (value < 2) {
throw new ArgumentError("Map size cannot be less than 2."); throw new ArgumentError("Map size cannot be less than 2.");
} else if (value > 2048) { } else if (value > 1024) {
throw new ArgumentError("Map size exceeds maximum value 2048."); throw new ArgumentError("Map size exceeds maximum value 1024.");
} }
if ((Math.log(value)/Math.LN2 % 1) != 0) { if ((Math.log(value)/Math.LN2 % 1) != 0) {
throw new ArgumentError("Map size must be power of two."); throw new ArgumentError("Map size must be power of two.");
@@ -769,6 +928,7 @@ package alternativa.engine3d.shadows {
/** /**
* Смещение Percentage Closer Filtering. Этот способ фильтрации используется для смягчения границ тени. * Смещение Percentage Closer Filtering. Этот способ фильтрации используется для смягчения границ тени.
* 1 pcfOffset equivalent 1 degree for all blur
*/ */
public function get pcfOffset():Number { public function get pcfOffset():Number {
return _pcfOffset; return _pcfOffset;
@@ -868,6 +1028,10 @@ class ShadowDebugMaterial extends Material {
} }
} }
private function copyDrawUnit(source:DrawUnit, dest:DrawUnit):void {
}
private function setupProgram(object:Object3D):ShaderProgram { private function setupProgram(object:Object3D):ShaderProgram {
var vertexLinker:Linker = new Linker(Context3DProgramType.VERTEX); var vertexLinker:Linker = new Linker(Context3DProgramType.VERTEX);
var positionVar:String = "aPosition"; var positionVar:String = "aPosition";
@@ -899,3 +1063,23 @@ class ShadowDebugMaterial extends Material {
} }
class SectionPlane {
public var x:Number = 0;
public var y:Number = 0;
public var z:Number = 0;
public var offset:Number = 0;
public var next:SectionPlane;
public var frontCameras:int;
public var backCameras:int;
public var unusedBits:int = 63;
public function SectionPlane(frontCameras:int, backCameras:int, unused:int) {
this.frontCameras = frontCameras;
this.backCameras = backCameras;
this.unusedBits = unused;
}
}