awayjs-display
Version:
AwayJS displaylist classes
215 lines (178 loc) • 5.82 kB
text/typescript
import Image2D from "awayjs-core/lib/image/Image2D";
import Matrix3D from "awayjs-core/lib/geom/Matrix3D";
import Matrix3DUtils from "awayjs-core/lib/geom/Matrix3DUtils";
import Plane3D from "awayjs-core/lib/geom/Plane3D";
import Vector3D from "awayjs-core/lib/geom/Vector3D";
import FreeMatrixProjection from "awayjs-core/lib/projections/FreeMatrixProjection";
import Scene from "../../display/Scene";
import IRenderer from "../../IRenderer";
import Camera from "../../display/Camera";
import DirectionalLight from "../../display/DirectionalLight";
import ShadowMapperBase from "../../materials/shadowmappers/ShadowMapperBase";
import Single2DTexture from "../../textures/Single2DTexture";
class DirectionalShadowMapper extends ShadowMapperBase
{
public _pOverallDepthCamera:Camera;
public _pLocalFrustum:Array<number>;
public _pLightOffset:number = 10000;
public _pMatrix:Matrix3D;
public _pOverallDepthProjection:FreeMatrixProjection;
public _pSnap:number = 64;
public _pCullPlanes:Array<Plane3D>;
public _pMinZ:number;
public _pMaxZ:number;
constructor()
{
super();
this._pCullPlanes = [];
this._pOverallDepthProjection = new FreeMatrixProjection();
this._pOverallDepthCamera = new Camera(this._pOverallDepthProjection);
this._pLocalFrustum = [];
this._pMatrix = new Matrix3D();
}
public get snap():number
{
return this._pSnap;
}
public set snap(value:number)
{
this._pSnap = value;
}
public get lightOffset():number
{
return this._pLightOffset;
}
public set lightOffset(value:number)
{
this._pLightOffset = value;
}
//@arcane
public get iDepthProjection():Matrix3D
{
return this._pOverallDepthCamera.viewProjection;
}
//@arcane
public get depth():number
{
return this._pMaxZ - this._pMinZ;
}
public iSetDepthMap(depthMap:Single2DTexture)
{
if (this._depthMap == depthMap)
return;
super.iSetDepthMap(depthMap);
if (this._depthMap) {
this._explicitDepthMap = true;
this._pDepthMapSize = depthMap.image2D.rect.width;
} else {
this._explicitDepthMap = false;
}
}
public pCreateDepthTexture():Single2DTexture
{
return new Single2DTexture(new Image2D(this._pDepthMapSize, this._pDepthMapSize));
}
//@override
public pDrawDepthMap(scene:Scene, target:Single2DTexture, renderer:IRenderer)
{
renderer.cullPlanes = this._pCullPlanes;
renderer._iRender(this._pOverallDepthCamera, scene, target.image2D);
}
//@protected
public pUpdateCullPlanes(camera:Camera)
{
var lightFrustumPlanes:Array<Plane3D> = this._pOverallDepthCamera.frustumPlanes;
var viewFrustumPlanes:Array<Plane3D> = camera.frustumPlanes;
this._pCullPlanes.length = 4;
this._pCullPlanes[0] = lightFrustumPlanes[0];
this._pCullPlanes[1] = lightFrustumPlanes[1];
this._pCullPlanes[2] = lightFrustumPlanes[2];
this._pCullPlanes[3] = lightFrustumPlanes[3];
var light:DirectionalLight = <DirectionalLight> this._pLight;
var dir:Vector3D = light.sceneDirection;
var dirX:number = dir.x;
var dirY:number = dir.y;
var dirZ:number = dir.z;
var j:number = 4;
for (var i:number = 0; i < 6; ++i) {
var plane:Plane3D = viewFrustumPlanes[i];
if (plane.a*dirX + plane.b*dirY + plane.c*dirZ < 0)
this._pCullPlanes[j++] = plane;
}
}
//@override
public pUpdateDepthProjection(camera:Camera)
{
this.pUpdateProjectionFromFrustumCorners(camera, camera.projection.frustumCorners, this._pMatrix);
this._pOverallDepthProjection.matrix = this._pMatrix;
this.pUpdateCullPlanes(camera);
}
public pUpdateProjectionFromFrustumCorners(camera:Camera, corners:Array<number>, matrix:Matrix3D)
{
var raw:Float32Array = Matrix3DUtils.RAW_DATA_CONTAINER;
var dir:Vector3D;
var x:number, y:number, z:number;
var minX:number, minY:number;
var maxX:number, maxY:number;
var i:number;
var light:DirectionalLight = <DirectionalLight> this._pLight;
dir = light.sceneDirection;
this._pOverallDepthCamera.transform.matrix3D = this._pLight.sceneTransform;
x = Math.floor((camera.x - dir.x*this._pLightOffset)/this._pSnap)*this._pSnap;
y = Math.floor((camera.y - dir.y*this._pLightOffset)/this._pSnap)*this._pSnap;
z = Math.floor((camera.z - dir.z*this._pLightOffset)/this._pSnap)*this._pSnap;
this._pOverallDepthCamera.x = x;
this._pOverallDepthCamera.y = y;
this._pOverallDepthCamera.z = z;
this._pMatrix.copyFrom(this._pOverallDepthCamera.inverseSceneTransform);
this._pMatrix.prepend(camera.sceneTransform);
this._pMatrix.transformVectors(corners, this._pLocalFrustum);
minX = maxX = this._pLocalFrustum[0];
minY = maxY = this._pLocalFrustum[1];
this._pMaxZ = this._pLocalFrustum[2];
i = 3;
while (i < 24) {
x = this._pLocalFrustum[i];
y = this._pLocalFrustum[i + 1];
z = this._pLocalFrustum[i + 2];
if (x < minX)
minX = x;
if (x > maxX)
maxX = x;
if (y < minY)
minY = y;
if (y > maxY)
maxY = y;
if (z > this._pMaxZ)
this._pMaxZ = z;
i += 3;
}
this._pMinZ = 1;
var w:number = maxX - minX;
var h:number = maxY - minY;
var d:number = 1/(this._pMaxZ - this._pMinZ);
if (minX < 0)
minX -= this._pSnap; // because int() rounds up for < 0
if (minY < 0)
minY -= this._pSnap;
minX = Math.floor(minX/this._pSnap)*this._pSnap;
minY = Math.floor(minY/this._pSnap)*this._pSnap;
var snap2:number = 2*this._pSnap;
w = Math.floor(w/snap2 + 2)*snap2;
h = Math.floor(h/snap2 + 2)*snap2;
maxX = minX + w;
maxY = minY + h;
w = 1/w;
h = 1/h;
raw[0] = 2*w;
raw[5] = 2*h;
raw[10] = d;
raw[12] = -(maxX + minX)*w;
raw[13] = -(maxY + minY)*h;
raw[14] = -this._pMinZ*d;
raw[15] = 1;
raw[1] = raw[2] = raw[3] = raw[4] = raw[6] = raw[7] = raw[8] = raw[9] = raw[11] = 0;
matrix.copyRawDataFrom(raw);
}
}
export default DirectionalShadowMapper;