| @@ -0,0 +1,37 @@ | |||
| <!DOCTYPE html> | |||
| <html lang="en"> | |||
| <head> | |||
| <meta charset="UTF-8"> | |||
| <title>Bloom Plugin</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/webgi-plugins": "https://unpkg.com/@threepipe/webgi-plugins@0.3.0/dist/index.mjs", | |||
| "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> | |||
| @@ -0,0 +1,48 @@ | |||
| import {_testFinish, IObject3D, LoadingScreenPlugin, PickingPlugin, SSAAPlugin, ThreeViewer} from 'threepipe' | |||
| import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' | |||
| // @ts-expect-error todo fix | |||
| import {AnisotropyPlugin, BloomPlugin, OutlinePlugin, SSContactShadowsPlugin, TemporalAAPlugin} from '@threepipe/webgi-plugins' | |||
| async function init() { | |||
| const viewer = new ThreeViewer({ | |||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||
| msaa: true, | |||
| rgbm: true, | |||
| zPrepass: false, | |||
| renderScale: 'auto', | |||
| // rgbm: false, | |||
| maxHDRIntensity: 8, | |||
| dropzone: { | |||
| addOptions: { | |||
| disposeSceneObjects: true, | |||
| }, | |||
| }, | |||
| plugins: [LoadingScreenPlugin, SSAAPlugin, TemporalAAPlugin, BloomPlugin, PickingPlugin, OutlinePlugin, SSContactShadowsPlugin], | |||
| }) | |||
| const anisotropy = viewer.addPluginSync(AnisotropyPlugin) | |||
| const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true)) | |||
| await viewer.setEnvironmentMap('https://demo-assets.pixotronics.com/pixo/hdr/gem_2.hdr', { | |||
| setBackground: false, | |||
| }) | |||
| await viewer.load<IObject3D>('https://demo-assets.pixotronics.com/pixo/gltf/anisotropyScene.glb', { | |||
| autoCenter: true, | |||
| autoScale: true, | |||
| }) | |||
| viewer.scene.mainCamera.position.set(5, 0, 0) | |||
| ui.setupPluginUi(anisotropy) | |||
| ui.setupPluginUi(BloomPlugin) | |||
| ui.setupPluginUi(PickingPlugin) | |||
| // // add a light to test shader compile with sscs | |||
| // const light = new DirectionalLight2() | |||
| // viewer.scene.addObject(light) | |||
| // light.castShadow = true | |||
| } | |||
| init().then(_testFinish) | |||
| @@ -89,13 +89,18 @@ | |||
| padding: 0; | |||
| } | |||
| .sidebar h1 a { | |||
| a.brand-link{ | |||
| //background: linear-gradient(to right, rgb(231, 7, 7), rgb(91, 34, 203), rgb(7, 108, 211)); | |||
| background: linear-gradient(to right, var(--secondary-color), var(--secondary-color), rgb(231, 7, 7)); | |||
| -webkit-background-clip: text; | |||
| -webkit-text-fill-color: transparent; | |||
| text-decoration: none; | |||
| } | |||
| a.brand-link.webgi-link::after { | |||
| content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAQElEQVR42qXKwQkAIAxDUUdxtO6/RBQkQZvSi8I/pL4BoGw/XPkh4XigPmsUgh0626AjRsgxHTkUThsG2T/sIlzdTsp52kSS1wAAAABJRU5ErkJggg==); | |||
| margin: 0 3px 0 5px; | |||
| filter: invert(1); | |||
| } | |||
| .sidebar h1 a:hover { | |||
| color: var(--text-color-accent); | |||
| @@ -109,14 +114,10 @@ | |||
| } | |||
| .sidebar ul { | |||
| font-size: 1rem; | |||
| list-style: none; | |||
| padding: 0 0 0 1rem; | |||
| margin: 0 0 1rem; | |||
| display: flex; | |||
| flex-direction: column; | |||
| font-weight: normal; | |||
| gap: 0.6rem; | |||
| font-size: 1rem; list-style: none; | |||
| padding: 0 0 0 1rem; margin: 0 0 1rem; | |||
| display: flex; gap: 0.6rem; | |||
| flex-direction: column; font-weight: normal; | |||
| } | |||
| .sidebar ul li a { | |||
| @@ -144,26 +145,15 @@ | |||
| } | |||
| .iframe-container { | |||
| flex: 1; | |||
| height: 100%; | |||
| overflow: hidden; | |||
| flex: 1; height: 100%; overflow: hidden; | |||
| } | |||
| .iframe-container iframe { | |||
| width: 100%; | |||
| height: 100%; | |||
| width: 100%; height: 100%; | |||
| border: none; | |||
| } | |||
| .closed > ul { | |||
| display: none; | |||
| } | |||
| .closed > h1 { | |||
| display: none; | |||
| } | |||
| .closed > h2 { | |||
| .closed > ul, .closed > h1, .closed > h2 { | |||
| display: none; | |||
| } | |||
| @@ -175,18 +165,14 @@ | |||
| .closed:before{ | |||
| content: attr(data-selected-example); | |||
| position: absolute; | |||
| top: 0; | |||
| left: 0; | |||
| height: 100%; | |||
| width: 3.3rem; | |||
| top: 0; left: 0; | |||
| height: 100%; width: 3.3rem; | |||
| color: var(--primary-color); | |||
| font-size: 1.25rem; | |||
| text-align: center; | |||
| vertical-align: middle; | |||
| text-align: center; vertical-align: middle; | |||
| line-height: 3.25rem; | |||
| writing-mode: vertical-lr; | |||
| text-orientation: upright; | |||
| text-transform: uppercase; | |||
| text-orientation: upright; text-transform: uppercase; | |||
| font-family: "Source Code Pro", Menlo, Courier, monospace; | |||
| } | |||
| @@ -195,19 +181,16 @@ | |||
| } | |||
| .search-bar{ | |||
| box-sizing: border-box; | |||
| margin-bottom: 1rem; | |||
| width: 90%; | |||
| margin-bottom: 1rem; width: 90%; | |||
| background: transparent; | |||
| position: relative; | |||
| } | |||
| .search-bar input{ | |||
| box-sizing: border-box; | |||
| width: 100%; | |||
| padding: 0.5rem; | |||
| width: 100%; padding: 0.5rem; | |||
| color: var(--text-color-accent); | |||
| background: var(--background-color-search); | |||
| border: none; | |||
| border-radius: 4px; | |||
| border: none; border-radius: 4px; | |||
| transition: all 0.3s ease-in-out; | |||
| } | |||
| .search-bar input:hover { | |||
| @@ -223,18 +206,20 @@ | |||
| } | |||
| .search-icon { | |||
| position: absolute; | |||
| top: 50%; | |||
| left: 10px; | |||
| top: 50%; left: 10px; | |||
| transform: translateY(-50%); | |||
| color: var(--primary-color); | |||
| width: 15px; | |||
| height: 15px; | |||
| width: 15px; height: 15px; | |||
| } | |||
| .search-bar input { | |||
| padding-left: 2rem; | |||
| } | |||
| .github-icon{ | |||
| position: absolute; right:-1.25rem; top: 0.1rem; fill: #eeeeee; cursor: pointer; | |||
| } | |||
| @media only screen and (max-width: 768px) { | |||
| .root-container { | |||
| flex-direction: column; | |||
| @@ -257,7 +242,6 @@ | |||
| } | |||
| } | |||
| </style> | |||
| <script> | |||
| window.addEventListener('DOMContentLoaded', () => { | |||
| @@ -349,7 +333,18 @@ | |||
| <div class="root-container"> | |||
| <div class="sidebar" data-selected-example="Tweakpane Editor"> | |||
| <button class="hamburger"> ☰</button> | |||
| <h1><a href="https://github.com/repalash/threepipe">ThreePipe</a> Examples</h1> | |||
| <h1 style="position:relative;"> | |||
| <a class="brand-link" href="https://threepipe.org">ThreePipe</a> | |||
| Examples | |||
| <a class="brand-link" target="_blank" href="https://github.com/repalash/threepipe"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" | |||
| width="28" height="28" viewBox="0 0 24 24" | |||
| class="github-icon"> | |||
| <path d="M10.9,2.1c-4.6,0.5-8.3,4.2-8.8,8.7c-0.5,4.7,2.2,8.9,6.3,10.5C8.7,21.4,9,21.2,9,20.8v-1.6c0,0-0.4,0.1-0.9,0.1 c-1.4,0-2-1.2-2.1-1.9c-0.1-0.4-0.3-0.7-0.6-1C5.1,16.3,5,16.3,5,16.2C5,16,5.3,16,5.4,16c0.6,0,1.1,0.7,1.3,1c0.5,0.8,1.1,1,1.4,1 c0.4,0,0.7-0.1,0.9-0.2c0.1-0.7,0.4-1.4,1-1.8c-2.3-0.5-4-1.8-4-4c0-1.1,0.5-2.2,1.2-3C7.1,8.8,7,8.3,7,7.6c0-0.4,0-0.9,0.2-1.3 C7.2,6.1,7.4,6,7.5,6c0,0,0.1,0,0.1,0C8.1,6.1,9.1,6.4,10,7.3C10.6,7.1,11.3,7,12,7s1.4,0.1,2,0.3c0.9-0.9,2-1.2,2.5-1.3 c0,0,0.1,0,0.1,0c0.2,0,0.3,0.1,0.4,0.3C17,6.7,17,7.2,17,7.6c0,0.8-0.1,1.2-0.2,1.4c0.7,0.8,1.2,1.8,1.2,3c0,2.2-1.7,3.5-4,4 c0.6,0.5,1,1.4,1,2.3v2.6c0,0.3,0.3,0.6,0.7,0.5c3.7-1.5,6.3-5.1,6.3-9.3C22,6.1,16.9,1.4,10.9,2.1z"></path> | |||
| </svg> | |||
| </a> | |||
| </h1> | |||
| <div class="search-bar"> | |||
| <svg class="search-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |||
| <circle cx="11" cy="11" r="8"></circle> | |||
| @@ -357,6 +352,7 @@ | |||
| </svg> | |||
| <input id="filterInput" type="text" placeholder="Search" autocomplete="off" autofocus > | |||
| </div> | |||
| <h2 class="category">Editors/Viewers</h2> | |||
| <ul> | |||
| <li><a class="selected" href="./tweakpane-editor/">Tweakpane Editor </a></li> | |||
| @@ -376,12 +372,17 @@ | |||
| <li><a href="./basic-svg-renderer-plugin/">Basic SVG Renderer Plugin </a></li> | |||
| <li><a href="./three-svg-renderer-plugin/">Three SVG Renderer Plugin </a></li> | |||
| </ul> | |||
| <h2 class="category">Realistic Rendering (webgi)</h2> | |||
| <h2 class="category">Realistic Rendering (<a class="brand-link webgi-link" href="https://webgi.dev/" target="_blank">webgi</a>)</h2> | |||
| <ul> | |||
| <li><a href="./bloom-plugin/">HDR Bloom 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="./temporalaa-plugin/">Temporal Anti-aliasing 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-ssr-plugin/">SSGI + SSR Plugins </a></li> | |||
| <!--<li><a href="./ssrtao-plugin/">Screen Space Ray Traced AO Plugin </a></li>--> | |||
| <li><a href="./anisotropy-plugin/">Anisotropy(Blender) Plugin </a></li> | |||
| <li><a href="./velocity-buffer-plugin/">Velocity Buffer Plugin (TAA) </a></li> | |||
| <li><a href="./sscontactshadows-plugin/">Contact Shadows(SSCS) Plugin </a></li> | |||
| </ul> | |||
| @@ -0,0 +1,37 @@ | |||
| <!DOCTYPE html> | |||
| <html lang="en"> | |||
| <head> | |||
| <meta charset="UTF-8"> | |||
| <title>SSReflection Plugin</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/webgi-plugins": "https://unpkg.com/@threepipe/webgi-plugins@0.3.0/dist/index.mjs", | |||
| "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> | |||
| @@ -0,0 +1,68 @@ | |||
| import { | |||
| _testFinish, | |||
| BaseGroundPlugin, | |||
| GBufferPlugin, | |||
| IObject3D, | |||
| LoadingScreenPlugin, | |||
| PickingPlugin, RenderTargetPreviewPlugin, | |||
| SSAAPlugin, | |||
| ThreeViewer, | |||
| } from 'threepipe' | |||
| import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' | |||
| import { | |||
| BloomPlugin, | |||
| OutlinePlugin, | |||
| SSReflectionPlugin, | |||
| TemporalAAPlugin, | |||
| VelocityBufferPlugin, | |||
| // @ts-expect-error todo fix | |||
| } from '@threepipe/webgi-plugins' | |||
| async function init() { | |||
| const viewer = new ThreeViewer({ | |||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||
| msaa: true, | |||
| rgbm: true, | |||
| dropzone: { | |||
| addOptions: { | |||
| disposeSceneObjects: true, | |||
| }, | |||
| }, | |||
| plugins: [LoadingScreenPlugin, GBufferPlugin, BloomPlugin, SSAAPlugin, TemporalAAPlugin, new VelocityBufferPlugin(undefined, false)], | |||
| }) | |||
| viewer.renderManager.stableNoise = true | |||
| const inline = true | |||
| const ssrefl = viewer.addPluginSync(new SSReflectionPlugin(inline)) | |||
| const ground = viewer.addPluginSync(new BaseGroundPlugin()) | |||
| ground.material!.roughness = 0.2 | |||
| viewer.addPluginSync(PickingPlugin) | |||
| console.log(ssrefl) | |||
| const outline = viewer.addPluginSync(OutlinePlugin) | |||
| outline.enableHighlight = true | |||
| const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true)) | |||
| await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr', { | |||
| setBackground: true, | |||
| }) | |||
| await viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf', { | |||
| autoCenter: true, | |||
| autoScale: true, | |||
| }) | |||
| ui.setupPluginUi(outline) | |||
| ui.setupPluginUi(BaseGroundPlugin) | |||
| ui.setupPluginUi(PickingPlugin) | |||
| ui.setupPluginUi(BloomPlugin) | |||
| ui.setupPluginUi(TemporalAAPlugin) | |||
| ui.setupPluginUi(VelocityBufferPlugin) | |||
| const targetPreview = viewer.addPluginSync(RenderTargetPreviewPlugin) | |||
| targetPreview.addTarget(()=>outline.target, 'outline', false, true, true, (s)=>`${s} = 1.-${s};`) | |||
| } | |||
| init().then(_testFinish) | |||
| @@ -0,0 +1,37 @@ | |||
| <!DOCTYPE html> | |||
| <html lang="en"> | |||
| <head> | |||
| <meta charset="UTF-8"> | |||
| <title>SSReflection Plugin</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/webgi-plugins": "https://unpkg.com/@threepipe/webgi-plugins@0.3.0/dist/index.mjs", | |||
| "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> | |||
| @@ -0,0 +1,146 @@ | |||
| import { | |||
| _testFinish, | |||
| BaseGroundPlugin, DirectionalLight2, | |||
| GBufferPlugin, | |||
| IObject3D, LoadingScreenPlugin, PhysicalMaterial, | |||
| PickingPlugin, | |||
| RenderTargetPreviewPlugin, SSAAPlugin, | |||
| ThreeViewer, Object3DWidgetsPlugin, TransformControlsPlugin, AssetExporterPlugin, OrbitControls3, | |||
| } from 'threepipe' | |||
| import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' | |||
| // @ts-expect-error todo fix | |||
| import {BloomPlugin, SSReflectionPlugin, TemporalAAPlugin, VelocityBufferPlugin, SSGIPlugin} from '@threepipe/webgi-plugins' | |||
| async function init() { | |||
| const viewer = new ThreeViewer({ | |||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||
| msaa: true, | |||
| rgbm: true, | |||
| zPrepass: false, | |||
| renderScale: 'auto', | |||
| maxRenderScale: 1.5, | |||
| dropzone: { | |||
| addOptions: { | |||
| disposeSceneObjects: true, | |||
| }, | |||
| }, | |||
| plugins: [LoadingScreenPlugin, GBufferPlugin, BloomPlugin, SSAAPlugin, TemporalAAPlugin, Object3DWidgetsPlugin, TransformControlsPlugin, AssetExporterPlugin, new VelocityBufferPlugin(undefined, false), SSReflectionPlugin], | |||
| // rgbm: false, | |||
| }) | |||
| viewer.renderManager.stableNoise = true | |||
| viewer.getPlugin(SSReflectionPlugin)!.enabled = false | |||
| const ssgi = viewer.addPluginSync(new SSGIPlugin()) | |||
| viewer.addPluginSync(new BaseGroundPlugin()) | |||
| const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true)) | |||
| await viewer.setEnvironmentMap('https://hdrihaven.r2cache.com/hdr/1k/empty_warehouse_01_1k.hdr', { | |||
| setBackground: true, | |||
| }) | |||
| await viewer.load<IObject3D>('https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/Sponza/glTF/Sponza.gltf', { | |||
| autoCenter: false, | |||
| autoScale: true, | |||
| autoScaleRadius: 30, | |||
| }) | |||
| viewer.scene.modelRoot.traverse((o) => { | |||
| if (o.material) { | |||
| const mat = o.material as PhysicalMaterial | |||
| mat.emissiveIntensity *= 10 | |||
| } | |||
| }) | |||
| viewer.scene.envMapIntensity = 0.0 | |||
| ui.setupPluginUi(ssgi) | |||
| ui.setupPluginUi(SSReflectionPlugin) | |||
| ui.setupPluginUi(BaseGroundPlugin) | |||
| ui.setupPluginUi(PickingPlugin) | |||
| ui.setupPluginUi(BloomPlugin) | |||
| ui.setupPluginUi(TemporalAAPlugin) | |||
| ui.setupPluginUi(VelocityBufferPlugin) | |||
| ui.setupPluginUi(AssetExporterPlugin) | |||
| const targetPreview = await viewer.addPlugin(RenderTargetPreviewPlugin) | |||
| targetPreview.addTarget(() => ssgi.target, 'ssgi') | |||
| // const gb = viewer.getPlugin(GBufferPlugin) | |||
| // targetPreview.addTarget(() => gb?.target, 'depth') | |||
| const camera = viewer.scene.mainCamera | |||
| camera.position.set(-1, 5, -0.7) | |||
| camera.target.set(-4, 4, -0.7) | |||
| const controls = camera.controls as OrbitControls3 | |||
| controls.minDistance = 2 | |||
| controls.maxDistance = 3 | |||
| controls.autoPushTarget = true | |||
| controls.autoPullTarget = true | |||
| const light = new DirectionalLight2() | |||
| viewer.scene.addObject(light) | |||
| light.position.set(0, 20, 0) | |||
| light.lookAt(-25, 0, 0) | |||
| light.intensity = 30 | |||
| light.castShadow = true | |||
| light.shadow.camera.left = -25 | |||
| light.shadow.camera.right = 25 | |||
| light.shadow.camera.top = 25 | |||
| light.shadow.camera.bottom = -25 | |||
| light.shadow.mapSize.set(1024, 1024) | |||
| // todo add to DirectionalLight | |||
| light.uiConfig.children!.push({ | |||
| type: 'vec2', | |||
| label: 'Shadow Map Size', | |||
| property: [light?.shadow, 'mapSize'], | |||
| onChange: ()=>{ | |||
| light.shadow.map?.dispose() | |||
| light.shadow.mapPass?.dispose() | |||
| light.shadow.map = null as any | |||
| light.shadow.mapPass = null as any | |||
| }, | |||
| }, | |||
| { | |||
| type: 'slider', | |||
| bounds: [-0.001, 0.001], | |||
| stepSize: 0.00002, | |||
| label: 'Shadow Bias', | |||
| property: [light?.shadow, 'bias'], | |||
| onChange: (e)=>light.setDirty(e), | |||
| }, | |||
| { | |||
| type: 'slider', | |||
| bounds: [-0.1, 0.1], | |||
| stepSize: 0.005, | |||
| label: 'Shadow Normal Bias', | |||
| property: [light?.shadow, 'normalBias'], | |||
| onChange: (e)=>light.setDirty(e), | |||
| }, | |||
| { | |||
| type: 'slider', | |||
| bounds: [0, 5], | |||
| label: 'Shadow radius', | |||
| property: [light?.shadow, 'radius'], | |||
| onChange: (e)=>light.setDirty(e), | |||
| }, | |||
| { | |||
| type: 'slider', | |||
| bounds: [0.1, 50], | |||
| label: 'Shadow frustum', | |||
| // property: [light.shadow, 'radius'], | |||
| getValue: ()=>{ | |||
| return light.shadow.camera.right * 2 | |||
| }, | |||
| setValue: (v: number)=>{ | |||
| light.shadow.camera.left = -v / 2 | |||
| light.shadow.camera.right = v / 2 | |||
| light.shadow.camera.top = v / 2 | |||
| light.shadow.camera.bottom = -v / 2 | |||
| }, | |||
| onChange: (e)=>light.setDirty(e), | |||
| }) | |||
| ui.appendChild(light.uiConfig) | |||
| } | |||
| init().then(_testFinish) | |||
| @@ -0,0 +1,37 @@ | |||
| <!DOCTYPE html> | |||
| <html lang="en"> | |||
| <head> | |||
| <meta charset="UTF-8"> | |||
| <title>SSReflection Plugin</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/webgi-plugins": "https://unpkg.com/@threepipe/webgi-plugins@0.3.0/dist/index.mjs", | |||
| "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> | |||
| @@ -0,0 +1,63 @@ | |||
| import { | |||
| _testFinish, | |||
| AssetExporterPlugin, | |||
| GBufferPlugin, | |||
| IObject3D, | |||
| LoadingScreenPlugin, | |||
| Object3DWidgetsPlugin, | |||
| PickingPlugin, | |||
| RenderTargetPreviewPlugin, | |||
| SSAAPlugin, | |||
| ThreeViewer, | |||
| } from 'threepipe' | |||
| import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' | |||
| // @ts-expect-error todo fix | |||
| import {BloomPlugin, SSGIPlugin, SSReflectionPlugin, TemporalAAPlugin, OutlinePlugin} from '@threepipe/webgi-plugins' | |||
| async function init() { | |||
| const viewer = new ThreeViewer({ | |||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||
| msaa: true, | |||
| rgbm: true, | |||
| zPrepass: false, | |||
| renderScale: 'auto', | |||
| maxRenderScale: 1.5, | |||
| dropzone: { | |||
| addOptions: { | |||
| disposeSceneObjects: true, | |||
| }, | |||
| }, | |||
| plugins: [LoadingScreenPlugin, GBufferPlugin, BloomPlugin, PickingPlugin, SSAAPlugin, TemporalAAPlugin, OutlinePlugin, Object3DWidgetsPlugin, AssetExporterPlugin, new SSReflectionPlugin(ssrInline), SSGIPlugin], | |||
| // rgbm: false, | |||
| }) | |||
| viewer.renderManager.stableNoise = true | |||
| viewer.getPlugin(SSReflectionPlugin)!.enabled = false | |||
| const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true)) | |||
| const model = await viewer.load<IObject3D>('https://asset-samples.threepipe.org/demos/sponza-ssgi-ssr.glb') | |||
| viewer.scene.envMapIntensity = 0.0 | |||
| viewer.getPlugin(SSGIPlugin)!.pass.stepCount = 8 | |||
| ui.setupPluginUi(SSGIPlugin) | |||
| ui.setupPluginUi(SSReflectionPlugin) | |||
| model?.traverse((obj) => { | |||
| if (obj.isLight) { | |||
| ui.appendChild(obj.uiConfig) | |||
| } | |||
| }) | |||
| ui.setupPluginUi(PickingPlugin) | |||
| ui.setupPluginUi(BloomPlugin) | |||
| ui.setupPluginUi(TemporalAAPlugin) | |||
| const targetPreview = await viewer.addPlugin(RenderTargetPreviewPlugin) | |||
| targetPreview.addTarget(() => viewer.getPlugin(SSGIPlugin)!.target, 'ssgi') | |||
| !ssrInline && targetPreview.addTarget(() => viewer.getPlugin(SSReflectionPlugin)!.target, 'ssr') | |||
| } | |||
| // todo: inline = false has a bug, not clearing maybe? | |||
| const ssrInline = true | |||
| init().then(_testFinish) | |||
| @@ -11,8 +11,7 @@ | |||
| <script type="importmap"> | |||
| { | |||
| "imports": { | |||
| "@threepipe/webgi-plugins": "https://unpkg.com/@threepipe/webgi-plugins@0.2.0/dist/index.mjs", | |||
| "@threepipe/webgi-plugins": "https://unpkg.com/@threepipe/webgi-plugins@0.3.0/dist/index.mjs", | |||
| "threepipe": "./../../dist/index.mjs", | |||
| "@threepipe/plugin-tweakpane": "./../../plugins/tweakpane/dist/index.mjs" | |||
| } | |||
| @@ -1,14 +1,16 @@ | |||
| import { | |||
| _testFinish, | |||
| BaseGroundPlugin, | |||
| Color, | |||
| GBufferPlugin, | |||
| IObject3D, LoadingScreenPlugin, | |||
| LoadingScreenPlugin, | |||
| PickingPlugin, | |||
| RenderTargetPreviewPlugin, SSAAPlugin, | |||
| RenderTargetPreviewPlugin, | |||
| SSAAPlugin, | |||
| ThreeViewer, | |||
| } from 'threepipe' | |||
| import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' | |||
| // @ts-expect-error todo fix | |||
| // @ts-expect-error todo fix import | |||
| import {BloomPlugin, SSReflectionPlugin, TemporalAAPlugin} from '@threepipe/webgi-plugins' | |||
| async function init() { | |||
| @@ -30,41 +32,30 @@ async function init() { | |||
| const ssrefl = viewer.addPluginSync(new SSReflectionPlugin(inline)) | |||
| const ground = viewer.addPluginSync(BaseGroundPlugin) | |||
| viewer.addPluginSync(PickingPlugin) | |||
| console.log(ssrefl) | |||
| const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true)) | |||
| await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr', { | |||
| setBackground: true, | |||
| }) | |||
| await viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf', { | |||
| autoCenter: true, | |||
| autoScale: true, | |||
| }) | |||
| // const model = result?.getObjectByName('node_damagedHelmet_-6514') | |||
| // const materials = (model?.materials || []) as PhysicalMaterial[] | |||
| const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true)) | |||
| ui.setupPluginUi(ssrefl) | |||
| ui.setupPluginUi(ssrefl, {expanded: true}) | |||
| ui.setupPluginUi(BaseGroundPlugin) | |||
| ui.setupPluginUi(PickingPlugin) | |||
| ui.setupPluginUi(BloomPlugin) | |||
| // for (const material of materials) { | |||
| // ui.appendChild(material.uiConfig) | |||
| // } | |||
| // bloom.pass!.intensity = 3 | |||
| // bloom.pass!.threshold = 1 | |||
| // viewer.scene.background = null | |||
| // bloom.pass!.bloomDebug = true | |||
| ground.material!.roughness = 0.2 | |||
| const targetPreview = await viewer.addPlugin(RenderTargetPreviewPlugin) | |||
| if (!ssrefl.inlineShaderRayTrace) { | |||
| targetPreview.addTarget(() => ssrefl.target, 'ssrefl') | |||
| } | |||
| // const gb = viewer.getPlugin(GBufferPlugin) | |||
| // targetPreview.addTarget(() => gb?.target, 'depth') | |||
| await viewer.load('https://asset-samples.threepipe.org/demos/classic-watch.glb', { | |||
| autoCenter: true, | |||
| autoScale: false, | |||
| }) | |||
| viewer.scene.backgroundColor = new Color(0x1B1B1F) | |||
| ground.tonemapGround = false | |||
| ground.material!.color.set(0x1B1B1F) | |||
| ground.material!.roughness = 0.2 | |||
| ground.material!.userData.separateEnvMapIntensity = true | |||
| ground.material!.envMapIntensity = 0 | |||
| } | |||
| @@ -26,7 +26,7 @@ | |||
| "@threepipe/plugin-network": "./../../plugins/network/dist/index.mjs", | |||
| "@threepipe/plugin-gltf-transform": "./../../plugins/gltf-transform/dist/index.mjs", | |||
| "@threepipe/plugin-gaussian-splatting": "./../../plugins/gaussian-splatting/dist/index.mjs", | |||
| "@threepipe/webgi-plugins": "https://unpkg.com/@threepipe/webgi-plugins@0.2.1/dist/index.mjs" | |||
| "@threepipe/webgi-plugins": "https://unpkg.com/@threepipe/webgi-plugins@0.3.1/dist/index.mjs" | |||
| } | |||
| } | |||
| @@ -66,7 +66,7 @@ import {MaterialConfiguratorPlugin, SwitchNodePlugin} from '@threepipe/plugin-co | |||
| import {AWSClientPlugin, TransfrSharePlugin} from '@threepipe/plugin-network' | |||
| import {GLTFDracoExportPlugin} from '@threepipe/plugin-gltf-transform' | |||
| // @ts-expect-error todo fix import | |||
| import {BloomPlugin, DepthOfFieldPlugin, SSContactShadowsPlugin, SSReflectionPlugin, TemporalAAPlugin, VelocityBufferPlugin} from '@threepipe/webgi-plugins' | |||
| import {BloomPlugin, DepthOfFieldPlugin, SSContactShadowsPlugin, SSReflectionPlugin, TemporalAAPlugin, VelocityBufferPlugin, OutlinePlugin, SSGIPlugin, AnisotropyPlugin} from '@threepipe/webgi-plugins' | |||
| function checkQuery(key: string, def = true) { | |||
| return !['false', 'no', 'f'].includes(getUrlQueryParam(key, def ? 'yes' : 'no').toLowerCase()) | |||
| @@ -107,8 +107,12 @@ async function init() { | |||
| new SSAAPlugin(), | |||
| GLTFAnimationPlugin, | |||
| TransformAnimationPlugin, | |||
| new GBufferPlugin(HalfFloatType, true, true, true), | |||
| new DepthBufferPlugin(HalfFloatType, false, false), | |||
| new NormalBufferPlugin(HalfFloatType, false), | |||
| PickingPlugin, | |||
| new TransformControlsPlugin(false), | |||
| OutlinePlugin, | |||
| EditorViewWidgetPlugin, | |||
| CameraViewPlugin, | |||
| ViewerUiConfigPlugin, | |||
| @@ -116,13 +120,11 @@ async function init() { | |||
| FragmentClippingExtensionPlugin, | |||
| NoiseBumpMaterialPlugin, | |||
| CustomBumpMapPlugin, | |||
| AnisotropyPlugin, | |||
| new ParallaxMappingPlugin(false), | |||
| GLTFKHRMaterialVariantsPlugin, | |||
| VirtualCamerasPlugin, | |||
| // new SceneUiConfigPlugin(), // this is already in ViewerUiPlugin | |||
| new GBufferPlugin(HalfFloatType, true, true, true), | |||
| new DepthBufferPlugin(HalfFloatType, false, false), | |||
| new NormalBufferPlugin(HalfFloatType, false), | |||
| new RenderTargetPreviewPlugin(false), | |||
| new FrameFadePlugin(), | |||
| new HDRiGroundPlugin(false, true), | |||
| @@ -136,6 +138,7 @@ async function init() { | |||
| BloomPlugin, | |||
| TemporalAAPlugin, | |||
| new VelocityBufferPlugin(UnsignedByteType, false), | |||
| new SSGIPlugin(UnsignedByteType, 1, false), | |||
| KTX2LoadPlugin, | |||
| KTXLoadPlugin, | |||
| PLYLoadPlugin, | |||
| @@ -186,13 +189,13 @@ async function init() { | |||
| editor.loadPlugins({ | |||
| ['Viewer']: [ViewerUiConfigPlugin, DropzonePlugin, FullScreenPlugin, TweakpaneUiPlugin, LoadingScreenPlugin, InteractionPromptPlugin], | |||
| ['Scene']: [SSAAPlugin, BaseGroundPlugin, SceneUiConfigPlugin, ContactShadowGroundPlugin], | |||
| ['Interaction']: [HierarchyUiPlugin, TransformControlsPlugin, PickingPlugin, Object3DGeneratorPlugin, GeometryGeneratorPlugin, EditorViewWidgetPlugin, Object3DWidgetsPlugin, MeshOptSimplifyModifierPlugin], | |||
| ['Interaction']: [HierarchyUiPlugin, TransformControlsPlugin, PickingPlugin, OutlinePlugin, Object3DGeneratorPlugin, GeometryGeneratorPlugin, EditorViewWidgetPlugin, Object3DWidgetsPlugin, MeshOptSimplifyModifierPlugin], | |||
| ['GBuffer']: [GBufferPlugin, DepthBufferPlugin, NormalBufferPlugin], | |||
| ['Post-processing']: [TonemapPlugin, ProgressivePlugin, SSAOPlugin, SSReflectionPlugin, BloomPlugin, DepthOfFieldPlugin, FrameFadePlugin, VignettePlugin, ChromaticAberrationPlugin, FilmicGrainPlugin, TemporalAAPlugin, VelocityBufferPlugin, SSContactShadowsPlugin], | |||
| ['Post-processing']: [TonemapPlugin, ProgressivePlugin, SSAOPlugin, SSReflectionPlugin, BloomPlugin, DepthOfFieldPlugin, SSGIPlugin, FrameFadePlugin, VignettePlugin, ChromaticAberrationPlugin, FilmicGrainPlugin, TemporalAAPlugin, VelocityBufferPlugin, SSContactShadowsPlugin], | |||
| ['Export']: [AssetExporterPlugin, CanvasSnapshotPlugin, AWSClientPlugin, TransfrSharePlugin], | |||
| ['Configurator']: [MaterialConfiguratorPlugin, SwitchNodePlugin, GLTFKHRMaterialVariantsPlugin], | |||
| ['Animation']: [GLTFAnimationPlugin, CameraViewPlugin], | |||
| ['Extras']: [HDRiGroundPlugin, Rhino3dmLoadPlugin, ClearcoatTintPlugin, FragmentClippingExtensionPlugin, NoiseBumpMaterialPlugin, CustomBumpMapPlugin, VirtualCamerasPlugin], | |||
| ['Extras']: [HDRiGroundPlugin, Rhino3dmLoadPlugin, ClearcoatTintPlugin, FragmentClippingExtensionPlugin, NoiseBumpMaterialPlugin, AnisotropyPlugin, CustomBumpMapPlugin, VirtualCamerasPlugin], | |||
| ['Debug']: [RenderTargetPreviewPlugin], | |||
| }) | |||
| @@ -1,12 +1,12 @@ | |||
| { | |||
| "name": "threepipe", | |||
| "version": "0.0.36", | |||
| "version": "0.0.37", | |||
| "lockfileVersion": 3, | |||
| "requires": true, | |||
| "packages": { | |||
| "": { | |||
| "name": "threepipe", | |||
| "version": "0.0.36", | |||
| "version": "0.0.37", | |||
| "license": "Apache-2.0", | |||
| "dependencies": { | |||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.153.1002/package.tgz", | |||
| @@ -57,6 +57,48 @@ | |||
| } | |||
| } | |||
| }, | |||
| "../threepipe-webgi": { | |||
| "name": "@threepipe/webgi-plugins", | |||
| "version": "0.3.1", | |||
| "extraneous": true, | |||
| "license": "GPL-3.0-only", | |||
| "dependencies": { | |||
| "@threepipe/plugin-tweakpane": "^0.5.1", | |||
| "threepipe": "^0.0.36" | |||
| }, | |||
| "devDependencies": { | |||
| "@rollup/plugin-json": "^6.0.0", | |||
| "@rollup/plugin-replace": "^5.0.2", | |||
| "@typescript-eslint/eslint-plugin": "^5.59.7", | |||
| "@typescript-eslint/parser": "^5.59.5", | |||
| "clean-package": "^2.2.0", | |||
| "copyfiles": "^2.4.1", | |||
| "eslint": "^8.40.0", | |||
| "eslint-import-resolver-typescript": "^3.5.5", | |||
| "eslint-plugin-deprecation": "^1.4.1", | |||
| "eslint-plugin-html": "^7.1.0", | |||
| "eslint-plugin-import": "^2.27.5", | |||
| "popmotion": "^11.0.5", | |||
| "rimraf": "^5.0.1", | |||
| "rollup-plugin-glsl": "^1.3.0", | |||
| "rollup-plugin-license": "^3.0.1", | |||
| "rollup-plugin-postcss": "^4.0.2", | |||
| "terser": "^5.31.6", | |||
| "ts-browser-helpers": "^0.16.2", | |||
| "tslib": "^2.5.0", | |||
| "typedoc": "^0.27.5", | |||
| "typescript": "^5.7.2", | |||
| "typescript-plugin-css-modules": "^5.0.1", | |||
| "vite": "^6.0.5", | |||
| "vite-plugin-dts": "^4.4.0", | |||
| "vitepress": "^1.5.0", | |||
| "vitepress-plugin-nprogress": "^0.0.4", | |||
| "vitepress-theme-api": "^0.1.7" | |||
| }, | |||
| "optionalDependencies": { | |||
| "win-node-env": "^0.6.1" | |||
| } | |||
| }, | |||
| "node_modules/@75lb/deep-merge": { | |||
| "version": "1.1.2", | |||
| "resolved": "https://registry.npmjs.org/@75lb/deep-merge/-/deep-merge-1.1.2.tgz", | |||
| @@ -1,6 +1,6 @@ | |||
| { | |||
| "name": "threepipe", | |||
| "version": "0.0.36", | |||
| "version": "0.0.37", | |||
| "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", | |||
| "module": "dist/index.mjs", | |||
| @@ -43,8 +43,8 @@ export class Object3DWidgetsPlugin extends AViewerPluginSync<''> { | |||
| onAdded(viewer: ThreeViewer) { | |||
| super.onAdded(viewer) | |||
| viewer.scene.addEventListener('addSceneObject', this._addSceneObject) | |||
| viewer.scene.addObject(this._widgetRoot, {addToRoot: true, autoScale: false, autoCenter: false}) | |||
| viewer.scene.addEventListener('addSceneObject', this._addSceneObject) | |||
| } | |||
| onRemove(viewer: ThreeViewer) { | |||
| viewer.scene.removeEventListener('addSceneObject', this._addSceneObject) | |||
| @@ -7,7 +7,11 @@ | |||
| varying vec2 vUv; | |||
| uniform sampler2D tLastThis; | |||
| #ifndef D_frameCount | |||
| #define D_frameCount | |||
| uniform float frameCount; | |||
| #endif | |||
| uniform vec4 saoData; | |||
| uniform vec3 saoBiasEpsilon; | |||
| @@ -76,6 +76,7 @@ export class RenderTargetPreviewPlugin<TEvent extends string> extends AViewerPlu | |||
| this._viewer.renderManager.blit(null, { | |||
| source: tex, | |||
| clear: !targetBlock.transparent, | |||
| // transparent: targetBlock.transparent, // todo | |||
| respectColorSpace: !targetBlock.originalColorSpace, | |||
| viewport: new Vector4(rect.x, rect.y, rect.width, rect.height), | |||
| material: targetBlock.material, | |||
| @@ -24,6 +24,7 @@ export abstract class AHelperWidget extends Object3D implements IWidget { | |||
| this.matrix = object.matrixWorld | |||
| this.matrixAutoUpdate = false | |||
| this.dispose = this.dispose.bind(this) | |||
| this._objectUpdate = this._objectUpdate.bind(this) | |||
| this.attach(object) | |||
| this.traverse(o => { | |||
| @@ -136,14 +136,19 @@ export interface ThreeViewerOptions { | |||
| */ | |||
| forceZPrepass?: boolean // todo | |||
| /* | |||
| /** | |||
| * Render scale, 1 = full resolution, 0.5 = half resolution, 2 = double resolution. | |||
| * Same as pixelRatio in three.js | |||
| * Can be set to `window.devicePixelRatio` to render at device resolution in browsers. | |||
| * An optimal value is `Math.min(2, window.devicePixelRatio)` to prevent issues on mobile. This is set when 'auto' is passed. | |||
| * Default is 1. | |||
| * @default 1 | |||
| */ | |||
| renderScale?: number | 'auto' | |||
| /** | |||
| * Max render scale when set to 'auto' | |||
| * @default 2 | |||
| */ | |||
| maxRenderScale?: number | |||
| debug?: boolean | |||
| @@ -430,7 +435,7 @@ export class ThreeViewer extends EventDispatcher<IViewerEvent, IViewerEventTypes | |||
| depthBuffer: !(options.zPrepass ?? options.useGBufferDepth ?? false), | |||
| screenShader: options.screenShader, | |||
| renderScale: typeof options.renderScale === 'string' ? options.renderScale === 'auto' ? | |||
| Math.min(2, window.devicePixelRatio) : parseFloat(options.renderScale) : | |||
| Math.min(options.maxRenderScale || 2, window.devicePixelRatio) : parseFloat(options.renderScale) : | |||
| options.renderScale, | |||
| maxHDRIntensity: options.maxHDRIntensity, | |||
| }) | |||
| @@ -1 +1 @@ | |||
| export const VERSION = '0.0.35' | |||
| export const VERSION = '0.0.37' | |||