@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
504 lines (503 loc) • 17.5 kB
JavaScript
"use strict";
import { LineType } from "../utils/LineType";
import { ShaderConfig } from "../configs/ShaderConfig";
import { VariableConfig } from "../configs/VariableConfig";
import { CodeBuilder } from "../utils/CodeBuilder";
import { GlobalsGeometryHandler } from "../globals/Geometry";
import { TypedAssembler } from "../../../utils/shaders/BaseAssembler";
import { ShaderName } from "../../../utils/shaders/ShaderName";
import { OutputGlNode } from "../../Output";
import { GlConnectionPoint, GlConnectionPointType } from "../../../utils/io/connections/Gl";
import { AttributeGlNode } from "../../Attribute";
import { ParamGlNode } from "../../Param";
import { TypedNodeTraverser } from "../../../utils/shaders/NodeTraverser";
import { GlNodeFinder } from "../utils/NodeFinder";
import { VaryingWriteGlNode } from "../../VaryingWrite";
import { SubnetOutputGlNode } from "../../SubnetOutput";
import { GlobalsOutput } from "./materials/common/GlobalOutput";
const INSERT_DEFINE_AFTER_MAP = /* @__PURE__ */ new Map([
[ShaderName.VERTEX, "#include <common>"],
[ShaderName.FRAGMENT, "#include <common>"]
]);
const INSERT_BODY_AFTER_MAP = /* @__PURE__ */ new Map([
[ShaderName.VERTEX, "#include <color_vertex>"],
[ShaderName.FRAGMENT, "vec4 diffuseColor = vec4( diffuse, opacity );"]
]);
const LINES_TO_REMOVE_MAP = /* @__PURE__ */ new Map([
[ShaderName.VERTEX, ["#include <begin_vertex>", "#include <beginnormal_vertex>"]],
[ShaderName.FRAGMENT, []]
]);
const SPACED_LINES = 3;
export class BaseGlShaderAssembler extends TypedAssembler {
constructor(_gl_parent_node) {
super();
this._gl_parent_node = _gl_parent_node;
this._shaders_by_name = /* @__PURE__ */ new Map();
this._lines = /* @__PURE__ */ new Map();
this._root_nodes = [];
this._leaf_nodes = [];
this._uniformsTimeDependent = false;
this._uniformsResolutionDependent = false;
}
setGlParentNode(gl_parent_node) {
this._overriden_gl_parent_node = gl_parent_node;
}
currentGlParentNode() {
return this._overriden_gl_parent_node || this._gl_parent_node;
}
compile() {
}
// private get material() {
// return (this._material = this._material || this._createMaterial());
// }
// async get_material(/*master_assembler?: BaseGlShaderAssembler*/) {
// this._material = this._material || this._createMaterial();
// await this._update_material(/*master_assembler*/);
// return this._material;
// }
_template_shader_for_shader_name(shader_name) {
var _a, _b;
switch (shader_name) {
case ShaderName.VERTEX:
return (_a = this.templateShader()) == null ? void 0 : _a.vertexShader;
case ShaderName.FRAGMENT:
return (_b = this.templateShader()) == null ? void 0 : _b.fragmentShader;
}
}
globalsHandler() {
var _a;
return (_a = this.currentGlParentNode().assemblerController()) == null ? void 0 : _a.globalsHandler();
}
compileAllowed() {
var _a;
return ((_a = this.currentGlParentNode().assemblerController()) == null ? void 0 : _a.globalsHandler()) != null;
}
shaders_by_name() {
return this._shaders_by_name;
}
// protected createMaterial(): ShaderMaterial | undefined {
// return undefined;
// }
_buildLines() {
for (let shaderName of this.shaderNames()) {
const template = this._template_shader_for_shader_name(shaderName);
if (template) {
this._replaceTemplate(template, shaderName);
}
}
}
// protected _build_lines_for_shader_name(shader_name: ShaderName){
// const template = this._template_shader()
// this._replace_template(template[`${shader_name}Shader`], shader_name)
// }
set_root_nodes(root_nodes) {
this._root_nodes = root_nodes;
}
templateShader() {
return void 0;
}
// protected addUniforms(uniforms: IUniforms) {
// for (let param_config of this.param_configs()) {
// uniforms[param_config.uniformName()] = param_config.uniform();
// }
// if (this.uniformsTimeDependent()) {
// uniforms[UniformName.TIME] = uniforms[UniformName.TIME] || {
// // type: '1f',
// value: this.currentGlParentNode().scene().time(),
// };
// }
// if (this.uniformsResolutionDependent()) {
// uniforms[UniformName.RESOLUTION] = uniforms[UniformName.RESOLUTION] || {
// value: new Vector2(1000, 1000),
// };
// }
// }
//
//
// ROOT NODES AND SHADER NAMES
//
//
rootNodesByShaderName(shaderName, rootNodes) {
const list = [];
for (const node of rootNodes) {
switch (node.type()) {
case VaryingWriteGlNode.type():
case ParamGlNode.type():
case SubnetOutputGlNode.type():
case OutputGlNode.type(): {
list.push(node);
break;
}
case AttributeGlNode.type(): {
break;
}
}
}
return list;
}
// leafNodesByShaderName(shaderName: ShaderName): BaseGlNodeType[] {
// const list = [];
// for (let node of this._leaf_nodes) {
// switch (node.type()) {
// case GlobalsGlNode.type(): {
// list.push(node);
// break;
// }
// case AttributeGlNode.type(): {
// break;
// }
// }
// }
// return list;
// }
set_node_lines_globals(globals_node, shaders_collection_controller) {
}
set_node_lines_output(output_node, shaders_collection_controller) {
}
setNodeLinesAttribute(attribute_node, shaders_collection_controller) {
}
//
//
// CHILDREN NODES PARAMS
//
//
codeBuilder() {
return this._codeBuilder = this._codeBuilder || this._createCodeBuilder();
}
_resetCodeBuilder() {
this._codeBuilder = void 0;
}
_createCodeBuilder() {
const nodeTraverser = new TypedNodeTraverser(
this.currentGlParentNode(),
this.shaderNames(),
(rootNode, shaderName) => {
return this.inputNamesForShaderName(rootNode, shaderName);
}
);
return new CodeBuilder(
nodeTraverser,
(shaderName, rootNodes) => {
return this.rootNodesByShaderName(shaderName, rootNodes);
},
this
);
}
buildCodeFromNodes(rootNodes, codeBuilderOptions) {
const paramNodes = GlNodeFinder.findParamGeneratingNodes(this.currentGlParentNode());
this.codeBuilder().buildFromNodes(rootNodes, paramNodes, codeBuilderOptions);
}
allow_new_param_configs() {
this.codeBuilder().allow_new_param_configs();
}
disallow_new_param_configs() {
this.codeBuilder().disallow_new_param_configs();
}
builder_param_configs() {
return this.codeBuilder().param_configs();
}
builder_lines(shader_name, line_type) {
return this.codeBuilder().lines(shader_name, line_type);
}
all_builder_lines() {
return this.codeBuilder().all_lines();
}
param_configs() {
const code_builder = this._param_config_owner || this.codeBuilder();
return code_builder.param_configs();
}
set_param_configs_owner(param_config_owner) {
this._param_config_owner = param_config_owner;
if (this._param_config_owner) {
this.codeBuilder().disallow_new_param_configs();
} else {
this.codeBuilder().allow_new_param_configs();
}
}
//
//
// CHILDREN NODES PARAMS
//
//
static output_input_connection_points() {
return [
new GlConnectionPoint("position", GlConnectionPointType.VEC3),
new GlConnectionPoint("normal", GlConnectionPointType.VEC3),
new GlConnectionPoint("color", GlConnectionPointType.VEC3),
new GlConnectionPoint("alpha", GlConnectionPointType.FLOAT),
new GlConnectionPoint("uv", GlConnectionPointType.VEC2)
];
}
add_output_inputs(output_child) {
output_child.io.inputs.setNamedInputConnectionPoints(BaseGlShaderAssembler.output_input_connection_points());
}
static create_globals_node_output_connections() {
return [
new GlConnectionPoint("position", GlConnectionPointType.VEC3),
new GlConnectionPoint("normal", GlConnectionPointType.VEC3),
new GlConnectionPoint("color", GlConnectionPointType.VEC3),
new GlConnectionPoint("uv", GlConnectionPointType.VEC2),
new GlConnectionPoint(GlobalsOutput.MV_POSITION, GlConnectionPointType.VEC4),
// Maybe I should not add worldPosition, worldNormal, I just now
// as those could add computation overhead when always present in the shader.
// But hopefully in the soon future, they will only be added when the code builder
// adds lines based on connections, as opposed to the whole node
new GlConnectionPoint(GlobalsOutput.WORLD_POSITION, GlConnectionPointType.VEC4),
// vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
new GlConnectionPoint(GlobalsOutput.WORLD_NORMAL, GlConnectionPointType.VEC3),
// vec3 worldNormal = normalize( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal );
// new GlConnectionPoint('I', GlConnectionPointType.VEC3), // vec3 I = worldPosition.xyz - cameraPosition;
new GlConnectionPoint(GlobalsOutput.GL_POSITION, GlConnectionPointType.VEC4),
new GlConnectionPoint(GlobalsOutput.GL_FRAGCOORD, GlConnectionPointType.VEC4),
new GlConnectionPoint("cameraPosition", GlConnectionPointType.VEC3),
new GlConnectionPoint(GlobalsOutput.RESOLUTION, GlConnectionPointType.VEC2),
new GlConnectionPoint(GlobalsOutput.TIME, GlConnectionPointType.FLOAT),
new GlConnectionPoint(GlobalsOutput.MODEL_MATRIX, GlConnectionPointType.MAT4),
new GlConnectionPoint(GlobalsOutput.MODEL_VIEW_MATRIX, GlConnectionPointType.MAT4),
new GlConnectionPoint(GlobalsOutput.NORMAL_MATRIX, GlConnectionPointType.MAT3)
];
}
create_globals_node_output_connections() {
return BaseGlShaderAssembler.create_globals_node_output_connections();
}
add_globals_outputs(globals_node) {
globals_node.io.outputs.setNamedOutputConnectionPoints(this.create_globals_node_output_connections());
}
allow_attribute_exports() {
return false;
}
//
//
// CONFIGS
//
//
reset_configs() {
this._reset_shader_configs();
this._reset_variable_configs();
this._resetUniformsTimeDependency();
this._resetUniformsResolutionDependency();
}
shaderConfigs() {
return this._shader_configs = this._shader_configs || this.create_shader_configs();
}
set_shader_configs(shader_configs) {
this._shader_configs = shader_configs;
}
shaderNames() {
var _a;
return ((_a = this.shaderConfigs()) == null ? void 0 : _a.map((sc) => sc.name())) || [];
}
_reset_shader_configs() {
this._shader_configs = void 0;
}
create_shader_configs() {
return [
new ShaderConfig(ShaderName.VERTEX, ["position", "normal", "uv", VaryingWriteGlNode.INPUT_NAME], []),
new ShaderConfig(ShaderName.FRAGMENT, ["color", "alpha"], [ShaderName.VERTEX])
];
}
shader_config(name) {
var _a;
return (_a = this.shaderConfigs()) == null ? void 0 : _a.filter((sc) => {
return sc.name() == name;
})[0];
}
variable_configs() {
return this._variable_configs = this._variable_configs || this.create_variable_configs();
}
set_variable_configs(variable_configs) {
this._variable_configs = variable_configs;
}
variable_config(name) {
return this.variable_configs().filter((vc) => {
return vc.name() == name;
})[0];
}
static create_variable_configs() {
return [
new VariableConfig("position", {
default_from_attribute: true,
// default: this.globalsHandler().variable_config_default('position'),
// required_definitions: this.globalsHandler().variable_config_required_definitions('position'),
prefix: "vec3 transformed = "
}),
new VariableConfig("normal", {
default_from_attribute: true,
prefix: "vec3 objectNormal = ",
postLines: ["#ifdef USE_TANGENT", " vec3 objectTangent = vec3( tangent.xyz );", "#endif"]
}),
new VariableConfig("color", {
prefix: "diffuseColor.xyz = "
}),
new VariableConfig("alpha", {
prefix: "diffuseColor.a = "
}),
new VariableConfig("uv", {
// default_from_attribute: true,
prefix: "vUv = ",
if: GlobalsGeometryHandler.IF_RULE.uv
})
];
}
create_variable_configs() {
return BaseGlShaderAssembler.create_variable_configs();
}
_reset_variable_configs() {
this._variable_configs = void 0;
this.variable_configs();
}
inputNamesForShaderName(root_node, shader_name) {
var _a;
return ((_a = this.shader_config(shader_name)) == null ? void 0 : _a.input_names()) || [];
}
// time dependency
_resetUniformsTimeDependency() {
this._uniformsTimeDependent = false;
}
setUniformsTimeDependent() {
this._uniformsTimeDependent = true;
}
uniformsTimeDependent() {
return this._uniformsTimeDependent;
}
// resolution dependency
_resetUniformsResolutionDependency() {
this._uniformsResolutionDependent = false;
}
setUniformsResolutionDependent() {
this._uniformsResolutionDependent = true;
}
uniformsResolutionDependent() {
return this._uniformsResolutionDependent;
}
_raymarchingLightsWorldCoordsDependent() {
return false;
}
//
//
// TEMPLATE HOOKS
//
//
insertDefineAfter(shaderName) {
return INSERT_DEFINE_AFTER_MAP.get(shaderName);
}
insertBodyAfter(shaderName) {
return INSERT_BODY_AFTER_MAP.get(shaderName);
}
linesToRemove(shaderName) {
return LINES_TO_REMOVE_MAP.get(shaderName);
}
//
//
// TEMPLATE CODE REPLACEMENT
//
//
_replaceTemplate(template, shaderName) {
const functionDeclaration = this.builder_lines(shaderName, LineType.FUNCTION_DECLARATION);
const define = this.builder_lines(shaderName, LineType.DEFINE);
const body = this.builder_lines(shaderName, LineType.BODY);
let templateLines = template.split("\n");
const newLines = [
// `#define FPS ${ThreeToGl.float(scene.time_controller.fps)}`,
// `#define TIME_INCREMENT (1.0/${ThreeToGl.float(scene.time_controller.fps)})`,
// `#define FRAME_RANGE_START ${ThreeToGl.float(scene.time_controller.frame_range[0])}`,
// `#define FRAME_RANGE_END ${ThreeToGl.float(scene.time_controller.frame_range[1])}`,
];
const lineBeforeDefine = this.insertDefineAfter(shaderName);
const lineBeforeBody = this.insertBodyAfter(shaderName);
const linesToRemove = this.linesToRemove(shaderName);
let lineBeforeDefineFound = false;
let lineBeforeBodyFoundOnPreviousLine = false;
let lineBeforeBodyFound = false;
for (const templateLine of templateLines) {
if (lineBeforeDefineFound == true) {
if (functionDeclaration) {
this._insertLines(newLines, functionDeclaration);
}
if (define) {
this._insertLines(newLines, define);
}
lineBeforeDefineFound = false;
}
if (lineBeforeBodyFoundOnPreviousLine == true) {
if (body) {
this._insertLines(newLines, body);
}
lineBeforeBodyFoundOnPreviousLine = false;
}
let line_remove_required = false;
if (linesToRemove) {
for (const line_to_remove of linesToRemove) {
if (templateLine.indexOf(line_to_remove) >= 0) {
line_remove_required = true;
}
}
}
if (!line_remove_required) {
newLines.push(templateLine);
} else {
newLines.push("// removed:");
newLines.push(`//${templateLine}`);
}
if (lineBeforeDefine && templateLine.indexOf(lineBeforeDefine) >= 0) {
lineBeforeDefineFound = true;
}
if (lineBeforeBody && templateLine.indexOf(lineBeforeBody) >= 0) {
lineBeforeBodyFoundOnPreviousLine = true;
lineBeforeBodyFound = true;
}
}
if (lineBeforeBody) {
if (!lineBeforeBodyFound) {
console.warn(`line '${lineBeforeBody}' was not found in shader '${shaderName}'`, template, this);
} else {
}
}
this._lines.set(shaderName, newLines);
}
// protected _insert_default_body_declarations(new_lines, shader_name){
// new_lines.push('float POLY_roughness = 1.0;')
// }
_insertLines(newLines, linesToAdd) {
if (linesToAdd.length == 0) {
return;
}
for (let i = 0; i < SPACED_LINES; i++) {
newLines.push("");
}
for (let lineToAdd of linesToAdd) {
newLines.push(lineToAdd);
}
for (let i = 0; i < SPACED_LINES; i++) {
newLines.push("");
}
}
_addFilterFragmentShaderCallback(callbackName, callback) {
}
_removeFilterFragmentShaderCallback(callbackName) {
}
getCustomMaterials() {
return /* @__PURE__ */ new Map();
}
//
//
// GLTF EXPORT
//
//
// static convert_material_to_gltf_supported(material: ShaderMaterial): Material{
// const gltf_constructor = this.isPhysical() ? MeshPhysicalMaterial : MeshStandardMaterial
// const options = {}
// this._match_uniform('color', options, material, 'diffuse')
// this._match_uniform('map', options, material)
// this._match_uniform('envMap', options, material)
// this._match_uniform('envMapIntensity', options, material)
// this._match_uniform('metalness', options, material)
// this._match_uniform('roughness', options, material)
// const gltf_material = new gltf_constructor(options)
// return gltf_material
// }
// static _match_uniform(name: string, options: object, material: ShaderMaterial, uniform_name?: string) {
// uniform_name = uniform_name || name;
// options[name] = material.uniforms[uniform_name].value;
// }
}