mirror of
https://github.com/MapMakersAndProgrammers/Alternativa3D.git
synced 2025-10-26 18:09:14 -07:00
Merge remote-tracking branch 'origin/8.29.BugOmniShadow'
This commit is contained in:
@@ -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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user