@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.
297 lines (295 loc) • 13.1 kB
JavaScript
import { __decorate } from "../../tslib.es6.js";
import { MaterialDefines } from "../../Materials/materialDefines.js";
import { MaterialPluginBase } from "../../Materials/materialPluginBase.js";
import { PBRBaseMaterial } from "../../Materials/PBR/pbrBaseMaterial.js";
import { expandToProperty, serialize } from "../../Misc/decorators.js";
import { RegisterClass } from "../../Misc/typeStore.js";
/**
* @internal
*/
class MaterialIBLShadowsRenderDefines extends MaterialDefines {
constructor() {
super(...arguments);
this.RENDER_WITH_IBL_SHADOWS = false;
this.COLORED_IBL_SHADOWS = false;
}
}
/**
* Plugin used to render the contribution from IBL shadows.
*/
export class IBLShadowsPluginMaterial extends MaterialPluginBase {
get iblShadowsTexture() {
return this._iblShadowsTexture;
}
set iblShadowsTexture(value) {
if (this._iblShadowsTexture === value) {
return;
}
this._iblShadowsTexture = value;
this._markAllSubMeshesAsTexturesDirty();
}
get isColored() {
return this._isColored;
}
set isColored(value) {
if (this._isColored === value) {
return;
}
this._isColored = value;
this._markAllSubMeshesAsTexturesDirty();
}
_markAllSubMeshesAsTexturesDirty() {
this._enable(this._isEnabled);
this._internalMarkAllSubMeshesAsTexturesDirty();
}
/**
* Gets a boolean indicating that the plugin is compatible with a give shader language.
* @returns true if the plugin is compatible with the shader language
*/
isCompatible() {
return true;
}
constructor(material) {
super(material, IBLShadowsPluginMaterial.Name, 310, new MaterialIBLShadowsRenderDefines());
/**
* The opacity of the shadows.
*/
this.shadowOpacity = 1.0;
this._isEnabled = false;
this._isColored = false;
/**
* Defines if the plugin is enabled in the material.
*/
this.isEnabled = false;
this._internalMarkAllSubMeshesAsTexturesDirty = material._dirtyCallbacks[1];
}
_isOpenPBRMaterial() {
return this._material.getClassName() === "OpenPBRMaterial";
}
prepareDefines(defines) {
defines.RENDER_WITH_IBL_SHADOWS = this._isEnabled;
defines.COLORED_IBL_SHADOWS = this.isColored;
}
getClassName() {
return "IBLShadowsPluginMaterial";
}
getUniforms(_shaderLanguage) {
const result = {};
result.ubo = [];
if (this._isOpenPBRMaterial()) {
if (_shaderLanguage === 1 /* ShaderLanguage.WGSL */) {
result.fragment = `
var shadowOpacity: f32;
}
else {
result.fragment = `
uniform float shadowOpacity;
}
}
else {
result.ubo.push({ name: "renderTargetSize", size: 2, type: "vec2" });
if (_shaderLanguage === 1 /* ShaderLanguage.WGSL */) {
result.fragment = `
var renderTargetSize: vec2f;
var shadowOpacity: f32;
}
else {
result.fragment = `
uniform vec2 renderTargetSize;
uniform float shadowOpacity;
}
}
result.ubo.push({ name: "shadowOpacity", size: 1, type: "float" });
return result;
}
getSamplers(samplers) {
samplers.push("iblShadowsTexture");
}
bindForSubMesh(uniformBuffer) {
if (this._isEnabled && this.iblShadowsTexture) {
uniformBuffer.bindTexture("iblShadowsTexture", this.iblShadowsTexture);
uniformBuffer.updateFloat2("renderTargetSize", this._material.getScene().getEngine().getRenderWidth(), this._material.getScene().getEngine().getRenderHeight());
uniformBuffer.updateFloat("shadowOpacity", this.shadowOpacity);
}
}
getCustomCode(shaderType, shaderLanguage) {
let frag;
if (shaderLanguage === 1 /* ShaderLanguage.WGSL */) {
frag = {
// eslint-disable-next-line @typescript-eslint/naming-convention
CUSTOM_FRAGMENT_DEFINITIONS: `
var iblShadowsTextureSampler: sampler;
var iblShadowsTexture: texture_2d<f32>;
fn computeIndirectShadow() -> vec3f {
var uv = fragmentInputs.position.xy / uniforms.renderTargetSize;
var shadowValue: vec3f = textureSample(iblShadowsTexture, iblShadowsTextureSampler, uv).rgb;
return mix(shadowValue, vec3f(1.0), 1.0 - uniforms.shadowOpacity);
}
fn computeIndirectShadow() -> vec2f {
var uv = fragmentInputs.position.xy / uniforms.renderTargetSize;
var shadowValue: vec2f = textureSample(iblShadowsTexture, iblShadowsTextureSampler, uv).rg;
return mix(shadowValue, vec2f(1.0), 1.0 - uniforms.shadowOpacity);
}
`,
};
if (this._material instanceof PBRBaseMaterial) {
// eslint-disable-next-line @typescript-eslint/naming-convention
frag["CUSTOM_FRAGMENT_BEFORE_FINALCOLORCOMPOSITION"] = `
var shadowValue: vec3f = computeIndirectShadow();
finalIrradiance *= shadowValue;
finalRadianceScaled *= mix(vec3f(1.0), shadowValue, roughness);
var shadowValue: vec2f = computeIndirectShadow();
finalIrradiance *= vec3f(shadowValue.x);
finalRadianceScaled *= vec3f(mix(pow(shadowValue.y, 4.0), shadowValue.x, roughness));
finalDiffuse *= computeIndirectShadow().x;
`;
}
else if (this._isOpenPBRMaterial()) {
// eslint-disable-next-line @typescript-eslint/naming-convention
frag["CUSTOM_FRAGMENT_BEFORE_IBLLAYERCOMPOSITION"] = `
var shadowValue: vec3f = computeIndirectShadow();
ambient_occlusion = min(ambient_occlusion, shadowValue);
var shadowValue: vec2f = computeIndirectShadow();
ambient_occlusion = min(ambient_occlusion, vec3f(shadowValue.x));
specular_ambient_occlusion = min(specular_ambient_occlusion, pow(shadowValue.y, 4.0));
ambient_occlusion = min(ambient_occlusion, vec3f(computeIndirectShadow().x));
`;
}
else {
frag["CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR"] = `
var shadowValue: vec3f = computeIndirectShadow();
color *= toGammaSpace(vec4f(shadowValue, 1.0f));
var shadowValue: vec2f = computeIndirectShadow();
color *= toGammaSpace(vec4f(shadowValue.x, shadowValue.x, shadowValue.x, 1.0f));
`;
}
}
else {
frag = {
// eslint-disable-next-line @typescript-eslint/naming-convention
CUSTOM_FRAGMENT_DEFINITIONS: `
uniform sampler2D iblShadowsTexture;
vec3 computeIndirectShadow() {
vec2 uv = gl_FragCoord.xy / renderTargetSize;
vec3 shadowValue = texture2D(iblShadowsTexture, uv).rgb;
return mix(shadowValue.rgb, vec3(1.0), 1.0 - shadowOpacity);
}
vec2 computeIndirectShadow() {
vec2 uv = gl_FragCoord.xy / renderTargetSize;
vec2 shadowValue = texture2D(iblShadowsTexture, uv).rg;
return mix(shadowValue.rg, vec2(1.0), 1.0 - shadowOpacity);
}
`,
};
if (this._material instanceof PBRBaseMaterial) {
// eslint-disable-next-line @typescript-eslint/naming-convention
frag["CUSTOM_FRAGMENT_BEFORE_FINALCOLORCOMPOSITION"] = `
vec3 shadowValue = computeIndirectShadow();
finalIrradiance.rgb *= shadowValue.rgb;
finalRadianceScaled *= mix(vec3(1.0), shadowValue.rgb, roughness);
vec2 shadowValue = computeIndirectShadow();
finalIrradiance *= shadowValue.x;
finalRadianceScaled *= mix(pow(shadowValue.y, 4.0), shadowValue.x, roughness);
finalDiffuse *= computeIndirectShadow().x;
`;
}
else if (this._isOpenPBRMaterial()) {
// eslint-disable-next-line @typescript-eslint/naming-convention
frag["CUSTOM_FRAGMENT_BEFORE_IBLLAYERCOMPOSITION"] = `
vec3 shadowValue = computeIndirectShadow();
ambient_occlusion = min(ambient_occlusion, shadowValue);
vec2 shadowValue = computeIndirectShadow();
ambient_occlusion = min(ambient_occlusion, vec3(shadowValue.x));
specular_ambient_occlusion = min(specular_ambient_occlusion, pow(shadowValue.y, 4.0));
ambient_occlusion = min(ambient_occlusion, vec3(computeIndirectShadow().x));
`;
}
else {
frag["CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR"] = `
vec3 shadowValue = computeIndirectShadow();
color.rgb *= toGammaSpace(shadowValue.rgb);
vec2 shadowValue = computeIndirectShadow();
color.rgb *= toGammaSpace(shadowValue.x);
`;
}
}
return shaderType === "vertex" ? null : frag;
}
}
/**
* Defines the name of the plugin.
*/
IBLShadowsPluginMaterial.Name = "IBLShadowsPluginMaterial";
__decorate([
serialize()
], IBLShadowsPluginMaterial.prototype, "shadowOpacity", void 0);
__decorate([
serialize(),
expandToProperty("_markAllSubMeshesAsTexturesDirty")
], IBLShadowsPluginMaterial.prototype, "isEnabled", void 0);
RegisterClass(`BABYLON.IBLShadowsPluginMaterial`, IBLShadowsPluginMaterial);
//# sourceMappingURL=iblShadowsPluginMaterial.js.map