| - [RenderTargetPreviewPlugin](#rendertargetpreviewplugin) - Preview any render target in a UI panel over the canvas | - [RenderTargetPreviewPlugin](#rendertargetpreviewplugin) - Preview any render target in a UI panel over the canvas | ||||
| - [GeometryUVPreviewPlugin](#geometryuvpreviewplugin) - Preview UVs of any geometry in a UI panel over the canvas | - [GeometryUVPreviewPlugin](#geometryuvpreviewplugin) - Preview UVs of any geometry in a UI panel over the canvas | ||||
| - [FrameFadePlugin](#framefadeplugin) - Post-render pass to smoothly fade to a new rendered frame over time | - [FrameFadePlugin](#framefadeplugin) - Post-render pass to smoothly fade to a new rendered frame over time | ||||
| - [VignettePlugin](#vignetteplugin) - Add Vignette effect by patching the final screen pass | |||||
| - [ChromaticAberrationPlugin](#chromaticaberrationplugin) - Add Chromatic Aberration effect by patching the final screen pass | |||||
| - [FilmicGrainPlugin](#filmicgrainplugin) - Add Filmic Grain effect by patching the final screen pass | |||||
| - [HDRiGroundPlugin](#hdrigroundplugin) - Add support for ground projected hdri/skybox to the webgl background shader. | - [HDRiGroundPlugin](#hdrigroundplugin) - Add support for ground projected hdri/skybox to the webgl background shader. | ||||
| - [Rhino3dmLoadPlugin](#rhino3dmloadplugin) - Add support for loading .3dm files | - [Rhino3dmLoadPlugin](#rhino3dmloadplugin) - Add support for loading .3dm files | ||||
| - [PLYLoadPlugin](#plyloadplugin) - Add support for loading .ply files | - [PLYLoadPlugin](#plyloadplugin) - Add support for loading .ply files | ||||
| // vignettePlugin.color.set('#ff0000'); vignettePlugin.setDirty() // Call setDirty to tell the plugin that color has changed | // vignettePlugin.color.set('#ff0000'); vignettePlugin.setDirty() // Call setDirty to tell the plugin that color has changed | ||||
| ``` | ``` | ||||
| ## ChromaticAberrationPlugin | |||||
| [//]: # (todo: image) | |||||
| Example: https://threepipe.org/examples/#chromatic-aberration-plugin/ | |||||
| Source Code: [src/plugins/postprocessing/ChromaticAberrationPlugin.ts](./src/plugins/postprocessing/ChromaticAberrationPlugin.ts) | |||||
| API Reference: [ChromaticAberrationPlugin](https://threepipe.org/docs/classes/ChromaticAberrationPlugin.html) | |||||
| ChromaticAberrationPlugin adds a post-processing material extension to the ScreenPass in render manager | |||||
| that applies a chromatic-aberration effect to the final render. The parameter `intensity` can be changed to customize the effect. | |||||
| ```typescript | |||||
| import {ThreeViewer, ChromaticAberrationPlugin} from 'threepipe' | |||||
| const viewer = new ThreeViewer({...}) | |||||
| const chromaticAberrationPlugin = viewer.addPluginSync(ChromaticAberrationPlugin) | |||||
| // Change the chromaticAberration color | |||||
| chromaticAberrationPlugin.intensity = 0.5 | |||||
| ``` | |||||
| ## FilmicGrainPlugin | |||||
| [//]: # (todo: image) | |||||
| Example: https://threepipe.org/examples/#filmic-grain-plugin/ | |||||
| Source Code: [src/plugins/postprocessing/FilmicGrainPlugin.ts](./src/plugins/postprocessing/FilmicGrainPlugin.ts) | |||||
| API Reference: [FilmicGrainPlugin](https://threepipe.org/docs/classes/FilmicGrainPlugin.html) | |||||
| FilmicGrainPlugin adds a post-processing material extension to the ScreenPass in render manager | |||||
| that applies a filmic-grain effect to the final render. The parameters `power` and `color` can be changed to customize the effect. | |||||
| ```typescript | |||||
| import {ThreeViewer, FilmicGrainPlugin} from 'threepipe' | |||||
| const viewer = new ThreeViewer({...}) | |||||
| const filmicGrainPlugin = viewer.addPluginSync(FilmicGrainPlugin) | |||||
| // Change the filmicGrain color | |||||
| filmicGrainPlugin.intensity = 10 | |||||
| filmicGrainPlugin.multiply = false | |||||
| ``` | |||||
| ## HDRiGroundPlugin | ## HDRiGroundPlugin | ||||
| [//]: # (todo: image) | [//]: # (todo: image) |
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="UTF-8"> | |||||
| <title>Chromatic Aberration 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": "./../../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, ChromaticAberrationPlugin, IObject3D, ThreeViewer} from 'threepipe' | |||||
| import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' | |||||
| async function init() { | |||||
| const viewer = new ThreeViewer({ | |||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||||
| }) | |||||
| viewer.addPluginSync(ChromaticAberrationPlugin) | |||||
| 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') | |||||
| const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true)) | |||||
| ui.setupPluginUi(ChromaticAberrationPlugin) | |||||
| } | |||||
| init().then(_testFinish) |
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="UTF-8"> | |||||
| <title>Filmic Grain 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": "./../../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, FilmicGrainPlugin, IObject3D, ThreeViewer} from 'threepipe' | |||||
| import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' | |||||
| async function init() { | |||||
| const viewer = new ThreeViewer({ | |||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||||
| }) | |||||
| viewer.addPluginSync(FilmicGrainPlugin) | |||||
| 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') | |||||
| const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true)) | |||||
| ui.setupPluginUi(FilmicGrainPlugin) | |||||
| } | |||||
| init().then(_testFinish) |
| <ul> | <ul> | ||||
| <li><a href="./tonemap-plugin/">Tonemap Plugin </a></li> | <li><a href="./tonemap-plugin/">Tonemap Plugin </a></li> | ||||
| <li><a href="./vignette-plugin/">Vignette Plugin </a></li> | <li><a href="./vignette-plugin/">Vignette Plugin </a></li> | ||||
| <li><a href="./chromatic-aberration-plugin/">Chromatic Aberration Plugin </a></li> | |||||
| <li><a href="./filmic-grain-plugin/">Filmic Grain Plugin </a></li> | |||||
| <li><a href="./frame-fade-plugin/">Frame Fade Plugin </a></li> | <li><a href="./frame-fade-plugin/">Frame Fade Plugin </a></li> | ||||
| </ul> | </ul> | ||||
| <h2 class="category">Rendering</h2> | <h2 class="category">Rendering</h2> |
| import { | import { | ||||
| _testFinish, | _testFinish, | ||||
| CameraViewPlugin, | CameraViewPlugin, | ||||
| ChromaticAberrationPlugin, | |||||
| DepthBufferPlugin, | DepthBufferPlugin, | ||||
| DropzonePlugin, | DropzonePlugin, | ||||
| FilmicGrainPlugin, | |||||
| FrameFadePlugin, | FrameFadePlugin, | ||||
| FullScreenPlugin, | FullScreenPlugin, | ||||
| GLTFAnimationPlugin, | GLTFAnimationPlugin, | ||||
| new NormalBufferPlugin(HalfFloatType, false), | new NormalBufferPlugin(HalfFloatType, false), | ||||
| new RenderTargetPreviewPlugin(false), | new RenderTargetPreviewPlugin(false), | ||||
| new FrameFadePlugin(), | new FrameFadePlugin(), | ||||
| new VignettePlugin(), | |||||
| new HDRiGroundPlugin(false, true), | new HDRiGroundPlugin(false, true), | ||||
| new VignettePlugin(false), | |||||
| new ChromaticAberrationPlugin(false), | |||||
| new FilmicGrainPlugin(false), | |||||
| KTX2LoadPlugin, | KTX2LoadPlugin, | ||||
| KTXLoadPlugin, | KTXLoadPlugin, | ||||
| PLYLoadPlugin, | PLYLoadPlugin, |
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | ||||
| }) | }) | ||||
| // A GBuffer(depth buffer here) is required for the `tonemapBackground` flag in TonemapPlugin to work | |||||
| viewer.addPluginSync(VignettePlugin) | viewer.addPluginSync(VignettePlugin) | ||||
| 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') |
| import {Importer, Rhino3dmLoader2} from '../../assetmanager' | import {Importer, Rhino3dmLoader2} from '../../assetmanager' | ||||
| import {BaseImporterPlugin} from '../base/BaseImporterPlugin' | import {BaseImporterPlugin} from '../base/BaseImporterPlugin' | ||||
| import {IUiConfigContainer, uiFolderContainer, UiObjectConfig, uiToggle} from 'uiconfig.js' | import {IUiConfigContainer, uiFolderContainer, UiObjectConfig, uiToggle} from 'uiconfig.js' | ||||
| import {ThreeViewer} from '../../viewer' | |||||
| /** | /** | ||||
| * Adds support for loading Rhino `.3dm`, `model/vnd.3dm`, `model/3dm` files and data uris. | * Adds support for loading Rhino `.3dm`, `model/vnd.3dm`, `model/3dm` files and data uris. | ||||
| * Same as {@link Rhino3dmLoader2.ImportMaterials} | * Same as {@link Rhino3dmLoader2.ImportMaterials} | ||||
| */ | */ | ||||
| @onChange(Rhino3dmLoadPlugin.prototype._refresh) @uiToggle() | @onChange(Rhino3dmLoadPlugin.prototype._refresh) @uiToggle() | ||||
| importMaterials = Rhino3dmLoader2.ImportMaterials | |||||
| importMaterials = true | |||||
| /** | /** | ||||
| * Force layer materials even if material/color source is not from layer. Only works if {@link importMaterials} is true | * Force layer materials even if material/color source is not from layer. Only works if {@link importMaterials} is true | ||||
| * Same as {@link Rhino3dmLoader2.ForceLayerMaterials} | * Same as {@link Rhino3dmLoader2.ForceLayerMaterials} | ||||
| */ | */ | ||||
| @onChange(Rhino3dmLoadPlugin.prototype._refresh) @uiToggle() | @onChange(Rhino3dmLoadPlugin.prototype._refresh) @uiToggle() | ||||
| forceLayerMaterials = Rhino3dmLoader2.ForceLayerMaterials | |||||
| forceLayerMaterials = false | |||||
| /** | /** | ||||
| * Replace meshes with instanced meshes if they have the same parent, geometry and material | * Replace meshes with instanced meshes if they have the same parent, geometry and material | ||||
| * Same as {@link Rhino3dmLoader2.ReplaceWithInstancedMesh} | * Same as {@link Rhino3dmLoader2.ReplaceWithInstancedMesh} | ||||
| */ | */ | ||||
| @onChange(Rhino3dmLoadPlugin.prototype._refresh) @uiToggle() | @onChange(Rhino3dmLoadPlugin.prototype._refresh) @uiToggle() | ||||
| replaceWithInstancedMesh = Rhino3dmLoader2.ReplaceWithInstancedMesh | |||||
| replaceWithInstancedMesh = false | |||||
| /** | /** | ||||
| * Hide all lines, line segments and points in the file | * Hide all lines, line segments and points in the file | ||||
| * Same as {@link Rhino3dmLoader2.HideLineMesh} | * Same as {@link Rhino3dmLoader2.HideLineMesh} | ||||
| */ | */ | ||||
| @onChange(Rhino3dmLoadPlugin.prototype._refresh) @uiToggle() | @onChange(Rhino3dmLoadPlugin.prototype._refresh) @uiToggle() | ||||
| hideLineMesh = Rhino3dmLoader2.HideLineMesh | |||||
| hideLineMesh = false | |||||
| protected _refresh() { | protected _refresh() { | ||||
| Rhino3dmLoader2.ImportMaterials = this.importMaterials | Rhino3dmLoader2.ImportMaterials = this.importMaterials | ||||
| Rhino3dmLoader2.HideLineMesh = this.hideLineMesh | Rhino3dmLoader2.HideLineMesh = this.hideLineMesh | ||||
| } | } | ||||
| onAdded(viewer: ThreeViewer) { | |||||
| super.onAdded(viewer) | |||||
| this._refresh() | |||||
| } | |||||
| } | } |
| export {AScreenPassExtensionPlugin} from './postprocessing/AScreenPassExtensionPlugin' | export {AScreenPassExtensionPlugin} from './postprocessing/AScreenPassExtensionPlugin' | ||||
| export {TonemapPlugin} from './postprocessing/TonemapPlugin' | export {TonemapPlugin} from './postprocessing/TonemapPlugin' | ||||
| export {VignettePlugin} from './postprocessing/VignettePlugin' | export {VignettePlugin} from './postprocessing/VignettePlugin' | ||||
| export {ChromaticAberrationPlugin} from './postprocessing/ChromaticAberrationPlugin' | |||||
| export {FilmicGrainPlugin} from './postprocessing/FilmicGrainPlugin' | |||||
| // animation | // animation | ||||
| export {GLTFAnimationPlugin} from './animation/GLTFAnimationPlugin' | export {GLTFAnimationPlugin} from './animation/GLTFAnimationPlugin' |
| import {uiFolderContainer, uiSlider, uiToggle} from 'uiconfig.js' | |||||
| import {glsl, onChange, serialize} from 'ts-browser-helpers' | |||||
| import {uniform} from '../../three' | |||||
| import ChromaticAberration from './shaders/ChromaticAberrationPlugin.glsl' | |||||
| import {AScreenPassExtensionPlugin} from './AScreenPassExtensionPlugin' | |||||
| /** | |||||
| * Chromatic Aberration Plugin | |||||
| * Adds an extension to {@link ScreenPass} material | |||||
| * for applying chromatic aberration effect on the final buffer before rendering to screen. | |||||
| * The intensity of the aberration can be controlled with the `intensity`(previously aberrationIntensity) property. | |||||
| * | |||||
| * @category Plugins | |||||
| */ | |||||
| @uiFolderContainer('ChromaticAberration') | |||||
| export class ChromaticAberrationPlugin extends AScreenPassExtensionPlugin<''> { | |||||
| static readonly PluginType = 'ChromaticAberration' | |||||
| readonly extraUniforms = { | |||||
| aberrationIntensity: {value: 1}, | |||||
| } as const | |||||
| @onChange(ChromaticAberrationPlugin.prototype.setDirty) | |||||
| @uiToggle('Enable') | |||||
| @serialize() enabled: boolean | |||||
| @uiSlider('Intensity', [0., 0.3], 0.001) | |||||
| @uniform({propKey: 'aberrationIntensity'}) | |||||
| @serialize('aberrationIntensity') intensity = 0.5 | |||||
| /** | |||||
| * The priority of the material extension when applied to the material in ScreenPass | |||||
| * set to very low priority, so applied at the end | |||||
| */ | |||||
| priority = -50 | |||||
| parsFragmentSnippet = () => { | |||||
| if (!this.enabled) return '' | |||||
| return glsl` | |||||
| uniform float aberrationIntensity; | |||||
| ${ChromaticAberration} | |||||
| ` | |||||
| } | |||||
| protected _shaderPatch = 'diffuseColor = ChromaticAberration(diffuseColor);' | |||||
| get aberrationIntensity() { | |||||
| console.warn('ChromaticAberrationPlugin.aberrationIntensity is deprecated, use ChromaticAberrationPlugin.intensity instead') | |||||
| return this.intensity | |||||
| } | |||||
| set aberrationIntensity(v) { | |||||
| console.warn('ChromaticAberrationPlugin.aberrationIntensity is deprecated, use ChromaticAberrationPlugin.intensity instead') | |||||
| this.intensity = v | |||||
| } | |||||
| constructor(enabled = true) { | |||||
| super() | |||||
| this.enabled = enabled | |||||
| } | |||||
| } |
| import {uiFolderContainer, uiSlider, uiToggle} from 'uiconfig.js' | |||||
| import {glsl, onChange, serialize} from 'ts-browser-helpers' | |||||
| import {uniform} from '../../three' | |||||
| import FilmicGrain from './shaders/FilmicGrainPlugin.glsl' | |||||
| import {AScreenPassExtensionPlugin} from './AScreenPassExtensionPlugin' | |||||
| /** | |||||
| * Filmic Grain Plugin | |||||
| * Adds an extension to {@link ScreenPass} material | |||||
| * for applying filmic grain effect on the final buffer before rendering to screen. | |||||
| * The intensity of the grain can be controlled with the `intensity` property | |||||
| * and the `multiply` property can be used to multiply the grain effect on the image instead of adding. | |||||
| * | |||||
| * @category Plugins | |||||
| */ | |||||
| @uiFolderContainer('FilmicGrain') | |||||
| export class FilmicGrainPlugin extends AScreenPassExtensionPlugin<''> { | |||||
| static readonly PluginType = 'FilmicGrain' | |||||
| readonly extraUniforms = { | |||||
| grainIntensity: {value: 1}, | |||||
| grainMultiply: {value: false}, | |||||
| } as const | |||||
| @onChange(FilmicGrainPlugin.prototype.setDirty) | |||||
| @uiToggle('Enable') | |||||
| @serialize() enabled: boolean | |||||
| @uiSlider('Intensity', [0., 20], 0.01) | |||||
| @uniform({propKey: 'grainIntensity'}) | |||||
| @serialize('grainIntensity') intensity = 10 | |||||
| @uiToggle('Multiply') | |||||
| @uniform({propKey: 'grainMultiply'}) | |||||
| @serialize('grainMultiply') multiply = false | |||||
| /** | |||||
| * The priority of the material extension when applied to the material in ScreenPass | |||||
| * set to very low priority, so applied at the end | |||||
| */ | |||||
| priority = -50 | |||||
| parsFragmentSnippet = () => { | |||||
| if (!this.enabled) return '' | |||||
| return glsl` | |||||
| uniform float grainIntensity; | |||||
| uniform bool grainMultiply; | |||||
| ${FilmicGrain} | |||||
| ` | |||||
| } | |||||
| protected _shaderPatch = 'diffuseColor = FilmicGrain(diffuseColor);' | |||||
| get grainIntensity() { | |||||
| console.warn('FilmicGrainPlugin.grainIntensity is deprecated, use FilmicGrainPlugin.intensity instead') | |||||
| return this.intensity | |||||
| } | |||||
| set grainIntensity(v) { | |||||
| console.warn('FilmicGrainPlugin.grainIntensity is deprecated, use FilmicGrainPlugin.intensity instead') | |||||
| this.intensity = v | |||||
| } | |||||
| constructor(enabled = true) { | |||||
| super() | |||||
| this.enabled = enabled | |||||
| } | |||||
| } |
| @onChange(VignettePlugin.prototype.setDirty) | @onChange(VignettePlugin.prototype.setDirty) | ||||
| @uiToggle('Enable') | @uiToggle('Enable') | ||||
| @serialize() enabled = false | |||||
| @serialize() enabled: boolean | |||||
| @uiSlider('Power', [0.1, 4], 0.01) | @uiSlider('Power', [0.1, 4], 0.01) | ||||
| @uniform({propKey: 'power'}) | @uniform({propKey: 'power'}) | ||||
| console.warn('VignettePlugin.bgcolor is deprecated, use VignettePlugin.color instead') | console.warn('VignettePlugin.bgcolor is deprecated, use VignettePlugin.color instead') | ||||
| this.color = v | this.color = v | ||||
| } | } | ||||
| constructor(enabled = true) { | |||||
| super() | |||||
| this.enabled = enabled | |||||
| } | |||||
| } | } |
| vec4 ChromaticAberration(in vec4 color) { | |||||
| vec2 distFromCenter = vUv - 0.5; | |||||
| vec2 aberrated = aberrationIntensity * pow(distFromCenter, vec2(2.0)); | |||||
| vec4 outColor = vec4( | |||||
| tDiffuseTexelToLinear (texture2D(tDiffuse, vUv + aberrated)).r, | |||||
| color.g, | |||||
| tDiffuseTexelToLinear (texture2D(tDiffuse, vUv - aberrated)).b, | |||||
| color.a | |||||
| ); | |||||
| return outColor; | |||||
| } |
| // https://www.shadertoy.com/view/4sXSWs | |||||
| vec4 FilmicGrain(in vec4 color) { | |||||
| float x = (vUv.x + 4.0 ) * (vUv.y + 4.0 ) * ( 10.0); | |||||
| vec4 grain = vec4(mod((mod(x, 13.0) + 1.0) * (mod(x, 123.0) + 1.0), 0.01)-0.005) * grainIntensity; | |||||
| return vec4( | |||||
| grainMultiply ? | |||||
| (color.rgb * vec3(1.-grain)) : | |||||
| (color.rgb + vec3(grain)), | |||||
| color.a); | |||||
| } |