UNPKG

@babylonjs/materials

Version:

Babylon.js Materials Library =====================

505 lines 20.5 kB
import { __decorate } from "@babylonjs/core/tslib.es6.js"; import { serializeAsVector3, serializeAsTexture, serialize, expandToProperty, serializeAsColor3 } from "@babylonjs/core/Misc/decorators.js"; import { SerializationHelper } from "@babylonjs/core/Misc/decorators.serialization.js"; import { Vector3 } from "@babylonjs/core/Maths/math.vector.js"; import { Color3 } from "@babylonjs/core/Maths/math.color.js"; import { Tags } from "@babylonjs/core/Misc/tags.js"; import { Texture } from "@babylonjs/core/Materials/Textures/texture.js"; import { DynamicTexture } from "@babylonjs/core/Materials/Textures/dynamicTexture.js"; import { MaterialDefines } from "@babylonjs/core/Materials/materialDefines.js"; import { PushMaterial } from "@babylonjs/core/Materials/pushMaterial.js"; import { MaterialFlags } from "@babylonjs/core/Materials/materialFlags.js"; import { VertexBuffer } from "@babylonjs/core/Buffers/buffer.js"; import { Scene } from "@babylonjs/core/scene.js"; import { RegisterClass } from "@babylonjs/core/Misc/typeStore.js"; import { EffectFallbacks } from "@babylonjs/core/Materials/effectFallbacks.js"; import "./fur.fragment.js"; import "./fur.vertex.js"; import { addClipPlaneUniforms, bindClipPlane } from "@babylonjs/core/Materials/clipPlaneMaterialHelper.js"; import { BindBonesParameters, BindFogParameters, BindLights, BindLogDepth, HandleFallbacksForShadows, PrepareAttributesForBones, PrepareAttributesForInstances, PrepareDefinesForAttributes, PrepareDefinesForFrameBoundValues, PrepareDefinesForLights, PrepareDefinesForMisc, PrepareUniformsAndSamplersList, } from "@babylonjs/core/Materials/materialHelper.functions.js"; class FurMaterialDefines extends MaterialDefines { constructor() { super(); this.DIFFUSE = false; this.HEIGHTMAP = false; this.CLIPPLANE = false; this.CLIPPLANE2 = false; this.CLIPPLANE3 = false; this.CLIPPLANE4 = false; this.CLIPPLANE5 = false; this.CLIPPLANE6 = false; this.ALPHATEST = false; this.DEPTHPREPASS = false; this.POINTSIZE = false; this.FOG = false; this.NORMAL = false; this.UV1 = false; this.UV2 = false; this.VERTEXCOLOR = false; this.VERTEXALPHA = false; this.NUM_BONE_INFLUENCERS = 0; this.BonesPerMesh = 0; this.INSTANCES = false; this.INSTANCESCOLOR = false; this.HIGHLEVEL = false; this.IMAGEPROCESSINGPOSTPROCESS = false; this.SKIPFINALCOLORCLAMP = false; this.LOGARITHMICDEPTH = false; this.AREALIGHTSUPPORTED = true; this.AREALIGHTNOROUGHTNESS = true; this.rebuild(); } } export class FurMaterial extends PushMaterial { constructor(name, scene) { super(name, scene); this.diffuseColor = new Color3(1, 1, 1); this.furLength = 1; this.furAngle = 0; this.furColor = new Color3(0.44, 0.21, 0.02); this.furOffset = 0.0; this.furSpacing = 12; this.furGravity = new Vector3(0, 0, 0); this.furSpeed = 100; this.furDensity = 20; this.furOcclusion = 0.0; this._disableLighting = false; this._maxSimultaneousLights = 4; this.highLevelFur = true; this._furTime = 0; } get furTime() { return this._furTime; } set furTime(furTime) { this._furTime = furTime; } needAlphaBlending() { return this.alpha < 1.0; } needAlphaTesting() { return false; } getAlphaTestTexture() { return null; } updateFur() { for (let i = 1; i < this._meshes.length; i++) { const offsetFur = this._meshes[i].material; offsetFur.furLength = this.furLength; offsetFur.furAngle = this.furAngle; offsetFur.furGravity = this.furGravity; offsetFur.furSpacing = this.furSpacing; offsetFur.furSpeed = this.furSpeed; offsetFur.furColor = this.furColor; offsetFur.diffuseTexture = this.diffuseTexture; offsetFur.furTexture = this.furTexture; offsetFur.highLevelFur = this.highLevelFur; offsetFur.furTime = this.furTime; offsetFur.furDensity = this.furDensity; } } // Methods isReadyForSubMesh(mesh, subMesh, useInstances) { const drawWrapper = subMesh._drawWrapper; if (this.isFrozen) { if (drawWrapper.effect && drawWrapper._wasPreviouslyReady && drawWrapper._wasPreviouslyUsingInstances === useInstances) { return true; } } if (!subMesh.materialDefines) { subMesh.materialDefines = new FurMaterialDefines(); } const defines = subMesh.materialDefines; const scene = this.getScene(); if (this._isReadyForSubMesh(subMesh)) { return true; } const engine = scene.getEngine(); // Textures if (defines._areTexturesDirty) { if (scene.texturesEnabled) { if (this.diffuseTexture && MaterialFlags.DiffuseTextureEnabled) { if (!this.diffuseTexture.isReady()) { return false; } else { defines._needUVs = true; defines.DIFFUSE = true; } } if (this.heightTexture && engine.getCaps().maxVertexTextureImageUnits) { if (!this.heightTexture.isReady()) { return false; } else { defines._needUVs = true; defines.HEIGHTMAP = true; } } } } // High level if (this.highLevelFur !== defines.HIGHLEVEL) { defines.HIGHLEVEL = true; defines.markAsUnprocessed(); } // Misc. PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this.needAlphaTestingForMesh(mesh), defines); // Lights defines._needNormals = PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting); // Values that need to be evaluated on every frame PrepareDefinesForFrameBoundValues(scene, engine, this, defines, useInstances ? true : false); // Attribs PrepareDefinesForAttributes(mesh, defines, true, true); // Get correct effect if (defines.isDirty) { defines.markAsProcessed(); scene.resetCachedMaterial(); // Fallbacks const fallbacks = new EffectFallbacks(); if (defines.FOG) { fallbacks.addFallback(1, "FOG"); } HandleFallbacksForShadows(defines, fallbacks, this.maxSimultaneousLights); if (defines.NUM_BONE_INFLUENCERS > 0) { fallbacks.addCPUSkinningFallback(0, mesh); } defines.IMAGEPROCESSINGPOSTPROCESS = scene.imageProcessingConfiguration.applyByPostProcess; //Attributes const 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); } PrepareAttributesForBones(attribs, mesh, defines, fallbacks); PrepareAttributesForInstances(attribs, defines); // Legacy browser patch const shaderName = "fur"; const join = defines.toString(); const uniforms = [ "world", "view", "viewProjection", "vEyePosition", "vLightsType", "vDiffuseColor", "vFogInfos", "vFogColor", "pointSize", "vDiffuseInfos", "mBones", "diffuseMatrix", "logarithmicDepthConstant", "furLength", "furAngle", "furColor", "furOffset", "furGravity", "furTime", "furSpacing", "furDensity", "furOcclusion", ]; addClipPlaneUniforms(uniforms); const samplers = ["diffuseSampler", "heightTexture", "furTexture", "areaLightsLTC1Sampler", "areaLightsLTC2Sampler"]; const uniformBuffers = []; PrepareUniformsAndSamplersList({ uniformsNames: uniforms, uniformBuffersNames: uniformBuffers, samplers: samplers, defines: defines, maxSimultaneousLights: this.maxSimultaneousLights, }); subMesh.setEffect(scene.getEngine().createEffect(shaderName, { attributes: attribs, uniformsNames: uniforms, uniformBuffersNames: uniformBuffers, samplers: samplers, defines: join, fallbacks: fallbacks, onCompiled: this.onCompiled, onError: this.onError, indexParameters: { maxSimultaneousLights: this.maxSimultaneousLights }, }, engine), defines, this._materialContext); } // Check if Area Lights have LTC texture. if (defines["AREALIGHTUSED"]) { for (let index = 0; index < mesh.lightSources.length; index++) { if (!mesh.lightSources[index]._isReady()) { return false; } } } if (!subMesh.effect || !subMesh.effect.isReady()) { return false; } defines._renderId = scene.getRenderId(); drawWrapper._wasPreviouslyReady = true; drawWrapper._wasPreviouslyUsingInstances = !!useInstances; return true; } bindForSubMesh(world, mesh, subMesh) { const scene = this.getScene(); const defines = subMesh.materialDefines; if (!defines) { return; } const effect = subMesh.effect; if (!effect) { return; } this._activeEffect = effect; // Matrices this.bindOnlyWorldMatrix(world); this._activeEffect.setMatrix("viewProjection", scene.getTransformMatrix()); // Bones BindBonesParameters(mesh, this._activeEffect); if (this._mustRebind(scene, effect, subMesh)) { // Textures if (this._diffuseTexture && MaterialFlags.DiffuseTextureEnabled) { this._activeEffect.setTexture("diffuseSampler", this._diffuseTexture); this._activeEffect.setFloat2("vDiffuseInfos", this._diffuseTexture.coordinatesIndex, this._diffuseTexture.level); this._activeEffect.setMatrix("diffuseMatrix", this._diffuseTexture.getTextureMatrix()); } if (this._heightTexture) { this._activeEffect.setTexture("heightTexture", this._heightTexture); } // Clip plane bindClipPlane(this._activeEffect, this, scene); // Point size if (this.pointsCloud) { this._activeEffect.setFloat("pointSize", this.pointSize); } // Log. depth if (this._useLogarithmicDepth) { BindLogDepth(defines, effect, scene); } scene.bindEyePosition(effect); } this._activeEffect.setColor4("vDiffuseColor", this.diffuseColor, this.alpha * mesh.visibility); if (scene.lightsEnabled && !this.disableLighting) { 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 BindFogParameters(scene, mesh, this._activeEffect); this._activeEffect.setFloat("furLength", this.furLength); this._activeEffect.setFloat("furAngle", this.furAngle); this._activeEffect.setColor4("furColor", this.furColor, 1.0); if (this.highLevelFur) { this._activeEffect.setVector3("furGravity", this.furGravity); this._activeEffect.setFloat("furOffset", this.furOffset); this._activeEffect.setFloat("furSpacing", this.furSpacing); this._activeEffect.setFloat("furDensity", this.furDensity); this._activeEffect.setFloat("furOcclusion", this.furOcclusion); this._furTime += this.getScene().getEngine().getDeltaTime() / this.furSpeed; this._activeEffect.setFloat("furTime", this._furTime); this._activeEffect.setTexture("furTexture", this.furTexture); } this._afterBind(mesh, this._activeEffect, subMesh); } getAnimatables() { const results = []; if (this.diffuseTexture && this.diffuseTexture.animations && this.diffuseTexture.animations.length > 0) { results.push(this.diffuseTexture); } if (this.heightTexture && this.heightTexture.animations && this.heightTexture.animations.length > 0) { results.push(this.heightTexture); } return results; } getActiveTextures() { const activeTextures = super.getActiveTextures(); if (this._diffuseTexture) { activeTextures.push(this._diffuseTexture); } if (this._heightTexture) { activeTextures.push(this._heightTexture); } return activeTextures; } hasTexture(texture) { if (super.hasTexture(texture)) { return true; } if (this.diffuseTexture === texture) { return true; } if (this._heightTexture === texture) { return true; } return false; } dispose(forceDisposeEffect) { if (this.diffuseTexture) { this.diffuseTexture.dispose(); } if (this._meshes) { for (let i = 1; i < this._meshes.length; i++) { const mat = this._meshes[i].material; if (mat) { mat.dispose(forceDisposeEffect); } this._meshes[i].dispose(); } } super.dispose(forceDisposeEffect); } clone(name) { return SerializationHelper.Clone(() => new FurMaterial(name, this.getScene()), this); } serialize() { const serializationObject = super.serialize(); serializationObject.customType = "BABYLON.FurMaterial"; if (this._meshes) { serializationObject.sourceMeshName = this._meshes[0].name; serializationObject.quality = this._meshes.length; } return serializationObject; } getClassName() { return "FurMaterial"; } // Statics static Parse(source, scene, rootUrl) { const material = SerializationHelper.Parse(() => new FurMaterial(source.name, scene), source, scene, rootUrl); if (source.sourceMeshName && material.highLevelFur) { scene.executeWhenReady(() => { const sourceMesh = scene.getMeshByName(source.sourceMeshName); if (sourceMesh) { const furTexture = FurMaterial.GenerateTexture("Fur Texture", scene); material.furTexture = furTexture; FurMaterial.FurifyMesh(sourceMesh, source.quality); } }); } return material; } static GenerateTexture(name, scene) { // Generate fur textures const texture = new DynamicTexture("FurTexture " + name, 256, scene, true); const context = texture.getContext(); for (let i = 0; i < 20000; ++i) { context.fillStyle = "rgba(255, " + Math.floor(Math.random() * 255) + ", " + Math.floor(Math.random() * 255) + ", 1)"; context.fillRect(Math.random() * texture.getSize().width, Math.random() * texture.getSize().height, 2, 2); } texture.update(false); texture.wrapU = Texture.WRAP_ADDRESSMODE; texture.wrapV = Texture.WRAP_ADDRESSMODE; return texture; } // Creates and returns an array of meshes used as shells for the Fur Material // that can be disposed later in your code // The quality is in interval [0, 100] static FurifyMesh(sourceMesh, quality) { const meshes = [sourceMesh]; const mat = sourceMesh.material; let i; if (!(mat instanceof FurMaterial)) { // eslint-disable-next-line no-throw-literal throw "The material of the source mesh must be a Fur Material"; } for (i = 1; i < quality; i++) { const offsetFur = new FurMaterial(mat.name + i, sourceMesh.getScene()); sourceMesh.getScene().materials.pop(); Tags.EnableFor(offsetFur); Tags.AddTagsTo(offsetFur, "furShellMaterial"); offsetFur.furLength = mat.furLength; offsetFur.furAngle = mat.furAngle; offsetFur.furGravity = mat.furGravity; offsetFur.furSpacing = mat.furSpacing; offsetFur.furSpeed = mat.furSpeed; offsetFur.furColor = mat.furColor; offsetFur.diffuseTexture = mat.diffuseTexture; offsetFur.furOffset = i / quality; offsetFur.furTexture = mat.furTexture; offsetFur.highLevelFur = mat.highLevelFur; offsetFur.furTime = mat.furTime; offsetFur.furDensity = mat.furDensity; const offsetMesh = sourceMesh.clone(sourceMesh.name + i); offsetMesh.material = offsetFur; offsetMesh.skeleton = sourceMesh.skeleton; offsetMesh.position = Vector3.Zero(); meshes.push(offsetMesh); } for (i = 1; i < meshes.length; i++) { meshes[i].parent = sourceMesh; } sourceMesh.material._meshes = meshes; return meshes; } } __decorate([ serializeAsTexture("diffuseTexture") ], FurMaterial.prototype, "_diffuseTexture", void 0); __decorate([ expandToProperty("_markAllSubMeshesAsTexturesDirty") ], FurMaterial.prototype, "diffuseTexture", void 0); __decorate([ serializeAsTexture("heightTexture") ], FurMaterial.prototype, "_heightTexture", void 0); __decorate([ expandToProperty("_markAllSubMeshesAsTexturesDirty") ], FurMaterial.prototype, "heightTexture", void 0); __decorate([ serializeAsColor3() ], FurMaterial.prototype, "diffuseColor", void 0); __decorate([ serialize() ], FurMaterial.prototype, "furLength", void 0); __decorate([ serialize() ], FurMaterial.prototype, "furAngle", void 0); __decorate([ serializeAsColor3() ], FurMaterial.prototype, "furColor", void 0); __decorate([ serialize() ], FurMaterial.prototype, "furOffset", void 0); __decorate([ serialize() ], FurMaterial.prototype, "furSpacing", void 0); __decorate([ serializeAsVector3() ], FurMaterial.prototype, "furGravity", void 0); __decorate([ serialize() ], FurMaterial.prototype, "furSpeed", void 0); __decorate([ serialize() ], FurMaterial.prototype, "furDensity", void 0); __decorate([ serialize() ], FurMaterial.prototype, "furOcclusion", void 0); __decorate([ serialize("disableLighting") ], FurMaterial.prototype, "_disableLighting", void 0); __decorate([ expandToProperty("_markAllSubMeshesAsLightsDirty") ], FurMaterial.prototype, "disableLighting", void 0); __decorate([ serialize("maxSimultaneousLights") ], FurMaterial.prototype, "_maxSimultaneousLights", void 0); __decorate([ expandToProperty("_markAllSubMeshesAsLightsDirty") ], FurMaterial.prototype, "maxSimultaneousLights", void 0); __decorate([ serialize() ], FurMaterial.prototype, "highLevelFur", void 0); __decorate([ serialize() ], FurMaterial.prototype, "furTime", null); RegisterClass("BABYLON.FurMaterial", FurMaterial); //# sourceMappingURL=furMaterial.js.map