1356 lines
61 KiB
HTML
1356 lines
61 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> Materials & Scene Examples</title>
|
|
<meta charset="utf-8">
|
|
<meta name="description" content="<model-viewer> scene graph 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" />
|
|
|
|
<script async src="https://ga.jspm.io/npm:es-module-shims@1.6.3/dist/es-module-shims.js"></script>
|
|
|
|
<script type="importmap-shim">
|
|
{
|
|
"imports": {
|
|
"three": "../../../../node_modules/@google/model-viewer/dist/model-viewer.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;
|
|
bottom: 40px;
|
|
left: 1rem;
|
|
border-radius: 0.5rem;
|
|
padding: 0.5rem 1rem;
|
|
/* max-height: 14rem; */
|
|
overflow: auto;
|
|
}
|
|
|
|
#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="variants" class="demo"></div>
|
|
<div class="content">
|
|
<div class="wrapper">
|
|
<div class="heading">
|
|
<h2 class="demo-title">Swap Model Variants</h2>
|
|
<p>This demonstrates the use of the glTF <a
|
|
href="https://www.khronos.org/blog/streamlining-3d-commerce-with-material-variant-support-in-gltf-assets">materials
|
|
variants extension</a> which allows multiple materials and textures
|
|
to be packed with a single geometry in a GLB. Our API exposes these
|
|
variant names as <code>availableVariants</code> and you can select
|
|
one using the <code>variantName</code> attribute. This is similar
|
|
functionality to the lower-level scene-graph API below, but in that
|
|
case it is up to you to choose the right texture URL, rather than
|
|
having that information stored in the GLB. <i>Note: setting <code>variantName</code>
|
|
to <code>null</code> reverts to the initial material.</i></p>
|
|
</div>
|
|
<example-snippet stamp-to="variants" highlight-as="html">
|
|
<template>
|
|
<model-viewer id="shoe" camera-controls touch-action="pan-y"
|
|
src="../../shared-assets/models/glTF-Sample-Assets/Models/MaterialsVariantsShoe/glTF-Binary/MaterialsVariantsShoe.glb"
|
|
ar alt="A 3D model of a Shoe">
|
|
<div class="controls glass">
|
|
<div>Variant: <select id="variant"></select></div>
|
|
</div>
|
|
</model-viewer>
|
|
<script>
|
|
const modelViewerVariants = document.querySelector("model-viewer#shoe");
|
|
const select = document.querySelector('#variant');
|
|
|
|
modelViewerVariants.addEventListener('load', () => {
|
|
const names = modelViewerVariants.availableVariants;
|
|
for (const name of names) {
|
|
const option = document.createElement('option');
|
|
option.value = name;
|
|
option.textContent = name;
|
|
select.appendChild(option);
|
|
}
|
|
// Adds a default option.
|
|
const option = document.createElement('option');
|
|
option.value = 'default';
|
|
option.textContent = 'Default';
|
|
select.appendChild(option);
|
|
});
|
|
|
|
select.addEventListener('input', (event) => {
|
|
modelViewerVariants.variantName = event.target.value === 'default' ? null : event.target.value;
|
|
});
|
|
</script>
|
|
</template>
|
|
</example-snippet>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sample">
|
|
<div id="transforms" class="demo"></div>
|
|
<div class="content">
|
|
<div class="wrapper">
|
|
<div class="heading">
|
|
<h2 class="demo-title">Model Transformations</h2>
|
|
<p>This demonstrates the <code>orientation</code> and
|
|
<code>scale</code> attributes which allow the model to be
|
|
transformed. Note that if specified before the model loads, they
|
|
will be taken into account by the automatic camera framing. If they
|
|
are changed afterwards the camera will not move, so to get new
|
|
automatic framing the <code>updateFraming()</code> method must be
|
|
called.
|
|
</p>
|
|
<p>Note that these changes can be made in AR as well, but only in
|
|
WebXR mode, as this is the only mode that remains in the browser.
|
|
Changes you made ahead of time will not be reflected in Scene
|
|
Viewer, since this app downloads the original model again from its
|
|
URL. iOS Quick Look will reflect your changes as long as
|
|
<code>ios-src</code> is not specified, since in this case a USDZ
|
|
will be generated on the fly from the current state.
|
|
</p>
|
|
</div>
|
|
<example-snippet stamp-to="transforms" highlight-as="html">
|
|
<template>
|
|
<model-viewer id="transform" orientation="20deg 0 0" shadow-intensity="1" camera-controls
|
|
touch-action="pan-y" ar src="../../shared-assets/models/Astronaut.glb"
|
|
alt="A 3D model of an astronaut">
|
|
<div class="controls glass">
|
|
<div>Roll: <input id="roll" value="20" size="3" class="number"> degrees</div>
|
|
<div>Pitch: <input id="pitch" value="0" size="3" class="number"> degrees</div>
|
|
<div>Yaw: <input id="yaw" value="0" size="3" class="number"> degrees</div>
|
|
<div>
|
|
Scale: X: <input id="x" value="1" size="3" class="number">,
|
|
Y: <input id="y" value="1" size="3" class="number">,
|
|
Z: <input id="z" value="1" size="3" class="number">
|
|
</div>
|
|
<button id="frame">Update Framing</button>
|
|
</div>
|
|
</model-viewer>
|
|
<script>
|
|
const modelViewerTransform = document.querySelector("model-viewer#transform");
|
|
const roll = document.querySelector('#roll');
|
|
const pitch = document.querySelector('#pitch');
|
|
const yaw = document.querySelector('#yaw');
|
|
const x = document.querySelector('#x');
|
|
const y = document.querySelector('#y');
|
|
const z = document.querySelector('#z');
|
|
const frame = document.querySelector('#frame');
|
|
|
|
frame.addEventListener('click', () => {
|
|
modelViewerTransform.updateFraming();
|
|
});
|
|
|
|
const updateOrientation = () => {
|
|
modelViewerTransform.orientation = `${roll.value}deg ${pitch.value}deg ${yaw.value}deg`;
|
|
};
|
|
|
|
const updateScale = () => {
|
|
modelViewerTransform.scale = `${x.value} ${y.value} ${z.value}`;
|
|
};
|
|
|
|
roll.addEventListener('input', () => {
|
|
updateOrientation();
|
|
});
|
|
pitch.addEventListener('input', () => {
|
|
updateOrientation();
|
|
});
|
|
yaw.addEventListener('input', () => {
|
|
updateOrientation();
|
|
});
|
|
x.addEventListener('input', () => {
|
|
updateScale();
|
|
});
|
|
y.addEventListener('input', () => {
|
|
updateScale();
|
|
});
|
|
z.addEventListener('input', () => {
|
|
updateScale();
|
|
});
|
|
</script>
|
|
</template>
|
|
</example-snippet>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sample">
|
|
<div id="changeColor" class="demo"></div>
|
|
<div class="content">
|
|
<div class="wrapper">
|
|
<h4 id="intro"><span class="font-medium">Directly manipulate the scene graph</span></h4>
|
|
<div class="heading">
|
|
<h2 class="demo-title">Change Material Base Color</h2>
|
|
<p>Note that color factors can be set two ways: [r, g, b, a] or a
|
|
CSS-style color string. For array input, the values are between 0
|
|
and 1 and represent a linear color space, identical to the glTF
|
|
spec. For string inputs, the values are internally converted from
|
|
the sRGB color space, so this is likely more user-friendly.</p>
|
|
<p>As above, you can change these values in AR, but only in WebXR
|
|
mode. iOS Quick Look does not reflect these color changes as USDZ
|
|
does not appear to support colors multiplied onto textures.</p>
|
|
</div>
|
|
<example-snippet stamp-to="changeColor" highlight-as="html">
|
|
<template>
|
|
<model-viewer id="color" camera-controls touch-action="pan-y" interaction-prompt="none"
|
|
src="../../shared-assets/models/Astronaut.glb" ar alt="A 3D model of an astronaut">
|
|
<div class="controls glass" id="color-controls">
|
|
<button data-color="#ff0000">Red</button>
|
|
<button data-color="#00ff00">Green</button>
|
|
<button data-color="#0000ff">Blue</button>
|
|
</div>
|
|
</model-viewer>
|
|
<script>
|
|
const modelViewerColor = document.querySelector("model-viewer#color");
|
|
|
|
document.querySelector('#color-controls').addEventListener('click', (event) => {
|
|
const colorString = event.target.dataset.color;
|
|
const [material] = modelViewerColor.model.materials;
|
|
material.pbrMetallicRoughness.setBaseColorFactor(colorString);
|
|
});
|
|
</script>
|
|
</template>
|
|
</example-snippet>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="sample">
|
|
<div id="changeMaterial" class="demo"></div>
|
|
<div class="content">
|
|
<div class="wrapper">
|
|
<div class="heading">
|
|
<h2 class="demo-title">Change Material Metalness and Roughness Factors</h2>
|
|
<p>As above, you can change these values in AR, but only in WebXR
|
|
mode. iOS Quick Look does reflect these property changes since they
|
|
are not also textured.</p>
|
|
</div>
|
|
<example-snippet stamp-to="changeMaterial" highlight-as="html">
|
|
<template>
|
|
<model-viewer id="sphere" camera-controls touch-action="pan-y" interaction-prompt="none"
|
|
src="../../shared-assets/models/reflective-sphere.gltf" ar alt="A 3D model of a sphere">
|
|
<div class="controls glass">
|
|
<div>
|
|
<p>Metalness: <span id="metalness-value"></span></p>
|
|
<input id="metalness" type="range" min="0" max="1" step="0.01" value="1" />
|
|
</div>
|
|
<div>
|
|
<p>Roughness: <span id="roughness-value"></span></p>
|
|
<input id="roughness" type="range" min="0" max="1" step="0.01" value="0" />
|
|
</div>
|
|
</div>
|
|
</model-viewer>
|
|
<script>
|
|
const modelViewerParameters = document.querySelector("model-viewer#sphere");
|
|
|
|
modelViewerParameters.addEventListener("load", (ev) => {
|
|
|
|
let material = modelViewerParameters.model.materials[0];
|
|
|
|
let metalnessDisplay = document.querySelector("#metalness-value");
|
|
let roughnessDisplay = document.querySelector("#roughness-value");
|
|
|
|
metalnessDisplay.textContent = material.pbrMetallicRoughness.metallicFactor;
|
|
roughnessDisplay.textContent = material.pbrMetallicRoughness.roughnessFactor;
|
|
|
|
// Defaults to gold
|
|
material.pbrMetallicRoughness.setBaseColorFactor([0.7294, 0.5333, 0.0392]);
|
|
|
|
document.querySelector('#metalness').addEventListener('input', (event) => {
|
|
material.pbrMetallicRoughness.setMetallicFactor(event.target.value);
|
|
metalnessDisplay.textContent = event.target.value;
|
|
});
|
|
|
|
document.querySelector('#roughness').addEventListener('input', (event) => {
|
|
material.pbrMetallicRoughness.setRoughnessFactor(event.target.value);
|
|
roughnessDisplay.textContent = event.target.value;
|
|
});
|
|
});
|
|
</script>
|
|
</template>
|
|
</example-snippet>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="sample">
|
|
<div id="createTexturesExample" class="demo"></div>
|
|
<div class="content">
|
|
<div class="wrapper">
|
|
<div class="heading">
|
|
<h2 class="demo-title">Create textures</h2>
|
|
<p>As above, you can change these values in AR, but only in WebXR
|
|
mode. iOS Quick Look reflects these texture changes so long as the
|
|
USDZ is auto-generated.</p>
|
|
</div>
|
|
<example-snippet stamp-to="createTexturesExample" highlight-as="html">
|
|
<template>
|
|
<model-viewer id="duck" camera-controls touch-action="pan-y"
|
|
src="../../shared-assets/models/glTF-Sample-Assets/Models/Duck/glTF-Binary/Duck.glb" ar
|
|
alt="A 3D model of a duck">
|
|
<div class="controls glass">
|
|
<p>Normals</p>
|
|
<select id="normals2">
|
|
<option>None</option>
|
|
<option
|
|
value="../../shared-assets/models/glTF-Sample-Assets/Models/DamagedHelmet/glTF/Default_normal.jpg">
|
|
Damaged helmet</option>
|
|
<option
|
|
value="../../shared-assets/models/glTF-Sample-Assets/Models/Lantern/glTF/Lantern_normal.png">
|
|
Lantern Pole</option>
|
|
<option
|
|
value="../../shared-assets/models/glTF-Sample-Assets/Models/WaterBottle/glTF/WaterBottle_normal.png">
|
|
Water Bottle</option>
|
|
</select>
|
|
<p>Custom texture name</p>
|
|
<p id="texture-name">None</p>
|
|
<p>Image name from file name</p>
|
|
<p id="image-name">None</p>
|
|
</div>
|
|
</model-viewer>
|
|
<script type="module">
|
|
const modelViewerTexture = document.querySelector("model-viewer#duck");
|
|
const textureName = document.querySelector('#texture-name');
|
|
const imageName = document.querySelector('#image-name');
|
|
|
|
modelViewerTexture.addEventListener("load", () => {
|
|
|
|
const material = modelViewerTexture.model.materials[0];
|
|
|
|
const createAndApplyTexture = async (channel, event) => {
|
|
if (event.target.value == "None") {
|
|
// Clears the texture.
|
|
material[channel].setTexture(null);
|
|
// Display the names values
|
|
textureName.innerText = "None";
|
|
imageName.innerText = "None";
|
|
} else if (event.target.value) {
|
|
// Creates a new texture.
|
|
const texture = await modelViewerTexture.createTexture(event.target.value);
|
|
// Set the texture name
|
|
texture.name = event.target.options[event.target.selectedIndex].text.replace(/ /g, "_").toLowerCase();
|
|
// Applies the new texture to the specified channel.
|
|
material[channel].setTexture(texture);
|
|
// Display the names values
|
|
textureName.innerText = texture.name;
|
|
imageName.innerText = texture.source.name;
|
|
}
|
|
}
|
|
|
|
document.querySelector('#normals2').addEventListener('input', (event) => {
|
|
createAndApplyTexture('normalTexture', event);
|
|
});
|
|
});
|
|
|
|
</script>
|
|
</template>
|
|
</example-snippet>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="sample">
|
|
<div id="swapTexturesExample" class="demo"></div>
|
|
<div class="content">
|
|
<div class="wrapper">
|
|
<div class="heading">
|
|
<h2 class="demo-title">Swap textures</h2>
|
|
<p>As above, you can change these values in AR, but only in WebXR
|
|
mode. iOS Quick Look reflects these texture changes so long as the
|
|
USDZ is auto-generated.</p>
|
|
</div>
|
|
<example-snippet stamp-to="swapTexturesExample" highlight-as="html">
|
|
<template>
|
|
<model-viewer id="helmet" camera-controls touch-action="pan-y"
|
|
src="../../shared-assets/models/glTF-Sample-Assets/Models/DamagedHelmet/glTF-Binary/DamagedHelmet.glb"
|
|
ar alt="A 3D model of a helmet">
|
|
<div class="controls glass">
|
|
<div>
|
|
<p>Diffuse</p>
|
|
<select id="diffuse">
|
|
<option
|
|
value="../../shared-assets/models/glTF-Sample-Assets/Models/DamagedHelmet/glTF/Default_albedo.jpg">
|
|
Damaged helmet</option>
|
|
<option
|
|
value="../../shared-assets/models/glTF-Sample-Assets/Models/Lantern/glTF/Lantern_baseColor.png">
|
|
Lantern Pole</option>
|
|
<option
|
|
value="../../shared-assets/models/glTF-Sample-Assets/Models/WaterBottle/glTF/WaterBottle_baseColor.png">
|
|
Water Bottle</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<p>Metallic-roughness</p>
|
|
<select id="metallicRoughness">
|
|
<option
|
|
value="../../shared-assets/models/glTF-Sample-Assets/Models/DamagedHelmet/glTF/Default_metalRoughness.jpg">
|
|
Damaged helmet</option>
|
|
<option
|
|
value="../../shared-assets/models/glTF-Sample-Assets/Models/Lantern/glTF/Lantern_roughnessMetallic.png">
|
|
Lantern Pole</option>
|
|
<option
|
|
value="../../shared-assets/models/glTF-Sample-Assets/Models/WaterBottle/glTF/WaterBottle_occlusionRoughnessMetallic.png">
|
|
Water Bottle</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<p>Normals</p>
|
|
<select id="normals">
|
|
<option
|
|
value="../../shared-assets/models/glTF-Sample-Assets/Models/DamagedHelmet/glTF/Default_normal.jpg">
|
|
Damaged helmet</option>
|
|
<option
|
|
value="../../shared-assets/models/glTF-Sample-Assets/Models/Lantern/glTF/Lantern_normal.png">
|
|
Lantern Pole</option>
|
|
<option
|
|
value="../../shared-assets/models/glTF-Sample-Assets/Models/WaterBottle/glTF/WaterBottle_normal.png">
|
|
Water Bottle</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<p>Occlusion</p>
|
|
<select id="occlusion">
|
|
<option
|
|
value="../../shared-assets/models/glTF-Sample-Assets/Models/DamagedHelmet/glTF/Default_AO.jpg">
|
|
Damaged helmet</option>
|
|
<option
|
|
value="../../shared-assets/models/glTF-Sample-Assets/Models/WaterBottle/glTF/WaterBottle_occlusionRoughnessMetallic.png">
|
|
Water Bottle</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<p>Emission</p>
|
|
<select id="emission">
|
|
<option
|
|
value="../../shared-assets/models/glTF-Sample-Assets/Models/DamagedHelmet/glTF/Default_emissive.jpg">
|
|
Damaged helmet</option>
|
|
<option
|
|
value="../../shared-assets/models/glTF-Sample-Assets/Models/Lantern/glTF/Lantern_emissive.png">
|
|
Lantern Pole</option>
|
|
<option
|
|
value="../../shared-assets/models/glTF-Sample-Assets/Models/WaterBottle/glTF/WaterBottle_emissive.png">
|
|
Water Bottle</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</model-viewer>
|
|
<script type="module">
|
|
const modelViewerTexture1 = document.querySelector("model-viewer#helmet");
|
|
|
|
modelViewerTexture1.addEventListener("load", () => {
|
|
|
|
const material = modelViewerTexture1.model.materials[0];
|
|
|
|
const createAndApplyTexture = async (channel, event) => {
|
|
const texture = await modelViewerTexture1.createTexture(event.target.value);
|
|
if (channel.includes('base') || channel.includes('metallic')) {
|
|
material.pbrMetallicRoughness[channel].setTexture(texture);
|
|
} else {
|
|
material[channel].setTexture(texture);
|
|
}
|
|
}
|
|
|
|
document.querySelector('#normals').addEventListener('input', (event) => {
|
|
createAndApplyTexture('normalTexture', event);
|
|
});
|
|
|
|
document.querySelector('#occlusion').addEventListener('input', (event) => {
|
|
createAndApplyTexture('occlusionTexture', event);
|
|
});
|
|
|
|
document.querySelector('#emission').addEventListener('input', (event) => {
|
|
createAndApplyTexture('emissiveTexture', event);
|
|
});
|
|
|
|
document.querySelector('#diffuse').addEventListener('input', (event) => {
|
|
createAndApplyTexture('baseColorTexture', event);
|
|
});
|
|
|
|
document.querySelector('#metallicRoughness').addEventListener('input', (event) => {
|
|
createAndApplyTexture('metallicRoughnessTexture', event);
|
|
});
|
|
});
|
|
|
|
</script>
|
|
</template>
|
|
</example-snippet>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="sample">
|
|
<div id="transformTexturesExample" class="demo"></div>
|
|
<div class="content">
|
|
<div class="wrapper">
|
|
<div class="heading">
|
|
<h2 class="demo-title">Transform textures</h2>
|
|
<p>As above, you can change these values in AR, but only in WebXR
|
|
mode. iOS Quick Look reflects these texture changes so long as the
|
|
USDZ is auto-generated.</p>
|
|
</div>
|
|
<example-snippet stamp-to="transformTexturesExample" highlight-as="html">
|
|
<template>
|
|
<model-viewer id="box" camera-controls touch-action="pan-y"
|
|
src="../../shared-assets/models/glTF-Sample-Assets/Models/Cube/glTF/Cube.gltf" ar
|
|
alt="A 3D model of a helmet">
|
|
<div class="controls glass">
|
|
<p>Rotation: <span id="texture-rotation"></span></p>
|
|
<input type="range" min="0" max="3.14" value="0" step="0.01" id="rotationSlider">
|
|
<p>Scale: <span id="texture-scale"></span></p>
|
|
<input type="range" min="0.5" max="1.5" value="1" step="0.01" id="scaleSlider">
|
|
<p>Offset</p>
|
|
<input type="range" min="0" max="1" value="0" step="0.01" id="offsetSlider">
|
|
<p>WrapMode</p>
|
|
<select id="wrapMode">
|
|
<option value="10497">Repeat</option>
|
|
<option value="33071">ClampToEdge</option>
|
|
<option value="33648">MirroredRepeat</option>
|
|
</select>
|
|
</div>
|
|
</model-viewer>
|
|
<script type="module">
|
|
const modelViewerTexture2 = document.querySelector("model-viewer#box");
|
|
const rotationSlider = document.querySelector('#rotationSlider');
|
|
const scaleSlider = document.querySelector('#scaleSlider');
|
|
const offsetSlider = document.querySelector('#offsetSlider');
|
|
|
|
modelViewerTexture2.addEventListener("load", () => {
|
|
|
|
const sampler = modelViewerTexture2.model.materials[0].pbrMetallicRoughness['baseColorTexture'].texture.sampler;
|
|
|
|
const rotationDisplay = document.querySelector('#texture-rotation');
|
|
const scaleDisplay = document.querySelector('#texture-scale');
|
|
|
|
rotationDisplay.textContent = rotationSlider.value;
|
|
scaleDisplay.textContent = scaleSlider.value;
|
|
|
|
rotationSlider.addEventListener('input', (event) => {
|
|
const rotation = rotationSlider.value;
|
|
sampler.setRotation(rotation);
|
|
rotationDisplay.textContent = rotation;
|
|
});
|
|
|
|
scaleSlider.addEventListener('input', (event) => {
|
|
const scale = {
|
|
u: scaleSlider.value,
|
|
v: scaleSlider.value
|
|
};
|
|
sampler.setScale(scale);
|
|
scaleDisplay.textContent = scale.x;
|
|
});
|
|
|
|
offsetSlider.addEventListener('input', (event) => {
|
|
const offset = {
|
|
u: offsetSlider.value,
|
|
v: -offsetSlider.value
|
|
};
|
|
sampler.setOffset(offset);
|
|
});
|
|
|
|
document.querySelector('#wrapMode').addEventListener('input', (event) => {
|
|
sampler.setWrapS(Number(event.target.value));
|
|
sampler.setWrapT(Number(event.target.value));
|
|
});
|
|
});
|
|
|
|
</script>
|
|
</template>
|
|
</example-snippet>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="sample">
|
|
<div id="hideShowMeshVariantsExample" class="demo"></div>
|
|
<div class="content">
|
|
<div class="wrapper">
|
|
<div class="heading">
|
|
<h2 class="demo-title">Toggle between Mesh Variants</h2>
|
|
<p>If you have a few mesh variants, you can hide and show them by changing textures opacity.</p>
|
|
</div>
|
|
<example-snippet stamp-to="hideShowMeshVariantsExample" highlight-as="html">
|
|
<template>
|
|
<model-viewer id="manifold" camera-controls touch-action="pan-y"
|
|
src="../../shared-assets/models/manifold.glb" ar alt="A 3D model of a stick and ball">
|
|
<div class="controls glass">
|
|
<div>Mesh Variants:
|
|
<select id="textures">
|
|
<option value="ball">ball</option>
|
|
<option value="stick">stick</option>
|
|
</select>
|
|
</div>
|
|
</model-viewer>
|
|
<script type="module">
|
|
const mvTextures = document.querySelector("model-viewer#manifold");
|
|
const textures = document.querySelector("#textures");
|
|
|
|
mvTextures.addEventListener("load", () => {
|
|
function updateAlphaValue(texture, alpha) {
|
|
const pbr = texture.pbrMetallicRoughness;
|
|
const baseColor = pbr.baseColorFactor;
|
|
baseColor[3] = alpha;
|
|
pbr.setBaseColorFactor(baseColor);
|
|
}
|
|
|
|
textures.addEventListener("input", (event) => {
|
|
const selectedValue = event.target.value;
|
|
const ball = mvTextures.model.getMaterialByName("ball");
|
|
ball.setAlphaMode("BLEND");
|
|
const stick = mvTextures.model.getMaterialByName("stick");
|
|
|
|
const animationDuration = 1000; // 1 second
|
|
const startTimestamp = performance.now();
|
|
function animate(currentTimestamp) {
|
|
const elapsed = currentTimestamp - startTimestamp;
|
|
|
|
const delta = elapsed / animationDuration;
|
|
const alpha = selectedValue === "ball" ? 1 - delta : delta;
|
|
updateAlphaValue(stick, alpha);
|
|
updateAlphaValue(ball, 1 - alpha);
|
|
|
|
if (elapsed < animationDuration) {
|
|
requestAnimationFrame(animate);
|
|
}
|
|
}
|
|
|
|
requestAnimationFrame(animate);
|
|
});
|
|
});
|
|
</script>
|
|
</template>
|
|
</example-snippet>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="sample">
|
|
<div id="animatedTexturesExample" class="demo"></div>
|
|
<div class="content">
|
|
<div class="wrapper">
|
|
<div class="heading">
|
|
<h2 class="demo-title">Create animated textures</h2>
|
|
<p>Though video textures are not part of the glTF spec yet, you can
|
|
create them and add them to your model after it loads. Video
|
|
elements, Canvas elements, and Lottie animations are all
|
|
supported.</p>
|
|
<p>For Lottie animations, an import map is required, pointing
|
|
"three" to the model-viewer library file you are loading, since
|
|
three.js is contained in the model-viewer bundle. Unfortunately this
|
|
cannot be done by our library automatically because the import map
|
|
must be specified before any libraries load. Put something like this
|
|
in your page's head:</p>
|
|
<pre><code>
|
|
<script type="importmap">
|
|
{
|
|
"imports": {
|
|
"three": "path/to/your/model-viewer.min.js"
|
|
}
|
|
}
|
|
</script>
|
|
</code></pre>
|
|
<p>Unfortunately, Safari does not yet support import maps, so to get
|
|
this to work universally, you will need the following code
|
|
instead:</p>
|
|
<pre><code>
|
|
<script async src="https://ga.jspm.io/npm:es-module-shims@1.6.3/dist/es-module-shims.js"></script>
|
|
|
|
<script type="importmap-shim">
|
|
{
|
|
"imports": {
|
|
"three": "path/to/your/model-viewer.min.js"
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<script type="module-shim" src="path/to/your/model-viewer.min.js"></script>
|
|
</code></pre>
|
|
</div>
|
|
<example-snippet stamp-to="animatedTexturesExample" highlight-as="html">
|
|
<template>
|
|
<model-viewer id="animated" camera-controls touch-action="pan-y"
|
|
src="../../shared-assets/models/sphere.glb" ar alt="A 3D model of a duck">
|
|
<div class="controls glass">
|
|
<p>Texture Type</p>
|
|
<select id="type">
|
|
<option value="lottie">Lottie</option>
|
|
<option value="video">Video</option>
|
|
<option value="canvas">Canvas</option>
|
|
</select>
|
|
</div>
|
|
</model-viewer>
|
|
<script type="module">
|
|
const modelViewerAnimated = document.querySelector("model-viewer#animated");
|
|
|
|
let videoTexture = null;
|
|
let canvasTexture = null;
|
|
let lottieTexture = null;
|
|
|
|
customElements.whenDefined('model-viewer').then(() => {
|
|
videoTexture = modelViewerAnimated.createVideoTexture("../../shared-assets/models/lottie-logo.mp4");
|
|
});
|
|
|
|
function getCanvasTexture() {
|
|
if (canvasTexture) return canvasTexture;
|
|
canvasTexture = modelViewerAnimated.createCanvasTexture();
|
|
const canvas = canvasTexture.source.element;
|
|
canvas.width = 1600;
|
|
canvas.height = 800;
|
|
const ctx = canvas.getContext('2d');
|
|
ctx.font = "250px sans-serif";
|
|
ctx.fillStyle = "#aaa";
|
|
ctx.fillText('Canvas 2D!', 0, 400);
|
|
canvasTexture.source.update();
|
|
return canvasTexture;
|
|
}
|
|
|
|
function getLottieTexture() {
|
|
if (lottieTexture) return lottieTexture;
|
|
lottieTexture = modelViewerAnimated.createLottieTexture("../../shared-assets/models/24017-lottie-logo-animation.json", 2);
|
|
return lottieTexture;
|
|
}
|
|
|
|
modelViewerAnimated.addEventListener("load", async () => {
|
|
|
|
const material = modelViewerAnimated.model.materials[0];
|
|
const { baseColorTexture } = material.pbrMetallicRoughness;
|
|
|
|
baseColorTexture.setTexture(await getLottieTexture());
|
|
|
|
document.querySelector('#type').addEventListener('input', async (event) => {
|
|
switch (event.target.value) {
|
|
case "video":
|
|
baseColorTexture.setTexture(videoTexture);
|
|
break;
|
|
case "canvas":
|
|
baseColorTexture.setTexture(getCanvasTexture());
|
|
break;
|
|
case "lottie":
|
|
baseColorTexture.setTexture(await getLottieTexture());
|
|
break;
|
|
}
|
|
});
|
|
});
|
|
|
|
</script>
|
|
</template>
|
|
</example-snippet>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sample">
|
|
<div id="pickMaterialExample" class="demo"></div>
|
|
<div class="content">
|
|
<div class="wrapper">
|
|
<div class="heading">
|
|
<h2 class="demo-title">Materials API</h2>
|
|
<p>The complete Materials interface is documented below, which is all accessible through the <a
|
|
href="../../docs/index.html#entrydocs-scenegraph-properties-model">model property</a>.
|
|
The Materials API is designed to follow the <a
|
|
href="https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#reference-material">glTF
|
|
structure</a>, just as though you are navigating their JSON object.
|
|
Only the materials and their children are exposed rather than the whole scene graph to keep the scope
|
|
small for this high-level web component.
|
|
Not every glTF parameter is exposed, but more may be added in the future. Additionally, several methods
|
|
have been added for useful operations.</p>
|
|
<p>This example demonstrates selecting a material with pointer input and changing its color. Note this
|
|
also works in the WebXR AR mode. It also demonstrates the use of the scale attribute since this GLB was
|
|
erroneously modeled in mm instead of meters.</p>
|
|
</div>
|
|
<example-snippet stamp-to="pickMaterialExample" highlight-as="html">
|
|
<template>
|
|
<model-viewer id="pickMaterial" shadow-intensity="1" camera-controls touch-action="pan-y" disable-tap
|
|
src="../../shared-assets/models/glTF-Sample-Assets/Models/MetalRoughSpheresNoTextures/glTF-Binary/MetalRoughSpheresNoTextures.glb"
|
|
ar ar-modes="webxr" scale="100 100 100" alt="A Material Picking Example">
|
|
</model-viewer>
|
|
<script type="module">
|
|
const modelViewer = document.querySelector("model-viewer#pickMaterial");
|
|
|
|
modelViewer.addEventListener("load", () => {
|
|
const changeColor = (event) => {
|
|
if (modelViewer.modelIsVisible) {
|
|
const material = modelViewer.materialFromPoint(event.clientX, event.clientY);
|
|
if (material != null) {
|
|
material.pbrMetallicRoughness.
|
|
setBaseColorFactor([Math.random(), Math.random(), Math.random()]);
|
|
}
|
|
}
|
|
};
|
|
|
|
document.addEventListener("click", changeColor);
|
|
});
|
|
</script>
|
|
<script>
|
|
/**
|
|
* This is not an actual script, but an API declaration made prettier with JS syntax highlighting.
|
|
*/
|
|
|
|
/** A 2D Cartesian coordinate */
|
|
interface Vector2DInterface {
|
|
u: number;
|
|
v: number;
|
|
}
|
|
|
|
type RGBA = [number, number, number, number];
|
|
type RGB = [number, number, number];
|
|
|
|
/**
|
|
* A Model is the root element of a 3DOM scene graph. It gives scripts access
|
|
* to the sub-elements found without the graph.
|
|
*/
|
|
interface Model {
|
|
/**
|
|
* An ordered set of unique Materials found in this model. The Materials
|
|
* correspond to the listing of materials in the glTF, with the possible
|
|
* addition of a default material at the end.
|
|
*/
|
|
readonly materials: Readonly<Material[]>;
|
|
|
|
/**
|
|
* Gets a material(s) by name.
|
|
* @param name the name of the material to return.
|
|
* @returns the first material to whose name matches `name`
|
|
*/
|
|
getMaterialByName(name: string): Material | null;
|
|
|
|
/**
|
|
* Creates a new material variant from an existing material.
|
|
* @param originalMaterialIndex index of the material to clone the variant
|
|
* from.
|
|
* @param materialName the name of the new material
|
|
* @param variantName the name of the variant
|
|
* @param activateVariant activates this material variant, i.e. the variant
|
|
* material is rendered, not the existing material.
|
|
* @returns returns a clone of the original material, returns `null` if the
|
|
* material instance for this variant already exists.
|
|
*/
|
|
createMaterialInstanceForVariant(
|
|
originalMaterialIndex: number, newMaterialName: string,
|
|
variantName: string, activateVariant: boolean): Material | null;
|
|
|
|
/**
|
|
* Adds a variant name to the model.
|
|
* @param variantName
|
|
*/
|
|
createVariant(variantName: string): void;
|
|
|
|
/**
|
|
* Adds an existing material to a variant name.
|
|
* @param materialIndex
|
|
* @param targetVariantName
|
|
*/
|
|
setMaterialToVariant(materialIndex: number, targetVariantName: string): void;
|
|
|
|
/**
|
|
* Removes the variant name from the model.
|
|
* @param variantName the variant to remove.
|
|
*/
|
|
deleteVariant(variantName: string): void;
|
|
}
|
|
|
|
/**
|
|
* A Material gives the script access to modify a single, unique material found
|
|
* in a model's scene graph.
|
|
*
|
|
* @see https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-material
|
|
*/
|
|
interface Material {
|
|
/**
|
|
* The name of the material, if any.
|
|
*/
|
|
name: string;
|
|
|
|
readonly normalTexture: TextureInfo | null;
|
|
readonly occlusionTexture: TextureInfo | null;
|
|
readonly emissiveTexture: TextureInfo | null;
|
|
|
|
readonly emissiveFactor: Readonly<RGB>;
|
|
setEmissiveFactor(rgb: RGB | string): void;
|
|
setAlphaCutoff(cutoff: number): void;
|
|
getAlphaCutoff(): number;
|
|
setDoubleSided(doubleSided: boolean): void;
|
|
getDoubleSided(): boolean;
|
|
setAlphaMode(alphaMode: AlphaMode): void;
|
|
getAlphaMode(): AlphaMode;
|
|
|
|
/**
|
|
* PBR Next properties.
|
|
*/
|
|
readonly emissiveStrength: number;
|
|
readonly clearcoatFactor: number;
|
|
readonly clearcoatRoughnessFactor: number;
|
|
readonly clearcoatTexture: TextureInfo;
|
|
readonly clearcoatRoughnessTexture: TextureInfo;
|
|
readonly clearcoatNormalTexture: TextureInfo;
|
|
readonly clearcoatNormalScale: number;
|
|
readonly ior: number;
|
|
readonly sheenColorFactor: Readonly<RGB>;
|
|
readonly sheenColorTexture: TextureInfo;
|
|
readonly sheenRoughnessFactor: number;
|
|
readonly sheenRoughnessTexture: TextureInfo;
|
|
readonly transmissionFactor: number;
|
|
readonly transmissionTexture: TextureInfo;
|
|
readonly thicknessFactor: number;
|
|
readonly thicknessTexture: TextureInfo;
|
|
readonly attenuationDistance: number;
|
|
readonly attenuationColor: Readonly<RGB>;
|
|
readonly specularFactor: number;
|
|
readonly specularTexture: TextureInfo;
|
|
readonly specularColorFactor: Readonly<RGB>;
|
|
readonly specularColorTexture: TextureInfo;
|
|
readonly iridescenceFactor: number;
|
|
readonly iridescenceTexture: TextureInfo;
|
|
readonly iridescenceIor: number;
|
|
readonly iridescenceThicknessMinimum: number;
|
|
readonly iridescenceThicknessMaximum: number;
|
|
readonly iridescenceThicknessTexture: TextureInfo;
|
|
readonly anisotropyStrength: number;
|
|
readonly anisotropyRotation: number;
|
|
readonly anisotropyTexture: TextureInfo;
|
|
|
|
setEmissiveStrength(emissiveStrength: number): void;
|
|
setClearcoatFactor(clearcoatFactor: number): void;
|
|
setClearcoatRoughnessFactor(clearcoatRoughnessFactor: number): void;
|
|
setClearcoatNormalScale(clearcoatNormalScale: number): void;
|
|
setIor(ior: number): void;
|
|
setSheenColorFactor(rgb: RGB | string): void;
|
|
setSheenRoughnessFactor(roughness: number): void;
|
|
setTransmissionFactor(transmission: number): void;
|
|
setThicknessFactor(thickness: number): void;
|
|
setAttenuationDistance(attenuationDistance: number): void;
|
|
setAttenuationColor(rgb: RGB | string): void;
|
|
setSpecularFactor(specularFactor: number): void;
|
|
setSpecularColorFactor(rgb: RGB | string): void;
|
|
setIridescenceFactor(iridescence: number): void;
|
|
setIridescenceIor(ior: number): void;
|
|
setIridescenceThicknessMinimum(thicknessMin: number): void;
|
|
setIridescenceThicknessMaximum(thicknessMax: number): void;
|
|
setAnisotropyStrength(strength: number): void;
|
|
setAnisotropyRotation(rotation: number): void;
|
|
|
|
/**
|
|
* The PBRMetallicRoughness configuration of the material.
|
|
*/
|
|
readonly pbrMetallicRoughness: PBRMetallicRoughness;
|
|
|
|
/**
|
|
* Asynchronously loads the underlying material resource if it's currently
|
|
* unloaded, otherwise the method is a noop.
|
|
*/
|
|
ensureLoaded(): void;
|
|
|
|
/**
|
|
* Returns true if the material participates in the variant.
|
|
* @param name the variant name.
|
|
*/
|
|
hasVariant(name: string): boolean;
|
|
|
|
/**
|
|
* Returns true if the material is loaded.
|
|
*/
|
|
readonly isLoaded: boolean;
|
|
|
|
/**
|
|
* Returns true if the material is participating in scene renders.
|
|
*/
|
|
readonly isActive: boolean;
|
|
|
|
/**
|
|
* Returns the glTF index of this material.
|
|
*/
|
|
readonly index: number;
|
|
}
|
|
|
|
/**
|
|
* The PBRMetallicRoughness encodes the PBR properties of a material
|
|
*
|
|
* @see https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-pbrmetallicroughness
|
|
*/
|
|
interface PBRMetallicRoughness {
|
|
/**
|
|
* The base color factor of the material, represented as RGBA values
|
|
*/
|
|
readonly baseColorFactor: Readonly<RGBA>;
|
|
|
|
/**
|
|
* Metalness factor of the material, represented as number between 0 and 1
|
|
*/
|
|
readonly metallicFactor: number;
|
|
|
|
/**
|
|
* Roughness factor of the material, represented as number between 0 and 1
|
|
*/
|
|
readonly roughnessFactor: number;
|
|
|
|
/**
|
|
* A texture reference, associating an image with color information and
|
|
* a sampler for describing base color factor for a UV coordinate space.
|
|
*/
|
|
readonly baseColorTexture: TextureInfo | null;
|
|
|
|
/**
|
|
* A texture reference, associating an image with color information and
|
|
* a sampler for describing metalness (B channel) and roughness (G channel)
|
|
* for a UV coordinate space.
|
|
*/
|
|
readonly metallicRoughnessTexture: TextureInfo | null;
|
|
|
|
/**
|
|
* Changes the base color factor of the material to the given value.
|
|
*/
|
|
setBaseColorFactor(rgba: RGBA | string): void;
|
|
|
|
/**
|
|
* Changes the metalness factor of the material to the given value.
|
|
*/
|
|
setMetallicFactor(value: number): void;
|
|
|
|
/**
|
|
* Changes the roughness factor of the material to the given value.
|
|
*/
|
|
setRoughnessFactor(value: number): void;
|
|
}
|
|
|
|
/**
|
|
* A TextureInfo is a pointer to a specific Texture in use on a Material
|
|
*
|
|
* @see https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-textureinfo
|
|
*/
|
|
interface TextureInfo {
|
|
/**
|
|
* The Texture being referenced by this TextureInfo.
|
|
*/
|
|
readonly texture: Texture | null;
|
|
|
|
/**
|
|
* Sets the texture, or removes it if argument is null. Note you cannot build
|
|
* your own Texture object, but must either use one from another TextureInfo,
|
|
* or create one with the createTexture method.
|
|
*/
|
|
setTexture(texture: Texture | null): void;
|
|
}
|
|
|
|
/**
|
|
* A Texture pairs an Image and a Sampler for use in a Material
|
|
*
|
|
* @see https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-texture
|
|
*/
|
|
interface Texture {
|
|
/**
|
|
* The name of the texture, if any.
|
|
*/
|
|
readonly name: string;
|
|
|
|
/**
|
|
* The Sampler for this Texture
|
|
*/
|
|
readonly sampler: Sampler;
|
|
|
|
/**
|
|
* The source Image for this Texture
|
|
*/
|
|
readonly source: Image;
|
|
}
|
|
|
|
/**
|
|
* A Sampler describes how to filter and wrap textures
|
|
*
|
|
* @see https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-sampler
|
|
*/
|
|
interface Sampler {
|
|
/**
|
|
* The name of the sampler, if any.
|
|
*/
|
|
readonly name: string;
|
|
|
|
/**
|
|
* @see https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#samplerminfilter
|
|
*/
|
|
readonly minFilter: MinFilter;
|
|
|
|
/**
|
|
* @see https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#samplermagfilter
|
|
*/
|
|
readonly magFilter: MagFilter;
|
|
|
|
/**
|
|
* @see https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#samplerwraps
|
|
*/
|
|
readonly wrapS: WrapMode;
|
|
|
|
/**
|
|
* @see https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#samplerwrapt
|
|
*/
|
|
readonly wrapT: WrapMode;
|
|
|
|
/**
|
|
* The texture rotation in radians.
|
|
*/
|
|
readonly rotation: number | null;
|
|
|
|
/**
|
|
* The texture scale.
|
|
*/
|
|
readonly scale: Vector2DInterface | null;
|
|
|
|
/**
|
|
* The texture offset.
|
|
*/
|
|
readonly offset: Vector2DInterface | null;
|
|
|
|
/**
|
|
* Configure the minFilter value of the Sampler.
|
|
*/
|
|
setMinFilter(filter: MinFilter): void;
|
|
|
|
/**
|
|
* Configure the magFilter value of the Sampler.
|
|
*/
|
|
setMagFilter(filter: MagFilter): void;
|
|
|
|
/**
|
|
* Configure the S (U) wrap mode of the Sampler.
|
|
*/
|
|
setWrapS(mode: WrapMode): void;
|
|
|
|
/**
|
|
* Configure the T (V) wrap mode of the Sampler.
|
|
*/
|
|
setWrapT(mode: WrapMode): void;
|
|
|
|
/**
|
|
* Sets the texture rotation, or resets it to zero if argument is null.
|
|
* Rotation is in radians, positive for counter-clockwise.
|
|
*/
|
|
setRotation(rotation: number | null): void;
|
|
|
|
/**
|
|
* Sets the texture scale, or resets it to (1, 1) if argument is null.
|
|
* As the scale value increases, the repetition of the texture will increase.
|
|
*/
|
|
setScale(scale: Vector2DInterface | null): void;
|
|
|
|
/**
|
|
* Sets the texture offset, or resets it to (0, 0) if argument is null.
|
|
*/
|
|
setOffset(offset: Vector2DInterface | null): void;
|
|
}
|
|
|
|
|
|
/**
|
|
* An Image represents an embedded or external image used to provide texture
|
|
* color data.
|
|
*
|
|
* @see https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-image
|
|
*/
|
|
interface Image {
|
|
/**
|
|
* The name of the image, if any.
|
|
*/
|
|
readonly name: string;
|
|
|
|
/**
|
|
* The type is 'external' if the image has a configured URI. Otherwise, it is
|
|
* considered to be 'embedded'. Note: this distinction is only implied by the
|
|
* glTF spec, and is made explicit here for convenience.
|
|
*/
|
|
readonly type: 'embedded' | 'external';
|
|
|
|
/**
|
|
* The URI of the image, if it is external.
|
|
*/
|
|
readonly uri?: string;
|
|
|
|
/**
|
|
* The bufferView of the image, if it is embedded.
|
|
*/
|
|
readonly bufferView?: number;
|
|
|
|
/**
|
|
* The backing HTML element, if this is a video or canvas texture.
|
|
*/
|
|
readonly element?: HTMLVideoElement | HTMLCanvasElement;
|
|
|
|
/**
|
|
* The Lottie animation object, if this is a Lottie texture. You may wish to
|
|
* do image.animation as import('lottie-web').AnimationItem; to get its type
|
|
* info.
|
|
*/
|
|
readonly animation?: any;
|
|
|
|
/**
|
|
* A method to create an object URL of this image at the desired
|
|
* resolution. Especially useful for KTX2 textures which are GPU compressed,
|
|
* and so are unreadable on the CPU without a method like this.
|
|
*/
|
|
createThumbnail(width: number, height: number): Promise<string>;
|
|
|
|
/**
|
|
* Only applies to canvas textures. Call when the content of the canvas has
|
|
* been updated and should be reflected in the model.
|
|
*/
|
|
update(): void;
|
|
}
|
|
</script>
|
|
</template>
|
|
</example-snippet>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sample">
|
|
<div id="exporter" class="demo"></div>
|
|
<div class="content">
|
|
<div class="wrapper">
|
|
|
|
<a class="lockup" href="../../index.html">
|
|
<div class="icon-button icon-modelviewer-black"></div>
|
|
<h1>examples</h1>
|
|
</a>
|
|
<div class="heading">
|
|
<h2 class="demo-title">Exporter</h2>
|
|
</div>
|
|
<example-snippet stamp-to="exporter" highlight-as="html">
|
|
<template>
|
|
<model-viewer id="static-model" src="../../shared-assets/models/Astronaut.glb" shadow-intensity="1"
|
|
camera-controls touch-action="pan-y" alt="A 3D model of an astronaut">
|
|
<div class="controls glass">
|
|
<button onclick="exportGLB()">Export GLB</button>
|
|
</div>
|
|
</model-viewer>
|
|
<script>
|
|
async function exportGLB() {
|
|
const modelViewer = document.getElementById("static-model");
|
|
const glTF = await modelViewer.exportScene();
|
|
const file = new File([glTF], "export.glb");
|
|
const link = document.createElement("a");
|
|
link.download = file.name;
|
|
link.href = URL.createObjectURL(file);
|
|
link.click();
|
|
}
|
|
</script>
|
|
</template>
|
|
</example-snippet>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="footer">
|
|
<ul>
|
|
<li class="attribution">
|
|
<a href="https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/MaterialsVariantsShoe">Shoe</a>
|
|
©Copyright 2020 <a href="https://www.shopify.com/">Shopify Inc.</a>,
|
|
licensed under <a href="https://creativecommons.org/licenses/by/4.0/">CC-BY-4.0</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://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/DamagedHelmet">Damaged
|
|
Helmet</a> by <a href="https://sketchfab.com/theblueturtle_">theblueturtle_</a>,
|
|
licensed under <a href="https://creativecommons.org/licenses/by-nc/3.0/us/">Creative Commons
|
|
Attribution-NonCommercial</a>.
|
|
</li>
|
|
<li class="attribution">
|
|
<a href="https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Lantern">Lantern</a>,
|
|
licensed under <a href="https://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero</a>.
|
|
</li>
|
|
<li class="attribution">
|
|
<a href="https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/WaterBottle">Water Bottle</a>,
|
|
licensed under <a href="https://creativecommons.org/publicdomain/zero/1.0/">Creative Commons Zero</a>.
|
|
</li>
|
|
<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://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Duck">Duck</a> by Sony Computer
|
|
Entertainment Inc.,
|
|
licensed under <a
|
|
href="https://web.archive.org/web/20160320123355/http://research.scea.com/scea_shared_source_license.html">the
|
|
SCEA Shared Source License, Version 1.0</a>.
|
|
</li>
|
|
</ul>
|
|
<div style="margin-top:24px;" class="copyright">©Copyright 2018-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-scenegraph'); })();
|
|
(() => { initFooterLinks(); })();
|
|
</script>
|
|
|
|
<!-- Documentation-specific dependencies: -->
|
|
<script type="module" src="../built/dependencies.js">
|
|
</script>
|
|
|
|
<!-- Loads <model-viewer> on modern browsers: -->
|
|
<script type="module-shim" src="../../../../node_modules/@google/model-viewer/dist/model-viewer.js">
|
|
</script>
|
|
</body>
|
|
|
|
</html> |