@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.
262 lines (260 loc) • 13.8 kB
JavaScript
import { __decorate } from "../../../../tslib.es6.js";
import { NodeMaterialBlock } from "../../nodeMaterialBlock.js";
import { NodeMaterialBlockConnectionPointTypes } from "../../Enums/nodeMaterialBlockConnectionPointTypes.js";
import { NodeMaterialBlockTargets } from "../../Enums/nodeMaterialBlockTargets.js";
import { RegisterClass } from "../../../../Misc/typeStore.js";
import { InputBlock } from "../Input/inputBlock.js";
import { NodeMaterialConnectionPointCustomObject } from "../../nodeMaterialConnectionPointCustomObject.js";
import { RefractionBlock } from "./refractionBlock.js";
import { editableInPropertyPage } from "../../../../Decorators/nodeDecorator.js";
import { PBRSubSurfaceConfiguration } from "../../../PBR/pbrSubSurfaceConfiguration.js";
/**
* Block used to implement the sub surface module of the PBR material
*/
export class SubSurfaceBlock extends NodeMaterialBlock {
/**
* Create a new SubSurfaceBlock
* @param name defines the block name
*/
constructor(name) {
super(name, NodeMaterialBlockTargets.Fragment);
/**
* Set it to true if your rendering in 8.0+ is different from that in 7 when you use sub-surface properties (transmission, refraction, etc.)
*/
this.applyAlbedoAfterSubSurface = PBRSubSurfaceConfiguration.DEFAULT_APPLY_ALBEDO_AFTERSUBSURFACE;
this._isUnique = true;
this.registerInput("thickness", NodeMaterialBlockConnectionPointTypes.Float, false, NodeMaterialBlockTargets.Fragment);
this.registerInput("tintColor", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
this.registerInput("translucencyIntensity", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
this.registerInput("translucencyDiffusionDist", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
this.registerInput("refraction", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment, new NodeMaterialConnectionPointCustomObject("refraction", this, 0 /* NodeMaterialConnectionPointDirection.Input */, RefractionBlock, "RefractionBlock"));
this.registerInput("dispersion", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
this.registerOutput("subsurface", NodeMaterialBlockConnectionPointTypes.Object, NodeMaterialBlockTargets.Fragment, new NodeMaterialConnectionPointCustomObject("subsurface", this, 1 /* NodeMaterialConnectionPointDirection.Output */, SubSurfaceBlock, "SubSurfaceBlock"));
}
/**
* Initialize the block and prepare the context for build
* @param state defines the state that will be used for the build
*/
initialize(state) {
state._excludeVariableName("subSurfaceOut");
state._excludeVariableName("vThicknessParam");
state._excludeVariableName("vTintColor");
state._excludeVariableName("vTranslucencyColor");
state._excludeVariableName("vSubSurfaceIntensity");
state._excludeVariableName("dispersion");
}
/**
* Gets the current class name
* @returns the class name
*/
getClassName() {
return "SubSurfaceBlock";
}
/**
* Gets the thickness component
*/
get thickness() {
return this._inputs[0];
}
/**
* Gets the tint color input component
*/
get tintColor() {
return this._inputs[1];
}
/**
* Gets the translucency intensity input component
*/
get translucencyIntensity() {
return this._inputs[2];
}
/**
* Gets the translucency diffusion distance input component
*/
get translucencyDiffusionDist() {
return this._inputs[3];
}
/**
* Gets the refraction object parameters
*/
get refraction() {
return this._inputs[4];
}
/**
* Gets the dispersion input component
*/
get dispersion() {
return this._inputs[5];
}
/**
* Gets the sub surface object output component
*/
get subsurface() {
return this._outputs[0];
}
autoConfigure() {
if (!this.thickness.isConnected) {
const thicknessInput = new InputBlock("SubSurface thickness", NodeMaterialBlockTargets.Fragment, NodeMaterialBlockConnectionPointTypes.Float);
thicknessInput.value = 0;
thicknessInput.output.connectTo(this.thickness);
}
}
prepareDefines(defines) {
const translucencyEnabled = this.translucencyDiffusionDist.isConnected || this.translucencyIntensity.isConnected;
defines.setValue("SUBSURFACE", translucencyEnabled || this.refraction.isConnected, true);
defines.setValue("SS_TRANSLUCENCY", translucencyEnabled, true);
defines.setValue("SS_THICKNESSANDMASK_TEXTURE", false, true);
defines.setValue("SS_REFRACTIONINTENSITY_TEXTURE", false, true);
defines.setValue("SS_TRANSLUCENCYINTENSITY_TEXTURE", false, true);
defines.setValue("SS_USE_GLTF_TEXTURES", false, true);
defines.setValue("SS_DISPERSION", this.dispersion.isConnected, true);
defines.setValue("SS_APPLY_ALBEDO_AFTER_SUBSURFACE", this.applyAlbedoAfterSubSurface, true);
}
/**
* Gets the main code of the block (fragment side)
* @param state current state of the node material building
* @param ssBlock instance of a SubSurfaceBlock or null if the code must be generated without an active sub surface module
* @param reflectionBlock instance of a ReflectionBlock null if the code must be generated without an active reflection module
* @param worldPosVarName name of the variable holding the world position
* @returns the shader code
*/
static GetCode(state, ssBlock, reflectionBlock, worldPosVarName) {
let code = "";
const thickness = ssBlock?.thickness.isConnected ? ssBlock.thickness.associatedVariableName : "0.";
const tintColor = ssBlock?.tintColor.isConnected ? ssBlock.tintColor.associatedVariableName : "vec3(1.)";
const translucencyIntensity = ssBlock?.translucencyIntensity.isConnected ? ssBlock?.translucencyIntensity.associatedVariableName : "1.";
const translucencyDiffusionDistance = ssBlock?.translucencyDiffusionDist.isConnected ? ssBlock?.translucencyDiffusionDist.associatedVariableName : "vec3(1.)";
const refractionBlock = (ssBlock?.refraction.isConnected ? ssBlock?.refraction.connectedPoint?.ownerBlock : null);
const refractionTintAtDistance = refractionBlock?.tintAtDistance.isConnected ? refractionBlock.tintAtDistance.associatedVariableName : "1.";
const refractionIntensity = refractionBlock?.intensity.isConnected ? refractionBlock.intensity.associatedVariableName : "1.";
const refractionView = refractionBlock?.view.isConnected ? refractionBlock.view.associatedVariableName : "";
const dispersion = ssBlock?.dispersion.isConnected ? ssBlock?.dispersion.associatedVariableName : "0.0";
const isWebGPU = state.shaderLanguage === 1 /* ShaderLanguage.WGSL */;
code += refractionBlock?.getCode(state) ?? "";
code += `${isWebGPU ? "var subSurfaceOut: subSurfaceOutParams" : "subSurfaceOutParams subSurfaceOut"};
#ifdef SUBSURFACE
${state._declareLocalVar("vThicknessParam", NodeMaterialBlockConnectionPointTypes.Vector2)} = vec2${state.fSuffix}(0., ${thickness});
${state._declareLocalVar("vTintColor", NodeMaterialBlockConnectionPointTypes.Vector4)} = vec4${state.fSuffix}(${tintColor}, ${refractionTintAtDistance});
${state._declareLocalVar("vSubSurfaceIntensity", NodeMaterialBlockConnectionPointTypes.Vector3)} = vec3(${refractionIntensity}, ${translucencyIntensity}, 0.);
${state._declareLocalVar("dispersion", NodeMaterialBlockConnectionPointTypes.Float)} = ${dispersion};
subSurfaceOut = subSurfaceBlock(
vSubSurfaceIntensity
, vThicknessParam
, vTintColor
, normalW
#ifdef LEGACY_SPECULAR_ENERGY_CONSERVATION
`;
code += isWebGPU
? `, vec3f(max(colorSpecularEnvironmentReflectance.r, max(colorSpecularEnvironmentReflectance.g, colorSpecularEnvironmentReflectance.b)))/n`
: `, vec3(max(colorSpecularEnvironmentReflectance.r, max(colorSpecularEnvironmentReflectance.g, colorSpecularEnvironmentReflectance.b)))/n`;
code += `#else
, baseSpecularEnvironmentReflectance
#endif
#ifdef SS_THICKNESSANDMASK_TEXTURE
, vec4${state.fSuffix}(0.)
#endif
#ifdef REFLECTION
#ifdef SS_TRANSLUCENCY
, ${(isWebGPU ? "uniforms." : "") + reflectionBlock?._reflectionMatrixName}
#ifdef USESPHERICALFROMREFLECTIONMAP
#if !defined(NORMAL) || !defined(USESPHERICALINVERTEX)
, reflectionOut.irradianceVector
#endif
#if defined(REALTIME_FILTERING)
, ${reflectionBlock?._cubeSamplerName}
${isWebGPU ? `, ${reflectionBlock?._cubeSamplerName}Sampler` : ""}
, ${reflectionBlock?._vReflectionFilteringInfoName}
#endif
#endif
#ifdef USEIRRADIANCEMAP
, irradianceSampler
${isWebGPU ? `, irradianceSamplerSampler` : ""}
#endif
#endif
#endif
#if defined(SS_REFRACTION) || defined(SS_TRANSLUCENCY)
, surfaceAlbedo
#endif
#ifdef SS_REFRACTION
, ${worldPosVarName}.xyz
, viewDirectionW
, ${refractionView}
, ${(isWebGPU ? "uniforms." : "") + (refractionBlock?._vRefractionInfosName ?? "")}
, ${(isWebGPU ? "uniforms." : "") + (refractionBlock?._refractionMatrixName ?? "")}
, ${(isWebGPU ? "uniforms." : "") + (refractionBlock?._vRefractionMicrosurfaceInfosName ?? "")}
, ${isWebGPU ? "uniforms." : ""}vLightingIntensity
#ifdef SS_LINKREFRACTIONTOTRANSPARENCY
, alpha
#endif
#ifdef ${refractionBlock?._defineLODRefractionAlpha ?? "IGNORE"}
, NdotVUnclamped
#endif
#ifdef ${refractionBlock?._defineLinearSpecularRefraction ?? "IGNORE"}
, roughness
#endif
, alphaG
#ifdef ${refractionBlock?._define3DName ?? "IGNORE"}
, ${refractionBlock?._cubeSamplerName ?? ""}
${isWebGPU ? `, ${refractionBlock?._cubeSamplerName}Sampler` : ""}
#else
, ${refractionBlock?._2DSamplerName ?? ""}
${isWebGPU ? `, ${refractionBlock?._2DSamplerName}Sampler` : ""}
#endif
#ifndef LODBASEDMICROSFURACE
#ifdef ${refractionBlock?._define3DName ?? "IGNORE"}
, ${refractionBlock?._cubeSamplerName ?? ""}
${isWebGPU ? `, ${refractionBlock?._cubeSamplerName}Sampler` : ""}
, ${refractionBlock?._cubeSamplerName ?? ""}
${isWebGPU ? `, ${refractionBlock?._cubeSamplerName}Sampler` : ""}
#else
, ${refractionBlock?._2DSamplerName ?? ""}
${isWebGPU ? `, ${refractionBlock?._2DSamplerName}Sampler` : ""}
, ${refractionBlock?._2DSamplerName ?? ""}
${isWebGPU ? `, ${refractionBlock?._2DSamplerName}Sampler` : ""}
#endif
#endif
#ifdef ANISOTROPIC
, anisotropicOut
#endif
#ifdef REALTIME_FILTERING
, ${refractionBlock?._vRefractionFilteringInfoName ?? ""}
#endif
#ifdef SS_USE_LOCAL_REFRACTIONMAP_CUBIC
, vRefractionPosition
, vRefractionSize
#endif
#ifdef SS_DISPERSION
, dispersion
#endif
#endif
#ifdef SS_TRANSLUCENCY
, ${translucencyDiffusionDistance}
, vTintColor
#ifdef SS_TRANSLUCENCYCOLOR_TEXTURE
, vec4${state.fSuffix}(0.)
#endif
#endif
);
#ifdef SS_REFRACTION
surfaceAlbedo = subSurfaceOut.surfaceAlbedo;
#ifdef SS_LINKREFRACTIONTOTRANSPARENCY
alpha = subSurfaceOut.alpha;
#endif
#endif
#else
subSurfaceOut.specularEnvironmentReflectance = colorSpecularEnvironmentReflectance;
#endif\n`;
return code;
}
_buildBlock(state) {
if (state.target === NodeMaterialBlockTargets.Fragment) {
state.sharedData.blocksWithDefines.push(this);
}
return this;
}
}
__decorate([
editableInPropertyPage("Apply albedo after sub-surface", 0 /* PropertyTypeForEdition.Boolean */, "ADVANCED")
], SubSurfaceBlock.prototype, "applyAlbedoAfterSubSurface", void 0);
RegisterClass("BABYLON.SubSurfaceBlock", SubSurfaceBlock);
//# sourceMappingURL=subSurfaceBlock.js.map