Sfoglia il codice sorgente

Adding Cell Shading Material
Adding way to compute custom lighting functions (computeCustomDiffuseLighting & computeCustomSpecularLighting) here used by cell material as example. Then added a way to keep the light intensity (ndl) in lightInfo structure following memory alignment

Julien Moreau-Mathis 8 anni fa
parent
commit
1f7fe81b6d

+ 10 - 0
Tools/Gulp/config.json

@@ -1033,6 +1033,16 @@
                     "../../materialsLibrary/src/custom/babylon.customMaterial.ts"
                 ], 
                 "output": "babylon.customMaterial.js"
+            },
+            {
+                "files": [
+                    "../../materialsLibrary/src/cell/babylon.cellMaterial.ts"
+                ],
+                "shaderFiles": [
+                    "../../materialsLibrary/src/cell/cell.vertex.fx",
+                    "../../materialsLibrary/src/cell/cell.fragment.fx"
+                ],
+                "output": "babylon.cellMaterial.js"
             }
         ],
         "build": {

+ 28 - 0
dist/preview release/materialsLibrary/babylon.cellMaterial.d.ts

@@ -0,0 +1,28 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    class CellMaterial extends PushMaterial {
+        private _diffuseTexture;
+        diffuseTexture: BaseTexture;
+        diffuseColor: Color3;
+        _computeHighLevel: boolean;
+        computeHighLevel: boolean;
+        private _disableLighting;
+        disableLighting: boolean;
+        private _maxSimultaneousLights;
+        maxSimultaneousLights: number;
+        private _worldViewProjectionMatrix;
+        private _scaledDiffuse;
+        private _renderId;
+        constructor(name: string, scene: Scene);
+        needAlphaBlending(): boolean;
+        needAlphaTesting(): boolean;
+        getAlphaTestTexture(): BaseTexture;
+        isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean;
+        bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void;
+        getAnimatables(): IAnimatable[];
+        dispose(forceDisposeEffect?: boolean): void;
+        clone(name: string): CellMaterial;
+        serialize(): any;
+        static Parse(source: any, scene: Scene, rootUrl: string): CellMaterial;
+    }
+}

File diff suppressed because it is too large
+ 276 - 0
dist/preview release/materialsLibrary/babylon.cellMaterial.js


File diff suppressed because it is too large
+ 1 - 0
dist/preview release/materialsLibrary/babylon.cellMaterial.min.js


+ 296 - 0
materialsLibrary/src/cell/babylon.cellMaterial.ts

