Bachelorarbeit/packages/modelviewer.dev/examples/postprocessing/index.html

534 lines
26 KiB
HTML

<!--
/*
* Copyright 2020 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<!DOCTYPE html>
<html lang="en">
<head>
<title>&lt;model-viewer&gt; PostProcessing Examples</title>
<meta charset="utf-8">
<meta name="description" content="&lt;model-viewer-effects&gt; post processing examples">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link type="text/css" href="../../styles/examples.css" rel="stylesheet" />
<link type="text/css" href="../../styles/docs.css" rel="stylesheet" />
<link rel="shortcut icon" type="image/png" href="../../assets/favicon.png" />
<!-- ES-Shims for older browsers -->
<script async src="https://ga.jspm.io/npm:es-module-shims@1.7.1/dist/es-module-shims.js"></script>
<!-- Import Three.js using an import-map -->
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@^0.172.0/build/three.module.min.js"
}
}
</script>
<!-- Import the <model-viewer> component without three bundled -->
<script type="module" src="../../../../node_modules/@google/model-viewer/dist/model-viewer-module.js"></script>
<!-- Import the <model-viewer-effects> addon -->
<script type="module"
src="../../../../node_modules/@google/model-viewer-effects/dist/model-viewer-effects.js"></script>
<script defer src="https://web3dsurvey.com/collector.js"></script>
<script>
window.ga = window.ga || function () { (ga.q = ga.q || []).push(arguments) }; ga.l = +new Date;
ga('create', 'UA-169901325-1', { 'storage': 'none' });
ga('set', 'referrer', document.referrer.split('?')[0]);
ga('set', 'anonymizeIp', true);
ga('send', 'pageview');
</script>
<script async src='https://www.google-analytics.com/analytics.js'></script>
<style>
.controls {
position: absolute;
display: flex;
flex-direction: column;
align-items: left;
bottom: 8px;
left: 8px;
}
#texture-name,
#image-name {
font-size: 0.8em;
}
button {
font-size: 1.3em;
margin: 0 0.25em;
}
</style>
</head>
<body>
<div class="examples-page">
<div class="sidebar" id="sidenav"></div>
<div id="toggle"></div>
<div class="examples-container">
<div class="sample">
<div id="setup" class="demo"></div>
<div class="content">
<div class="wrapper">
<div class="heading">
<h2 class="demo-title">Setup Post Processing</h2>
<p>The <code>&lt;model-viewer-effects&gt;</code> library addon for <code>&lt;model-viewer&gt;</code>
provides
you with a easy-to-use postprocessing workflow for spicing up your models. <br />The list of currently
support effects is: SMAA, FXAA, Pixelate, Outline, Glitch, SSAO, Bloom (Global/Selective), and Color
Grade.<br /><br />
In order to avoid package collisions, you will be required to add an
<a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap"
target='_blank'>import-map</a>
for the <a href="https://threejs.org/" target='_blank'>Three.js</a> package, and use the <i>module</i>
version of <code>&lt;model-viewer&gt;</code>.
</p>
<p>Safari does not support <code>import maps</code>, the following script will make your code work
universally: </p>
<example-snippet stamp-to="setup" highlight-as="html">
<template>
<script type="noexecute" async
src="https://ga.jspm.io/npm:es-module-shims@1.7.1/dist/es-module-shims.js"></script>
</template>
</example-snippet>
<p>Bring <code>Three.js</code> from any cdn - cdnjs, unpkg, or jsdelivr:</p>
<example-snippet stamp-to="setup" highlight-as="html">
<template>
<script type="importmap-noexecute">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@^0.172.0/build/three.module.min.js"
}
}
</script>
</template>
</example-snippet stamp-to="setup" highlight-as="html">
<p>Now import the <code>&lt;model-viewer&gt;</code> module version which doesn't package three, and the
<code>&lt;model-viewer-effects&gt;</code> addon:</p>
<example-snippet stamp-to="setup" highlight-as="html">
<template>
<script type="module-noexecute"
src="https://cdn.jsdelivr.net/npm/@google/model-viewer/dist/model-viewer-module.min.js"></script>
<script type="module-noexecute"
src="https://cdn.jsdelivr.net/npm/@google/model-viewer-effects/dist/model-viewer-effects.min.js"></script>
</template>
</example-snippet>
<p>Setting up post-processing effects is as simple as adding an <code>&lt;effect-composer&gt;</code>
component inside your <code>&lt;model-viewer&gt;</code> element.
From here, simply add any of the supported effects inside the
<code>&lt;effect-composer&gt;</code>.<br>See the
<a href="../../docs/mve.html">API Reference</a> for a list of all supported effects.
</p>
</div>
<example-snippet stamp-to="setup" highlight-as="html">
<template>
<!-- Use the <effect-composer> component inside the <model-viewer> element -->
<model-viewer autoplay ar camera-controls touch-action="pan-y"
src="../../shared-assets/models/Horse.glb" scale="0.01 0.01 0.01"
alt="A 3D model of a horse galloping.">
<effect-composer>
<pixelate-effect></pixelate-effect>
</effect-composer>
</model-viewer>
</template>
</example-snippet>
</div>
</div>
</div>
<div class="sample">
<div id="effects" class="demo"></div>
<div class="content">
<div class="wrapper">
<div class="heading">
<h2 class="demo-title">The Effects API</h2>
<a href="../../docs/mve#effectcomposer">
<h3>Effect Composer</h3>
</a>
<p>The <code>&lt;effect-composer&gt;</code> component has two main properties: <code>render-mode</code>
and <code>msaa</code>.<br><br>
The default value for <code>renderMode</code> is <code>'performance'</code>. By switching to
<code>'quality'</code>, the <code>&lt;effect-composer&gt;</code>
will use high-precision linear buffers for rendering, allowing for HDR-like workflows, at a performance
cost. <code>renderMode</code> can only be set once,
before the Effect Composer instantiates. Updating it after that is not possible.<br>
<i>Note: the default 'performance' <code>renderMode</code> is prone to banding in dark scenes, which is
especially noticeable with
<code>&lt;bloom-effect&gt;</code>.</i><br><br>
<code>msaa</code> uses a performant algorithm for anti-aliasing on WebGL2 enabled browsers. Set this to
a factor of 2 to enable - it is disabled by default.<br>
<i>Note: <code>msaa</code> may introduce visual artifacts when used with depth-based effects such as
<code>&lt;ssao-effect&gt;</code>, in which case
it would be preferred to use the <code>&lt;smaa-effect&gt;</code>.</i>
</p><br>
<a href="../../docs/mve#bloom">
<h3>Effects</h3>
</a>
<p>All Effects are reactive components, so all properties can be changed during runtime.
This example demonstrates the <a href='../../docs/mve#blendmodemixin'><code>BlendMode API</code></a>,
which allows you to blend effects like you would
layers in Photoshop. We use a <a
href="../../docs/mve#colorgrade"><code>&lt;color-grade-effect&gt;</code></a>, which allows you to
alter the look of your model.
</p>
</div>
<example-snippet stamp-to="effects" highlight-as="html">
<template>
<model-viewer id="blendViewer" camera-controls touch-action="pan-y" ar
src="../../shared-assets/models/Astronaut.glb" alt="A 3D model of an astronaut">
<effect-composer render-mode="quality" msaa="8">
<color-grade-effect contrast="0.5" saturation="-1" opacity="1"
blend-mode="default"></color-grade-effect>
</effect-composer>
<div class="controls glass">
<label for="opacity">Opacity</label>
<input id="opacity" type="range" min="0" max="1" step="0.01" value="1">
<label for="blend-mode">Blend Mode:</label>
<select id="blend-mode">
<option value="default">Default</option>
<option value="skip">Skip</option>
<option value="add">Add</option>
<option value="subtract">Subtract</option>
<option value="divide">Divide</option>
<option value="negation">Negation</option>
</select>
</div>
</model-viewer>
<script type="module">
const blendViewer = document.querySelector("model-viewer#blendViewer");
const blendEffect = blendViewer.querySelector('color-grade-effect');
const opacity = blendViewer.querySelector('#opacity');
const mode = blendViewer.querySelector('#blend-mode');
opacity.addEventListener('input', (e) => blendEffect.opacity = e.target.value);
mode.addEventListener('change', (e) => blendEffect.blendMode = e.target.value);
</script>
</template>
</example-snippet>
</div>
</div>
</div>
<div class="sample">
<div id="colorgrade" class="demo"></div>
<div class="content">
<div class="wrapper">
<div class="heading">
<h2 class="demo-title">Color Grading</h2>
<p>The default <code>tonemapping</code> provided by <code>&lt;model-viewer&gt;</code> is
<code>Aces Filmic</code> tonemapping,
which provides the most pleasing image, similar to Filament's gltf-viewer. However the this tonemapping
is not applied to
<code>&lt;model-viewer-effects&gt;</code> postprocessing. To overcome this, it is recommended to always
add the <code>&lt;color-grade-effect&gt;</code>
at the end of your postprocess pipeline, which similarly sets the default tonemapping to
<code>Aces Filmic</code>.<br>
The example below showcases the rendering difference with and without the
<code>&lt;color-grade-effect&gt;</code> when &lt;bloom-effect&gt; is applied, as well as
allows you to select any of the other tonemapping modes.
</p>
</div>
<example-snippet stamp-to="colorgrade" highlight-as="html">
<template>
<model-viewer id="colorViewer" camera-controls touch-action="pan-y" ar
src="../../shared-assets/models/EmissiveStrengthTest.glb" scale="0.1 0.1 0.1"
alt="A 3D model of an astronaut">
<effect-composer render-mode="quality" msaa="8">
<bloom-effect></bloom-effect>
<color-grade-effect></color-grade-effect>
</effect-composer>
<div class="controls glass">
<div>
<input type="checkbox" id="colorgrading" checked>
<label for="colorgrading">Color Grading</label>
</div>
<label for="tonemapping">Tonemapping:</label>
<select id="tonemapping">
<option value="aces_filmic">Aces Filmic</option>
<option value="reinhard">Reinhard</option>
<option value="reinhard2">Reinhard2</option>
<option value="reinhard2_adaptive">Reinhard2 Adaptive</option>
<option value="optimized_cineon">Optimized Cineon</option>
</select>
</div>
</model-viewer>
<script type="module">
const colorViewer = document.querySelector("model-viewer#colorViewer");
const colorGradeEffect = colorViewer.querySelector('color-grade-effect');
const colorGrading = colorViewer.querySelector('#colorgrading');
const tonemapping = colorViewer.querySelector('#tonemapping');
colorGrading.addEventListener('change', (e) => colorGradeEffect.blendMode = e.target.checked ? 'default' : 'skip');
tonemapping.addEventListener('input', (e) => colorGradeEffect.tonemapping = e.target.value);
</script>
</template>
</example-snippet>
</div>
</div>
</div>
<div class="sample">
<div id="selective-effects" class="demo"></div>
<div class="content">
<div class="wrapper">
<div class="heading">
<h2 class="demo-title">Selective Effects</h2>
<p>Some of the implemented effects are selective and may be applied to only certain meshes in your model.
Currently, this is exclusive to <a
href="../../docs/mve#selectivebloom"><code>&lt;selective-bloom-effect&gt;</code></a>
and <a href="../../docs/mve#outline"><code>&lt;outline-effect&gt;</code></a>. The default behavior for
selective
effects is to use the default <code>selection</code> provided by the
<code>&lt;effect-composer&gt;</code>, which contains a set of
all meshes in the model.<br />
By providing an array of mesh names to the <code>selection</code> attribute, you may enable the effects
only for those meshes.<br />
This example demonstrates the application of the <code>&lt;selective-bloom-effect&gt;</code> exclusively
to Meshes with an emissive material:</p>
</div>
<example-snippet stamp-to="selective-effects" highlight-as="html">
<template>
<model-viewer camera-orbit="45deg 115deg auto" camera-controls touch-action="pan-y" autoplay
src="../../shared-assets/models/RocketShip.glb" ar alt="A 3D model of a Rocket Ship">
<effect-composer id="selectiveComposer" render-mode="quality">
<selective-bloom-effect strength="5" radius="0.7" threshold="0"></selective-bloom-effect>
<color-grade-effect></color-grade-effect>
</effect-composer>
</model-viewer>
<script type="module">
const selectiveComposer = document.querySelector("effect-composer#selectiveComposer");
const selectiveBloom = selectiveComposer.querySelector("selective-bloom-effect");
selectiveComposer.addEventListener('updated-selection', () => {
const selection = [];
selectiveComposer.selection.forEach((obj) =>
(obj.material.emissive.r > 0
|| obj.material.emissive.g > 0
|| obj.material.emissive.b > 0) &&
selection.push(obj)
);
selectiveBloom.selection = selection;
});
</script>
</template>
</example-snippet>
</div>
</div>
</div>
<div class="sample">
<div id="combining-effects" class="demo"></div>
<div class="content">
<div class="wrapper">
<div class="heading">
<h2 class="demo-title">Combining Effects</h2>
<p>&lt;model-viewer-effects&gt;</code> will attempt to join as many of your effects as possible into a
single
<code>EffectPass</code>, which has a significant performance benefit as opposed to keeping all the
effects
in separates Passes. Effects can be disabled by setting the <code>blend-mode</code> to
<code>skip</code>.
<br>
It is recommended to follow the official <a
href="https://github.com/pmndrs/postprocessing/wiki/Effect-Merging#effect-execution-order"
target='_blank'>Postprocessing Wiki</a>
for best practices in combining effects. The <code>&lt;model-viewer-effects&gt;</code> handles effect
compatibility issues by
placing incompatible effects in a separate Pass.
</p>
</div>
<example-snippet stamp-to="combining-effects" highlight-as="html">
<template>
<model-viewer id="effectsViewer" camera-controls scale="0.1 0.1 0.1" touch-action="pan-y"
src="../../shared-assets/models/EmissiveStrengthTest.glb" ar alt="A 3D ">
<effect-composer render-mode="quality">
<outline-effect color="blue" blend-mode="skip"></outline-effect>
<ssao-effect blend-mode="skip"></ssao-effect>
<glitch-effect blend-mode="skip"></glitch-effect>
<smaa-effect blend-mode="skip"></smaa-effect>
<bloom-effect blend-mode="skip"></bloom-effect>
<pixelate-effect granularity="5" blend-mode="skip"></pixelate-effect>
<color-grade-effect blend-mode="default"></color-grade-effect>
</effect-composer>
<div class="controls glass">
<div>
<input type="checkbox" id="outline">
<label for="outline">Outline Effect</label>
</div>
<div>
<input type="checkbox" id="ssao">
<label for="ssao">SSAO Effect</label>
</div>
<div>
<input type="checkbox" id="glitch">
<label for="glitch">Glitch Effect</label>
</div>
<div>
<input type="checkbox" id="smaa">
<label for="smaa">SMAA Effect</label>
</div>
<div>
<input type="checkbox" id="bloom">
<label for="bloom">Bloom Effect</label>
</div>
<div>
<input type="checkbox" id="pixelate">
<label for="pixelate">Pixelate Effect</label>
</div>
<div>
<input type="checkbox" id="colorgrade" checked>
<label for="colorgrade">Color Grade Effect</label>
</div>
</div>
</model-viewer>
<script type="module">
const effectsViewer = document.querySelector("model-viewer#effectsViewer");
const effects = effectsViewer.querySelector("effect-composer").children;
const inputs = effectsViewer.querySelectorAll("input");
for (let i = 0; i < effects.length; i++) {
inputs[i].addEventListener('change', (e) => effects[i].blendMode = e.target.checked ? 'default' : 'skip');
}
</script>
</template>
</example-snippet>
</div>
</div>
</div>
<div class="sample">
<div id="custom-effects" class="demo"></div>
<div class="content">
<div class="wrapper">
<div class="heading">
<h2 class="demo-title">Custom Effects</h2>
<p>Using the <a
href="../../docs/mve.html#entrydocs-effectcomposer-methods-addPass"><code>addPass()</code></a> method
on the <code>&lt;effect-composer&gt;</code>, you can add custom
PostProcessing effects that are not provided by the base library. If you would like to implement
your own effects from scratch, refer to the <a
href="https://github.com/pmndrs/postprocessing/wiki/Custom-Effects" target='_blank'>Postprocessing
Wiki</a>.<br /><br />
If your Pass requires the scene or camera instance, they are set automatically. Similarly,
if any of the effects in the pass require a <code>normalBuffer</code> or <code>selection</code>,
you can access them from the <code>&lt;effect-composer&gt;</code>.<br />
If any property of your effect changes, you must call the <a
href="../../docs/mve.html#entrydocs-effectcomposer-methods-queueRender"><code>queueRender()</code></a>
method so that the <code>&lt;effect-composer&gt;</code> knows to re-render with your new
changes.<br /><br />
<i>Note: If your pass uses the normalBuffer, you must specify as such in the <code>addPass</code>
method, as the normals
are disabled by default unless they are used. Similarly, if your pass requires to be re-rendered each
frame,
you must pass the </i><code>requireDirtyRender</code><i> parameter.</i>
</p>
</div>
<example-snippet stamp-to="custom-effects" highlight-as="html">
<template>
<model-viewer camera-controls touch-action="pan-y" autoplay
src="../../shared-assets/models/RobotExpressive.glb" ar alt="A 3D model of a Lantern">
<effect-composer id="customComposer" msaa="8">
</effect-composer>
<div class="controls glass">
<label for="scale">Grid Scale</label>
<input id="scale" type="range" min="0" max="2" step="0.01" value="1">
</div>
</model-viewer>
<script type="module">
import * as PostProcessing from 'https://cdn.jsdelivr.net/npm/postprocessing@6.35.3/build/index.js';
const customComposer = document.querySelector("effect-composer#customComposer");
const grid = new PostProcessing.GridEffect();
const sepia = new PostProcessing.SepiaEffect();
// The camera is set automatically when added to the <effect-composer>
const noisePass = new PostProcessing.EffectPass(undefined, grid, sepia);
customComposer.addPass(noisePass);
customComposer.nextElementSibling.addEventListener('input', (e) => {
grid.scale = e.target.value;
// Request a render frame, to update
customComposer.queueRender();
});
</script>
</template>
</example-snippet>
</div>
</div>
</div>
<div class="footer">
<ul>
<li class="attribution">
<a href="https://github.com/dataarts/3-dreams-of-black/tree/master/deploy/files/models/soup">Horse</a> by <a
href="https://github.com/dataarts">Google Data Arts Team</a>,
licensed under <a
href="https://github.com/dataarts/3-dreams-of-black/blob/master/deploy/files/models/soup/LICENSE.txt">Creative
Commons Attribution-NonCommercial-ShareAlike</a>.
</li>
<li class="attribution">
<a href="https://poly.google.com/view/dLHpzNdygsg">Astronaut</a> by <a
href="https://poly.google.com/user/4aEd8rQgKu2">Poly</a>,
licensed under <a href="https://creativecommons.org/licenses/by/2.0/">CC-BY</a>.
</li>
<li class="attribution">
<a href="https://poly.pizza/m/9dyJn4gp7U8">Rocket Ship</a> by <a
href="https://poly.google.com/user/4aEd8rQgKu2">Daniel Melchior</a>,
licensed under <a href="https://creativecommons.org/licenses/by/3.0/">CC-BY</a>.
</li>
<li class="attribution">
<a
href="https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/EmissiveStrengthTest">EmissiveStrengthTest</a>
by <a href="https://github.com/emackey">Ed Mackey</a>,
licensed under <a href="https://creativecommons.org/licenses/by/4.0/">CC-BY</a>.
</li>
<li class="attribution">
<a
href="https://github.com/mrdoob/three.js/tree/dev/examples/models/gltf/RobotExpressive">RobotExpressive</a>
by <a href="https://www.patreon.com/quaternius">Tomás Laulhé</a>,
licensed under <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>.
</li>
</ul>
<div style="margin-top:24px;" class="copyright">©Copyright 2025 Google Inc. Licensed under the Apache License
2.0.</div>
<div id='footer-links'></div>
</div>
</div>
</div>
<script type="module" src="../../examples/built/docs-and-examples.js">
</script>
<script type="module">
(() => { init('examples-postprocessing'); })();
(() => { initFooterLinks(); })();
</script>
<!-- Documentation-specific dependencies: -->
<script type="module" src="../built/dependencies.js">
</script>
</body>
</html>