Good culling of objects for CubeMap

This commit is contained in:
Yaski
2012-05-03 20:55:13 +06:00
parent 38b6af446b
commit 441d463d93
4 changed files with 101 additions and 168 deletions

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,12 +200,5 @@ package alternativa.engine3d.lights {
return res; return res;
} }
/**
* @private
*/
override public function set shadow(value:Shadow):void {
_shadow = value;
if (_shadow!=null) _shadow._light = this;
}
} }
} }

View File

@@ -58,7 +58,7 @@ public class ParserA3D extends Parser {
* @param input <code>ByteArray</code> consists of A3D data. * @param input <code>ByteArray</code> consists of A3D data.
*/ */
public function parse(input:ByteArray):void { public function parse(input:ByteArray):void {
// try { try {
input.position = 0; input.position = 0;
var version:int = input.readByte(); var version:int = input.readByte();
if (version == 0) { if (version == 0) {
@@ -69,10 +69,10 @@ public class ParserA3D extends Parser {
// Bit of packing. It always equal to 1, because version 2 and above is always packed. // Bit of packing. It always equal to 1, because version 2 and above is always packed.
parseVersionOver1(input); parseVersionOver1(input);
} }
// } catch (e:Error) { } catch (e:Error) {
// e.message = "Parsing failed: " + e.message; e.message = "Parsing failed: " + e.message;
// throw e; throw e;
// } }
} }

View File

@@ -8,17 +8,15 @@
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.BoundBox;
import alternativa.engine3d.core.Camera3D; import alternativa.engine3d.core.Camera3D;
import alternativa.engine3d.core.CullingPlane; 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.lights.OmniLight; import alternativa.engine3d.lights.OmniLight;
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;
import alternativa.engine3d.materials.compiler.Linker; import alternativa.engine3d.materials.compiler.Linker;
@@ -40,9 +38,7 @@ import alternativa.engine3d.materials.Material;
import flash.display3D.textures.CubeTexture; import flash.display3D.textures.CubeTexture;
import flash.utils.Dictionary; import flash.utils.Dictionary;
import spark.effects.easing.Elastic; use namespace alternativa3d;
use namespace alternativa3d;
public class OmniLightShadow extends Shadow{ public class OmniLightShadow extends Shadow{
@@ -71,14 +67,9 @@ use namespace alternativa3d;
private var _casters:Vector.<Object3D> = new Vector.<Object3D>(); private var _casters:Vector.<Object3D> = new Vector.<Object3D>();
private var castersInLight:Vector.<Object3D> = new Vector.<Object3D>();
private var castersInLightCount:int;
private var actualCasters:Vector.<Object3D> = new Vector.<Object3D>(); private var actualCasters:Vector.<Object3D> = new Vector.<Object3D>();
private var actualCastersCount:int; private var actualCastersCount:int;
// cube face -> caster
private var edgeCameraToCasterTransform:Transform3D = new Transform3D();
// caster -> cube face // caster -> cube face
private var casterToEdgedCameraTransform:Transform3D = new Transform3D(); private var casterToEdgedCameraTransform:Transform3D = new Transform3D();
// object -> light // object -> light
@@ -95,12 +86,12 @@ use namespace alternativa3d;
* @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(); sections = new SectionPlane(0x11, 0x22, 0xC); // RU
sections.next = new SectionPlane(); sections.next = new SectionPlane(0x12, 0x21, 0xC); // LU
sections.next.next = new SectionPlane(); sections.next.next = new SectionPlane(0x14, 0x28, 0x3); // FU
sections.next.next.next = new SectionPlane(); sections.next.next.next = new SectionPlane(0x18, 0x24, 0x3); // BU
sections.next.next.next.next = new SectionPlane(); sections.next.next.next.next = new SectionPlane(0x5, 0xA, 0x30); // RF
sections.next.next.next.next.next = new SectionPlane(); sections.next.next.next.next.next = new SectionPlane(0x9, 0x6, 0x30); // RB
this.mapSize = mapSize; this.mapSize = mapSize;
this.pcfOffset = pcfOffset; this.pcfOffset = pcfOffset;
@@ -145,12 +136,6 @@ use namespace alternativa3d;
cameras[4].rotationX = 0; cameras[4].rotationX = 0;
cameras[4].scaleY = -1; cameras[4].scaleY = -1;
cameras[4].composeTransforms(); cameras[4].composeTransforms();
// DUBFLR
// TODO: overwrite calculateFrustum function or setTransformConstants function
// TODO: 2 step culling. 1-culling by radius for light. 2-culling for current camera by 4 planes
} }
private function createDebugObject(material:Material, context:Context3D):Mesh{ private function createDebugObject(material:Material, context:Context3D):Mesh{
@@ -222,7 +207,6 @@ use namespace alternativa3d;
cam.calculateProjection(radius, radius); cam.calculateProjection(radius, radius);
} }
var castersCount:int = _casters.length; var castersCount:int = _casters.length;
actualCastersCount = 0; actualCastersCount = 0;
@@ -236,6 +220,7 @@ use namespace alternativa3d;
parent = parent._parent; parent = parent._parent;
} }
// TODO: remove Object3D.cameras, use something another
if (visible) { if (visible) {
// calculate transform matrices // calculate transform matrices
_light.lightToObjectTransform.combine(caster.cameraToLocalTransform, _light.localToCameraTransform); _light.lightToObjectTransform.combine(caster.cameraToLocalTransform, _light.localToCameraTransform);
@@ -255,7 +240,7 @@ use namespace alternativa3d;
} else { } else {
caster.cameras = 63; caster.cameras = 63;
} }
// update Skin Joints matrices // update Skin Joints matrices
var skin:Skin = caster as Skin; var skin:Skin = caster as Skin;
if (skin != null) { if (skin != null) {
@@ -275,24 +260,11 @@ use namespace alternativa3d;
} }
} }
// Iterate through six cameras // Iterate through six cameras
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++) {
// Cube side camera // Cube side camera
var edgeCamera:Camera3D = cameras[i]; var edgeCamera:Camera3D = cameras[i];
// проверяем, есть ли видимые кастеры попадающие на грань куба
// var flipX:Boolean = edgeCamera.scaleX < 0;
// var flipY:Boolean = edgeCamera.scaleY < 0;
// edgeCamera.scaleX = 1;
// edgeCamera.scaleY = 1;
// edgeCamera.composeTransforms();
// if (flipX) edgeCamera.scaleX = -1;
// if (flipY) edgeCamera.scaleY = -1;
// edgeCamera.composeTransforms();
var edgeBit:int = (1<<i); var edgeBit:int = (1<<i);
if (actualCastersCount > 0) { if (actualCastersCount > 0) {
// Настройка параметров рендеринга: // Настройка параметров рендеринга:
@@ -305,7 +277,7 @@ use namespace alternativa3d;
caster = actualCasters[j]; caster = actualCasters[j];
// Проверить находится ли кастер в зоне 4-х плоскостей // Проверить находится ли кастер в зоне 4-х плоскостей
if (caster.cameras & edgeBit) { if ((caster.cameras & edgeBit)) {
// собираем матрицу перевода из кастера в пространство edgeCamera // собираем матрицу перевода из кастера в пространство edgeCamera
casterToEdgedCameraTransform.combine(edgeCamera.inverseTransform, caster.localToLightTransform); casterToEdgedCameraTransform.combine(edgeCamera.inverseTransform, caster.localToLightTransform);
// Собираем драуколлы для кастера и его дочерних объектов // Собираем драуколлы для кастера и его дочерних объектов
@@ -313,7 +285,7 @@ use namespace alternativa3d;
} }
} }
if (renderer.drawUnits.length == 0) context.clear(0, 0, 0, 0.0); // if (renderer.drawUnits.length == 0) context.clear(0, 0, 0, 0.0);
// Отрисовка дроуколов // Отрисовка дроуколов
renderer.render(context); renderer.render(context);
@@ -322,9 +294,9 @@ use namespace alternativa3d;
else{ else{
// Если относительно одной из камер ничего не менялось, не вызываем отрисовочный вызов // Если относительно одной из камер ничего не менялось, не вызываем отрисовочный вызов
if (prevActualCastersMask & edgeBit){ if ((prevActualCastersMask & edgeBit)){
context.setRenderToTexture(cubeShadowMap, false, 0, i); context.setRenderToTexture(cubeShadowMap, false, 0, i);
context.clear(0, 0, 0, 0); context.clear(1, 0, 0, 0);
prevActualCastersMask &= ~edgeBit; prevActualCastersMask &= ~edgeBit;
} }
@@ -347,13 +319,13 @@ use namespace alternativa3d;
// } // }
if (debug) { if (debug) {
if (actualCastersCount > 0 || true) { if (actualCastersCount > 0) {
// TODO: draw debug mesh always (DirectionalLightShadow) // TODO: draw debug mesh always (DirectionalLightShadow)
// Создаем дебаговый объект, если он не создан // Create debug object if needed
if (debugObject == null) { if (debugObject == null) {
debugObject = createDebugObject(debugMaterial, camera.context3D); debugObject = createDebugObject(debugMaterial, camera.context3D);
// TODO: select wright radius // TODO: select right radius
// debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius/12; // debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius/12;
debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius; debugObject.scaleX = debugObject.scaleY = debugObject.scaleZ = radius;
debugObject.composeTransforms(); debugObject.composeTransforms();
@@ -371,86 +343,81 @@ use namespace alternativa3d;
private var sections:SectionPlane; private var sections:SectionPlane;
private function calculatePlanes(lightToObjectTransform:Transform3D):void { private function calculatePlanes(transform:Transform3D):void {
// DUBFLR
var planeRU:SectionPlane = sections; var planeRU:SectionPlane = sections;
var planeLU:SectionPlane = sections.next; var planeLU:SectionPlane = sections.next;
var planeFU:SectionPlane = sections.next.next;
var planeBU:SectionPlane = sections.next.next.next;
var planeRF:SectionPlane = sections.next.next.next.next;
var planeRB:SectionPlane = sections.next.next.next.next.next;
sections.x = 0.707; // TODO: reuse points
sections.z = 0.707; var ax:Number = transform.c - transform.a + transform.b;
sections.offset = sections.x*lightToObjectTransform.d + sections.z*lightToObjectTransform.l; var ay:Number = transform.g - transform.e + transform.f;
var az:Number = transform.k - transform.i + transform.j;
var bx:Number = transform.c - transform.a - transform.b;
var by:Number = transform.g - transform.e - transform.f;
var bz:Number = transform.k - transform.i - transform.j;
planeRU.x = bz * ay - by * az;
planeRU.y = bx * az - bz * ax;
planeRU.z = by * ax - bx * ay;
planeRU.offset = transform.d*planeRU.x + transform.h*planeRU.y + transform.l*planeRU.z;
//var RIGHT_SIDE:int = 0; ax = transform.c + transform.a - transform.b;
ay = transform.g + transform.e - transform.f;
az = transform.k + transform.i - transform.j;
bx = transform.c + transform.a + transform.b;
by = transform.g + transform.e + transform.f;
bz = transform.k + transform.i + transform.j;
planeLU.x = bz * ay - by * az;
planeLU.y = bx * az - bz * ax;
planeLU.z = by * ax - bx * ay;
planeLU.offset = transform.d*planeLU.x + transform.h*planeLU.y + transform.l*planeLU.z;
sections.frontCameras = 0x11; ax = transform.c - transform.a - transform.b;
sections.backCameras = 0x22; ay = transform.g - transform.e - transform.f;
// sections.unused = 0x33; az = transform.k - transform.i - transform.j;
sections.unused = 0xC; bx = transform.c + transform.a - transform.b;
by = transform.g + transform.e - transform.f;
bz = transform.k + transform.i - transform.j;
planeFU.x = bz * ay - by * az;
planeFU.y = bx * az - bz * ax;
planeFU.z = by * ax - bx * ay;
planeFU.offset = transform.d*planeFU.x + transform.h*planeFU.y + transform.l*planeFU.z;
planeLU.x = -0.707; ax = transform.c + transform.a + transform.b;
planeLU.z = 0.707; ay = transform.g + transform.e + transform.f;
planeLU.offset = planeLU.x*lightToObjectTransform.d + planeLU.z*lightToObjectTransform.l; az = transform.k + transform.i + transform.j;
bx = transform.c - transform.a + transform.b;
by = transform.g - transform.e + transform.f;
bz = transform.k - transform.i + transform.j;
planeBU.x = bz * ay - by * az;
planeBU.y = bx * az - bz * ax;
planeBU.z = by * ax - bx * ay;
planeBU.offset = transform.d*planeBU.x + transform.h*planeBU.y + transform.l*planeBU.z;
planeLU.frontCameras = 0x12; ax = transform.a - transform.b + transform.c;
planeLU.backCameras = 0x21; ay = transform.e - transform.f + transform.g;
planeLU.unused = 0xC; az = transform.i - transform.j + transform.k;
bx = transform.a - transform.b - transform.c;
by = transform.e - transform.f - transform.g;
bz = transform.i - transform.j - transform.k;
planeRF.x = bz * ay - by * az;
planeRF.y = bx * az - bz * ax;
planeRF.z = by * ax - bx * ay;
planeRF.offset = transform.d*planeRF.x + transform.h*planeRF.y + transform.l*planeRF.z;
// var nearPlane:CullingPlane = sections; ax = transform.a + transform.b - transform.c;
// var farPlane:CullingPlane = nearPlane.next; ay = transform.e + transform.f - transform.g;
// var leftPlane:CullingPlane = farPlane.next; az = transform.i + transform.j - transform.k;
// var rightPlane:CullingPlane = leftPlane.next; bx = transform.a + transform.b + transform.c;
// var topPlane:CullingPlane = rightPlane.next; by = transform.e + transform.f + transform.g;
// var bottomPlane:CullingPlane = topPlane.next; bz = transform.i + transform.j + transform.k;
// planeRB.x = bz * ay - by * az;
// var fa:Number = transform.a * correctionX; planeRB.y = bx * az - bz * ax;
// var fe:Number = transform.e * correctionX; planeRB.z = by * ax - bx * ay;
// var fi:Number = transform.i * correctionX; planeRB.offset = transform.d*planeRB.x + transform.h*planeRB.y + transform.l*planeRB.z;
// var fb:Number = transform.b * correctionY;
// var ff:Number = transform.f * correctionY;
// var fj:Number = transform.j * correctionY;
//
// var ax:Number = -fa - fb + transform.c;
// var ay:Number = -fe - ff + transform.g;
// var az:Number = -fi - fj + transform.k;
// var bx:Number = fa - fb + transform.c;
// var by:Number = fe - ff + transform.g;
// var bz:Number = fi - fj + transform.k;
// topPlane.x = bz * ay - by * az;
// topPlane.y = bx * az - bz * ax;
// topPlane.z = by * ax - bx * ay;
// topPlane.offset = transform.d * topPlane.x + transform.h * topPlane.y + transform.l * topPlane.z;
// // Right plane.
// ax = bx;
// ay = by;
// az = bz;
// bx = fa + fb + transform.c;
// by = fe + ff + transform.g;
// bz = fi + fj + transform.k;
// rightPlane.x = bz * ay - by * az;
// rightPlane.y = bx * az - bz * ax;
// rightPlane.z = by * ax - bx * ay;
// rightPlane.offset = transform.d * rightPlane.x + transform.h * rightPlane.y + transform.l * rightPlane.z;
// // Bottom plane.
// ax = bx;
// ay = by;
// az = bz;
// bx = -fa + fb + transform.c;
// by = -fe + ff + transform.g;
// bz = -fi + fj + transform.k;
// bottomPlane.x = bz*ay - by*az;
// bottomPlane.y = bx*az - bz*ax;
// bottomPlane.z = by*ax - bx*ay;
// bottomPlane.offset = transform.d*bottomPlane.x + transform.h*bottomPlane.y + transform.l*bottomPlane.z;
// // Left plane.
// ax = bx;
// ay = by;
// az = bz;
// bx = -fa - fb + transform.c;
// by = -fe - ff + transform.g;
// bz = -fi - fj + transform.k;
// leftPlane.x = bz*ay - by*az;
// leftPlane.y = bx*az - bz*ax;
// leftPlane.z = by*ax - bx*ay;
// leftPlane.offset = transform.d*leftPlane.x + transform.h*leftPlane.y + transform.l*leftPlane.z;
} }
private function recognizeObjectCameras(bb:BoundBox):int { private function recognizeObjectCameras(bb:BoundBox):int {
@@ -537,37 +504,6 @@ use namespace alternativa3d;
} }
} }
// // собирает список actualCasters для одной из 6-и камер
// private function calculateVisibility(root:Object3D, camera:Camera3D):void{
// var casterCulling:int;
//
// if (root.visible) {
// // Вычисляем результат кулинга для объекта
// if (root.boundBox != null) {
// edgeCameraToCasterTransform.combine(root.lightToLocalTransform, camera.transform);
// camera.calculateFrustum(edgeCameraToCasterTransform);
// casterCulling = root.boundBox.checkFrustumCulling(camera.frustum, 63);
// } else {
// casterCulling = 63;
// }
//
// if (casterCulling <= 0) numCulled++;
//
// // добавляем кастер в список актуальных кастеров
// if (casterCulling >= 0) {
// actualCasters[actualCastersCount] = root;
// actualCastersCount++
// }
//
// // Если есть дочерние объекты,
// // Проверяем их на кулинг
// for (var child:Object3D = root.childrenList; child != null; child = child.next) {
// calculateVisibility(child, camera);
// }
// }
// }
private function collectDraws(context:Context3D, caster:Object3D, edgeCamera:Camera3D):void{ private function collectDraws(context:Context3D, caster:Object3D, edgeCamera:Camera3D):void{
// если объект является мешем, собираем для него дроуколы // если объект является мешем, собираем для него дроуколы
var mesh:Mesh = caster as Mesh; var mesh:Mesh = caster as Mesh;
@@ -650,7 +586,6 @@ use namespace alternativa3d;
} }
} }
/** /**
* @private * @private
* Процедура для передачи UV координат во фрагментный шейдер * Процедура для передачи UV координат во фрагментный шейдер
@@ -1122,4 +1057,10 @@ class SectionPlane {
public var backCameras:int; public var backCameras:int;
public var unused:int = 63; public var unused:int = 63;
public function SectionPlane(frontCameras:int, backCameras:int, unused:int) {
this.frontCameras = frontCameras;
this.backCameras = backCameras;
this.unused = unused;
}
} }