@@ -0,0 +1,296 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON {
+    class CellMaterialDefines extends MaterialDefines {
+        public DIFFUSE = false;
+        public CLIPPLANE = false;
+        public ALPHATEST = false;
+        public POINTSIZE = false;
+        public FOG = false;
+        public NORMAL = false;
+        public UV1 = false;
+        public UV2 = false;
+        public VERTEXCOLOR = false;
+        public VERTEXALPHA = false;
+        public NUM_BONE_INFLUENCERS = 0;
+        public BonesPerMesh = 0;
+        public INSTANCES = false;
+        public NDOTL = true;
+        public CUSTOMUSERLIGHTING = true;
+        public CELLBASIC = true;
+
+        constructor() {
+            super();
+            this.rebuild();
+        }
+    }
+
+    export class CellMaterial extends PushMaterial {
+        @serializeAsTexture("diffuseTexture")
+        private _diffuseTexture: BaseTexture;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public diffuseTexture: BaseTexture;
+
+        @serializeAsColor3("diffuseColor")
+        public diffuseColor = new Color3(1, 1, 1);
+
+        @serialize("computeHighLevel")
+        public _computeHighLevel: boolean = false;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public computeHighLevel: boolean;
+        
+        @serialize("disableLighting")
+        private _disableLighting = false;
+        @expandToProperty("_markAllSubMeshesAsLightsDirty")
+        public disableLighting: boolean;   
+        
+        @serialize("maxSimultaneousLights")
+        private _maxSimultaneousLights = 4;
+        @expandToProperty("_markAllSubMeshesAsLightsDirty")
+        public maxSimultaneousLights: number; 
+
+        private _worldViewProjectionMatrix = Matrix.Zero();
+        private _scaledDiffuse = new Color3();
+        private _renderId: number;
+
+        constructor(name: string, scene: Scene) {
+            super(name, scene);
+        }
+
+        public needAlphaBlending(): boolean {
+            return (this.alpha < 1.0);
+        }
+
+        public needAlphaTesting(): boolean {
+            return false;
+        }
+
+        public getAlphaTestTexture(): BaseTexture {
+            return null;
+        }
+
+        // Methods   
+        public isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean {   
+            if (this.isFrozen) {
+                if (this._wasPreviouslyReady && subMesh.effect) {
+                    return true;
+                }
+            }
+
+            if (!subMesh._materialDefines) {
+                subMesh._materialDefines = new CellMaterialDefines();
+            }
+
+            var defines = <CellMaterialDefines>subMesh._materialDefines;
+            var scene = this.getScene();
+
+            if (!this.checkReadyOnEveryCall && subMesh.effect) {
+                if (this._renderId === scene.getRenderId()) {
+                    return true;
+                }
+            }
+
+            var engine = scene.getEngine();
+
+            // Textures
+            if (defines._areTexturesDirty) {
+                defines._needUVs = false;
+                if (scene.texturesEnabled) {
+                    if (this._diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
+                        if (!this._diffuseTexture.isReady()) {
+                            return false;
+                        } else {
+                            defines._needUVs = true;
+                            defines.DIFFUSE = true;
+                        }
+                    }                
+                }
+            }
+
+            // High level
+            defines.CELLBASIC = !this.computeHighLevel;
+
+            // Misc.
+            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+
+            // Lights
+            defines._needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
+
+            // Values that need to be evaluated on every frame
+            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances);
+            
+            // Attribs
+            MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
+
+            // Get correct effect      
+            if (defines.isDirty) {
+                defines.markAsProcessed();
+                scene.resetCachedMaterial();
+
+                // Fallbacks
+                var fallbacks = new EffectFallbacks();             
+                if (defines.FOG) {
+                    fallbacks.addFallback(1, "FOG");
+                }
+
+                MaterialHelper.HandleFallbacksForShadows(defines, fallbacks, this.maxSimultaneousLights);
+                
+                if (defines.NUM_BONE_INFLUENCERS > 0) {
+                    fallbacks.addCPUSkinningFallback(0, mesh);
+                }
+
+                //Attributes
+                var attribs = [VertexBuffer.PositionKind];
+
+                if (defines.NORMAL) {
+                    attribs.push(VertexBuffer.NormalKind);
+                }
+
+                if (defines.UV1) {
+                    attribs.push(VertexBuffer.UVKind);
+                }
+
+                if (defines.UV2) {
+                    attribs.push(VertexBuffer.UV2Kind);
+                }
+
+                if (defines.VERTEXCOLOR) {
+                    attribs.push(VertexBuffer.ColorKind);
+                }
+
+                MaterialHelper.PrepareAttributesForBones(attribs, mesh, defines, fallbacks);
+                MaterialHelper.PrepareAttributesForInstances(attribs, defines);
+
+                var shaderName = "cell";
+                var join = defines.toString();
+                var uniforms = ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vDiffuseColor",
+                                "vFogInfos", "vFogColor", "pointSize",
+                                "vDiffuseInfos", 
+                                "mBones",
+                                "vClipPlane", "diffuseMatrix", "depthValues"
+                ];
+                var samplers = ["diffuseSampler"];
+                var uniformBuffers = [];
+
+                MaterialHelper.PrepareUniformsAndSamplersList(<EffectCreationOptions>{
+                    uniformsNames: uniforms, 
+                    uniformBuffersNames: uniformBuffers,
+                    samplers: samplers, 
+                    defines: defines, 
+                    maxSimultaneousLights: this.maxSimultaneousLights
+                });
+                subMesh.setEffect(scene.getEngine().createEffect(shaderName,
+                    <EffectCreationOptions>{
+                        attributes: attribs,
+                        uniformsNames: uniforms,
+                        uniformBuffersNames: uniformBuffers,
+                        samplers: samplers,
+                        defines: join,
+                        fallbacks: fallbacks,
+                        onCompiled: this.onCompiled,
+                        onError: this.onError,
+                        indexParameters: { maxSimultaneousLights: this.maxSimultaneousLights - 1 }
+                    }, engine), defines);
+
+            }
+            if (!subMesh.effect.isReady()) {
+                return false;
+            }
+
+            this._renderId = scene.getRenderId();
+            this._wasPreviouslyReady = true;
+
+            return true;
+        }
+
+        public bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void {
+            var scene = this.getScene();
+
+            var defines = <CellMaterialDefines>subMesh._materialDefines;
+            if (!defines) {
+                return;
+            }
+
+            var effect = subMesh.effect;
+            this._activeEffect = effect;
+
+            // Matrices        
+            this.bindOnlyWorldMatrix(world);
+            this._activeEffect.setMatrix("viewProjection", scene.getTransformMatrix());
+
+            // Bones
+            MaterialHelper.BindBonesParameters(mesh, this._activeEffect);
+
+            if (this._mustRebind(scene, effect)) {
+                // Textures        
+                if (this._diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
+                    this._activeEffect.setTexture("diffuseSampler", this._diffuseTexture);
+
+                    this._activeEffect.setFloat2("vDiffuseInfos", this._diffuseTexture.coordinatesIndex, this._diffuseTexture.level);
+                    this._activeEffect.setMatrix("diffuseMatrix", this._diffuseTexture.getTextureMatrix());
+                }
+                
+                // Clip plane
+                MaterialHelper.BindClipPlane(this._activeEffect, scene);
+
+                // Point size
+                if (this.pointsCloud) {
+                    this._activeEffect.setFloat("pointSize", this.pointSize);
+                }
+
+                this._activeEffect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);                
+            }
+
+            this._activeEffect.setColor4("vDiffuseColor", this.diffuseColor, this.alpha * mesh.visibility);
+
+            // Lights
+            if (scene.lightsEnabled && !this.disableLighting) {
+                MaterialHelper.BindLights(scene, mesh, this._activeEffect, defines, this._maxSimultaneousLights);          
+            }
+
+            // View
+            if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
+                this._activeEffect.setMatrix("view", scene.getViewMatrix());
+            }
+
+            // Fog
+            MaterialHelper.BindFogParameters(scene, mesh, this._activeEffect);
+
+            this._afterBind(mesh, this._activeEffect);
+        }
+
+        public getAnimatables(): IAnimatable[] {
+            var results = [];
+
+            if (this._diffuseTexture && this._diffuseTexture.animations && this._diffuseTexture.animations.length > 0) {
+                results.push(this._diffuseTexture);
+            }
+
+            return results;
+        }
+
+        public dispose(forceDisposeEffect?: boolean): void {
+            if (this._diffuseTexture) {
+                this._diffuseTexture.dispose();
+            }
+
+            super.dispose(forceDisposeEffect);
+        }
+
+        public clone(name: string): CellMaterial {
+            return SerializationHelper.Clone<CellMaterial>(() => new CellMaterial(name, this.getScene()), this);
+        }
+        
+        public serialize(): any {
+            var serializationObject = SerializationHelper.Serialize(this);
+            serializationObject.customType = "BABYLON.CellMaterial";
+            return serializationObject;
+        }
+
+        // Statics
+        public static Parse(source: any, scene: Scene, rootUrl: string): CellMaterial {
+            return SerializationHelper.Parse(() => new CellMaterial(source.name, scene), source, scene, rootUrl);
+        }
+    }
+} 
+

