| [Github](https://github.com/repalash/threepipe) — | [Github](https://github.com/repalash/threepipe) — | ||||
| [Examples](https://threepipe.org/examples/) — | [Examples](https://threepipe.org/examples/) — | ||||
| [API Reference](https://threepipe.org/docs/) — | [API Reference](https://threepipe.org/docs/) — | ||||
| [WebGi](https://webgi.xyz/docs/) | |||||
| [WebGi](https://webgi.dev/) | |||||
| [](https://www.npmjs.com/package/threepipe) | [](https://www.npmjs.com/package/threepipe) | ||||
| [](https://discord.gg/apzU8rUWxY) | [](https://discord.gg/apzU8rUWxY) | ||||
| Some plugins(in the [plugins](https://github.com/repalash/threepipe/tree/master/plugins) folder) might have different licenses. Check the individual plugin documentation and the source folder/files for more details. | Some plugins(in the [plugins](https://github.com/repalash/threepipe/tree/master/plugins) folder) might have different licenses. Check the individual plugin documentation and the source folder/files for more details. | ||||
| ## Status | ## Status | ||||
| The project is in `alpha` stage and under active development. Many features will be added but the core API will not change significantly in future releases. | |||||
| Check out [WebGi](https://webgi.xyz/docs) for an advanced tailor-made solution for e-commerce, jewelry, automobile, apparel, furniture etc. | |||||
| The project is in `beta` stage and under active development. | |||||
| Many features will be added but the core API will not change significantly in future releases. | |||||
| ## Table of Contents | ## Table of Contents | ||||
| <html lang="en"> | <html lang="en"> | ||||
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>Bloom Plugin</title> | |||||
| <title>Anisotropy Plugin</title> | |||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> |
| msaa: true, | msaa: true, | ||||
| rgbm: true, | rgbm: true, | ||||
| zPrepass: true, // This example shows a bug in zPrepass | zPrepass: true, // This example shows a bug in zPrepass | ||||
| // forceZPrepass: true, | |||||
| plugins: [LoadingScreenPlugin], | plugins: [LoadingScreenPlugin], | ||||
| }) | }) | ||||
| <li><a href="./progressive-plugin/">Progressive Plugin </a></li> | <li><a href="./progressive-plugin/">Progressive Plugin </a></li> | ||||
| <li><a href="./custom-pipeline/">Custom Pipeline specification </a></li> | <li><a href="./custom-pipeline/">Custom Pipeline specification </a></li> | ||||
| <li><a href="./ssaa-plugin/">SSAA Plugin </a></li> | <li><a href="./ssaa-plugin/">SSAA Plugin </a></li> | ||||
| <li><a href="./msaa-ssaa/">MSAA + SSAA </a></li> | |||||
| <li><a href="./depth-buffer-plugin/">Depth Buffer Plugin </a></li> | <li><a href="./depth-buffer-plugin/">Depth Buffer Plugin </a></li> | ||||
| <li><a href="./normal-buffer-plugin/">Normal Buffer Plugin </a></li> | <li><a href="./normal-buffer-plugin/">Normal Buffer Plugin </a></li> | ||||
| <li><a href="./gbuffer-plugin/">GBuffer Plugin <br/>(NormalDepth+Flags) </a></li> | <li><a href="./gbuffer-plugin/">GBuffer Plugin <br/>(NormalDepth+Flags) </a></li> | ||||
| <li><a href="./bloom-plugin/">HDR Bloom Plugin </a></li> | <li><a href="./bloom-plugin/">HDR Bloom Plugin </a></li> | ||||
| <li><a href="./depthoffield-plugin/">DepthOfField Plugin </a></li> | <li><a href="./depthoffield-plugin/">DepthOfField Plugin </a></li> | ||||
| <li><a href="./ssreflection-plugin/">Screen Space Reflection(SSR) Plugin </a></li> | <li><a href="./ssreflection-plugin/">Screen Space Reflection(SSR) Plugin </a></li> | ||||
| <li><a href="./temporalaa-plugin/">Temporal Anti-aliasing Plugin </a></li> | |||||
| <li><a href="./temporalaa-plugin/">Temporal Anti-aliasing(TAA) Plugin </a></li> | |||||
| <li><a href="./outline-plugin/">Outline(Picking) Plugin </a></li> | <li><a href="./outline-plugin/">Outline(Picking) Plugin </a></li> | ||||
| <li><a href="./ssgi-plugin/">Screen Space Global Illumination(SSGI) Plugin </a></li> | <li><a href="./ssgi-plugin/">Screen Space Global Illumination(SSGI) Plugin </a></li> | ||||
| <li><a href="./ssgi-ssr-plugin/">SSGI + SSR Plugins </a></li> | <li><a href="./ssgi-ssr-plugin/">SSGI + SSR Plugins </a></li> |
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="UTF-8"> | |||||
| <title>MSAA + SSAA</title> | |||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- 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, | |||||
| IObject3D, | |||||
| LoadingScreenPlugin, | |||||
| PhysicalMaterial, | |||||
| ProgressivePlugin, | |||||
| SSAAPlugin, | |||||
| ThreeViewer, | |||||
| } from 'threepipe' | |||||
| import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' | |||||
| async function init() { | |||||
| const viewer = new ThreeViewer({ | |||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||||
| debug: true, | |||||
| msaa: true, | |||||
| rgbm: true, | |||||
| renderScale: 1, | |||||
| dropzone: { | |||||
| addOptions: { | |||||
| disposeSceneObjects: true, | |||||
| importConfig: true, | |||||
| }, | |||||
| }, | |||||
| plugins: [LoadingScreenPlugin], | |||||
| }) | |||||
| viewer.addPluginSync(new SSAAPlugin()) | |||||
| await Promise.all([ | |||||
| viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr'), | |||||
| // viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/IridescenceLamp.glb', { | |||||
| // autoCenter: true, | |||||
| // autoScale: true, | |||||
| // }), | |||||
| viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/LittlestTokyo.glb', { | |||||
| autoCenter: true, | |||||
| autoScale: true, | |||||
| }), | |||||
| ]) | |||||
| viewer.renderManager.renderPass.overrideMaterial = new PhysicalMaterial({ | |||||
| color: 'white', | |||||
| roughness: 1, | |||||
| metalness: 0, | |||||
| wireframe: true, | |||||
| }) | |||||
| viewer.scene.mainCamera.position.set(0, 0, 3.5) | |||||
| const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true)) | |||||
| ui.appendChild({ | |||||
| type: 'toggle', | |||||
| label: 'Auto Rotate', | |||||
| property: [viewer.scene.mainCamera.controls, 'autoRotate'], | |||||
| }) | |||||
| ui.setupPluginUi(SSAAPlugin, { | |||||
| expanded: true, | |||||
| }) | |||||
| ui.setupPlugins(ProgressivePlugin) | |||||
| ui.appendChild(viewer.renderManager.uiConfig) | |||||
| await viewer.getPlugin(ProgressivePlugin)?.convergedPromise | |||||
| console.log('converged') | |||||
| } | |||||
| init().finally(_testFinish) |
| <html lang="en"> | <html lang="en"> | ||||
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>SSReflection Plugin</title> | |||||
| <title>Outline Plugin</title> | |||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> |
| <html lang="en"> | <html lang="en"> | ||||
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>SSReflection Plugin</title> | |||||
| <title>SSGI Plugin</title> | |||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> |
| <html lang="en"> | <html lang="en"> | ||||
| <head> | <head> | ||||
| <meta charset="UTF-8"> | <meta charset="UTF-8"> | ||||
| <title>SSReflection Plugin</title> | |||||
| <title>SSGI + SSR Plugins</title> | |||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||
| <!-- Import maps polyfill --> | <!-- Import maps polyfill --> | ||||
| <!-- Remove this when import maps will be widely supported --> | <!-- Remove this when import maps will be widely supported --> |
| const viewer = new ThreeViewer({ | const viewer = new ThreeViewer({ | ||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | ||||
| msaa: true, | msaa: true, | ||||
| rgbm: true, | |||||
| dropzone: { | dropzone: { | ||||
| addOptions: { | addOptions: { | ||||
| disposeSceneObjects: true, | disposeSceneObjects: true, |
| const viewer = new ThreeViewer({ | const viewer = new ThreeViewer({ | ||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | ||||
| renderScale: 'auto', | renderScale: 'auto', | ||||
| msaa: checkQuery('msaa', false), | |||||
| msaa: checkQuery('msaa', true), | |||||
| rgbm: checkQuery('rgbm', true), | rgbm: checkQuery('rgbm', true), | ||||
| debug: checkQuery('debug', false), | debug: checkQuery('debug', false), | ||||
| assetManager: { | assetManager: { |
| { | { | ||||
| "name": "threepipe", | "name": "threepipe", | ||||
| "version": "0.0.37", | |||||
| "version": "0.0.38-dev", | |||||
| "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": "dist/index.js", | "main": "dist/index.js", | ||||
| "module": "dist/index.mjs", | "module": "dist/index.mjs", |
| }, | }, | ||||
| { | { | ||||
| type: 'slider', | type: 'slider', | ||||
| bounds: [0, 10], | |||||
| bounds: [0, 100], | |||||
| property: [material, 'emissiveIntensity'], | property: [material, 'emissiveIntensity'], | ||||
| }, | }, | ||||
| { | { |
| for (const vElement of v) shader.vertexShader = shaderReplaceString(shader.vertexShader, vElement[0], '#glMarker ' + vElement[1] + '\n' + vElement[0]) | for (const vElement of v) shader.vertexShader = shaderReplaceString(shader.vertexShader, vElement[0], '#glMarker ' + vElement[1] + '\n' + vElement[0]) | ||||
| for (const fElement of f) shader.fragmentShader = shaderReplaceString(shader.fragmentShader, fElement[0], '#glMarker ' + fElement[1] + '\n' + fElement[0]) | for (const fElement of f) shader.fragmentShader = shaderReplaceString(shader.fragmentShader, fElement[0], '#glMarker ' + fElement[1] + '\n' + fElement[0]) | ||||
| // for NaN. todo do the same in Unlit and line materials? | |||||
| shader.fragmentShader = shaderReplaceString(shader.fragmentShader, '#include <output_fragment>', 'gl_FragColor = clamp(gl_FragColor, 0.0, 1000.0);\n', {append: true}) | |||||
| iMaterialCommons.onBeforeCompile.call(this, shader, renderer) | iMaterialCommons.onBeforeCompile.call(this, shader, renderer) | ||||
| shader.defines && (shader.defines.INVERSE_ALPHAMAP = this.userData.inverseAlphaMap ? 1 : 0) | shader.defines && (shader.defines.INVERSE_ALPHAMAP = this.userData.inverseAlphaMap ? 1 : 0) |
| screenShader?: TViewerScreenShader, | screenShader?: TViewerScreenShader, | ||||
| /** | /** | ||||
| * Use MSAA. | * Use MSAA. | ||||
| * Renders objects in a multi-sampled buffer. | |||||
| * @default false | |||||
| */ | */ | ||||
| msaa?: boolean, | msaa?: boolean, | ||||
| /** | /** | ||||
| * Use Uint8 RGBM HDR Render Pipeline. | * Use Uint8 RGBM HDR Render Pipeline. | ||||
| * Provides better performance with post-processing. | * Provides better performance with post-processing. | ||||
| * RenderManager Uses Half-float if set to false. | * RenderManager Uses Half-float if set to false. | ||||
| * @default true | |||||
| */ | */ | ||||
| rgbm?: boolean | rgbm?: boolean | ||||
| /** | /** | ||||
| * Use rendered gbuffer as depth-prepass / z-prepass. (Requires DepthBufferPlugin/GBufferPlugin). | * Use rendered gbuffer as depth-prepass / z-prepass. (Requires DepthBufferPlugin/GBufferPlugin). | ||||
| * Set it to true if you only have opaque objects in the scene to get better performance. | * Set it to true if you only have opaque objects in the scene to get better performance. | ||||
| * | * | ||||
| * todo fix: It will be disabled when there are any transparent/transmissive objects with render to depth buffer enabled, see forceZPrepass | |||||
| * todo fix: It should be disabled when there are any transparent/transmissive objects with render to depth buffer enabled, see forceZPrepass | |||||
| */ | */ | ||||
| zPrepass?: boolean | zPrepass?: boolean | ||||
| /** | |||||
| * Force z-prepass even if there are transparent/transmissive objects with render to depth buffer enabled. | |||||
| */ | |||||
| forceZPrepass?: boolean // todo | |||||
| // /** | |||||
| // * Force z-prepass even if there are transparent/transmissive objects with render to depth buffer enabled. | |||||
| // * Not implemented | |||||
| // */ | |||||
| // forceZPrepass?: boolean // todo | |||||
| /** | /** | ||||
| * Render scale, 1 = full resolution, 0.5 = half resolution, 2 = double resolution. | * Render scale, 1 = full resolution, 0.5 = half resolution, 2 = double resolution. | ||||
| this.renderManager = new ViewerRenderManager({ | this.renderManager = new ViewerRenderManager({ | ||||
| canvas: this._canvas, | canvas: this._canvas, | ||||
| msaa: options.msaa ?? options.isAntialiased ?? false, | msaa: options.msaa ?? options.isAntialiased ?? false, | ||||
| rgbm: options.rgbm ?? options.useRgbm ?? false, | |||||
| rgbm: options.rgbm ?? options.useRgbm ?? true, | |||||
| zPrepass: options.zPrepass ?? options.useGBufferDepth ?? false, | zPrepass: options.zPrepass ?? options.useGBufferDepth ?? false, | ||||
| depthBuffer: !(options.zPrepass ?? options.useGBufferDepth ?? false), | depthBuffer: !(options.zPrepass ?? options.useGBufferDepth ?? false), | ||||
| screenShader: options.screenShader, | screenShader: options.screenShader, | ||||
| * Deserialize and import all the viewer and plugin settings, exported with {@link exportConfig}. | * Deserialize and import all the viewer and plugin settings, exported with {@link exportConfig}. | ||||
| */ | */ | ||||
| async importConfig(json: ISerializedConfig|ISerializedViewerConfig) { | async importConfig(json: ISerializedConfig|ISerializedViewerConfig) { | ||||
| if (json.type !== this.type && <string>json.type !== 'ViewerApp') { | |||||
| if (json.type !== this.type && <string>json.type !== 'ViewerApp' && <string>json.type !== 'ThreeViewer') { | |||||
| if (this.getPlugin(json.type)) { | if (this.getPlugin(json.type)) { | ||||
| return this.importPluginConfig(json) | return this.importPluginConfig(json) | ||||
| } else { | } else { |