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.
*/
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;
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 (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) {
}
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) {
}
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) {
}
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 {

View File

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

View File

@@ -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;
}
}
}

View File

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

View File

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

View File

@@ -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();

View File

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

View File

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

View File

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