+ 144 - 0
materialsLibrary/src/cell/cell.fragment.fx

@@ -0,0 +1,144 @@
+precision highp float;
+
+// Constants
+uniform vec3 vEyePosition;
+uniform vec4 vDiffuseColor;
+
+// Input
+varying vec3 vPositionW;
+
+#ifdef NORMAL
+varying vec3 vNormalW;
+#endif
+
+#ifdef VERTEXCOLOR
+varying vec4 vColor;
+#endif
+
+// Lights
+#include<__decl__lightFragment>[0..maxSimultaneousLights]
+
+#include<lightsFragmentFunctions>
+#include<shadowsFragmentFunctions>
+
+// Samplers
+#ifdef DIFFUSE
+varying vec2 vDiffuseUV;
+uniform sampler2D diffuseSampler;
+uniform vec2 vDiffuseInfos;
+#endif
+
+#include<clipPlaneFragmentDeclaration>
+
+// Fog
+#include<fogFragmentDeclaration>
+
+// Custom
+vec3 computeCustomDiffuseLighting(lightingInfo info, vec3 diffuseBase, float shadow)
+{
+	diffuseBase = info.diffuse * shadow;
+
+#ifdef CELLBASIC
+	float level = 1.0;
+	if (info.ndl < 0.5)
+		level = 0.5;
+	
+	diffuseBase.rgb * vec3(level, level, level);
+#else
+	float ToonThresholds[4];
+	ToonThresholds[0] = 0.95;
+	ToonThresholds[1] = 0.5;
+	ToonThresholds[2] = 0.2;
+	ToonThresholds[3] = 0.03;
+
+	float ToonBrightnessLevels[5];
+	ToonBrightnessLevels[0] = 1.0;
+	ToonBrightnessLevels[1] = 0.8;
+	ToonBrightnessLevels[2] = 0.6;
+	ToonBrightnessLevels[3] = 0.35;
+	ToonBrightnessLevels[4] = 0.2;
+
+	if (info.ndl > ToonThresholds[0])
+	{
+		diffuseBase.rgb *= ToonBrightnessLevels[0];
+	}
+	else if (info.ndl > ToonThresholds[1])
+	{
+		diffuseBase.rgb *= ToonBrightnessLevels[1];
+	}
+	else if (info.ndl > ToonThresholds[2])
+	{
+		diffuseBase.rgb *= ToonBrightnessLevels[2];
+	}
+	else if (info.ndl > ToonThresholds[3])
+	{
+		diffuseBase.rgb *= ToonBrightnessLevels[3];
+	}
+	else
+	{
+		diffuseBase.rgb *= ToonBrightnessLevels[4];
+	}
+#endif
+
+	return max(diffuseBase, vec3(0.2));
+}
+
+void main(void)
+{
+#include<clipPlaneFragment>
+
+	vec3 viewDirectionW = normalize(vEyePosition - vPositionW);
+
+	// Base color
+	vec4 baseColor = vec4(1., 1., 1., 1.);
+	vec3 diffuseColor = vDiffuseColor.rgb;
+
+	// Alpha
+	float alpha = vDiffuseColor.a;
+
+#ifdef DIFFUSE
+	baseColor = texture2D(diffuseSampler, vDiffuseUV);
+
+#ifdef ALPHATEST
+	if (baseColor.a < 0.4)
+		discard;
+#endif
+
+	baseColor.rgb *= vDiffuseInfos.y;
+#endif
+
+#ifdef VERTEXCOLOR
+	baseColor.rgb *= vColor.rgb;
+#endif
+
+	// Normal
+#ifdef NORMAL
+	vec3 normalW = normalize(vNormalW);
+#else
+	vec3 normalW = vec3(1.0, 1.0, 1.0);
+#endif
+
+	// Lighting
+    lightingInfo info;
+	vec3 diffuseBase = vec3(0., 0., 0.);
+	float shadow = 1.;
+    float glossiness = 0.;
+
+#ifdef SPECULARTERM
+	vec3 specularBase = vec3(0., 0., 0.);
+#endif    
+#include<lightFragment>[0..maxSimultaneousLights]
+
+#ifdef VERTEXALPHA
+	alpha *= vColor.a;
+#endif
+
+	vec3 finalDiffuse = clamp(diffuseBase * diffuseColor, 0.0, 1.0) * baseColor.rgb;;
+
+	// Composition
+	vec4 color = vec4(finalDiffuse, alpha);
+
+#include<fogFragment>
+
+	gl_FragColor = color;
+}

