playcanvas
Version:
PlayCanvas WebGL game engine
849 lines (848 loc) • 60.4 kB
JavaScript
import { Debug } from '../../core/debug.js';
import { Color } from '../../core/math/color.js';
import { math } from '../../core/math/math.js';
import { Vec2 } from '../../core/math/vec2.js';
import { ShaderProcessorOptions } from '../../platform/graphics/shader-processor-options.js';
import { CUBEPROJ_BOX, SHADER_PICK, SHADER_PREPASS, tonemapNames, SPECOCC_AO, FRESNEL_SCHLICK, CUBEPROJ_NONE, DITHER_NONE, DETAILMODE_MUL } from '../constants.js';
import { ShaderPass } from '../shader-pass.js';
import { EnvLighting } from '../graphics/env-lighting.js';
import { getProgramLibrary } from '../shader-lib/get-program-library.js';
import { _matTex2D, standard } from '../shader-lib/programs/standard.js';
import { Material } from './material.js';
import { StandardMaterialOptionsBuilder } from './standard-material-options-builder.js';
import { standardMaterialTextureParameters, standardMaterialCubemapParameters } from './standard-material-parameters.js';
import { DebugGraphics } from '../../platform/graphics/debug-graphics.js';
import { ShaderUtils } from '../shader-lib/shader-utils.js';
/**
* @import { BoundingBox } from '../../core/shape/bounding-box.js'
* @import { StandardMaterialOptions } from './standard-material-options.js'
* @import { Texture } from '../../platform/graphics/texture.js'
*/ // properties that get created on a standard material
const _props = {};
// special uniform functions on a standard material
const _uniforms = {};
// temporary set of params
let _params = new Set();
const _tempColor = new Color();
/**
* @callback UpdateShaderCallback
* Callback used by {@link StandardMaterial#onUpdateShader}.
* @param {StandardMaterialOptions} options - An object with shader generator settings (based on current
* material and scene properties), that you can change and then return. Properties of the object passed
* into this function are documented in {@link StandardMaterial}. Also contains a member named litOptions
* which holds some of the options only used by the lit shader backend {@link LitShaderOptions}.
* @returns {StandardMaterialOptions} Returned settings will be used by the shader.
*/ /**
* A standard material is the main, general purpose material that is most often used for rendering.
* It can approximate a wide variety of surface types and can simulate dynamic reflected light.
* Most maps can use 3 types of input values in any combination: constant ({@link Color} or number),
* mesh vertex colors and a {@link Texture}. All enabled inputs are multiplied together.
*
* @property {Color} ambient The ambient color of the material. This color value is 3-component
* (RGB), where each component is between 0 and 1.
* @property {Color} diffuse The diffuse color of the material. This color value is 3-component
* (RGB), where each component is between 0 and 1. Defines basic surface color (aka albedo).
* @property {Texture|null} diffuseMap The main (primary) diffuse map of the material (default is
* null).
* @property {number} diffuseMapUv Main (primary) diffuse map UV channel.
* @property {Vec2} diffuseMapTiling Controls the 2D tiling of the main (primary) diffuse map.
* @property {Vec2} diffuseMapOffset Controls the 2D offset of the main (primary) diffuse map. Each
* component is between 0 and 1.
* @property {number} diffuseMapRotation Controls the 2D rotation (in degrees) of the main
* (primary) diffuse map.
* @property {string} diffuseMapChannel Color channels of the main (primary) diffuse map to use.
* Can be "r", "g", "b", "a", "rgb" or any swizzled combination.
* @property {boolean} diffuseVertexColor Multiply diffuse by the mesh vertex colors.
* @property {string} diffuseVertexColorChannel Vertex color channels to use for diffuse. Can be
* "r", "g", "b", "a", "rgb" or any swizzled combination.
* @property {Texture|null} diffuseDetailMap The detail (secondary) diffuse map of the material
* (default is null). Will only be used if main (primary) diffuse map is non-null.
* @property {number} diffuseDetailMapUv Detail (secondary) diffuse map UV channel.
* @property {Vec2} diffuseDetailMapTiling Controls the 2D tiling of the detail (secondary) diffuse
* map.
* @property {Vec2} diffuseDetailMapOffset Controls the 2D offset of the detail (secondary) diffuse
* map. Each component is between 0 and 1.
* @property {number} diffuseDetailMapRotation Controls the 2D rotation (in degrees) of the main
* (secondary) diffuse map.
* @property {string} diffuseDetailMapChannel Color channels of the detail (secondary) diffuse map
* to use. Can be "r", "g", "b", "a", "rgb" or any swizzled combination.
* @property {string} diffuseDetailMode Determines how the main (primary) and detail (secondary)
* diffuse maps are blended together. Can be:
*
* - {@link DETAILMODE_MUL}: Multiply together the primary and secondary colors.
* - {@link DETAILMODE_ADD}: Add together the primary and secondary colors.
* - {@link DETAILMODE_SCREEN}: Softer version of {@link DETAILMODE_ADD}.
* - {@link DETAILMODE_OVERLAY}: Multiplies or screens the colors, depending on the primary color.
* - {@link DETAILMODE_MIN}: Select whichever of the primary and secondary colors is darker,
* component-wise.
* - {@link DETAILMODE_MAX}: Select whichever of the primary and secondary colors is lighter,
* component-wise.
*
* Defaults to {@link DETAILMODE_MUL}.
* @property {Color} specular The specular color of the material. This color value is 3-component
* (RGB), where each component is between 0 and 1. Defines surface reflection/specular color.
* Affects specular intensity and tint.
* @property {boolean} specularTint Multiply specular map and/or specular vertex color by the
* constant specular value.
* @property {Texture|null} specularMap The specular map of the material (default is null).
* @property {number} specularMapUv Specular map UV channel.
* @property {Vec2} specularMapTiling Controls the 2D tiling of the specular map.
* @property {Vec2} specularMapOffset Controls the 2D offset of the specular map. Each component is
* between 0 and 1.
* @property {number} specularMapRotation Controls the 2D rotation (in degrees) of the specular map.
* @property {string} specularMapChannel Color channels of the specular map to use. Can be "r", "g",
* "b", "a", "rgb" or any swizzled combination.
* @property {boolean} specularVertexColor Use mesh vertex colors for specular. If specularMap or
* are specularTint are set, they'll be multiplied by vertex colors.
* @property {string} specularVertexColorChannel Vertex color channels to use for specular. Can be
* "r", "g", "b", "a", "rgb" or any swizzled combination.
* @property {boolean} specularityFactorTint Multiply specularity factor map and/or specular vertex color by the
* constant specular value.
* @property {number} specularityFactor The factor of specular intensity, used to weight the fresnel and specularity. Default is 1.0.
* @property {Texture|null} specularityFactorMap The factor of specularity as a texture (default is
* null).
* @property {number} specularityFactorMapUv Specularity factor map UV channel.
* @property {Vec2} specularityFactorMapTiling Controls the 2D tiling of the specularity factor map.
* @property {Vec2} specularityFactorMapOffset Controls the 2D offset of the specularity factor map. Each component is
* between 0 and 1.
* @property {number} specularityFactorMapRotation Controls the 2D rotation (in degrees) of the specularity factor map.
* @property {string} specularityFactorMapChannel The channel used by the specularity factor texture to sample from (default is 'a').
* @property {boolean} specularityFactorVertexColor Use mesh vertex colors for specularity factor. If specularityFactorMap or
* are specularityFactorTint are set, they'll be multiplied by vertex colors.
* @property {string} specularityFactorVertexColorChannel Vertex color channels to use for specularity factor. Can be
* "r", "g", "b", "a", "rgb" or any swizzled combination.
* @property {boolean} enableGGXSpecular Enables GGX specular. Also enables
* {@link StandardMaterial#anisotropyIntensity} parameter to set material anisotropy.
* @property {number} anisotropyIntensity Defines amount of anisotropy. Requires
* {@link StandardMaterial#enableGGXSpecular} is set to true.
* - When anisotropyIntensity == 0, specular is isotropic.
* - Specular anisotropy increases as anisotropyIntensity value increases to maximum of 1.
* @property {number} anisotropyRotation Defines the rotation (in degrees) of anisotropy.
* @property {Texture|null} anisotropyMap The anisotropy map of the material (default is null).
* @property {number} anisotropyMapUv Anisotropy map UV channel.
* @property {Vec2} anisotropyMapTiling Controls the 2D tiling of the anisotropy map.
* @property {Vec2} anisotropyMapOffset Controls the 2D offset of the anisotropy map. Each
* component is between 0 and 1.
* @property {number} anisotropyMapRotation Controls the 2D rotation (in degrees) of the anisotropy map.
* @property {number} clearCoat Defines intensity of clearcoat layer from 0 to 1. Clearcoat layer
* is disabled when clearCoat == 0. Default value is 0 (disabled).
* @property {Texture|null} clearCoatMap Monochrome clearcoat intensity map (default is null). If
* specified, will be multiplied by normalized 'clearCoat' value and/or vertex colors.
* @property {number} clearCoatMapUv Clearcoat intensity map UV channel.
* @property {Vec2} clearCoatMapTiling Controls the 2D tiling of the clearcoat intensity map.
* @property {Vec2} clearCoatMapOffset Controls the 2D offset of the clearcoat intensity map. Each
* component is between 0 and 1.
* @property {number} clearCoatMapRotation Controls the 2D rotation (in degrees) of the clearcoat
* intensity map.
* @property {string} clearCoatMapChannel Color channel of the clearcoat intensity map to use. Can
* be "r", "g", "b" or "a".
* @property {boolean} clearCoatVertexColor Use mesh vertex colors for clearcoat intensity. If
* clearCoatMap is set, it'll be multiplied by vertex colors.
* @property {string} clearCoatVertexColorChannel Vertex color channel to use for clearcoat
* intensity. Can be "r", "g", "b" or "a".
* @property {number} clearCoatGloss Defines the clearcoat glossiness of the clearcoat layer
* from 0 (rough) to 1 (mirror).
* @property {boolean} clearCoatGlossInvert Invert the clearcoat gloss component (default is false).
* Enabling this flag results in material treating the clear coat gloss members as roughness.
* @property {Texture|null} clearCoatGlossMap Monochrome clearcoat glossiness map (default is
* null). If specified, will be multiplied by normalized 'clearCoatGloss' value and/or vertex
* colors.
* @property {number} clearCoatGlossMapUv Clearcoat gloss map UV channel.
* @property {Vec2} clearCoatGlossMapTiling Controls the 2D tiling of the clearcoat gloss map.
* @property {Vec2} clearCoatGlossMapOffset Controls the 2D offset of the clearcoat gloss map.
* Each component is between 0 and 1.
* @property {number} clearCoatGlossMapRotation Controls the 2D rotation (in degrees) of the clear
* coat gloss map.
* @property {string} clearCoatGlossMapChannel Color channel of the clearcoat gloss map to use.
* Can be "r", "g", "b" or "a".
* @property {boolean} clearCoatGlossVertexColor Use mesh vertex colors for clearcoat glossiness.
* If clearCoatGlossMap is set, it'll be multiplied by vertex colors.
* @property {string} clearCoatGlossVertexColorChannel Vertex color channel to use for clearcoat
* glossiness. Can be "r", "g", "b" or "a".
* @property {Texture|null} clearCoatNormalMap The clearcoat normal map of the material (default is
* null). The texture must contains normalized, tangent space normals.
* @property {number} clearCoatNormalMapUv Clearcoat normal map UV channel.
* @property {Vec2} clearCoatNormalMapTiling Controls the 2D tiling of the main clearcoat normal
* map.
* @property {Vec2} clearCoatNormalMapOffset Controls the 2D offset of the main clearcoat normal
* map. Each component is between 0 and 1.
* @property {number} clearCoatNormalMapRotation Controls the 2D rotation (in degrees) of the main
* clearcoat map.
* @property {number} clearCoatBumpiness The bumpiness of the clearcoat layer. This value scales
* the assigned main clearcoat normal map. It should be normally between 0 (no bump mapping) and 1
* (full bump mapping), but can be set to e.g. 2 to give even more pronounced bump effect.
* @property {boolean} useIridescence Enable thin-film iridescence.
* @property {Texture|null} iridescenceMap The per-pixel iridescence intensity. Only used when
* useIridescence is enabled.
* @property {number} iridescenceMapUv Iridescence map UV channel.
* @property {Vec2} iridescenceMapTiling Controls the 2D tiling of the iridescence map.
* @property {Vec2} iridescenceMapOffset Controls the 2D offset of the iridescence map. Each component is
* between 0 and 1.
* @property {number} iridescenceMapRotation Controls the 2D rotation (in degrees) of the iridescence
* map.
* @property {string} iridescenceMapChannel Color channels of the iridescence map to use. Can be "r",
* "g", "b" or "a".
* @property {Texture|null} iridescenceThicknessMap The per-pixel iridescence thickness. Defines a
* gradient weight between iridescenceThicknessMin and iridescenceThicknessMax. Only used when
* useIridescence is enabled.
* @property {number} iridescenceThicknessMapUv Iridescence thickness map UV channel.
* @property {Vec2} iridescenceThicknessMapTiling Controls the 2D tiling of the iridescence
* thickness map.
* @property {Vec2} iridescenceThicknessMapOffset Controls the 2D offset of the iridescence
* thickness map. Each component is between 0 and 1.
* @property {number} iridescenceThicknessMapRotation Controls the 2D rotation (in degrees)
* of the iridescence map.
* @property {string} iridescenceThicknessMapChannel Color channels of the iridescence thickness
* map to use. Can be "r", "g", "b" or "a".
* @property {number} iridescenceThicknessMin The minimum thickness for the iridescence layer.
* Only used when an iridescence thickness map is used. The unit is in nm.
* @property {number} iridescenceThicknessMax The maximum thickness for the iridescence layer.
* Used as the 'base' thickness when no iridescence thickness map is defined. The unit is in nm.
* @property {number} iridescenceRefractionIndex The index of refraction of the iridescent
* thin-film. Affects the color phase shift as described here:
* https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_iridescence
* @property {boolean} useMetalness Use metalness properties instead of specular. When enabled,
* diffuse colors also affect specular instead of the dedicated specular map. This can be used as
* alternative to specular color to save space. With metalness == 0, the pixel is assumed to be
* dielectric, and diffuse color is used as normal. With metalness == 1, the pixel is fully
* metallic, and diffuse color is used as specular color instead.
* @property {boolean} useMetalnessSpecularColor When metalness is enabled, use the
* specular map to apply color tint to specular reflections.
* at direct angles.
* @property {number} metalness Defines how much the surface is metallic. From 0 (dielectric) to 1
* (metal).
* @property {Texture|null} metalnessMap Monochrome metalness map (default is null).
* @property {number} metalnessMapUv Metalness map UV channel.
* @property {Vec2} metalnessMapTiling Controls the 2D tiling of the metalness map.
* @property {Vec2} metalnessMapOffset Controls the 2D offset of the metalness map. Each component
* is between 0 and 1.
* @property {number} metalnessMapRotation Controls the 2D rotation (in degrees) of the metalness
* map.
* @property {string} metalnessMapChannel Color channel of the metalness map to use. Can be "r",
* "g", "b" or "a".
* @property {boolean} metalnessVertexColor Use mesh vertex colors for metalness. If metalnessMap
* is set, it'll be multiplied by vertex colors.
* @property {string} metalnessVertexColorChannel Vertex color channel to use for metalness. Can be
* "r", "g", "b" or "a".
* @property {number} gloss Defines the glossiness of the material from 0 (rough) to 1 (shiny).
* @property {Texture|null} glossMap Gloss map (default is null). If specified, will be multiplied
* by normalized gloss value and/or vertex colors.
* @property {boolean} glossInvert Invert the gloss component (default is false). Enabling this
* flag results in material treating the gloss members as roughness.
* @property {number} glossMapUv Gloss map UV channel.
* @property {string} glossMapChannel Color channel of the gloss map to use. Can be "r", "g", "b"
* or "a".
* @property {Vec2} glossMapTiling Controls the 2D tiling of the gloss map.
* @property {Vec2} glossMapOffset Controls the 2D offset of the gloss map. Each component is
* between 0 and 1.
* @property {number} glossMapRotation Controls the 2D rotation (in degrees) of the gloss map.
* @property {boolean} glossVertexColor Use mesh vertex colors for glossiness. If glossMap is set,
* it'll be multiplied by vertex colors.
* @property {string} glossVertexColorChannel Vertex color channel to use for glossiness. Can be
* "r", "g", "b" or "a".
* @property {number} refraction Defines the visibility of refraction. Material can refract the
* same cube map as used for reflections.
* @property {Texture|null} refractionMap The map of the refraction visibility.
* @property {number} refractionMapUv Refraction map UV channel.
* @property {Vec2} refractionMapTiling Controls the 2D tiling of the refraction map.
* @property {Vec2} refractionMapOffset Controls the 2D offset of the refraction map. Each component
* is between 0 and 1.
* @property {number} refractionMapRotation Controls the 2D rotation (in degrees) of the emissive
* map.
* @property {string} refractionMapChannel Color channels of the refraction map to use. Can be "r",
* "g", "b", "a", "rgb" or any swizzled combination.
* @property {boolean} refractionVertexColor Use mesh vertex colors for refraction. If
* refraction map is set, it will be be multiplied by vertex colors.
* @property {boolean} refractionVertexColorChannel Vertex color channel to use for refraction.
* Can be "r", "g", "b" or "a".
* @property {number} refractionIndex Defines the index of refraction, i.e. The amount of
* distortion. The value is calculated as (outerIor / surfaceIor), where inputs are measured
* indices of refraction, the one around the object and the one of its own surface. In most
* situations outer medium is air, so outerIor will be approximately 1. Then you only need to do
* (1.0 / surfaceIor).
* @property {number} dispersion The strength of the angular separation of colors (chromatic
* aberration) transmitting through a volume. Defaults to 0, which is equivalent to no dispersion.
* @property {boolean} useDynamicRefraction Enables higher quality refractions using the grab pass
* instead of pre-computed cube maps for refractions.
* @property {number} thickness The thickness of the medium, only used when useDynamicRefraction
* is enabled. The unit is in base units, and scales with the size of the object.
* @property {Texture|null} thicknessMap The per-pixel thickness of the medium, only used when
* useDynamicRefraction is enabled.
* @property {number} thicknessMapUv Thickness map UV channel.
* @property {Vec2} thicknessMapTiling Controls the 2D tiling of the thickness map.
* @property {Vec2} thicknessMapOffset Controls the 2D offset of the thickness map. Each component is
* between 0 and 1.
* @property {number} thicknessMapRotation Controls the 2D rotation (in degrees) of the thickness
* map.
* @property {string} thicknessMapChannel Color channels of the thickness map to use. Can be "r",
* "g", "b" or "a".
* @property {boolean} thicknessVertexColor Use mesh vertex colors for thickness. If
* thickness map is set, it will be be multiplied by vertex colors.
* @property {Color} attenuation The attenuation color for refractive materials, only used when
* useDynamicRefraction is enabled.
* @property {number} attenuationDistance The distance defining the absorption rate of light
* within the medium. Only used when useDynamicRefraction is enabled.
* @property {Color} emissive The emissive color of the material. This color value is 3-component
* (RGB), where each component is between 0 and 1.
* @property {Texture|null} emissiveMap The emissive map of the material (default is null). Can be
* HDR. When the emissive map is applied, the emissive color is multiplied by the texel color in the
* map. Since the emissive color is black by default, the emissive map won't be visible unless the
* emissive color is changed.
* @property {number} emissiveIntensity Emissive color multiplier.
* @property {number} emissiveMapUv Emissive map UV channel.
* @property {Vec2} emissiveMapTiling Controls the 2D tiling of the emissive map.
* @property {Vec2} emissiveMapOffset Controls the 2D offset of the emissive map. Each component is
* between 0 and 1.
* @property {number} emissiveMapRotation Controls the 2D rotation (in degrees) of the emissive
* map.
* @property {string} emissiveMapChannel Color channels of the emissive map to use. Can be "r",
* "g", "b", "a", "rgb" or any swizzled combination.
* @property {boolean} emissiveVertexColor Use mesh vertex colors for emission. If emissiveMap or
* emissive are set, they'll be multiplied by vertex colors.
* @property {string} emissiveVertexColorChannel Vertex color channels to use for emission. Can be
* "r", "g", "b", "a", "rgb" or any swizzled combination.
* @property {boolean} useSheen Toggle sheen specular effect on/off.
* @property {Color} sheen The specular color of the sheen (fabric) microfiber structure.
* This color value is 3-component (RGB), where each component is between 0 and 1.
* @property {Texture|null} sheenMap The sheen microstructure color map of the material (default is
* null).
* @property {number} sheenMapUv Sheen map UV channel.
* @property {Vec2} sheenMapTiling Controls the 2D tiling of the sheen map.
* @property {Vec2} sheenMapOffset Controls the 2D offset of the sheen map. Each component is
* between 0 and 1.
* @property {number} sheenMapRotation Controls the 2D rotation (in degrees) of the sheen
* map.
* @property {string} sheenMapChannel Color channels of the sheen map to use. Can be "r",
* "g", "b", "a", "rgb" or any swizzled combination.
* @property {boolean} sheenVertexColor Use mesh vertex colors for sheen. If sheen map or
* sheen tint are set, they'll be multiplied by vertex colors.
* @property {number} sheenGloss The glossiness of the sheen (fabric) microfiber structure.
* This color value is a single value between 0 and 1.
* @property {boolean} sheenGlossInvert Invert the sheen gloss component (default is false).
* Enabling this flag results in material treating the sheen gloss members as roughness.
* @property {Texture|null} sheenGlossMap The sheen glossiness microstructure color map of the
* material (default is null).
* @property {number} sheenGlossMapUv Sheen map UV channel.
* @property {Vec2} sheenGlossMapTiling Controls the 2D tiling of the sheen glossiness map.
* @property {Vec2} sheenGlossMapOffset Controls the 2D offset of the sheen glossiness map.
* Each component is between 0 and 1.
* @property {number} sheenGlossMapRotation Controls the 2D rotation (in degrees) of the sheen
* glossiness map.
* @property {string} sheenGlossMapChannel Color channels of the sheen glossiness map to use.
* Can be "r", "g", "b", "a", "rgb" or any swizzled combination.
* @property {boolean} sheenGlossVertexColor Use mesh vertex colors for sheen glossiness.
* If sheen glossiness map or sheen glossiness tint are set, they'll be multiplied by vertex colors.
* @property {string} sheenGlossVertexColorChannel Vertex color channels to use for sheen glossiness.
* Can be "r", "g", "b" or "a".
* @property {number} opacity The opacity of the material. This value can be between 0 and 1, where
* 0 is fully transparent and 1 is fully opaque. If you want the material to be semi-transparent
* you also need to set the {@link Material#blendType} to {@link BLEND_NORMAL},
* {@link BLEND_ADDITIVE} or any other mode. Also note that for most semi-transparent objects you
* want {@link Material#depthWrite} to be false, otherwise they can fully occlude objects behind
* them.
* @property {Texture|null} opacityMap The opacity map of the material (default is null).
* @property {number} opacityMapUv Opacity map UV channel.
* @property {string} opacityMapChannel Color channel of the opacity map to use. Can be "r", "g",
* "b" or "a".
* @property {Vec2} opacityMapTiling Controls the 2D tiling of the opacity map.
* @property {Vec2} opacityMapOffset Controls the 2D offset of the opacity map. Each component is
* between 0 and 1.
* @property {number} opacityMapRotation Controls the 2D rotation (in degrees) of the opacity map.
* @property {boolean} opacityVertexColor Use mesh vertex colors for opacity. If opacityMap is set,
* it'll be multiplied by vertex colors.
* @property {string} opacityVertexColorChannel Vertex color channels to use for opacity. Can be
* "r", "g", "b" or "a".
* @property {boolean} opacityFadesSpecular Used to specify whether specular and reflections are
* faded out using {@link StandardMaterial#opacity}. Default is true. When set to false use
* {@link Material#alphaFade} to fade out materials.
* @property {string} opacityDither Used to specify whether opacity is dithered, which allows
* transparency without alpha blending. Can be:
*
* - {@link DITHER_NONE}: Opacity dithering is disabled.
* - {@link DITHER_BAYER8}: Opacity is dithered using a Bayer 8 matrix.
* - {@link DITHER_BLUENOISE}: Opacity is dithered using a blue noise.
* - {@link DITHER_IGNNOISE}: Opacity is dithered using an interleaved gradient noise.
*
* Defaults to {@link DITHER_NONE}.
* @property {boolean} opacityShadowDither Used to specify whether shadow opacity is dithered, which
* allows shadow transparency without alpha blending. Can be:
*
* - {@link DITHER_NONE}: Opacity dithering is disabled.
* - {@link DITHER_BAYER8}: Opacity is dithered using a Bayer 8 matrix.
* - {@link DITHER_BLUENOISE}: Opacity is dithered using a blue noise.
* - {@link DITHER_IGNNOISE}: Opacity is dithered using an interleaved gradient noise.
*
* Defaults to {@link DITHER_NONE}.
* @property {number} alphaFade Used to fade out materials when
* {@link StandardMaterial#opacityFadesSpecular} is set to false.
* @property {Texture|null} normalMap The main (primary) normal map of the material (default is
* null). The texture must contains normalized, tangent space normals.
* @property {number} normalMapUv Main (primary) normal map UV channel.
* @property {Vec2} normalMapTiling Controls the 2D tiling of the main (primary) normal map.
* @property {Vec2} normalMapOffset Controls the 2D offset of the main (primary) normal map. Each
* component is between 0 and 1.
* @property {number} normalMapRotation Controls the 2D rotation (in degrees) of the main (primary)
* normal map.
* @property {number} bumpiness The bumpiness of the material. This value scales the assigned main
* (primary) normal map. It should be normally between 0 (no bump mapping) and 1 (full bump
* mapping), but can be set to e.g. 2 to give even more pronounced bump effect.
* @property {Texture|null} normalDetailMap The detail (secondary) normal map of the material
* (default is null). Will only be used if main (primary) normal map is non-null.
* @property {number} normalDetailMapUv Detail (secondary) normal map UV channel.
* @property {Vec2} normalDetailMapTiling Controls the 2D tiling of the detail (secondary) normal
* map.
* @property {Vec2} normalDetailMapOffset Controls the 2D offset of the detail (secondary) normal
* map. Each component is between 0 and 1.
* @property {number} normalDetailMapRotation Controls the 2D rotation (in degrees) of the detail
* (secondary) normal map.
* @property {number} normalDetailMapBumpiness The bumpiness of the material. This value scales the
* assigned detail (secondary) normal map. It should be normally between 0 (no bump mapping) and 1
* (full bump mapping), but can be set to e.g. 2 to give even more pronounced bump effect.
* @property {Texture|null} heightMap The height map of the material (default is null). Used for a
* view-dependent parallax effect. The texture must represent the height of the surface where
* darker pixels are lower and lighter pixels are higher. It is recommended to use it together with
* a normal map.
* @property {number} heightMapUv Height map UV channel.
* @property {string} heightMapChannel Color channel of the height map to use. Can be "r", "g", "b"
* or "a".
* @property {Vec2} heightMapTiling Controls the 2D tiling of the height map.
* @property {Vec2} heightMapOffset Controls the 2D offset of the height map. Each component is
* between 0 and 1.
* @property {number} heightMapRotation Controls the 2D rotation (in degrees) of the height map.
* @property {number} heightMapFactor Height map multiplier. Affects the strength of the parallax
* effect.
* @property {Texture|null} envAtlas The prefiltered environment lighting atlas (default is null).
* This setting overrides cubeMap and sphereMap and will replace the scene lighting environment.
* @property {Texture|null} cubeMap The cubic environment map of the material (default is null).
* This setting overrides sphereMap and will replace the scene lighting environment.
* @property {Texture|null} sphereMap The spherical environment map of the material (default is
* null). This will replace the scene lighting environment.
* @property {number} cubeMapProjection The type of projection applied to the cubeMap property:
* - {@link CUBEPROJ_NONE}: The cube map is treated as if it is infinitely far away.
* - {@link CUBEPROJ_BOX}: Box-projection based on a world space axis-aligned bounding box.
* Defaults to {@link CUBEPROJ_NONE}.
* @property {BoundingBox} cubeMapProjectionBox The world space axis-aligned bounding box
* defining the box-projection used for the cubeMap property. Only used when cubeMapProjection is
* set to {@link CUBEPROJ_BOX}.
* @property {number} reflectivity Environment map intensity.
* @property {Texture|null} lightMap A custom lightmap of the material (default is null). Lightmaps
* are textures that contain pre-rendered lighting. Can be HDR.
* @property {number} lightMapUv Lightmap UV channel
* @property {string} lightMapChannel Color channels of the lightmap to use. Can be "r", "g", "b",
* "a", "rgb" or any swizzled combination.
* @property {Vec2} lightMapTiling Controls the 2D tiling of the lightmap.
* @property {Vec2} lightMapOffset Controls the 2D offset of the lightmap. Each component is
* between 0 and 1.
* @property {number} lightMapRotation Controls the 2D rotation (in degrees) of the lightmap.
* @property {boolean} lightVertexColor Use baked vertex lighting. If lightMap is set, it'll be
* multiplied by vertex colors.
* @property {string} lightVertexColorChannel Vertex color channels to use for baked lighting. Can
* be "r", "g", "b", "a", "rgb" or any swizzled combination.
* @property {number} aoIntensity Ambient occlusion intensity. Defaults to 1.
* @property {Texture|null} aoMap The main (primary) baked ambient occlusion (AO) map (default is
* null). Modulates ambient color.
* @property {number} aoMapUv Main (primary) AO map UV channel
* @property {string} aoMapChannel Color channel of the main (primary) AO map to use. Can be "r", "g", "b" or "a".
* @property {Vec2} aoMapTiling Controls the 2D tiling of the main (primary) AO map.
* @property {Vec2} aoMapOffset Controls the 2D offset of the main (primary) AO map. Each component is between 0
* and 1.
* @property {number} aoMapRotation Controls the 2D rotation (in degrees) of the main (primary) AO map.
* @property {boolean} aoVertexColor Use mesh vertex colors for AO. If aoMap is set, it'll be
* multiplied by vertex colors.
* @property {string} aoVertexColorChannel Vertex color channels to use for AO. Can be "r", "g",
* "b" or "a".
* @property {Texture|null} aoDetailMap The detail (secondary) baked ambient occlusion (AO) map of
* the material (default is null). Will only be used if main (primary) ao map is non-null.
* @property {number} aoDetailMapUv Detail (secondary) AO map UV channel.
* @property {Vec2} aoDetailMapTiling Controls the 2D tiling of the detail (secondary) AO map.
* @property {Vec2} aoDetailMapOffset Controls the 2D offset of the detail (secondary) AO map. Each
* component is between 0 and 1.
* @property {number} aoDetailMapRotation Controls the 2D rotation (in degrees) of the detail
* (secondary) AO map.
* @property {string} aoDetailMapChannel Color channels of the detail (secondary) AO map to use.
* Can be "r", "g", "b" or "a" (default is "g").
* @property {string} aoDetailMode Determines how the main (primary) and detail (secondary)
* AO maps are blended together. Can be:
*
* - {@link DETAILMODE_MUL}: Multiply together the primary and secondary colors.
* - {@link DETAILMODE_ADD}: Add together the primary and secondary colors.
* - {@link DETAILMODE_SCREEN}: Softer version of {@link DETAILMODE_ADD}.
* - {@link DETAILMODE_OVERLAY}: Multiplies or screens the colors, depending on the primary color.
* - {@link DETAILMODE_MIN}: Select whichever of the primary and secondary colors is darker,
* component-wise.
* - {@link DETAILMODE_MAX}: Select whichever of the primary and secondary colors is lighter,
* component-wise.
*
* Defaults to {@link DETAILMODE_MUL}.
* @property {number} occludeSpecular Uses ambient occlusion to darken specular/reflection. It's a
* hack, because real specular occlusion is view-dependent. However, it can be better than nothing.
*
* - {@link SPECOCC_NONE}: No specular occlusion
* - {@link SPECOCC_AO}: Use AO directly to occlude specular.
* - {@link SPECOCC_GLOSSDEPENDENT}: Modify AO based on material glossiness/view angle to occlude
* specular.
*
* @property {number} occludeSpecularIntensity Controls visibility of specular occlusion.
* @property {boolean} occludeDirect Tells if AO should darken directional lighting. Defaults to
* false.
* @property {number} fresnelModel Defines the formula used for Fresnel effect.
* As a side-effect, enabling any Fresnel model changes the way diffuse and reflection components
* are combined. When Fresnel is off, legacy non energy-conserving combining is used. When it is
* on, combining behavior is energy-conserving.
*
* - {@link FRESNEL_NONE}: No Fresnel.
* - {@link FRESNEL_SCHLICK}: Schlick's approximation of Fresnel (recommended). Parameterized by
* specular color.
*
* @property {boolean} useFog Apply fogging (as configured in scene settings)
* @property {boolean} useLighting Apply lighting
* @property {boolean} useSkybox Apply scene skybox as prefiltered environment map
* @property {boolean} useTonemap Apply tonemapping (as configured in {@link Scene#rendering} or
* {@link CameraComponent.rendering}). Defaults to true.
* @property {boolean} pixelSnap Align vertices to pixel coordinates when rendering. Useful for
* pixel perfect 2D graphics.
* @property {boolean} twoSidedLighting Calculate proper normals (and therefore lighting) on
* backfaces.
* @property {boolean} shadowCatcher When enabled, the material will output accumulated directional
* shadow value in linear space as the color.
*
* @category Graphics
*/ class StandardMaterial extends Material {
static{
this.TEXTURE_PARAMETERS = standardMaterialTextureParameters;
}
static{
this.CUBEMAP_PARAMETERS = standardMaterialCubemapParameters;
}
/**
* Create a new StandardMaterial instance.
*
* @example
* // Create a new Standard material
* const material = new pc.StandardMaterial();
*
* // Update the material's diffuse and specular properties
* material.diffuse.set(1, 0, 0);
* material.specular.set(1, 1, 1);
*
* // Notify the material that it has been modified
* material.update();
* @example
* // Create a new Standard material
* const material = new pc.StandardMaterial();
*
* // Assign a texture to the diffuse slot
* material.diffuseMap = texture;
*
* // Use the alpha channel of the texture for alpha testing with a reference value of 0.5
* material.opacityMap = texture;
* material.alphaTest = 0.5;
*
* // Notify the material that it has been modified
* material.update();
*/ constructor(){
super(), this.userAttributes = new Map();
// storage for texture and cubemap asset references
this._assetReferences = {};
this._activeParams = new Set();
this._activeLightingParams = new Set();
this.shaderOptBuilder = new StandardMaterialOptionsBuilder();
this.reset();
}
reset() {
// set default values
Object.keys(_props).forEach((name)=>{
this[`_${name}`] = _props[name].value();
});
this._uniformCache = {};
}
/**
* Copy a `StandardMaterial`.
*
* @param {StandardMaterial} source - The material to copy from.
* @returns {StandardMaterial} The destination material.
*/ copy(source) {
super.copy(source);
// set properties
Object.keys(_props).forEach((k)=>{
this[k] = source[k];
});
// clone user attributes
this.userAttributes = new Map(source.userAttributes);
return this;
}
/**
* Sets a vertex shader attribute on a material.
*
* @param {string} name - The name of the parameter to set.
* @param {string} semantic - Semantic to map the vertex data. Must match with the semantic set
* on vertex stream of the mesh.
* @example
* mesh.setVertexStream(pc.SEMANTIC_ATTR15, offset, 3);
* material.setAttribute('offset', pc.SEMANTIC_ATTR15);
*/ setAttribute(name, semantic) {
this.userAttributes.set(semantic, name);
}
_setParameter(name, value) {
_params.add(name);
this.setParameter(name, value);
}
_setParameters(parameters) {
parameters.forEach((v)=>{
this._setParameter(v.name, v.value);
});
}
_processParameters(paramsName) {
const prevParams = this[paramsName];
prevParams.forEach((param)=>{
if (!_params.has(param)) {
delete this.parameters[param];
}
});
this[paramsName] = _params;
_params = prevParams;
_params.clear();
}
_updateMap(p) {
const mname = `${p}Map`;
const map = this[mname];
if (map) {
this._setParameter(`texture_${mname}`, map);
const tname = `${mname}Transform`;
const uniform = this.getUniform(tname);
if (uniform) {
this._setParameters(uniform);
}
}
}
// allocate a uniform if it doesn't already exist in the uniform cache
_allocUniform(name, allocFunc) {
let uniform = this._uniformCache[name];
if (!uniform) {
uniform = allocFunc();
this._uniformCache[name] = uniform;
}
return uniform;
}
getUniform(name, device, scene) {
return _uniforms[name](this, device, scene);
}
updateUniforms(device, scene) {
const getUniform = (name)=>{
return this.getUniform(name, device, scene);
};
this._setParameter('material_ambient', getUniform('ambient'));
this._setParameter('material_diffuse', getUniform('diffuse'));
this._setParameter('material_aoIntensity', this.aoIntensity);
if (this.useMetalness) {
if (!this.metalnessMap || this.metalness < 1) {
this._setParameter('material_metalness', this.metalness);
}
if (!this.specularMap || this.specularTint) {
this._setParameter('material_specular', getUniform('specular'));
}
if (!this.specularityFactorMap || this.specularityFactorTint) {
this._setParameter('material_specularityFactor', this.specularityFactor);
}
this._setParameter('material_sheen', getUniform('sheen'));
this._setParameter('material_sheenGloss', this.sheenGloss);
this._setParameter('material_refractionIndex', this.refractionIndex);
} else {
if (!this.specularMap || this.specularTint) {
this._setParameter('material_specular', getUniform('specular'));
}
}
if (this.enableGGXSpecular) {
this._setParameter('material_anisotropyIntensity', this.anisotropyIntensity);
this._setParameter('material_anisotropyRotation', [
Math.cos(this.anisotropyRotation * math.DEG_TO_RAD),
Math.sin(this.anisotropyRotation * math.DEG_TO_RAD)
]);
}
if (this.clearCoat > 0) {
this._setParameter('material_clearCoat', this.clearCoat);
this._setParameter('material_clearCoatGloss', this.clearCoatGloss);
this._setParameter('material_clearCoatBumpiness', this.clearCoatBumpiness);
}
this._setParameter('material_gloss', this.gloss);
Debug.call(()=>{
if (this.emissiveMap && this.emissive.r === 0 && this.emissive.g === 0 && this.emissive.b === 0) {
Debug.warnOnce(`Emissive map is set but emissive color is black, making the map invisible. Set emissive color to white to make the map visible. Rendering [${DebugGraphics.toString()}]`, this);
}
});
this._setParameter('material_emissive', getUniform('emissive'));
this._setParameter('material_emissiveIntensity', this.emissiveIntensity);
if (this.refraction > 0) {
this._setParameter('material_refraction', this.refraction);
}
if (this.dispersion > 0) {
this._setParameter('material_dispersion', this.dispersion);
}
if (this.useDynamicRefraction) {
this._setParameter('material_thickness', this.thickness);
this._setParameter('material_attenuation', getUniform('attenuation'));
this._setParameter('material_invAttenuationDistance', this.attenuationDistance === 0 ? 0 : 1.0 / this.attenuationDistance);
}
if (this.useIridescence) {
this._setParameter('material_iridescence', this.iridescence);
this._setParameter('material_iridescenceRefractionIndex', this.iridescenceRefractionIndex);
this._setParameter('material_iridescenceThicknessMin', this.iridescenceThicknessMin);
this._setParameter('material_iridescenceThicknessMax', this.iridescenceThicknessMax);
}
this._setParameter('material_opacity', this.opacity);
if (this.opacityFadesSpecular === false) {
this._setParameter('material_alphaFade', this.alphaFade);
}
if (this.occludeSpecular) {
this._setParameter('material_occludeSpecularIntensity', this.occludeSpecularIntensity);
}
if (this.cubeMapProjection === CUBEPROJ_BOX) {
this._setParameter(getUniform('cubeMapProjectionBox'));
}
for(const p in _matTex2D){
this._updateMap(p);
}
if (this.ambientSH) {
this._setParameter('ambientSH[0]', this.ambientSH);
}
if (this.normalMap) {
this._setParameter('material_bumpiness', this.bumpiness);
}
if (this.normalMap && this.normalDetailMap) {
this._setParameter('material_normalDetailMapBumpiness', this.normalDetailMapBumpiness);
}
if (this.heightMap) {
this._setParameter('material_heightMapFactor', getUniform('heightMapFactor'));
}
// set overridden environment textures
if (this.envAtlas && this.cubeMap) {
this._setParameter('texture_envAtlas', this.envAtlas);
this._setParameter('texture_cubeMap', this.cubeMap);
} else if (this.envAtlas) {
this._setParameter('texture_envAtlas', this.envAtlas);
} else if (this.cubeMap) {
this._setParameter('texture_cubeMap', this.cubeMap);
} else if (this.sphereMap) {
this._setParameter('texture_sphereMap', this.sphereMap);
}
this._setParameter('material_reflectivity', this.reflectivity);
// remove unused params
this._processParameters('_activeParams');
super.updateUniforms(device, scene);
}
updateEnvUniforms(device, scene) {
const hasLocalEnvOverride = this.envAtlas || this.cubeMap || this.sphereMap;
if (!hasLocalEnvOverride && this.useSkybox) {
if (scene.envAtlas && scene.skybox) {
this._setParameter('texture_envAtlas', scene.envAtlas);
this._setParameter('texture_cubeMap', scene.skybox);
} else if (scene.envAtlas) {
this._setParameter('texture_envAtlas', scene.envAtlas);
} else if (scene.skybox) {
this._setParameter('texture_cubeMap', scene.skybox);
}
}
this._processParameters('_activeLightingParams');
}
getShaderVariant(params) {
const { device, scene, pass, objDefs, sortedLights, cameraShaderParams } = params;
// update prefiltered lighting data
this.updateEnvUniforms(device, scene);
// Minimal options for Depth, Shadow and Prepass passes
const shaderPassInfo = ShaderPass.get(device).getByIndex(pass);
const minimalOptions = pass === SHADER_PICK || pass === SHADER_PREPASS || shaderPassInfo.isShadow;
let options = minimalOptions ? standard.optionsContextMin : standard.optionsContext;
options.defines = ShaderUtils.getCoreDefines(this, params);
if (minimalOptions) {
this.shaderOptBuilder.updateMinRef(options, scene, this, objDefs, pass, sortedLights);
} else {
this.shaderOptBuilder.updateRef(options, scene, cameraShaderParams, this, objDefs, pass, sortedLights);
}
// standard material can overwrite camera's fog setting
if (!this.useFog) options.defines.set('FOG', 'NONE');
// standard material can overwrite camera's tonemapping setting
options.defines.set('TONEMAP', tonemapNames[options.litOptions.toneMap]);
// execute user callback to modify the options
if (this.onUpdateShader) {
options = this.onUpdateShader(options);
}
const processingOptions = new ShaderProcessorOptions(params.viewUniformFormat, params.viewBindGroupFormat, params.vertexFormat);
const library = getProgramLibrary(device);
library.register('standard', standard);
const shader = library.getProgram('standard', options, processingOptions, this.userId);
this._dirtyShader = false;
return shader;
}
/**
* Removes this material from the scene and possibly frees up memory from its shaders (if there
* are no other materials using it).
*/ destroy() {
// unbind (texture) asset references
for(const asset in this._assetReferences){
this._assetReferences[asset]._unbind();
}
this._assetReferences = null;
super.destroy();
}
}
// define a uniform get function
const defineUniform = (name, getUniformFunc)=>{
_uniforms[name] = getUniformFunc;
};
const definePropInternal = (name, constructorFunc, setterFunc, getterFunc)=>{
Object.defineProperty(StandardMaterial.prototype, name, {
get: getterFunc || function() {
return this[`_${name}`];
},
set: setterFunc
});
_props[name] = {
value: constructorFunc
};
};
// define a simple value property (float, string etc)
const defineValueProp = (prop)=>{
const internalName = `_${prop.name}`;
const dirtyShaderFunc = prop.dirtyShaderFunc || (()=>true);
const setterFunc = function(value) {
const oldValue = this[internalName];
if (oldValue !== value) {
this._dirtyShader = this._dirtyShader || dirtyShaderFunc(oldValue, value);
this[internalName] = value;
}
};
definePropInternal(prop.name, ()=>prop.defaultValue, setterFunc, prop.getterFunc);
};
// define an aggregate property (color, vec3 etc)
const defineAggProp = (prop)=>{
const internalName = `_${prop.name}`;
const dirtyShaderFunc = prop.dirtyShaderFunc || (()=>true);
const setterFunc = function(value) {
const oldValue = this[internalName];
if (!oldValue.equals(value)) {
this._dirtyShader = this._dirtyShader || dirtyShaderFunc(oldValue, value);
this[internalName] = oldValue.copy(value);
}
};
definePropInternal(prop.name, ()=>prop.defaultValue.clone(), setterFunc, prop.getterFunc);
};
// define either a value or aggregate property
const defineProp = (prop)=>{
return prop.defaultValue && prop.defaultValue.clone ? defineAggProp(prop) : defineValueProp(prop);
};
function _defineTex2D(name, channel = 'rgb', vertexColor = true, uv = 0) {
// store texture name
_matTex2D[name] = channel.length || -1;
defineProp({
name: `${name}Map`,
defaultValue: null,
dirtyShaderFunc: (oldValue, newValue)=>{
return !!oldValue !== !!newValue || oldValue && (oldValue.type !== newValue.type || oldValue.format !== newValue.format);
}
});
defineProp({
name: `${name}MapTiling`,
defaultValue: new Vec2(1, 1)
});
defineProp({
name: `${name}MapOf