UNPKG

@polygonjs/polygonjs

Version:

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

186 lines (168 loc) 7.14 kB
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; } }