+ 101 - 0
materialsLibrary/src/cell/cell.vertex.fx

@@ -0,0 +1,101 @@
+precision highp float;
+
+// Attributes
+attribute vec3 position;
+#ifdef NORMAL
+attribute vec3 normal;
+#endif
+#ifdef UV1
+attribute vec2 uv;
+#endif
+#ifdef UV2
+attribute vec2 uv2;
+#endif
+#ifdef VERTEXCOLOR
+attribute vec4 color;
+#endif
+
+#include<bonesDeclaration>
+
+// Uniforms
+#include<instancesDeclaration>
+
+uniform mat4 view;
+uniform mat4 viewProjection;
+
+#ifdef DIFFUSE
+varying vec2 vDiffuseUV;
+uniform mat4 diffuseMatrix;
+uniform vec2 vDiffuseInfos;
+#endif
+
+#ifdef POINTSIZE
+uniform float pointSize;
+#endif
+
+// Output
+varying vec3 vPositionW;
+#ifdef NORMAL
+varying vec3 vNormalW;
+#endif
+
+#ifdef VERTEXCOLOR
+varying vec4 vColor;
+#endif
+
+
+#include<clipPlaneVertexDeclaration>
+
+#include<fogVertexDeclaration>
+#include<shadowsVertexDeclaration>[0..maxSimultaneousLights]
+
+void main(void) {
+
+#include<instancesVertex>
+#include<bonesVertex>
+
+	gl_Position = viewProjection * finalWorld * vec4(position, 1.0);
+
+	vec4 worldPos = finalWorld * vec4(position, 1.0);
+	vPositionW = vec3(worldPos);
+
+#ifdef NORMAL
+	vNormalW = normalize(vec3(finalWorld * vec4(normal, 0.0)));
+#endif
+
+	// Texture coordinates
+#ifndef UV1
+	vec2 uv = vec2(0., 0.);
+#endif
+#ifndef UV2
+	vec2 uv2 = vec2(0., 0.);
+#endif
+
+#ifdef DIFFUSE
+	if (vDiffuseInfos.x == 0.)
+	{
+		vDiffuseUV = vec2(diffuseMatrix * vec4(uv, 1.0, 0.0));
+	}
+	else
+	{
+		vDiffuseUV = vec2(diffuseMatrix * vec4(uv2, 1.0, 0.0));
+	}
+#endif
+
+	// Clip plane
+#include<clipPlaneVertex>
+
+    // Fog
+#include<fogVertex>
+#include<shadowsVertex>[0..maxSimultaneousLights]
+
+	// Vertex color
+#ifdef VERTEXCOLOR
+	vColor = color;
+#endif
+
+	// Point size
+#ifdef POINTSIZE
+	gl_PointSize = pointSize;
+#endif
+}

