| Key features include: | Key features include: | ||||
| - Simple, intuitive API for creating 3D model viewers/configurators/editors on web pages, with many built-in presets for common workflows and use-cases. | - Simple, intuitive API for creating 3D model viewers/configurators/editors on web pages, with many built-in presets for common workflows and use-cases. | ||||
| - Companion [editor](TODO) to create, edit and configure 3D scenes in the browser. | |||||
| - Companion [editor](https://threepipe.org/examples/tweakpane-editor/) to create, edit and configure 3D scenes in the browser. | |||||
| - Modular architecture that allows you to easily extend the viewer, scene objects, materials, shaders, rendering, post-processing and serialization with custom functionality. | - Modular architecture that allows you to easily extend the viewer, scene objects, materials, shaders, rendering, post-processing and serialization with custom functionality. | ||||
| - Simple plugin system along with a rich library of built-in plugins that allows you to easily add new features to the viewer. | - Simple plugin system along with a rich library of built-in plugins that allows you to easily add new features to the viewer. | ||||
| - [uiconfig](https://github.com/repalash/uiconfig.js) compatibility to automatically generate configuration UIs in the browser. | - [uiconfig](https://github.com/repalash/uiconfig.js) compatibility to automatically generate configuration UIs in the browser. | ||||
| ## File Formats | ## File Formats | ||||
| ThreePipe Asset Manager supports the import of following file formats out of the box: | |||||
| ThreePipe Asset Manager supports the import of the following file formats out of the box: | |||||
| * Models: | * Models: | ||||
| * gltf, glb | * gltf, glb | ||||
| * obj, mtl | * obj, mtl | ||||
| * zip | * zip | ||||
| * txt | * txt | ||||
| Additional formats can be added by plugins: | |||||
| Plugins can add additional formats: | |||||
| * Models | * Models | ||||
| * 3dm - Using [Rhino3dmLoadPlugin](#Rhino3dmLoadPlugin) | * 3dm - Using [Rhino3dmLoadPlugin](#Rhino3dmLoadPlugin) | ||||
| ThreePipe has a simple plugin system that allows you to easily add new features to the viewer. Plugins can be added to the viewer using the `addPlugin` and `addPluginSync` methods. The plugin system is designed to be modular and extensible. Plugins can be added to the viewer at any time and can be removed using the `removePlugin` and `removePluginSync` methods. | ThreePipe has a simple plugin system that allows you to easily add new features to the viewer. Plugins can be added to the viewer using the `addPlugin` and `addPluginSync` methods. The plugin system is designed to be modular and extensible. Plugins can be added to the viewer at any time and can be removed using the `removePlugin` and `removePluginSync` methods. | ||||
| ### TonemapPlugin | |||||
| todo: image | |||||
| Example: https://threepipe.org/examples/#tonemap-plugin/ | |||||
| Source Code: [src/plugins/postprocessing/TonemapPlugin.ts](./src/plugins/postprocessing/TonemapPlugin.ts) | |||||
| API Reference: [TonemapPlugin](https://threepipe.org/docs/classes/TonemapPlugin.html) | |||||
| TonemapPlugin adds a post-processing material extension to the ScreenPass in render manager | |||||
| that applies tonemapping to the color. The tonemapping operator can be changed | |||||
| by setting the `toneMapping` property of the plugin. The default tonemapping operator is `ACESFilmicToneMapping`. | |||||
| Other Tonemapping properties can be like `exposure`, `contrast` and `saturation` | |||||
| TonemapPlugin is added by default in ThreeViewer unless `tonemap` is set to `false` in the options. | |||||
| ### DropzonePlugin | |||||
| todo: image | |||||
| Example: https://threepipe.org/examples/#dropzone-plugin/ | |||||
| Source Code: [src/plugins/interaction/DropzonePlugin.ts](./src/plugins/interaction/DropzonePlugin.ts) | |||||
| API Reference: [DropzonePlugin](https://threepipe.org/docs/classes/DropzonePlugin.html) | |||||
| DropzonePlugin adds support for drag and drop of local files to automatically import, process and load them into the viewer. | |||||
| DropzonePlugin can be added by default in ThreeViewer | |||||
| by setting the `dropzone` property to `true` or an object of `DropzonePluginOptions` in the options. | |||||
| ```typescript | |||||
| import {DropzonePlugin, ThreeViewer} from 'threepipe' | |||||
| const viewer = new ThreeViewer({ | |||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||||
| dropzone: true, // just set to true to enable drag drop functionatility in the viewer | |||||
| }) | |||||
| ``` | |||||
| To set custom options, | |||||
| pass an object of [DropzonePluginOptions](https://threepipe.org/docs/interfaces/DropzonePluginOptions.html) type to the `dropzone` property. | |||||
| ```typescript | |||||
| import {DropzonePlugin, ThreeViewer} from 'threepipe' | |||||
| const viewer = new ThreeViewer({ | |||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||||
| dropzone: { // this can also be set to true and configured by getting a reference to the DropzonePlugin | |||||
| allowedExtensions: ['gltf', 'glb', 'hdr', 'png', 'jpg', 'json', 'fbx', 'obj'], // only allow these file types. If undefined, all files are allowed. | |||||
| addOptions: { | |||||
| disposeSceneObjects: true, // auto dispose of old scene objects | |||||
| autoSetEnvironment: true, // when hdr is dropped | |||||
| autoSetBackground: true, // when any image is dropped | |||||
| autoCenter: true, // auto center the object | |||||
| autoScale: true, // auto scale according to radius | |||||
| autoScaleRadius: 2, | |||||
| license: 'Imported from dropzone', // Any license to set on imported objects | |||||
| importConfig: true, // import config from file | |||||
| }, | |||||
| // check more options in the DropzonePluginOptions interface | |||||
| }, | |||||
| }) | |||||
| ``` | |||||
| ### DepthBufferPlugin | ### DepthBufferPlugin | ||||
| todo: image | todo: image | ||||
| Source Code: [src/plugins/pipeline/DepthBufferPlugin.ts](./src/plugins/pipeline/DepthBufferPlugin.ts) | Source Code: [src/plugins/pipeline/DepthBufferPlugin.ts](./src/plugins/pipeline/DepthBufferPlugin.ts) | ||||
| API Reference: [DepthBufferPlugin](https://threepipe.org/docs/classes/DepthBufferPlugin.html) | |||||
| Depth Buffer Plugin adds a pre-render pass to the render manager and renders a depth buffer to a target. The render target can be accessed by other plugins throughout the rendering pipeline to create effects like depth of field, SSAO, SSR, etc. | Depth Buffer Plugin adds a pre-render pass to the render manager and renders a depth buffer to a target. The render target can be accessed by other plugins throughout the rendering pipeline to create effects like depth of field, SSAO, SSR, etc. | ||||
| ```typescript | ```typescript | ||||
| Source Code: [src/plugins/pipeline/NormalBufferPlugin.ts](./src/plugins/pipeline/NormalBufferPlugin.ts) | Source Code: [src/plugins/pipeline/NormalBufferPlugin.ts](./src/plugins/pipeline/NormalBufferPlugin.ts) | ||||
| API Reference: [NormalBufferPlugin](https://threepipe.org/docs/classes/NormalBufferPlugin.html) | |||||
| Normal Buffer Plugin adds a pre-render pass to the render manager and renders a normal buffer to a target. The render target can be accessed by other plugins throughout the rendering pipeline to create effects like SSAO, SSR, etc. | Normal Buffer Plugin adds a pre-render pass to the render manager and renders a normal buffer to a target. The render target can be accessed by other plugins throughout the rendering pipeline to create effects like SSAO, SSR, etc. | ||||
| Note: Use [`DepthNormalBufferPlugin`](#DepthNormalBufferPlugin) if using both `DepthBufferPlugin` and `NormalBufferPlugin` to render both depth and normal buffers in a single pass. | Note: Use [`DepthNormalBufferPlugin`](#DepthNormalBufferPlugin) if using both `DepthBufferPlugin` and `NormalBufferPlugin` to render both depth and normal buffers in a single pass. | ||||
| Source Code: [src/plugins/ui/RenderTargetPreviewPlugin.ts](./src/plugins/ui/RenderTargetPreviewPlugin.ts) | Source Code: [src/plugins/ui/RenderTargetPreviewPlugin.ts](./src/plugins/ui/RenderTargetPreviewPlugin.ts) | ||||
| API Reference: [RenderTargetPreviewPlugin](https://threepipe.org/docs/classes/RenderTargetPreviewPlugin.html) | |||||
| RenderTargetPreviewPlugin is a useful development and debugging plugin that renders any registered render-target to the screen in small collapsable panels. | RenderTargetPreviewPlugin is a useful development and debugging plugin that renders any registered render-target to the screen in small collapsable panels. | ||||
| ```typescript | ```typescript | ||||
| Source Code: [src/plugins/import/Rhino3dmLoadPlugin.ts](./src/plugins/import/Rhino3dmLoadPlugin.ts) | Source Code: [src/plugins/import/Rhino3dmLoadPlugin.ts](./src/plugins/import/Rhino3dmLoadPlugin.ts) | ||||
| API Reference: [Rhino3dmLoadPlugin](https://threepipe.org/docs/classes/Rhino3dmLoadPlugin.html) | |||||
| Adds support for loading .3dm files generated by [Rhino 3D](https://www.rhino3d.com/). This plugin includes some changes with how 3dm files are loaded in three.js. The changes are around loading layer and primitive properties when set as reference in the 3dm files. | Adds support for loading .3dm files generated by [Rhino 3D](https://www.rhino3d.com/). This plugin includes some changes with how 3dm files are loaded in three.js. The changes are around loading layer and primitive properties when set as reference in the 3dm files. | ||||
| ## Additional Plugins | |||||
| Additional plugins can be found in the [plugins](plugins/) directory. | |||||
| These add support for integrating with other libraries, adding new features, and other functionality with different licenses. | |||||
| ### Tweakpane Ui plugin | |||||
| todo: image | |||||
| Example: https://threepipe.org/examples/#viewer-uiconfig/ | |||||
| Source Code: [plugins/tweakpane/src/TweakpaneUiPlugin.ts](plugins/tweakpane/src/TweakpaneUiPlugin.ts) | |||||
| API Reference: [TweakpaneUiPlugin](https://threepipe.org/plugins/tweakpane/docs/classes/TweakpaneUiPlugin.html) | |||||
| NPM: `npm install @threepipe/plugin-tweakpane` | |||||
| CDN: https://threepipe.org/plugins/tweakpane/dist/index.mjs | |||||
| TweakpaneUiPlugin adds support for using [uiconfig-tweakpane](https://github.com/repalash/uiconfig-tweakpane) | |||||
| to create a configuration UI in applications using the [Tweakpane](https://cocopon.github.io/tweakpane/) library. | |||||
| The plugin takes the [uiconfig](https://github.com/repalash/uiconfig.js) | |||||
| that's defined in the viewer and all the objects to automatically render a UI in the browser. | |||||
| ```typescript | |||||
| import {IObject3D, ThreeViewer, TonemapPlugin} from 'threepipe' | |||||
| import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' | |||||
| const viewer = new ThreeViewer({...}) | |||||
| // Add the plugin | |||||
| const plugin = viewer.addPluginSync(new TweakpaneUiPlugin(true)) // true to show expanded the UI by default | |||||
| // Add the UI for the viewer | |||||
| plugin.appendChild(viewer.uiConfig) | |||||
| // Add UI for some plugins | |||||
| plugin.setupPlugins(TonemapPlugin, DropzonePlugin) | |||||
| ``` | |||||
| ### Tweakpane Editor Plugin | |||||
| todo: image | |||||
| Example: https://threepipe.org/examples/#tweakpane-editor/ | |||||
| Source Code: [plugins/tweakpane-editor/src/TweakpaneEditorPlugin.ts](plugins/tweakpane-editor/src/TweakpaneEditorPlugin.ts) | |||||
| API Reference: [TweakpaneEditorPlugin](https://threepipe.org/plugins/tweakpane-editor/docs/classes/TweakpaneEditorPlugin.html) | |||||
| NPM: `npm install @threepipe/plugin-tweakpane-editor` | |||||
| CDN: https://threepipe.org/plugins/tweakpane-editor/dist/index.mjs | |||||
| TweakpaneEditorPlugin uses TweakpaneUiPlugin to create an editor for editing viewer, | |||||
| plugins, model and material configurations in the browser. | |||||
| ```typescript | |||||
| import {IObject3D, ThreeViewer, TonemapPlugin} from 'threepipe' | |||||
| import {TweakpaneEditorPlugin} from '@threepipe/plugin-tweakpane-editor' | |||||
| const viewer = new ThreeViewer({...}) | |||||
| viewer.addPluginSync(new TweakpaneUiPlugin(true)) | |||||
| const editor = viewer.addPluginSync(new TweakpaneEditorPlugin()) | |||||
| // Add some plugins to the viewer | |||||
| await viewer.addPlugins([ | |||||
| new ViewerUiConfigPlugin(), | |||||
| // new SceneUiConfigPlugin(), // this is already in ViewerUiPlugin | |||||
| new DepthBufferPlugin(HalfFloatType, true, true), | |||||
| new NormalBufferPlugin(HalfFloatType, false), | |||||
| new RenderTargetPreviewPlugin(false), | |||||
| ]) | |||||
| // Load the plugin UI in the editor and tweakpane ui with categories. | |||||
| editor.loadPlugins({ | |||||
| ['Viewer']: [ViewerUiConfigPlugin, SceneUiConfigPlugin, DropzonePlugin, FullScreenPlugin], | |||||
| ['GBuffer']: [DepthBufferPlugin, NormalBufferPlugin], | |||||
| ['Post-processing']: [TonemapPlugin], | |||||
| ['Debug']: [RenderTargetPreviewPlugin], | |||||
| }) | |||||
| ``` |
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="UTF-8"> | |||||
| <title>Half float HDR Test</title> | |||||
| <!-- Import maps polyfill --> | |||||
| <!-- Remove this when import maps will be widely supported --> | |||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | |||||
| <script type="importmap"> | |||||
| { | |||||
| "imports": { | |||||
| "threepipe": "./../../dist/index.mjs", | |||||
| "@threepipe/plugin-tweakpane": "./../../plugins/tweakpane/dist/index.mjs" | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style id="example-style"> | |||||
| html, body, #canvas-container, #mcanvas { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| margin: 0; | |||||
| overflow: hidden; | |||||
| } | |||||
| </style> | |||||
| <script type="module" src="../examples-utils/simple-code-preview.mjs"></script> | |||||
| <script id="example-script" type="module" src="./script.js" data-scripts="./script.ts;./script.js"></script> | |||||
| </head> | |||||
| <body> | |||||
| <div id="canvas-container"> | |||||
| <canvas id="mcanvas"></canvas> | |||||
| </div> | |||||
| </body> |
| import {_testFinish, BoxGeometry, Color, Mesh, PhysicalMaterial, ThreeViewer, TonemapPlugin} from 'threepipe' | |||||
| import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' | |||||
| async function init() { | |||||
| const viewer = new ThreeViewer({ | |||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||||
| rgbm: false, | |||||
| dropzone: { | |||||
| allowedExtensions: ['gltf', 'glb', 'hdr'], | |||||
| addOptions: { | |||||
| disposeSceneObjects: true, | |||||
| autoSetEnvironment: true, // when hdr is dropped | |||||
| autoSetBackground: true, | |||||
| }, | |||||
| }, | |||||
| }) | |||||
| viewer.scene.backgroundColor = new Color().set('black') | |||||
| viewer.getPlugin(TonemapPlugin)!.exposure = 0.04 | |||||
| // viewer.renderManager.screenPass.outputColorSpace = LinearSRGBColorSpace | |||||
| const box = new BoxGeometry(0.5, 0.5, 0.5) | |||||
| const material = new PhysicalMaterial({ | |||||
| color: 'white', | |||||
| emissive: 'white', | |||||
| emissiveIntensity: 1, | |||||
| }) | |||||
| const n = 5 | |||||
| for (let i = 0; i < n * n; i++) { | |||||
| const mesh = new Mesh() | |||||
| const mat = material.clone() | |||||
| mat.emissiveIntensity = (1 - i / (n * n)) * 16 | |||||
| mesh.material = mat | |||||
| mesh.geometry = box | |||||
| mesh.position.x = Math.floor(n / 2) - Math.floor(i % n) | |||||
| mesh.position.y = Math.floor(i / n) - Math.floor(n / 2) | |||||
| mesh.position.multiplyScalar(0.5) | |||||
| viewer.scene.addObject(mesh) | |||||
| console.log(mat.emissiveIntensity) | |||||
| } | |||||
| const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true)) | |||||
| ui.setupPluginUi(TonemapPlugin) | |||||
| ui.appendChild(viewer.renderManager.screenPass.uiConfig) | |||||
| } | |||||
| init().then(_testFinish) |
| <h2 class="category">Tests</h2> | <h2 class="category">Tests</h2> | ||||
| <ul> | <ul> | ||||
| <li><a href="./gltf-transmission-test/">GLTF Transmission Test </a></li> | <li><a href="./gltf-transmission-test/">GLTF Transmission Test </a></li> | ||||
| <li><a href="./uint8-rgbm-hdr-test/">Uint8 RGBM HDR Test </a></li> | |||||
| <li><a href="./half-float-hdr-test/">Half-float HDR Test </a></li> | |||||
| <li><a href="./sphere-rgbm-test/">RGBM Test </a></li> | <li><a href="./sphere-rgbm-test/">RGBM Test </a></li> | ||||
| <li><a href="./sphere-half-float-test/">Half Float Test </a></li> | <li><a href="./sphere-half-float-test/">Half Float Test </a></li> | ||||
| <li><a href="./sphere-msaa-test/">MSAA Test </a></li> | <li><a href="./sphere-msaa-test/">MSAA Test </a></li> |
| const viewer = new ThreeViewer({ | const viewer = new ThreeViewer({ | ||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | ||||
| tonemap: true, // this is true by default | |||||
| }) | }) | ||||
| // A GBuffer(depth buffer here) is required for the `tonemapBackground` flag in TonemapPlugin to work | // A GBuffer(depth buffer here) is required for the `tonemapBackground` flag in TonemapPlugin to work | ||||
| viewer.addPluginSync(new DepthBufferPlugin(UnsignedByteType, true)) | viewer.addPluginSync(new DepthBufferPlugin(UnsignedByteType, true)) | ||||
| viewer.addPluginSync(new TonemapPlugin()) | |||||
| await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr') | await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr') | ||||
| await viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf') | await viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf') |
| await viewer.addPlugins([ | await viewer.addPlugins([ | ||||
| new ViewerUiConfigPlugin(), | new ViewerUiConfigPlugin(), | ||||
| // new SceneUiConfigPlugin(), | |||||
| // new SceneUiConfigPlugin(), // this is already in ViewerUiPlugin | |||||
| new DepthBufferPlugin(HalfFloatType, true, true), | new DepthBufferPlugin(HalfFloatType, true, true), | ||||
| new NormalBufferPlugin(HalfFloatType, false), | new NormalBufferPlugin(HalfFloatType, false), | ||||
| new RenderTargetPreviewPlugin(false), | new RenderTargetPreviewPlugin(false), | ||||
| new TonemapPlugin(), | |||||
| ]) | ]) | ||||
| const rt = viewer.getOrAddPluginSync(RenderTargetPreviewPlugin) | const rt = viewer.getOrAddPluginSync(RenderTargetPreviewPlugin) |
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="UTF-8"> | |||||
| <title>Uint8 RGBM HDR Test</title> | |||||
| <!-- Import maps polyfill --> | |||||
| <!-- Remove this when import maps will be widely supported --> | |||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | |||||
| <script type="importmap"> | |||||
| { | |||||
| "imports": { | |||||
| "threepipe": "./../../dist/index.mjs", | |||||
| "@threepipe/plugin-tweakpane": "./../../plugins/tweakpane/dist/index.mjs" | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style id="example-style"> | |||||
| html, body, #canvas-container, #mcanvas { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| margin: 0; | |||||
| overflow: hidden; | |||||
| } | |||||
| </style> | |||||
| <script type="module" src="../examples-utils/simple-code-preview.mjs"></script> | |||||
| <script id="example-script" type="module" src="./script.js" data-scripts="./script.ts;./script.js"></script> | |||||
| </head> | |||||
| <body> | |||||
| <div id="canvas-container"> | |||||
| <canvas id="mcanvas"></canvas> | |||||
| </div> | |||||
| </body> |
| import {_testFinish, BoxGeometry, Color, Mesh, PhysicalMaterial, ThreeViewer, TonemapPlugin} from 'threepipe' | |||||
| import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' | |||||
| async function init() { | |||||
| const viewer = new ThreeViewer({ | |||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||||
| rgbm: true, | |||||
| dropzone: { | |||||
| allowedExtensions: ['gltf', 'glb', 'hdr'], | |||||
| addOptions: { | |||||
| disposeSceneObjects: true, | |||||
| autoSetEnvironment: true, // when hdr is dropped | |||||
| autoSetBackground: true, | |||||
| }, | |||||
| }, | |||||
| }) | |||||
| viewer.scene.backgroundColor = new Color().set('black') | |||||
| viewer.getPlugin(TonemapPlugin)!.exposure = 0.04 | |||||
| // viewer.renderManager.screenPass.outputColorSpace = LinearSRGBColorSpace | |||||
| const box = new BoxGeometry(0.5, 0.5, 0.5) | |||||
| const material = new PhysicalMaterial({ | |||||
| color: 'white', | |||||
| emissive: 'white', | |||||
| emissiveIntensity: 1, | |||||
| }) | |||||
| const n = 5 | |||||
| for (let i = 0; i < n * n; i++) { | |||||
| const mesh = new Mesh() | |||||
| const mat = material.clone() | |||||
| mat.emissiveIntensity = (1 - i / (n * n)) * 16 | |||||
| mesh.material = mat | |||||
| mesh.geometry = box | |||||
| mesh.position.x = Math.floor(n / 2) - Math.floor(i % n) | |||||
| mesh.position.y = Math.floor(i / n) - Math.floor(n / 2) | |||||
| mesh.position.multiplyScalar(0.5) | |||||
| viewer.scene.addObject(mesh) | |||||
| console.log(mat.emissiveIntensity) | |||||
| } | |||||
| const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true)) | |||||
| ui.setupPluginUi(TonemapPlugin) | |||||
| ui.appendChild(viewer.renderManager.screenPass.uiConfig) | |||||
| } | |||||
| init().then(_testFinish) |
| { | { | ||||
| "name": "threepipe", | "name": "threepipe", | ||||
| "version": "0.0.9", | |||||
| "version": "0.0.10-dev.1", | |||||
| "description": "A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.", | "description": "A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.", | ||||
| "main": "src/index.ts", | "main": "src/index.ts", | ||||
| "module": "dist/index.mjs", | "module": "dist/index.mjs", |
| ReinhardToneMapping, | ReinhardToneMapping, | ||||
| Shader, | Shader, | ||||
| ShaderChunk, | ShaderChunk, | ||||
| SRGBColorSpace, | |||||
| ToneMapping, | ToneMapping, | ||||
| Vector4, | Vector4, | ||||
| WebGLRenderer, | WebGLRenderer, | ||||
| // eslint-disable-next-line @typescript-eslint/naming-convention | // eslint-disable-next-line @typescript-eslint/naming-convention | ||||
| export const Uncharted2Tonemapping: ToneMapping = CustomToneMapping | export const Uncharted2Tonemapping: ToneMapping = CustomToneMapping | ||||
| /** | |||||
| * Tonemap Plugin | |||||
| * | |||||
| * Adds an extension to {@link ScreenPass} material | |||||
| * for applying tonemapping on the final buffer before rendering to screen. | |||||
| * | |||||
| * Also adds support for Uncharted2 tone-mapping. | |||||
| * @category Plugins | |||||
| */ | |||||
| @uiFolderContainer('Tonemapping') | @uiFolderContainer('Tonemapping') | ||||
| export class TonemapPlugin extends AViewerPluginSync<''> implements MaterialExtension, GBufferUpdater { | export class TonemapPlugin extends AViewerPluginSync<''> implements MaterialExtension, GBufferUpdater { | ||||
| static readonly PluginType = 'Tonemap' | static readonly PluginType = 'Tonemap' | ||||
| onObjectRender(_: Object3D, material: IMaterial, renderer: WebGLRenderer): void { | onObjectRender(_: Object3D, material: IMaterial, renderer: WebGLRenderer): void { | ||||
| if (!this.enabled) return | if (!this.enabled) return | ||||
| const {toneMapping, toneMappingExposure, outputColorSpace} = renderer | |||||
| const {toneMapping, toneMappingExposure} = renderer | |||||
| this._rendererState.toneMapping = toneMapping | this._rendererState.toneMapping = toneMapping | ||||
| this._rendererState.toneMappingExposure = toneMappingExposure | this._rendererState.toneMappingExposure = toneMappingExposure | ||||
| this._rendererState.outputColorSpace = outputColorSpace | |||||
| renderer.toneMapping = this.toneMapping | renderer.toneMapping = this.toneMapping | ||||
| renderer.toneMappingExposure = this.exposure | renderer.toneMappingExposure = this.exposure | ||||
| renderer.outputColorSpace = SRGBColorSpace | |||||
| material.toneMapped = true | material.toneMapped = true | ||||
| material.needsUpdate = true | material.needsUpdate = true | ||||
| } | } | ||||
| onAfterRender(_: Object3D, _1: IMaterial, renderer: WebGLRenderer): void { | onAfterRender(_: Object3D, _1: IMaterial, renderer: WebGLRenderer): void { | ||||
| renderer.toneMapping = this._rendererState.toneMapping | renderer.toneMapping = this._rendererState.toneMapping | ||||
| renderer.toneMappingExposure = this._rendererState.toneMappingExposure | renderer.toneMappingExposure = this._rendererState.toneMappingExposure | ||||
| renderer.outputColorSpace = this._rendererState.outputColorSpace | |||||
| } | } | ||||
| getUiConfig(): any { | getUiConfig(): any { |
| import {ICamera, IRenderManager, IScene, IWebGLRenderer, ShaderMaterial2} from '../core' | import {ICamera, IRenderManager, IScene, IWebGLRenderer, ShaderMaterial2} from '../core' | ||||
| import {CopyShader} from 'three/examples/jsm/shaders/CopyShader.js' | import {CopyShader} from 'three/examples/jsm/shaders/CopyShader.js' | ||||
| import {IPassID, IPipelinePass} from './Pass' | import {IPassID, IPipelinePass} from './Pass' | ||||
| import {uiFolderContainer, uiToggle} from 'uiconfig.js' | |||||
| import {uiDropdown, uiFolderContainer, UiObjectConfig, uiToggle} from 'uiconfig.js' | |||||
| import {ViewerRenderManager} from '../viewer' | import {ViewerRenderManager} from '../viewer' | ||||
| import {matDefine} from '../three' | |||||
| import {matDefine, threeConstMappings} from '../three' | |||||
| import ScreenPassShader from './ScreenPass.glsl' | import ScreenPassShader from './ScreenPass.glsl' | ||||
| import {shaderReplaceString} from '../utils' | import {shaderReplaceString} from '../utils' | ||||
| @uiFolderContainer('Screen Pass') | @uiFolderContainer('Screen Pass') | ||||
| export class ScreenPass extends ExtendedShaderPass implements IPipelinePass<'screen'> { | export class ScreenPass extends ExtendedShaderPass implements IPipelinePass<'screen'> { | ||||
| uiConfig!: UiObjectConfig | |||||
| readonly passId = 'screen' | readonly passId = 'screen' | ||||
| after: IPassID[] = ['render'] | after: IPassID[] = ['render'] | ||||
| required: IPassID[] = ['render'] | required: IPassID[] = ['render'] | ||||
| this.material.addEventListener('materialUpdate', this.setDirty) | this.material.addEventListener('materialUpdate', this.setDirty) | ||||
| } | } | ||||
| outputColorSpace: ColorSpace = SRGBColorSpace | |||||
| @uiDropdown('Output Color Space', threeConstMappings.ColorSpace.uiConfig, (t: ScreenPass)=>({onChange: t.setDirty})) | |||||
| outputColorSpace: ColorSpace = SRGBColorSpace | |||||
| private _lastReadBuffer?: WebGLMultipleRenderTargets | WebGLRenderTarget | private _lastReadBuffer?: WebGLMultipleRenderTargets | WebGLRenderTarget | ||||
| import {DropzonePlugin, DropzonePluginOptions} from '../plugins/interaction/DropzonePlugin' | import {DropzonePlugin, DropzonePluginOptions} from '../plugins/interaction/DropzonePlugin' | ||||
| import {uiConfig, uiFolderContainer, UiObjectConfig} from 'uiconfig.js' | import {uiConfig, uiFolderContainer, UiObjectConfig} from 'uiconfig.js' | ||||
| import {IRenderTarget} from '../rendering' | import {IRenderTarget} from '../rendering' | ||||
| import {TonemapPlugin} from '../plugins' | |||||
| export type IViewerEvent = BaseEvent & { | export type IViewerEvent = BaseEvent & { | ||||
| type: 'update'|'preRender'|'postRender'|'preFrame'|'postFrame'|'dispose'|'addPlugin'|'renderEnabled'|'renderDisabled' | type: 'update'|'preRender'|'postRender'|'preFrame'|'postFrame'|'dispose'|'addPlugin'|'renderEnabled'|'renderDisabled' | ||||
| debug?: boolean | debug?: boolean | ||||
| /** | |||||
| * TonemapPlugin is added to the viewer if this is true. | |||||
| * @default true | |||||
| */ | |||||
| tonemap?: boolean | |||||
| /** | /** | ||||
| * Options for the asset manager. | * Options for the asset manager. | ||||
| */ | */ | ||||
| useGBufferDepth?: boolean | useGBufferDepth?: boolean | ||||
| } | } | ||||
| const VIEWER_VERSION = '0.0.1' | |||||
| const VIEWER_VERSION = '0.0.10-dev.1' | |||||
| /** | /** | ||||
| * The ThreeViewer is the main class in the framework. | |||||
| * Three Viewer | |||||
| * | |||||
| * The ThreeViewer is the main class in the framework to manage a scene, render and add plugins to it. | |||||
| * @category Viewer | * @category Viewer | ||||
| */ | */ | ||||
| @uiFolderContainer('Viewer') | @uiFolderContainer('Viewer') | ||||
| if (options.dropzone) { | if (options.dropzone) { | ||||
| this.addPluginSync(new DropzonePlugin(typeof options.dropzone === 'object' ? options.dropzone : undefined)) | this.addPluginSync(new DropzonePlugin(typeof options.dropzone === 'object' ? options.dropzone : undefined)) | ||||
| } | } | ||||
| if (options.tonemap !== false) { | |||||
| this.addPluginSync(new TonemapPlugin()) | |||||
| } | |||||
| this.console.log('ThreePipe Viewer instance initialized, version: ', ThreeViewer.VERSION) | this.console.log('ThreePipe Viewer instance initialized, version: ', ThreeViewer.VERSION) | ||||