mirror of
https://github.com/MapMakersAndProgrammers/Alternativa3D.git
synced 2025-10-26 09:59:10 -07:00
Removes old shadow classes
This commit is contained in:
@@ -1,540 +0,0 @@
|
|||||||
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.Transform3D;
|
|
||||||
import alternativa.engine3d.core.VertexAttributes;
|
|
||||||
import alternativa.engine3d.lights.DirectionalLight;
|
|
||||||
import alternativa.engine3d.materials.ShaderProgram;
|
|
||||||
import alternativa.engine3d.materials.TextureMaterial;
|
|
||||||
import alternativa.engine3d.materials.compiler.Linker;
|
|
||||||
import alternativa.engine3d.materials.compiler.Procedure;
|
|
||||||
import alternativa.engine3d.materials.compiler.VariableType;
|
|
||||||
import alternativa.engine3d.objects.Mesh;
|
|
||||||
import alternativa.engine3d.objects.Surface;
|
|
||||||
import alternativa.engine3d.primitives.Box;
|
|
||||||
import alternativa.engine3d.resources.ExternalTextureResource;
|
|
||||||
import alternativa.engine3d.resources.TextureResource;
|
|
||||||
|
|
||||||
import flash.display3D.Context3D;
|
|
||||||
import flash.display3D.Context3DProgramType;
|
|
||||||
import flash.display3D.Context3DTextureFormat;
|
|
||||||
import flash.display3D.Context3DTriangleFace;
|
|
||||||
import flash.display3D.Program3D;
|
|
||||||
import flash.display3D.textures.Texture;
|
|
||||||
import flash.geom.Matrix3D;
|
|
||||||
import flash.geom.Vector3D;
|
|
||||||
|
|
||||||
use namespace alternativa3d;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
public class DirectionalShadowRenderer extends ShadowRenderer {
|
|
||||||
|
|
||||||
public var offset:Vector3D = new Vector3D();
|
|
||||||
|
|
||||||
public var caster:Object3D;
|
|
||||||
|
|
||||||
private var context:Context3D;
|
|
||||||
|
|
||||||
private var shadowMap:Texture;
|
|
||||||
private var _worldSize:Number;
|
|
||||||
|
|
||||||
private var light:DirectionalLight;
|
|
||||||
alternativa3d var globalToShadowMap:Matrix3D = new Matrix3D();
|
|
||||||
|
|
||||||
private var debugObject:Mesh;
|
|
||||||
public var debugMaterial:TextureMaterial = new TextureMaterial();
|
|
||||||
private var debugTexture:TextureResource = new ExternalTextureResource("null");
|
|
||||||
// private var debugTexture:TextureResource = new BitmapTextureResource(new BitmapData(4, 4, false, 0xFF0000));
|
|
||||||
|
|
||||||
private static const constants:Vector.<Number> = Vector.<Number>([
|
|
||||||
// 255, 255*0.98, 100, 1
|
|
||||||
255, 255*0.96, 100, 1
|
|
||||||
]);
|
|
||||||
|
|
||||||
private var pcfOffset:Number = 0;
|
|
||||||
private var pcfOffsets:Vector.<Number>;
|
|
||||||
|
|
||||||
public function DirectionalShadowRenderer(context:Context3D, size:int, worldSize:Number, pcfSize:Number = 0) {
|
|
||||||
this.context = context;
|
|
||||||
this._worldSize = worldSize;
|
|
||||||
this.pcfOffset = pcfSize/worldSize/255;
|
|
||||||
// this.pcfOffset = pcfSize;
|
|
||||||
if (pcfOffset > 0) {
|
|
||||||
pcfOffsets = Vector.<Number>([
|
|
||||||
-pcfOffset, -pcfOffset, 0, 1/4,
|
|
||||||
-pcfOffset, pcfOffset, 0, 1,
|
|
||||||
pcfOffset, -pcfOffset, 0, 1,
|
|
||||||
pcfOffset, pcfOffset, 0, 1
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
this.shadowMap = context.createTexture(size, size, Context3DTextureFormat.BGRA, true);
|
|
||||||
debugTexture._texture = this.shadowMap;
|
|
||||||
debugMaterial.diffuseMap = debugTexture;
|
|
||||||
debugMaterial.alpha = 0.9;
|
|
||||||
// TODO: fix
|
|
||||||
debugMaterial.transparentPass = true;
|
|
||||||
debugMaterial.opaquePass = false;
|
|
||||||
debugMaterial.alphaThreshold = 1.1;
|
|
||||||
|
|
||||||
// debugTexture.upload(context);
|
|
||||||
|
|
||||||
debugObject = new Box(worldSize, worldSize, 1, 1, 1, 1, false, debugMaterial);
|
|
||||||
debugObject.geometry.upload(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function get worldSize():Number {
|
|
||||||
return _worldSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function set worldSize(value:Number):void {
|
|
||||||
_worldSize = value;
|
|
||||||
var newDebug:Mesh = new Box(_worldSize, _worldSize, 1, 1, 1, 1, false, debugMaterial);
|
|
||||||
newDebug.geometry.upload(context);
|
|
||||||
if (debugObject._parent != null) {
|
|
||||||
debugObject._parent.addChild(newDebug);
|
|
||||||
debugObject._parent.removeChild(debugObject);
|
|
||||||
}
|
|
||||||
debugObject = newDebug;
|
|
||||||
}
|
|
||||||
|
|
||||||
private var _debug:Boolean = false;
|
|
||||||
public function setLight(value:DirectionalLight):void {
|
|
||||||
light = value;
|
|
||||||
if (_debug) {
|
|
||||||
light.addChild(debugObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override public function get debug():Boolean {
|
|
||||||
return _debug;
|
|
||||||
}
|
|
||||||
|
|
||||||
override public function set debug(value:Boolean):void {
|
|
||||||
_debug = value;
|
|
||||||
if (_debug) {
|
|
||||||
if (light != null) {
|
|
||||||
light.addChild(debugObject);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (debugObject._parent != null) {
|
|
||||||
debugObject._parent.removeChild(debugObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static var matrix:Matrix3D = new Matrix3D();
|
|
||||||
override alternativa3d function cullReciever(boundBox:BoundBox, object:Object3D):Boolean {
|
|
||||||
copyMatrixFromTransform(matrix, object.localToGlobalTransform);
|
|
||||||
matrix.append(this.globalToShadowMap);
|
|
||||||
return cullObjectImplementation(boundBox, matrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
private var lightProjectionMatrix:Matrix3D = new Matrix3D();
|
|
||||||
private var uvMatrix:Matrix3D = new Matrix3D();
|
|
||||||
private var center:Vector3D = new Vector3D();
|
|
||||||
override public function update():void {
|
|
||||||
active = true;
|
|
||||||
var root:Object3D;
|
|
||||||
// Расчитываем матрицу объекта
|
|
||||||
// if (caster.transformChanged) {
|
|
||||||
caster.localToCameraTransform.compose(caster._x, caster._y, caster._z, caster._rotationX, caster._rotationY, caster._rotationZ, caster._scaleX, caster._scaleY, caster._scaleZ);
|
|
||||||
// } else {
|
|
||||||
// caster.localToCameraTransform.copy(caster.transform);
|
|
||||||
// }
|
|
||||||
root = caster;
|
|
||||||
while (root._parent != null) {
|
|
||||||
root = root._parent;
|
|
||||||
// if (root.transformChanged) {
|
|
||||||
root.localToGlobalTransform.compose(root._x, root._y, root._z, root._rotationX, root._rotationY, root._rotationZ, root._scaleX, root._scaleY, root._scaleZ);
|
|
||||||
// }
|
|
||||||
caster.localToCameraTransform.append(root.localToGlobalTransform);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Расчитываем матрицу лайта
|
|
||||||
light.localToGlobalTransform.compose(light._x, light._y, light._z, light._rotationX, light._rotationY, light._rotationZ, light._scaleX, light._scaleY, light._scaleZ);
|
|
||||||
root = light;
|
|
||||||
while (root._parent != null) {
|
|
||||||
root = root._parent;
|
|
||||||
// if (root.transformChanged) {
|
|
||||||
root.localToGlobalTransform.compose(root._x, root._y, root._z, root._rotationX, root._rotationY, root._rotationZ, root._scaleX, root._scaleY, root._scaleZ);
|
|
||||||
// }
|
|
||||||
light.localToGlobalTransform.append(root.localToGlobalTransform);
|
|
||||||
}
|
|
||||||
light.globalToLocalTransform.copy(light.localToGlobalTransform);
|
|
||||||
light.globalToLocalTransform.invert();
|
|
||||||
|
|
||||||
// Получаем матрицу перевода из объекта в лайт
|
|
||||||
caster.localToCameraTransform.append(light.globalToLocalTransform);
|
|
||||||
|
|
||||||
// Расчет матрицы проецирования
|
|
||||||
var t:Transform3D = caster.localToCameraTransform;
|
|
||||||
center.x = t.a*offset.x + t.b*offset.y + t.c*offset.z + t.d;
|
|
||||||
center.y = t.e*offset.x + t.f*offset.y + t.g*offset.z + t.h;
|
|
||||||
center.z = t.i*offset.x + t.j*offset.y + t.k*offset.z + t.l;
|
|
||||||
// var center:Vector3D = new Vector3D(caster.localToCameraTransform.d, caster.localToCameraTransform.h, caster.localToCameraTransform.l);
|
|
||||||
|
|
||||||
calculateShadowMapProjection(lightProjectionMatrix, uvMatrix, center, _worldSize, _worldSize, _worldSize);
|
|
||||||
copyMatrixFromTransform(globalToShadowMap, light.globalToLocalTransform);
|
|
||||||
globalToShadowMap.append(uvMatrix);
|
|
||||||
|
|
||||||
debugObject.x = center.x;
|
|
||||||
debugObject.y = center.y;
|
|
||||||
debugObject.z = center.z - _worldSize/2;
|
|
||||||
// trace("center", center);
|
|
||||||
|
|
||||||
debugMaterial.diffuseMap = null;
|
|
||||||
|
|
||||||
// Рисуем в шедоумапу
|
|
||||||
context.setRenderToTexture(shadowMap, true, 0, 0);
|
|
||||||
// context.clear(1);
|
|
||||||
context.clear(1, 1, 1, 1);
|
|
||||||
cleanContext(context);
|
|
||||||
drawObjectToShadowMap(context, caster, light, lightProjectionMatrix);
|
|
||||||
context.setRenderToBackBuffer();
|
|
||||||
cleanContext(context);
|
|
||||||
debugMaterial.diffuseMap = debugTexture;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static var transformToMatrixRawData:Vector.<Number> = new Vector.<Number>(16);
|
|
||||||
alternativa3d static function copyMatrixFromTransform(matrix:Matrix3D, transform:Transform3D):void {
|
|
||||||
transformToMatrixRawData[0] = transform.a;
|
|
||||||
transformToMatrixRawData[1] = transform.e;
|
|
||||||
transformToMatrixRawData[2] = transform.i;
|
|
||||||
transformToMatrixRawData[3] = 0;
|
|
||||||
transformToMatrixRawData[4] = transform.b;
|
|
||||||
transformToMatrixRawData[5] = transform.f;
|
|
||||||
transformToMatrixRawData[6] = transform.j;
|
|
||||||
transformToMatrixRawData[7] = 0;
|
|
||||||
transformToMatrixRawData[8] = transform.c;
|
|
||||||
transformToMatrixRawData[9] = transform.g;
|
|
||||||
transformToMatrixRawData[10] = transform.k;
|
|
||||||
transformToMatrixRawData[11] = 0;
|
|
||||||
transformToMatrixRawData[12] = transform.d;
|
|
||||||
transformToMatrixRawData[13] = transform.h;
|
|
||||||
transformToMatrixRawData[14] = transform.l;
|
|
||||||
transformToMatrixRawData[15] = 1;
|
|
||||||
// matrix.copyRawDataFrom(transformToMatrixRawData);
|
|
||||||
matrix.rawData = transformToMatrixRawData;
|
|
||||||
}
|
|
||||||
|
|
||||||
alternativa3d static function drawObjectToShadowMap(context:Context3D, object:Object3D, light:DirectionalLight, projection:Matrix3D):void {
|
|
||||||
if (object is Mesh) {
|
|
||||||
drawMeshToShadowMap(context, Mesh(object), projection);
|
|
||||||
}
|
|
||||||
for (var child:Object3D = object.childrenList; child != null; child = child.next) {
|
|
||||||
if (child.visible && child.useShadow) {
|
|
||||||
if (child.transformChanged) child.composeTransforms();
|
|
||||||
child.localToCameraTransform.combine(object.localToCameraTransform, child.transform);
|
|
||||||
drawObjectToShadowMap(context, child, light, projection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static var drawProjection:Matrix3D = new Matrix3D();
|
|
||||||
private static var directionalShadowMapProgram:Program3D;
|
|
||||||
private static function drawMeshToShadowMap(context:Context3D, mesh:Mesh, projection:Matrix3D):void {
|
|
||||||
if (mesh.geometry == null || mesh.geometry.numTriangles == 0 || !mesh.geometry.isUploaded) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
copyMatrixFromTransform(drawProjection, mesh.localToCameraTransform);
|
|
||||||
drawProjection.append(projection);
|
|
||||||
if (directionalShadowMapProgram == null) directionalShadowMapProgram = initMeshToShadowMapProgram(context);
|
|
||||||
context.setProgram(directionalShadowMapProgram);
|
|
||||||
|
|
||||||
context.setVertexBufferAt(0, mesh.geometry.getVertexBuffer(VertexAttributes.POSITION), mesh.geometry._attributesOffsets[VertexAttributes.POSITION], VertexAttributes.FORMATS[VertexAttributes.POSITION]);
|
|
||||||
|
|
||||||
context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, drawProjection, true);
|
|
||||||
context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 4, Vector.<Number>([255, 0, 0, 1]));
|
|
||||||
context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, Vector.<Number>([1/255, 0, 0, 1]));
|
|
||||||
|
|
||||||
context.setCulling(Context3DTriangleFace.BACK);
|
|
||||||
|
|
||||||
for (var i:int = 0; i < mesh._surfacesLength; i++) {
|
|
||||||
var surface:Surface = mesh._surfaces[i];
|
|
||||||
if (surface.material == null || !surface.material.canDrawInShadowMap) continue;
|
|
||||||
context.drawTriangles(mesh.geometry._indexBuffer, surface.indexBegin, surface.numTriangles);
|
|
||||||
}
|
|
||||||
context.setVertexBufferAt(0, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function initMeshToShadowMapProgram(context3d:Context3D):Program3D {
|
|
||||||
var vLinker:Linker = new Linker(Context3DProgramType.VERTEX);
|
|
||||||
var fLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
|
|
||||||
var proc:Procedure = Procedure.compileFromArray([
|
|
||||||
"#a0=a0",
|
|
||||||
"#c4=c4",
|
|
||||||
"#v0=v0",
|
|
||||||
"m44 t0, a0, c0",
|
|
||||||
"mul v0, t0, c4.x",
|
|
||||||
"mov o0, t0"
|
|
||||||
]);
|
|
||||||
proc.assignVariableName(VariableType.CONSTANT, 0, "c0", 4);
|
|
||||||
vLinker.addProcedure(proc);
|
|
||||||
|
|
||||||
fLinker.addProcedure(Procedure.compileFromArray([
|
|
||||||
"#v0=v0",
|
|
||||||
"#c0=c0",
|
|
||||||
"mov t0.xy, v0.zz",
|
|
||||||
"frc t0.y, v0.z",
|
|
||||||
"sub t0.x, v0.z, t0.y",
|
|
||||||
"mul t0.x, t0.x, c0.x",
|
|
||||||
"mov t0.z, c0.z",
|
|
||||||
"mov t0.w, c0.w",
|
|
||||||
"mov o0, t0"
|
|
||||||
]));
|
|
||||||
var program:Program3D = context3d.createProgram();
|
|
||||||
// trace("VERTEX");
|
|
||||||
// trace(A3DUtils.disassemble(vLinker.getByteCode()));
|
|
||||||
// trace("FRAGMENT");
|
|
||||||
// trace(A3DUtils.disassemble(fLinker.getByteCode()));
|
|
||||||
fLinker.varyings = vLinker.varyings;
|
|
||||||
vLinker.link();
|
|
||||||
fLinker.link();
|
|
||||||
program.upload(vLinker.data, fLinker.data);
|
|
||||||
return program;
|
|
||||||
}
|
|
||||||
|
|
||||||
// должен быть заполнен нулями
|
|
||||||
private var rawData:Vector.<Number> = new Vector.<Number>(16);
|
|
||||||
private function calculateShadowMapProjection(matrix:Matrix3D, uvMatrix:Matrix3D, offset:Vector3D, width:Number, height:Number, length:Number):void {
|
|
||||||
var halfW:Number = width/2;
|
|
||||||
var halfH:Number = height/2;
|
|
||||||
var halfL:Number = length/2;
|
|
||||||
var frustumMinX:Number = offset.x - halfW;
|
|
||||||
var frustumMaxX:Number = offset.x + halfW;
|
|
||||||
var frustumMinY:Number = offset.y - halfH;
|
|
||||||
var frustumMaxY:Number = offset.y + halfH;
|
|
||||||
var frustumMinZ:Number = offset.z - halfL;
|
|
||||||
var frustumMaxZ:Number = offset.z + halfL;
|
|
||||||
|
|
||||||
// Считаем матрицу проецирования
|
|
||||||
rawData[0] = 2/(frustumMaxX - frustumMinX);
|
|
||||||
rawData[5] = 2/(frustumMaxY - frustumMinY);
|
|
||||||
rawData[10]= 1/(frustumMaxZ - frustumMinZ);
|
|
||||||
rawData[12] = (-0.5 * (frustumMaxX + frustumMinX) * rawData[0]);
|
|
||||||
rawData[13] = (-0.5 * (frustumMaxY + frustumMinY) * rawData[5]);
|
|
||||||
rawData[14]= -frustumMinZ/(frustumMaxZ - frustumMinZ);
|
|
||||||
rawData[15]= 1;
|
|
||||||
matrix.rawData = rawData;
|
|
||||||
|
|
||||||
rawData[0] = 1/((frustumMaxX - frustumMinX));
|
|
||||||
// if (useSingle) {
|
|
||||||
// rawData[5] = 1/((frustumMaxY - frustumMinY));
|
|
||||||
// } else {
|
|
||||||
rawData[5] = -1/((frustumMaxY - frustumMinY));
|
|
||||||
// }
|
|
||||||
rawData[12] = 0.5 - (0.5 * (frustumMaxX + frustumMinX) * rawData[0]);
|
|
||||||
rawData[13] = 0.5 - (0.5 * (frustumMaxY + frustumMinY) * rawData[5]);
|
|
||||||
uvMatrix.rawData = rawData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
private static const fullVShader:Procedure = initFullVShader();
|
|
||||||
private static function initFullVShader():Procedure {
|
|
||||||
var shader:Procedure = Procedure.compileFromArray([
|
|
||||||
"m44 o0, a0, c0",
|
|
||||||
// Координата вершины в локальном пространстве
|
|
||||||
"m44 v0, a0, c4",
|
|
||||||
]);
|
|
||||||
shader.assignVariableName(VariableType.ATTRIBUTE, 0, "aPosition");
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 0, "cPROJ", 4);
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 4, "cTOSHADOW", 4);
|
|
||||||
shader.assignVariableName(VariableType.VARYING, 0, "vSHADOWSAMPLE");
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
private static function initVShader(index:int):Procedure {
|
|
||||||
var shader:Procedure = Procedure.compileFromArray([
|
|
||||||
"m44 v0, a0, c0"
|
|
||||||
]);
|
|
||||||
shader.assignVariableName(VariableType.ATTRIBUTE, 0, "aPosition");
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 0, index + "cTOSHADOW", 4);
|
|
||||||
shader.assignVariableName(VariableType.VARYING, 0, index + "vSHADOWSAMPLE");
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
private static function initFShader(mult:Boolean, usePCF:Boolean, index:int, grayScale:Boolean = false):Procedure {
|
|
||||||
var i:int;
|
|
||||||
var line:int = 0;
|
|
||||||
var shaderArr:Array = [];
|
|
||||||
var numPass:uint = (usePCF) ? 4 : 1;
|
|
||||||
for (i = 0; i < numPass; i++) {
|
|
||||||
// Расстояние
|
|
||||||
shaderArr[line++] = "mov t0.w, v0.z";
|
|
||||||
shaderArr[line++] = "mul t0.w, t0.w, c4.y"; // bias [0.99] * 255
|
|
||||||
|
|
||||||
if (usePCF) {
|
|
||||||
// Добавляем смещение
|
|
||||||
shaderArr[line++] = "mul t1, c" + (i + 6).toString() + ", t0.w";
|
|
||||||
shaderArr[line++] = "add t1, v0, t1";
|
|
||||||
shaderArr[line++] = "tex t1, t1, s0 <2d,clamp,near,nomip>";
|
|
||||||
} else {
|
|
||||||
shaderArr[line++] = "tex t1, v0, s0 <2d,clamp,near,nomip>";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Восстанавливаем расстояние
|
|
||||||
shaderArr[line++] = "mul t1.w, t1.x, c4.x"; // * 255
|
|
||||||
shaderArr[line++] = "add t1.w, t1.w, t1.y";
|
|
||||||
|
|
||||||
// Перекрытие тенью
|
|
||||||
shaderArr[line++] = "sub t2.z, t1.w, t0.w";
|
|
||||||
shaderArr[line++] = "mul t2.z, t2.z, c4.z"; // smooth [10000]
|
|
||||||
shaderArr[line++] = "sat t2.z, t2.z";
|
|
||||||
|
|
||||||
// Добавляем маску и прозрачность, затем sat
|
|
||||||
if (grayScale) {
|
|
||||||
shaderArr[line++] = "add t2, t2.zzzz, t1.zzzz"; // маска тени
|
|
||||||
} else {
|
|
||||||
shaderArr[line++] = "add t2.z, t2.z, t1.z"; // маска тени
|
|
||||||
shaderArr[line++] = "add t2, t2.zzzz, c5"; // цвет тени
|
|
||||||
}
|
|
||||||
shaderArr[line++] = "sat t2, t2";
|
|
||||||
|
|
||||||
if (usePCF) {
|
|
||||||
if (i == 0) {
|
|
||||||
shaderArr[line++] = "mov t3, t2";
|
|
||||||
} else {
|
|
||||||
shaderArr[line++] = "add t3, t3, t2";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (usePCF) {
|
|
||||||
shaderArr[line++] = "mul t2, t3, c6.w";
|
|
||||||
}
|
|
||||||
if (grayScale) {
|
|
||||||
shaderArr[line++] = "mov o0.w, t2.x";
|
|
||||||
} else {
|
|
||||||
if (mult) {
|
|
||||||
shaderArr[line++] = "mul t0.xyz, i0.xyz, t2.xyz";
|
|
||||||
shaderArr[line++] = "mov t0.w, i0.w";
|
|
||||||
shaderArr[line++] = "mov o0, t0";
|
|
||||||
} else {
|
|
||||||
shaderArr[line++] = "mov o0, t2";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var shader:Procedure = Procedure.compileFromArray(shaderArr, "DirectionalShadowMap");
|
|
||||||
shader.assignVariableName(VariableType.VARYING, 0, index + "vSHADOWSAMPLE");
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 4, index + "cConstants", 1);
|
|
||||||
if (!grayScale) shader.assignVariableName(VariableType.CONSTANT, 5, index + "cShadowColor", 1);
|
|
||||||
if (usePCF) {
|
|
||||||
for (i = 0; i < numPass; i++) {
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, i + 6, "cDPCF" + i.toString(), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
shader.assignVariableName(VariableType.SAMPLER, 0, index + "sSHADOWMAP");
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
override public function getVShader(index:int = 0):Procedure {
|
|
||||||
return initVShader(index);
|
|
||||||
}
|
|
||||||
override public function getFShader(index:int = 0):Procedure {
|
|
||||||
return initFShader(false, (pcfOffset > 0), index);
|
|
||||||
}
|
|
||||||
// override public function getMultFShader():Procedure {
|
|
||||||
// return initFShader(true, (pcfOffset > 0), 0);
|
|
||||||
// }
|
|
||||||
// override public function getMultVShader():Procedure {
|
|
||||||
// return initVShader(0);
|
|
||||||
// }
|
|
||||||
|
|
||||||
override public function getFIntensityShader():Procedure {
|
|
||||||
return initFShader(false, (pcfOffset > 0), 0, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static const objectToShadowMap:Matrix3D = new Matrix3D();
|
|
||||||
private static const localToGlobal:Transform3D = new Transform3D();
|
|
||||||
private static const vector:Vector.<Number> = new Vector.<Number>(16, false);
|
|
||||||
override public function applyShader(drawUnit:DrawUnit, program:ShaderProgram, object:Object3D, camera:Camera3D, index:int = 0):void {
|
|
||||||
// Считаем матрицу перевода в лайт из объекта
|
|
||||||
localToGlobal.combine(camera.localToGlobalTransform, object.localToCameraTransform);
|
|
||||||
copyMatrixFromTransform(objectToShadowMap, localToGlobal);
|
|
||||||
objectToShadowMap.append(globalToShadowMap);
|
|
||||||
objectToShadowMap.copyRawDataTo(vector, 0, true);
|
|
||||||
// objectToShadowMap.transpose();
|
|
||||||
|
|
||||||
// drawUnit.setVertexConstantsFromVector(program.vertexShader.getVariableIndex(index + "cTOSHADOW"), objectToShadowMap.rawData, 4)
|
|
||||||
drawUnit.setVertexConstantsFromVector(program.vertexShader.getVariableIndex(index + "cTOSHADOW"), vector, 4)
|
|
||||||
drawUnit.setFragmentConstantsFromVector(program.fragmentShader.getVariableIndex(index + "cConstants"), constants, 1);
|
|
||||||
if (program.fragmentShader.containsVariable(index + "cShadowColor")) {
|
|
||||||
// drawUnit.setFragmentConstantsFromVector(program.fragmentShader.getVariableIndex(index + "cShadowColor"), camera.ambient, 1);
|
|
||||||
// В дальнейшем яркость тени увеличтся в два раза
|
|
||||||
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex(index + "cShadowColor"), camera.ambient[0]/2, camera.ambient[1]/2, camera.ambient[2]/2, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pcfOffset > 0) {
|
|
||||||
// destination.addFragmentConstantSet(program.fragmentShader.getVariableIndex(index + "cPCF0"), pcfOffsets, pcfOffsets.length/4);
|
|
||||||
drawUnit.setFragmentConstantsFromVector(program.fragmentShader.getVariableIndex("cDPCF0"), pcfOffsets, pcfOffsets.length/4);
|
|
||||||
}
|
|
||||||
drawUnit.setTextureAt(program.fragmentShader.getVariableIndex(index + "sSHADOWMAP"), shadowMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
// override public function getTextureIndex(fLinker:Linker):int {
|
|
||||||
// return fLinker.getVariableIndex("sSHADOWMAP");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private static var program:ShaderProgram;
|
|
||||||
// private static var programPCF:ShaderProgram;
|
|
||||||
// private static function initMeshProgram(context:Context3D, usePCF:Boolean):ShaderProgram {
|
|
||||||
// var vLinker:Linker = new Linker(Context3DProgramType.VERTEX);
|
|
||||||
// vLinker.addProcedure(fullVShader);
|
|
||||||
//
|
|
||||||
// var fLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
|
|
||||||
// if (usePCF) {
|
|
||||||
// fLinker.addProcedure(pcfFShader);
|
|
||||||
// } else {
|
|
||||||
// fLinker.addProcedure(fShader);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// vLinker.setOppositeLinker(fLinker);
|
|
||||||
// fLinker.setOppositeLinker(vLinker);
|
|
||||||
//
|
|
||||||
//// trace("[VERTEX]");
|
|
||||||
//// trace(AgalUtils.disassemble(vLinker.getByteCode()));
|
|
||||||
//// trace("[FRAGMENT]");
|
|
||||||
//// trace(AgalUtils.disassemble(fLinker.getByteCode()));
|
|
||||||
//
|
|
||||||
// var result:ShaderProgram;
|
|
||||||
// if (usePCF) {
|
|
||||||
// programPCF = new ShaderProgram(vLinker, fLinker);
|
|
||||||
// result = programPCF;
|
|
||||||
// } else {
|
|
||||||
// program = new ShaderProgram(vLinker, fLinker);
|
|
||||||
// result = program;
|
|
||||||
// }
|
|
||||||
// return result;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// override public function drawShadow(mesh:Mesh, camera:Camera3D, texture:Texture):void {
|
|
||||||
// var context3d:Context3D = camera.view._context3d;
|
|
||||||
//
|
|
||||||
// var linkedProgram:ShaderProgram;
|
|
||||||
// if (pcfOffset > 0) {
|
|
||||||
// linkedProgram = (programPCF == null) ? initMeshProgram(context3d, true) : programPCF;
|
|
||||||
// } else {
|
|
||||||
// linkedProgram = (program == null) ? initMeshProgram(context3d, false) : program;
|
|
||||||
// }
|
|
||||||
// var vLinker:Linker = linkedProgram.vLinker;
|
|
||||||
// var fLinker:Linker = linkedProgram.fLinker;
|
|
||||||
// context3d.setProgram(linkedProgram.program);
|
|
||||||
//
|
|
||||||
// context3d.setVertexBufferAt(vLinker.getVariableIndex("aPOSITION"), mesh.geometry.vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
|
|
||||||
// context3d.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, vLinker.getVariableIndex("cPROJ"), mesh.projectionMatrix, true);
|
|
||||||
// applyShader(context3d, linkedProgram, mesh, camera);
|
|
||||||
// context3d.setVertexBufferAt(1, null);
|
|
||||||
//
|
|
||||||
// context3d.setCulling(Context3DTriangleFace.FRONT);
|
|
||||||
// context3d.drawTriangles(mesh.geometry.indexBuffer, 0, mesh.geometry.numTriangles);
|
|
||||||
//
|
|
||||||
// context3d.setVertexBufferAt(vLinker.getVariableIndex("aPOSITION"), null);
|
|
||||||
// context.setTextureAt(getTextureIndex(fLinker), texture);
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,798 +0,0 @@
|
|||||||
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.Transform3D;
|
|
||||||
import alternativa.engine3d.core.VertexAttributes;
|
|
||||||
import alternativa.engine3d.core.View;
|
|
||||||
import alternativa.engine3d.lights.OmniLight;
|
|
||||||
import alternativa.engine3d.materials.FillMaterial;
|
|
||||||
import alternativa.engine3d.materials.ShaderProgram;
|
|
||||||
import alternativa.engine3d.materials.compiler.Linker;
|
|
||||||
import alternativa.engine3d.materials.compiler.Procedure;
|
|
||||||
import alternativa.engine3d.materials.compiler.VariableType;
|
|
||||||
import alternativa.engine3d.objects.Mesh;
|
|
||||||
import alternativa.engine3d.objects.Surface;
|
|
||||||
import alternativa.engine3d.primitives.GeoSphere;
|
|
||||||
import alternativa.engine3d.resources.Geometry;
|
|
||||||
|
|
||||||
import flash.display3D.Context3D;
|
|
||||||
import flash.display3D.Context3DProgramType;
|
|
||||||
import flash.display3D.Context3DTextureFormat;
|
|
||||||
import flash.display3D.Context3DTriangleFace;
|
|
||||||
import flash.display3D.Program3D;
|
|
||||||
import flash.display3D.textures.CubeTexture;
|
|
||||||
import flash.geom.Vector3D;
|
|
||||||
|
|
||||||
use namespace alternativa3d;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
public class OmniShadowRenderer extends ShadowRenderer {
|
|
||||||
|
|
||||||
// [Embed("geosphere.A3D", mimeType="application/octet-stream")] private static const ModelClass:Class;
|
|
||||||
private static const debugGeometry:Geometry = createDebugGeometry();
|
|
||||||
private static function createDebugGeometry():Geometry {
|
|
||||||
// var parser:ParserA3D = new ParserA3D();
|
|
||||||
// parser.parse(new ModelClass());
|
|
||||||
// var mesh:Mesh = Mesh(parser.getObjectByName("sphere"));
|
|
||||||
// return mesh.geometry;
|
|
||||||
var geo:GeoSphere = new GeoSphere(0.5, 4);
|
|
||||||
return geo.geometry;
|
|
||||||
}
|
|
||||||
|
|
||||||
private var caster:Object3D;
|
|
||||||
private var casterBounds:BoundBox = new BoundBox();
|
|
||||||
|
|
||||||
private var pcfOffset:Number = 0;
|
|
||||||
|
|
||||||
private var context:Context3D;
|
|
||||||
|
|
||||||
public var omnies:Vector.<OmniLight>;
|
|
||||||
|
|
||||||
private var shadowMap:CubeTexture;
|
|
||||||
private var shadowMapSize:int;
|
|
||||||
private var cameras:Vector.<Camera3D> = new Vector.<Camera3D>();
|
|
||||||
private var clearBits:uint = 0xFF;
|
|
||||||
|
|
||||||
private var currentOmni:OmniLight = new OmniLight(0, 0, 0);
|
|
||||||
|
|
||||||
private static const constants:Vector.<Number> = Vector.<Number>([
|
|
||||||
255, 0.97, 10000, 1/255
|
|
||||||
]);
|
|
||||||
private static const offset:Number = 0.005;
|
|
||||||
private static const pcfOffsets:Vector.<Number> = Vector.<Number>([
|
|
||||||
-offset, -offset, -offset, 1/8,
|
|
||||||
-offset, -offset, offset, 1,
|
|
||||||
-offset, offset, -offset, 1,
|
|
||||||
-offset, offset, offset, 1,
|
|
||||||
offset, -offset, -offset, 1,
|
|
||||||
offset, -offset, offset, 1,
|
|
||||||
offset, offset, -offset, 1,
|
|
||||||
offset, offset, offset, 1,
|
|
||||||
]);
|
|
||||||
|
|
||||||
public function OmniShadowRenderer(context:Context3D, size:int, pcfSize:Number = 0) {
|
|
||||||
this.context = context;
|
|
||||||
this.pcfOffset = pcfSize;
|
|
||||||
shadowMapSize = size;
|
|
||||||
shadowMap = context.createCubeTexture(size, Context3DTextureFormat.BGRA, true);
|
|
||||||
debugGeometry.upload(context);
|
|
||||||
|
|
||||||
for (var i:int = 0; i < 6; i++) {
|
|
||||||
var cam:Camera3D = new Camera3D(1, 100);
|
|
||||||
cam.fov = 1.910633237;
|
|
||||||
cam.view = new View(size, size);
|
|
||||||
cameras[i] = cam;
|
|
||||||
}
|
|
||||||
// Left
|
|
||||||
cameras[1].rotationY = -Math.PI/2;
|
|
||||||
cameras[1].scaleY = -1;
|
|
||||||
// Right
|
|
||||||
cameras[0].rotationY = Math.PI/2;
|
|
||||||
cameras[0].scaleY = -1;
|
|
||||||
// Back
|
|
||||||
cameras[3].rotationX = -Math.PI/2;
|
|
||||||
cameras[3].rotationZ = Math.PI;
|
|
||||||
cameras[3].scaleX = -1;
|
|
||||||
// Front
|
|
||||||
cameras[2].rotationX = -Math.PI/2;
|
|
||||||
cameras[2].scaleY = -1;
|
|
||||||
// Bottom
|
|
||||||
cameras[5].rotationX = Math.PI;
|
|
||||||
cameras[5].scaleX = -1;
|
|
||||||
// Top
|
|
||||||
cameras[4].rotationX = 0;
|
|
||||||
cameras[4].scaleY = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
alternativa3d override function cullReciever(boundBox:BoundBox, object:Object3D):Boolean {
|
|
||||||
// tempBounds.reset();
|
|
||||||
// object.localToCameraTransform.copy(object.localToGlobalTransform);
|
|
||||||
// StaticShadowRenderer.calculateBoundBox(tempBounds, object, false);
|
|
||||||
var bounds:BoundBox = object.boundBox;
|
|
||||||
object.globalToLocalTransform.copy(object.localToGlobalTransform);
|
|
||||||
object.globalToLocalTransform.invert();
|
|
||||||
var inverseMatrix:Transform3D = object.globalToLocalTransform;
|
|
||||||
|
|
||||||
// trace(object.scaleX, object.scaleY, object.scaleZ);
|
|
||||||
var ox:Number = inverseMatrix.a*currentOmni._x + inverseMatrix.b*currentOmni._y + inverseMatrix.c*currentOmni._z + inverseMatrix.d;
|
|
||||||
var oy:Number = inverseMatrix.e*currentOmni._x + inverseMatrix.f*currentOmni._y + inverseMatrix.g*currentOmni._z + inverseMatrix.h;
|
|
||||||
var oz:Number = inverseMatrix.i*currentOmni._x + inverseMatrix.j*currentOmni._y + inverseMatrix.k*currentOmni._z + inverseMatrix.l;
|
|
||||||
var radius:Number = currentOmni.attenuationEnd;
|
|
||||||
if (ox + radius > bounds.minX && ox - radius < bounds.maxX && oy + radius > bounds.minY && oy - radius < bounds.maxY && oz + radius > bounds.minZ && oz - radius < bounds.maxZ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
alternativa3d override function get needMultiplyBlend():Boolean {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public var debugObject:Mesh = new Mesh();
|
|
||||||
// TODO: repair
|
|
||||||
// private var debugMaterial:OmniShadowRendererDebugMaterial = new OmniShadowRendererDebugMaterial();
|
|
||||||
private var debugMaterial:Object;
|
|
||||||
|
|
||||||
public function setCaster(object:Object3D):void {
|
|
||||||
caster = object;
|
|
||||||
object.localToCameraTransform.identity();
|
|
||||||
StaticShadowRenderer.calculateBoundBox(casterBounds, object);
|
|
||||||
|
|
||||||
debugObject.geometry = debugGeometry;
|
|
||||||
// debugObject.addSurface(debugMaterial, 0, debugGeometry.numTriangles);
|
|
||||||
debugObject.addSurface(new FillMaterial(0xFFFFFF), 0, debugGeometry.numTriangles);
|
|
||||||
debugObject.scaleX = 400;
|
|
||||||
debugObject.scaleY = 400;
|
|
||||||
debugObject.scaleZ = 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
private var culledOmnies:Vector.<OmniLight> = new Vector.<OmniLight>();
|
|
||||||
|
|
||||||
private var influences:Vector.<Number> = new Vector.<Number>();
|
|
||||||
private static const inverseMatrix:Transform3D = new Transform3D();
|
|
||||||
|
|
||||||
// private static const omniLocalCoords:Vector.<Number> = new Vector.<Number>(3);
|
|
||||||
|
|
||||||
override public function update():void {
|
|
||||||
// Расчет матрицы объекта
|
|
||||||
caster.localToGlobalTransform.compose(caster._x, caster._y, caster._z, caster._rotationX, caster._rotationY, caster._rotationZ, caster._scaleX, caster._scaleY, caster._scaleZ);
|
|
||||||
var root:Object3D = caster;
|
|
||||||
while (root._parent != null) {
|
|
||||||
root = root._parent;
|
|
||||||
root.localToGlobalTransform.compose(root._x, root._y, root._z, root._rotationX, root._rotationY, root._rotationZ, root._scaleX, root._scaleY, root._scaleZ);
|
|
||||||
caster.localToGlobalTransform.append(root.localToGlobalTransform);
|
|
||||||
}
|
|
||||||
// Расчет матрицы перевода в объект
|
|
||||||
caster.globalToLocalTransform.copy(caster.localToGlobalTransform);
|
|
||||||
caster.globalToLocalTransform.invert();
|
|
||||||
|
|
||||||
/**
|
|
||||||
// // Вычисление множителя масштаба
|
|
||||||
// caster.inverseCameraMatrix.transformVectors(sIn, sOut);
|
|
||||||
// var dx:Number = sOut[0] - sOut[3];
|
|
||||||
// var dy:Number = sOut[1] - sOut[4];
|
|
||||||
// var dz:Number = sOut[2] - sOut[5];
|
|
||||||
// var scale:Number = Math.sqrt(dx*dx + dy*dy + dz*dz);*/
|
|
||||||
|
|
||||||
// var selectedOmni:OmniLight;
|
|
||||||
// var selectedOmniInfluence:Number = -1;
|
|
||||||
var influenceSum:Number = 0;
|
|
||||||
|
|
||||||
var omni:OmniLight;
|
|
||||||
|
|
||||||
culledOmnies.length = 0;
|
|
||||||
influences.length = 0;
|
|
||||||
// Куллинг источников света и нахождение основного
|
|
||||||
for each (omni in omnies) {
|
|
||||||
// Вычисление глобальной позиции омника
|
|
||||||
inverseMatrix.identity();
|
|
||||||
var parent:Object3D = omni._parent;
|
|
||||||
if (parent != null) {
|
|
||||||
parent.localToGlobalTransform.compose(parent._x, parent._y, parent._z, parent._rotationX, parent._rotationY, parent._rotationZ, parent._scaleX, parent._scaleY, parent._scaleZ);
|
|
||||||
root = parent;
|
|
||||||
while (root._parent != null) {
|
|
||||||
if (root == caster || parent == caster) {
|
|
||||||
throw new Error("Caster can not be parent of light");
|
|
||||||
}
|
|
||||||
root = root._parent;
|
|
||||||
root.localToGlobalTransform.compose(root._x, root._y, root._z, root._rotationX, root._rotationY, root._rotationZ, root._scaleX, root._scaleY, root._scaleZ);
|
|
||||||
parent.localToGlobalTransform.append(root.localToGlobalTransform);
|
|
||||||
}
|
|
||||||
inverseMatrix.append(parent.localToGlobalTransform);
|
|
||||||
}
|
|
||||||
inverseMatrix.append(caster.globalToLocalTransform);
|
|
||||||
|
|
||||||
var ox:Number = inverseMatrix.a*omni._x + inverseMatrix.b*omni._y + inverseMatrix.c*omni._z + inverseMatrix.d;
|
|
||||||
var oy:Number = inverseMatrix.e*omni._x + inverseMatrix.f*omni._y + inverseMatrix.g*omni._z + inverseMatrix.h;
|
|
||||||
var oz:Number = inverseMatrix.i*omni._x + inverseMatrix.j*omni._y + inverseMatrix.k*omni._z + inverseMatrix.l;
|
|
||||||
|
|
||||||
// Использовать описывающий баунд-бокс объекта
|
|
||||||
// Куллинг
|
|
||||||
if (ox + omni.attenuationEnd > casterBounds.minX && ox - omni.attenuationEnd < casterBounds.maxX && oy + omni.attenuationEnd > casterBounds.minY && oy - omni.attenuationEnd < casterBounds.maxY && oz + omni.attenuationEnd > casterBounds.minZ && oz - omni.attenuationEnd < casterBounds.maxZ) {
|
|
||||||
// В зоне действия источника
|
|
||||||
// Считаем степень влияния
|
|
||||||
var d:Number = Math.sqrt(ox*ox + oy*oy + oz*oz)/omni.attenuationEnd - 0.1;
|
|
||||||
var influence:Number;
|
|
||||||
if (d > 1) {
|
|
||||||
influence = 0;
|
|
||||||
} else {
|
|
||||||
influence = omni.intensity*calcBrightness(omni.color) * (1 - d);
|
|
||||||
}
|
|
||||||
// if (influence > selectedOmniInfluence) {
|
|
||||||
// selectedOmni = omni;
|
|
||||||
// selectedOmniInfluence = influence;
|
|
||||||
// }
|
|
||||||
influenceSum += influence;
|
|
||||||
influences.push(influence);
|
|
||||||
culledOmnies.push(omni);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
debugMaterial.texture = null;
|
|
||||||
|
|
||||||
var i:int;
|
|
||||||
var surface:uint;
|
|
||||||
var drawed:int = 0;
|
|
||||||
/** if (selectedOmni == null || influenceSum <= 0) {*/
|
|
||||||
if (culledOmnies.length == 0 || influenceSum <= 0) {
|
|
||||||
// Ни один источник не влияет
|
|
||||||
for (i = 0; i < 6; i++) {
|
|
||||||
surface = 1 << i;
|
|
||||||
if (clearBits & surface) {
|
|
||||||
context.setRenderToTexture(shadowMap, true, 0, i);
|
|
||||||
// context.clear(1);
|
|
||||||
context.clear(1, 1, 1, 1);
|
|
||||||
// trace("clear", i);
|
|
||||||
clearBits &= ~surface;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// trace("INVISIBLE");
|
|
||||||
} else {
|
|
||||||
currentOmni._x = 0;
|
|
||||||
currentOmni._y = 0;
|
|
||||||
currentOmni._z = 0;
|
|
||||||
currentOmni.attenuationEnd = 0;
|
|
||||||
for (i = 0; i < culledOmnies.length; i++) {
|
|
||||||
var weight:Number = influences[i]/influenceSum;
|
|
||||||
omni = culledOmnies[i];
|
|
||||||
// Считаем матрицу перевода в глобальное пространство из омника
|
|
||||||
omni.localToGlobalTransform.identity();
|
|
||||||
omni.localToGlobalTransform.d = omni.x;
|
|
||||||
omni.localToGlobalTransform.h = omni.y;
|
|
||||||
omni.localToGlobalTransform.l = omni.z;
|
|
||||||
root = omni;
|
|
||||||
while (root._parent != null) {
|
|
||||||
root = root._parent;
|
|
||||||
if (root.transformChanged) root.composeTransforms();
|
|
||||||
omni.localToGlobalTransform.append(root.transform);
|
|
||||||
}
|
|
||||||
currentOmni._x += omni.localToGlobalTransform.d*weight;
|
|
||||||
currentOmni._y += omni.localToGlobalTransform.h*weight;
|
|
||||||
currentOmni._z += omni.localToGlobalTransform.l*weight;
|
|
||||||
currentOmni.attenuationEnd += omni.attenuationEnd*weight;
|
|
||||||
}
|
|
||||||
currentOmni.localToGlobalTransform.identity();
|
|
||||||
currentOmni.localToGlobalTransform.d = currentOmni._x;
|
|
||||||
currentOmni.localToGlobalTransform.h = currentOmni._y;
|
|
||||||
currentOmni.localToGlobalTransform.l = currentOmni._z;
|
|
||||||
|
|
||||||
// constants[3] = 0.5*1/255;
|
|
||||||
constants[3] = 1.0/255;
|
|
||||||
/** // Расчитываем яркость тени
|
|
||||||
// var weight:Number = (selectedOmniInfluence > 0) ? 1 - (influenceSum - selectedOmniInfluence)/influenceSum : 0;
|
|
||||||
// trace(weight, influenceSum, selectedOmniInfluence);
|
|
||||||
// trace(weight);
|
|
||||||
// var weight:Number = 1;
|
|
||||||
// if (weight > 0) {
|
|
||||||
// constants[3] = (1 + (1 - weight)*5)/255;
|
|
||||||
// } else {
|
|
||||||
// constants[3] = 1/255;
|
|
||||||
// }
|
|
||||||
// // Считаем матрицу перевода в глобальное пространство из омника
|
|
||||||
// selectedOmni.cameraMatrix.identity();
|
|
||||||
// selectedOmni.cameraMatrix.appendTranslation(selectedOmni.x, selectedOmni.y, selectedOmni.z);
|
|
||||||
//// selectedOmni.composeMatrix();
|
|
||||||
// root = selectedOmni;
|
|
||||||
// while (root._parent != null) {
|
|
||||||
// root = root._parent;
|
|
||||||
// root.composeMatrix();
|
|
||||||
// selectedOmni.cameraMatrix.append(root.cameraMatrix);
|
|
||||||
// }
|
|
||||||
//// // Матрица родителя уже посчитана
|
|
||||||
//// if (omni._parent != null) {
|
|
||||||
//// omni.cameraMatrix.append(omni._parent.cameraMatrix);
|
|
||||||
//// }
|
|
||||||
// selectedOmni.globalCoords[0] = 0;
|
|
||||||
// selectedOmni.globalCoords[1] = 0;
|
|
||||||
// selectedOmni.globalCoords[2] = 0;
|
|
||||||
// selectedOmni.cameraMatrix.transformVectors(selectedOmni.globalCoords, selectedOmni.globalCoords); */
|
|
||||||
// Записываем параметры омника в константы
|
|
||||||
|
|
||||||
debugObject.x = currentOmni._x;
|
|
||||||
debugObject.y = currentOmni._y;
|
|
||||||
debugObject.z = currentOmni._z;
|
|
||||||
|
|
||||||
cleanContext(context);
|
|
||||||
for (i = 0; i < 6; i++) {
|
|
||||||
surface = 1 << i;
|
|
||||||
context.setRenderToTexture(shadowMap, true, 0, i);
|
|
||||||
// trace("SIDE:", i);
|
|
||||||
if (renderToOmniShadowMap(currentOmni, cameras[i])) {
|
|
||||||
drawed++;
|
|
||||||
clearBits |= surface;
|
|
||||||
} else {
|
|
||||||
if (clearBits & surface) {
|
|
||||||
// trace("clear", i);
|
|
||||||
context.clear(1, 1, 1, 1);
|
|
||||||
// context.clear(1, 1, 1, 1);
|
|
||||||
clearBits &= ~surface;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// trace("NUMSIDES:", drawed);
|
|
||||||
debugMaterial.texture = shadowMap;
|
|
||||||
}
|
|
||||||
context.setRenderToBackBuffer();
|
|
||||||
cleanContext(context);
|
|
||||||
active = drawed > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function calcBrightness(color:uint):Number {
|
|
||||||
var r:uint = color & 0xFF;
|
|
||||||
var g:uint = (color >> 8) & 0xFF;
|
|
||||||
var b:uint = (color >> 16) & 0xFF;
|
|
||||||
var result:uint = (r > g) ? ((r > b) ? r : b) : ((g > b) ? g : b);
|
|
||||||
return result/255;
|
|
||||||
}
|
|
||||||
|
|
||||||
// private var axises:Vector.<Number> = Vector.<Number>([
|
|
||||||
// 1, 0, 0,
|
|
||||||
// 0, 1, 0,
|
|
||||||
// ]);
|
|
||||||
// private var globalAxises:Vector.<Number> = new Vector.<Number>(6);
|
|
||||||
|
|
||||||
public function renderToOmniShadowMap(omni:OmniLight, camera:Camera3D):Boolean {
|
|
||||||
camera.nearClipping = 1;
|
|
||||||
camera.farClipping = omni.attenuationEnd;
|
|
||||||
// Расчёт параметров проецирования
|
|
||||||
camera.calculateProjection(camera.view._width, camera.view._height);
|
|
||||||
|
|
||||||
if (camera.transformChanged) camera.composeTransforms();
|
|
||||||
// Считаем омник родительским объектом камеры
|
|
||||||
camera.localToGlobalTransform.combine(omni.localToGlobalTransform, camera.transform);
|
|
||||||
camera.globalToLocalTransform.copy(camera.localToGlobalTransform);
|
|
||||||
camera.globalToLocalTransform.invert();
|
|
||||||
|
|
||||||
caster.localToCameraTransform.compose(caster._x, caster._y, caster._z, caster._rotationX, caster._rotationY, caster._rotationZ, caster._scaleX, caster._scaleY, caster._scaleZ);
|
|
||||||
var root:Object3D = caster;
|
|
||||||
while (root._parent != null) {
|
|
||||||
root = root._parent;
|
|
||||||
if (root.transformChanged) root.composeTransforms();
|
|
||||||
caster.localToCameraTransform.append(root.transform);
|
|
||||||
}
|
|
||||||
caster.localToCameraTransform.append(camera.globalToLocalTransform);
|
|
||||||
|
|
||||||
/** if (pcfOffset > 0.1) {
|
|
||||||
// axises[0] = pcfOffset;
|
|
||||||
// // Считаем преобразования PCF
|
|
||||||
// camera.globalMatrix.transformVectors(axises, globalAxises);
|
|
||||||
// pcfOffsets[0] = -pcfOffset*globalAxises[0];
|
|
||||||
// pcfOffsets[1] = -pcfOffset*globalAxises[1];
|
|
||||||
// pcfOffsets[2] = -pcfOffset*globalAxises[2];
|
|
||||||
// pcfOffsets[4] = pcfOffset*globalAxises[0];
|
|
||||||
// pcfOffsets[5] = pcfOffset*globalAxises[1];
|
|
||||||
// pcfOffsets[6] = pcfOffset*globalAxises[2];
|
|
||||||
// pcfOffsets[8] = -pcfOffset*globalAxises[3];
|
|
||||||
// pcfOffsets[9] = -pcfOffset*globalAxises[4];
|
|
||||||
// pcfOffsets[10] = -pcfOffset*globalAxises[5];
|
|
||||||
// pcfOffsets[12] = pcfOffset*globalAxises[3];
|
|
||||||
// pcfOffsets[13] = pcfOffset*globalAxises[4];
|
|
||||||
// pcfOffsets[14] = pcfOffset*globalAxises[5];
|
|
||||||
} */
|
|
||||||
|
|
||||||
// Отрисовка в шедоумапу
|
|
||||||
if (cullingInCamera(caster, casterBounds)) {
|
|
||||||
context.clear(1, 1, 0, 1);
|
|
||||||
drawObjectToShadowMap(context, caster, camera);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static const points:Vector.<Vector3D> = Vector.<Vector3D>([
|
|
||||||
new Vector3D(), new Vector3D(), new Vector3D(), new Vector3D(),
|
|
||||||
new Vector3D(), new Vector3D(), new Vector3D(), new Vector3D(),
|
|
||||||
new Vector3D(), new Vector3D(), new Vector3D(), new Vector3D(),
|
|
||||||
new Vector3D(), new Vector3D(), new Vector3D(), new Vector3D()
|
|
||||||
]);
|
|
||||||
private static const boundVertices:Vector.<Number> = new Vector.<Number>(24);
|
|
||||||
alternativa3d function cullingInCamera(object:Object3D, objectBounds:BoundBox):Boolean {
|
|
||||||
var i:int;
|
|
||||||
var infront:Boolean;
|
|
||||||
var behind:Boolean;
|
|
||||||
// Заполнение
|
|
||||||
var point:Vector3D;
|
|
||||||
var bb:BoundBox = objectBounds;
|
|
||||||
point = points[0];
|
|
||||||
point.x = bb.minX;
|
|
||||||
point.y = bb.minY;
|
|
||||||
point.z = bb.minZ;
|
|
||||||
point = points[1];
|
|
||||||
point.x = bb.minX;
|
|
||||||
point.y = bb.minY;
|
|
||||||
point.z = bb.maxZ;
|
|
||||||
point = points[2];
|
|
||||||
point.x = bb.minX;
|
|
||||||
point.y = bb.maxY;
|
|
||||||
point.z = bb.minZ;
|
|
||||||
point = points[3];
|
|
||||||
point.x = bb.minX;
|
|
||||||
point.y = bb.maxY;
|
|
||||||
point.z = bb.maxZ;
|
|
||||||
point = points[4];
|
|
||||||
point.x = bb.maxX;
|
|
||||||
point.y = bb.minY;
|
|
||||||
point.z = bb.minZ;
|
|
||||||
point = points[5];
|
|
||||||
point.x = bb.maxX;
|
|
||||||
point.y = bb.minY;
|
|
||||||
point.z = bb.maxZ;
|
|
||||||
point = points[6];
|
|
||||||
point.x = bb.maxX;
|
|
||||||
point.y = bb.maxY;
|
|
||||||
point.z = bb.minZ;
|
|
||||||
point = points[7];
|
|
||||||
point.x = bb.maxX;
|
|
||||||
point.y = bb.maxY;
|
|
||||||
point.z = bb.maxZ;
|
|
||||||
// Коррекция под 90 градусов
|
|
||||||
var transform:Transform3D = object.localToCameraTransform;
|
|
||||||
for (i = 0; i < 8; i++) {
|
|
||||||
point = points[i];
|
|
||||||
var x:Number = transform.a*point.x + transform.b*point.y + transform.c*point.z + transform.d;
|
|
||||||
var y:Number = transform.e*point.x + transform.f*point.y + transform.g*point.z + transform.h;
|
|
||||||
var z:Number = transform.i*point.x + transform.j*point.y + transform.k*point.z + transform.l;
|
|
||||||
var index:int = 3*i;
|
|
||||||
boundVertices[int(index++)] = x;
|
|
||||||
boundVertices[int(index++)] = y;
|
|
||||||
boundVertices[index] = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Куллинг
|
|
||||||
for (i = 0, infront = false, behind = false; i <= 21; i += 3) {
|
|
||||||
if (-boundVertices[i] < boundVertices[int(i + 2)]) {
|
|
||||||
infront = true;
|
|
||||||
if (behind) break;
|
|
||||||
} else {
|
|
||||||
behind = true;
|
|
||||||
if (infront) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (behind) {
|
|
||||||
// trace("L", infront);
|
|
||||||
if (!infront) return false;
|
|
||||||
}
|
|
||||||
for (i = 0, infront = false, behind = false; i <= 21; i += 3) {
|
|
||||||
if (boundVertices[i] < boundVertices[int(i + 2)]) {
|
|
||||||
infront = true;
|
|
||||||
if (behind) break;
|
|
||||||
} else {
|
|
||||||
behind = true;
|
|
||||||
if (infront) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (behind) {
|
|
||||||
// trace("R", infront);
|
|
||||||
if (!infront) return false;
|
|
||||||
}
|
|
||||||
for (i = 1, infront = false, behind = false; i <= 22; i += 3) {
|
|
||||||
if (-boundVertices[i] < boundVertices[int(i + 1)]) {
|
|
||||||
infront = true;
|
|
||||||
if (behind) break;
|
|
||||||
} else {
|
|
||||||
behind = true;
|
|
||||||
if (infront) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (behind) {
|
|
||||||
// trace("U", infront);
|
|
||||||
if (!infront) return false;
|
|
||||||
}
|
|
||||||
for (i = 1, infront = false, behind = false; i <= 22; i += 3) {
|
|
||||||
if (boundVertices[i] < boundVertices[int(i + 1)]) {
|
|
||||||
infront = true;
|
|
||||||
if (behind) break;
|
|
||||||
} else {
|
|
||||||
behind = true;
|
|
||||||
if (infront) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (behind) {
|
|
||||||
// trace("D", infront);
|
|
||||||
if (!infront) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
alternativa3d static function drawObjectToShadowMap(context:Context3D, object:Object3D, camera:Camera3D):void {
|
|
||||||
if (object is Mesh) {
|
|
||||||
drawMeshToShadowMap(context, Mesh(object), camera);
|
|
||||||
}
|
|
||||||
for (var child:Object3D = object.childrenList; child != null; child = child.next) {
|
|
||||||
if (child.visible) {
|
|
||||||
if (child.transformChanged) child.composeTransforms();
|
|
||||||
child.localToCameraTransform.combine(object.localToCameraTransform, child.transform);
|
|
||||||
drawObjectToShadowMap(context, child, camera);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function copyRawFromTransform(raw:Vector.<Number>, transform:Transform3D):void {
|
|
||||||
raw[0] = transform.a;
|
|
||||||
raw[1] = transform.b;
|
|
||||||
raw[2] = transform.c;
|
|
||||||
raw[3] = transform.d;
|
|
||||||
raw[4] = transform.e;
|
|
||||||
raw[5] = transform.f;
|
|
||||||
raw[6] = transform.g;
|
|
||||||
raw[7] = transform.h;
|
|
||||||
raw[8] = transform.i;
|
|
||||||
raw[9] = transform.j;
|
|
||||||
raw[10] = transform.k;
|
|
||||||
raw[11] = transform.l;
|
|
||||||
raw[12] = 0;
|
|
||||||
raw[13] = 0;
|
|
||||||
raw[14] = 0;
|
|
||||||
raw[15] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static var shadowMapProgram:Program3D;
|
|
||||||
private static var projectionVector:Vector.<Number> = new Vector.<Number>(16);
|
|
||||||
private static function drawMeshToShadowMap(context:Context3D, mesh:Mesh, camera:Camera3D):void {
|
|
||||||
if (mesh.geometry == null || mesh.geometry.numTriangles == 0 || !mesh.geometry.isUploaded) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO : update to new logic
|
|
||||||
if (shadowMapProgram == null) shadowMapProgram = initMeshToShadowMapProgram(context);
|
|
||||||
context.setProgram(shadowMapProgram);
|
|
||||||
|
|
||||||
context.setVertexBufferAt(0, mesh.geometry.getVertexBuffer(VertexAttributes.POSITION), mesh.geometry._attributesOffsets[VertexAttributes.POSITION], VertexAttributes.FORMATS[VertexAttributes.POSITION]);
|
|
||||||
|
|
||||||
// TODO: uncomment
|
|
||||||
// camera.composeProjectionMatrix(projectionVector, 0, mesh.localToCameraTransform);
|
|
||||||
|
|
||||||
context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 0, projectionVector, 4);
|
|
||||||
|
|
||||||
copyRawFromTransform(projectionVector, mesh.localToCameraTransform);
|
|
||||||
|
|
||||||
context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 4, projectionVector, 4);
|
|
||||||
|
|
||||||
context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 8, Vector.<Number>([Math.sqrt(255)/camera.farClipping, 0, 0, 1]));
|
|
||||||
context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, Vector.<Number>([1/255, 0, 0, 1]));
|
|
||||||
|
|
||||||
context.setCulling(Context3DTriangleFace.BACK);
|
|
||||||
for (var i:int = 0; i < mesh._surfacesLength; i++) {
|
|
||||||
var surface:Surface = mesh._surfaces[i];
|
|
||||||
if (surface.material == null) continue;
|
|
||||||
context.drawTriangles(mesh.geometry._indexBuffer, surface.indexBegin, surface.numTriangles);
|
|
||||||
}
|
|
||||||
context.setVertexBufferAt(0, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function initMeshToShadowMapProgram(context3d:Context3D):Program3D {
|
|
||||||
var vLinker:Linker = new Linker(Context3DProgramType.VERTEX);
|
|
||||||
var fLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
|
|
||||||
var proc:Procedure = Procedure.compileFromArray([
|
|
||||||
"#a0=a0",
|
|
||||||
"#c8=c8",
|
|
||||||
"#v0=v0",
|
|
||||||
"m44 o0, a0, c0",
|
|
||||||
"m44 t0, a0, c4",
|
|
||||||
"mul t0, t0, c8.x",
|
|
||||||
"mov v0, t0"
|
|
||||||
]);
|
|
||||||
proc.assignVariableName(VariableType.CONSTANT, 0, "c0", 4);
|
|
||||||
proc.assignVariableName(VariableType.CONSTANT, 4, "c4", 4);
|
|
||||||
vLinker.addProcedure(proc);
|
|
||||||
|
|
||||||
fLinker.addProcedure(Procedure.compileFromArray([
|
|
||||||
"#v0=v0",
|
|
||||||
"#c0=c0",
|
|
||||||
"mov t0.zw, c0.z \n",
|
|
||||||
"dp3 t1.w, v0.xyz, v0.xyz \n",
|
|
||||||
"frc t0.y, t1.w",
|
|
||||||
"sub t0.x, t1.w, t0.y",
|
|
||||||
"mul t0.x, t0.x, c0.x",
|
|
||||||
"mov o0, to"
|
|
||||||
]));
|
|
||||||
var program:Program3D = context3d.createProgram();
|
|
||||||
// trace("VERTEX");
|
|
||||||
// trace(A3DUtils.disassemble(vLinker.getByteCode()));
|
|
||||||
// trace("FRAGMENT");
|
|
||||||
// trace(A3DUtils.disassemble(fLinker.getByteCode()));
|
|
||||||
fLinker.varyings = vLinker.varyings;
|
|
||||||
vLinker.link();
|
|
||||||
fLinker.link();
|
|
||||||
program.upload(vLinker.data, fLinker.data);
|
|
||||||
return program;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function initVShader():Procedure {
|
|
||||||
var shader:Procedure = Procedure.compileFromArray([
|
|
||||||
// Координата вершины в глобальном пространстве
|
|
||||||
"m44 v0, a0, c0"
|
|
||||||
]);
|
|
||||||
shader.assignVariableName(VariableType.ATTRIBUTE, 0, "aPosition");
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 0, "cGLOBALMATRIX", 4);
|
|
||||||
shader.assignVariableName(VariableType.VARYING, 0, "vPOSITION");
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function initFShader(mult:Boolean, usePCF:Boolean):Procedure {
|
|
||||||
var line:int = 0;
|
|
||||||
var shaderArr:Array = [];
|
|
||||||
var numPass:uint = (usePCF) ? 8 : 1;
|
|
||||||
for (var i:int = 0; i < numPass; i++) {
|
|
||||||
// Вектор от источника света к точке
|
|
||||||
shaderArr[line++] = "sub t0.xyz, v0.xyz, c4.xyz";
|
|
||||||
|
|
||||||
// Квадрат расстояния
|
|
||||||
shaderArr[line++] = "dp3 t0.w, t0.xyz, t0.xyz";
|
|
||||||
shaderArr[line++] = "mul t0.w, t0.w, c4.w"; // * (255 / radius^2)
|
|
||||||
shaderArr[line++] = "mul t0.w, t0.w, c5.y"; // bias [0.95]
|
|
||||||
|
|
||||||
// Квадрат расстояния из карты теней
|
|
||||||
shaderArr[line++] = "nrm t0.xyz, t0.xyz";
|
|
||||||
|
|
||||||
if (usePCF) {
|
|
||||||
shaderArr[line++] = "add t0.xyz, t0.xyz, c" + (i + 6).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
shaderArr[line++] = "tex t1, t0, s0 <cube,clamp,near,nomip>";
|
|
||||||
shaderArr[line++] = "mov t3, t1";
|
|
||||||
shaderArr[line++] = "mul t1.w, t1.x, c5.x"; // 255
|
|
||||||
shaderArr[line++] = "add t1.w, t1.w, t1.y";
|
|
||||||
|
|
||||||
// Перекрытие тенью
|
|
||||||
shaderArr[line++] = "sub t2.z, t1.w, t0.w";
|
|
||||||
shaderArr[line++] = "mul t2.z, t2.z, c5.z"; // smooth [10000]
|
|
||||||
shaderArr[line++] = "sat t2.z, t2.z";
|
|
||||||
|
|
||||||
// // Затухание тени по расстоянию
|
|
||||||
shaderArr[line++] = "mul t1.x, t0.w, c5.w"; // div 255
|
|
||||||
shaderArr[line++] = "add t2.z, t2.z, t1.x";
|
|
||||||
if (i == 0) {
|
|
||||||
shaderArr[line++] = "sat t2.x, t2.z";
|
|
||||||
} else {
|
|
||||||
shaderArr[line++] = "sat t2.z, t2.z";
|
|
||||||
shaderArr[line++] = "add t2.x, t2.x, t2.z";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (usePCF) {
|
|
||||||
shaderArr[line++] = "mul t2.x, t2.x, c6.w";
|
|
||||||
}
|
|
||||||
if (mult) {
|
|
||||||
shaderArr.push("mul t0.xyz, i0.xyz, t2.x");
|
|
||||||
// shaderArr.push("mul t0.xyz, t1.w, c5.w");
|
|
||||||
shaderArr.push("mov t0.w, i0.w");
|
|
||||||
shaderArr.push("mov o0, t0");
|
|
||||||
} else {
|
|
||||||
shaderArr.push("mov o0, t2.xxxx");
|
|
||||||
}
|
|
||||||
var shader:Procedure = Procedure.compileFromArray(shaderArr, "OmniShadowMap");
|
|
||||||
shader.assignVariableName(VariableType.VARYING, 0, "vPOSITION");
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 4, "cOmni", 1);
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 5, "cConstants", 1);
|
|
||||||
if (usePCF) {
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 6, "cPCF0", 1);
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 7, "cPCF1", 1);
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 8, "cPCF2", 1);
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 9, "cPCF3", 1);
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 10, "cPCF4", 1);
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 11, "cPCF5", 1);
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 12, "cPCF6", 1);
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 13, "cPCF7", 1);
|
|
||||||
}
|
|
||||||
shader.assignVariableName(VariableType.SAMPLER, 0, "sCUBE");
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
override public function getVShader(index:int = 0):Procedure {
|
|
||||||
return initVShader();
|
|
||||||
}
|
|
||||||
|
|
||||||
override public function getFShader(index:int = 0):Procedure {
|
|
||||||
return initFShader(false, pcfOffset > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static const globalMatrix:Transform3D = new Transform3D();
|
|
||||||
override public function applyShader(drawUnit:DrawUnit, program:ShaderProgram, object:Object3D, camera:Camera3D, index:int = 0):void {
|
|
||||||
var fLinker:Linker = program.fragmentShader;
|
|
||||||
|
|
||||||
globalMatrix.combine(camera.localToGlobalTransform, object.localToCameraTransform);
|
|
||||||
|
|
||||||
var mIndex:int = program.vertexShader.getVariableIndex("cGLOBALMATRIX");
|
|
||||||
drawUnit.setVertexConstantsFromNumbers(mIndex, globalMatrix.a, globalMatrix.b, globalMatrix.c, globalMatrix.d);
|
|
||||||
drawUnit.setVertexConstantsFromNumbers(mIndex+1, globalMatrix.e, globalMatrix.f, globalMatrix.g, globalMatrix.h);
|
|
||||||
drawUnit.setVertexConstantsFromNumbers(mIndex+2, globalMatrix.i, globalMatrix.j, globalMatrix.k, globalMatrix.l);
|
|
||||||
drawUnit.setVertexConstantsFromNumbers(mIndex+3, 0, 0, 0, 1);
|
|
||||||
|
|
||||||
// destination.addFragmentConstantSet(fLinker.getVariableIndex("cOmni"), omniPos, 1);
|
|
||||||
drawUnit.setFragmentConstantsFromNumbers(fLinker.getVariableIndex("cOmni"), currentOmni._x, currentOmni._y, currentOmni._z, 255/currentOmni.attenuationEnd/currentOmni.attenuationEnd);
|
|
||||||
drawUnit.setFragmentConstantsFromVector(fLinker.getVariableIndex("cConstants"), constants, 1);
|
|
||||||
if (pcfOffset > 0) {
|
|
||||||
drawUnit.setVertexConstantsFromVector(fLinker.getVariableIndex("cPCF0"), pcfOffsets, 8);
|
|
||||||
}
|
|
||||||
drawUnit.setTextureAt(fLinker.getVariableIndex("sCUBE"), shadowMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
// private static var program:LinkedProgram;
|
|
||||||
// private static var programPCF:LinkedProgram;
|
|
||||||
// private static function initMeshProgram(context:Context3D, usePCF:Boolean):LinkedProgram {
|
|
||||||
// var vLinker:Linker = new Linker(Context3DProgramType.VERTEX);
|
|
||||||
// vLinker.addShader(vShader);
|
|
||||||
//
|
|
||||||
// var fLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
|
|
||||||
// if (usePCF) {
|
|
||||||
// fLinker.addShader(pcfFShader);
|
|
||||||
// } else {
|
|
||||||
// fLinker.addShader(fShader);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// vLinker.setOppositeLinker(fLinker);
|
|
||||||
// fLinker.setOppositeLinker(vLinker);
|
|
||||||
//
|
|
||||||
// trace("[VERTEX]");
|
|
||||||
// trace(AgalUtils.disassemble(vLinker.getByteCode()));
|
|
||||||
// trace("[FRAGMENT]");
|
|
||||||
// trace(AgalUtils.disassemble(fLinker.getByteCode()));
|
|
||||||
//
|
|
||||||
// var result:LinkedProgram;
|
|
||||||
// if (usePCF) {
|
|
||||||
// programPCF = new LinkedProgram();
|
|
||||||
// result = programPCF;
|
|
||||||
// } else {
|
|
||||||
// program = new LinkedProgram();
|
|
||||||
// result = program;
|
|
||||||
// }
|
|
||||||
// result.vLinker = vLinker;
|
|
||||||
// result.fLinker = fLinker;
|
|
||||||
// result.program = context.createProgram();
|
|
||||||
// result.program.upload(vLinker.getByteCode(), fLinker.getByteCode());
|
|
||||||
//
|
|
||||||
// return result;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override public function drawShadow(mesh:Mesh, camera:Camera3D, texture:Texture):void {
|
|
||||||
// var context3d:Context3D = camera.view._context3d;
|
|
||||||
//
|
|
||||||
// var linkedProgram:LinkedProgram;
|
|
||||||
// if (pcfOffset > 0) {
|
|
||||||
// linkedProgram = (programPCF == null) ? initMeshProgram(context3d, true) : programPCF;
|
|
||||||
// } else {
|
|
||||||
// linkedProgram = (program == null) ? initMeshProgram(context3d, false) : program;
|
|
||||||
// }
|
|
||||||
// var vLinker:Linker = linkedProgram.vLinker;
|
|
||||||
// var fLinker:Linker = linkedProgram.fLinker;
|
|
||||||
// context3d.setProgram(linkedProgram.program);
|
|
||||||
//
|
|
||||||
// context3d.setVertexBufferAt(vLinker.getVariableIndex("aPOSITION"), mesh.geometry.vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
|
|
||||||
// context3d.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, vLinker.getVariableIndex("cPROJ"), mesh.projectionMatrix, true);
|
|
||||||
// applyShader(context3d, linkedProgram, mesh, camera);
|
|
||||||
// context3d.setVertexBufferAt(1, null);
|
|
||||||
//
|
|
||||||
// context3d.setCulling(Context3DTriangleFace.FRONT);
|
|
||||||
// context3d.drawTriangles(mesh.geometry.indexBuffer, 0, mesh.geometry.numTriangles);
|
|
||||||
//
|
|
||||||
// context3d.setVertexBufferAt(vLinker.getVariableIndex("aPOSITION"), null);
|
|
||||||
// context.setTextureAt(getTextureIndex(fLinker), texture);
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
package alternativa.engine3d.shadows {
|
|
||||||
|
|
||||||
import alternativa.engine3d.alternativa3d;
|
|
||||||
import alternativa.engine3d.core.Camera3D;
|
|
||||||
import alternativa.engine3d.core.Light3D;
|
|
||||||
import alternativa.engine3d.core.Object3D;
|
|
||||||
import alternativa.engine3d.materials.*;
|
|
||||||
import alternativa.engine3d.materials.compiler.Linker;
|
|
||||||
import alternativa.engine3d.materials.compiler.Procedure;
|
|
||||||
import alternativa.engine3d.materials.compiler.VariableType;
|
|
||||||
import alternativa.engine3d.objects.Surface;
|
|
||||||
import alternativa.engine3d.resources.Geometry;
|
|
||||||
|
|
||||||
import flash.display3D.Context3DProgramType;
|
|
||||||
import flash.display3D.textures.CubeTexture;
|
|
||||||
import flash.utils.Dictionary;
|
|
||||||
|
|
||||||
use namespace alternativa3d;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
public class OmniShadowRendererDebugMaterial extends Material {
|
|
||||||
|
|
||||||
alternativa3d override function get canDrawInShadowMap():Boolean {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static alternativa3d const _samplerSetProcedure:Procedure = new Procedure(
|
|
||||||
[
|
|
||||||
"#v0=vUV",
|
|
||||||
"#s0=sTexture",
|
|
||||||
"#c0=cAlpha",
|
|
||||||
"tex t0, v0, s0 <cube,clamp,near,nomip>",
|
|
||||||
"mov t0.w, c0.w",
|
|
||||||
"mov o0, t0"
|
|
||||||
]);
|
|
||||||
|
|
||||||
static alternativa3d const _samplerSetProcedureDiffuseAlpha:Procedure = new Procedure(
|
|
||||||
[
|
|
||||||
"#v0=vUV",
|
|
||||||
"#s0=sTexture",
|
|
||||||
"#c0=cAlpha",
|
|
||||||
"tex t0, v0, s0 <cube,clamp,near,nomip>",
|
|
||||||
"mul t0.w, t0.w, c0.w",
|
|
||||||
"mov o0, t0"
|
|
||||||
]);
|
|
||||||
|
|
||||||
static alternativa3d const _passUVProcedure:Procedure = new Procedure(["#v0=vUV", "#a0=aNORMAL", "mov v0, a0"]);
|
|
||||||
private static var _programs:Dictionary = new Dictionary();
|
|
||||||
/**
|
|
||||||
* Текстура
|
|
||||||
*/
|
|
||||||
public var texture:CubeTexture;
|
|
||||||
/**
|
|
||||||
* Прозрачность
|
|
||||||
*/
|
|
||||||
public var alpha:Number = 1;
|
|
||||||
/**
|
|
||||||
* Использование alpha канала текстуры
|
|
||||||
*/
|
|
||||||
public var useDiffuseAlphaChannel:Boolean = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Создает экземпляр материала
|
|
||||||
* @param texture текстура
|
|
||||||
* @param alpha прозрачность
|
|
||||||
*/
|
|
||||||
public function OmniShadowRendererDebugMaterial(texture:CubeTexture = null, alpha:Number = 1) {
|
|
||||||
this.texture = texture;
|
|
||||||
this.alpha = alpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function setupProgram(targetObject:Object3D):Vector.<ShaderProgram> {
|
|
||||||
var optionsPrograms:Vector.<ShaderProgram> = new Vector.<ShaderProgram>();
|
|
||||||
|
|
||||||
var vertexLinker:Linker = new Linker(Context3DProgramType.VERTEX);
|
|
||||||
var positionVar:String = "aPosition";
|
|
||||||
vertexLinker.declareVariable(positionVar, VariableType.ATTRIBUTE);
|
|
||||||
if (targetObject.transformProcedure != null) {
|
|
||||||
positionVar = appendPositionTransformProcedure(targetObject.transformProcedure, vertexLinker);
|
|
||||||
}
|
|
||||||
vertexLinker.addProcedure(_projectProcedure);
|
|
||||||
vertexLinker.setInputParams(_projectProcedure, positionVar);
|
|
||||||
vertexLinker.addProcedure(_passUVProcedure);
|
|
||||||
vertexLinker.link();
|
|
||||||
|
|
||||||
var fragmentLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
|
|
||||||
fragmentLinker.addProcedure(_samplerSetProcedure);
|
|
||||||
fragmentLinker.varyings = vertexLinker.varyings;
|
|
||||||
optionsPrograms[optionsPrograms.length] = new ShaderProgram(vertexLinker, fragmentLinker);
|
|
||||||
|
|
||||||
var fragmentLinkerDiffuseAlpha:Linker = new Linker(Context3DProgramType.FRAGMENT);
|
|
||||||
fragmentLinkerDiffuseAlpha.addProcedure(_samplerSetProcedureDiffuseAlpha);
|
|
||||||
fragmentLinkerDiffuseAlpha.varyings = vertexLinker.varyings;
|
|
||||||
optionsPrograms[optionsPrograms.length] = new ShaderProgram(vertexLinker, fragmentLinkerDiffuseAlpha);
|
|
||||||
|
|
||||||
// trace(A3DUtils.disassemble(fragmentLinker.getByteCode()));
|
|
||||||
|
|
||||||
_programs[targetObject.transformProcedure] = optionsPrograms;
|
|
||||||
return optionsPrograms;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
override alternativa3d function collectDraws(camera:Camera3D, surface:Surface, geometry:Geometry, lights:Vector.<Light3D>, lightsLength:int, objectRenderPriority:int = -1):void {
|
|
||||||
// TODO: repair
|
|
||||||
/*
|
|
||||||
destination.isValid = destination.isValid && texture != null;
|
|
||||||
|
|
||||||
var optionsPrograms:Vector.<ShaderProgram> = _programs[transformHolder.transformProcedure];
|
|
||||||
if(!optionsPrograms) optionsPrograms = setupProgram(transformHolder);
|
|
||||||
var program:ShaderProgram;
|
|
||||||
if(!useDiffuseAlphaChannel){
|
|
||||||
program = optionsPrograms[0];
|
|
||||||
}else {
|
|
||||||
program = optionsPrograms[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!destination.isValid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alpha < 1 || useDiffuseAlphaChannel) {
|
|
||||||
destination.blendModeSource = Context3DBlendFactor.SOURCE_ALPHA;
|
|
||||||
destination.blendModeDestination = Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA;
|
|
||||||
destination.renderPriority = Renderer.TRANSPARENT_SORT;
|
|
||||||
} else {
|
|
||||||
destination.blendModeSource = Context3DBlendFactor.ONE;
|
|
||||||
destination.blendModeDestination = Context3DBlendFactor.ZERO;
|
|
||||||
destination.renderPriority = Renderer.OPAQUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
destination.program = program;
|
|
||||||
geometry.setAttribute(destination, VertexAttributes.POSITION, program.vertexShader.getVariableIndex("aPosition"));
|
|
||||||
geometry.setAttribute(destination, VertexAttributes.NORMAL, program.vertexShader.getVariableIndex("aNORMAL"));
|
|
||||||
camera.composeProjectionMatrix(destination.constantSetVertexVectorValues, program.vertexShader.getVariableIndex("cProjMatrix") << 2, transformHolder.localToCameraTransform);
|
|
||||||
destination.constantSetVertexRegistersCount = destination.constantSetVertexVectorValues.length >> 2;
|
|
||||||
destination.addTextureSet(program.fragmentShader.getVariableIndex("sTexture"), texture);
|
|
||||||
destination.addFragmentConstantVector(program.fragmentShader.getVariableIndex("cAlpha"), 0, 0, 0, alpha);
|
|
||||||
destination.cullingMode = cullingMode;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
override public function clone():Material {
|
|
||||||
var res:OmniShadowRendererDebugMaterial = new OmniShadowRendererDebugMaterial(texture, alpha);
|
|
||||||
res.clonePropertiesFrom(this);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
override protected function clonePropertiesFrom(source:Material):void {
|
|
||||||
super.clonePropertiesFrom(source);
|
|
||||||
var t:OmniShadowRendererDebugMaterial = OmniShadowRendererDebugMaterial(source);
|
|
||||||
texture = t.texture;
|
|
||||||
alpha = t.alpha;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
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.materials.ShaderProgram;
|
|
||||||
import alternativa.engine3d.materials.compiler.Procedure;
|
|
||||||
|
|
||||||
import flash.display3D.Context3D;
|
|
||||||
import flash.display3D.Context3DBlendFactor;
|
|
||||||
import flash.display3D.Context3DCompareMode;
|
|
||||||
import flash.geom.Matrix3D;
|
|
||||||
|
|
||||||
use namespace alternativa3d;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
public class ShadowRenderer {
|
|
||||||
|
|
||||||
alternativa3d var shaderKey:String;
|
|
||||||
private static var counter:int = 0;
|
|
||||||
|
|
||||||
public var active:Boolean = false;
|
|
||||||
|
|
||||||
public function ShadowRenderer() {
|
|
||||||
counter++;
|
|
||||||
shaderKey = "M" + counter.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
alternativa3d function get needMultiplyBlend():Boolean {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function update():void {}
|
|
||||||
|
|
||||||
// Нет входных, выходных параметров
|
|
||||||
public function getVShader(index:int = 0):Procedure {return null}
|
|
||||||
public function getFShader(index:int = 0):Procedure {return null}
|
|
||||||
|
|
||||||
public function getFIntensityShader():Procedure { throw new Error("Not implemented") };
|
|
||||||
|
|
||||||
// public function getMultVShader():Procedure {return null};
|
|
||||||
// // i0 - input color
|
|
||||||
// // o0 - shadowed result
|
|
||||||
// public function getMultFShader():Procedure {return null};
|
|
||||||
|
|
||||||
public function applyShader(destination:DrawUnit, program:ShaderProgram, object:Object3D, camera:Camera3D, index:int = 0):void {}
|
|
||||||
// public function drawShadow(mesh:Mesh, camera:Camera3D, texture:Texture):void {}
|
|
||||||
|
|
||||||
// public function getTextureIndex(fLinker:Linker):int {return 0};
|
|
||||||
|
|
||||||
public function get debug():Boolean { return false }
|
|
||||||
public function set debug(value:Boolean):void { }
|
|
||||||
|
|
||||||
alternativa3d function cullReciever(boundBox:BoundBox, object:Object3D):Boolean {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function cleanContext(context:Context3D):void {
|
|
||||||
context.setTextureAt(0, null);
|
|
||||||
context.setTextureAt(1, null);
|
|
||||||
context.setTextureAt(2, null);
|
|
||||||
context.setTextureAt(3, null);
|
|
||||||
context.setTextureAt(4, null);
|
|
||||||
context.setTextureAt(5, null);
|
|
||||||
context.setTextureAt(6, null);
|
|
||||||
context.setTextureAt(7, null);
|
|
||||||
context.setVertexBufferAt(1, null);
|
|
||||||
context.setVertexBufferAt(2, null);
|
|
||||||
context.setVertexBufferAt(3, null);
|
|
||||||
context.setVertexBufferAt(4, null);
|
|
||||||
context.setVertexBufferAt(5, null);
|
|
||||||
context.setVertexBufferAt(6, null);
|
|
||||||
context.setVertexBufferAt(7, null);
|
|
||||||
context.setDepthTest(true, Context3DCompareMode.LESS);
|
|
||||||
context.setBlendFactors(Context3DBlendFactor.ONE, Context3DBlendFactor.ZERO);
|
|
||||||
}
|
|
||||||
|
|
||||||
static private const boundVertices:Vector.<Number> = new Vector.<Number>(24);
|
|
||||||
alternativa3d function cullObjectImplementation(bounds:BoundBox, matrix:Matrix3D):Boolean {
|
|
||||||
var i:int;
|
|
||||||
var infront:Boolean;
|
|
||||||
var behind:Boolean;
|
|
||||||
// Заполнение
|
|
||||||
boundVertices[0] = bounds.minX;
|
|
||||||
boundVertices[1] = bounds.minY;
|
|
||||||
boundVertices[2] = bounds.minZ;
|
|
||||||
boundVertices[3] = bounds.maxX;
|
|
||||||
boundVertices[4] = bounds.minY;
|
|
||||||
boundVertices[5] = bounds.minZ;
|
|
||||||
boundVertices[6] = bounds.minX;
|
|
||||||
boundVertices[7] = bounds.maxY;
|
|
||||||
boundVertices[8] = bounds.minZ;
|
|
||||||
boundVertices[9] = bounds.maxX;
|
|
||||||
boundVertices[10] = bounds.maxY;
|
|
||||||
boundVertices[11] = bounds.minZ;
|
|
||||||
boundVertices[12] = bounds.minX;
|
|
||||||
boundVertices[13] = bounds.minY;
|
|
||||||
boundVertices[14] = bounds.maxZ;
|
|
||||||
boundVertices[15] = bounds.maxX;
|
|
||||||
boundVertices[16] = bounds.minY;
|
|
||||||
boundVertices[17] = bounds.maxZ;
|
|
||||||
boundVertices[18] = bounds.minX;
|
|
||||||
boundVertices[19] = bounds.maxY;
|
|
||||||
boundVertices[20] = bounds.maxZ;
|
|
||||||
boundVertices[21] = bounds.maxX;
|
|
||||||
boundVertices[22] = bounds.maxY;
|
|
||||||
boundVertices[23] = bounds.maxZ;
|
|
||||||
|
|
||||||
// Трансформация в камеру
|
|
||||||
matrix.transformVectors(boundVertices, boundVertices);
|
|
||||||
// Куллинг
|
|
||||||
for (i = 2, infront = false, behind = false; i <= 23; i += 3) {
|
|
||||||
if (boundVertices[i] > 0) {
|
|
||||||
infront = true;
|
|
||||||
if (behind) break;
|
|
||||||
} else {
|
|
||||||
behind = true;
|
|
||||||
if (infront) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (behind) {
|
|
||||||
if (!infront) return false;
|
|
||||||
}
|
|
||||||
// left
|
|
||||||
for (i = 0, infront = false, behind = false; i <= 21; i += 3) {
|
|
||||||
if (boundVertices[i] > 0) {
|
|
||||||
infront = true;
|
|
||||||
if (behind) break;
|
|
||||||
} else {
|
|
||||||
behind = true;
|
|
||||||
if (infront) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (behind) {
|
|
||||||
if (!infront) return false;
|
|
||||||
}
|
|
||||||
// right
|
|
||||||
for (i = 0, infront = false, behind = false; i <= 21; i += 3) {
|
|
||||||
if (boundVertices[i] < 1) {
|
|
||||||
infront = true;
|
|
||||||
if (behind) break;
|
|
||||||
} else {
|
|
||||||
behind = true;
|
|
||||||
if (infront) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (behind) {
|
|
||||||
if (!infront) return false;
|
|
||||||
}
|
|
||||||
// up
|
|
||||||
for (i = 1, infront = false, behind = false; i <= 22; i += 3) {
|
|
||||||
if (boundVertices[i] > 0) {
|
|
||||||
infront = true;
|
|
||||||
if (behind) break;
|
|
||||||
} else {
|
|
||||||
behind = true;
|
|
||||||
if (infront) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (behind) {
|
|
||||||
if (!infront) return false;
|
|
||||||
}
|
|
||||||
// down
|
|
||||||
for (i = 1, infront = false, behind = false; i <= 22; i += 3) {
|
|
||||||
if (boundVertices[i] < 1) {
|
|
||||||
infront = true;
|
|
||||||
if (behind) break;
|
|
||||||
} else {
|
|
||||||
behind = true;
|
|
||||||
if (infront) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (behind) {
|
|
||||||
if (!infront) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
package alternativa.engine3d.shadows {
|
|
||||||
|
|
||||||
import alternativa.engine3d.alternativa3d;
|
|
||||||
import alternativa.engine3d.core.Object3D;
|
|
||||||
|
|
||||||
import flash.utils.Dictionary;
|
|
||||||
|
|
||||||
use namespace alternativa3d;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
public class ShadowsSystem {
|
|
||||||
|
|
||||||
private static const MAX_SHADOWMAPS:int = 3;
|
|
||||||
// private static const MAX_SHADOWMAPS:int = 4;
|
|
||||||
|
|
||||||
public var renderers:Vector.<ShadowRenderer> = new Vector.<ShadowRenderer>();
|
|
||||||
|
|
||||||
private var containers:Dictionary = new Dictionary();
|
|
||||||
|
|
||||||
public function ShadowsSystem() {
|
|
||||||
}
|
|
||||||
|
|
||||||
private var numShadowed:int;
|
|
||||||
|
|
||||||
private var numActiveRenderers:int;
|
|
||||||
private var activeRenderers:Vector.<ShadowRenderer> = new Vector.<ShadowRenderer>();
|
|
||||||
|
|
||||||
private var maxShadows:int;
|
|
||||||
|
|
||||||
public function update(root:Object3D):void {
|
|
||||||
if (renderers.length == 0) return;
|
|
||||||
numActiveRenderers = 0;
|
|
||||||
var num:int = renderers.length;
|
|
||||||
for (var i:int = 0; i < num; i++) {
|
|
||||||
var renderer:ShadowRenderer = renderers[i];
|
|
||||||
renderer.update();
|
|
||||||
if (renderer.active) {
|
|
||||||
activeRenderers[numActiveRenderers] = renderer;
|
|
||||||
numActiveRenderers++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Пробегаемся иерархически по объектам и проверяем наложение на них тени
|
|
||||||
if (root.transformChanged) root.composeTransforms();
|
|
||||||
root.localToGlobalTransform.copy(root.transform);
|
|
||||||
numShadowed = 0;
|
|
||||||
maxShadows = 0;
|
|
||||||
recursive(root);
|
|
||||||
// trace("SHADOWED:", numShadowed, ":", maxShadows);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function recursive(object:Object3D):void {
|
|
||||||
for (var child:Object3D = object.childrenList; child != null; child = child.next) {
|
|
||||||
var value:Vector.<ShadowRenderer> = null;
|
|
||||||
var numRenderers:int = 0;
|
|
||||||
if (child.visible) {
|
|
||||||
if (child.transformChanged) child.composeTransforms();
|
|
||||||
child.localToGlobalTransform.combine(object.localToGlobalTransform, child.transform);
|
|
||||||
for (var i:int = 0; i < numActiveRenderers; i++) {
|
|
||||||
var renderer:ShadowRenderer = activeRenderers[i];
|
|
||||||
if (child.useShadow) {
|
|
||||||
if (child.boundBox == null || renderer.cullReciever(child.boundBox, child)) {
|
|
||||||
numShadowed++;
|
|
||||||
if (value == null) {
|
|
||||||
value = containers[child];
|
|
||||||
if (value == null) {
|
|
||||||
value = new Vector.<ShadowRenderer>();
|
|
||||||
containers[child] = value;
|
|
||||||
} else {
|
|
||||||
value.length = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
value[numRenderers] = renderer;
|
|
||||||
numRenderers++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
recursive(child);
|
|
||||||
}
|
|
||||||
setRenderers(child, value, numRenderers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function setRenderers(object:Object3D, renderers:Vector.<ShadowRenderer>, numShadowRenderers:int):void {
|
|
||||||
if (numShadowRenderers > maxShadows) maxShadows = numShadowRenderers;
|
|
||||||
if (numShadowRenderers > MAX_SHADOWMAPS) {
|
|
||||||
numShadowRenderers = MAX_SHADOWMAPS;
|
|
||||||
renderers.length = MAX_SHADOWMAPS;
|
|
||||||
}
|
|
||||||
object.shadowRenderers = renderers;
|
|
||||||
object.numShadowRenderers = numShadowRenderers;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,656 +0,0 @@
|
|||||||
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.Transform3D;
|
|
||||||
import alternativa.engine3d.core.VertexAttributes;
|
|
||||||
import alternativa.engine3d.lights.SpotLight;
|
|
||||||
import alternativa.engine3d.materials.ShaderProgram;
|
|
||||||
import alternativa.engine3d.materials.TextureMaterial;
|
|
||||||
import alternativa.engine3d.materials.compiler.Linker;
|
|
||||||
import alternativa.engine3d.materials.compiler.Procedure;
|
|
||||||
import alternativa.engine3d.materials.compiler.VariableType;
|
|
||||||
import alternativa.engine3d.objects.Mesh;
|
|
||||||
import alternativa.engine3d.objects.Surface;
|
|
||||||
import alternativa.engine3d.primitives.Box;
|
|
||||||
import alternativa.engine3d.resources.TextureResource;
|
|
||||||
|
|
||||||
import flash.display3D.Context3D;
|
|
||||||
import flash.display3D.Context3DProgramType;
|
|
||||||
import flash.display3D.Context3DTextureFormat;
|
|
||||||
import flash.display3D.Context3DTriangleFace;
|
|
||||||
import flash.display3D.Program3D;
|
|
||||||
import flash.display3D.textures.Texture;
|
|
||||||
import flash.geom.Matrix3D;
|
|
||||||
|
|
||||||
use namespace alternativa3d;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
public class SpotShadowRenderer extends ShadowRenderer {
|
|
||||||
|
|
||||||
public var caster:Object3D;
|
|
||||||
|
|
||||||
private var context:Context3D;
|
|
||||||
|
|
||||||
private var shadowMap:Texture;
|
|
||||||
|
|
||||||
private var light:SpotLight;
|
|
||||||
|
|
||||||
private var debugObject:Mesh;
|
|
||||||
public var debugMaterial:TextureMaterial = new TextureMaterial();
|
|
||||||
private var debugTexture:TextureResource = new TextureResource();
|
|
||||||
|
|
||||||
private var globalToShadowMap:Matrix3D = new Matrix3D();
|
|
||||||
|
|
||||||
private static const constants:Vector.<Number> = Vector.<Number>([
|
|
||||||
255, 255*0.96, 100, 1
|
|
||||||
]);
|
|
||||||
|
|
||||||
private var pcfSize:Number = 0;
|
|
||||||
private var pcfOffset:Number = 0;
|
|
||||||
private var pcfOffsets:Vector.<Number>;
|
|
||||||
|
|
||||||
public function SpotShadowRenderer(context:Context3D, size:int, pcfSize:Number = 0) {
|
|
||||||
this.context = context;
|
|
||||||
this.shadowMap = context.createTexture(size, size, Context3DTextureFormat.BGRA, true);
|
|
||||||
this.pcfSize = pcfSize;
|
|
||||||
debugTexture._texture = this.shadowMap;
|
|
||||||
// debugMaterial.diffuseMap = debugTexture;
|
|
||||||
debugMaterial.alpha = 0.9;
|
|
||||||
debugMaterial.opaquePass = false;
|
|
||||||
debugMaterial.transparentPass = true;
|
|
||||||
debugMaterial.alphaThreshold = 1.1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setLight(value:SpotLight):void {
|
|
||||||
light = value;
|
|
||||||
var width:Number = 2*Math.sin(light.falloff*0.5)*light.attenuationEnd;
|
|
||||||
this.pcfOffset = pcfSize/width/255;
|
|
||||||
if (pcfOffset > 0) {
|
|
||||||
pcfOffsets = Vector.<Number>([
|
|
||||||
-pcfOffset, -pcfOffset, 0, 1/4,
|
|
||||||
-pcfOffset, pcfOffset, 0, 1,
|
|
||||||
pcfOffset, -pcfOffset, 0, 1,
|
|
||||||
pcfOffset, pcfOffset, 0, 1
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
debugObject = new Box(width, width, 1, 1, 1, 1, false, debugMaterial);
|
|
||||||
debugObject.rotationX = Math.PI;
|
|
||||||
debugObject.geometry.upload(context);
|
|
||||||
if (_debug) {
|
|
||||||
light.addChild(debugObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var _debug:Boolean = false;
|
|
||||||
override public function get debug():Boolean {
|
|
||||||
return _debug;
|
|
||||||
}
|
|
||||||
|
|
||||||
override public function set debug(value:Boolean):void {
|
|
||||||
_debug = value;
|
|
||||||
if (_debug) {
|
|
||||||
if (light != null) {
|
|
||||||
light.addChild(debugObject);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (debugObject != null && debugObject._parent != null) {
|
|
||||||
debugObject._parent.removeChild(debugObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static var matrix:Matrix3D = new Matrix3D();
|
|
||||||
override alternativa3d function cullReciever(boundBox:BoundBox, object:Object3D):Boolean {
|
|
||||||
copyMatrixFromTransform(matrix, object.localToGlobalTransform);
|
|
||||||
matrix.append(this.globalToShadowMap);
|
|
||||||
return cullObjectImpl(boundBox, matrix);
|
|
||||||
}
|
|
||||||
private function cullCaster(boundBox:BoundBox, objectToGlobal:Transform3D):Boolean {
|
|
||||||
copyMatrixFromTransform(matrix, objectToGlobal);
|
|
||||||
matrix.append(this.globalToShadowMap);
|
|
||||||
return cullObjectImpl(boundBox, matrix, light.attenuationEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
private var projection:ProjectionTransform3D = new ProjectionTransform3D();
|
|
||||||
private var uvProjection:Matrix3D = new Matrix3D();
|
|
||||||
override public function update():void {
|
|
||||||
// Считаем матрицу перевода в лайт
|
|
||||||
var root:Object3D;
|
|
||||||
// Расчитываем матрицу объекта для перевода в глобал
|
|
||||||
// if (caster.transformChanged) {
|
|
||||||
caster.localToGlobalTransform.compose(caster._x, caster._y, caster._z, caster._rotationX, caster._rotationY, caster._rotationZ, caster._scaleX, caster._scaleY, caster._scaleZ);
|
|
||||||
// } else {
|
|
||||||
// caster.localToCameraTransform.copy(caster.transform);
|
|
||||||
// }
|
|
||||||
root = caster;
|
|
||||||
while (root._parent != null) {
|
|
||||||
root = root._parent;
|
|
||||||
// if (root.transformChanged) {
|
|
||||||
root.localToGlobalTransform.compose(root._x, root._y, root._z, root._rotationX, root._rotationY, root._rotationZ, root._scaleX, root._scaleY, root._scaleZ);
|
|
||||||
// }
|
|
||||||
caster.localToGlobalTransform.append(root.localToGlobalTransform);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Расчитываем матрицу лайта
|
|
||||||
light.localToGlobalTransform.compose(light._x, light._y, light._z, light._rotationX, light._rotationY, light._rotationZ, light._scaleX, light._scaleY, light._scaleZ);
|
|
||||||
root = light;
|
|
||||||
while (root._parent != null) {
|
|
||||||
root = root._parent;
|
|
||||||
// if (root.transformChanged) {
|
|
||||||
root.localToGlobalTransform.compose(root._x, root._y, root._z, root._rotationX, root._rotationY, root._rotationZ, root._scaleX, root._scaleY, root._scaleZ);
|
|
||||||
// }
|
|
||||||
light.localToGlobalTransform.append(root.localToGlobalTransform);
|
|
||||||
}
|
|
||||||
light.globalToLocalTransform.copy(light.localToGlobalTransform);
|
|
||||||
light.globalToLocalTransform.invert();
|
|
||||||
|
|
||||||
// Получаем матрицу перевода из объекта в лайт
|
|
||||||
caster.localToCameraTransform.combine(light.globalToLocalTransform, caster.localToGlobalTransform);
|
|
||||||
// caster.localToCameraTransform.append(light.globalToLocalTransform);
|
|
||||||
|
|
||||||
// Считаем матрицу проецирования
|
|
||||||
calculateProjection(projection, uvProjection, light.falloff, 1, light.attenuationEnd);
|
|
||||||
// globalToShadowMap.copy(light.globalToLocalTransform);
|
|
||||||
copyMatrixFromTransform(globalToShadowMap, light.globalToLocalTransform);
|
|
||||||
globalToShadowMap.append(uvProjection);
|
|
||||||
|
|
||||||
debugMaterial.diffuseMap = null;
|
|
||||||
|
|
||||||
// trace("TEST:", testCasterCulling(caster));
|
|
||||||
if (!testCasterCulling(caster)) {
|
|
||||||
active = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
active = true;
|
|
||||||
|
|
||||||
// Рисуем в шедоумапу
|
|
||||||
context.setRenderToTexture(shadowMap, true, 0, 0);
|
|
||||||
// context.clear(1);
|
|
||||||
context.clear(1, 1, 1, 1);
|
|
||||||
cleanContext(context);
|
|
||||||
drawObjectToShadowMap(context, caster, projection);
|
|
||||||
context.setRenderToBackBuffer();
|
|
||||||
cleanContext(context);
|
|
||||||
debugMaterial.diffuseMap = debugTexture;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function testCasterCulling(object:Object3D):Boolean {
|
|
||||||
for (var child:Object3D = object.childrenList; child != null; child = child.next) {
|
|
||||||
if (child.visible) {
|
|
||||||
if (child.transformChanged) child.composeTransforms();
|
|
||||||
child.localToGlobalTransform.combine(object.localToGlobalTransform, child.transform);
|
|
||||||
if (child.boundBox == null || cullCaster(child.boundBox, child.localToGlobalTransform)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (testCasterCulling(child)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static private const boundVertices:Vector.<Number> = new Vector.<Number>(24);
|
|
||||||
alternativa3d function cullObjectImpl(bounds:BoundBox, matrix:Matrix3D, far:Number = 0):Boolean {
|
|
||||||
var i:int;
|
|
||||||
var infront:Boolean;
|
|
||||||
var behind:Boolean;
|
|
||||||
// Заполнение
|
|
||||||
boundVertices[0] = bounds.minX;
|
|
||||||
boundVertices[1] = bounds.minY;
|
|
||||||
boundVertices[2] = bounds.minZ;
|
|
||||||
boundVertices[3] = bounds.maxX;
|
|
||||||
boundVertices[4] = bounds.minY;
|
|
||||||
boundVertices[5] = bounds.minZ;
|
|
||||||
boundVertices[6] = bounds.minX;
|
|
||||||
boundVertices[7] = bounds.maxY;
|
|
||||||
boundVertices[8] = bounds.minZ;
|
|
||||||
boundVertices[9] = bounds.maxX;
|
|
||||||
boundVertices[10] = bounds.maxY;
|
|
||||||
boundVertices[11] = bounds.minZ;
|
|
||||||
boundVertices[12] = bounds.minX;
|
|
||||||
boundVertices[13] = bounds.minY;
|
|
||||||
boundVertices[14] = bounds.maxZ;
|
|
||||||
boundVertices[15] = bounds.maxX;
|
|
||||||
boundVertices[16] = bounds.minY;
|
|
||||||
boundVertices[17] = bounds.maxZ;
|
|
||||||
boundVertices[18] = bounds.minX;
|
|
||||||
boundVertices[19] = bounds.maxY;
|
|
||||||
boundVertices[20] = bounds.maxZ;
|
|
||||||
boundVertices[21] = bounds.maxX;
|
|
||||||
boundVertices[22] = bounds.maxY;
|
|
||||||
boundVertices[23] = bounds.maxZ;
|
|
||||||
|
|
||||||
// Трансформация в камеру
|
|
||||||
matrix.transformVectors(boundVertices, boundVertices);
|
|
||||||
// Куллинг
|
|
||||||
// left
|
|
||||||
for (i = 0, infront = false, behind = false; i <= 21; i += 3) {
|
|
||||||
// trace("POS", boundVertices[i], boundVertices[int(i + 2)]);
|
|
||||||
if (boundVertices[i] > 0) {
|
|
||||||
infront = true;
|
|
||||||
if (behind) break;
|
|
||||||
} else {
|
|
||||||
behind = true;
|
|
||||||
if (infront) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (behind) {
|
|
||||||
// trace("L", infront);
|
|
||||||
if (!infront) return false;
|
|
||||||
}
|
|
||||||
// right
|
|
||||||
for (i = 0, infront = false, behind = false; i <= 21; i += 3) {
|
|
||||||
if (boundVertices[i] < boundVertices[int(i + 2)]) {
|
|
||||||
infront = true;
|
|
||||||
if (behind) break;
|
|
||||||
} else {
|
|
||||||
behind = true;
|
|
||||||
if (infront) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (behind) {
|
|
||||||
// trace("R", infront);
|
|
||||||
if (!infront) return false;
|
|
||||||
}
|
|
||||||
// up
|
|
||||||
for (i = 1, infront = false, behind = false; i <= 22; i += 3) {
|
|
||||||
// if (-boundVertices[i] < boundVertices[int(i + 1)]) {
|
|
||||||
if (boundVertices[i] > 0) {
|
|
||||||
infront = true;
|
|
||||||
if (behind) break;
|
|
||||||
} else {
|
|
||||||
behind = true;
|
|
||||||
if (infront) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (behind) {
|
|
||||||
// trace("U", infront);
|
|
||||||
if (!infront) return false;
|
|
||||||
}
|
|
||||||
// down
|
|
||||||
for (i = 1, infront = false, behind = false; i <= 22; i += 3) {
|
|
||||||
if (boundVertices[i] < boundVertices[int(i + 1)]) {
|
|
||||||
infront = true;
|
|
||||||
if (behind) break;
|
|
||||||
} else {
|
|
||||||
behind = true;
|
|
||||||
if (infront) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (behind) {
|
|
||||||
// trace("D", infront);
|
|
||||||
if (!infront) return false;
|
|
||||||
}
|
|
||||||
if (far > 0) {
|
|
||||||
for (i = 2, infront = false, behind = false; i <= 23; i += 3) {
|
|
||||||
if (boundVertices[i] < far) {
|
|
||||||
infront = true;
|
|
||||||
if (behind) break;
|
|
||||||
} else {
|
|
||||||
behind = true;
|
|
||||||
if (infront) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (behind) {
|
|
||||||
// trace("N", infront);
|
|
||||||
if (!infront) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i = 2, infront = false, behind = false; i <= 23; i += 3) {
|
|
||||||
if (boundVertices[i] > 0) {
|
|
||||||
infront = true;
|
|
||||||
if (behind) break;
|
|
||||||
} else {
|
|
||||||
behind = true;
|
|
||||||
if (infront) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (behind) {
|
|
||||||
// trace("N", infront);
|
|
||||||
if (!infront) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// должен быть заполнен нулями
|
|
||||||
private var rawData:Vector.<Number> = new Vector.<Number>(16);
|
|
||||||
private var m:Matrix3D = new Matrix3D();
|
|
||||||
private function calculateProjection(projection:ProjectionTransform3D, uvProjection:Matrix3D, fov:Number, nearClipping:Number, farClipping:Number):void {
|
|
||||||
var viewSize:Number = 1;
|
|
||||||
var focalLength:Number = viewSize/Math.tan(fov*0.5);
|
|
||||||
projection.m0 = focalLength/viewSize;
|
|
||||||
projection.m5 = -focalLength/viewSize;
|
|
||||||
projection.m10 = farClipping/(farClipping - nearClipping);
|
|
||||||
projection.m14 = -nearClipping*projection.m10;
|
|
||||||
|
|
||||||
for (var i:int = 0; i < 16; i++) {
|
|
||||||
rawData[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: предумножить матрицы
|
|
||||||
|
|
||||||
rawData[0] = projection.m0;
|
|
||||||
rawData[5] = -projection.m5;
|
|
||||||
rawData[10]= projection.m10;
|
|
||||||
rawData[11]= 1;
|
|
||||||
rawData[14]= projection.m14;
|
|
||||||
uvProjection.rawData = rawData;
|
|
||||||
|
|
||||||
// 0.5f, 0.0f, 0.0f, 0.0f,
|
|
||||||
// 0.0f, 0.5f, 0.0f, 0.0f,
|
|
||||||
// 0.0f, 0.0f, 0.5f, 0.0f,
|
|
||||||
// 0.5f, 0.5f, 0.5f, 1.0f
|
|
||||||
|
|
||||||
rawData[0] = 0.5;
|
|
||||||
rawData[12] = 0.5;
|
|
||||||
rawData[5] = 0.5;
|
|
||||||
rawData[13] = 0.5;
|
|
||||||
rawData[10] = 0.5;
|
|
||||||
rawData[14] = 0.5;
|
|
||||||
rawData[11] = 0;
|
|
||||||
rawData[15] = 1;
|
|
||||||
m.rawData = rawData;
|
|
||||||
uvProjection.append(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
private var transformToMatrixRawData:Vector.<Number> = new Vector.<Number>(16);
|
|
||||||
private function copyMatrixFromTransform(matrix:Matrix3D, transform:Transform3D):void {
|
|
||||||
transformToMatrixRawData[0] = transform.a;
|
|
||||||
transformToMatrixRawData[1] = transform.e;
|
|
||||||
transformToMatrixRawData[2] = transform.i;
|
|
||||||
transformToMatrixRawData[3] = 0;
|
|
||||||
transformToMatrixRawData[4] = transform.b;
|
|
||||||
transformToMatrixRawData[5] = transform.f;
|
|
||||||
transformToMatrixRawData[6] = transform.j;
|
|
||||||
transformToMatrixRawData[7] = 0;
|
|
||||||
transformToMatrixRawData[8] = transform.c;
|
|
||||||
transformToMatrixRawData[9] = transform.g;
|
|
||||||
transformToMatrixRawData[10] = transform.k;
|
|
||||||
transformToMatrixRawData[11] = 0;
|
|
||||||
transformToMatrixRawData[12] = transform.d;
|
|
||||||
transformToMatrixRawData[13] = transform.h;
|
|
||||||
transformToMatrixRawData[14] = transform.l;
|
|
||||||
transformToMatrixRawData[15] = 1;
|
|
||||||
matrix.rawData = transformToMatrixRawData;
|
|
||||||
}
|
|
||||||
|
|
||||||
alternativa3d static function drawObjectToShadowMap(context:Context3D, object:Object3D, projection:ProjectionTransform3D):void {
|
|
||||||
if (object is Mesh) {
|
|
||||||
drawMeshToShadowMap(context, Mesh(object), projection);
|
|
||||||
}
|
|
||||||
for (var child:Object3D = object.childrenList; child != null; child = child.next) {
|
|
||||||
if (child.visible) {
|
|
||||||
if (child.transformChanged) child.composeTransforms();
|
|
||||||
child.localToCameraTransform.combine(object.localToCameraTransform, child.transform);
|
|
||||||
drawObjectToShadowMap(context, child, projection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static var shadowMapProgram:Program3D;
|
|
||||||
private static var projectionVector:Vector.<Number> = new Vector.<Number>(16);
|
|
||||||
private static function drawMeshToShadowMap(context:Context3D, mesh:Mesh, projection:ProjectionTransform3D):void {
|
|
||||||
if (mesh.geometry == null || mesh.geometry.numTriangles == 0 || !mesh.geometry.isUploaded) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shadowMapProgram == null) shadowMapProgram = initMeshToShadowMapProgram(context);
|
|
||||||
context.setProgram(shadowMapProgram);
|
|
||||||
|
|
||||||
context.setVertexBufferAt(0, mesh.geometry.getVertexBuffer(VertexAttributes.POSITION), mesh.geometry._attributesOffsets[VertexAttributes.POSITION], VertexAttributes.FORMATS[VertexAttributes.POSITION]);
|
|
||||||
|
|
||||||
var transform:Transform3D = mesh.localToCameraTransform;
|
|
||||||
projectionVector[0] = transform.a*projection.m0;
|
|
||||||
projectionVector[1] = transform.b*projection.m0;
|
|
||||||
projectionVector[2] = transform.c*projection.m0;
|
|
||||||
projectionVector[3] = transform.d*projection.m0;
|
|
||||||
projectionVector[4] = transform.e*projection.m5;
|
|
||||||
projectionVector[5] = transform.f*projection.m5;
|
|
||||||
projectionVector[6] = transform.g*projection.m5;
|
|
||||||
projectionVector[7] = transform.h*projection.m5;
|
|
||||||
projectionVector[8] = transform.i*projection.m10;
|
|
||||||
projectionVector[9] = transform.j*projection.m10;
|
|
||||||
projectionVector[10] = transform.k*projection.m10;
|
|
||||||
projectionVector[11] = transform.l*projection.m10 + projection.m14;
|
|
||||||
projectionVector[12] = transform.i;
|
|
||||||
projectionVector[13] = transform.j;
|
|
||||||
projectionVector[14] = transform.k;
|
|
||||||
projectionVector[15] = transform.l;
|
|
||||||
|
|
||||||
context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 0, projectionVector, 4);
|
|
||||||
context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 4, Vector.<Number>([255, 0, 0, 1]));
|
|
||||||
context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, Vector.<Number>([1/255, 0, 0, 1]));
|
|
||||||
|
|
||||||
context.setCulling(Context3DTriangleFace.BACK);
|
|
||||||
for (var i:int = 0; i < mesh._surfacesLength; i++) {
|
|
||||||
var surface:Surface = mesh._surfaces[i];
|
|
||||||
if (surface.material == null) continue;
|
|
||||||
context.drawTriangles(mesh.geometry._indexBuffer, surface.indexBegin, surface.numTriangles);
|
|
||||||
}
|
|
||||||
context.setVertexBufferAt(0, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function initMeshToShadowMapProgram(context3d:Context3D):Program3D {
|
|
||||||
var vLinker:Linker = new Linker(Context3DProgramType.VERTEX);
|
|
||||||
var fLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
|
|
||||||
var proc:Procedure = Procedure.compileFromArray([
|
|
||||||
"#a0=a0",
|
|
||||||
"#c4=c4",
|
|
||||||
"#v0=v0",
|
|
||||||
"m44 t0, a0, c0",
|
|
||||||
"mul v0, t0, c4.x",
|
|
||||||
"mov o0, t0"
|
|
||||||
]);
|
|
||||||
proc.assignVariableName(VariableType.CONSTANT, 0, "c0", 4);
|
|
||||||
vLinker.addProcedure(proc);
|
|
||||||
|
|
||||||
fLinker.addProcedure(Procedure.compileFromArray([
|
|
||||||
"#v0=v0",
|
|
||||||
"#c0=c0",
|
|
||||||
"mov t0.xy, v0.zz",
|
|
||||||
"frc t0.y, v0.z",
|
|
||||||
"sub t0.x, v0.z, t0.y",
|
|
||||||
"mul t0.x, t0.x, c0.x",
|
|
||||||
"mov t0.z, c0.z",
|
|
||||||
"mov t0.w, c0.w",
|
|
||||||
"mov o0, t0"
|
|
||||||
]));
|
|
||||||
var program:Program3D = context3d.createProgram();
|
|
||||||
// trace("VERTEX");
|
|
||||||
// trace(A3DUtils.disassemble(vLinker.getByteCode()));
|
|
||||||
// trace("FRAGMENT");
|
|
||||||
// trace(A3DUtils.disassemble(fLinker.getByteCode()));
|
|
||||||
fLinker.varyings = vLinker.varyings;
|
|
||||||
vLinker.link();
|
|
||||||
fLinker.link();
|
|
||||||
program.upload(vLinker.data, fLinker.data);
|
|
||||||
return program;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rendering with shadow
|
|
||||||
private static function initVShader(index:int):Procedure {
|
|
||||||
var shader:Procedure = Procedure.compileFromArray([
|
|
||||||
"m44 v0, a0, c0",
|
|
||||||
"mov v1, a0"
|
|
||||||
]);
|
|
||||||
shader.assignVariableName(VariableType.ATTRIBUTE, 0, "aPosition");
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 0, index + "cTOSHADOW", 4);
|
|
||||||
shader.assignVariableName(VariableType.VARYING, 0, index + "vSHADOWSAMPLE");
|
|
||||||
shader.assignVariableName(VariableType.VARYING, 1, "vPosition");
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function initFShader(mult:Boolean, usePCF:Boolean, index:int):Procedure {
|
|
||||||
var i:int;
|
|
||||||
var line:int = 0;
|
|
||||||
var shaderArr:Array = [];
|
|
||||||
var numPass:uint = (usePCF) ? 4 : 1;
|
|
||||||
for (i = 0; i < numPass; i++) {
|
|
||||||
// Расстояние
|
|
||||||
shaderArr[line++] = "mov t0.w, v0.z";
|
|
||||||
shaderArr[line++] = "div t2, v0, v0.w";
|
|
||||||
shaderArr[line++] = "mul t0.w, t0.w, c4.y"; // bias [0.99] * 255
|
|
||||||
|
|
||||||
if (usePCF) {
|
|
||||||
// Добавляем смещение
|
|
||||||
shaderArr[line++] = "mul t1, c" + (i + 9).toString() + ", t0.w";
|
|
||||||
// shaderArr[line++] = "add t1, v0, t1";
|
|
||||||
shaderArr[line++] = "add t1, t2, t1";
|
|
||||||
shaderArr[line++] = "tex t1, t1, s0 <2d,clamp,near,nomip>";
|
|
||||||
} else {
|
|
||||||
// shaderArr[line++] = "tex t1, v0, s0 <2d,clamp,near,nomip>";
|
|
||||||
shaderArr[line++] = "tex t1, t2, s0 <2d,clamp,near,nomip>";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Восстанавливаем расстояние
|
|
||||||
shaderArr[line++] = "mul t1.w, t1.x, c4.x"; // * 255
|
|
||||||
shaderArr[line++] = "add t1.w, t1.w, t1.y";
|
|
||||||
|
|
||||||
// Перекрытие тенью
|
|
||||||
shaderArr[line++] = "sub t2.z, t1.w, t0.w";
|
|
||||||
shaderArr[line++] = "mul t2.z, t2.z, c4.z"; // smooth [10000]
|
|
||||||
shaderArr[line++] = "sat t2.z, t2.z";
|
|
||||||
|
|
||||||
// Добавляем маску и прозрачность, затем sat
|
|
||||||
shaderArr[line++] = "add t2.z, t2.z, t1.z"; // маска тени
|
|
||||||
shaderArr[line++] = "add t2, t2.zzzz, c5"; // цвет тени
|
|
||||||
|
|
||||||
// Плавный уход в прозрачность -------------
|
|
||||||
shaderArr[line++] = "#c6=c" + index + "Spot";
|
|
||||||
shaderArr[line++] = "#c7=c" + index + "Direction";
|
|
||||||
shaderArr[line++] = "#c8=c" + index + "Geometry";
|
|
||||||
shaderArr[line++] = "#v1=vPosition";
|
|
||||||
// Считаем вектор из точки к свету
|
|
||||||
|
|
||||||
// Вектор из точки к свету
|
|
||||||
shaderArr[line++] = "sub t0, c6, v1";
|
|
||||||
// shaderArr[line++] = "sub t0, v1, c6";
|
|
||||||
// Квадрат расстояния до точки
|
|
||||||
shaderArr[line++] = "dp3 t0.w, t0, t0";
|
|
||||||
// Расстояние до точки
|
|
||||||
shaderArr[line++] = "sqt t0.w, t0.w";
|
|
||||||
|
|
||||||
// Нормализованное направление к источнику
|
|
||||||
shaderArr[line++] = "nrm t0.xyz, t0.xyz";
|
|
||||||
// cos(Угол) между направлением к точке и направлением спота
|
|
||||||
shaderArr[line++] = "dp3 t0.y, t0.xyz, c7.xyz";
|
|
||||||
// // cos(угол) - cos(falloff*0.5)
|
|
||||||
shaderArr[line++] = "sub t0.y, t0.y, c8.w";
|
|
||||||
// // Делим на (cos(hotspot*0.5) - cos(falloff*0.5))
|
|
||||||
shaderArr[line++] = "div t0.y, t0.y, c8.z";
|
|
||||||
|
|
||||||
// Минус atenuationBegin
|
|
||||||
shaderArr[line++] = "sub t0.w, t0.w, c8.y"; // len = len - atenuationBegin
|
|
||||||
// Делим на (atenuationEnd - atenuationBegin)
|
|
||||||
shaderArr[line++] = "div t0.w, t0.w, c8.x"; // att = len/radius
|
|
||||||
// 1 - соотношение между расстоянием до точки и максимальным расстоянием
|
|
||||||
shaderArr[line++] = "sub t0.w, c6.w, t0.w"; // att = 1 - len/radius
|
|
||||||
|
|
||||||
shaderArr[line++] = "mul t0.w, t0.y, t0.w";
|
|
||||||
// shaderArr[line++] = "mov t0.w, t0.y";
|
|
||||||
shaderArr[line++] = "sub t0.w, c7.w, t0.w";
|
|
||||||
// shaderArr[line++] = "mov t2, t0.wwww";
|
|
||||||
shaderArr[line++] = "sat t0.w, t0.w";
|
|
||||||
shaderArr[line++] = "add t2, t2, t0.wwww";
|
|
||||||
// -----------------------------------------------------
|
|
||||||
|
|
||||||
shaderArr[line++] = "sat t2, t2";
|
|
||||||
|
|
||||||
if (usePCF) {
|
|
||||||
if (i == 0) {
|
|
||||||
shaderArr[line++] = "mov t3, t2";
|
|
||||||
} else {
|
|
||||||
shaderArr[line++] = "add t3, t3, t2";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (usePCF) {
|
|
||||||
shaderArr[line++] = "mul t2, t3, c9.w";
|
|
||||||
}
|
|
||||||
if (mult) {
|
|
||||||
shaderArr[line++] = "mul t0.xyz, i0.xyz, t2.xyz";
|
|
||||||
shaderArr[line++] = "mov t0.w, i0.w";
|
|
||||||
shaderArr[line++] = "mov o0, t0";
|
|
||||||
} else {
|
|
||||||
shaderArr[line++] = "mov o0, t2";
|
|
||||||
// shaderArr[line++] = "mov o0, t1";
|
|
||||||
}
|
|
||||||
var shader:Procedure = Procedure.compileFromArray(shaderArr);
|
|
||||||
shader.assignVariableName(VariableType.VARYING, 0, index + "vSHADOWSAMPLE");
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 4, index + "cConstants", 1);
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 5, index + "cShadowColor", 1);
|
|
||||||
if (usePCF) {
|
|
||||||
for (i = 0; i < numPass; i++) {
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, i + 9, "cSPCF" + i.toString(), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
shader.assignVariableName(VariableType.SAMPLER, 0, index + "sSHADOWMAP");
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
override public function getFShader(index:int = 0):Procedure {
|
|
||||||
return initFShader(false, (pcfOffset > 0), index);
|
|
||||||
}
|
|
||||||
override public function getVShader(index:int = 0):Procedure {
|
|
||||||
return initVShader(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static const objectToShadowMap:Matrix3D = new Matrix3D();
|
|
||||||
private static const localToGlobal:Transform3D = new Transform3D();
|
|
||||||
override public function applyShader(drawUnit:DrawUnit, program:ShaderProgram, object:Object3D, camera:Camera3D, index:int = 0):void {
|
|
||||||
// Считаем матрицу перевода в лайт из объекта
|
|
||||||
localToGlobal.combine(camera.localToGlobalTransform, object.localToCameraTransform);
|
|
||||||
copyMatrixFromTransform(objectToShadowMap, localToGlobal);
|
|
||||||
objectToShadowMap.append(globalToShadowMap);
|
|
||||||
|
|
||||||
// var casterPos:Vector3D = new Vector3D(caster.localToGlobalTransform.d, caster.localToGlobalTransform.h, caster.localToGlobalTransform.l);
|
|
||||||
// var p:Vector3D = objectToShadowMap.transformVector(casterPos);
|
|
||||||
// p.scaleBy(1/p.w);
|
|
||||||
// trace("caster pos:", p);
|
|
||||||
|
|
||||||
objectToShadowMap.transpose();
|
|
||||||
|
|
||||||
drawUnit.setVertexConstantsFromVector(program.vertexShader.getVariableIndex(index + "cTOSHADOW"), objectToShadowMap.rawData, 4);
|
|
||||||
drawUnit.setFragmentConstantsFromVector(program.fragmentShader.getVariableIndex(index + "cConstants"), constants, constants.length/4);
|
|
||||||
drawUnit.setFragmentConstantsFromVector(program.fragmentShader.getVariableIndex(index + "cShadowColor"), camera.ambient, 1);
|
|
||||||
if (pcfOffset > 0) {
|
|
||||||
drawUnit.setFragmentConstantsFromVector(program.fragmentShader.getVariableIndex("cSPCF0"), pcfOffsets, pcfOffsets.length/4);
|
|
||||||
}
|
|
||||||
drawUnit.setTextureAt(program.fragmentShader.getVariableIndex(index + "sSHADOWMAP"), shadowMap);
|
|
||||||
|
|
||||||
// localToGlobal.combine(light.cameraToLocalTransform, object.localToCameraTransform);
|
|
||||||
localToGlobal.combine(object.cameraToLocalTransform, light.localToCameraTransform);
|
|
||||||
// localToGlobal.invert();
|
|
||||||
|
|
||||||
// Настройки затухания
|
|
||||||
var transform:Transform3D = localToGlobal;
|
|
||||||
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + index + "Spot"), transform.d, transform.h, transform.l, 1);
|
|
||||||
var rScale:Number = Math.sqrt(transform.a * transform.a + transform.e * transform.e + transform.i * transform.i);
|
|
||||||
rScale += Math.sqrt(transform.b * transform.b + transform.f * transform.f + transform.j * transform.j);
|
|
||||||
var dLen:Number = Math.sqrt(transform.c * transform.c + transform.g * transform.g + transform.k * transform.k);
|
|
||||||
rScale += dLen;
|
|
||||||
rScale /= 3;
|
|
||||||
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + index + "Direction"), -transform.c / dLen, -transform.g / dLen, -transform.k / dLen, 0.5);
|
|
||||||
|
|
||||||
var falloff:Number = Math.cos(light.falloff * 0.5);
|
|
||||||
var hotspot:Number = Math.cos(light.hotspot * 0.5);
|
|
||||||
|
|
||||||
drawUnit.setFragmentConstantsFromNumbers(program.fragmentShader.getVariableIndex("c" + index + "Geometry"), light.attenuationEnd * rScale - light.attenuationBegin * rScale, light.attenuationBegin * rScale, hotspot == falloff ? 0.000001 : hotspot - falloff, falloff);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ProjectionTransform3D {
|
|
||||||
public var m0:Number;
|
|
||||||
public var m5:Number;
|
|
||||||
public var m10:Number;
|
|
||||||
public var m14:Number;
|
|
||||||
}
|
|
||||||
@@ -1,569 +0,0 @@
|
|||||||
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.Transform3D;
|
|
||||||
import alternativa.engine3d.lights.DirectionalLight;
|
|
||||||
import alternativa.engine3d.materials.ShaderProgram;
|
|
||||||
import alternativa.engine3d.materials.TextureMaterial;
|
|
||||||
import alternativa.engine3d.materials.compiler.Procedure;
|
|
||||||
import alternativa.engine3d.materials.compiler.VariableType;
|
|
||||||
import alternativa.engine3d.objects.Mesh;
|
|
||||||
import alternativa.engine3d.primitives.Box;
|
|
||||||
import alternativa.engine3d.resources.ExternalTextureResource;
|
|
||||||
import alternativa.engine3d.resources.TextureResource;
|
|
||||||
|
|
||||||
import flash.display3D.Context3D;
|
|
||||||
import flash.display3D.Context3DTextureFormat;
|
|
||||||
import flash.display3D.textures.Texture;
|
|
||||||
import flash.geom.Matrix3D;
|
|
||||||
import flash.geom.Vector3D;
|
|
||||||
import flash.utils.Dictionary;
|
|
||||||
|
|
||||||
use namespace alternativa3d;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
public class StaticShadowRenderer extends ShadowRenderer {
|
|
||||||
|
|
||||||
public var context:Context3D;
|
|
||||||
|
|
||||||
private const alpha:Number = 0.7;
|
|
||||||
|
|
||||||
private var bounds:BoundBox = new BoundBox();
|
|
||||||
private var partSize:Number;
|
|
||||||
private var partsShadowMaps:Vector.<Vector.<Texture>> = new Vector.<Vector.<Texture>>();
|
|
||||||
private var partsUVMatrices:Vector.<Vector.<Matrix3D>> = new Vector.<Vector.<Matrix3D>>();
|
|
||||||
|
|
||||||
private var light:DirectionalLight;
|
|
||||||
private var globalToLight:Transform3D = new Transform3D();
|
|
||||||
|
|
||||||
private var _debug:Boolean = false;
|
|
||||||
private var debugContainer:Object3D;
|
|
||||||
|
|
||||||
private var _recievers:Dictionary = new Dictionary();
|
|
||||||
public function addReciever(object:Object3D):void {
|
|
||||||
_recievers[object] = true;
|
|
||||||
}
|
|
||||||
public function removeReciever(object:Object3D):void {
|
|
||||||
delete _recievers[object];
|
|
||||||
}
|
|
||||||
|
|
||||||
private static const constants:Vector.<Number> = Vector.<Number>([
|
|
||||||
// 255, 255*0.99, 100, 1/255
|
|
||||||
// 255, 255*0.96, 100, 1
|
|
||||||
255, 255, 1000, 1
|
|
||||||
]);
|
|
||||||
|
|
||||||
private var pcfOffset:Number = 0;
|
|
||||||
private static var pcfOffsets:Vector.<Number>;
|
|
||||||
|
|
||||||
public function dispose():void {
|
|
||||||
for each (var textures:Vector.<Texture> in partsShadowMaps) {
|
|
||||||
for each (var texture:Texture in textures) {
|
|
||||||
texture.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
partsShadowMaps.length = 0;
|
|
||||||
partsUVMatrices.length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function StaticShadowRenderer(context:Context3D, partSize:int, pcfSize:Number = 0) {
|
|
||||||
this.context = context;
|
|
||||||
this.partSize = partSize;
|
|
||||||
this.pcfOffset = pcfSize;
|
|
||||||
constants[3] = 1 - alpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
override alternativa3d function cullReciever(boundBox:BoundBox, object:Object3D):Boolean {
|
|
||||||
return _recievers[object];
|
|
||||||
}
|
|
||||||
|
|
||||||
private var lightProjectionMatrix:Matrix3D = new Matrix3D();
|
|
||||||
public function calculateShadows(object:Object3D, light:DirectionalLight, widthPartsCount:int = 1, heightPartsCount:int = 1, overlap:Number = 0):void {
|
|
||||||
this.light = light;
|
|
||||||
|
|
||||||
var root:Object3D;
|
|
||||||
// Расчитываем матрицу объекта
|
|
||||||
// if (object.transformChanged) {
|
|
||||||
object.localToCameraTransform.compose(object._x, object._y, object._z, object._rotationX, object._rotationY, object._rotationZ, object._scaleX, object._scaleY, object._scaleZ);
|
|
||||||
// } else {
|
|
||||||
// object.localToCameraTransform.copy(caster.transform);
|
|
||||||
// }
|
|
||||||
root = object;
|
|
||||||
while (root._parent != null) {
|
|
||||||
root = root._parent;
|
|
||||||
// if (root.transformChanged) {
|
|
||||||
root.localToGlobalTransform.compose(root._x, root._y, root._z, root._rotationX, root._rotationY, root._rotationZ, root._scaleX, root._scaleY, root._scaleZ);
|
|
||||||
// }
|
|
||||||
object.localToCameraTransform.append(root.localToGlobalTransform);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Расчитываем матрицу лайта
|
|
||||||
light.localToGlobalTransform.compose(light._x, light._y, light._z, light._rotationX, light._rotationY, light._rotationZ, light._scaleX, light._scaleY, light._scaleZ);
|
|
||||||
root = light;
|
|
||||||
while (root._parent != null) {
|
|
||||||
root = root._parent;
|
|
||||||
// if (root.transformChanged) {
|
|
||||||
root.localToGlobalTransform.compose(root._x, root._y, root._z, root._rotationX, root._rotationY, root._rotationZ, root._scaleX, root._scaleY, root._scaleZ);
|
|
||||||
// }
|
|
||||||
light.localToGlobalTransform.append(root.localToGlobalTransform);
|
|
||||||
}
|
|
||||||
light.globalToLocalTransform.copy(light.localToGlobalTransform);
|
|
||||||
light.globalToLocalTransform.invert();
|
|
||||||
|
|
||||||
globalToLight.copy(light.globalToLocalTransform);
|
|
||||||
|
|
||||||
// Получаем матрицу перевода из объекта в лайт
|
|
||||||
object.localToCameraTransform.append(light.globalToLocalTransform);
|
|
||||||
|
|
||||||
bounds.reset();
|
|
||||||
calculateBoundBox(bounds, object);
|
|
||||||
|
|
||||||
var frustumMinX:Number = bounds.minX;
|
|
||||||
var frustumMaxX:Number = bounds.maxX;
|
|
||||||
var frustumMinY:Number = bounds.minY;
|
|
||||||
var frustumMaxY:Number = bounds.maxY;
|
|
||||||
var frustumMinZ:Number = bounds.minZ;
|
|
||||||
var frustumMaxZ:Number = bounds.maxZ;
|
|
||||||
|
|
||||||
// Считаем шаг
|
|
||||||
var halfOverlap:Number = overlap*0.5;
|
|
||||||
var partWorldWidth:Number = (frustumMaxX - frustumMinX)/widthPartsCount;
|
|
||||||
var partWorldHeight:Number = (frustumMaxY - frustumMinY)/heightPartsCount;
|
|
||||||
|
|
||||||
debugContainer = new Object3D();
|
|
||||||
if (_debug) {
|
|
||||||
light.addChild(debugContainer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Создаем шэдоумапы и рендерим
|
|
||||||
for (var xIndex:int = 0; xIndex < widthPartsCount; xIndex++) {
|
|
||||||
var maps:Vector.<Texture> = new Vector.<Texture>();
|
|
||||||
var matrices:Vector.<Matrix3D> = new Vector.<Matrix3D>();
|
|
||||||
for (var yIndex:int = 0; yIndex < heightPartsCount; yIndex++) {
|
|
||||||
var leftX:Number = frustumMinX + xIndex*partWorldWidth;
|
|
||||||
var leftY:Number = frustumMinY + yIndex*partWorldHeight;
|
|
||||||
|
|
||||||
var width:Number;
|
|
||||||
var height:Number;
|
|
||||||
if (xIndex == 0) {
|
|
||||||
width = partWorldWidth + halfOverlap;
|
|
||||||
} else if (xIndex == (widthPartsCount - 1)) {
|
|
||||||
leftX -= halfOverlap;
|
|
||||||
width = partWorldWidth + halfOverlap;
|
|
||||||
} else {
|
|
||||||
leftX -= halfOverlap;
|
|
||||||
width = partWorldWidth + overlap;
|
|
||||||
}
|
|
||||||
if (yIndex == 0) {
|
|
||||||
height = partWorldHeight + halfOverlap;
|
|
||||||
} else if (yIndex == (heightPartsCount - 1)) {
|
|
||||||
leftY -= halfOverlap;
|
|
||||||
height = partWorldHeight + halfOverlap;
|
|
||||||
} else {
|
|
||||||
leftY -= halfOverlap;
|
|
||||||
height = partWorldHeight + overlap;
|
|
||||||
}
|
|
||||||
|
|
||||||
var uvMatrix:Matrix3D = new Matrix3D();
|
|
||||||
calculateShadowMapProjection(lightProjectionMatrix, uvMatrix, leftX, leftY, frustumMinZ, leftX + width, leftY + height, frustumMaxZ);
|
|
||||||
|
|
||||||
var shadowMap:Texture = context.createTexture(partSize, partSize, Context3DTextureFormat.BGRA, true);
|
|
||||||
// Рисуем в шедоумапу
|
|
||||||
context.setRenderToTexture(shadowMap, true, 0, 0);
|
|
||||||
context.clear(1, 1, 1, 0.5);
|
|
||||||
cleanContext(context);
|
|
||||||
DirectionalShadowRenderer.drawObjectToShadowMap(context, object, light, lightProjectionMatrix);
|
|
||||||
cleanContext(context);
|
|
||||||
|
|
||||||
maps.push(shadowMap);
|
|
||||||
matrices.push(uvMatrix);
|
|
||||||
|
|
||||||
var texture:TextureResource = new ExternalTextureResource(null);
|
|
||||||
texture._texture = shadowMap;
|
|
||||||
var material:TextureMaterial = new TextureMaterial(texture);
|
|
||||||
material.opaquePass = false;
|
|
||||||
material.transparentPass = true;
|
|
||||||
material.alphaThreshold = 1.1;
|
|
||||||
var debugObject:Mesh = new Box(width, height, 1, 1, 1, 1, false, material);
|
|
||||||
// var debugObject:Mesh = new Box(width, height, 1, 1, 1, 1, false, new FillMaterial());
|
|
||||||
debugObject.geometry.upload(context);
|
|
||||||
debugObject.x = leftX + width/2;
|
|
||||||
debugObject.y = leftY + height/2;
|
|
||||||
debugObject.z = frustumMinZ;
|
|
||||||
debugContainer.addChild(debugObject);
|
|
||||||
}
|
|
||||||
partsShadowMaps.push(maps);
|
|
||||||
partsUVMatrices.push(matrices);
|
|
||||||
}
|
|
||||||
context.setRenderToBackBuffer();
|
|
||||||
if (pcfOffset > 0) {
|
|
||||||
var offset:Number = pcfOffset/partWorldWidth;
|
|
||||||
// pcfOffsets = Vector.<Number>([
|
|
||||||
// -offset, -offset, 0, 1/4,
|
|
||||||
// -offset, offset, 0, 1,
|
|
||||||
// offset, -offset, 0, 1,
|
|
||||||
// offset, offset, 0, 1,
|
|
||||||
// ]);
|
|
||||||
pcfOffsets = Vector.<Number>([
|
|
||||||
-offset, -offset, 0, 1/4,
|
|
||||||
-offset, offset, 0, 1,
|
|
||||||
offset, -offset, 0, 1,
|
|
||||||
offset, offset, 0, 1
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static const points:Vector.<Vector3D> = Vector.<Vector3D>([
|
|
||||||
new Vector3D(), new Vector3D(), new Vector3D(), new Vector3D(),
|
|
||||||
new Vector3D(), new Vector3D(), new Vector3D(), new Vector3D(),
|
|
||||||
new Vector3D(), new Vector3D(), new Vector3D(), new Vector3D(),
|
|
||||||
new Vector3D(), new Vector3D(), new Vector3D(), new Vector3D()
|
|
||||||
]);
|
|
||||||
alternativa3d static function calculateBoundBox(boundBox:BoundBox, object:Object3D, hierarchy:Boolean = true):void {
|
|
||||||
// Считаем баунды объекта в лайте
|
|
||||||
var point:Vector3D;
|
|
||||||
if (object.boundBox != null) {
|
|
||||||
var bb:BoundBox = object.boundBox;
|
|
||||||
point = points[0];
|
|
||||||
point.x = bb.minX;
|
|
||||||
point.y = bb.minY;
|
|
||||||
point.z = bb.minZ;
|
|
||||||
point = points[1];
|
|
||||||
point.x = bb.minX;
|
|
||||||
point.y = bb.minY;
|
|
||||||
point.z = bb.maxZ;
|
|
||||||
point = points[2];
|
|
||||||
point.x = bb.minX;
|
|
||||||
point.y = bb.maxY;
|
|
||||||
point.z = bb.minZ;
|
|
||||||
point = points[3];
|
|
||||||
point.x = bb.minX;
|
|
||||||
point.y = bb.maxY;
|
|
||||||
point.z = bb.maxZ;
|
|
||||||
point = points[4];
|
|
||||||
point.x = bb.maxX;
|
|
||||||
point.y = bb.minY;
|
|
||||||
point.z = bb.minZ;
|
|
||||||
point = points[5];
|
|
||||||
point.x = bb.maxX;
|
|
||||||
point.y = bb.minY;
|
|
||||||
point.z = bb.maxZ;
|
|
||||||
point = points[6];
|
|
||||||
point.x = bb.maxX;
|
|
||||||
point.y = bb.maxY;
|
|
||||||
point.z = bb.minZ;
|
|
||||||
point = points[7];
|
|
||||||
point.x = bb.maxX;
|
|
||||||
point.y = bb.maxY;
|
|
||||||
point.z = bb.maxZ;
|
|
||||||
var transform:Transform3D = object.localToCameraTransform;
|
|
||||||
for (var i:int = 0; i < 8; i++) {
|
|
||||||
point = points[i];
|
|
||||||
var x:Number = transform.a*point.x + transform.b*point.y + transform.c*point.z + transform.d;
|
|
||||||
var y:Number = transform.e*point.x + transform.f*point.y + transform.g*point.z + transform.h;
|
|
||||||
var z:Number = transform.i*point.x + transform.j*point.y + transform.k*point.z + transform.l;
|
|
||||||
if (x < boundBox.minX) {
|
|
||||||
boundBox.minX = x;
|
|
||||||
}
|
|
||||||
if (x > boundBox.maxX) {
|
|
||||||
boundBox.maxX = x;
|
|
||||||
}
|
|
||||||
if (y < boundBox.minY) {
|
|
||||||
boundBox.minY = y;
|
|
||||||
}
|
|
||||||
if (y > boundBox.maxY) {
|
|
||||||
boundBox.maxY = y;
|
|
||||||
}
|
|
||||||
if (z < boundBox.minZ) {
|
|
||||||
boundBox.minZ = z;
|
|
||||||
}
|
|
||||||
if (z > boundBox.maxZ) {
|
|
||||||
boundBox.maxZ = z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hierarchy) {
|
|
||||||
// Пробегаемся по дочерним объектам
|
|
||||||
for (var child:Object3D = object.childrenList; child != null; child = child.next) {
|
|
||||||
if (child.visible) {
|
|
||||||
if (child.transformChanged) {
|
|
||||||
child.composeTransforms();
|
|
||||||
}
|
|
||||||
child.localToCameraTransform.combine(object.localToCameraTransform, child.transform);
|
|
||||||
calculateBoundBox(boundBox, child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var rawData:Vector.<Number> = new Vector.<Number>(16);
|
|
||||||
private function calculateShadowMapProjection(matrix:Matrix3D, uvMatrix:Matrix3D, frustumMinX:Number, frustumMinY:Number, frustumMinZ:Number, frustumMaxX:Number, frustumMaxY:Number, frustumMaxZ:Number):void {
|
|
||||||
// Считаем матрицу проецирования
|
|
||||||
rawData[0] = 2/(frustumMaxX - frustumMinX);
|
|
||||||
rawData[5] = 2/(frustumMaxY - frustumMinY);
|
|
||||||
rawData[10]= 1/(frustumMaxZ - frustumMinZ);
|
|
||||||
rawData[12] = (-0.5 * (frustumMaxX + frustumMinX) * rawData[0]);
|
|
||||||
rawData[13] = (-0.5 * (frustumMaxY + frustumMinY) * rawData[5]);
|
|
||||||
rawData[14]= -frustumMinZ/(frustumMaxZ - frustumMinZ);
|
|
||||||
rawData[15]= 1;
|
|
||||||
matrix.rawData = rawData;
|
|
||||||
|
|
||||||
rawData[0] = 1/((frustumMaxX - frustumMinX));
|
|
||||||
// if (useSingle) {
|
|
||||||
// rawData[5] = 1/((frustumMaxY - frustumMinY));
|
|
||||||
// } else {
|
|
||||||
rawData[5] = -1/((frustumMaxY - frustumMinY));
|
|
||||||
// }
|
|
||||||
rawData[12] = 0.5 - (0.5 * (frustumMaxX + frustumMinX) * rawData[0]);
|
|
||||||
rawData[13] = 0.5 - (0.5 * (frustumMaxY + frustumMinY) * rawData[5]);
|
|
||||||
uvMatrix.rawData = rawData;
|
|
||||||
}
|
|
||||||
|
|
||||||
override public function get debug():Boolean {
|
|
||||||
return _debug;
|
|
||||||
}
|
|
||||||
|
|
||||||
override public function set debug(value:Boolean):void {
|
|
||||||
_debug = value;
|
|
||||||
if (debugContainer != null) {
|
|
||||||
if (value) {
|
|
||||||
if (light != null) {
|
|
||||||
light.addChild(debugContainer);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (debugContainer._parent != null) {
|
|
||||||
debugContainer.removeFromParent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// private static const vShader:Procedure = initVShader(index);
|
|
||||||
private static function initVShader(index:int):Procedure {
|
|
||||||
var shader:Procedure = Procedure.compileFromArray([
|
|
||||||
// "m44 o0, a0, c0",
|
|
||||||
// Координата вершины в локальном пространстве
|
|
||||||
"m44 v0, a0, c4"
|
|
||||||
]);
|
|
||||||
shader.assignVariableName(VariableType.ATTRIBUTE, 0, "aPosition");
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 0, "cPROJ", 4);
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 4, "cTOSHADOW", 4);
|
|
||||||
shader.assignVariableName(VariableType.VARYING, 0, "vSHADOWSAMPLE");
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
// private static const multVShader:Procedure = initMultVShader();
|
|
||||||
// private static function initMultVShader():Procedure {
|
|
||||||
// var shader:Procedure = Procedure.compileFromArray([
|
|
||||||
// "m44 v0, a0, c0",
|
|
||||||
// ]);
|
|
||||||
// shader.assignVariableName(VariableType.ATTRIBUTE, 0, "aPOSITION");
|
|
||||||
// shader.assignVariableName(VariableType.CONSTANT, 0, "cTOSHADOW", 4);
|
|
||||||
// shader.assignVariableName(VariableType.VARYING, 0, "vSHADOWSAMPLE");
|
|
||||||
// return shader;
|
|
||||||
// }
|
|
||||||
// private static const fShader:Procedure = initFShader(false, false, index);
|
|
||||||
// private static const pcfFShader:Procedure = initFShader(false, true, index);
|
|
||||||
// i0 - input color
|
|
||||||
// o0 - shadowed result
|
|
||||||
// private static const multFShader:Procedure = initFShader(true, false, index);
|
|
||||||
// private static const pcfMultFShader:Procedure = initFShader(true, true, index);
|
|
||||||
private static function initFShader(mult:Boolean, usePCF:Boolean, index:int, grayScale:Boolean = false):Procedure {
|
|
||||||
var i:int;
|
|
||||||
var line:int = 0;
|
|
||||||
var shaderArr:Array = [];
|
|
||||||
var numPass:uint = (usePCF) ? 4 : 1;
|
|
||||||
for (i = 0; i < numPass; i++) {
|
|
||||||
// Расстояние
|
|
||||||
shaderArr[line++] = "mov t0.w, v0.z";
|
|
||||||
shaderArr[line++] = "mul t0.w, t0.w, c4.y"; // bias [0.99] * 255
|
|
||||||
|
|
||||||
if (usePCF) {
|
|
||||||
// Добавляем смещение
|
|
||||||
// shaderArr[line++] = "mul t1, c" + (i + 5).toString() + ", t0.w";
|
|
||||||
shaderArr[line++] = "add t1, v0, c" + (i + 5).toString() + "";
|
|
||||||
// shaderArr[line++] = "add t1, v0, c" + (i + 5).toString();
|
|
||||||
shaderArr[line++] = "tex t1, t1, s0 <2d,clamp,near,nomip>";
|
|
||||||
} else {
|
|
||||||
shaderArr[line++] = "tex t1, v0, s0 <2d,clamp,near,nomip>";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Восстанавливаем расстояние
|
|
||||||
shaderArr[line++] = "mul t1.w, t1.x, c4.x"; // * 255
|
|
||||||
shaderArr[line++] = "add t1.w, t1.w, t1.y";
|
|
||||||
|
|
||||||
// Перекрытие тенью
|
|
||||||
shaderArr[line++] = "sub t2.z, t1.w, t0.w";
|
|
||||||
shaderArr[line++] = "mul t2.z, t2.z, c4.z"; // smooth [10000]
|
|
||||||
shaderArr[line++] = "sat t2.z, t2.z";
|
|
||||||
|
|
||||||
// Добавляем маску и прозрачность, затем sat
|
|
||||||
// shaderArr[line++] = "add t2.z, t2.z, t1.z"; // маска тени
|
|
||||||
// shaderArr[line++] = "add t2.z, t2.z, c4.w"; // вес тени
|
|
||||||
shaderArr[line++] = "sat t2.z, t2.z";
|
|
||||||
|
|
||||||
if (usePCF) {
|
|
||||||
if (i == 0) {
|
|
||||||
shaderArr[line++] = "mov t2.x, t2.z";
|
|
||||||
} else {
|
|
||||||
shaderArr[line++] = "add t2.x, t2.x, t2.z";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (usePCF) {
|
|
||||||
shaderArr[line++] = "mul t2.z, t2.x, c5.w";
|
|
||||||
}
|
|
||||||
if (grayScale) {
|
|
||||||
shaderArr.push("mov o0.w, t2.z");
|
|
||||||
} else {
|
|
||||||
if (mult) {
|
|
||||||
shaderArr.push("mul t0.xyz, i0.xyz, t2.z");
|
|
||||||
shaderArr.push("mov t0.w, i0.w");
|
|
||||||
shaderArr.push("mov o0, t0");
|
|
||||||
} else {
|
|
||||||
shaderArr.push("mov t0, t2.z");
|
|
||||||
shaderArr.push("mov o0, t0");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var shader:Procedure = Procedure.compileFromArray(shaderArr, "StaticShadowMap");
|
|
||||||
shader.assignVariableName(VariableType.VARYING, 0, "vSHADOWSAMPLE");
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, 4, "cConstants", 1);
|
|
||||||
if (usePCF) {
|
|
||||||
for (i = 0; i < numPass; i++) {
|
|
||||||
shader.assignVariableName(VariableType.CONSTANT, i + 5, "cPCF" + i.toString(), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
shader.assignVariableName(VariableType.SAMPLER, 0, "sSHADOWMAP");
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
override public function getVShader(index:int = 0):Procedure {
|
|
||||||
return initVShader(index);
|
|
||||||
}
|
|
||||||
override public function getFShader(index:int = 0):Procedure {
|
|
||||||
return initFShader(false, (pcfOffset > 0), index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// override public function getMultFShader():Procedure {
|
|
||||||
// return (pcfOffset > 0) ? pcfMultFShader : multFShader;
|
|
||||||
// }
|
|
||||||
// override public function getMultVShader():Procedure {
|
|
||||||
// return multVShader;
|
|
||||||
// }
|
|
||||||
|
|
||||||
override public function getFIntensityShader():Procedure {
|
|
||||||
return initFShader(false, (pcfOffset > 0), 0, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static const objectToShadowMap:Transform3D = new Transform3D();
|
|
||||||
private static const objectToUVMap:Matrix3D = new Matrix3D();
|
|
||||||
override public function applyShader(drawUnit:DrawUnit, program:ShaderProgram, object:Object3D, camera:Camera3D, index:int = 0):void {
|
|
||||||
// Считаем матрицу перевода в лайт из объекта
|
|
||||||
|
|
||||||
objectToShadowMap.combine(camera.localToGlobalTransform, object.localToCameraTransform);
|
|
||||||
objectToShadowMap.append(globalToLight);
|
|
||||||
|
|
||||||
// objectToShadowMap.identity();
|
|
||||||
// objectToShadowMap.append(object.cameraMatrix);
|
|
||||||
// objectToShadowMap.append(camera.globalMatrix);
|
|
||||||
// objectToShadowMap.append(globalToLight);
|
|
||||||
|
|
||||||
// Получаем индекс шедоумапы
|
|
||||||
// var coords:Vector3D = objectToShadowMap.position;
|
|
||||||
var coords:Vector3D = new Vector3D(objectToShadowMap.d, objectToShadowMap.h, objectToShadowMap.l);
|
|
||||||
var xIndex:int = (coords.x - bounds.minX)/(bounds.maxX - bounds.minX)*partsShadowMaps.length;
|
|
||||||
|
|
||||||
xIndex = (xIndex < 0) ? 0 : ((xIndex >= partsShadowMaps.length) ? partsShadowMaps.length - 1 : xIndex);
|
|
||||||
var maps:Vector.<Texture> = partsShadowMaps[xIndex];
|
|
||||||
var matrices:Vector.<Matrix3D> = partsUVMatrices[xIndex];
|
|
||||||
|
|
||||||
var yIndex:int = (coords.y - bounds.minY)/(bounds.maxY - bounds.minY)*maps.length;
|
|
||||||
yIndex = (yIndex < 0) ? 0 : ((yIndex >= maps.length) ? maps.length - 1 : yIndex);
|
|
||||||
|
|
||||||
// trace(xIndex, yIndex);
|
|
||||||
|
|
||||||
var shadowMap:Texture = maps[yIndex];
|
|
||||||
var uvMatrix:Matrix3D = matrices[yIndex];
|
|
||||||
|
|
||||||
DirectionalShadowRenderer.copyMatrixFromTransform(objectToUVMap, objectToShadowMap);
|
|
||||||
objectToUVMap.append(uvMatrix);
|
|
||||||
objectToUVMap.transpose();
|
|
||||||
// objectToShadowMap.append(uvMatrix);
|
|
||||||
|
|
||||||
drawUnit.setVertexConstantsFromVector(program.vertexShader.getVariableIndex("cTOSHADOW"), objectToUVMap.rawData, 4);
|
|
||||||
drawUnit.setFragmentConstantsFromVector(program.fragmentShader.getVariableIndex("cConstants"), constants, 1);
|
|
||||||
if (pcfOffset > 0) {
|
|
||||||
drawUnit.setFragmentConstantsFromVector(program.fragmentShader.getVariableIndex("cPCF0"), pcfOffsets, pcfOffsets.length >> 2)
|
|
||||||
}
|
|
||||||
drawUnit.setTextureAt(program.fragmentShader.getVariableIndex("sSHADOWMAP"), shadowMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
// private static var program:LinkedProgram;
|
|
||||||
// private static var programPCF:LinkedProgram;
|
|
||||||
// private static function initMeshProgram(context:Context3D, usePCF:Boolean):LinkedProgram {
|
|
||||||
// var vLinker:Linker = new Linker(Context3DProgramType.VERTEX);
|
|
||||||
// vLinker.addShader(vShader);
|
|
||||||
//
|
|
||||||
// var fLinker:Linker = new Linker(Context3DProgramType.FRAGMENT);
|
|
||||||
// if (usePCF) {
|
|
||||||
// fLinker.addShader(pcfFShader);
|
|
||||||
// } else {
|
|
||||||
// fLinker.addShader(fShader);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// vLinker.setOppositeLinker(fLinker);
|
|
||||||
// fLinker.setOppositeLinker(vLinker);
|
|
||||||
//
|
|
||||||
//// trace("[VERTEX]");
|
|
||||||
//// trace(AgalUtils.disassemble(vLinker.getByteCode()));
|
|
||||||
//// trace("[FRAGMENT]");
|
|
||||||
//// trace(AgalUtils.disassemble(fLinker.getByteCode()));
|
|
||||||
//
|
|
||||||
// var result:LinkedProgram;
|
|
||||||
// if (usePCF) {
|
|
||||||
// programPCF = new LinkedProgram();
|
|
||||||
// result = programPCF;
|
|
||||||
// } else {
|
|
||||||
// program = new LinkedProgram();
|
|
||||||
// result = program;
|
|
||||||
// }
|
|
||||||
// result.vLinker = vLinker;
|
|
||||||
// result.fLinker = fLinker;
|
|
||||||
// result.program = context.createProgram();
|
|
||||||
// result.program.upload(vLinker.getByteCode(), fLinker.getByteCode());
|
|
||||||
//
|
|
||||||
// return result;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override public function drawShadow(mesh:Mesh, camera:Camera3D, texture:Texture):void {
|
|
||||||
// var context3d:Context3D = camera.view._context3d;
|
|
||||||
//
|
|
||||||
// var linkedProgram:LinkedProgram;
|
|
||||||
// if (pcfOffset > 0) {
|
|
||||||
// linkedProgram = (programPCF == null) ? initMeshProgram(context3d, true) : programPCF;
|
|
||||||
// } else {
|
|
||||||
// linkedProgram = (program == null) ? initMeshProgram(context3d, false) : program;
|
|
||||||
// }
|
|
||||||
// var vLinker:Linker = linkedProgram.vLinker;
|
|
||||||
// var fLinker:Linker = linkedProgram.fLinker;
|
|
||||||
// context3d.setProgram(linkedProgram.program);
|
|
||||||
//
|
|
||||||
// context3d.setVertexBufferAt(vLinker.getVariableIndex("aPOSITION"), mesh.geometry.vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
|
|
||||||
// context3d.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, vLinker.getVariableIndex("cPROJ"), mesh.projectionMatrix, true);
|
|
||||||
// applyShader(context3d, linkedProgram, mesh, camera);
|
|
||||||
// context3d.setVertexBufferAt(1, null);
|
|
||||||
//
|
|
||||||
// context3d.setCulling(Context3DTriangleFace.FRONT);
|
|
||||||
// context3d.drawTriangles(mesh.geometry.indexBuffer, 0, mesh.geometry.numTriangles);
|
|
||||||
//
|
|
||||||
// context3d.setVertexBufferAt(vLinker.getVariableIndex("aPOSITION"), null);
|
|
||||||
// context.setTextureAt(getTextureIndex(fLinker), texture);
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user