@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
186 lines (168 loc) • 7.14 kB
text/typescript
import {Camera, Vector2, WebGLRenderer} from 'three';
import {PolyScene} from '../../engine/scene/PolyScene';
import {Poly} from '../../engine/Poly';
import {
DEFAULT_OUTPUT_COLOR_SPACE,
DEFAULT_SHADOW_MAP_TYPE,
DEFAULT_TONE_MAPPING,
} from '../../engine/nodes/rop/WebGLRenderer';
import {defaultPixelRatio} from '../render/defaultPixelRatio';
import {CameraAttribute} from './CoreCamera';
import {isNumber} from '../Type';
import {RopType} from '../../engine/poly/registers/nodes/types/Rop';
import {NodeContext} from '../../engine/poly/NodeContext';
import {TypedNode} from '../../engine/nodes/_Base';
import {AbstractRenderer} from '../../engine/viewers/Common';
import type {PathTracingRendererRopNode} from '../../engine/nodes/rop/PathTracingRenderer';
import type {WebGLRendererRopNode} from '../../engine/nodes/rop/WebGLRenderer';
// @ts-ignore
import type {PathTracingRenderer} from '../../core/thirdParty/three-gpu-pathtracer';
import {PathTracingRendererContainer} from '../../engine/nodes/rop/utils/pathTracing/PathTracingRendererContainer';
import {coreObjectClassFactory} from '../geometry/CoreObjectFactory';
const UPDATE_STYLE = false;
const SIZE_MULT = 1;
interface RendererRopOptions {
camera: Camera;
scene: PolyScene;
}
interface RendererConfigOptions {
camera: Camera;
scene: PolyScene;
canvas: HTMLCanvasElement;
// size: Vector2;
// rendererROP?: WebGLRendererRopNode;
}
// type AvailableRopNode = WebGLRendererRopNode | PathTracingRendererRopNode;
// type AvailableRenderer = WebGLRenderer | PathTracingRenderer;
// export interface RendererConfig<A extends AvailableRenderer> {
// renderer: A;
// rendererNode?: AvailableRopNode;
// }
interface RendererConfigWebGL {
renderer: WebGLRenderer;
rendererNode?: WebGLRendererRopNode;
}
interface RendererConfigPathtracing {
renderer: PathTracingRendererContainer;
rendererNode?: PathTracingRendererRopNode;
}
export type AvailableRenderConfig = RendererConfigWebGL | RendererConfigPathtracing;
export class CoreCameraRendererController {
// private static _resolutionByCanvas: Map<HTMLCanvasElement, Vector2> = new Map();
private static _defaultRendererByContext: Map<WebGLRenderingContext, AbstractRenderer> = new Map();
private static _renderersByCanvas: Map<HTMLCanvasElement, AbstractRenderer> = new Map();
// private static _superSamplingSize = new Vector2();
// static canvasResolution(canvas: HTMLCanvasElement) {
// return this._resolutionByCanvasId.get(canvas.id);
// }
static renderer(canvas: HTMLCanvasElement) {
return this._renderersByCanvas.get(canvas);
}
static rendererNode(options: RendererRopOptions) {
const {scene, camera} = options;
const rendererROPId = coreObjectClassFactory(camera).attribValue(camera, CameraAttribute.RENDERER_NODE_ID);
if (rendererROPId && isNumber(rendererROPId)) {
const rendererROP = scene.graph.nodeFromId(rendererROPId);
return rendererROP;
}
}
static rendererConfig<A extends AvailableRenderConfig>(options: RendererConfigOptions): A | undefined {
const {canvas, scene} = options;
const gl = Poly.renderersController.getRenderingContext(canvas);
if (!gl) {
console.error('failed to create webgl context');
return;
}
let renderer: A['renderer'] | undefined;
let rendererNode: A['rendererNode'] | undefined;
// if (isBooleanTrue(this.node.pv.setRenderer)) {
// await this._updateRenderer();
const rendererROP = this.rendererNode(options);
if (rendererROP != null && rendererROP instanceof TypedNode && rendererROP.context() == NodeContext.ROP) {
const type = rendererROP.type();
switch (type) {
case RopType.WEBGL: {
renderer = (rendererROP as WebGLRendererRopNode).createRenderer(canvas, gl);
rendererNode = rendererROP as WebGLRendererRopNode;
break;
}
case RopType.PATH_TRACING: {
renderer = (rendererROP as PathTracingRendererRopNode).renderer(canvas, gl);
rendererNode = rendererROP as PathTracingRendererRopNode;
break;
}
}
}
// }
if (!renderer) {
renderer = this._defaultRendererByContext.get(gl) as A['renderer'] | undefined;
if (!renderer) {
renderer = CoreCameraRendererController.createDefaultRenderer(canvas, gl);
this._defaultRendererByContext.set(gl, renderer);
}
}
// https://github.com/mrdoob/js/issues/15493
// This below is an attempt to fix env map not being loaded in firefox, but that doesn't work.
// Since the threejs example (https://threejs.org/examples/?q=exr#webgl_materials_envmaps_exr) also only works in chrome, not in firefox, I assume this is a firefox+linux bug
// console.log(renderer.extensions)
// renderer.extensions.get( 'EXT_color_buffer_float' );
// attempt to have particle systems work in firefox on mobile
// (current solution is to have the node SOP/particlesSystemGPU force webgl2 to be used)
// renderer.extensions.get( 'WEBGL_color_buffer_float' );
// renderer.extensions.get( 'WEBGL_draw_buffers' );
scene.renderersRegister.registerRenderer(renderer);
this._renderersByCanvas.set(canvas, renderer);
// this._superSamplingSize.copy(size);
// this.setRendererSize(canvas, this._superSamplingSize);
// remove devicePixelRatio for now, as this seems to double the size
// of the canvas on high dpi screens
// or if this is used, make sure to have the canvas at 100% width and height
// renderer.setPixelRatio(window.devicePixelRatio);
// UPDATE: favor using devicePixelRatio
// to have nice subsampling feel, without needing antialias
if (!renderer) {
return;
}
const renderConfig: A = {
renderer,
rendererNode,
} as A;
return renderConfig;
}
static setRendererSize(canvas: HTMLCanvasElement, size: Vector2) {
const renderer = this.renderer(canvas);
if (renderer) {
renderer.setSize(SIZE_MULT * size.x, SIZE_MULT * size.y, UPDATE_STYLE);
}
}
static createDefaultRenderer(canvas: HTMLCanvasElement, gl: WebGLRenderingContext) {
// const params: WebGLRendererParameters = {
// ...WEBGL_RENDERER_DEFAULT_PARAMS,
// // powerPreference: PowerPreference.HIGH,
// // canvas: canvas,
// // no anti alias with a pixel ratio of 2 is more performant
// // but using a pixel ratio of 2 by default can also create hard to debug
// // inconsistencies when using post processing
// // antialias: true, //defaultPixelRatio() < 2,
// // alpha: true, // let's use threejs default alpha
// context: gl,
// };
const renderer = Poly.renderersController.defaultWebGLRendererForCanvas(canvas);
const pixelRatio = defaultPixelRatio();
renderer.setPixelRatio(pixelRatio);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = DEFAULT_SHADOW_MAP_TYPE;
// // TODO: find a way to have those accessible via params
renderer.toneMapping = DEFAULT_TONE_MAPPING;
renderer.toneMappingExposure = 1;
renderer.outputColorSpace = DEFAULT_OUTPUT_COLOR_SPACE;
if (Poly.renderersController.printDebug()) {
Poly.renderersController.printDebugMessage('create default renderer');
// Poly.renderersController.printDebugMessage({
// params: params,
// pixelRatio: pixelRatio,
// });
}
return renderer;
}
}