@babylonjs/core
Version:
Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.
1,009 lines (1,008 loc) • 43.9 kB
JavaScript
import { __decorate } from "../../tslib.es6.js";
/* eslint-disable @typescript-eslint/naming-convention */
import { serialize, serializeAsColor3, expandToProperty, serializeAsTexture, serializeAsVector3 } from "../../Misc/decorators.js";
import { SmartArray } from "../../Misc/smartArray.js";
import { Logger } from "../../Misc/logger.js";
import { TmpVectors, Vector3, Vector4 } from "../../Maths/math.vector.js";
import { VertexBuffer } from "../../Buffers/buffer.js";
import { MaterialDefines } from "../../Materials/materialDefines.js";
import { PushMaterial } from "../../Materials/pushMaterial.js";
import { ImageProcessingDefinesMixin } from "../../Materials/imageProcessingConfiguration.defines.js";
import { ImageProcessingConfiguration } from "../../Materials/imageProcessingConfiguration.js";
import { RegisterClass } from "../../Misc/typeStore.js";
import { MaterialFlags } from "../materialFlags.js";
import { Color3 } from "../../Maths/math.color.js";
import { EffectFallbacks } from "../effectFallbacks.js";
import { AddClipPlaneUniforms, BindClipPlane } from "../clipPlaneMaterialHelper.js";
import { BindBonesParameters, BindFogParameters, BindLights, BindLogDepth, BindTextureMatrix, BindIBLParameters, BindIBLSamplers, HandleFallbacksForShadows, PrepareAttributesForBones, PrepareAttributesForInstances, PrepareDefinesForAttributes, PrepareDefinesForFrameBoundValues, PrepareDefinesForLights, PrepareDefinesForIBL, PrepareDefinesForMergedUV, PrepareDefinesForMisc, PrepareDefinesForMultiview, PrepareUniformsAndSamplersList, PrepareUniformsAndSamplersForIBL, PrepareUniformLayoutForIBL, } from "../materialHelper.functions.js";
import { SerializationHelper } from "../../Misc/decorators.serialization.js";
import { ImageProcessingMixin } from "../imageProcessing.js";
class BackgroundMaterialDefinesBase extends MaterialDefines {
}
/**
* Background material defines definition.
* @internal Mainly internal Use
*/
class BackgroundMaterialDefines extends ImageProcessingDefinesMixin(BackgroundMaterialDefinesBase) {
/**
* Constructor of the defines.
*/
constructor() {
super();
/**
* True if the diffuse texture is in use.
*/
this.DIFFUSE = false;
/**
* The direct UV channel to use.
*/
this.DIFFUSEDIRECTUV = 0;
/**
* True if the diffuse texture is in gamma space.
*/
this.GAMMADIFFUSE = false;
/**
* True if the diffuse texture has opacity in the alpha channel.
*/
this.DIFFUSEHASALPHA = false;
/**
* True if you want the material to fade to transparent at grazing angle.
*/
this.OPACITYFRESNEL = false;
/**
* True if an extra blur needs to be added in the reflection.
*/
this.REFLECTIONBLUR = false;
/**
* True if you want the material to fade to reflection at grazing angle.
*/
this.REFLECTIONFRESNEL = false;
/**
* True if you want the material to falloff as far as you move away from the scene center.
*/
this.REFLECTIONFALLOFF = false;
/**
* False if the current Webgl implementation does not support the texture lod extension.
*/
this.TEXTURELODSUPPORT = false;
/**
* True to ensure the data are premultiplied.
*/
this.PREMULTIPLYALPHA = false;
/**
* True if the texture contains cooked RGB values and not gray scaled multipliers.
*/
this.USERGBCOLOR = false;
/**
* True if highlight and shadow levels have been specified. It can help ensuring the main perceived color
* stays aligned with the desired configuration.
*/
this.USEHIGHLIGHTANDSHADOWCOLORS = false;
/**
* True if only shadows must be rendered
*/
this.BACKMAT_SHADOWONLY = false;
/**
* True to add noise in order to reduce the banding effect.
*/
this.NOISE = false;
/**
* is the reflection texture in BGR color scheme?
* Mainly used to solve a bug in ios10 video tag
*/
this.REFLECTIONBGR = false;
/**
* True if ground projection has been enabled.
*/
this.PROJECTED_GROUND = false;
/** Defines whether reflection is enabled */
this.REFLECTION = false;
/** Defines whether the reflection map is 3D */
this.REFLECTIONMAP_3D = false;
/** Defines whether the reflection map is spherical */
this.REFLECTIONMAP_SPHERICAL = false;
/** Defines whether the reflection map is planar */
this.REFLECTIONMAP_PLANAR = false;
/** Defines whether the reflection map is cubic */
this.REFLECTIONMAP_CUBIC = false;
/** Defines whether the reflection map is in projection mode */
this.REFLECTIONMAP_PROJECTION = false;
/** Defines whether the reflection map is a skybox */
this.REFLECTIONMAP_SKYBOX = false;
/** Defines whether the reflection map is explicit */
this.REFLECTIONMAP_EXPLICIT = false;
/** Defines whether the reflection map is equirectangular */
this.REFLECTIONMAP_EQUIRECTANGULAR = false;
/** Defines whether the reflection map is fixed equirectangular */
this.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = false;
/** Defines whether the reflection map is mirrored fixed equirectangular */
this.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = false;
/** Defines whether the cubic map should be inverted */
this.INVERTCUBICMAP = false;
/** Defines whether the reflection map uses opposite Z */
this.REFLECTIONMAP_OPPOSITEZ = false;
/** Defines whether LOD is stored in the reflection alpha channel */
this.LODINREFLECTIONALPHA = false;
/** Defines whether the reflection uses gamma space */
this.GAMMAREFLECTION = false;
/** Defines whether the reflection is in RGBD format */
this.RGBDREFLECTION = false;
/** Defines whether the equirectangular reflection uses a custom field of view */
this.EQUIRECTANGULAR_RELFECTION_FOV = false;
/** Defines whether main UV1 channel is used */
this.MAINUV1 = false;
/** Defines whether main UV2 channel is used */
this.MAINUV2 = false;
/** Defines whether UV1 is used */
this.UV1 = false;
/** Defines whether UV2 is used */
this.UV2 = false;
/** Defines whether clip plane 1 is enabled */
this.CLIPPLANE = false;
/** Defines whether clip plane 2 is enabled */
this.CLIPPLANE2 = false;
/** Defines whether clip plane 3 is enabled */
this.CLIPPLANE3 = false;
/** Defines whether clip plane 4 is enabled */
this.CLIPPLANE4 = false;
/** Defines whether clip plane 5 is enabled */
this.CLIPPLANE5 = false;
/** Defines whether clip plane 6 is enabled */
this.CLIPPLANE6 = false;
/** Defines whether point size is used */
this.POINTSIZE = false;
/** Defines whether fog is enabled */
this.FOG = false;
/** Defines whether normals are available */
this.NORMAL = false;
/** Defines the number of bone influencers */
this.NUM_BONE_INFLUENCERS = 0;
/** Defines the number of bones per mesh */
this.BonesPerMesh = 0;
/** Defines whether instances are used */
this.INSTANCES = false;
/** Defines whether shadow uses float textures */
this.SHADOWFLOAT = false;
/** Defines whether logarithmic depth is enabled */
this.LOGARITHMICDEPTH = false;
/** Defines whether non-uniform scaling is applied */
this.NONUNIFORMSCALING = false;
/** Defines whether alpha testing is enabled */
this.ALPHATEST = false;
this.rebuild();
}
}
class BackgroundMaterialBase extends ImageProcessingMixin(PushMaterial) {
}
/**
* Background material used to create an efficient environment around your scene.
* #157MGZ: simple test
*/
export class BackgroundMaterial extends BackgroundMaterialBase {
/**
* Experimental Internal Use Only.
*
* Key light Color in "perceptual value" meaning the color you would like to see on screen.
* This acts as a helper to set the primary color to a more "human friendly" value.
* Conversion to linear space as well as exposure and tone mapping correction will be applied to keep the
* output color as close as possible from the chosen value.
* (This does not account for contrast color grading and color curves as they are considered post effect and not directly
* part of lighting setup.)
*/
get _perceptualColor() {
return this.__perceptualColor;
}
set _perceptualColor(value) {
this.__perceptualColor = value;
this._computePrimaryColorFromPerceptualColor();
this._markAllSubMeshesAsLightsDirty();
}
/**
* Defines the level of the shadows (dark area of the reflection map) in order to help scaling the colors.
* The color opposite to the primary color is used at the level chosen to define what the black area would look.
*/
get primaryColorShadowLevel() {
return this._primaryColorShadowLevel;
}
set primaryColorShadowLevel(value) {
this._primaryColorShadowLevel = value;
this._computePrimaryColors();
this._markAllSubMeshesAsLightsDirty();
}
/**
* Defines the level of the highlights (highlight area of the reflection map) in order to help scaling the colors.
* The primary color is used at the level chosen to define what the white area would look.
*/
get primaryColorHighlightLevel() {
return this._primaryColorHighlightLevel;
}
set primaryColorHighlightLevel(value) {
this._primaryColorHighlightLevel = value;
this._computePrimaryColors();
this._markAllSubMeshesAsLightsDirty();
}
/**
* Sets the reflection reflectance fresnel values according to the default standard
* empirically know to work well :-)
*/
set reflectionStandardFresnelWeight(value) {
let reflectionWeight = value;
if (reflectionWeight < 0.5) {
reflectionWeight = reflectionWeight * 2.0;
this.reflectionReflectance0 = BackgroundMaterial.StandardReflectance0 * reflectionWeight;
this.reflectionReflectance90 = BackgroundMaterial.StandardReflectance90 * reflectionWeight;
}
else {
reflectionWeight = reflectionWeight * 2.0 - 1.0;
this.reflectionReflectance0 = BackgroundMaterial.StandardReflectance0 + (1.0 - BackgroundMaterial.StandardReflectance0) * reflectionWeight;
this.reflectionReflectance90 = BackgroundMaterial.StandardReflectance90 + (1.0 - BackgroundMaterial.StandardReflectance90) * reflectionWeight;
}
}
/**
* The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
* Best used when trying to implement visual zoom effects like fish-eye or binoculars while not adjusting camera fov.
* Recommended to be keep at 1.0 except for special cases.
*/
get fovMultiplier() {
return this._fovMultiplier;
}
set fovMultiplier(value) {
if (isNaN(value)) {
value = 1.0;
}
this._fovMultiplier = Math.max(0.0, Math.min(2.0, value));
}
/**
* Instantiates a Background Material in the given scene
* @param name The friendly name of the material
* @param scene The scene to add the material to
* @param forceGLSL Use the GLSL code generation for the shader (even on WebGPU). Default is false
*/
constructor(name, scene, forceGLSL = false) {
super(name, scene, undefined, forceGLSL);
/**
* Key light Color (multiply against the environment texture)
*/
this.primaryColor = Color3.White();
this._primaryColorShadowLevel = 0;
this._primaryColorHighlightLevel = 0;
/**
* Reflection Texture used in the material.
* Should be author in a specific way for the best result (refer to the documentation).
*/
this.reflectionTexture = null;
/**
* Reflection Texture level of blur.
*
* Can be use to reuse an existing HDR Texture and target a specific LOD to prevent authoring the
* texture twice.
*/
this.reflectionBlur = 0;
/**
* Diffuse Texture used in the material.
* Should be author in a specific way for the best result (refer to the documentation).
*/
this.diffuseTexture = null;
this._shadowLights = null;
/**
* Specify the list of lights casting shadow on the material.
* All scene shadow lights will be included if null.
*/
this.shadowLights = null;
/**
* Helps adjusting the shadow to a softer level if required.
* 0 means black shadows and 1 means no shadows.
*/
this.shadowLevel = 0;
/**
* In case of opacity Fresnel or reflection falloff, this is use as a scene center.
* It is usually zero but might be interesting to modify according to your setup.
*/
this.sceneCenter = Vector3.Zero();
/**
* This helps specifying that the material is falling off to the sky box at grazing angle.
* This helps ensuring a nice transition when the camera goes under the ground.
*/
this.opacityFresnel = true;
/**
* This helps specifying that the material is falling off from diffuse to the reflection texture at grazing angle.
* This helps adding a mirror texture on the ground.
*/
this.reflectionFresnel = false;
/**
* This helps specifying the falloff radius off the reflection texture from the sceneCenter.
* This helps adding a nice falloff effect to the reflection if used as a mirror for instance.
*/
this.reflectionFalloffDistance = 0.0;
/**
* This specifies the weight of the reflection against the background in case of reflection Fresnel.
*/
this.reflectionAmount = 1.0;
/**
* This specifies the weight of the reflection at grazing angle.
*/
this.reflectionReflectance0 = 0.05;
/**
* This specifies the weight of the reflection at a perpendicular point of view.
*/
this.reflectionReflectance90 = 0.5;
/**
* Helps to directly use the maps channels instead of their level.
*/
this.useRGBColor = true;
/**
* This helps reducing the banding effect that could occur on the background.
*/
this.enableNoise = false;
this._fovMultiplier = 1.0;
/**
* Enable the FOV adjustment feature controlled by fovMultiplier.
*/
this.useEquirectangularFOV = false;
this._maxSimultaneousLights = 4;
/**
* Number of Simultaneous lights allowed on the material.
*/
this.maxSimultaneousLights = 4;
this._shadowOnly = false;
/**
* Make the material only render shadows
*/
this.shadowOnly = false;
/**
* Due to a bug in iOS10, video tags (which are using the background material) are in BGR and not RGB.
* Setting this flag to true (not done automatically!) will convert it back to RGB.
*/
this.switchToBGR = false;
this._enableGroundProjection = false;
/**
* Enables the ground projection mode on the material.
* @see https://doc.babylonjs.com/features/featuresDeepDive/environment/skybox#ground-projection
*/
this.enableGroundProjection = false;
/**
* Defines the radius of the projected ground if enableGroundProjection is true.
* @see https://doc.babylonjs.com/features/featuresDeepDive/environment/skybox#ground-projection
*/
this.projectedGroundRadius = 1000;
/**
* Defines the height of the projected ground if enableGroundProjection is true.
* @see https://doc.babylonjs.com/features/featuresDeepDive/environment/skybox#ground-projection
*/
this.projectedGroundHeight = 10;
// Temp values kept as cache in the material.
this._renderTargets = new SmartArray(16);
this._reflectionControls = Vector4.Zero();
this._white = Color3.White();
this._primaryShadowColor = Color3.Black();
this._primaryHighlightColor = Color3.Black();
this._shadersLoaded = false;
// Setup the default processing configuration to the scene.
this._attachImageProcessingConfiguration(null);
this.getRenderTargetTextures = () => {
this._renderTargets.reset();
if (this._diffuseTexture && this._diffuseTexture.isRenderTarget) {
this._renderTargets.push(this._diffuseTexture);
}
if (this._reflectionTexture && this._reflectionTexture.isRenderTarget) {
this._renderTargets.push(this._reflectionTexture);
}
return this._renderTargets;
};
}
/**
* Gets a boolean indicating that current material needs to register RTT
*/
get hasRenderTargetTextures() {
if (this._diffuseTexture && this._diffuseTexture.isRenderTarget) {
return true;
}
if (this._reflectionTexture && this._reflectionTexture.isRenderTarget) {
return true;
}
return false;
}
/**
* The entire material has been created in order to prevent overdraw.
* @returns false
*/
needAlphaTesting() {
return true;
}
/**
* The entire material has been created in order to prevent overdraw.
* @returns true if blending is enable
*/
needAlphaBlending() {
return this.alpha < 1 || (this._diffuseTexture != null && this._diffuseTexture.hasAlpha) || this._shadowOnly;
}
/**
* Checks whether the material is ready to be rendered for a given mesh.
* @param mesh The mesh to render
* @param subMesh The submesh to check against
* @param useInstances Specify wether or not the material is used with instances
* @returns true if all the dependencies are ready (Textures, Effects...)
*/
isReadyForSubMesh(mesh, subMesh, useInstances = false) {
const drawWrapper = subMesh._drawWrapper;
if (drawWrapper.effect && this.isFrozen) {
if (drawWrapper._wasPreviouslyReady && drawWrapper._wasPreviouslyUsingInstances === useInstances) {
return true;
}
}
if (!subMesh.materialDefines) {
subMesh.materialDefines = new BackgroundMaterialDefines();
}
const scene = this.getScene();
const defines = subMesh.materialDefines;
if (this._isReadyForSubMesh(subMesh)) {
return true;
}
const engine = scene.getEngine();
// Lights
PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights);
defines._needNormals = true;
// Multiview
PrepareDefinesForMultiview(scene, defines);
// Textures
if (defines._areTexturesDirty) {
defines._needUVs = false;
if (scene.texturesEnabled) {
if (scene.getEngine().getCaps().textureLOD) {
defines.TEXTURELODSUPPORT = true;
}
if (this._diffuseTexture && MaterialFlags.DiffuseTextureEnabled) {
if (!this._diffuseTexture.isReadyOrNotBlocking()) {
return false;
}
PrepareDefinesForMergedUV(this._diffuseTexture, defines, "DIFFUSE");
defines.DIFFUSEHASALPHA = this._diffuseTexture.hasAlpha;
defines.GAMMADIFFUSE = this._diffuseTexture.gammaSpace;
defines.OPACITYFRESNEL = this._opacityFresnel;
}
else {
defines.DIFFUSE = false;
defines.DIFFUSEDIRECTUV = 0;
defines.DIFFUSEHASALPHA = false;
defines.GAMMADIFFUSE = false;
defines.OPACITYFRESNEL = false;
}
const reflectionTexture = this._reflectionTexture;
PrepareDefinesForIBL(scene, reflectionTexture, defines);
if (reflectionTexture && MaterialFlags.ReflectionTextureEnabled) {
if (!reflectionTexture.isReadyOrNotBlocking()) {
return false;
}
defines.EQUIRECTANGULAR_RELFECTION_FOV = this.useEquirectangularFOV;
defines.REFLECTIONBGR = this.switchToBGR;
defines.REFLECTIONBLUR = this._reflectionBlur > 0;
if (this.reflectionFresnel) {
defines.REFLECTIONFRESNEL = true;
defines.REFLECTIONFALLOFF = this.reflectionFalloffDistance > 0;
this._reflectionControls.x = this.reflectionAmount;
this._reflectionControls.y = this.reflectionReflectance0;
this._reflectionControls.z = this.reflectionReflectance90;
this._reflectionControls.w = 1 / this.reflectionFalloffDistance;
}
else {
defines.REFLECTIONFRESNEL = false;
defines.REFLECTIONFALLOFF = false;
}
}
else {
defines.REFLECTIONFRESNEL = false;
defines.REFLECTIONFALLOFF = false;
defines.REFLECTIONBLUR = false;
}
}
defines.PREMULTIPLYALPHA = this.alphaMode === 7 || this.alphaMode === 8;
defines.USERGBCOLOR = this._useRGBColor;
defines.NOISE = this._enableNoise;
}
if (defines._areLightsDirty) {
defines.USEHIGHLIGHTANDSHADOWCOLORS = !this._useRGBColor && (this._primaryColorShadowLevel !== 0 || this._primaryColorHighlightLevel !== 0);
defines.BACKMAT_SHADOWONLY = this._shadowOnly;
}
if (defines._areImageProcessingDirty && this._imageProcessingConfiguration) {
if (!this._imageProcessingConfiguration.isReady()) {
return false;
}
this._imageProcessingConfiguration.prepareDefines(defines);
}
if (defines._areMiscDirty) {
if (defines.REFLECTIONMAP_3D && this._enableGroundProjection) {
defines.PROJECTED_GROUND = true;
defines.REFLECTIONMAP_SKYBOX = true;
}
else {
defines.PROJECTED_GROUND = false;
}
}
// Misc.
PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this.needAlphaTestingForMesh(mesh), defines, undefined, undefined, undefined, this._isVertexOutputInvariant);
// Values that need to be evaluated on every frame
PrepareDefinesForFrameBoundValues(scene, engine, this, defines, useInstances, null, subMesh.getRenderingMesh().hasThinInstances);
// Attribs
if (PrepareDefinesForAttributes(mesh, defines, false, true, false)) {
if (mesh) {
if (!scene.getEngine().getCaps().standardDerivatives && !mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
mesh.createNormals(true);
Logger.Warn("BackgroundMaterial: Normals have been created for the mesh: " + mesh.name);
}
}
}
// Get correct effect
if (defines.isDirty) {
defines.markAsProcessed();
scene.resetCachedMaterial();
// Fallbacks
const fallbacks = new EffectFallbacks();
if (defines.FOG) {
fallbacks.addFallback(0, "FOG");
}
if (defines.POINTSIZE) {
fallbacks.addFallback(1, "POINTSIZE");
}
if (defines.MULTIVIEW) {
fallbacks.addFallback(0, "MULTIVIEW");
}
HandleFallbacksForShadows(defines, fallbacks, this._maxSimultaneousLights);
//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);
}
PrepareAttributesForBones(attribs, mesh, defines, fallbacks);
PrepareAttributesForInstances(attribs, defines);
const uniforms = [
"world",
"view",
"viewProjection",
"vEyePosition",
"vLightsType",
"vFogInfos",
"vFogColor",
"pointSize",
"mBones",
"vPrimaryColor",
"vPrimaryColorShadow",
"fFovMultiplier",
"shadowLevel",
"alpha",
"vBackgroundCenter",
"vReflectionControl",
"vDiffuseInfos",
"diffuseMatrix",
"projectedGroundInfos",
"logarithmicDepthConstant",
];
AddClipPlaneUniforms(uniforms);
const samplers = ["diffuseSampler"];
PrepareUniformsAndSamplersForIBL(uniforms, samplers, false);
const uniformBuffers = ["Material", "Scene"];
if (ImageProcessingConfiguration) {
ImageProcessingConfiguration.PrepareUniforms(uniforms, defines);
ImageProcessingConfiguration.PrepareSamplers(samplers, defines);
}
PrepareUniformsAndSamplersList({
uniformsNames: uniforms,
uniformBuffersNames: uniformBuffers,
samplers: samplers,
defines: defines,
maxSimultaneousLights: this._maxSimultaneousLights,
});
const join = defines.toString();
const effect = scene.getEngine().createEffect("background", {
attributes: attribs,
uniformsNames: uniforms,
uniformBuffersNames: uniformBuffers,
samplers: samplers,
defines: join,
fallbacks: fallbacks,
onCompiled: this.onCompiled,
onError: this.onError,
indexParameters: { maxSimultaneousLights: this._maxSimultaneousLights },
shaderLanguage: this._shaderLanguage,
extraInitializationsAsync: this._shadersLoaded
? undefined
: async () => {
if (this.shaderLanguage === 1 /* ShaderLanguage.WGSL */) {
await Promise.all([import("../../ShadersWGSL/background.vertex.js"), import("../../ShadersWGSL/background.fragment.js")]);
}
else {
await Promise.all([import("../../Shaders/background.vertex.js"), import("../../Shaders/background.fragment.js")]);
}
this._shadersLoaded = true;
},
}, engine);
subMesh.setEffect(effect, defines, this._materialContext);
this.buildUniformLayout();
}
if (!subMesh.effect || !subMesh.effect.isReady()) {
return false;
}
defines._renderId = scene.getRenderId();
drawWrapper._wasPreviouslyReady = true;
drawWrapper._wasPreviouslyUsingInstances = useInstances;
this._checkScenePerformancePriority();
return true;
}
/**
* Compute the primary color according to the chosen perceptual color.
*/
_computePrimaryColorFromPerceptualColor() {
if (!this.__perceptualColor) {
return;
}
this._primaryColor.copyFrom(this.__perceptualColor);
// Revert gamma space.
this._primaryColor.toLinearSpaceToRef(this._primaryColor, this.getScene().getEngine().useExactSrgbConversions);
// Revert image processing configuration.
if (this._imageProcessingConfiguration) {
// Revert Exposure.
this._primaryColor.scaleToRef(1 / this._imageProcessingConfiguration.exposure, this._primaryColor);
}
this._computePrimaryColors();
}
/**
* Compute the highlights and shadow colors according to their chosen levels.
*/
_computePrimaryColors() {
if (this._primaryColorShadowLevel === 0 && this._primaryColorHighlightLevel === 0) {
return;
}
// Find the highlight color based on the configuration.
this._primaryColor.scaleToRef(this._primaryColorShadowLevel, this._primaryShadowColor);
this._primaryColor.subtractToRef(this._primaryShadowColor, this._primaryShadowColor);
// Find the shadow color based on the configuration.
this._white.subtractToRef(this._primaryColor, this._primaryHighlightColor);
this._primaryHighlightColor.scaleToRef(this._primaryColorHighlightLevel, this._primaryHighlightColor);
this._primaryColor.addToRef(this._primaryHighlightColor, this._primaryHighlightColor);
}
/**
* Build the uniform buffer used in the material.
*/
buildUniformLayout() {
// Order is important !
this._uniformBuffer.addUniform("vPrimaryColor", 4);
this._uniformBuffer.addUniform("vPrimaryColorShadow", 4);
this._uniformBuffer.addUniform("vDiffuseInfos", 2);
this._uniformBuffer.addUniform("diffuseMatrix", 16);
this._uniformBuffer.addUniform("fFovMultiplier", 1);
this._uniformBuffer.addUniform("pointSize", 1);
this._uniformBuffer.addUniform("shadowLevel", 1);
this._uniformBuffer.addUniform("alpha", 1);
this._uniformBuffer.addUniform("vBackgroundCenter", 3);
this._uniformBuffer.addUniform("vReflectionControl", 4);
this._uniformBuffer.addUniform("projectedGroundInfos", 2);
PrepareUniformLayoutForIBL(this._uniformBuffer, true, false, false);
this._uniformBuffer.create();
}
/**
* Unbind the material.
*/
unbind() {
if (this._diffuseTexture && this._diffuseTexture.isRenderTarget) {
this._uniformBuffer.setTexture("diffuseSampler", null);
}
if (this._reflectionTexture && this._reflectionTexture.isRenderTarget) {
this._uniformBuffer.setTexture("reflectionSampler", null);
}
super.unbind();
}
/**
* Bind only the world matrix to the material.
* @param world The world matrix to bind.
*/
bindOnlyWorldMatrix(world) {
this._activeEffect.setMatrix("world", world);
}
/**
* Bind the material for a dedicated submesh (every used meshes will be considered opaque).
* @param world The world matrix to bind.
* @param mesh the mesh to bind for.
* @param subMesh The submesh to bind for.
*/
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);
// Bones
BindBonesParameters(mesh, this._activeEffect);
const mustRebind = this._mustRebind(scene, effect, subMesh, mesh.visibility);
if (mustRebind) {
this._uniformBuffer.bindToEffect(effect, "Material");
this.bindViewProjection(effect);
const reflectionTexture = this._reflectionTexture;
if (!this._uniformBuffer.useUbo || !this.isFrozen || !this._uniformBuffer.isSync || subMesh._drawWrapper._forceRebindOnNextCall) {
// Texture uniforms
if (scene.texturesEnabled) {
if (this._diffuseTexture && MaterialFlags.DiffuseTextureEnabled) {
this._uniformBuffer.updateFloat2("vDiffuseInfos", this._diffuseTexture.coordinatesIndex, this._diffuseTexture.level);
BindTextureMatrix(this._diffuseTexture, this._uniformBuffer, "diffuse");
}
BindIBLParameters(scene, defines, this._uniformBuffer, Color3.White(), reflectionTexture, false, true, false, false, false, false, this._reflectionBlur);
}
if (this.shadowLevel > 0) {
this._uniformBuffer.updateFloat("shadowLevel", this.shadowLevel);
}
this._uniformBuffer.updateFloat("alpha", this.alpha);
// Point size
if (this.pointsCloud) {
this._uniformBuffer.updateFloat("pointSize", this.pointSize);
}
if (defines.USEHIGHLIGHTANDSHADOWCOLORS) {
this._uniformBuffer.updateColor4("vPrimaryColor", this._primaryHighlightColor, 1.0);
this._uniformBuffer.updateColor4("vPrimaryColorShadow", this._primaryShadowColor, 1.0);
}
else {
this._uniformBuffer.updateColor4("vPrimaryColor", this._primaryColor, 1.0);
}
}
this._uniformBuffer.updateFloat("fFovMultiplier", this._fovMultiplier);
// Fresnel
if (defines.REFLECTIONFRESNEL) {
this._uniformBuffer.updateFloat4("vReflectionControl", this._reflectionControls.x, this._reflectionControls.y, this._reflectionControls.z, this._reflectionControls.w);
}
if ((defines.REFLECTIONFRESNEL && defines.REFLECTIONFALLOFF) || defines.OPACITYFRESNEL) {
const center = TmpVectors.Vector3[0].copyFrom(this.sceneCenter).subtractInPlace(scene.floatingOriginOffset);
this._uniformBuffer.updateFloat3("vBackgroundCenter", center.x, center.y, center.z);
}
// Textures
if (scene.texturesEnabled) {
if (this._diffuseTexture && MaterialFlags.DiffuseTextureEnabled) {
this._uniformBuffer.setTexture("diffuseSampler", this._diffuseTexture);
}
if (reflectionTexture && MaterialFlags.ReflectionTextureEnabled) {
BindIBLSamplers(scene, defines, this._uniformBuffer, reflectionTexture);
}
if (defines.PROJECTED_GROUND) {
this._uniformBuffer.updateFloat2("projectedGroundInfos", this.projectedGroundRadius, this.projectedGroundHeight);
}
}
// Clip plane
BindClipPlane(this._activeEffect, this, scene);
scene.bindEyePosition(effect);
}
else if (scene.getEngine()._features.needToAlwaysBindUniformBuffers) {
this._uniformBuffer.bindToEffect(effect, "Material");
this._needToBindSceneUbo = true;
}
if (mustRebind || !this.isFrozen) {
if (scene.lightsEnabled) {
BindLights(scene, mesh, this._activeEffect, defines, this._maxSimultaneousLights);
}
// View
this.bindView(effect);
// Fog
BindFogParameters(scene, mesh, this._activeEffect, true);
// Log. depth
if (this._useLogarithmicDepth) {
BindLogDepth(defines, effect, scene);
}
// image processing
if (this._imageProcessingConfiguration) {
this._imageProcessingConfiguration.bind(this._activeEffect);
}
}
this._afterBind(mesh, this._activeEffect, subMesh);
this._uniformBuffer.update();
}
/**
* Checks to see if a texture is used in the material.
* @param texture - Base texture to use.
* @returns - Boolean specifying if a texture is used in the material.
*/
hasTexture(texture) {
if (super.hasTexture(texture)) {
return true;
}
if (this._reflectionTexture === texture) {
return true;
}
if (this._diffuseTexture === texture) {
return true;
}
return false;
}
/**
* Dispose the material.
* @param forceDisposeEffect Force disposal of the associated effect.
* @param forceDisposeTextures Force disposal of the associated textures.
*/
dispose(forceDisposeEffect = false, forceDisposeTextures = false) {
if (forceDisposeTextures) {
if (this.diffuseTexture) {
this.diffuseTexture.dispose();
}
if (this.reflectionTexture) {
this.reflectionTexture.dispose();
}
}
this._renderTargets.dispose();
if (this._imageProcessingConfiguration && this._imageProcessingObserver) {
this._imageProcessingConfiguration.onUpdateParameters.remove(this._imageProcessingObserver);
}
super.dispose(forceDisposeEffect);
}
/**
* Clones the material.
* @param name The cloned name.
* @returns The cloned material.
*/
clone(name) {
return SerializationHelper.Clone(() => new BackgroundMaterial(name, this.getScene()), this);
}
/**
* Serializes the current material to its JSON representation.
* @returns The JSON representation.
*/
serialize() {
const serializationObject = super.serialize();
serializationObject.customType = "BABYLON.BackgroundMaterial";
return serializationObject;
}
/**
* Gets the class name of the material
* @returns "BackgroundMaterial"
*/
getClassName() {
return "BackgroundMaterial";
}
/**
* Parse a JSON input to create back a background material.
* @param source The JSON data to parse
* @param scene The scene to create the parsed material in
* @param rootUrl The root url of the assets the material depends upon
* @returns the instantiated BackgroundMaterial.
*/
static Parse(source, scene, rootUrl) {
return SerializationHelper.Parse(() => new BackgroundMaterial(source.name, scene), source, scene, rootUrl);
}
}
/**
* Standard reflectance value at parallel view angle.
*/
BackgroundMaterial.StandardReflectance0 = 0.05;
/**
* Standard reflectance value at grazing angle.
*/
BackgroundMaterial.StandardReflectance90 = 0.5;
__decorate([
serializeAsColor3()
], BackgroundMaterial.prototype, "_primaryColor", void 0);
__decorate([
expandToProperty("_markAllSubMeshesAsLightsDirty")
], BackgroundMaterial.prototype, "primaryColor", void 0);
__decorate([
serializeAsColor3()
], BackgroundMaterial.prototype, "__perceptualColor", void 0);
__decorate([
serialize()
], BackgroundMaterial.prototype, "_primaryColorShadowLevel", void 0);
__decorate([
serialize()
], BackgroundMaterial.prototype, "_primaryColorHighlightLevel", void 0);
__decorate([
expandToProperty("_markAllSubMeshesAsLightsDirty")
], BackgroundMaterial.prototype, "primaryColorHighlightLevel", null);
__decorate([
serializeAsTexture()
], BackgroundMaterial.prototype, "_reflectionTexture", void 0);
__decorate([
expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "reflectionTexture", void 0);
__decorate([
serialize()
], BackgroundMaterial.prototype, "_reflectionBlur", void 0);
__decorate([
expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "reflectionBlur", void 0);
__decorate([
serializeAsTexture()
], BackgroundMaterial.prototype, "_diffuseTexture", void 0);
__decorate([
expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "diffuseTexture", void 0);
__decorate([
expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "shadowLights", void 0);
__decorate([
serialize()
], BackgroundMaterial.prototype, "_shadowLevel", void 0);
__decorate([
expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "shadowLevel", void 0);
__decorate([
serializeAsVector3()
], BackgroundMaterial.prototype, "_sceneCenter", void 0);
__decorate([
expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "sceneCenter", void 0);
__decorate([
serialize()
], BackgroundMaterial.prototype, "_opacityFresnel", void 0);
__decorate([
expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "opacityFresnel", void 0);
__decorate([
serialize()
], BackgroundMaterial.prototype, "_reflectionFresnel", void 0);
__decorate([
expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "reflectionFresnel", void 0);
__decorate([
serialize()
], BackgroundMaterial.prototype, "_reflectionFalloffDistance", void 0);
__decorate([
expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "reflectionFalloffDistance", void 0);
__decorate([
serialize()
], BackgroundMaterial.prototype, "_reflectionAmount", void 0);
__decorate([
expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "reflectionAmount", void 0);
__decorate([
serialize()
], BackgroundMaterial.prototype, "_reflectionReflectance0", void 0);
__decorate([
expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "reflectionReflectance0", void 0);
__decorate([
serialize()
], BackgroundMaterial.prototype, "_reflectionReflectance90", void 0);
__decorate([
expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "reflectionReflectance90", void 0);
__decorate([
serialize()
], BackgroundMaterial.prototype, "_useRGBColor", void 0);
__decorate([
expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "useRGBColor", void 0);
__decorate([
serialize()
], BackgroundMaterial.prototype, "_enableNoise", void 0);
__decorate([
expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "enableNoise", void 0);
__decorate([
serialize()
], BackgroundMaterial.prototype, "_maxSimultaneousLights", void 0);
__decorate([
expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "maxSimultaneousLights", void 0);
__decorate([
serialize()
], BackgroundMaterial.prototype, "_shadowOnly", void 0);
__decorate([
expandToProperty("_markAllSubMeshesAsLightsDirty")
], BackgroundMaterial.prototype, "shadowOnly", void 0);
__decorate([
serialize(),
expandToProperty("_markAllSubMeshesAsMiscDirty")
], BackgroundMaterial.prototype, "enableGroundProjection", void 0);
__decorate([
serialize()
], BackgroundMaterial.prototype, "projectedGroundRadius", void 0);
__decorate([
serialize()
], BackgroundMaterial.prototype, "projectedGroundHeight", void 0);
RegisterClass("BABYLON.BackgroundMaterial", BackgroundMaterial);
//# sourceMappingURL=backgroundMaterial.js.map