+ 6 - 1
src/Shaders/ShadersInclude/lightFragment.fx

@@ -37,7 +37,12 @@
 	#else
 		shadow = 1.;
 	#endif
-    #if defined(LIGHTMAP) && defined(LIGHTMAPEXCLUDED{X})
+	#ifdef CUSTOMUSERLIGHTING
+		diffuseBase += computeCustomDiffuseLighting(info, diffuseBase, shadow);
+		#ifdef SPECULARTERM
+			specularBase += computeCustomSpecularLighting(info, specularBase, shadow);
+		#endif
+    #elif defined(LIGHTMAP) && defined(LIGHTMAPEXCLUDED{X})
 	    diffuseBase += lightmapColor * shadow;
 	    #ifdef SPECULARTERM
             #ifndef LIGHTMAPNOSPECULAR{X}

+ 17 - 0
src/Shaders/ShadersInclude/lightsFragmentFunctions.fx

@@ -5,6 +5,9 @@ struct lightingInfo
 #ifdef SPECULARTERM
 	vec3 specular;
 #endif
+#ifdef NDOTL
+	float ndl;
+#endif
 };
 
 lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float range, float glossiness) {
@@ -26,6 +29,10 @@ lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData,
 
 	// diffuse
 	float ndl = max(0., dot(vNormal, lightVectorW));
+#ifdef NDOTL
+	result.ndl = ndl;
+#endif
+
 	result.diffuse = ndl * diffuseColor * attenuation;
 
 #ifdef SPECULARTERM
@@ -56,6 +63,9 @@ lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightDa
 
 		// Diffuse
 		float ndl = max(0., dot(vNormal, lightVectorW));
+#ifdef NDOTL
+		result.ndl = ndl;
+#endif
 		result.diffuse = ndl * diffuseColor * attenuation;
 
 #ifdef SPECULARTERM
@@ -73,6 +83,9 @@ lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightDa
 #ifdef SPECULARTERM
 	result.specular = vec3(0.);
 #endif
+#ifdef NDOTL
+	result.ndl = 0.;
+#endif
 
 	return result;
 }
@@ -82,6 +95,10 @@ lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4
 
 	// Diffuse
 	float ndl = dot(vNormal, lightData.xyz) * 0.5 + 0.5;
+#ifdef NDOTL
+	result.ndl = ndl;
+#endif
+
 	result.diffuse = mix(groundColor, diffuseColor, ndl);
 
 #ifdef SPECULARTERM