|
@@ -0,0 +1,240 @@
|
|
|
|
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
|
|
|
|
+
|
|
|
|
+module BABYLON {
|
|
|
|
+ class ShadowOnlyMaterialDefines extends MaterialDefines {
|
|
|
|
+ public CLIPPLANE = false;
|
|
|
|
+ public POINTSIZE = false;
|
|
|
|
+ public FOG = false;
|
|
|
|
+ public NORMAL = false;
|
|
|
|
+ public NUM_BONE_INFLUENCERS = 0;
|
|
|
|
+ public BonesPerMesh = 0;
|
|
|
|
+ public INSTANCES = false;
|
|
|
|
+
|
|
|
|
+ constructor() {
|
|
|
|
+ super();
|
|
|
|
+ this.rebuild();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ export class ShadowOnlyMaterial extends Material {
|
|
|
|
+ @serialize()
|
|
|
|
+
|
|
|
|
+ private _worldViewProjectionMatrix = Matrix.Zero();
|
|
|
|
+ private _scaledDiffuse = new Color3();
|
|
|
|
+ private _renderId: number;
|
|
|
|
+
|
|
|
|
+ private _defines = new ShadowOnlyMaterialDefines();
|
|
|
|
+ private _cachedDefines = new ShadowOnlyMaterialDefines();
|
|
|
|
+
|
|
|
|
+ constructor(name: string, scene: Scene) {
|
|
|
|
+ super(name, scene);
|
|
|
|
+
|
|
|
|
+ this._cachedDefines.BonesPerMesh = -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public needAlphaBlending(): boolean {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public needAlphaTesting(): boolean {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public getAlphaTestTexture(): BaseTexture {
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Methods
|
|
|
|
+ private _checkCache(scene: Scene, mesh?: AbstractMesh, useInstances?: boolean): boolean {
|
|
|
|
+ if (!mesh) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (this._defines.INSTANCES !== useInstances) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (mesh._materialDefines && mesh._materialDefines.isEqual(this._defines)) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
|
|
|
|
+ if (this.checkReadyOnlyOnce) {
|
|
|
|
+ if (this._wasPreviouslyReady) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var scene = this.getScene();
|
|
|
|
+
|
|
|
|
+ if (!this.checkReadyOnEveryCall) {
|
|
|
|
+ if (this._renderId === scene.getRenderId()) {
|
|
|
|
+ if (this._checkCache(scene, mesh, useInstances)) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var engine = scene.getEngine();
|
|
|
|
+ var needNormals = false;
|
|
|
|
+
|
|
|
|
+ this._defines.reset();
|
|
|
|
+
|
|
|
|
+ // Effect
|
|
|
|
+ if (scene.clipPlane) {
|
|
|
|
+ this._defines.CLIPPLANE = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Point size
|
|
|
|
+ if (this.pointsCloud || scene.forcePointsCloud) {
|
|
|
|
+ this._defines.POINTSIZE = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Fog
|
|
|
|
+ if (scene.fogEnabled && mesh && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE && this.fogEnabled) {
|
|
|
|
+ this._defines.FOG = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (scene.lightsEnabled) {
|
|
|
|
+ needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, this._defines, 1);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Attribs
|
|
|
|
+ if (mesh) {
|
|
|
|
+ if (needNormals && mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
|
|
|
|
+ this._defines.NORMAL = true;
|
|
|
|
+ }
|
|
|
|
+ if (mesh.useBones && mesh.computeBonesUsingShaders) {
|
|
|
|
+ this._defines.NUM_BONE_INFLUENCERS = mesh.numBoneInfluencers;
|
|
|
|
+ this._defines.BonesPerMesh = (mesh.skeleton.bones.length + 1);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Instances
|
|
|
|
+ if (useInstances) {
|
|
|
|
+ this._defines.INSTANCES = true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Get correct effect
|
|
|
|
+ if (!this._defines.isEqual(this._cachedDefines)) {
|
|
|
|
+ this._defines.cloneTo(this._cachedDefines);
|
|
|
|
+
|
|
|
|
+ scene.resetCachedMaterial();
|
|
|
|
+
|
|
|
|
+ // Fallbacks
|
|
|
|
+ var fallbacks = new EffectFallbacks();
|
|
|
|
+ if (this._defines.FOG) {
|
|
|
|
+ fallbacks.addFallback(1, "FOG");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ MaterialHelper.HandleFallbacksForShadows(this._defines, fallbacks, 1);
|
|
|
|
+
|
|
|
|
+ if (this._defines.NUM_BONE_INFLUENCERS > 0) {
|
|
|
|
+ fallbacks.addCPUSkinningFallback(0, mesh);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //Attributes
|
|
|
|
+ var attribs = [VertexBuffer.PositionKind];
|
|
|
|
+
|
|
|
|
+ if (this._defines.NORMAL) {
|
|
|
|
+ attribs.push(VertexBuffer.NormalKind);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ MaterialHelper.PrepareAttributesForBones(attribs, mesh, this._defines, fallbacks);
|
|
|
|
+ MaterialHelper.PrepareAttributesForInstances(attribs, this._defines);
|
|
|
|
+
|
|
|
|
+ var shaderName = "shadowOnly";
|
|
|
|
+ var join = this._defines.toString();
|
|
|
|
+ var uniforms = ["world", "view", "viewProjection", "vEyePosition", "vLightsType",
|
|
|
|
+ "vFogInfos", "vFogColor", "pointSize",
|
|
|
|
+ "mBones",
|
|
|
|
+ "vClipPlane", "depthValues"
|
|
|
|
+ ];
|
|
|
|
+ var samplers = [];
|
|
|
|
+
|
|
|
|
+ MaterialHelper.PrepareUniformsAndSamplersList(uniforms, samplers, this._defines, 1);
|
|
|
|
+
|
|
|
|
+ this._effect = scene.getEngine().createEffect(shaderName,
|
|
|
|
+ attribs, uniforms, samplers,
|
|
|
|
+ join, fallbacks, this.onCompiled, this.onError, {maxSimultaneousLights: 1});
|
|
|
|
+ }
|
|
|
|
+ if (!this._effect.isReady()) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this._renderId = scene.getRenderId();
|
|
|
|
+ this._wasPreviouslyReady = true;
|
|
|
|
+
|
|
|
|
+ if (mesh) {
|
|
|
|
+ if (!mesh._materialDefines) {
|
|
|
|
+ mesh._materialDefines = new ShadowOnlyMaterialDefines();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this._defines.cloneTo(mesh._materialDefines);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public bindOnlyWorldMatrix(world: Matrix): void {
|
|
|
|
+ this._effect.setMatrix("world", world);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public bind(world: Matrix, mesh?: Mesh): void {
|
|
|
|
+ var scene = this.getScene();
|
|
|
|
+
|
|
|
|
+ // Matrices
|
|
|
|
+ this.bindOnlyWorldMatrix(world);
|
|
|
|
+ this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
|
|
|
|
+
|
|
|
|
+ // Bones
|
|
|
|
+ MaterialHelper.BindBonesParameters(mesh, this._effect);
|
|
|
|
+
|
|
|
|
+ if (scene.getCachedMaterial() !== this) {
|
|
|
|
+ // Clip plane
|
|
|
|
+ MaterialHelper.BindClipPlane(this._effect, scene);
|
|
|
|
+
|
|
|
|
+ // Point size
|
|
|
|
+ if (this.pointsCloud) {
|
|
|
|
+ this._effect.setFloat("pointSize", this.pointSize);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this._effect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Lights
|
|
|
|
+ if (scene.lightsEnabled) {
|
|
|
|
+ MaterialHelper.BindLights(scene, mesh, this._effect, this._defines, 1);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // View
|
|
|
|
+ if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
|
|
|
|
+ this._effect.setMatrix("view", scene.getViewMatrix());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Fog
|
|
|
|
+ MaterialHelper.BindFogParameters(scene, mesh, this._effect);
|
|
|
|
+
|
|
|
|
+ super.bind(world, mesh);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public clone(name: string): ShadowOnlyMaterial {
|
|
|
|
+ return SerializationHelper.Clone<ShadowOnlyMaterial>(() => new ShadowOnlyMaterial(name, this.getScene()), this);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public serialize(): any {
|
|
|
|
+ var serializationObject = SerializationHelper.Serialize(this);
|
|
|
|
+ serializationObject.customType = "BABYLON.ShadowOnlyMaterial";
|
|
|
|
+ return serializationObject;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Statics
|
|
|
|
+ public static Parse(source: any, scene: Scene, rootUrl: string): ShadowOnlyMaterial {
|
|
|
|
+ return SerializationHelper.Parse(() => new ShadowOnlyMaterial(source.name, scene), source, scene, rootUrl);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|