UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

313 lines (312 loc) 12.2 kB
"use strict"; import { NodeContext } from "./../../poly/NodeContext"; import { GlType } from "./../../poly/registers/nodes/types/Gl"; import { ParamConfig } from "./../utils/params/ParamsConfig"; import { FunctionGLDefinition } from "./utils/GLDefinition"; import { TypedGlNode } from "./_Base"; import { ThreeToGl } from "../../../core/ThreeToGl"; import { NodeParamsConfig } from "../utils/params/ParamsConfig"; import { GlConnectionPoint, GlConnectionPointType } from "../utils/io/connections/Gl"; import { isBooleanTrue } from "../../../core/Type"; import SDF_ENV_MAP_SAMPLE from "./gl/raymarching/sdfEnvMapSample.glsl"; import SDF_ENV_MAP from "./gl/raymarching/sdfEnvMap.glsl"; import SDF_REFLECTION from "./gl/raymarching/sdfReflection.glsl"; import Quaternion from "./gl/quaternion.glsl"; class BodyLine { constructor(_content) { this._content = _content; } content() { return this._content; } lines() { return this._content.split("\n"); } replaceVars(vars) { const varNames = Object.keys(vars); for (let varName of varNames) { this._replaceVar(varName, vars[varName]); } } addTabs(tabsCount) { const lines = this._content.split("\n"); const newLines = []; for (let line of lines) { const prefix = " ".repeat(tabsCount); newLines.push(`${prefix}${line}`); } this._content = newLines.join("\n"); } _replaceVar(varName, replacement) { const regex = new RegExp(`__${varName}__`, "g"); this._content = this._content.replace(regex, replacement); } } const OUTPUT_NAME = GlType.SDF_MATERIAL; class SDFMaterialGlParamsConfig extends NodeParamsConfig { constructor() { super(...arguments); // globals this.globals = ParamConfig.FOLDER(); this.color = ParamConfig.COLOR([1, 1, 1]); this.useEnvMap = ParamConfig.BOOLEAN(0); this.useReflection = ParamConfig.BOOLEAN(0); this.useRefraction = ParamConfig.BOOLEAN(0); // lighting this.lighting = ParamConfig.FOLDER(); this.useLights = ParamConfig.BOOLEAN(1); this.diffuse = ParamConfig.COLOR([1, 1, 1], { visibleIf: { useLights: 1 } }); this.emissive = ParamConfig.COLOR([0, 0, 0]); // envMap this.envMap = ParamConfig.FOLDER(); this.envMapTint = ParamConfig.COLOR([1, 1, 1], { visibleIf: { useEnvMap: 1 } }); this.envMapIntensity = ParamConfig.FLOAT(1, { visibleIf: { useEnvMap: 1 } }); this.envMapRoughness = ParamConfig.FLOAT(0, { visibleIf: { useEnvMap: 1 } }); this.envMapFresnel = ParamConfig.FLOAT(0, { visibleIf: { useEnvMap: 1 } }); this.envMapFresnelPower = ParamConfig.FLOAT(5, { range: [0, 10], rangeLocked: [true, false], visibleIf: { useEnvMap: 1 } }); // reflection this.reflection = ParamConfig.FOLDER(); this.reflectionTint = ParamConfig.COLOR([1, 1, 1], { visibleIf: { useReflection: 1 } }); this.reflectionDepth = ParamConfig.INTEGER(3, { visibleIf: { useReflection: 1 }, range: [0, 10], rangeLocked: [true, false] }); this.reflectivity = ParamConfig.FLOAT(0.5, { visibleIf: { useReflection: 1 }, range: [0, 1], rangeLocked: [true, false] }); this.reflectionBiasMult = ParamConfig.FLOAT(2, { visibleIf: { useReflection: 1 }, range: [0, 10], rangeLocked: [true, false] }); // refraction this.refraction = ParamConfig.FOLDER(); this.refractionTint = ParamConfig.COLOR([1, 1, 1], { visibleIf: { useRefraction: 1 } }); this.ior = ParamConfig.FLOAT(1.45, { visibleIf: { useRefraction: 1 }, range: [0, 2], rangeLocked: [true, false] }); this.splitRGB = ParamConfig.BOOLEAN(0, { visibleIf: { useRefraction: 1 } }); this.iorOffset = ParamConfig.VECTOR3([-0.01, 0, 0.01], { visibleIf: { useRefraction: 1, splitRGB: 1 } }); this.transmission = ParamConfig.FLOAT(0.5, { visibleIf: { useRefraction: 1 }, range: [0, 1], rangeLocked: [true, false] }); this.absorption = ParamConfig.FLOAT(0.5, { visibleIf: { useRefraction: 1 }, range: [0, 5], rangeLocked: [false, false] }); this.refractionDepth = ParamConfig.INTEGER(3, { visibleIf: { useRefraction: 1 }, range: [0, 10], rangeLocked: [true, false], separatorBefore: true }); this.refractionMaxDist = ParamConfig.FLOAT(100, { visibleIf: { useRefraction: 1 }, range: [0, 100], rangeLocked: [true, false], step: 1e-4 }); this.refractionBiasMult = ParamConfig.FLOAT(2, { visibleIf: { useRefraction: 1 }, range: [0, 10], rangeLocked: [true, false] }); this.sampleEnvMapOnLastRefractionRay = ParamConfig.BOOLEAN(1, { visibleIf: { useRefraction: 1 } }); this.refractionStartOutsideMedium = ParamConfig.BOOLEAN(1, { visibleIf: { useRefraction: 1 } }); } } const ParamsConfig = new SDFMaterialGlParamsConfig(); export class SDFMaterialGlNode extends TypedGlNode { constructor() { super(...arguments); this.paramsConfig = ParamsConfig; } static type() { return GlType.SDF_MATERIAL; } initializeNode() { super.initializeNode(); this.io.connection_points.spare_params.setInputlessParamNames([ "useLights", "useEnvMap", "useReflection", "reflectionDepth", "useRefraction", "refractionDepth", "splitRGB", "sampleEnvMapOnLastRefractionRay", "refractionStartOutsideMedium" ]); this.io.outputs.setNamedOutputConnectionPoints([ new GlConnectionPoint(OUTPUT_NAME, GlConnectionPointType.SDF_MATERIAL) ]); } materialIdName() { return this.path().replace(/\//g, "_").toUpperCase(); } _materialId() { const parentMatNode = this.parentController.firstAncestorWithContext(NodeContext.MAT); if (!parentMatNode) { return 0; } if (!parentMatNode.childrenController) { return 0; } let i = 0; let matId = 0; parentMatNode.childrenController.traverseChildren((childNode) => { if (childNode.context() == NodeContext.GL && childNode.type() == SDFMaterialGlNode.type()) { i++; if (childNode.graphNodeId() == this.graphNodeId()) { matId = i; } } }); return matId; } setLines(shadersCollectionController) { const matId = this._materialId(); const matIdName = this.materialIdName(); const definitions = []; const useEnvMap = isBooleanTrue(this.pv.useEnvMap); const useReflection = isBooleanTrue(this.pv.useReflection); const useRefraction = isBooleanTrue(this.pv.useRefraction); const envMapRoughness = ThreeToGl.float(this.variableForInputParam(this.p.envMapRoughness)); const defineDeclaration = `const int ${matIdName} = ${matId};`; definitions.push(new FunctionGLDefinition(this, defineDeclaration)); definitions.push(new FunctionGLDefinition(this, Quaternion)); definitions.push(new FunctionGLDefinition(this, SDF_ENV_MAP_SAMPLE)); const color = ThreeToGl.vector3(this.variableForInputParam(this.p.color)); const diffuse = ThreeToGl.vector3(this.variableForInputParam(this.p.diffuse)); const emissive = ThreeToGl.vector3(this.variableForInputParam(this.p.emissive)); const bodyLines = [`if(mat == ${matIdName}){`]; bodyLines.push(` col = vec3(0., 0., 0.);`); const useLights = isBooleanTrue(this.pv.useLights); if (useLights) { bodyLines.push(` vec3 diffuse = ${color} * ${diffuse} * GetLight(p, n, sdfContext);`); bodyLines.push(` col += diffuse;`); } bodyLines.push(` col += ${emissive};`); if (useEnvMap) { const envMapTint = ThreeToGl.vector3(this.variableForInputParam(this.p.envMapTint)); const envMapIntensity = ThreeToGl.float(this.variableForInputParam(this.p.envMapIntensity)); const envMapFresnel = ThreeToGl.float(this.variableForInputParam(this.p.envMapFresnel)); const envMapFresnelPower = ThreeToGl.float(this.variableForInputParam(this.p.envMapFresnelPower)); const lineEnvMap = new BodyLine(SDF_ENV_MAP); lineEnvMap.replaceVars({ envMapTint, envMapIntensity, envMapRoughness, envMapFresnel, envMapFresnelPower }); lineEnvMap.addTabs(1); bodyLines.push(...lineEnvMap.lines()); } if (useReflection) { const reflectionDepth = `${this.pv.reflectionDepth}`; const reflectionTint = ThreeToGl.vector3(this.variableForInputParam(this.p.reflectionTint)); const reflectivity = ThreeToGl.float(this.variableForInputParam(this.p.reflectivity)); const reflectionBiasMult = ThreeToGl.float(this.variableForInputParam(this.p.reflectionBiasMult)); const lineReflection = new BodyLine(SDF_REFLECTION); lineReflection.replaceVars({ reflectionTint, reflectionDepth, reflectivity, reflectionBiasMult, envMapRoughness }); lineReflection.addTabs(1); bodyLines.push(...lineReflection.lines()); definitions.push(new FunctionGLDefinition(this, "#define RAYMARCHED_REFLECTIONS 1")); } if (useRefraction) { const refractionTint = ThreeToGl.vector3(this.variableForInputParam(this.p.refractionTint)); const refractionDepth = this.pv.refractionDepth; const ior = ThreeToGl.float(this.variableForInputParam(this.p.ior)); const transmission = ThreeToGl.float(this.variableForInputParam(this.p.transmission)); const absorption = ThreeToGl.float(this.variableForInputParam(this.p.absorption)); const refractionBiasMult = ThreeToGl.float(this.variableForInputParam(this.p.refractionBiasMult)); const refractionMaxDist = ThreeToGl.float(this.variableForInputParam(this.p.refractionMaxDist)); const splitRGB = isBooleanTrue(this.pv.splitRGB); const iorOffset = ThreeToGl.vector3(this.variableForInputParam(this.p.iorOffset)); bodyLines.push(` // --- REFRACTION - START vec3 refractedColor = vec3(0.); float ior = ${ior}; float biasMult = ${refractionBiasMult}; vec3 baseValue = ${color}; vec3 tint = ${refractionTint}; float absorption = ${absorption}; `); if (splitRGB) { bodyLines.push(` vec3 offset = ${iorOffset}; vec4 refractedDataR = GetRefractedData(p, n, rayDir, ior+offset.x, biasMult, ${envMapRoughness}, ${refractionMaxDist}, ${refractionDepth}, sdfContext); vec4 refractedDataG = GetRefractedData(p, n, rayDir, ior+offset.y, biasMult, ${envMapRoughness}, ${refractionMaxDist}, ${refractionDepth}, sdfContext); vec4 refractedDataB = GetRefractedData(p, n, rayDir, ior+offset.z, biasMult, ${envMapRoughness}, ${refractionMaxDist}, ${refractionDepth}, sdfContext); refractedColor.r = applyRefractionAbsorption(refractedDataR.r, baseValue.r, tint.r, refractedDataR.w, absorption); refractedColor.g = applyRefractionAbsorption(refractedDataG.g, baseValue.g, tint.g, refractedDataG.w, absorption); refractedColor.b = applyRefractionAbsorption(refractedDataB.b, baseValue.b, tint.b, refractedDataB.w, absorption); `); } else { bodyLines.push(` vec4 refractedData = GetRefractedData(p, n, rayDir, ior, biasMult, ${envMapRoughness}, ${refractionMaxDist}, ${refractionDepth}, sdfContext); refractedColor = applyRefractionAbsorption(refractedData.rgb, baseValue, tint, refractedData.w, absorption); `); } bodyLines.push(` col += refractedColor * ${transmission}; // --- REFRACTION - END `); definitions.push(new FunctionGLDefinition(this, "#define RAYMARCHED_REFRACTIONS 1")); if (isBooleanTrue(this.pv.sampleEnvMapOnLastRefractionRay)) { definitions.push( new FunctionGLDefinition(this, "#define RAYMARCHED_REFRACTIONS_SAMPLE_ENV_MAP_ON_LAST 1") ); } if (isBooleanTrue(this.pv.refractionStartOutsideMedium)) { definitions.push( new FunctionGLDefinition(this, "#define RAYMARCHED_REFRACTIONS_START_OUTSIDE_MEDIUM 1") ); } } bodyLines.push(`}`); shadersCollectionController.addBodyLines(this, bodyLines); shadersCollectionController.addDefinitions(this, definitions); } }