534 lines
26 KiB
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><model-viewer> PostProcessing Examples</title>
|
|
<meta charset="utf-8">
|
|
<meta name="description" content="<model-viewer-effects> 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><model-viewer-effects></code> library addon for <code><model-viewer></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><model-viewer></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><model-viewer></code> module version which doesn't package three, and the
|
|
<code><model-viewer-effects></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><effect-composer></code>
|
|
component inside your <code><model-viewer></code> element.
|
|
From here, simply add any of the supported effects inside the
|
|
<code><effect-composer></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><effect-composer></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><effect-composer></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><bloom-effect></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><ssao-effect></code>, in which case
|
|
it would be preferred to use the <code><smaa-effect></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><color-grade-effect></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><model-viewer></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><model-viewer-effects></code> postprocessing. To overcome this, it is recommended to always
|
|
add the <code><color-grade-effect></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><color-grade-effect></code> when <bloom-effect> 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><selective-bloom-effect></code></a>
|
|
and <a href="../../docs/mve#outline"><code><outline-effect></code></a>. The default behavior for
|
|
selective
|
|
effects is to use the default <code>selection</code> provided by the
|
|
<code><effect-composer></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><selective-bloom-effect></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><model-viewer-effects></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><model-viewer-effects></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><effect-composer></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><effect-composer></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><effect-composer></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> |