@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
394 lines (393 loc) • 13.8 kB
JavaScript
"use strict";
import { TypedRopNode } from "./_Base";
import { RopType } from "../../poly/registers/nodes/types/Rop";
import {
SRGBColorSpace,
LinearSRGBColorSpace,
DisplayP3ColorSpace,
NoToneMapping,
LinearToneMapping,
ReinhardToneMapping,
CineonToneMapping,
ACESFilmicToneMapping,
BasicShadowMap,
PCFShadowMap,
PCFSoftShadowMap,
VSMShadowMap
} from "three";
import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig";
import { isArray } from "../../../core/Type";
import { Poly } from "../../Poly";
import { isBooleanTrue } from "../../../core/BooleanValue";
import { defaultPixelRatio } from "../../../core/render/defaultPixelRatio";
import {
PowerPreference,
POWER_PREFERENCES,
RENDERER_PRECISIONS,
RendererPrecision,
WEBGL_RENDERER_DEFAULT_PARAMS
} from "../../../core/render/Common";
import { COLOR_SPACE_NAME_BY_COLOR_SPACE } from "../../../core/cop/ColorSpace";
const COLOR_SPACES = [SRGBColorSpace, LinearSRGBColorSpace, DisplayP3ColorSpace];
export const DEFAULT_OUTPUT_COLOR_SPACE = SRGBColorSpace;
var ToneMappingName = /* @__PURE__ */ ((ToneMappingName2) => {
ToneMappingName2["No"] = "No";
ToneMappingName2["Linear"] = "Linear";
ToneMappingName2["Reinhard"] = "Reinhard";
ToneMappingName2["Cineon"] = "Cineon";
ToneMappingName2["ACESFilmic"] = "ACESFilmic";
return ToneMappingName2;
})(ToneMappingName || {});
var ToneMappingValue = /* @__PURE__ */ ((ToneMappingValue2) => {
ToneMappingValue2[ToneMappingValue2["No"] = NoToneMapping] = "No";
ToneMappingValue2[ToneMappingValue2["Linear"] = LinearToneMapping] = "Linear";
ToneMappingValue2[ToneMappingValue2["Reinhard"] = ReinhardToneMapping] = "Reinhard";
ToneMappingValue2[ToneMappingValue2["Cineon"] = CineonToneMapping] = "Cineon";
ToneMappingValue2[ToneMappingValue2["ACESFilmic"] = ACESFilmicToneMapping] = "ACESFilmic";
return ToneMappingValue2;
})(ToneMappingValue || {});
const TONE_MAPPING_NAMES = [
"No" /* No */,
"Linear" /* Linear */,
"Reinhard" /* Reinhard */,
"Cineon" /* Cineon */,
"ACESFilmic" /* ACESFilmic */
];
const TONE_MAPPING_VALUES = [
ToneMappingValue.No,
ToneMappingValue.Linear,
ToneMappingValue.Reinhard,
ToneMappingValue.Cineon,
ToneMappingValue.ACESFilmic
];
export const DEFAULT_TONE_MAPPING = ToneMappingValue.ACESFilmic;
const TONE_MAPPING_MENU_ENTRIES = TONE_MAPPING_NAMES.map((name, i) => {
return {
name,
value: TONE_MAPPING_VALUES[i]
};
});
var ShadowMapTypeName = /* @__PURE__ */ ((ShadowMapTypeName2) => {
ShadowMapTypeName2["Basic"] = "Basic";
ShadowMapTypeName2["PCF"] = "PCF";
ShadowMapTypeName2["PCFSoft"] = "PCFSoft";
ShadowMapTypeName2["VSM"] = "VSM";
return ShadowMapTypeName2;
})(ShadowMapTypeName || {});
var ShadowMapTypeValue = /* @__PURE__ */ ((ShadowMapTypeValue2) => {
ShadowMapTypeValue2[ShadowMapTypeValue2["Basic"] = BasicShadowMap] = "Basic";
ShadowMapTypeValue2[ShadowMapTypeValue2["PCF"] = PCFShadowMap] = "PCF";
ShadowMapTypeValue2[ShadowMapTypeValue2["PCFSoft"] = PCFSoftShadowMap] = "PCFSoft";
ShadowMapTypeValue2[ShadowMapTypeValue2["VSM"] = VSMShadowMap] = "VSM";
return ShadowMapTypeValue2;
})(ShadowMapTypeValue || {});
const SHADOW_MAP_TYPE_NAMES = [
"Basic" /* Basic */,
"PCF" /* PCF */,
"PCFSoft" /* PCFSoft */,
"VSM" /* VSM */
];
const SHADOW_MAP_TYPE_VALUES = [
ShadowMapTypeValue.Basic,
ShadowMapTypeValue.PCF,
ShadowMapTypeValue.PCFSoft,
ShadowMapTypeValue.VSM
];
export const SHADOW_MAP_TYPES = [BasicShadowMap, PCFShadowMap, PCFSoftShadowMap, VSMShadowMap];
export const DEFAULT_SHADOW_MAP_TYPE = ShadowMapTypeValue.PCFSoft;
class WebGPURendererRopParamsConfig extends NodeParamsConfig {
constructor() {
super(...arguments);
//
//
//
//
//
this.common = ParamConfig.FOLDER();
/** @param tone mapping */
this.toneMapping = ParamConfig.INTEGER(DEFAULT_TONE_MAPPING, {
menu: {
entries: TONE_MAPPING_MENU_ENTRIES
},
cook: false,
callback: (node) => {
WebGPURendererRopNode.PARAM_CALLBACK_updateToneMapping(node);
}
});
/** @param tone mapping exposure */
this.toneMappingExposure = ParamConfig.FLOAT(1, {
range: [0, 2],
cook: false,
callback: (node) => {
WebGPURendererRopNode.PARAM_CALLBACK_updateToneMappingExposure(node);
}
});
/** @param output color space */
this.outputColorSpace = ParamConfig.STRING(DEFAULT_OUTPUT_COLOR_SPACE, {
menuString: {
entries: COLOR_SPACES.map((colorSpace) => ({
name: COLOR_SPACE_NAME_BY_COLOR_SPACE[colorSpace],
value: colorSpace
}))
},
cook: false,
callback: (node) => {
WebGPURendererRopNode.PARAM_CALLBACK_updateOutputColorSpace(node);
}
});
/** @param sort objects, which can be necessary when rendering transparent objects */
this.sortObjects = ParamConfig.BOOLEAN(1, {
cook: false,
callback: (node) => {
WebGPURendererRopNode.PARAM_CALLBACK_updateSortObjects(node);
}
});
/** @param toggle to override the default pixel ratio, which is 1 for mobile devices, and Math.max(2, globalThis.devicePixelRatio) for other devices */
this.tpixelRatio = ParamConfig.BOOLEAN(0, {
cook: false,
callback: (node) => {
WebGPURendererRopNode.PARAM_CALLBACK_updatePixelRatio(node);
}
});
/** @param higher pixelRatio improves render sharpness but reduces performance */
this.pixelRatio = ParamConfig.FLOAT(2, {
visibleIf: { tpixelRatio: true },
range: [0.1, 4],
rangeLocked: [true, false],
cook: false,
callback: (node) => {
WebGPURendererRopNode.PARAM_CALLBACK_updatePixelRatio(node);
}
});
//
//
//
//
//
this.shadow = ParamConfig.FOLDER();
/** @param toggle on to have shadow maps */
this.tshadowMap = ParamConfig.BOOLEAN(1, {
cook: false,
callback: (node) => {
WebGPURendererRopNode.PARAM_CALLBACK_updateShadow(node);
}
});
/** @param toggle on to recompute the shadow maps on every frame. If all objects are static, you may want to turn this off */
this.shadowMapAutoUpdate = ParamConfig.BOOLEAN(1, {
visibleIf: { tshadowMap: 1 },
cook: false,
callback: (node) => {
WebGPURendererRopNode.PARAM_CALLBACK_updateShadow(node);
}
});
/** @param toggle on to trigger shadows update */
this.shadowMapNeedsUpdate = ParamConfig.BOOLEAN(0, {
visibleIf: { tshadowMap: 1 },
cook: false,
callback: (node) => {
WebGPURendererRopNode.PARAM_CALLBACK_updateShadow(node);
}
});
/** @param shadows type */
this.shadowMapType = ParamConfig.INTEGER(DEFAULT_SHADOW_MAP_TYPE, {
visibleIf: { tshadowMap: 1 },
menu: {
entries: SHADOW_MAP_TYPE_NAMES.map((name, i) => {
return {
name,
value: SHADOW_MAP_TYPE_VALUES[i]
};
})
},
cook: false,
callback: (node) => {
WebGPURendererRopNode.PARAM_CALLBACK_updateShadow(node);
}
});
//
//
//
//
//
this.advanced = ParamConfig.FOLDER();
/** @param toggle on to have alpha on (change requires page reload) */
this.alpha = ParamConfig.BOOLEAN(1);
/** @param toggle on to have antialias on (change requires page reload) */
this.antialias = ParamConfig.BOOLEAN(1);
/** @param premultipliedAlpha */
this.premultipliedAlpha = ParamConfig.BOOLEAN(1);
/** @param stencil */
this.stencil = ParamConfig.BOOLEAN(1);
/** @param depth */
this.depth = ParamConfig.BOOLEAN(1);
/** @param localClippingEnabled */
this.localClippingEnabled = ParamConfig.BOOLEAN(0);
/** @param logarithmicDepthBuffer */
this.logarithmicDepthBuffer = ParamConfig.BOOLEAN(0);
/** @param preserveDrawingBuffer */
this.preserveDrawingBuffer = ParamConfig.BOOLEAN(0);
/** @param toggle on to set the precision */
this.tprecision = ParamConfig.BOOLEAN(0);
/** @param set the precision */
this.precision = ParamConfig.INTEGER(RENDERER_PRECISIONS.indexOf(RendererPrecision.HIGH), {
visibleIf: { tprecision: 1 },
menu: {
entries: RENDERER_PRECISIONS.map((name, value) => {
return { value, name };
})
}
});
/** @param toggle on to set the power preferenc */
this.tpowerPreference = ParamConfig.BOOLEAN(0);
/** @param set the precision */
this.powerPreference = ParamConfig.INTEGER(POWER_PREFERENCES.indexOf(PowerPreference.HIGH), {
visibleIf: { tpowerPreference: 1 },
menu: {
entries: POWER_PREFERENCES.map((name, value) => {
return { value, name };
})
}
});
}
// preserve_drawing_buffer = ParamConfig.BOOLEAN(0);
}
const ParamsConfig = new WebGPURendererRopParamsConfig();
export class WebGPURendererRopNode extends TypedRopNode {
constructor() {
super(...arguments);
this.paramsConfig = ParamsConfig;
this._rendererByCanvas = /* @__PURE__ */ new Map();
}
static type() {
return RopType.WEBGPU;
}
// private _renderersbyCamera: Map<Camera, WebGLRenderer> = new Map();
createRenderer(canvas, gl) {
const params = {};
const keys = Object.keys(WEBGL_RENDERER_DEFAULT_PARAMS);
let k;
for (k of keys) {
params[k] = WEBGL_RENDERER_DEFAULT_PARAMS[k];
}
if (isBooleanTrue(this.pv.tprecision)) {
const precision = RENDERER_PRECISIONS[this.pv.precision];
params.precision = precision;
}
if (isBooleanTrue(this.pv.tpowerPreference)) {
const powerPreference = POWER_PREFERENCES[this.pv.powerPreference];
params.powerPreference = powerPreference;
}
params.antialias = isBooleanTrue(this.pv.antialias);
params.alpha = isBooleanTrue(this.pv.alpha);
params.premultipliedAlpha = isBooleanTrue(this.pv.premultipliedAlpha);
params.depth = isBooleanTrue(this.pv.depth);
params.stencil = isBooleanTrue(this.pv.stencil);
params.logarithmicDepthBuffer = isBooleanTrue(this.pv.logarithmicDepthBuffer);
params.canvas = canvas;
params.context = gl;
params.preserveDrawingBuffer = this.pv.preserveDrawingBuffer;
const renderer = Poly.renderersController.createWebGLRenderer(params);
renderer.localClippingEnabled = isBooleanTrue(this.pv.localClippingEnabled);
this._rendererByCanvas.set(canvas, renderer);
if (Poly.renderersController.printDebug()) {
Poly.renderersController.printDebugMessage(`create renderer from node '${this.path()}'`);
Poly.renderersController.printDebugMessage({
params
});
}
this._updateRenderer(renderer);
return renderer;
}
cook() {
this._traverseSceneAndUpdateMaterials();
this.cookController.endCook();
}
_updateRenderer(renderer) {
this._updateRendererOutputColorSpace(renderer);
this._updateRendererToneMapping(renderer);
this._updateRendererToneMappingExposure(renderer);
this._updateRendererShadow(renderer);
this._updateRendererSortObjects(renderer);
this._updateRendererPixelRatio(renderer);
}
_traverseSceneAndUpdateMaterials() {
this.scene().threejsScene().traverse((object) => {
const material = object.material;
if (material) {
if (isArray(material)) {
for (const mat of material) {
mat.needsUpdate = true;
}
} else {
material.needsUpdate = true;
}
}
});
}
//
//
static PARAM_CALLBACK_updateToneMapping(node) {
node._rendererByCanvas.forEach((renderer, canvas) => {
node._updateRendererToneMapping(renderer);
});
}
static PARAM_CALLBACK_updateToneMappingExposure(node) {
node._rendererByCanvas.forEach((renderer, canvas) => {
node._updateRendererToneMappingExposure(renderer);
});
}
static PARAM_CALLBACK_updateOutputColorSpace(node) {
node._rendererByCanvas.forEach((renderer, canvas) => {
node._updateRendererOutputColorSpace(renderer);
});
}
static PARAM_CALLBACK_updateShadow(node) {
node._rendererByCanvas.forEach((renderer, canvas) => {
node._updateRendererShadow(renderer);
});
}
static PARAM_CALLBACK_updateSortObjects(node) {
node._rendererByCanvas.forEach((renderer, canvas) => {
node._updateRendererSortObjects(renderer);
});
}
static PARAM_CALLBACK_updatePixelRatio(node) {
node._rendererByCanvas.forEach((renderer, canvas) => {
node._updateRendererPixelRatio(renderer);
});
globalThis.dispatchEvent(new Event("resize"));
}
//
//
_updateRendererToneMapping(renderer) {
renderer.toneMapping = this.pv.toneMapping;
}
_updateRendererToneMappingExposure(renderer) {
renderer.toneMappingExposure = this.pv.toneMappingExposure;
}
_updateRendererOutputColorSpace(renderer) {
renderer.outputColorSpace = this.pv.outputColorSpace;
}
_updateRendererShadow(renderer) {
renderer.shadowMap.enabled = this.pv.tshadowMap;
renderer.shadowMap.autoUpdate = this.pv.shadowMapAutoUpdate;
renderer.shadowMap.needsUpdate = this.pv.shadowMapNeedsUpdate;
renderer.shadowMap.type = this.pv.shadowMapType;
}
_updateRendererSortObjects(renderer) {
renderer.sortObjects = this.pv.sortObjects;
}
_updateRendererPixelRatio(renderer) {
const pixelRatio = this.pv.tpixelRatio ? this.pv.pixelRatio : defaultPixelRatio();
if (Poly.renderersController.printDebug()) {
Poly.renderersController.printDebugMessage(`set renderer pixelRatio from '${this.path()}'`);
Poly.renderersController.printDebugMessage({
pixelRatio
});
}
renderer.setPixelRatio(pixelRatio);
}
setToneMapping(toneMapping) {
this.p.toneMapping.set(toneMapping);
}
}