464 lines
17 KiB
HTML
464 lines
17 KiB
HTML
<!--
|
|
/* @license
|
|
* 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> Augmented Reality</title>
|
|
<meta charset="utf-8">
|
|
<meta name="description" content="<model-viewer> AR 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 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>
|
|
</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="webXR" class="demo"></div>
|
|
<div class="content">
|
|
<div class="wrapper">
|
|
|
|
<div class="heading">
|
|
<h2 class="demo-title">WebXR Demo</h2>
|
|
<h4>Customize a WebXR Augmented Reality session with HTML, CSS, and JS in Chrome 83+ on Android.</h4>
|
|
<p>
|
|
This demonstrates the use of slots, as well as shared and unshared DOM between the 3D and AR modes.
|
|
</p>
|
|
<p>
|
|
A slot is used here for replacing the default AR button with a custom one - in this case
|
|
the one recommended by SceneViewer. This is not the default only because this way localization of the text is left
|
|
to whatever system you prefer to use. Note the AR button will only be visible on AR-capable devices.
|
|
</p>
|
|
<p>
|
|
By styling based on the <code>ar-status</code> attribute, you can add DOM that only shows up in certain modes.
|
|
In this case a CSS animation has been added to prompt the user to move their phone around to help ARCore find
|
|
their floor so that the object can be placed. User studies show a prompt like this is an important part of
|
|
guiding users to a good AR experience.
|
|
</p>
|
|
<p>
|
|
Finally, even complex DOM can easily function in both 3D and AR modes, including interactions via script. In
|
|
this case a simple carousel of models is demonstrated. Unfortunately none of this DOM content can flow into
|
|
SceneViewer or QuickLook, as these are native apps. Only through WebXR, now our default AR mode, can this be
|
|
achieved, as the AR session is still inside of the browser. This also removes the need to redownload the model.
|
|
</p>
|
|
<p>
|
|
Note that by not specifying an <code>ios-src</code>,
|
|
the USDZ will instead be auto-generated when the user clicks the
|
|
AR button on iOS to launch Quick Look.
|
|
</p>
|
|
</div>
|
|
<example-snippet stamp-to="webXR" highlight-as="html">
|
|
<template>
|
|
<model-viewer src="../../assets/ShopifyModels/Chair.glb" poster="../../assets/ShopifyModels/Chair.webp" shadow-intensity="1" ar camera-controls touch-action="pan-y" alt="A 3D model carousel">
|
|
|
|
<button slot="ar-button" id="ar-button">
|
|
View in your space
|
|
</button>
|
|
|
|
<div id="ar-prompt">
|
|
<img src="../../assets/hand.png">
|
|
</div>
|
|
|
|
<button id="ar-failure">
|
|
AR is not tracking!
|
|
</button>
|
|
|
|
<div class="slider">
|
|
<div class="slides">
|
|
<button class="slide selected" onclick="switchSrc(this, 'Chair')"
|
|
style="background-image: url('../../assets/ShopifyModels/Chair.webp');">
|
|
|
|
<button class="slide" onclick="switchSrc(this, 'Mixer')"
|
|
style="background-image: url('../../assets/ShopifyModels/Mixer.webp');">
|
|
|
|
<button class="slide" onclick="switchSrc(this, 'GeoPlanter')"
|
|
style="background-image: url('../../assets/ShopifyModels/GeoPlanter.webp');">
|
|
|
|
<button class="slide" onclick="switchSrc(this, 'ToyTrain')"
|
|
style="background-image: url('../../assets/ShopifyModels/ToyTrain.webp');">
|
|
|
|
<button class="slide" onclick="switchSrc(this, 'Canoe')"
|
|
style="background-image: url('../../assets/ShopifyModels/Canoe.webp');">
|
|
</div>
|
|
</div>
|
|
</model-viewer>
|
|
|
|
<script type="module">
|
|
const modelViewer = document.querySelector("model-viewer");
|
|
|
|
window.switchSrc = (element, name) => {
|
|
const base = "../../assets/ShopifyModels/" + name;
|
|
modelViewer.src = base + '.glb';
|
|
modelViewer.poster = base + '.webp';
|
|
const slides = document.querySelectorAll(".slide");
|
|
slides.forEach((element) => {element.classList.remove("selected");});
|
|
element.classList.add("selected");
|
|
};
|
|
|
|
document.querySelector(".slider").addEventListener('beforexrselect', (ev) => {
|
|
// Keep slider interactions from affecting the XR scene.
|
|
ev.preventDefault();
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
/* This keeps child nodes hidden while the element loads */
|
|
:not(:defined) > * {
|
|
display: none;
|
|
}
|
|
|
|
model-viewer {
|
|
background-color: #eee;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
#ar-button {
|
|
background-image: url(../../assets/ic_view_in_ar_new_googblue_48dp.png);
|
|
background-repeat: no-repeat;
|
|
background-size: 20px 20px;
|
|
background-position: 12px 50%;
|
|
background-color: #fff;
|
|
position: absolute;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
white-space: nowrap;
|
|
bottom: 132px;
|
|
padding: 0px 16px 0px 40px;
|
|
font-family: Roboto Regular, Helvetica Neue, sans-serif;
|
|
font-size: 14px;
|
|
color:#4285f4;
|
|
height: 36px;
|
|
line-height: 36px;
|
|
border-radius: 18px;
|
|
border: 1px solid #DADCE0;
|
|
}
|
|
|
|
#ar-button:active {
|
|
background-color: #E8EAED;
|
|
}
|
|
|
|
#ar-button:focus {
|
|
outline: none;
|
|
}
|
|
|
|
#ar-button:focus-visible {
|
|
outline: 1px solid #4285f4;
|
|
}
|
|
|
|
@keyframes circle {
|
|
from { transform: translateX(-50%) rotate(0deg) translateX(50px) rotate(0deg); }
|
|
to { transform: translateX(-50%) rotate(360deg) translateX(50px) rotate(-360deg); }
|
|
}
|
|
|
|
@keyframes elongate {
|
|
from { transform: translateX(100px); }
|
|
to { transform: translateX(-100px); }
|
|
}
|
|
|
|
model-viewer > #ar-prompt {
|
|
position: absolute;
|
|
left: 50%;
|
|
bottom: 175px;
|
|
animation: elongate 2s infinite ease-in-out alternate;
|
|
display: none;
|
|
}
|
|
|
|
model-viewer[ar-status="session-started"] > #ar-prompt {
|
|
display: block;
|
|
}
|
|
|
|
model-viewer > #ar-prompt > img {
|
|
animation: circle 4s linear infinite;
|
|
}
|
|
|
|
model-viewer > #ar-failure {
|
|
position: absolute;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
bottom: 175px;
|
|
display: none;
|
|
}
|
|
|
|
model-viewer[ar-tracking="not-tracking"] > #ar-failure {
|
|
display: block;
|
|
}
|
|
|
|
.slider {
|
|
width: 100%;
|
|
text-align: center;
|
|
overflow: hidden;
|
|
position: absolute;
|
|
bottom: 16px;
|
|
}
|
|
|
|
.slides {
|
|
display: flex;
|
|
overflow-x: auto;
|
|
scroll-snap-type: x mandatory;
|
|
scroll-behavior: smooth;
|
|
-webkit-overflow-scrolling: touch;
|
|
}
|
|
|
|
.slide {
|
|
scroll-snap-align: start;
|
|
flex-shrink: 0;
|
|
width: 100px;
|
|
height: 100px;
|
|
background-size: contain;
|
|
background-repeat: no-repeat;
|
|
background-position: center;
|
|
background-color: #fff;
|
|
margin-right: 10px;
|
|
border-radius: 10px;
|
|
border: none;
|
|
display: flex;
|
|
}
|
|
|
|
.slide.selected {
|
|
border: 2px solid #4285f4;
|
|
}
|
|
|
|
.slide:focus {
|
|
outline: none;
|
|
}
|
|
|
|
.slide:focus-visible {
|
|
outline: 1px solid #4285f4;
|
|
}
|
|
|
|
</style>
|
|
</template>
|
|
</example-snippet>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sample">
|
|
<div id="ar" class="demo"></div>
|
|
<div class="content">
|
|
<div class="wrapper">
|
|
<div class="heading">
|
|
<h2 class="demo-title">Augmented Reality</h2>
|
|
<h4>This demonstrates several augmented reality modes, including
|
|
<code>webxr</code>, <code>scene-viewer</code>,
|
|
<code>quick-look</code> & the accompanying attributes,
|
|
<code>ar</code>, <code>ar-scale</code>,
|
|
<code>ios-src</code>.</h4>
|
|
<p>
|
|
Note that WebXR mode requires the page be served on HTTPS and if
|
|
enclosed in an iframe, that iframe must allow your origin the
|
|
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/xr-spatial-tracking">
|
|
<code>xr-spatial-tracking</code></a> policy.
|
|
</p>
|
|
<p>
|
|
In this example an <code>ios-src</code> attribute is specified.
|
|
This requires an extra download, but can be useful if the
|
|
auto-generated USDZ is not adequate (for instance it does not
|
|
support animations yet). Also, this source can be either a .usdz
|
|
or a .reality file.
|
|
</p>
|
|
<p>
|
|
Additionally, <code>ar-scale="fixed"</code> is used to prevent the
|
|
user from scaling the object in AR, applying to all three AR
|
|
modes. The <code>xr-environment</code> attribute causes estimated
|
|
lighting to be used in the WebXR AR mode, rather than the lighting
|
|
from the 3D mode, but does not affect Quick Look or Scene Viewer.
|
|
</p>
|
|
</div>
|
|
<example-snippet stamp-to="ar" highlight-as="html">
|
|
<template>
|
|
<model-viewer src="../../shared-assets/models/Astronaut.glb" ar ar-scale="fixed" camera-controls touch-action="pan-y" alt="A 3D model of an astronaut" shadow-intensity="2" skybox-image="../../shared-assets/environments/spruit_sunrise_1k_HDR.jpg" skybox-height="2m" max-camera-orbit="auto 90deg auto" ios-src="../../shared-assets/models/Astronaut.usdz" xr-environment></model-viewer>
|
|
</template>
|
|
</example-snippet>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sample">
|
|
<div id="sceneViewer" class="demo"></div>
|
|
<div class="content">
|
|
<div class="wrapper">
|
|
<div class="heading">
|
|
<h2 class="demo-title">Scene Viewer</h2>
|
|
<h4>Here the Scene Viewer app is given priority, to make it easier to compare with the default WebXR, above. This also uses USDZ auto-generation for AR Quick Look on iOS, as compared to the separate ios-src file given above.</h4>
|
|
</div>
|
|
<example-snippet stamp-to="sceneViewer" highlight-as="html">
|
|
<template>
|
|
<model-viewer id="model-viewer" src="../../shared-assets/models/Astronaut.glb" ar ar-modes="scene-viewer quick-look" camera-controls touch-action="pan-y" alt="A 3D model of an astronaut" shadow-intensity="2" auto-rotate disable-pan skybox-image="../../shared-assets/environments/spruit_sunrise_1k_HDR.jpg" skybox-height="2m" max-camera-orbit="auto 90deg auto">
|
|
<div id="error" class="hide">AR is not supported on this device</div>
|
|
</model-viewer>
|
|
<script>
|
|
document.querySelector("#model-viewer").addEventListener('ar-status', (event) => {
|
|
if(event.detail.status === 'failed'){
|
|
const error = document.querySelector("#error");
|
|
error.classList.remove('hide');
|
|
error.addEventListener('transitionend',(event) => {
|
|
error.classList.add('hide');
|
|
});
|
|
}
|
|
});
|
|
</script>
|
|
<style>
|
|
#error {
|
|
background-color: #ffffffdd;
|
|
border-radius: 16px;
|
|
padding: 16px;
|
|
position: absolute;
|
|
left: 50%;
|
|
top: 50%;
|
|
transform: translate3d(-50%, -50%, 0);
|
|
transition: opacity 0.3s;
|
|
}
|
|
#error.hide {
|
|
opacity: 0;
|
|
visibility: hidden;
|
|
transition: visibility 2s, opacity 1s 1s;
|
|
}
|
|
</style>
|
|
</template>
|
|
</example-snippet>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sample">
|
|
<div id="wall" class="demo"></div>
|
|
<div class="content">
|
|
<div class="wrapper">
|
|
<div class="heading">
|
|
<h2 class="demo-title">Placing on a Wall</h2>
|
|
<h4>This demonstrates the <code>ar-placement</code> attribute, which defaults to "floor", but using "wall" gives a different AR placement experience.</h4>
|
|
</div>
|
|
<example-snippet stamp-to="wall" highlight-as="html">
|
|
<template>
|
|
<model-viewer src="../../assets/boom_2_.glb" ar ar-placement="wall" camera-controls touch-action="pan-y" alt="A 3D model of some wall art"></model-viewer>
|
|
</template>
|
|
</example-snippet>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sample">
|
|
<div id="customButton" class="demo"></div>
|
|
<div class="content">
|
|
<div class="wrapper">
|
|
<h4 id="intro"><span class="font-medium">Using Slots In <model-viewer>. </span>This page demonstrates how you can change parts of <model-viewer> using web component slots.</h4>
|
|
<div class="heading">
|
|
<h2 class="demo-title">Custom AR Button</h2>
|
|
<h4></h4>
|
|
</div>
|
|
<example-snippet stamp-to="customButton" highlight-as="html">
|
|
<template>
|
|
<model-viewer ar camera-controls touch-action="pan-y" auto-rotate src="../../shared-assets/models/Astronaut.glb" alt="A 3D model of an astronaut">
|
|
<button slot="ar-button" style="background-color: white; border-radius: 4px; border: none; position: absolute; top: 16px; right: 16px; ">
|
|
👋 Activate AR
|
|
</button>
|
|
</model-viewer>
|
|
</template>
|
|
</example-snippet>
|
|
|
|
<p>
|
|
Since this slot will only appear on an AR enabled device screenshots are provided below. They compare the <model-viewer> default button in the bottom right and a custom button ("👋 Activate AR") in the top right of the viewport, with a custom style.
|
|
</p>
|
|
|
|
<img class="eg-image" src="../../assets/eg-default-ar-button.jpg" alt="Image displaying the default model-viewer button of a box with slits cut out in the lower-right, next to the example astronaut model." />
|
|
<img class="eg-image" src="../../assets/eg-custom-ar-button.jpg" alt="Image displaying model-viewer with a custom button reading '👋 Activate AR'." / >
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sample">
|
|
<div id="transparentBackground" class="demo"></div>
|
|
<div class="content">
|
|
<div class="wrapper">
|
|
<div class="heading">
|
|
<h2 class="demo-title">Transparent Background</h2>
|
|
<h4></h4>
|
|
</div>
|
|
<example-snippet stamp-to="transparentBackground" highlight-as="html">
|
|
<template>
|
|
<div class="demo" style="background: linear-gradient(#ffffff, #ada996); overflow-x: hidden;">
|
|
<span style="position: absolute; text-align: center; font-size: 100px; line-height: 100px; left: 50%; transform: translateX(-50%);">Background<br>is visible<br>through<br>transparent<br>objects.</span>
|
|
<model-viewer camera-controls touch-action="pan-y" src="../../shared-assets/models/glTF-Sample-Assets/Models/ToyCar/glTF-Binary/ToyCar.glb" ar alt="A 3D transparency test" style="background-color: unset;"></model-viewer>
|
|
</div>
|
|
</template>
|
|
</example-snippet>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="footer">
|
|
<ul>
|
|
<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">
|
|
Chair, Mixer, GeoPlanter, ToyTrain, Canoe ©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://kaboomlaser.com/products/test">Laser Tree</a> by <a href="https://kaboomlaser.com/">Kaboomlaser</a>,
|
|
licensed under <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</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-augmentedreality'); })();
|
|
(() => { initFooterLinks();})();
|
|
</script>
|
|
|
|
<!-- Documentation-specific dependencies: -->
|
|
<script type="module"
|
|
src="../built/dependencies.js">
|
|
</script>
|
|
|
|
<!-- Loads <model-viewer> on modern browsers: -->
|
|
<script type="module"
|
|
src="../../../../node_modules/@google/model-viewer/dist/model-viewer.js">
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|