[automated] Updating /docs due to commit a73957a
Full commit hash is a73957a590
DOCS_ALLOW_DIRECT_EDITS
@@ -229,6 +229,14 @@ libaries often have README.md in their root to describe itself. We collect these
|
||||
book. In addition, client usage of Filament also requires using a set of binary tools, which are
|
||||
located in <code>tools</code>. Some of tools also have README.md as description. We also collect them into the book.</p>
|
||||
<p>The process for copying and processing these READMEs is outlined in <a href="#introductory-doc">Introductory docs</a>.</p>
|
||||
<h3 id="web-examples-and-tutorials"><a class="header" href="#web-examples-and-tutorials">Web Examples and Tutorials</a></h3>
|
||||
<p>Filament provides a number of WebGL tutorials and examples in the <code>web/</code> directory. These are compiled during the WebGL CMake build and are integrated into the documentation via <code>duplicates.json</code>. The process is entirely automated:</p>
|
||||
<ol>
|
||||
<li><code>run.py</code> maps the <code>.html</code> and <code>.md</code> WebGL outputs from the <code>out/cmake-webgl-release/...</code> directory into <code>docs_src/src_mdbook/src/samples/web/</code> using the instructions in <code>duplicates.json</code>.</li>
|
||||
<li>While transferring <code>.html</code> to <code>.md</code>, <code>run.py</code> strips away the <code><!DOCTYPE html></code>, <code><head></code>, and <code><html></code> tags. By retaining only the <code><style></code> and <code><body></code> elements, the HTML samples can be embedded cleanly into the <code>mdbook</code> site template without corrupting the DOM. It additionally collapses double-newlines (<code>\n\n</code>) because Markdown parsers will mistakenly fragment and wrap multi-line HTML tags into <code><p></code> blocks.</li>
|
||||
<li>After <code>mdbook build</code> concludes, <code>docs_src/build/copy_web_docs.py</code> is invoked. This script creates <code>web/lib</code> and <code>web/assets</code> directories inside the final <code>book/</code> output directory, copying in the compiled WebAssembly engine (<code>filament.wasm</code>/<code>filament.js</code>) and any necessary assets (<code>.filamat</code>, <code>.glb</code>, <code>.ktx</code>, etc.).</li>
|
||||
<li>Finally, <code>copy_web_docs.py</code> performs a regex pass over all HTML pages in <code>book/samples/web/</code> and <code>book/remote/</code> to rewrite their inline resource URLs to securely point to the shared <code>web/lib</code> and <code>web/assets</code> directories. It also dynamically overrides the <code>asset.loadResources()</code> Javascript call with an absolute URL (<code>new URL(..., window.location.href)</code>) so that <code>.glb</code>/<code>.gltf</code> assets fetch their internal <code>.bin</code> chunks correctly.</li>
|
||||
</ol>
|
||||
<h3 id="other-technical-notes"><a class="header" href="#other-technical-notes">Other technical notes</a></h3>
|
||||
<p>These are technical documents that do not fit into a library, tool, or directory of the
|
||||
Filament source tree. We collect them into the <code>docs_src/src_mdbook/src/notes</code> directory. No additional
|
||||
|
||||
BIN
docs/images/web_sample_animation.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
docs/images/web_sample_cube_fl0.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
docs/images/web_sample_helmet.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
docs/images/web_sample_morphing.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
docs/images/web_sample_parquet.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
docs/images/web_sample_redball.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
docs/images/web_sample_skinning.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
docs/images/web_sample_suzanne.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
docs/images/web_sample_triangle.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
@@ -165,7 +165,7 @@
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../samples/web.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../samples/web/skinning.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
@@ -179,7 +179,7 @@
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../samples/web.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../samples/web/skinning.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<title>Filament Remote</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1">
|
||||
<link href="../favicon.png" rel="icon" type="image/x-icon" />
|
||||
<link href="../web/assets/favicon.png" rel="icon" type="image/x-icon" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700" rel="stylesheet">
|
||||
<style>
|
||||
html, body {
|
||||
@@ -110,7 +110,7 @@ a:visited { color: rgb(26, 65, 78); }
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="filament.js"></script>
|
||||
<script src="../web/lib/filament.js"></script>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
@@ -517,7 +517,7 @@ _engine->getTransformManager().create(_triangle);
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../samples/web.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../samples/web/tutorials.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
@@ -531,7 +531,7 @@ _engine->getTransformManager().create(_triangle);
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../samples/web.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../samples/web/tutorials.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
285
docs/samples/web/animation.html
Normal file
@@ -0,0 +1,285 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>animation - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="shortcut icon" href="../../favicon.png">
|
||||
<link rel="stylesheet" href="../../css/variables.css">
|
||||
<link rel="stylesheet" href="../../css/general.css">
|
||||
<link rel="stylesheet" href="../../css/chrome.css">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../../fonts/fonts.css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../../highlight.css">
|
||||
<link rel="stylesheet" href="../../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
<!-- MathJax -->
|
||||
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
|
||||
<!-- Provide site root to javascript -->
|
||||
<script>
|
||||
var path_to_root = "../../";
|
||||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../../toc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body-container">
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
<script>
|
||||
try {
|
||||
var theme = localStorage.getItem('mdbook-theme');
|
||||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||
|
||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||
}
|
||||
|
||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||
}
|
||||
} catch (e) { }
|
||||
</script>
|
||||
|
||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||
<script>
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||
const html = document.documentElement;
|
||||
html.classList.remove('light')
|
||||
html.classList.add(theme);
|
||||
html.classList.add("js");
|
||||
</script>
|
||||
|
||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
<script>
|
||||
var sidebar = null;
|
||||
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||||
if (document.body.clientWidth >= 1080) {
|
||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||
sidebar = sidebar || 'visible';
|
||||
} else {
|
||||
sidebar = 'hidden';
|
||||
}
|
||||
sidebar_toggle.checked = sidebar === 'visible';
|
||||
html.classList.remove('sidebar-visible');
|
||||
html.classList.add("sidebar-" + sidebar);
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div style="display:flex;align-items:center;justify-content:center">
|
||||
<img class="flogo" src="../../images/filament_logo_small.png"></img>
|
||||
</div>
|
||||
<!-- populated by js -->
|
||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||||
<noscript>
|
||||
<iframe class="sidebar-iframe-outer" src="../../toc.html"></iframe>
|
||||
</noscript>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||||
<div class="sidebar-resize-indicator"></div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
||||
<div class="page">
|
||||
<div id="menu-bar-hover-placeholder"></div>
|
||||
<div id="menu-bar" class="menu-bar sticky">
|
||||
<div class="left-buttons">
|
||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||
<i class="fa fa-bars"></i>
|
||||
</label>
|
||||
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
|
||||
<!--
|
||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||
<i class="fa fa-paint-brush"></i>
|
||||
</button>
|
||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||
</ul>
|
||||
-->
|
||||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">Filament</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
|
||||
<i id="git-repository-button" class="fa fa-github"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-wrapper" class="hidden">
|
||||
<form id="searchbar-outer" class="searchbar-outer">
|
||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||
</form>
|
||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||
<div id="searchresults-header" class="searchresults-header"></div>
|
||||
<ul id="searchresults">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||
<script>
|
||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<style>
|
||||
body { margin: 0; overflow: hidden; }
|
||||
canvas { touch-action: none; width: 100%; height: 400px; border: 1px solid black; }
|
||||
</style>
|
||||
<p><canvas></canvas></p>
|
||||
<script src="../../web/lib/filament.js"></script>
|
||||
<script src="../../web/lib/gl-matrix-min.js"></script>
|
||||
<script>
|
||||
const mesh_url = "../../web/assets/animation/AnimatedTriangle.gltf";
|
||||
Filament.init([mesh_url], () => {
|
||||
window.gltfio = Filament.gltfio;
|
||||
window.Fov = Filament.Camera$Fov;
|
||||
window.LightType = Filament.LightManager$Type;
|
||||
window.app = new App(document.querySelector("canvas"));
|
||||
});
|
||||
class App {
|
||||
constructor(canvas) {
|
||||
this.canvas = canvas;
|
||||
const engine = this.engine = Filament.Engine.create(this.canvas);
|
||||
const scene = this.scene = engine.createScene();
|
||||
const loader = engine.createAssetLoader();
|
||||
const asset = this.asset = loader.createAsset(mesh_url);
|
||||
const sunlight = Filament.EntityManager.get().create();
|
||||
Filament.LightManager.Builder(LightType.SUN).direction([0, 0, -1]).build(engine, sunlight);
|
||||
this.scene.addEntity(sunlight);
|
||||
const onDone = () => {
|
||||
loader.delete();
|
||||
// Dynamically enable two-sided lighting for testing purposes.
|
||||
const entities = asset.getEntities();
|
||||
const rm = engine.getRenderableManager();
|
||||
const renderable = rm.getInstance(entities[0]);
|
||||
rm.getMaterialInstanceAt(renderable, 0).setDoubleSided(true)
|
||||
renderable.delete();
|
||||
scene.addEntities(entities);
|
||||
this.animator = asset.getInstance().getAnimator();
|
||||
this.animationStartTime = Date.now();
|
||||
};
|
||||
asset.loadResources(onDone, null, new URL('../../web/assets/animation/', window.location.href).href);
|
||||
this.swapChain = engine.createSwapChain();
|
||||
this.renderer = engine.createRenderer();
|
||||
this.camera = engine.createCamera(Filament.EntityManager.get().create());
|
||||
this.view = engine.createView();
|
||||
this.view.setCamera(this.camera);
|
||||
this.view.setScene(this.scene);
|
||||
this.renderer.setClearOptions({clearColor: [0.2, 0.3, 0.4, 1.0], clear: true});
|
||||
this.resize();
|
||||
this.render = this.render.bind(this);
|
||||
this.resize = this.resize.bind(this);
|
||||
window.addEventListener("resize", this.resize);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
render() {
|
||||
if (this.animator) {
|
||||
const ms = Date.now() - this.animationStartTime;
|
||||
this.animator.applyAnimation(0, ms / 1000);
|
||||
this.animator.updateBoneMatrices();
|
||||
}
|
||||
this.renderer.render(this.swapChain, this.view);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
resize() {
|
||||
const dpr = window.devicePixelRatio;
|
||||
const width = this.canvas.width = this.canvas.clientWidth * dpr;
|
||||
const height = this.canvas.height = this.canvas.clientHeight * dpr;
|
||||
this.view.setViewport([0, 0, width, height]);
|
||||
const eye = [0, 0, 5], center = [0, 0, 0], up = [0, 1, 0];
|
||||
this.camera.lookAt(eye, center, up);
|
||||
const aspect = width / height;
|
||||
const fov = aspect < 1 ? Fov.HORIZONTAL : Fov.VERTICAL;
|
||||
this.camera.setProjectionFov(30, aspect, 1.0, 20.0, fov);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../../samples/web/samples.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../samples/web/cube_fl0.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../../samples/web/samples.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../samples/web/cube_fl0.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
window.playground_copyable = true;
|
||||
</script>
|
||||
|
||||
|
||||
<script src="../../elasticlunr.min.js"></script>
|
||||
<script src="../../mark.min.js"></script>
|
||||
<script src="../../searcher.js"></script>
|
||||
|
||||
<script src="../../clipboard.min.js"></script>
|
||||
<script src="../../highlight.js"></script>
|
||||
<script src="../../book.js"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
359
docs/samples/web/cube_fl0.html
Normal file
@@ -0,0 +1,359 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>cube_fl0 - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="shortcut icon" href="../../favicon.png">
|
||||
<link rel="stylesheet" href="../../css/variables.css">
|
||||
<link rel="stylesheet" href="../../css/general.css">
|
||||
<link rel="stylesheet" href="../../css/chrome.css">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../../fonts/fonts.css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../../highlight.css">
|
||||
<link rel="stylesheet" href="../../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
<!-- MathJax -->
|
||||
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
|
||||
<!-- Provide site root to javascript -->
|
||||
<script>
|
||||
var path_to_root = "../../";
|
||||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../../toc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body-container">
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
<script>
|
||||
try {
|
||||
var theme = localStorage.getItem('mdbook-theme');
|
||||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||
|
||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||
}
|
||||
|
||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||
}
|
||||
} catch (e) { }
|
||||
</script>
|
||||
|
||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||
<script>
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||
const html = document.documentElement;
|
||||
html.classList.remove('light')
|
||||
html.classList.add(theme);
|
||||
html.classList.add("js");
|
||||
</script>
|
||||
|
||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
<script>
|
||||
var sidebar = null;
|
||||
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||||
if (document.body.clientWidth >= 1080) {
|
||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||
sidebar = sidebar || 'visible';
|
||||
} else {
|
||||
sidebar = 'hidden';
|
||||
}
|
||||
sidebar_toggle.checked = sidebar === 'visible';
|
||||
html.classList.remove('sidebar-visible');
|
||||
html.classList.add("sidebar-" + sidebar);
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div style="display:flex;align-items:center;justify-content:center">
|
||||
<img class="flogo" src="../../images/filament_logo_small.png"></img>
|
||||
</div>
|
||||
<!-- populated by js -->
|
||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||||
<noscript>
|
||||
<iframe class="sidebar-iframe-outer" src="../../toc.html"></iframe>
|
||||
</noscript>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||||
<div class="sidebar-resize-indicator"></div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
||||
<div class="page">
|
||||
<div id="menu-bar-hover-placeholder"></div>
|
||||
<div id="menu-bar" class="menu-bar sticky">
|
||||
<div class="left-buttons">
|
||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||
<i class="fa fa-bars"></i>
|
||||
</label>
|
||||
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
|
||||
<!--
|
||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||
<i class="fa fa-paint-brush"></i>
|
||||
</button>
|
||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||
</ul>
|
||||
-->
|
||||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">Filament</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
|
||||
<i id="git-repository-button" class="fa fa-github"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-wrapper" class="hidden">
|
||||
<form id="searchbar-outer" class="searchbar-outer">
|
||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||
</form>
|
||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||
<div id="searchresults-header" class="searchresults-header"></div>
|
||||
<ul id="searchresults">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||
<script>
|
||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
canvas {
|
||||
touch-action: none;
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
<p><canvas></canvas></p>
|
||||
<script src="../../web/lib/filament.js"></script>
|
||||
<script src="../../web/lib/gl-matrix-min.js"></script>
|
||||
<script>
|
||||
Filament.init(['../../web/assets/cube_fl0/nonlit_fl0.filamat'], () => {
|
||||
window.VertexAttribute = Filament.VertexAttribute;
|
||||
window.AttributeType = Filament.VertexBuffer$AttributeType;
|
||||
window.Projection = Filament.Camera$Projection;
|
||||
window.Fov = Filament.Camera$Fov;
|
||||
window.app = new App(document.getElementsByTagName('canvas')[0]);
|
||||
});
|
||||
class App {
|
||||
constructor(canvas) {
|
||||
this.canvas = canvas;
|
||||
const engine = this.engine = Filament.Engine.create(this.canvas, {}, { forceGLES2Context: true });
|
||||
console.log("Engine Config forceGLES2Context:", engine.getConfig().forceGLES2Context);
|
||||
this.scene = engine.createScene();
|
||||
this.cube = Filament.EntityManager.get().create();
|
||||
this.scene.addEntity(this.cube);
|
||||
const CUBE_POSITIONS = new Float32Array([
|
||||
// Front face
|
||||
-1.0, -1.0, 1.0,
|
||||
1.0, -1.0, 1.0,
|
||||
1.0, 1.0, 1.0,
|
||||
-1.0, 1.0, 1.0,
|
||||
// Back face
|
||||
-1.0, -1.0, -1.0,
|
||||
-1.0, 1.0, -1.0,
|
||||
1.0, 1.0, -1.0,
|
||||
1.0, -1.0, -1.0,
|
||||
// Top face
|
||||
-1.0, 1.0, -1.0,
|
||||
-1.0, 1.0, 1.0,
|
||||
1.0, 1.0, 1.0,
|
||||
1.0, 1.0, -1.0,
|
||||
// Bottom face
|
||||
-1.0, -1.0, -1.0,
|
||||
1.0, -1.0, -1.0,
|
||||
1.0, -1.0, 1.0,
|
||||
-1.0, -1.0, 1.0,
|
||||
// Right face
|
||||
1.0, -1.0, -1.0,
|
||||
1.0, 1.0, -1.0,
|
||||
1.0, 1.0, 1.0,
|
||||
1.0, -1.0, 1.0,
|
||||
// Left face
|
||||
-1.0, -1.0, -1.0,
|
||||
-1.0, -1.0, 1.0,
|
||||
-1.0, 1.0, 1.0,
|
||||
-1.0, 1.0, -1.0,
|
||||
]);
|
||||
const CUBE_COLORS = new Uint32Array([
|
||||
// Front face (red)
|
||||
0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff,
|
||||
// Back face (green)
|
||||
0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00,
|
||||
// Top face (blue)
|
||||
0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000,
|
||||
// Bottom face (yellow)
|
||||
0xff00ffff, 0xff00ffff, 0xff00ffff, 0xff00ffff,
|
||||
// Right face (magenta)
|
||||
0xffff00ff, 0xffff00ff, 0xffff00ff, 0xffff00ff,
|
||||
// Left face (cyan)
|
||||
0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00,
|
||||
]);
|
||||
const CUBE_INDICES = new Uint16Array([
|
||||
0, 1, 2, 0, 2, 3, // front
|
||||
4, 5, 6, 4, 6, 7, // back
|
||||
8, 9, 10, 8, 10, 11, // top
|
||||
12, 13, 14, 12, 14, 15, // bottom
|
||||
16, 17, 18, 16, 18, 19, // right
|
||||
20, 21, 22, 20, 22, 23, // left
|
||||
]);
|
||||
this.vb = Filament.VertexBuffer.Builder()
|
||||
.vertexCount(24)
|
||||
.bufferCount(2)
|
||||
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT3, 0, 12)
|
||||
.attribute(VertexAttribute.COLOR, 1, AttributeType.UBYTE4, 0, 4)
|
||||
.normalized(VertexAttribute.COLOR)
|
||||
.build(engine);
|
||||
this.vb.setBufferAt(engine, 0, CUBE_POSITIONS);
|
||||
this.vb.setBufferAt(engine, 1, CUBE_COLORS);
|
||||
this.ib = Filament.IndexBuffer.Builder()
|
||||
.indexCount(36)
|
||||
.bufferType(Filament.IndexBuffer$IndexType.USHORT)
|
||||
.build(engine);
|
||||
this.ib.setBuffer(engine, CUBE_INDICES);
|
||||
const mat = engine.createMaterial('../../web/assets/cube_fl0/nonlit_fl0.filamat');
|
||||
const matinst = mat.getDefaultInstance();
|
||||
Filament.RenderableManager.Builder(1)
|
||||
.boundingBox({ center: [-1, -1, -1], halfExtent: [1, 1, 1] })
|
||||
.material(0, matinst)
|
||||
.geometry(0, Filament.RenderableManager$PrimitiveType.TRIANGLES, this.vb, this.ib)
|
||||
.build(engine, this.cube);
|
||||
this.swapChain = engine.createSwapChain();
|
||||
this.renderer = engine.createRenderer();
|
||||
this.camera = engine.createCamera(Filament.EntityManager.get().create());
|
||||
this.view = engine.createView();
|
||||
this.view.setSampleCount(4);
|
||||
this.view.setCamera(this.camera);
|
||||
this.view.setScene(this.scene);
|
||||
this.view.setPostProcessingEnabled(false);
|
||||
this.renderer.setClearOptions({ clearColor: [0.0, 0.1, 0.2, 1.0], clear: true });
|
||||
this.resize();
|
||||
this.render = this.render.bind(this);
|
||||
this.resize = this.resize.bind(this);
|
||||
window.addEventListener('resize', this.resize);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
render() {
|
||||
const radians = Date.now() / 1000;
|
||||
// Combine rotations around Y and X axes for a spinning effect
|
||||
const transformY = mat4.fromRotation(mat4.create(), radians, [0, 1, 0]);
|
||||
const transformX = mat4.fromRotation(mat4.create(), radians * 0.5, [1, 0, 0]);
|
||||
const transform = mat4.multiply(mat4.create(), transformY, transformX);
|
||||
const tcm = this.engine.getTransformManager();
|
||||
const inst = tcm.getInstance(this.cube);
|
||||
tcm.setTransform(inst, transform);
|
||||
inst.delete();
|
||||
this.renderer.render(this.swapChain, this.view);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
resize() {
|
||||
const dpr = window.devicePixelRatio;
|
||||
const width = this.canvas.width = this.canvas.clientWidth * dpr;
|
||||
const height = this.canvas.height = this.canvas.clientHeight * dpr;
|
||||
this.view.setViewport([0, 0, width, height]);
|
||||
const eye = [0, 0, 5], center = [0, 0, 0], up = [0, 1, 0];
|
||||
this.camera.lookAt(eye, center, up);
|
||||
const aspect = width / height;
|
||||
const fov = aspect < 1 ? Fov.HORIZONTAL : Fov.VERTICAL;
|
||||
this.camera.setProjectionFov(90, aspect, 1.0, 10.0, fov);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../../samples/web/animation.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../samples/web/helmet.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../../samples/web/animation.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../samples/web/helmet.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
window.playground_copyable = true;
|
||||
</script>
|
||||
|
||||
|
||||
<script src="../../elasticlunr.min.js"></script>
|
||||
<script src="../../mark.min.js"></script>
|
||||
<script src="../../searcher.js"></script>
|
||||
|
||||
<script src="../../clipboard.min.js"></script>
|
||||
<script src="../../highlight.js"></script>
|
||||
<script src="../../book.js"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
360
docs/samples/web/helmet.html
Normal file
@@ -0,0 +1,360 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>helmet - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="shortcut icon" href="../../favicon.png">
|
||||
<link rel="stylesheet" href="../../css/variables.css">
|
||||
<link rel="stylesheet" href="../../css/general.css">
|
||||
<link rel="stylesheet" href="../../css/chrome.css">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../../fonts/fonts.css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../../highlight.css">
|
||||
<link rel="stylesheet" href="../../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
<!-- MathJax -->
|
||||
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
|
||||
<!-- Provide site root to javascript -->
|
||||
<script>
|
||||
var path_to_root = "../../";
|
||||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../../toc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body-container">
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
<script>
|
||||
try {
|
||||
var theme = localStorage.getItem('mdbook-theme');
|
||||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||
|
||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||
}
|
||||
|
||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||
}
|
||||
} catch (e) { }
|
||||
</script>
|
||||
|
||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||
<script>
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||
const html = document.documentElement;
|
||||
html.classList.remove('light')
|
||||
html.classList.add(theme);
|
||||
html.classList.add("js");
|
||||
</script>
|
||||
|
||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
<script>
|
||||
var sidebar = null;
|
||||
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||||
if (document.body.clientWidth >= 1080) {
|
||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||
sidebar = sidebar || 'visible';
|
||||
} else {
|
||||
sidebar = 'hidden';
|
||||
}
|
||||
sidebar_toggle.checked = sidebar === 'visible';
|
||||
html.classList.remove('sidebar-visible');
|
||||
html.classList.add("sidebar-" + sidebar);
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div style="display:flex;align-items:center;justify-content:center">
|
||||
<img class="flogo" src="../../images/filament_logo_small.png"></img>
|
||||
</div>
|
||||
<!-- populated by js -->
|
||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||||
<noscript>
|
||||
<iframe class="sidebar-iframe-outer" src="../../toc.html"></iframe>
|
||||
</noscript>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||||
<div class="sidebar-resize-indicator"></div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
||||
<div class="page">
|
||||
<div id="menu-bar-hover-placeholder"></div>
|
||||
<div id="menu-bar" class="menu-bar sticky">
|
||||
<div class="left-buttons">
|
||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||
<i class="fa fa-bars"></i>
|
||||
</label>
|
||||
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
|
||||
<!--
|
||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||
<i class="fa fa-paint-brush"></i>
|
||||
</button>
|
||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||
</ul>
|
||||
-->
|
||||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">Filament</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
|
||||
<i id="git-repository-button" class="fa fa-github"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-wrapper" class="hidden">
|
||||
<form id="searchbar-outer" class="searchbar-outer">
|
||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||
</form>
|
||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||
<div id="searchresults-header" class="searchresults-header"></div>
|
||||
<ul id="searchresults">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||
<script>
|
||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<style>
|
||||
#container { position: relative; width: 100%; height: 400px; border: 1px solid black; }
|
||||
canvas { position: absolute; width: 100%; height: 100%; touch-action: none; }
|
||||
#messages { position: absolute; width: 100%; height: 100%; padding-left: 10px; color:blue; pointer-events: none; overflow: hidden; }
|
||||
</style>
|
||||
<div id="container">
|
||||
<canvas></canvas>
|
||||
<pre id="messages"></pre>
|
||||
</div>
|
||||
<script src="../../web/lib/filament.js"></script>
|
||||
<script src="../../web/lib/gl-matrix-min.js"></script>
|
||||
<script src="../../web/lib/gltumble.min.js"></script>
|
||||
<script>
|
||||
const ibl_url = '../../web/assets/helmet/default_env/default_env_ibl.ktx';
|
||||
const sky_url = '../../web/assets/helmet/default_env/default_env_skybox.ktx';
|
||||
const mesh_url = '../../web/assets/helmet/FlightHelmet.gltf';
|
||||
Filament.init([mesh_url, ibl_url, sky_url], () => {
|
||||
window.gltfio = Filament.gltfio;
|
||||
window.Fov = Filament.Camera$Fov;
|
||||
window.LightType = Filament.LightManager$Type;
|
||||
window.IndirectLight = Filament.IndirectLight;
|
||||
window.app = new App(document.getElementsByTagName('canvas')[0]);
|
||||
});
|
||||
class App {
|
||||
constructor(canvas) {
|
||||
this.canvas = canvas;
|
||||
const engine = this.engine = Filament.Engine.create(this.canvas);
|
||||
const scene = this.scene = engine.createScene();
|
||||
this.trackball = new Trackball(canvas, {startSpin: 0.035});
|
||||
const messages = document.getElementById('messages');
|
||||
canvas.addEventListener('pointerdown', evt => {
|
||||
const x = evt.clientX;
|
||||
const y = this.canvas.getBoundingClientRect().height - 1 - evt.clientY;
|
||||
const dpr = window.devicePixelRatio;
|
||||
this.view.pick(x * dpr, y * dpr, (results) => {
|
||||
const name = this.asset.getName(results.renderable);
|
||||
messages.innerText = name ? ('Picked ' + name) : '';
|
||||
});
|
||||
});
|
||||
const indirectLight = this.ibl = engine.createIblFromKtx1(ibl_url);
|
||||
this.scene.setIndirectLight(indirectLight);
|
||||
const iblDirection = IndirectLight.getDirectionEstimate(indirectLight.shfloats);
|
||||
const iblColor = IndirectLight.getColorEstimate(indirectLight.shfloats, iblDirection);
|
||||
const iblIntensity = 20000;
|
||||
indirectLight.setIntensity(iblIntensity);
|
||||
// Rotate the IBL so that a bright light is behind the helmet, to show off bloom.
|
||||
const mat = [];
|
||||
const radians = 3.14;
|
||||
mat3.fromRotation(mat, radians, [0, 1, 0]);
|
||||
indirectLight.setRotation(mat);
|
||||
const skybox = engine.createSkyFromKtx1(sky_url);
|
||||
this.scene.setSkybox(skybox);
|
||||
const sunlight = Filament.EntityManager.get().create();
|
||||
Filament.LightManager.Builder(LightType.SUN)
|
||||
.color(iblColor.slice(0, 3))
|
||||
.intensity(iblColor[3] * iblIntensity)
|
||||
.direction(iblDirection)
|
||||
.sunAngularRadius(1.9)
|
||||
.castShadows(true)
|
||||
.sunHaloSize(10.0)
|
||||
.sunHaloFalloff(80.0)
|
||||
.build(engine, sunlight);
|
||||
this.scene.addEntity(sunlight);
|
||||
const loader = this.loader = engine.createAssetLoader();
|
||||
this.allowRefresh = false;
|
||||
const asset = this.asset = loader.createAsset(mesh_url);
|
||||
this.assetRoot = this.asset.getRoot();
|
||||
// Crudely indicate progress by printing the URI of each resource as it is loaded.
|
||||
const onFetched = (uri) => messages.innerText += `Downloaded ${uri}\n`;
|
||||
const onDone = () => {
|
||||
this.allowRefresh = true;
|
||||
// Clear the progress indication messages.
|
||||
messages.innerText = "";
|
||||
};
|
||||
asset.loadResources(onDone, onFetched, new URL('../../web/assets/helmet/', window.location.href).href);
|
||||
const cameraEntity = Filament.EntityManager.get().create();
|
||||
this.camera = engine.createCamera(cameraEntity);
|
||||
const colorGrading = Filament.ColorGrading.Builder()
|
||||
.toneMapping(Filament.ColorGrading$ToneMapping.ACES_LEGACY)
|
||||
.build(engine);
|
||||
this.swapChain = engine.createSwapChain();
|
||||
this.renderer = engine.createRenderer();
|
||||
this.view = engine.createView();
|
||||
this.view.setVignetteOptions({ midPoint: 0.8, enabled: true });
|
||||
this.view.setBloomOptions({ strength: 0.2, enabled: true });
|
||||
this.view.setCamera(this.camera);
|
||||
this.view.setScene(this.scene);
|
||||
this.view.setColorGrading(colorGrading);
|
||||
this.resize();
|
||||
this.render = this.render.bind(this);
|
||||
this.resize = this.resize.bind(this);
|
||||
this.refresh = this.refresh.bind(this);
|
||||
window.addEventListener('resize', this.resize);
|
||||
window.addEventListener('dblclick', this.refresh);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
// Test for memory leaks by destroying and recreating the asset.
|
||||
refresh() {
|
||||
if (!this.allowRefresh) {
|
||||
console.warn('Refresh not allowed while the model is still loading.');
|
||||
return;
|
||||
}
|
||||
console.info('Refreshing...');
|
||||
this.allowRefresh = false;
|
||||
this.scene.removeEntities(this.asset.getEntities());
|
||||
this.loader.destroyAsset(this.asset);
|
||||
this.asset = this.loader.createAsset(mesh_url);
|
||||
const onDone = () => { this.allowRefresh = true; }
|
||||
this.asset.loadResources(onDone, null, new URL('../../web/assets/helmet/', window.location.href).href);
|
||||
}
|
||||
render() {
|
||||
// Spin the model according to the trackball controller.
|
||||
const tcm = this.engine.getTransformManager();
|
||||
const inst = tcm.getInstance(this.assetRoot);
|
||||
tcm.setTransform(inst, this.trackball.getMatrix());
|
||||
inst.delete();
|
||||
// Gradually add renderables to the scene as their textures become ready.
|
||||
let entity;
|
||||
const popRenderable = () => {
|
||||
entity = this.asset.popRenderable();
|
||||
return entity.getId() != 0;
|
||||
}
|
||||
while (popRenderable()) {
|
||||
this.scene.addEntity(entity);
|
||||
entity.delete();
|
||||
}
|
||||
entity.delete();
|
||||
// Render the scene and request the next animation frame.
|
||||
if (this.renderer.beginFrame(this.swapChain)) {
|
||||
this.renderer.renderView(this.view);
|
||||
this.renderer.endFrame();
|
||||
}
|
||||
this.engine.execute();
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
resize() {
|
||||
const dpr = window.devicePixelRatio;
|
||||
const width = this.canvas.width = this.canvas.clientWidth * dpr;
|
||||
const height = this.canvas.height = this.canvas.clientHeight * dpr;
|
||||
this.view.setViewport([0, 0, width, height]);
|
||||
const y = -0.125, eye = [0, y, 2], center = [0, y, 0], up = [0, 1, 0];
|
||||
this.camera.lookAt(eye, center, up);
|
||||
const aspect = width / height;
|
||||
const fov = aspect < 1 ? Fov.HORIZONTAL : Fov.VERTICAL;
|
||||
this.camera.setProjectionFov(30, aspect, 1.0, 10.0, fov);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../../samples/web/cube_fl0.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../samples/web/morphing.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../../samples/web/cube_fl0.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../samples/web/morphing.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
window.playground_copyable = true;
|
||||
</script>
|
||||
|
||||
|
||||
<script src="../../elasticlunr.min.js"></script>
|
||||
<script src="../../mark.min.js"></script>
|
||||
<script src="../../searcher.js"></script>
|
||||
|
||||
<script src="../../clipboard.min.js"></script>
|
||||
<script src="../../highlight.js"></script>
|
||||
<script src="../../book.js"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
291
docs/samples/web/morphing.html
Normal file
@@ -0,0 +1,291 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>morphing - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="shortcut icon" href="../../favicon.png">
|
||||
<link rel="stylesheet" href="../../css/variables.css">
|
||||
<link rel="stylesheet" href="../../css/general.css">
|
||||
<link rel="stylesheet" href="../../css/chrome.css">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../../fonts/fonts.css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../../highlight.css">
|
||||
<link rel="stylesheet" href="../../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
<!-- MathJax -->
|
||||
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
|
||||
<!-- Provide site root to javascript -->
|
||||
<script>
|
||||
var path_to_root = "../../";
|
||||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../../toc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body-container">
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
<script>
|
||||
try {
|
||||
var theme = localStorage.getItem('mdbook-theme');
|
||||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||
|
||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||
}
|
||||
|
||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||
}
|
||||
} catch (e) { }
|
||||
</script>
|
||||
|
||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||
<script>
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||
const html = document.documentElement;
|
||||
html.classList.remove('light')
|
||||
html.classList.add(theme);
|
||||
html.classList.add("js");
|
||||
</script>
|
||||
|
||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
<script>
|
||||
var sidebar = null;
|
||||
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||||
if (document.body.clientWidth >= 1080) {
|
||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||
sidebar = sidebar || 'visible';
|
||||
} else {
|
||||
sidebar = 'hidden';
|
||||
}
|
||||
sidebar_toggle.checked = sidebar === 'visible';
|
||||
html.classList.remove('sidebar-visible');
|
||||
html.classList.add("sidebar-" + sidebar);
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div style="display:flex;align-items:center;justify-content:center">
|
||||
<img class="flogo" src="../../images/filament_logo_small.png"></img>
|
||||
</div>
|
||||
<!-- populated by js -->
|
||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||||
<noscript>
|
||||
<iframe class="sidebar-iframe-outer" src="../../toc.html"></iframe>
|
||||
</noscript>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||||
<div class="sidebar-resize-indicator"></div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
||||
<div class="page">
|
||||
<div id="menu-bar-hover-placeholder"></div>
|
||||
<div id="menu-bar" class="menu-bar sticky">
|
||||
<div class="left-buttons">
|
||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||
<i class="fa fa-bars"></i>
|
||||
</label>
|
||||
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
|
||||
<!--
|
||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||
<i class="fa fa-paint-brush"></i>
|
||||
</button>
|
||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||
</ul>
|
||||
-->
|
||||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">Filament</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
|
||||
<i id="git-repository-button" class="fa fa-github"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-wrapper" class="hidden">
|
||||
<form id="searchbar-outer" class="searchbar-outer">
|
||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||
</form>
|
||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||
<div id="searchresults-header" class="searchresults-header"></div>
|
||||
<ul id="searchresults">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||
<script>
|
||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<style>
|
||||
body { margin: 0; overflow: hidden; }
|
||||
canvas { touch-action: none; width: 100%; height: 400px; border: 1px solid black; }
|
||||
</style>
|
||||
<p><canvas></canvas></p>
|
||||
<script src="../../web/lib/filament.js"></script>
|
||||
<script src="../../web/lib/gl-matrix-min.js"></script>
|
||||
<script src="../../web/lib/gltumble.min.js"></script>
|
||||
<script>
|
||||
const mesh_url = "../../web/assets/morphing/AnimatedMorphCube.glb";
|
||||
const ibl_url = "../../web/assets/morphing/default_env/default_env_ibl.ktx";
|
||||
const sky_url = "../../web/assets/morphing/default_env/default_env_skybox.ktx";
|
||||
Filament.init([mesh_url, ibl_url, sky_url], () => {
|
||||
window.gltfio = Filament.gltfio;
|
||||
window.Fov = Filament.Camera$Fov;
|
||||
window.app = new App(document.querySelector("canvas"));
|
||||
});
|
||||
class App {
|
||||
constructor(canvas) {
|
||||
this.canvas = canvas;
|
||||
const engine = this.engine = Filament.Engine.create(this.canvas);
|
||||
const scene = this.scene = engine.createScene();
|
||||
const sunlight = Filament.EntityManager.get().create();
|
||||
Filament.LightManager.Builder(Filament.LightManager$Type.SUN).direction([0, 0, -1]).build(engine, sunlight);
|
||||
this.scene.addEntity(sunlight);
|
||||
const indirectLight = engine.createIblFromKtx1(ibl_url);
|
||||
indirectLight.setIntensity(50000);
|
||||
this.scene.setIndirectLight(indirectLight);
|
||||
const skybox = engine.createSkyFromKtx1(sky_url);
|
||||
this.scene.setSkybox(skybox);
|
||||
this.trackball = new Trackball(canvas, {startSpin: 0.035});
|
||||
const loader = engine.createAssetLoader();
|
||||
const asset = this.asset = loader.createAsset(mesh_url);
|
||||
const onDone = () => {
|
||||
loader.delete();
|
||||
scene.addEntities(asset.getEntities());
|
||||
this.animator = asset.getInstance().getAnimator();
|
||||
this.animationStartTime = Date.now();
|
||||
};
|
||||
asset.loadResources(onDone, null, new URL('../../web/assets/morphing/', window.location.href).href);
|
||||
this.swapChain = engine.createSwapChain();
|
||||
this.renderer = engine.createRenderer();
|
||||
this.camera = engine.createCamera(Filament.EntityManager.get().create());
|
||||
this.view = engine.createView();
|
||||
this.view.setCamera(this.camera);
|
||||
this.view.setScene(this.scene);
|
||||
this.renderer.setClearOptions({clearColor: [0.6, 0.6, 0.6, 1.0], clear: true});
|
||||
this.resize();
|
||||
this.render = this.render.bind(this);
|
||||
this.resize = this.resize.bind(this);
|
||||
window.addEventListener("resize", this.resize);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
render() {
|
||||
const tcm = this.engine.getTransformManager();
|
||||
const inst = tcm.getInstance(this.asset.getRoot());
|
||||
tcm.setTransform(inst, this.trackball.getMatrix());
|
||||
inst.delete();
|
||||
if (this.animator) {
|
||||
const ms = Date.now() - this.animationStartTime;
|
||||
this.animator.applyAnimation(0, ms / 1000);
|
||||
this.animator.updateBoneMatrices();
|
||||
}
|
||||
this.renderer.render(this.swapChain, this.view);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
resize() {
|
||||
const dpr = window.devicePixelRatio;
|
||||
const width = this.canvas.width = this.canvas.clientWidth * dpr;
|
||||
const height = this.canvas.height = this.canvas.clientHeight * dpr;
|
||||
this.view.setViewport([0, 0, width, height]);
|
||||
const eye = [0, 0, 5], center = [0, 0, 0], up = [0, 1, 0];
|
||||
this.camera.lookAt(eye, center, up);
|
||||
const aspect = width / height;
|
||||
const fov = aspect < 1 ? Fov.HORIZONTAL : Fov.VERTICAL;
|
||||
this.camera.setProjectionFov(30, aspect, 1.0, 20.0, fov);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../../samples/web/helmet.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../samples/web/parquet.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../../samples/web/helmet.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../samples/web/parquet.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
window.playground_copyable = true;
|
||||
</script>
|
||||
|
||||
|
||||
<script src="../../elasticlunr.min.js"></script>
|
||||
<script src="../../mark.min.js"></script>
|
||||
<script src="../../searcher.js"></script>
|
||||
|
||||
<script src="../../clipboard.min.js"></script>
|
||||
<script src="../../highlight.js"></script>
|
||||
<script src="../../book.js"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
312
docs/samples/web/parquet.html
Normal file
@@ -0,0 +1,312 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>parquet - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="shortcut icon" href="../../favicon.png">
|
||||
<link rel="stylesheet" href="../../css/variables.css">
|
||||
<link rel="stylesheet" href="../../css/general.css">
|
||||
<link rel="stylesheet" href="../../css/chrome.css">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../../fonts/fonts.css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../../highlight.css">
|
||||
<link rel="stylesheet" href="../../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
<!-- MathJax -->
|
||||
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
|
||||
<!-- Provide site root to javascript -->
|
||||
<script>
|
||||
var path_to_root = "../../";
|
||||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../../toc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body-container">
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
<script>
|
||||
try {
|
||||
var theme = localStorage.getItem('mdbook-theme');
|
||||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||
|
||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||
}
|
||||
|
||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||
}
|
||||
} catch (e) { }
|
||||
</script>
|
||||
|
||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||
<script>
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||
const html = document.documentElement;
|
||||
html.classList.remove('light')
|
||||
html.classList.add(theme);
|
||||
html.classList.add("js");
|
||||
</script>
|
||||
|
||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
<script>
|
||||
var sidebar = null;
|
||||
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||||
if (document.body.clientWidth >= 1080) {
|
||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||
sidebar = sidebar || 'visible';
|
||||
} else {
|
||||
sidebar = 'hidden';
|
||||
}
|
||||
sidebar_toggle.checked = sidebar === 'visible';
|
||||
html.classList.remove('sidebar-visible');
|
||||
html.classList.add("sidebar-" + sidebar);
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div style="display:flex;align-items:center;justify-content:center">
|
||||
<img class="flogo" src="../../images/filament_logo_small.png"></img>
|
||||
</div>
|
||||
<!-- populated by js -->
|
||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||||
<noscript>
|
||||
<iframe class="sidebar-iframe-outer" src="../../toc.html"></iframe>
|
||||
</noscript>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||||
<div class="sidebar-resize-indicator"></div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
||||
<div class="page">
|
||||
<div id="menu-bar-hover-placeholder"></div>
|
||||
<div id="menu-bar" class="menu-bar sticky">
|
||||
<div class="left-buttons">
|
||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||
<i class="fa fa-bars"></i>
|
||||
</label>
|
||||
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
|
||||
<!--
|
||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||
<i class="fa fa-paint-brush"></i>
|
||||
</button>
|
||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||
</ul>
|
||||
-->
|
||||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">Filament</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
|
||||
<i id="git-repository-button" class="fa fa-github"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-wrapper" class="hidden">
|
||||
<form id="searchbar-outer" class="searchbar-outer">
|
||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||
</form>
|
||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||
<div id="searchresults-header" class="searchresults-header"></div>
|
||||
<ul id="searchresults">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||
<script>
|
||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<style>
|
||||
body { margin: 0; overflow: hidden; }
|
||||
canvas { touch-action: none; width: 100%; height: 400px; border: 1px solid black; }
|
||||
</style>
|
||||
<p><canvas></canvas></p>
|
||||
<script src="../../web/lib/filament.js"></script>
|
||||
<script src="../../web/lib/gl-matrix-min.js"></script>
|
||||
<script>
|
||||
const iblfile = '../../web/assets/parquet/default_env/default_env_ibl.ktx';
|
||||
const skyfile = '../../web/assets/parquet/default_env/default_env_skybox.ktx';
|
||||
Filament.init([
|
||||
'../../web/assets/parquet/parquet.filamat',
|
||||
'../../web/assets/parquet/shader_ball.filamesh',
|
||||
'../../web/assets/parquet/floor_ao_roughness_metallic.png',
|
||||
'../../web/assets/parquet/floor_basecolor.jpg',
|
||||
'../../web/assets/parquet/floor_normal.png',
|
||||
iblfile, skyfile
|
||||
], () => {
|
||||
window.VertexAttribute = Filament.VertexAttribute;
|
||||
window.AttributeType = Filament.VertexBuffer$AttributeType;
|
||||
window.PrimitiveType = Filament.RenderableManager$PrimitiveType;
|
||||
window.IndexType = Filament.IndexBuffer$IndexType;
|
||||
window.Fov = Filament.Camera$Fov;
|
||||
window.LightType = Filament.LightManager$Type;
|
||||
window.app = new App(document.getElementsByTagName('canvas')[0]);
|
||||
});
|
||||
class App {
|
||||
constructor(canvas) {
|
||||
this.canvas = canvas;
|
||||
const engine = this.engine = Filament.Engine.create(this.canvas);
|
||||
this.scene = engine.createScene();
|
||||
const sunlight = Filament.EntityManager.get().create();
|
||||
Filament.LightManager.Builder(LightType.SUN)
|
||||
.color([0.98, 0.92, 0.89])
|
||||
.intensity(100000.0)
|
||||
.direction([0.6, -1.0, -0.8])
|
||||
.castShadows(true)
|
||||
.sunAngularRadius(1.9)
|
||||
.sunHaloSize(10.0)
|
||||
.sunHaloFalloff(80.0)
|
||||
.build(engine, sunlight);
|
||||
this.scene.addEntity(sunlight);
|
||||
const indirectLight = this.ibl = engine.createIblFromKtx1(iblfile);
|
||||
this.scene.setIndirectLight(indirectLight);
|
||||
const radians = 1.0;
|
||||
indirectLight.setRotation(mat3.fromRotation(mat3.create(), radians, [0, 1, 0]))
|
||||
indirectLight.setIntensity(10000);
|
||||
const skybox = engine.createSkyFromKtx1(skyfile);
|
||||
this.scene.setSkybox(skybox);
|
||||
const material = engine.createMaterial('../../web/assets/parquet/parquet.filamat');
|
||||
const matinstance = material.createInstance();
|
||||
const sampler = new Filament.TextureSampler(
|
||||
Filament.MinFilter.LINEAR_MIPMAP_LINEAR,
|
||||
Filament.MagFilter.LINEAR,
|
||||
Filament.WrapMode.REPEAT);
|
||||
const texargs = { usage: Filament.Texture$Usage.DEFAULT.value | Filament.Texture$Usage.GEN_MIPMAPPABLE.value };
|
||||
const ao = engine.createTextureFromPng('../../web/assets/parquet/floor_ao_roughness_metallic.png', texargs);
|
||||
const basecolor = engine.createTextureFromJpeg('../../web/assets/parquet/floor_basecolor.jpg', Object.assign({srgb: true}, texargs));
|
||||
const normal = engine.createTextureFromPng('../../web/assets/parquet/floor_normal.png', texargs);
|
||||
matinstance.setTextureParameter('aoRoughnessMetallic', ao, sampler)
|
||||
matinstance.setTextureParameter('baseColor', basecolor, sampler)
|
||||
matinstance.setTextureParameter('normal', normal, sampler)
|
||||
const mesh = engine.loadFilamesh('../../web/assets/parquet/shader_ball.filamesh', matinstance);
|
||||
this.shaderball = mesh.renderable;
|
||||
this.scene.addEntity(mesh.renderable);
|
||||
this.swapChain = engine.createSwapChain();
|
||||
this.renderer = engine.createRenderer();
|
||||
this.camera = engine.createCamera(Filament.EntityManager.get().create());
|
||||
this.view = engine.createView();
|
||||
this.view.setCamera(this.camera);
|
||||
this.view.setScene(this.scene);
|
||||
this.resize();
|
||||
this.render = this.render.bind(this);
|
||||
this.resize = this.resize.bind(this);
|
||||
window.addEventListener('resize', this.resize);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
render() {
|
||||
const radians = Date.now() / 1000;
|
||||
const transform = mat4.fromRotation(mat4.create(), radians, [0, 1, 0]);
|
||||
const tcm = this.engine.getTransformManager();
|
||||
const inst = tcm.getInstance(this.shaderball);
|
||||
tcm.setTransform(inst, transform);
|
||||
inst.delete();
|
||||
this.renderer.render(this.swapChain, this.view);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
resize() {
|
||||
const dpr = window.devicePixelRatio;
|
||||
const width = this.canvas.width = this.canvas.clientWidth * dpr;
|
||||
const height = this.canvas.height = this.canvas.clientHeight * dpr;
|
||||
this.view.setViewport([0, 0, width, height]);
|
||||
const eye = [0, 1.8, 5], center = [0, 1, -1], up = [0, 1, 0];
|
||||
this.camera.lookAt(eye, center, up);
|
||||
const aspect = width / height;
|
||||
const fov = aspect < 1 ? Fov.HORIZONTAL : Fov.VERTICAL;
|
||||
this.camera.setProjectionFov(45, aspect, 1.0, 10.0, fov);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../../samples/web/morphing.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../samples/web/skinning.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../../samples/web/morphing.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../samples/web/skinning.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
window.playground_copyable = true;
|
||||
</script>
|
||||
|
||||
|
||||
<script src="../../elasticlunr.min.js"></script>
|
||||
<script src="../../mark.min.js"></script>
|
||||
<script src="../../searcher.js"></script>
|
||||
|
||||
<script src="../../clipboard.min.js"></script>
|
||||
<script src="../../highlight.js"></script>
|
||||
<script src="../../book.js"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
651
docs/samples/web/redball.html
Normal file
@@ -0,0 +1,651 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>redball - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="shortcut icon" href="../../favicon.png">
|
||||
<link rel="stylesheet" href="../../css/variables.css">
|
||||
<link rel="stylesheet" href="../../css/general.css">
|
||||
<link rel="stylesheet" href="../../css/chrome.css">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../../fonts/fonts.css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../../highlight.css">
|
||||
<link rel="stylesheet" href="../../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
<!-- MathJax -->
|
||||
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
|
||||
<!-- Provide site root to javascript -->
|
||||
<script>
|
||||
var path_to_root = "../../";
|
||||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../../toc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body-container">
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
<script>
|
||||
try {
|
||||
var theme = localStorage.getItem('mdbook-theme');
|
||||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||
|
||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||
}
|
||||
|
||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||
}
|
||||
} catch (e) { }
|
||||
</script>
|
||||
|
||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||
<script>
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||
const html = document.documentElement;
|
||||
html.classList.remove('light')
|
||||
html.classList.add(theme);
|
||||
html.classList.add("js");
|
||||
</script>
|
||||
|
||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
<script>
|
||||
var sidebar = null;
|
||||
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||||
if (document.body.clientWidth >= 1080) {
|
||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||
sidebar = sidebar || 'visible';
|
||||
} else {
|
||||
sidebar = 'hidden';
|
||||
}
|
||||
sidebar_toggle.checked = sidebar === 'visible';
|
||||
html.classList.remove('sidebar-visible');
|
||||
html.classList.add("sidebar-" + sidebar);
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div style="display:flex;align-items:center;justify-content:center">
|
||||
<img class="flogo" src="../../images/filament_logo_small.png"></img>
|
||||
</div>
|
||||
<!-- populated by js -->
|
||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||||
<noscript>
|
||||
<iframe class="sidebar-iframe-outer" src="../../toc.html"></iframe>
|
||||
</noscript>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||||
<div class="sidebar-resize-indicator"></div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
||||
<div class="page">
|
||||
<div id="menu-bar-hover-placeholder"></div>
|
||||
<div id="menu-bar" class="menu-bar sticky">
|
||||
<div class="left-buttons">
|
||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||
<i class="fa fa-bars"></i>
|
||||
</label>
|
||||
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
|
||||
<!--
|
||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||
<i class="fa fa-paint-brush"></i>
|
||||
</button>
|
||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||
</ul>
|
||||
-->
|
||||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">Filament</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
|
||||
<i id="git-repository-button" class="fa fa-github"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-wrapper" class="hidden">
|
||||
<form id="searchbar-outer" class="searchbar-outer">
|
||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||
</form>
|
||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||
<div id="searchresults-header" class="searchresults-header"></div>
|
||||
<ul id="searchresults">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||
<script>
|
||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<div class="demo_frame" style="width:100%; height:400px; border: 1px solid black; position: relative;">
|
||||
<canvas id="demo-canvas" style="width:100%; height:100%; touch-action: none;"></canvas>
|
||||
</div>
|
||||
<script src="../../web/lib/filament.js"></script>
|
||||
<script src="../../web/lib/gl-matrix-min.js"></script>
|
||||
<script>
|
||||
// We wrap the demo code so it applies to demo-canvas instead of generic canvas
|
||||
(function() {
|
||||
const originalGetElementsByTagName = document.getElementsByTagName;
|
||||
document.getElementsByTagName = function(tag) {
|
||||
if (tag === 'canvas') return [document.getElementById('demo-canvas')];
|
||||
return originalGetElementsByTagName.call(document, tag);
|
||||
};
|
||||
//
|
||||
const ibl_url = '../../web/assets/redball/pillars_2k/pillars_2k_ibl.ktx';
|
||||
const sky_url = '../../web/assets/redball/pillars_2k/pillars_2k_skybox.ktx';
|
||||
const filamat_url = '../../web/assets/redball/plastic.filamat'
|
||||
//
|
||||
Filament.init([ filamat_url, ibl_url, sky_url ], () => {
|
||||
// Create some global aliases to enums for convenience.
|
||||
window.VertexAttribute = Filament.VertexAttribute;
|
||||
window.AttributeType = Filament.VertexBuffer$AttributeType;
|
||||
window.PrimitiveType = Filament.RenderableManager$PrimitiveType;
|
||||
window.IndexType = Filament.IndexBuffer$IndexType;
|
||||
window.Fov = Filament.Camera$Fov;
|
||||
window.LightType = Filament.LightManager$Type;
|
||||
//
|
||||
// Obtain the canvas DOM object and pass it to the App.
|
||||
const canvas = document.getElementsByTagName('canvas')[0];
|
||||
window.app = new App(canvas);
|
||||
} );
|
||||
//
|
||||
class App {
|
||||
constructor(canvas) {
|
||||
this.canvas = canvas;
|
||||
const engine = this.engine = Filament.Engine.create(canvas);
|
||||
const scene = engine.createScene();
|
||||
//
|
||||
const material = engine.createMaterial(filamat_url);
|
||||
const matinstance = material.createInstance();
|
||||
//
|
||||
const red = [0.8, 0.0, 0.0];
|
||||
matinstance.setColor3Parameter('baseColor', Filament.RgbType.sRGB, red);
|
||||
matinstance.setFloatParameter('roughness', 0.5);
|
||||
matinstance.setFloatParameter('clearCoat', 1.0);
|
||||
matinstance.setFloatParameter('clearCoatRoughness', 0.3);
|
||||
const renderable = Filament.EntityManager.get().create();
|
||||
scene.addEntity(renderable);
|
||||
//
|
||||
const icosphere = new Filament.IcoSphere(5);
|
||||
//
|
||||
const vb = Filament.VertexBuffer.Builder()
|
||||
.vertexCount(icosphere.vertices.length / 3)
|
||||
.bufferCount(2)
|
||||
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT3, 0, 0)
|
||||
.attribute(VertexAttribute.TANGENTS, 1, AttributeType.SHORT4, 0, 0)
|
||||
.normalized(VertexAttribute.TANGENTS)
|
||||
.build(engine);
|
||||
//
|
||||
const ib = Filament.IndexBuffer.Builder()
|
||||
.indexCount(icosphere.triangles.length)
|
||||
.bufferType(IndexType.USHORT)
|
||||
.build(engine);
|
||||
//
|
||||
vb.setBufferAt(engine, 0, icosphere.vertices);
|
||||
vb.setBufferAt(engine, 1, icosphere.tangents);
|
||||
ib.setBuffer(engine, icosphere.triangles);
|
||||
//
|
||||
Filament.RenderableManager.Builder(1)
|
||||
.boundingBox({ center: [-1, -1, -1], halfExtent: [1, 1, 1] })
|
||||
.material(0, matinstance)
|
||||
.geometry(0, PrimitiveType.TRIANGLES, vb, ib)
|
||||
.build(engine, renderable);
|
||||
const sunlight = Filament.EntityManager.get().create();
|
||||
scene.addEntity(sunlight);
|
||||
Filament.LightManager.Builder(LightType.SUN)
|
||||
.color([0.98, 0.92, 0.89])
|
||||
.intensity(110000.0)
|
||||
.direction([0.6, -1.0, -0.8])
|
||||
.sunAngularRadius(1.9)
|
||||
.sunHaloSize(10.0)
|
||||
.sunHaloFalloff(80.0)
|
||||
.build(engine, sunlight);
|
||||
//
|
||||
const backlight = Filament.EntityManager.get().create();
|
||||
scene.addEntity(backlight);
|
||||
Filament.LightManager.Builder(LightType.DIRECTIONAL)
|
||||
.direction([-1, 0, 1])
|
||||
.intensity(50000.0)
|
||||
.build(engine, backlight);
|
||||
const indirectLight = engine.createIblFromKtx1(ibl_url);
|
||||
indirectLight.setIntensity(50000);
|
||||
scene.setIndirectLight(indirectLight);
|
||||
const skybox = engine.createSkyFromKtx1(sky_url);
|
||||
scene.setSkybox(skybox);
|
||||
//
|
||||
this.swapChain = engine.createSwapChain();
|
||||
this.renderer = engine.createRenderer();
|
||||
this.camera = engine.createCamera(Filament.EntityManager.get().create());
|
||||
this.view = engine.createView();
|
||||
this.view.setCamera(this.camera);
|
||||
this.view.setScene(scene);
|
||||
this.resize();
|
||||
this.render = this.render.bind(this);
|
||||
this.resize = this.resize.bind(this);
|
||||
window.addEventListener('resize', this.resize);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
//
|
||||
render() {
|
||||
const eye = [0, 0, 4], center = [0, 0, 0], up = [0, 1, 0];
|
||||
const radians = Date.now() / 10000;
|
||||
vec3.rotateY(eye, eye, center, radians);
|
||||
this.camera.lookAt(eye, center, up);
|
||||
this.renderer.render(this.swapChain, this.view);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
//
|
||||
resize() {
|
||||
const dpr = window.devicePixelRatio;
|
||||
const width = this.canvas.width = this.canvas.clientWidth * dpr;
|
||||
const height = this.canvas.height = this.canvas.clientHeight * dpr;
|
||||
this.view.setViewport([0, 0, width, height]);
|
||||
this.camera.setProjectionFov(45, width / height, 1.0, 10.0, Fov.VERTICAL);
|
||||
}
|
||||
}
|
||||
//
|
||||
})();
|
||||
</script>
|
||||
<p>This tutorial will describe how to create the <strong>redball</strong> demo, introducing you to materials and
|
||||
textures.</p>
|
||||
<p>For starters, create a text file called <code>redball.html</code> and copy over the HTML that we used in the
|
||||
previous tutorial. Change the last script tag from <code>triangle.js</code> to <code>redball.js</code>.</p>
|
||||
<p>Next you'll need to get a couple command-line tools: <code>matc</code> and <code>cmgen</code>. You can find these in the
|
||||
appropriate <a href="//github.com/google/filament/releases">Filament release</a>. You should choose the
|
||||
archive that corresponds to your development machine rather than the one for web, and the version
|
||||
that matches the <code>unpkg.com/filament@x.x.x</code> url in the script tag of <code>redball.html</code> (you may check
|
||||
out the last available release of <a href="https://www.npmjs.com/package/filament">filament on npm</a>).</p>
|
||||
<h2 id="define-plastic-material"><a class="header" href="#define-plastic-material">Define plastic material</a></h2>
|
||||
<p>The <code>matc</code> tool consumes a text file containing a high-level description of a PBR material, and
|
||||
produces a binary material package that contains shader code and associated metadata. For more
|
||||
information, see the official document describing the <a href="https://google.github.io/filament/Materials.md.html">Filament Material System</a>.</p>
|
||||
<p>Let's try out <code>matc</code>. Create the following file in your favorite text editor and call it
|
||||
<code>plastic.mat</code>.</p>
|
||||
<pre><code class="language-text">material {
|
||||
name : Lit,
|
||||
shadingModel : lit,
|
||||
parameters : [
|
||||
{ type : float3, name : baseColor },
|
||||
{ type : float, name : roughness },
|
||||
{ type : float, name : clearCoat },
|
||||
{ type : float, name : clearCoatRoughness }
|
||||
],
|
||||
}
|
||||
|
||||
fragment {
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
material.baseColor.rgb = materialParams.baseColor;
|
||||
material.roughness = materialParams.roughness;
|
||||
material.clearCoat = materialParams.clearCoat;
|
||||
material.clearCoatRoughness = materialParams.clearCoatRoughness;
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>Next, invoke <code>matc</code> as follows.</p>
|
||||
<pre><code class="language-bash">matc -a opengl -p mobile -o plastic.filamat plastic.mat
|
||||
</code></pre>
|
||||
<p>You should now have a material archive in your working directory, which we'll use later in the
|
||||
tutorial.</p>
|
||||
<h2 id="bake-environment-map"><a class="header" href="#bake-environment-map">Bake environment map</a></h2>
|
||||
<p>Next we'll use Filament's <code>cmgen</code> tool to consume a HDR environment map in latlong format, and
|
||||
produce two cubemap files: a mipmapped IBL and a blurry skybox.</p>
|
||||
<p>Download <a href="//github.com/google/filament/blob/main/third_party/environments/pillars_2k.hdr">pillars_2k.hdr</a>, then invoke the following command in your terminal.</p>
|
||||
<pre><code class="language-bash">cmgen -x pillars_2k --format=ktx --size=256 --extract-blur=0.1 pillars_2k.hdr
|
||||
</code></pre>
|
||||
<p>You should now have a <code>pillars_2k</code> folder containing a couple KTX files for the IBL and skybox, as
|
||||
well as a text file with spherical harmonics coefficients. You can discard the text file because the
|
||||
IBL KTX contains these coefficients in its metadata.</p>
|
||||
<h2 id="create-javascript"><a class="header" href="#create-javascript">Create JavaScript</a></h2>
|
||||
<p>Next, create <code>redball.js</code> with the following content.</p>
|
||||
<pre><code class="language-js">const ibl_url = '../../web/assets/redball/pillars_2k/pillars_2k_ibl.ktx';
|
||||
const sky_url = '../../web/assets/redball/pillars_2k/pillars_2k_skybox.ktx';
|
||||
const filamat_url = '../../web/assets/redball/plastic.filamat'
|
||||
|
||||
Filament.init([ filamat_url, ibl_url, sky_url ], () => {
|
||||
// Create some global aliases to enums for convenience.
|
||||
window.VertexAttribute = Filament.VertexAttribute;
|
||||
window.AttributeType = Filament.VertexBuffer$AttributeType;
|
||||
window.PrimitiveType = Filament.RenderableManager$PrimitiveType;
|
||||
window.IndexType = Filament.IndexBuffer$IndexType;
|
||||
window.Fov = Filament.Camera$Fov;
|
||||
window.LightType = Filament.LightManager$Type;
|
||||
|
||||
// Obtain the canvas DOM object and pass it to the App.
|
||||
const canvas = document.getElementsByTagName('canvas')[0];
|
||||
window.app = new App(canvas);
|
||||
} );
|
||||
|
||||
class App {
|
||||
constructor(canvas) {
|
||||
this.canvas = canvas;
|
||||
const engine = this.engine = Filament.Engine.create(canvas);
|
||||
const scene = engine.createScene();
|
||||
|
||||
const material = engine.createMaterial(filamat_url);
|
||||
const matinstance = material.createInstance();
|
||||
|
||||
const red = [0.8, 0.0, 0.0];
|
||||
matinstance.setColor3Parameter('baseColor', Filament.RgbType.sRGB, red);
|
||||
matinstance.setFloatParameter('roughness', 0.5);
|
||||
matinstance.setFloatParameter('clearCoat', 1.0);
|
||||
matinstance.setFloatParameter('clearCoatRoughness', 0.3);
|
||||
const renderable = Filament.EntityManager.get().create();
|
||||
scene.addEntity(renderable);
|
||||
|
||||
const icosphere = new Filament.IcoSphere(5);
|
||||
|
||||
const vb = Filament.VertexBuffer.Builder()
|
||||
.vertexCount(icosphere.vertices.length / 3)
|
||||
.bufferCount(2)
|
||||
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT3, 0, 0)
|
||||
.attribute(VertexAttribute.TANGENTS, 1, AttributeType.SHORT4, 0, 0)
|
||||
.normalized(VertexAttribute.TANGENTS)
|
||||
.build(engine);
|
||||
|
||||
const ib = Filament.IndexBuffer.Builder()
|
||||
.indexCount(icosphere.triangles.length)
|
||||
.bufferType(IndexType.USHORT)
|
||||
.build(engine);
|
||||
|
||||
vb.setBufferAt(engine, 0, icosphere.vertices);
|
||||
vb.setBufferAt(engine, 1, icosphere.tangents);
|
||||
ib.setBuffer(engine, icosphere.triangles);
|
||||
|
||||
Filament.RenderableManager.Builder(1)
|
||||
.boundingBox({ center: [-1, -1, -1], halfExtent: [1, 1, 1] })
|
||||
.material(0, matinstance)
|
||||
.geometry(0, PrimitiveType.TRIANGLES, vb, ib)
|
||||
.build(engine, renderable);
|
||||
const sunlight = Filament.EntityManager.get().create();
|
||||
scene.addEntity(sunlight);
|
||||
Filament.LightManager.Builder(LightType.SUN)
|
||||
.color([0.98, 0.92, 0.89])
|
||||
.intensity(110000.0)
|
||||
.direction([0.6, -1.0, -0.8])
|
||||
.sunAngularRadius(1.9)
|
||||
.sunHaloSize(10.0)
|
||||
.sunHaloFalloff(80.0)
|
||||
.build(engine, sunlight);
|
||||
|
||||
const backlight = Filament.EntityManager.get().create();
|
||||
scene.addEntity(backlight);
|
||||
Filament.LightManager.Builder(LightType.DIRECTIONAL)
|
||||
.direction([-1, 0, 1])
|
||||
.intensity(50000.0)
|
||||
.build(engine, backlight);
|
||||
const indirectLight = engine.createIblFromKtx1(ibl_url);
|
||||
indirectLight.setIntensity(50000);
|
||||
scene.setIndirectLight(indirectLight);
|
||||
const skybox = engine.createSkyFromKtx1(sky_url);
|
||||
scene.setSkybox(skybox);
|
||||
|
||||
this.swapChain = engine.createSwapChain();
|
||||
this.renderer = engine.createRenderer();
|
||||
this.camera = engine.createCamera(Filament.EntityManager.get().create());
|
||||
this.view = engine.createView();
|
||||
this.view.setCamera(this.camera);
|
||||
this.view.setScene(scene);
|
||||
this.resize();
|
||||
this.render = this.render.bind(this);
|
||||
this.resize = this.resize.bind(this);
|
||||
window.addEventListener('resize', this.resize);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
|
||||
render() {
|
||||
const eye = [0, 0, 4], center = [0, 0, 0], up = [0, 1, 0];
|
||||
const radians = Date.now() / 10000;
|
||||
vec3.rotateY(eye, eye, center, radians);
|
||||
this.camera.lookAt(eye, center, up);
|
||||
this.renderer.render(this.swapChain, this.view);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
|
||||
resize() {
|
||||
const dpr = window.devicePixelRatio;
|
||||
const width = this.canvas.width = this.canvas.clientWidth * dpr;
|
||||
const height = this.canvas.height = this.canvas.clientHeight * dpr;
|
||||
this.view.setViewport([0, 0, width, height]);
|
||||
this.camera.setProjectionFov(45, width / height, 1.0, 10.0, Fov.VERTICAL);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>The above boilerplate should be familiar to you from the previous tutorial, although it loads in a
|
||||
new set of assets. We also added some animation to the camera.</p>
|
||||
<p>Next let's create a material instance from the package that we built at the beginning the tutorial.
|
||||
Replace the <strong>create material</strong> comment with the following snippet.</p>
|
||||
<pre><code class="language-js">const material = engine.createMaterial(filamat_url);
|
||||
const matinstance = material.createInstance();
|
||||
|
||||
const red = [0.8, 0.0, 0.0];
|
||||
matinstance.setColor3Parameter('baseColor', Filament.RgbType.sRGB, red);
|
||||
matinstance.setFloatParameter('roughness', 0.5);
|
||||
matinstance.setFloatParameter('clearCoat', 1.0);
|
||||
matinstance.setFloatParameter('clearCoatRoughness', 0.3);
|
||||
</code></pre>
|
||||
<p>The next step is to create a renderable for the sphere. To help with this, we'll use the <code>IcoSphere</code>
|
||||
utility class, whose constructor takes a LOD. Its job is to subdivide an icosadedron, producing
|
||||
three arrays:</p>
|
||||
<ul>
|
||||
<li><code>icosphere.vertices</code> Float32Array of XYZ coordinates.</li>
|
||||
<li><code>icosphere.tangents</code> Uint16Array (interpreted as half-floats) encoding the surface orientation
|
||||
as quaternions.</li>
|
||||
<li><code>icosphere.triangles</code> Uint16Array with triangle indices.</li>
|
||||
</ul>
|
||||
<p>Let's go ahead use these arrays to build the vertex buffer and index buffer. Replace <strong>create
|
||||
sphere</strong> with the following snippet.</p>
|
||||
<pre><code class="language-js">const renderable = Filament.EntityManager.get().create();
|
||||
scene.addEntity(renderable);
|
||||
|
||||
const icosphere = new Filament.IcoSphere(5);
|
||||
|
||||
const vb = Filament.VertexBuffer.Builder()
|
||||
.vertexCount(icosphere.vertices.length / 3)
|
||||
.bufferCount(2)
|
||||
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT3, 0, 0)
|
||||
.attribute(VertexAttribute.TANGENTS, 1, AttributeType.SHORT4, 0, 0)
|
||||
.normalized(VertexAttribute.TANGENTS)
|
||||
.build(engine);
|
||||
|
||||
const ib = Filament.IndexBuffer.Builder()
|
||||
.indexCount(icosphere.triangles.length)
|
||||
.bufferType(IndexType.USHORT)
|
||||
.build(engine);
|
||||
|
||||
vb.setBufferAt(engine, 0, icosphere.vertices);
|
||||
vb.setBufferAt(engine, 1, icosphere.tangents);
|
||||
ib.setBuffer(engine, icosphere.triangles);
|
||||
|
||||
Filament.RenderableManager.Builder(1)
|
||||
.boundingBox({ center: [-1, -1, -1], halfExtent: [1, 1, 1] })
|
||||
.material(0, matinstance)
|
||||
.geometry(0, PrimitiveType.TRIANGLES, vb, ib)
|
||||
.build(engine, renderable);
|
||||
</code></pre>
|
||||
<p>At this point, the app is rendering a sphere, but it is black so it doesn't show up. To prove that
|
||||
the sphere is there, you can try changing the background color to blue via <code>setClearColor</code>, like we
|
||||
did in the first tutorial.</p>
|
||||
<h2 id="add-lighting"><a class="header" href="#add-lighting">Add lighting</a></h2>
|
||||
<p>In this section we will create some directional light sources, as well as an image-based light (IBL)
|
||||
defined by one of the KTX files we built at the start of the demo. First, replace the <strong>create
|
||||
lights</strong> comment with the following snippet.</p>
|
||||
<pre><code class="language-js">const sunlight = Filament.EntityManager.get().create();
|
||||
scene.addEntity(sunlight);
|
||||
Filament.LightManager.Builder(LightType.SUN)
|
||||
.color([0.98, 0.92, 0.89])
|
||||
.intensity(110000.0)
|
||||
.direction([0.6, -1.0, -0.8])
|
||||
.sunAngularRadius(1.9)
|
||||
.sunHaloSize(10.0)
|
||||
.sunHaloFalloff(80.0)
|
||||
.build(engine, sunlight);
|
||||
|
||||
const backlight = Filament.EntityManager.get().create();
|
||||
scene.addEntity(backlight);
|
||||
Filament.LightManager.Builder(LightType.DIRECTIONAL)
|
||||
.direction([-1, 0, 1])
|
||||
.intensity(50000.0)
|
||||
.build(engine, backlight);
|
||||
</code></pre>
|
||||
<p>The <code>SUN</code> light source is similar to the <code>DIRECTIONAL</code> light source, but has some extra
|
||||
parameters because Filament will automatically draw a disk into the skybox.</p>
|
||||
<p>Next we need to create an <code>IndirectLight</code> object from the KTX IBL. One way of doing this is the
|
||||
following (don't type this out, there's an easier way).</p>
|
||||
<pre><code class="language-js">const format = Filament.PixelDataFormat.RGB;
|
||||
const datatype = Filament.PixelDataType.UINT_10F_11F_11F_REV;
|
||||
|
||||
// Create a Texture object for the mipmapped cubemap.
|
||||
const ibl_package = Filament.Buffer(Filament.assets[ibl_url]);
|
||||
const iblktx = new Filament.Ktx1Bundle(ibl_package);
|
||||
|
||||
const ibltex = Filament.Texture.Builder()
|
||||
.width(iblktx.info().pixelWidth)
|
||||
.height(iblktx.info().pixelHeight)
|
||||
.levels(iblktx.getNumMipLevels())
|
||||
.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)
|
||||
.format(Filament.Texture$InternalFormat.RGBA8)
|
||||
.build(engine);
|
||||
|
||||
for (let level = 0; level < iblktx.getNumMipLevels(); ++level) {
|
||||
const uint8array = iblktx.getCubeBlob(level).getBytes();
|
||||
const pixelbuffer = Filament.PixelBuffer(uint8array, format, datatype);
|
||||
ibltex.setImageCube(engine, level, pixelbuffer);
|
||||
}
|
||||
|
||||
// Parse the spherical harmonics metadata.
|
||||
const shstring = iblktx.getMetadata('sh');
|
||||
const shfloats = shstring.split(/\s/, 9 * 3).map(parseFloat);
|
||||
|
||||
// Build the IBL object and insert it into the scene.
|
||||
const indirectLight = Filament.IndirectLight.Builder()
|
||||
.reflections(ibltex)
|
||||
.irradianceSh(3, shfloats)
|
||||
.intensity(50000.0)
|
||||
.build(engine);
|
||||
|
||||
scene.setIndirectLight(indirectLight);
|
||||
</code></pre>
|
||||
<p>Filament provides a JavaScript utility to make this simpler,
|
||||
simply replace the <strong>create IBL</strong> comment with the following snippet.</p>
|
||||
<pre><code class="language-js">const indirectLight = engine.createIblFromKtx1(ibl_url);
|
||||
indirectLight.setIntensity(50000);
|
||||
scene.setIndirectLight(indirectLight);
|
||||
</code></pre>
|
||||
<h2 id="add-background"><a class="header" href="#add-background">Add background</a></h2>
|
||||
<p>At this point you can run the demo and you should see a red plastic ball against a black background.
|
||||
Without a skybox, the reflections on the ball are not representative of its surroundings.
|
||||
Here's one way to create a texture for the skybox:</p>
|
||||
<pre><code class="language-js">const sky_package = Filament.Buffer(Filament.assets[sky_url]);
|
||||
const skyktx = new Filament.Ktx1Bundle(sky_package);
|
||||
const skytex = Filament.Texture.Builder()
|
||||
.width(skyktx.info().pixelWidth)
|
||||
.height(skyktx.info().pixelHeight)
|
||||
.levels(1)
|
||||
.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)
|
||||
.format(Filament.Texture$InternalFormat.RGBA8)
|
||||
.build(engine);
|
||||
|
||||
const uint8array = skyktx.getCubeBlob(0).getBytes();
|
||||
const pixelbuffer = Filament.PixelBuffer(uint8array, format, datatype);
|
||||
skytex.setImageCube(engine, 0, pixelbuffer);
|
||||
</code></pre>
|
||||
<p>Filament provides a Javascript utility to make this easier.
|
||||
Replace <strong>create skybox</strong> with the following.</p>
|
||||
<pre><code class="language-js">const skybox = engine.createSkyFromKtx1(sky_url);
|
||||
scene.setSkybox(skybox);
|
||||
</code></pre>
|
||||
<p>That's it, we now have a shiny red ball floating in an environment!</p>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../../samples/web/triangle.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../samples/web/suzanne.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../../samples/web/triangle.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../samples/web/suzanne.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
window.playground_copyable = true;
|
||||
</script>
|
||||
|
||||
|
||||
<script src="../../elasticlunr.min.js"></script>
|
||||
<script src="../../mark.min.js"></script>
|
||||
<script src="../../searcher.js"></script>
|
||||
|
||||
<script src="../../clipboard.min.js"></script>
|
||||
<script src="../../highlight.js"></script>
|
||||
<script src="../../book.js"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
274
docs/samples/web/samples.html
Normal file
@@ -0,0 +1,274 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>Web Samples - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="shortcut icon" href="../../favicon.png">
|
||||
<link rel="stylesheet" href="../../css/variables.css">
|
||||
<link rel="stylesheet" href="../../css/general.css">
|
||||
<link rel="stylesheet" href="../../css/chrome.css">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../../fonts/fonts.css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../../highlight.css">
|
||||
<link rel="stylesheet" href="../../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
<!-- MathJax -->
|
||||
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
|
||||
<!-- Provide site root to javascript -->
|
||||
<script>
|
||||
var path_to_root = "../../";
|
||||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../../toc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body-container">
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
<script>
|
||||
try {
|
||||
var theme = localStorage.getItem('mdbook-theme');
|
||||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||
|
||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||
}
|
||||
|
||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||
}
|
||||
} catch (e) { }
|
||||
</script>
|
||||
|
||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||
<script>
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||
const html = document.documentElement;
|
||||
html.classList.remove('light')
|
||||
html.classList.add(theme);
|
||||
html.classList.add("js");
|
||||
</script>
|
||||
|
||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
<script>
|
||||
var sidebar = null;
|
||||
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||||
if (document.body.clientWidth >= 1080) {
|
||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||
sidebar = sidebar || 'visible';
|
||||
} else {
|
||||
sidebar = 'hidden';
|
||||
}
|
||||
sidebar_toggle.checked = sidebar === 'visible';
|
||||
html.classList.remove('sidebar-visible');
|
||||
html.classList.add("sidebar-" + sidebar);
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div style="display:flex;align-items:center;justify-content:center">
|
||||
<img class="flogo" src="../../images/filament_logo_small.png"></img>
|
||||
</div>
|
||||
<!-- populated by js -->
|
||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||||
<noscript>
|
||||
<iframe class="sidebar-iframe-outer" src="../../toc.html"></iframe>
|
||||
</noscript>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||||
<div class="sidebar-resize-indicator"></div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
||||
<div class="page">
|
||||
<div id="menu-bar-hover-placeholder"></div>
|
||||
<div id="menu-bar" class="menu-bar sticky">
|
||||
<div class="left-buttons">
|
||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||
<i class="fa fa-bars"></i>
|
||||
</label>
|
||||
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
|
||||
<!--
|
||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||
<i class="fa fa-paint-brush"></i>
|
||||
</button>
|
||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||
</ul>
|
||||
-->
|
||||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">Filament</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
|
||||
<i id="git-repository-button" class="fa fa-github"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-wrapper" class="hidden">
|
||||
<form id="searchbar-outer" class="searchbar-outer">
|
||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||
</form>
|
||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||
<div id="searchresults-header" class="searchresults-header"></div>
|
||||
<ul id="searchresults">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||
<script>
|
||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<h1 id="web-samples"><a class="header" href="#web-samples">Web Samples</a></h1>
|
||||
<p>Here are some additional standalone examples demonstrating Filament's capabilities in WebGL:</p>
|
||||
<style>
|
||||
.sample-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
|
||||
gap: 20px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.sample-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
border: 1px solid var(--sidebar-bg);
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
background-color: var(--bg);
|
||||
}
|
||||
.sample-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
||||
text-decoration: none;
|
||||
}
|
||||
.sample-card img {
|
||||
border-radius: 4px;
|
||||
margin-bottom: 10px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
</style>
|
||||
<div class="sample-grid">
|
||||
<a href="animation.html" class="sample-card">
|
||||
<img src="../../images/web_sample_animation.png" alt="animation" />
|
||||
<span>animation</span>
|
||||
</a>
|
||||
<a href="cube_fl0.html" class="sample-card">
|
||||
<img src="../../images/web_sample_cube_fl0.png" alt="cube_fl0" />
|
||||
<span>cube_fl0</span>
|
||||
</a>
|
||||
<a href="helmet.html" class="sample-card">
|
||||
<img src="../../images/web_sample_helmet.png" alt="helmet" />
|
||||
<span>helmet</span>
|
||||
</a>
|
||||
<a href="morphing.html" class="sample-card">
|
||||
<img src="../../images/web_sample_morphing.png" alt="morphing" />
|
||||
<span>morphing</span>
|
||||
</a>
|
||||
<a href="parquet.html" class="sample-card">
|
||||
<img src="../../images/web_sample_parquet.png" alt="parquet" />
|
||||
<span>parquet</span>
|
||||
</a>
|
||||
<a href="skinning.html" class="sample-card">
|
||||
<img src="../../images/web_sample_skinning.png" alt="skinning" />
|
||||
<span>skinning</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../../samples/web/suzanne.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../samples/web/animation.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../../samples/web/suzanne.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../samples/web/animation.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
window.playground_copyable = true;
|
||||
</script>
|
||||
|
||||
|
||||
<script src="../../elasticlunr.min.js"></script>
|
||||
<script src="../../mark.min.js"></script>
|
||||
<script src="../../searcher.js"></script>
|
||||
|
||||
<script src="../../clipboard.min.js"></script>
|
||||
<script src="../../highlight.js"></script>
|
||||
<script src="../../book.js"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
357
docs/samples/web/skinning.html
Normal file
@@ -0,0 +1,357 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>skinning - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="shortcut icon" href="../../favicon.png">
|
||||
<link rel="stylesheet" href="../../css/variables.css">
|
||||
<link rel="stylesheet" href="../../css/general.css">
|
||||
<link rel="stylesheet" href="../../css/chrome.css">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../../fonts/fonts.css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../../highlight.css">
|
||||
<link rel="stylesheet" href="../../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
<!-- MathJax -->
|
||||
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
|
||||
<!-- Provide site root to javascript -->
|
||||
<script>
|
||||
var path_to_root = "../../";
|
||||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../../toc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body-container">
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
<script>
|
||||
try {
|
||||
var theme = localStorage.getItem('mdbook-theme');
|
||||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||
|
||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||
}
|
||||
|
||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||
}
|
||||
} catch (e) { }
|
||||
</script>
|
||||
|
||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||
<script>
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||
const html = document.documentElement;
|
||||
html.classList.remove('light')
|
||||
html.classList.add(theme);
|
||||
html.classList.add("js");
|
||||
</script>
|
||||
|
||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
<script>
|
||||
var sidebar = null;
|
||||
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||||
if (document.body.clientWidth >= 1080) {
|
||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||
sidebar = sidebar || 'visible';
|
||||
} else {
|
||||
sidebar = 'hidden';
|
||||
}
|
||||
sidebar_toggle.checked = sidebar === 'visible';
|
||||
html.classList.remove('sidebar-visible');
|
||||
html.classList.add("sidebar-" + sidebar);
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div style="display:flex;align-items:center;justify-content:center">
|
||||
<img class="flogo" src="../../images/filament_logo_small.png"></img>
|
||||
</div>
|
||||
<!-- populated by js -->
|
||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||||
<noscript>
|
||||
<iframe class="sidebar-iframe-outer" src="../../toc.html"></iframe>
|
||||
</noscript>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||||
<div class="sidebar-resize-indicator"></div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
||||
<div class="page">
|
||||
<div id="menu-bar-hover-placeholder"></div>
|
||||
<div id="menu-bar" class="menu-bar sticky">
|
||||
<div class="left-buttons">
|
||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||
<i class="fa fa-bars"></i>
|
||||
</label>
|
||||
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
|
||||
<!--
|
||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||
<i class="fa fa-paint-brush"></i>
|
||||
</button>
|
||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||
</ul>
|
||||
-->
|
||||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">Filament</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
|
||||
<i id="git-repository-button" class="fa fa-github"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-wrapper" class="hidden">
|
||||
<form id="searchbar-outer" class="searchbar-outer">
|
||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||
</form>
|
||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||
<div id="searchresults-header" class="searchresults-header"></div>
|
||||
<ul id="searchresults">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||
<script>
|
||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<style>
|
||||
body { margin: 0; overflow: hidden; }
|
||||
canvas { touch-action: none; width: 100%; height: 400px; border: 1px solid black; }
|
||||
</style>
|
||||
<p><canvas></canvas></p>
|
||||
<script src="../../web/lib/filament.js"></script>
|
||||
<script src="../../web/lib/gl-matrix-min.js"></script>
|
||||
<script>
|
||||
let buffer0 = "AAABAAMAAAADAAIAAgADAAUAAgAFAAQABAAFAAcABAAHAAYABgAHAAkABgAJAAgAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAD8AAAAAAACAPwAAAD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAAAAAAAAwD8AAAAAAACAPwAAwD8AAAAAAAAAAAAAAEAAAAAAAACAPwAAAEAAAAAA";
|
||||
let buffer1 = "AAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAABAPwAAgD4AAAAAAAAAAAAAQD8AAIA+AAAAAAAAAAAAAAA/AAAAPwAAAAAAAAAAAAAAPwAAAD8AAAAAAAAAAAAAgD4AAEA/AAAAAAAAAAAAAIA+AABAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAA=";
|
||||
let buffer2 = "AACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAvwAAgL8AAAAAAACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAL8AAIC/AAAAAAAAgD8=";
|
||||
let buffer3 = "AAAAAAAAAD8AAIA/AADAPwAAAEAAACBAAABAQAAAYEAAAIBAAACQQAAAoEAAALBAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAkxjEPkSLbD8AAAAAAAAAAPT9ND/0/TQ/AAAAAAAAAAD0/TQ/9P00PwAAAAAAAAAAkxjEPkSLbD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAkxjEvkSLbD8AAAAAAAAAAPT9NL/0/TQ/AAAAAAAAAAD0/TS/9P00PwAAAAAAAAAAkxjEvkSLbD8AAAAAAAAAAAAAAAAAAIA/";
|
||||
buffer0 = Uint8Array.from(atob(buffer0), c => c.charCodeAt(0)).buffer;
|
||||
buffer1 = Uint8Array.from(atob(buffer1), c => c.charCodeAt(0)).buffer;
|
||||
buffer2 = Uint8Array.from(atob(buffer2), c => c.charCodeAt(0)).buffer;
|
||||
buffer3 = Uint8Array.from(atob(buffer3), c => c.charCodeAt(0)).buffer;
|
||||
const bufview0 = new Uint16Array(buffer0, 0, 24); // ushort indices
|
||||
const bufview1 = new Float32Array(buffer0, 48); // vec3 positions
|
||||
const bufview2 = new Uint8Array(buffer1, 0); // bone indices and weights
|
||||
const bufview3 = new Float32Array(buffer2); // two bone matrices (inverseBindMatrices)
|
||||
const bufview4 = new Float32Array(buffer3, 0, 12); // 12 floats (time in seconds)
|
||||
const bufview5 = new Float32Array(buffer3, 48); // 12 rotation quaternions
|
||||
/*
|
||||
This demo is heavily inspired by gltfTutorial_019_SimpleSkin:
|
||||
"nodes" : [
|
||||
{ "skin" : 0, "mesh" : 0, "children" : [ 1 ] },
|
||||
{ "children" : [ 2 ], "translation" : [ 0.0, 1.0, 0.0 ] },
|
||||
{ "rotation" : [ 0.0, 0.0, 0.0, 1.0 ] }
|
||||
],
|
||||
"skins" : [ {
|
||||
"inverseBindMatrices" : 4, // points to an accessor with two matrices
|
||||
"joints" : [ 1, 2 ] // the 2nd and 3rd nodes (which have no geometry) are the joints
|
||||
} ],
|
||||
"animations" : [ {
|
||||
"channels" : [ {
|
||||
"sampler" : 0,
|
||||
"target" : { "node" : 2, "path" : "rotation" } // the animation only applies to the 3rd node
|
||||
} ],
|
||||
"samplers" : [ { "input" : 5, "interpolation" : "LINEAR", "output" : 6 } ]
|
||||
} ],
|
||||
...
|
||||
*/
|
||||
const ibl_url = '../../web/assets/skinning/default_env/default_env_ibl.ktx';
|
||||
const sky_url = '../../web/assets/skinning/default_env/default_env_skybox.ktx';
|
||||
Filament.init([ '../../web/assets/skinning/skinning.filamat', ibl_url, sky_url ], () => {
|
||||
window.AttributeType = Filament.VertexBuffer$AttributeType;
|
||||
window.Fov = Filament.Camera$Fov;
|
||||
window.Projection = Filament.Camera$Projection;
|
||||
window.VertexAttribute = Filament.VertexAttribute;
|
||||
window.app = new App(document.getElementsByTagName('canvas')[0]);
|
||||
});
|
||||
class App {
|
||||
constructor(canvas) {
|
||||
this.canvas = canvas;
|
||||
const engine = this.engine = Filament.Engine.create(this.canvas);
|
||||
this.scene = engine.createScene();
|
||||
const indirectLight = engine.createIblFromKtx1(ibl_url);
|
||||
indirectLight.setIntensity(50000);
|
||||
this.scene.setIndirectLight(indirectLight);
|
||||
const skybox = engine.createSkyFromKtx1(sky_url);
|
||||
this.scene.setSkybox(skybox);
|
||||
this.mesh = Filament.EntityManager.get().create();
|
||||
this.scene.addEntity(this.mesh);
|
||||
this.ib = Filament.IndexBuffer.Builder()
|
||||
.indexCount(24)
|
||||
.bufferType(Filament.IndexBuffer$IndexType.USHORT)
|
||||
.build(engine);
|
||||
this.ib.setBuffer(engine, bufview0);
|
||||
this.vb = Filament.VertexBuffer.Builder()
|
||||
.vertexCount(10)
|
||||
.bufferCount(3)
|
||||
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT3, 0, 12)
|
||||
.attribute(VertexAttribute.BONE_INDICES, 1, AttributeType.USHORT4, 0, 16)
|
||||
.attribute(VertexAttribute.BONE_WEIGHTS, 2, AttributeType.FLOAT4, 0, 16)
|
||||
.build(engine);
|
||||
this.vb.setBufferAt(engine, 0, bufview1);
|
||||
this.vb.setBufferAt(engine, 1, bufview2.subarray(0, 160));
|
||||
this.vb.setBufferAt(engine, 2, bufview2.subarray(160, 320));
|
||||
const mat = engine.createMaterial('../../web/assets/skinning/skinning.filamat');
|
||||
const matinst = mat.getDefaultInstance();
|
||||
Filament.RenderableManager.Builder(1)
|
||||
.boundingBox({ center: [-1, -1, -1], halfExtent: [1, 1, 1] })
|
||||
.material(0, matinst)
|
||||
.geometry(0, Filament.RenderableManager$PrimitiveType.TRIANGLES, this.vb, this.ib)
|
||||
.skinning(2)
|
||||
.build(engine, this.mesh);
|
||||
this.swapChain = engine.createSwapChain();
|
||||
this.renderer = engine.createRenderer();
|
||||
this.camera = engine.createCamera(Filament.EntityManager.get().create());
|
||||
const eye = [0, 0, 4], center = [0, 0, 0], up = [0, 1, 0];
|
||||
this.camera.lookAt(eye, center, up);
|
||||
this.view = engine.createView();
|
||||
this.view.setCamera(this.camera);
|
||||
this.view.setScene(this.scene);
|
||||
this.renderer.setClearOptions({clearColor: [1.0, 1.0, 1.0, 1.0], clear: true});
|
||||
this.resize();
|
||||
this.render = this.render.bind(this);
|
||||
this.resize = this.resize.bind(this);
|
||||
window.addEventListener('resize', this.resize);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
render() {
|
||||
const endTime = 5.5;
|
||||
const timepoints = bufview4;
|
||||
const quats = bufview5;
|
||||
const inverseBindMatrices = bufview3;
|
||||
const nframes = timepoints.length;
|
||||
const seconds = (Date.now() / 1000) % endTime;
|
||||
let t = -1;
|
||||
let q = [0, 0, 0, 1];
|
||||
for (let i = 0; i < nframes; i++) {
|
||||
const j = (i + 1) % nframes;
|
||||
const next = (i == nframes - 1) ? (endTime + timepoints[0]) : timepoints[i + 1];
|
||||
const curr = timepoints[i];
|
||||
if (seconds >= curr && seconds < next) {
|
||||
t = (seconds - curr) / (next - curr);
|
||||
const q0 = quats.subarray(4 * i, 4 * (i + 1));
|
||||
const q1 = quats.subarray(4 * j, 4 * (j + 1));
|
||||
quat.slerp(q, q0, q1, t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
const transforms = [mat4.create(), mat4.create()];
|
||||
mat4.multiply(transforms[0], transforms[0], inverseBindMatrices.subarray(0, 16));
|
||||
mat4.multiply(transforms[1], transforms[1], inverseBindMatrices.subarray(16, 32));
|
||||
const m = mat4.fromQuat(mat4.create(), q);
|
||||
mat4.multiply(transforms[1], m, transforms[1]);
|
||||
const rm = this.engine.getRenderableManager();
|
||||
const renderable = rm.getInstance(this.mesh);
|
||||
rm.setBonesFromMatrices(renderable, transforms, 0);
|
||||
renderable.delete();
|
||||
this.renderer.render(this.swapChain, this.view);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
resize() {
|
||||
const dpr = window.devicePixelRatio;
|
||||
const width = this.canvas.width = this.canvas.clientWidth * dpr;
|
||||
const height = this.canvas.height = this.canvas.clientHeight * dpr;
|
||||
this.view.setViewport([0, 0, width, height]);
|
||||
const aspect = width / height;
|
||||
const fov = aspect < 1 ? Fov.HORIZONTAL : Fov.VERTICAL;
|
||||
this.camera.setProjectionFov(45, aspect, 1.0, 10.0, fov);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../../samples/web/parquet.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../notes/index.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../../samples/web/parquet.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../notes/index.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
window.playground_copyable = true;
|
||||
</script>
|
||||
|
||||
|
||||
<script src="../../elasticlunr.min.js"></script>
|
||||
<script src="../../mark.min.js"></script>
|
||||
<script src="../../searcher.js"></script>
|
||||
|
||||
<script src="../../clipboard.min.js"></script>
|
||||
<script src="../../highlight.js"></script>
|
||||
<script src="../../book.js"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
603
docs/samples/web/suzanne.html
Normal file
@@ -0,0 +1,603 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>suzanne - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="shortcut icon" href="../../favicon.png">
|
||||
<link rel="stylesheet" href="../../css/variables.css">
|
||||
<link rel="stylesheet" href="../../css/general.css">
|
||||
<link rel="stylesheet" href="../../css/chrome.css">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../../fonts/fonts.css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../../highlight.css">
|
||||
<link rel="stylesheet" href="../../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
<!-- MathJax -->
|
||||
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
|
||||
<!-- Provide site root to javascript -->
|
||||
<script>
|
||||
var path_to_root = "../../";
|
||||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../../toc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body-container">
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
<script>
|
||||
try {
|
||||
var theme = localStorage.getItem('mdbook-theme');
|
||||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||
|
||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||
}
|
||||
|
||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||
}
|
||||
} catch (e) { }
|
||||
</script>
|
||||
|
||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||
<script>
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||
const html = document.documentElement;
|
||||
html.classList.remove('light')
|
||||
html.classList.add(theme);
|
||||
html.classList.add("js");
|
||||
</script>
|
||||
|
||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
<script>
|
||||
var sidebar = null;
|
||||
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||||
if (document.body.clientWidth >= 1080) {
|
||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||
sidebar = sidebar || 'visible';
|
||||
} else {
|
||||
sidebar = 'hidden';
|
||||
}
|
||||
sidebar_toggle.checked = sidebar === 'visible';
|
||||
html.classList.remove('sidebar-visible');
|
||||
html.classList.add("sidebar-" + sidebar);
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div style="display:flex;align-items:center;justify-content:center">
|
||||
<img class="flogo" src="../../images/filament_logo_small.png"></img>
|
||||
</div>
|
||||
<!-- populated by js -->
|
||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||||
<noscript>
|
||||
<iframe class="sidebar-iframe-outer" src="../../toc.html"></iframe>
|
||||
</noscript>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||||
<div class="sidebar-resize-indicator"></div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
||||
<div class="page">
|
||||
<div id="menu-bar-hover-placeholder"></div>
|
||||
<div id="menu-bar" class="menu-bar sticky">
|
||||
<div class="left-buttons">
|
||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||
<i class="fa fa-bars"></i>
|
||||
</label>
|
||||
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
|
||||
<!--
|
||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||
<i class="fa fa-paint-brush"></i>
|
||||
</button>
|
||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||
</ul>
|
||||
-->
|
||||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">Filament</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
|
||||
<i id="git-repository-button" class="fa fa-github"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-wrapper" class="hidden">
|
||||
<form id="searchbar-outer" class="searchbar-outer">
|
||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||
</form>
|
||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||
<div id="searchresults-header" class="searchresults-header"></div>
|
||||
<ul id="searchresults">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||
<script>
|
||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<div class="demo_frame" style="width:100%; height:400px; border: 1px solid black; position: relative;">
|
||||
<canvas id="demo-canvas" style="width:100%; height:100%; touch-action: none;"></canvas>
|
||||
</div>
|
||||
<script src="../../web/lib/filament.js"></script>
|
||||
<script src="../../web/lib/gl-matrix-min.js"></script>
|
||||
<script src="../../web/lib/gltumble.min.js"></script>
|
||||
<script>
|
||||
// We wrap the demo code so it applies to demo-canvas instead of generic canvas
|
||||
(function() {
|
||||
const originalGetElementsByTagName = document.getElementsByTagName;
|
||||
document.getElementsByTagName = function(tag) {
|
||||
if (tag === 'canvas') return [document.getElementById('demo-canvas')];
|
||||
return originalGetElementsByTagName.call(document, tag);
|
||||
};
|
||||
//
|
||||
const albedo_suffix = Filament.getSupportedFormatSuffix('astc s3tc_srgb');
|
||||
const texture_suffix = Filament.getSupportedFormatSuffix('etc');
|
||||
//
|
||||
const ibl_url = '../../web/assets/suzanne/venetian_crossroads_2k/venetian_crossroads_2k_ibl.ktx';
|
||||
const sky_small_url = '../../web/assets/suzanne/venetian_crossroads_2k/venetian_crossroads_2k_skybox_tiny.ktx';
|
||||
const sky_large_url = '../../web/assets/suzanne/venetian_crossroads_2k/venetian_crossroads_2k_skybox.ktx';
|
||||
const albedo_url = `../../web/assets/suzanne/albedo.ktx2`;
|
||||
const ao_url = `../../web/assets/suzanne/ao.ktx2`;
|
||||
const metallic_url = `../../web/assets/suzanne/metallic.ktx2`;
|
||||
const normal_url = `../../web/assets/suzanne/normal.ktx2`;
|
||||
const roughness_url = `../../web/assets/suzanne/roughness.ktx2`;
|
||||
const filamat_url = '../../web/assets/suzanne/textured.filamat';
|
||||
const filamesh_url = '../../web/assets/suzanne/suzanne.filamesh';
|
||||
//
|
||||
Filament.init([ filamat_url, filamesh_url, sky_small_url, ibl_url ], () => {
|
||||
window.app = new App(document.getElementsByTagName('canvas')[0]);
|
||||
});
|
||||
//
|
||||
class App {
|
||||
constructor(canvas) {
|
||||
this.canvas = canvas;
|
||||
this.engine = Filament.Engine.create(canvas);
|
||||
this.scene = this.engine.createScene();
|
||||
//
|
||||
const material = this.engine.createMaterial(filamat_url);
|
||||
this.matinstance = material.createInstance();
|
||||
//
|
||||
const filamesh = this.engine.loadFilamesh(filamesh_url, this.matinstance);
|
||||
this.suzanne = filamesh.renderable;
|
||||
//
|
||||
this.skybox = this.engine.createSkyFromKtx1(sky_small_url);
|
||||
this.scene.setSkybox(this.skybox);
|
||||
this.indirectLight = this.engine.createIblFromKtx1(ibl_url);
|
||||
this.indirectLight.setIntensity(100000);
|
||||
this.scene.setIndirectLight(this.indirectLight);
|
||||
this.trackball = new Trackball(canvas, {startSpin: 0.035});
|
||||
Filament.fetch([sky_large_url, albedo_url, roughness_url, metallic_url, normal_url, ao_url], () => {
|
||||
const albedo = this.engine.createTextureFromKtx2(albedo_url, {srgb: true});
|
||||
const roughness = this.engine.createTextureFromKtx2(roughness_url);
|
||||
const metallic = this.engine.createTextureFromKtx2(metallic_url);
|
||||
const normal = this.engine.createTextureFromKtx2(normal_url);
|
||||
const ao = this.engine.createTextureFromKtx2(ao_url);
|
||||
//
|
||||
const sampler = new Filament.TextureSampler(
|
||||
Filament.MinFilter.LINEAR_MIPMAP_LINEAR,
|
||||
Filament.MagFilter.LINEAR,
|
||||
Filament.WrapMode.CLAMP_TO_EDGE);
|
||||
//
|
||||
this.matinstance.setTextureParameter('albedo', albedo, sampler);
|
||||
this.matinstance.setTextureParameter('roughness', roughness, sampler);
|
||||
this.matinstance.setTextureParameter('metallic', metallic, sampler);
|
||||
this.matinstance.setTextureParameter('normal', normal, sampler);
|
||||
this.matinstance.setTextureParameter('ao', ao, sampler);
|
||||
//
|
||||
// Replace low-res skybox with high-res skybox.
|
||||
this.engine.destroySkybox(this.skybox);
|
||||
this.skybox = this.engine.createSkyFromKtx1(sky_large_url);
|
||||
this.scene.setSkybox(this.skybox);
|
||||
//
|
||||
this.scene.addEntity(this.suzanne);
|
||||
});
|
||||
//
|
||||
this.swapChain = this.engine.createSwapChain();
|
||||
this.renderer = this.engine.createRenderer();
|
||||
this.camera = this.engine.createCamera(Filament.EntityManager.get().create());
|
||||
this.view = this.engine.createView();
|
||||
this.view.setCamera(this.camera);
|
||||
this.view.setScene(this.scene);
|
||||
this.render = this.render.bind(this);
|
||||
this.resize = this.resize.bind(this);
|
||||
window.addEventListener('resize', this.resize);
|
||||
//
|
||||
const eye = [0, 0, 4], center = [0, 0, 0], up = [0, 1, 0];
|
||||
this.camera.lookAt(eye, center, up);
|
||||
//
|
||||
this.resize();
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
//
|
||||
render() {
|
||||
const tcm = this.engine.getTransformManager();
|
||||
const inst = tcm.getInstance(this.suzanne);
|
||||
tcm.setTransform(inst, this.trackball.getMatrix());
|
||||
inst.delete();
|
||||
this.renderer.render(this.swapChain, this.view);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
//
|
||||
resize() {
|
||||
const dpr = window.devicePixelRatio;
|
||||
const width = this.canvas.width = this.canvas.clientWidth * dpr;
|
||||
const height = this.canvas.height = this.canvas.clientHeight * dpr;
|
||||
this.view.setViewport([0, 0, width, height]);
|
||||
//
|
||||
const aspect = width / height;
|
||||
const Fov = Filament.Camera$Fov, fov = aspect < 1 ? Fov.HORIZONTAL : Fov.VERTICAL;
|
||||
this.camera.setProjectionFov(45, aspect, 1.0, 10.0, fov);
|
||||
}
|
||||
}
|
||||
//
|
||||
})();
|
||||
</script>
|
||||
<p>This tutorial will describe how to create the <strong>suzanne</strong> demo, introducing you to compressed
|
||||
textures, mipmap generation, asynchronous texture loading, and trackball rotation.</p>
|
||||
<p>Much like the [previous tutorial], you'll need to use the command-line tools that can be found in
|
||||
the appropriate <a href="//github.com/google/filament/releases">Filament release</a> for your development machine. In addition to <code>matc</code> and <code>cmgen</code>,
|
||||
we'll also be using <code>filamesh</code> and <code>mipgen</code>.</p>
|
||||
<h2 id="create-filamesh-file"><a class="header" href="#create-filamesh-file">Create filamesh file</a></h2>
|
||||
<p>Filament does not have an asset loading system, but it does provide a binary mesh format
|
||||
called <code>filamesh</code> for simple use cases. Let's create a compressed filamesh file for suzanne by
|
||||
converting <a href="https://github.com/google/filament/blob/main/assets/models/monkey/monkey.obj">this OBJ file</a>:</p>
|
||||
<pre><code class="language-bash">filamesh --compress monkey.obj suzanne.filamesh
|
||||
</code></pre>
|
||||
<h2 id="create-mipmapped-textures"><a class="header" href="#create-mipmapped-textures">Create mipmapped textures</a></h2>
|
||||
<p>Next, let's create mipmapped KTX files using filament's <code>mipgen</code> tool. We'll create compressed and
|
||||
non-compressed variants for each texture, since not all platforms support the same compression
|
||||
formats. First copy over the PNG files from the <a href="https://github.com/google/filament/blob/main/assets/models/monkey">monkey folder</a>, then do:</p>
|
||||
<pre><code class="language-bash"># Create mipmaps for base color
|
||||
mipgen albedo.png albedo.ktx2
|
||||
mipgen --compression=uastc albedo.png albedo.ktx2
|
||||
|
||||
# Create mipmaps for the normal map and a compressed variant.
|
||||
mipgen --strip-alpha --kernel=NORMALS --linear normal.png normal.ktx
|
||||
mipgen --strip-alpha --kernel=NORMALS --linear --compression=uastc_normals \
|
||||
normal.png normal.ktx2
|
||||
|
||||
# Create mipmaps for the single-component roughness map and a compressed variant.
|
||||
mipgen --grayscale roughness.png roughness.ktx
|
||||
mipgen --grayscale --compression=uastc roughness.png roughness.ktx2
|
||||
|
||||
# Create mipmaps for the single-component metallic map and a compressed variant.
|
||||
mipgen --grayscale metallic.png metallic.ktx
|
||||
mipgen --grayscale --compression=uastc metallic.png metallic.ktx2
|
||||
|
||||
# Create mipmaps for the single-component occlusion map and a compressed variant.
|
||||
mipgen --grayscale ao.png ao.ktx
|
||||
mipgen --grayscale --compression=uastc ao.png ao.ktx2
|
||||
</code></pre>
|
||||
<p>For more information on mipgen's arguments and supported formats, do <code>mipgen --help</code>.</p>
|
||||
<p>In a production setting, you'd want to invoke these commands with a script or build system.</p>
|
||||
<h2 id="bake-environment-map"><a class="header" href="#bake-environment-map">Bake environment map</a></h2>
|
||||
<p>Much like the [previous tutorial] we need to use Filament's <code>cmgen</code> tool to produce cubemap files.</p>
|
||||
<p>Download <a href="//github.com/google/filament/blob/main/third_party/environments/venetian_crossroads_2k.hdr">venetian_crossroads_2k.hdr</a>, then invoke the following commands in your terminal.</p>
|
||||
<pre><code class="language-bash">cmgen -x . --format=ktx --size=64 --extract-blur=0.1 venetian_crossroads_2k.hdr
|
||||
cd venetian* ; mv venetian*_ibl.ktx venetian_crossroads_2k_skybox_tiny.ktx ; cd -
|
||||
|
||||
cmgen -x . --format=ktx --size=256 --extract-blur=0.1 venetian_crossroads_2k.hdr
|
||||
cmgen -x . --format=ktx --size=256 --extract-blur=0.1 venetian_crossroads_2k.hdr
|
||||
cmgen -x . --format=ktx --size=256 --extract-blur=0.1 venetian_crossroads_2k.hdr
|
||||
</code></pre>
|
||||
<h2 id="define-textured-material"><a class="header" href="#define-textured-material">Define textured material</a></h2>
|
||||
<p>You might recall the <code>filamat</code> file we generated in the previous tutorial for red plastic. For this
|
||||
demo, we'll create a material that uses textures for several parameters.</p>
|
||||
<p>Create the following text file and call it <code>textured.mat</code>. Note that our material definition now
|
||||
requires a <code>uv0</code> attribute.</p>
|
||||
<pre><code class="language-text">material {
|
||||
name : textured,
|
||||
requires : [ uv0 ],
|
||||
shadingModel : lit,
|
||||
parameters : [
|
||||
{ type : sampler2d, name : albedo },
|
||||
{ type : sampler2d, name : roughness },
|
||||
{ type : sampler2d, name : metallic },
|
||||
{ type : float, name : clearCoat },
|
||||
{ type : sampler2d, name : normal },
|
||||
{ type : sampler2d, name : ao }
|
||||
],
|
||||
}
|
||||
|
||||
fragment {
|
||||
void material(inout MaterialInputs material) {
|
||||
material.normal = texture(materialParams_normal, getUV0()).xyz * 2.0 - 1.0;
|
||||
prepareMaterial(material);
|
||||
material.baseColor = texture(materialParams_albedo, getUV0());
|
||||
material.roughness = texture(materialParams_roughness, getUV0()).r;
|
||||
material.metallic = texture(materialParams_metallic, getUV0()).r;
|
||||
material.clearCoat = materialParams.clearCoat;
|
||||
material.ambientOcclusion = texture(materialParams_ao, getUV0()).r;
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>Next, invoke <code>matc</code> as follows.</p>
|
||||
<pre><code class="language-bash">matc -a opengl -p mobile -o textured.filamat textured.mat
|
||||
</code></pre>
|
||||
<p>You should now have a material archive in your working directory. For the suzanne asset, the normal
|
||||
map adds scratches, the albedo map paints the eyes white, and so on. For more information on
|
||||
materials, consult the official document describing the <a href="https://google.github.io/filament/Materials.md.html">Filament Material System</a>.</p>
|
||||
<h2 id="create-app-skeleton"><a class="header" href="#create-app-skeleton">Create app skeleton</a></h2>
|
||||
<p>Create a text file called <code>suzanne.html</code> and copy over the HTML that we used in the [previous
|
||||
tutorial]. Change the last script tag from <code>redball.js</code> to <code>suzanne.js</code>. Next, create <code>suzanne.js</code>
|
||||
with the following content.</p>
|
||||
<pre><code class="language-js">const albedo_suffix = Filament.getSupportedFormatSuffix('astc s3tc_srgb');
|
||||
const texture_suffix = Filament.getSupportedFormatSuffix('etc');
|
||||
|
||||
const ibl_url = '../../web/assets/suzanne/venetian_crossroads_2k/venetian_crossroads_2k_ibl.ktx';
|
||||
const sky_small_url = '../../web/assets/suzanne/venetian_crossroads_2k/venetian_crossroads_2k_skybox_tiny.ktx';
|
||||
const sky_large_url = '../../web/assets/suzanne/venetian_crossroads_2k/venetian_crossroads_2k_skybox.ktx';
|
||||
const albedo_url = `../../web/assets/suzanne/albedo.ktx2`;
|
||||
const ao_url = `../../web/assets/suzanne/ao.ktx2`;
|
||||
const metallic_url = `../../web/assets/suzanne/metallic.ktx2`;
|
||||
const normal_url = `../../web/assets/suzanne/normal.ktx2`;
|
||||
const roughness_url = `../../web/assets/suzanne/roughness.ktx2`;
|
||||
const filamat_url = '../../web/assets/suzanne/textured.filamat';
|
||||
const filamesh_url = '../../web/assets/suzanne/suzanne.filamesh';
|
||||
|
||||
Filament.init([ filamat_url, filamesh_url, sky_small_url, ibl_url ], () => {
|
||||
window.app = new App(document.getElementsByTagName('canvas')[0]);
|
||||
});
|
||||
|
||||
class App {
|
||||
constructor(canvas) {
|
||||
this.canvas = canvas;
|
||||
this.engine = Filament.Engine.create(canvas);
|
||||
this.scene = this.engine.createScene();
|
||||
|
||||
const material = this.engine.createMaterial(filamat_url);
|
||||
this.matinstance = material.createInstance();
|
||||
|
||||
const filamesh = this.engine.loadFilamesh(filamesh_url, this.matinstance);
|
||||
this.suzanne = filamesh.renderable;
|
||||
|
||||
this.skybox = this.engine.createSkyFromKtx1(sky_small_url);
|
||||
this.scene.setSkybox(this.skybox);
|
||||
this.indirectLight = this.engine.createIblFromKtx1(ibl_url);
|
||||
this.indirectLight.setIntensity(100000);
|
||||
this.scene.setIndirectLight(this.indirectLight);
|
||||
this.trackball = new Trackball(canvas, {startSpin: 0.035});
|
||||
Filament.fetch([sky_large_url, albedo_url, roughness_url, metallic_url, normal_url, ao_url], () => {
|
||||
const albedo = this.engine.createTextureFromKtx2(albedo_url, {srgb: true});
|
||||
const roughness = this.engine.createTextureFromKtx2(roughness_url);
|
||||
const metallic = this.engine.createTextureFromKtx2(metallic_url);
|
||||
const normal = this.engine.createTextureFromKtx2(normal_url);
|
||||
const ao = this.engine.createTextureFromKtx2(ao_url);
|
||||
|
||||
const sampler = new Filament.TextureSampler(
|
||||
Filament.MinFilter.LINEAR_MIPMAP_LINEAR,
|
||||
Filament.MagFilter.LINEAR,
|
||||
Filament.WrapMode.CLAMP_TO_EDGE);
|
||||
|
||||
this.matinstance.setTextureParameter('albedo', albedo, sampler);
|
||||
this.matinstance.setTextureParameter('roughness', roughness, sampler);
|
||||
this.matinstance.setTextureParameter('metallic', metallic, sampler);
|
||||
this.matinstance.setTextureParameter('normal', normal, sampler);
|
||||
this.matinstance.setTextureParameter('ao', ao, sampler);
|
||||
|
||||
// Replace low-res skybox with high-res skybox.
|
||||
this.engine.destroySkybox(this.skybox);
|
||||
this.skybox = this.engine.createSkyFromKtx1(sky_large_url);
|
||||
this.scene.setSkybox(this.skybox);
|
||||
|
||||
this.scene.addEntity(this.suzanne);
|
||||
});
|
||||
|
||||
this.swapChain = this.engine.createSwapChain();
|
||||
this.renderer = this.engine.createRenderer();
|
||||
this.camera = this.engine.createCamera(Filament.EntityManager.get().create());
|
||||
this.view = this.engine.createView();
|
||||
this.view.setCamera(this.camera);
|
||||
this.view.setScene(this.scene);
|
||||
this.render = this.render.bind(this);
|
||||
this.resize = this.resize.bind(this);
|
||||
window.addEventListener('resize', this.resize);
|
||||
|
||||
const eye = [0, 0, 4], center = [0, 0, 0], up = [0, 1, 0];
|
||||
this.camera.lookAt(eye, center, up);
|
||||
|
||||
this.resize();
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
|
||||
render() {
|
||||
const tcm = this.engine.getTransformManager();
|
||||
const inst = tcm.getInstance(this.suzanne);
|
||||
tcm.setTransform(inst, this.trackball.getMatrix());
|
||||
inst.delete();
|
||||
this.renderer.render(this.swapChain, this.view);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
|
||||
resize() {
|
||||
const dpr = window.devicePixelRatio;
|
||||
const width = this.canvas.width = this.canvas.clientWidth * dpr;
|
||||
const height = this.canvas.height = this.canvas.clientHeight * dpr;
|
||||
this.view.setViewport([0, 0, width, height]);
|
||||
|
||||
const aspect = width / height;
|
||||
const Fov = Filament.Camera$Fov, fov = aspect < 1 ? Fov.HORIZONTAL : Fov.VERTICAL;
|
||||
this.camera.setProjectionFov(45, aspect, 1.0, 10.0, fov);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>Our app will only require a subset of assets to be present for <code>App</code> construction. We'll download
|
||||
the other assets after construction. By using a progressive loading strategy, we can reduce the
|
||||
perceived load time.</p>
|
||||
<p>Next we need to supply the URLs for various assets. This is actually a bit tricky, because different
|
||||
clients have different capabilities for compressed textures.</p>
|
||||
<p>To help you download only the texture assets that you need, Filament provides a
|
||||
<code>getSupportedFormatSuffix</code> function. This takes a space-separated list of desired format types
|
||||
(<code>etc</code>, <code>s3tc</code>, or <code>astc</code>) that the app developer knows is available from the server. The function
|
||||
performs an intersection of the <em>desired</em> set with the <em>supported</em> set, then returns an appropriate
|
||||
string -- which might be empty.</p>
|
||||
<p>In our case, we know that our web server will have <code>astc</code> and <code>s3tc</code> variants for albedo, and <code>etc</code>
|
||||
variants for the other textures. The uncompressed variants (empty string) are always available as a
|
||||
last resort. Go ahead and replace the <strong>declare asset URLs</strong> comment with the following snippet.</p>
|
||||
<pre><code class="language-js">const albedo_suffix = Filament.getSupportedFormatSuffix('astc s3tc_srgb');
|
||||
const texture_suffix = Filament.getSupportedFormatSuffix('etc');
|
||||
|
||||
const ibl_url = '../../web/assets/suzanne/venetian_crossroads_2k/venetian_crossroads_2k_ibl.ktx';
|
||||
const sky_small_url = '../../web/assets/suzanne/venetian_crossroads_2k/venetian_crossroads_2k_skybox_tiny.ktx';
|
||||
const sky_large_url = '../../web/assets/suzanne/venetian_crossroads_2k/venetian_crossroads_2k_skybox.ktx';
|
||||
const albedo_url = `../../web/assets/suzanne/albedo.ktx2`;
|
||||
const ao_url = `../../web/assets/suzanne/ao.ktx2`;
|
||||
const metallic_url = `../../web/assets/suzanne/metallic.ktx2`;
|
||||
const normal_url = `../../web/assets/suzanne/normal.ktx2`;
|
||||
const roughness_url = `../../web/assets/suzanne/roughness.ktx2`;
|
||||
const filamat_url = '../../web/assets/suzanne/textured.filamat';
|
||||
const filamesh_url = '../../web/assets/suzanne/suzanne.filamesh';
|
||||
</code></pre>
|
||||
<h2 id="create-skybox-and-ibl"><a class="header" href="#create-skybox-and-ibl">Create skybox and IBL</a></h2>
|
||||
<p>Next, let's create the low-resolution skybox and IBL in the <code>App</code> constructor.</p>
|
||||
<pre><code class="language-js">this.skybox = this.engine.createSkyFromKtx1(sky_small_url);
|
||||
this.scene.setSkybox(this.skybox);
|
||||
this.indirectLight = this.engine.createIblFromKtx1(ibl_url);
|
||||
this.indirectLight.setIntensity(100000);
|
||||
this.scene.setIndirectLight(this.indirectLight);
|
||||
</code></pre>
|
||||
<p>This allows users to see a reasonable background fairly quickly, before larger assets have finished
|
||||
loading in.</p>
|
||||
<h2 id="fetch-assets-asychronously"><a class="header" href="#fetch-assets-asychronously">Fetch assets asychronously</a></h2>
|
||||
<p>Next we'll invoke the <code>Filament.fetch</code> function from within the app constructor. This function is
|
||||
very similar to <code>Filament.init</code>. It takes a list of asset URLs and a callback function that triggers
|
||||
when the assets have finished downloading.</p>
|
||||
<p>In our callback, we'll make several <code>setTextureParameter</code> calls on the material instance, then we'll
|
||||
recreate the skybox using a higher-resolution texture. As a last step we unhide the renderable that
|
||||
was created in the app constructor.</p>
|
||||
<pre><code class="language-js">Filament.fetch([sky_large_url, albedo_url, roughness_url, metallic_url, normal_url, ao_url], () => {
|
||||
const albedo = this.engine.createTextureFromKtx2(albedo_url, {srgb: true});
|
||||
const roughness = this.engine.createTextureFromKtx2(roughness_url);
|
||||
const metallic = this.engine.createTextureFromKtx2(metallic_url);
|
||||
const normal = this.engine.createTextureFromKtx2(normal_url);
|
||||
const ao = this.engine.createTextureFromKtx2(ao_url);
|
||||
|
||||
const sampler = new Filament.TextureSampler(
|
||||
Filament.MinFilter.LINEAR_MIPMAP_LINEAR,
|
||||
Filament.MagFilter.LINEAR,
|
||||
Filament.WrapMode.CLAMP_TO_EDGE);
|
||||
|
||||
this.matinstance.setTextureParameter('albedo', albedo, sampler);
|
||||
this.matinstance.setTextureParameter('roughness', roughness, sampler);
|
||||
this.matinstance.setTextureParameter('metallic', metallic, sampler);
|
||||
this.matinstance.setTextureParameter('normal', normal, sampler);
|
||||
this.matinstance.setTextureParameter('ao', ao, sampler);
|
||||
|
||||
// Replace low-res skybox with high-res skybox.
|
||||
this.engine.destroySkybox(this.skybox);
|
||||
this.skybox = this.engine.createSkyFromKtx1(sky_large_url);
|
||||
this.scene.setSkybox(this.skybox);
|
||||
|
||||
this.scene.addEntity(this.suzanne);
|
||||
});
|
||||
</code></pre>
|
||||
<h2 id="introduce-trackball-rotation"><a class="header" href="#introduce-trackball-rotation">Introduce trackball rotation</a></h2>
|
||||
<p>Add the following script tag to your HTML file. This imports a small third-party library that
|
||||
listens for drag events and computes a rotation matrix.</p>
|
||||
<pre><code class="language-html"><script src="//unpkg.com/gltumble"></script>
|
||||
</code></pre>
|
||||
<p>Next, replace the <strong>initialize gltumble</strong> and <strong>apply gltumble matrix</strong> comments with the following
|
||||
two code snippets.</p>
|
||||
<pre><code class="language-js">this.trackball = new Trackball(canvas, {startSpin: 0.035});
|
||||
</code></pre>
|
||||
<pre><code class="language-js">const tcm = this.engine.getTransformManager();
|
||||
const inst = tcm.getInstance(this.suzanne);
|
||||
tcm.setTransform(inst, this.trackball.getMatrix());
|
||||
inst.delete();
|
||||
</code></pre>
|
||||
<p>That's it, we now have a fast-loading interactive demo.</p>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../../samples/web/redball.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../samples/web/samples.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../../samples/web/redball.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../samples/web/samples.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
window.playground_copyable = true;
|
||||
</script>
|
||||
|
||||
|
||||
<script src="../../elasticlunr.min.js"></script>
|
||||
<script src="../../mark.min.js"></script>
|
||||
<script src="../../searcher.js"></script>
|
||||
|
||||
<script src="../../clipboard.min.js"></script>
|
||||
<script src="../../highlight.js"></script>
|
||||
<script src="../../book.js"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
593
docs/samples/web/triangle.html
Normal file
@@ -0,0 +1,593 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>triangle - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="shortcut icon" href="../../favicon.png">
|
||||
<link rel="stylesheet" href="../../css/variables.css">
|
||||
<link rel="stylesheet" href="../../css/general.css">
|
||||
<link rel="stylesheet" href="../../css/chrome.css">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../../fonts/fonts.css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../../highlight.css">
|
||||
<link rel="stylesheet" href="../../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
<!-- MathJax -->
|
||||
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
|
||||
<!-- Provide site root to javascript -->
|
||||
<script>
|
||||
var path_to_root = "../../";
|
||||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../../toc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body-container">
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
<script>
|
||||
try {
|
||||
var theme = localStorage.getItem('mdbook-theme');
|
||||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||
|
||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||
}
|
||||
|
||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||
}
|
||||
} catch (e) { }
|
||||
</script>
|
||||
|
||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||
<script>
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||
const html = document.documentElement;
|
||||
html.classList.remove('light')
|
||||
html.classList.add(theme);
|
||||
html.classList.add("js");
|
||||
</script>
|
||||
|
||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
<script>
|
||||
var sidebar = null;
|
||||
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||||
if (document.body.clientWidth >= 1080) {
|
||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||
sidebar = sidebar || 'visible';
|
||||
} else {
|
||||
sidebar = 'hidden';
|
||||
}
|
||||
sidebar_toggle.checked = sidebar === 'visible';
|
||||
html.classList.remove('sidebar-visible');
|
||||
html.classList.add("sidebar-" + sidebar);
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div style="display:flex;align-items:center;justify-content:center">
|
||||
<img class="flogo" src="../../images/filament_logo_small.png"></img>
|
||||
</div>
|
||||
<!-- populated by js -->
|
||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||||
<noscript>
|
||||
<iframe class="sidebar-iframe-outer" src="../../toc.html"></iframe>
|
||||
</noscript>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||||
<div class="sidebar-resize-indicator"></div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
||||
<div class="page">
|
||||
<div id="menu-bar-hover-placeholder"></div>
|
||||
<div id="menu-bar" class="menu-bar sticky">
|
||||
<div class="left-buttons">
|
||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||
<i class="fa fa-bars"></i>
|
||||
</label>
|
||||
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
|
||||
<!--
|
||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||
<i class="fa fa-paint-brush"></i>
|
||||
</button>
|
||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||
</ul>
|
||||
-->
|
||||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">Filament</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
|
||||
<i id="git-repository-button" class="fa fa-github"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-wrapper" class="hidden">
|
||||
<form id="searchbar-outer" class="searchbar-outer">
|
||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||
</form>
|
||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||
<div id="searchresults-header" class="searchresults-header"></div>
|
||||
<ul id="searchresults">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||
<script>
|
||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<div class="demo_frame" style="width:100%; height:400px; border: 1px solid black; position: relative;">
|
||||
<canvas id="demo-canvas" style="width:100%; height:100%; touch-action: none;"></canvas>
|
||||
</div>
|
||||
<script src="../../web/lib/filament.js"></script>
|
||||
<script src="../../web/lib/gl-matrix-min.js"></script>
|
||||
<script>
|
||||
// We wrap the demo code so it applies to demo-canvas instead of generic canvas
|
||||
(function() {
|
||||
const originalGetElementsByTagName = document.getElementsByTagName;
|
||||
document.getElementsByTagName = function(tag) {
|
||||
if (tag === 'canvas') return [document.getElementById('demo-canvas')];
|
||||
return originalGetElementsByTagName.call(document, tag);
|
||||
};
|
||||
//
|
||||
class App {
|
||||
constructor() {
|
||||
this.canvas = document.getElementsByTagName('canvas')[0];
|
||||
const engine = this.engine = Filament.Engine.create(this.canvas);
|
||||
this.scene = engine.createScene();
|
||||
this.triangle = Filament.EntityManager.get().create();
|
||||
this.scene.addEntity(this.triangle);
|
||||
const TRIANGLE_POSITIONS = new Float32Array([
|
||||
1, 0,
|
||||
Math.cos(Math.PI * 2 / 3), Math.sin(Math.PI * 2 / 3),
|
||||
Math.cos(Math.PI * 4 / 3), Math.sin(Math.PI * 4 / 3),
|
||||
]);
|
||||
//
|
||||
const TRIANGLE_COLORS = new Uint32Array([0xffff0000, 0xff00ff00, 0xff0000ff]);
|
||||
const VertexAttribute = Filament.VertexAttribute;
|
||||
const AttributeType = Filament.VertexBuffer$AttributeType;
|
||||
this.vb = Filament.VertexBuffer.Builder()
|
||||
.vertexCount(3)
|
||||
.bufferCount(2)
|
||||
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT2, 0, 8)
|
||||
.attribute(VertexAttribute.COLOR, 1, AttributeType.UBYTE4, 0, 4)
|
||||
.normalized(VertexAttribute.COLOR)
|
||||
.build(engine);
|
||||
//
|
||||
this.vb.setBufferAt(engine, 0, TRIANGLE_POSITIONS);
|
||||
this.vb.setBufferAt(engine, 1, TRIANGLE_COLORS);
|
||||
this.ib = Filament.IndexBuffer.Builder()
|
||||
.indexCount(3)
|
||||
.bufferType(Filament.IndexBuffer$IndexType.USHORT)
|
||||
.build(engine);
|
||||
//
|
||||
this.ib.setBuffer(engine, new Uint16Array([0, 1, 2]));
|
||||
const mat = engine.createMaterial('../../web/assets/triangle/triangle.filamat');
|
||||
const matinst = mat.getDefaultInstance();
|
||||
Filament.RenderableManager.Builder(1)
|
||||
.boundingBox({ center: [-1, -1, -1], halfExtent: [1, 1, 1] })
|
||||
.material(0, matinst)
|
||||
.geometry(0, Filament.RenderableManager$PrimitiveType.TRIANGLES, this.vb, this.ib)
|
||||
.build(engine, this.triangle);
|
||||
this.swapChain = engine.createSwapChain();
|
||||
this.renderer = engine.createRenderer();
|
||||
this.camera = engine.createCamera(Filament.EntityManager.get().create());
|
||||
this.view = engine.createView();
|
||||
this.view.setCamera(this.camera);
|
||||
this.view.setScene(this.scene);
|
||||
//
|
||||
// Set up a blue-green background:
|
||||
this.renderer.setClearOptions({clearColor: [0.0, 0.1, 0.2, 1.0], clear: true});
|
||||
//
|
||||
// Adjust the initial viewport:
|
||||
this.resize();
|
||||
this.render = this.render.bind(this);
|
||||
this.resize = this.resize.bind(this);
|
||||
window.addEventListener('resize', this.resize);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
render() {
|
||||
// Rotate the triangle.
|
||||
const radians = Date.now() / 1000;
|
||||
const transform = mat4.fromRotation(mat4.create(), radians, [0, 0, 1]);
|
||||
const tcm = this.engine.getTransformManager();
|
||||
const inst = tcm.getInstance(this.triangle);
|
||||
tcm.setTransform(inst, transform);
|
||||
inst.delete();
|
||||
//
|
||||
// Render the frame.
|
||||
this.renderer.render(this.swapChain, this.view);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
resize() {
|
||||
const dpr = window.devicePixelRatio;
|
||||
const width = this.canvas.width = this.canvas.clientWidth * dpr;
|
||||
const height = this.canvas.height = this.canvas.clientHeight * dpr;
|
||||
this.view.setViewport([0, 0, width, height]);
|
||||
//
|
||||
const aspect = width / height;
|
||||
const Projection = Filament.Camera$Projection;
|
||||
this.camera.setProjection(Projection.ORTHO, -aspect, aspect, -1, 1, 0, 1);
|
||||
}
|
||||
}
|
||||
//
|
||||
Filament.init(['../../web/assets/triangle/triangle.filamat'], () => { window.app = new App() } );
|
||||
//
|
||||
})();
|
||||
</script>
|
||||
<h2 id="start-your-project"><a class="header" href="#start-your-project">Start your project</a></h2>
|
||||
<p>First, create a text file called <code>triangle.html</code> and fill it with the following HTML. This creates
|
||||
a mobile-friendly page with a full-screen canvas.</p>
|
||||
<pre><code class="language-html"><!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Filament Tutorial</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1">
|
||||
<style>
|
||||
body { margin: 0; overflow: hidden; }
|
||||
canvas { touch-action: none; width: 100%; height: 100%; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas></canvas>
|
||||
<script src="../../web/lib/filament.js"></script>
|
||||
<script src="//unpkg.com/gl-matrix@2.8.1"></script>
|
||||
<script src="triangle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</code></pre>
|
||||
<p>The above HTML loads three JavaScript files:</p>
|
||||
<ul>
|
||||
<li><code>filament.js</code> does a couple things:
|
||||
<ul>
|
||||
<li>Downloads assets and compiles the Filament WASM module.</li>
|
||||
<li>Contains high-level utilities, e.g. to simplify loading KTX textures from JavaScript.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><code>gl-matrix-min.js</code> is a small library that provides vector math functionality.</li>
|
||||
<li><code>triangle.js</code> will contain your application code.</li>
|
||||
</ul>
|
||||
<p>Go ahead and create <code>triangle.js</code> with the following content.</p>
|
||||
<pre><code class="language-js">class App {
|
||||
constructor() {
|
||||
this.canvas = document.getElementsByTagName('canvas')[0];
|
||||
const engine = this.engine = Filament.Engine.create(this.canvas);
|
||||
this.scene = engine.createScene();
|
||||
this.triangle = Filament.EntityManager.get().create();
|
||||
this.scene.addEntity(this.triangle);
|
||||
const TRIANGLE_POSITIONS = new Float32Array([
|
||||
1, 0,
|
||||
Math.cos(Math.PI * 2 / 3), Math.sin(Math.PI * 2 / 3),
|
||||
Math.cos(Math.PI * 4 / 3), Math.sin(Math.PI * 4 / 3),
|
||||
]);
|
||||
|
||||
const TRIANGLE_COLORS = new Uint32Array([0xffff0000, 0xff00ff00, 0xff0000ff]);
|
||||
const VertexAttribute = Filament.VertexAttribute;
|
||||
const AttributeType = Filament.VertexBuffer$AttributeType;
|
||||
this.vb = Filament.VertexBuffer.Builder()
|
||||
.vertexCount(3)
|
||||
.bufferCount(2)
|
||||
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT2, 0, 8)
|
||||
.attribute(VertexAttribute.COLOR, 1, AttributeType.UBYTE4, 0, 4)
|
||||
.normalized(VertexAttribute.COLOR)
|
||||
.build(engine);
|
||||
|
||||
this.vb.setBufferAt(engine, 0, TRIANGLE_POSITIONS);
|
||||
this.vb.setBufferAt(engine, 1, TRIANGLE_COLORS);
|
||||
this.ib = Filament.IndexBuffer.Builder()
|
||||
.indexCount(3)
|
||||
.bufferType(Filament.IndexBuffer$IndexType.USHORT)
|
||||
.build(engine);
|
||||
|
||||
this.ib.setBuffer(engine, new Uint16Array([0, 1, 2]));
|
||||
const mat = engine.createMaterial('../../web/assets/triangle/triangle.filamat');
|
||||
const matinst = mat.getDefaultInstance();
|
||||
Filament.RenderableManager.Builder(1)
|
||||
.boundingBox({ center: [-1, -1, -1], halfExtent: [1, 1, 1] })
|
||||
.material(0, matinst)
|
||||
.geometry(0, Filament.RenderableManager$PrimitiveType.TRIANGLES, this.vb, this.ib)
|
||||
.build(engine, this.triangle);
|
||||
this.swapChain = engine.createSwapChain();
|
||||
this.renderer = engine.createRenderer();
|
||||
this.camera = engine.createCamera(Filament.EntityManager.get().create());
|
||||
this.view = engine.createView();
|
||||
this.view.setCamera(this.camera);
|
||||
this.view.setScene(this.scene);
|
||||
|
||||
// Set up a blue-green background:
|
||||
this.renderer.setClearOptions({clearColor: [0.0, 0.1, 0.2, 1.0], clear: true});
|
||||
|
||||
// Adjust the initial viewport:
|
||||
this.resize();
|
||||
this.render = this.render.bind(this);
|
||||
this.resize = this.resize.bind(this);
|
||||
window.addEventListener('resize', this.resize);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
render() {
|
||||
// Rotate the triangle.
|
||||
const radians = Date.now() / 1000;
|
||||
const transform = mat4.fromRotation(mat4.create(), radians, [0, 0, 1]);
|
||||
const tcm = this.engine.getTransformManager();
|
||||
const inst = tcm.getInstance(this.triangle);
|
||||
tcm.setTransform(inst, transform);
|
||||
inst.delete();
|
||||
|
||||
// Render the frame.
|
||||
this.renderer.render(this.swapChain, this.view);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
resize() {
|
||||
const dpr = window.devicePixelRatio;
|
||||
const width = this.canvas.width = this.canvas.clientWidth * dpr;
|
||||
const height = this.canvas.height = this.canvas.clientHeight * dpr;
|
||||
this.view.setViewport([0, 0, width, height]);
|
||||
|
||||
const aspect = width / height;
|
||||
const Projection = Filament.Camera$Projection;
|
||||
this.camera.setProjection(Projection.ORTHO, -aspect, aspect, -1, 1, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
Filament.init(['../../web/assets/triangle/triangle.filamat'], () => { window.app = new App() } );
|
||||
</code></pre>
|
||||
<p>The two calls to <code>bind()</code> allow us to pass instance methods as callbacks for animation and resize
|
||||
events.</p>
|
||||
<p><code>Filament.init()</code> consumes two things: a list of asset URLs and a callback.</p>
|
||||
<p>The callback will be triggered only after all assets finish downloading and the Filament module has
|
||||
become ready. In our callback, we simply instantiated the <code>App</code> object, since we'll do most of the
|
||||
work in its constructor. We also set the app instance into a <code>Window</code> property to make it accessible
|
||||
from the developer console.</p>
|
||||
<p>Go ahead and download <a href="../../web/assets/triangle/triangle.filamat">triangle.filamat</a> and place it in your project folder.
|
||||
This is a <em>material package</em>, which is a binary file that contains shaders and other bits of data
|
||||
that define a PBR material. We'll learn more about material packages in the next tutorial.</p>
|
||||
<h2 id="spawn-a-local-server"><a class="header" href="#spawn-a-local-server">Spawn a local server</a></h2>
|
||||
<p>Because of CORS restrictions, your web app cannot fetch the material package directly from the
|
||||
file system. One way around this is to create a temporary server using Python or node:</p>
|
||||
<pre><code class="language-bash">python3 -m http.server # Python 3
|
||||
python -m SimpleHTTPServer # Python 2.7
|
||||
npx http-server -p 8000 # nodejs
|
||||
</code></pre>
|
||||
<p>To see if this works, navigate to <a href="http://localhost:8000">http://localhost:8000</a> and check if you
|
||||
can load the page without any errors appearing in the developer console.</p>
|
||||
<p>Take care not to use Python's simple server in production since it does not serve WebAssembly files
|
||||
with the correct MIME type.</p>
|
||||
<h2 id="create-the-engine-and-scene"><a class="header" href="#create-the-engine-and-scene">Create the Engine and Scene</a></h2>
|
||||
<p>We now have a basic skeleton that can respond to paint and resize events. Let's start adding
|
||||
Filament objects to the app. Insert the following code into the top of the app constructor.</p>
|
||||
<pre><code class="language-js">this.canvas = document.getElementsByTagName('canvas')[0];
|
||||
const engine = this.engine = Filament.Engine.create(this.canvas);
|
||||
</code></pre>
|
||||
<p>The above snippet creates the <code>Engine</code> by passing it a canvas DOM object. The engine needs the
|
||||
canvas in order to create a WebGL 2.0 context in its contructor.</p>
|
||||
<p>The engine is a factory for many Filament entities, including <code>Scene</code>, which is a flat container of
|
||||
entities. Let's go ahead and create a scene, then add a blank entity called <code>triangle</code> into the
|
||||
scene.</p>
|
||||
<pre><code class="language-js">this.scene = engine.createScene();
|
||||
this.triangle = Filament.EntityManager.get().create();
|
||||
this.scene.addEntity(this.triangle);
|
||||
</code></pre>
|
||||
<p>Filament uses an <a href="//en.wikipedia.org/wiki/Entity-component-system">Entity-Component System</a>.
|
||||
The triangle entity in the above snippet does not yet have an associated component. Later in the
|
||||
tutorial we will make it into a <em>renderable</em>. Renderables are entities that have associated draw
|
||||
calls.</p>
|
||||
<h2 id="construct-typed-arrays"><a class="header" href="#construct-typed-arrays">Construct typed arrays</a></h2>
|
||||
<p>Next we'll create two typed arrays: a positions array with XY coordinates for each vertex, and a
|
||||
colors array with a 32-bit word for each vertex.</p>
|
||||
<pre><code class="language-js">const TRIANGLE_POSITIONS = new Float32Array([
|
||||
1, 0,
|
||||
Math.cos(Math.PI * 2 / 3), Math.sin(Math.PI * 2 / 3),
|
||||
Math.cos(Math.PI * 4 / 3), Math.sin(Math.PI * 4 / 3),
|
||||
]);
|
||||
|
||||
const TRIANGLE_COLORS = new Uint32Array([0xffff0000, 0xff00ff00, 0xff0000ff]);
|
||||
</code></pre>
|
||||
<p>Next we'll use the positions and colors buffers to create a single <code>VertexBuffer</code> object.</p>
|
||||
<pre><code class="language-js">const VertexAttribute = Filament.VertexAttribute;
|
||||
const AttributeType = Filament.VertexBuffer$AttributeType;
|
||||
this.vb = Filament.VertexBuffer.Builder()
|
||||
.vertexCount(3)
|
||||
.bufferCount(2)
|
||||
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT2, 0, 8)
|
||||
.attribute(VertexAttribute.COLOR, 1, AttributeType.UBYTE4, 0, 4)
|
||||
.normalized(VertexAttribute.COLOR)
|
||||
.build(engine);
|
||||
|
||||
this.vb.setBufferAt(engine, 0, TRIANGLE_POSITIONS);
|
||||
this.vb.setBufferAt(engine, 1, TRIANGLE_COLORS);
|
||||
</code></pre>
|
||||
<p>The above snippet first creates aliases for two enum types, then constructs the vertex buffer using
|
||||
its <code>Builder</code> method. After that, it pushes two buffer objects into the appropriate slots using
|
||||
<code>setBufferAt</code>.</p>
|
||||
<p>In the Filament API, the above builder pattern is often used for constructing objects in lieu of
|
||||
long argument lists. The daisy chain of function calls allows the client code to be somewhat
|
||||
self-documenting.</p>
|
||||
<p>Our app sets up two buffer slots in the vertex buffer, and each slot is associated with a single
|
||||
attribute. Alternatively, we could have interleaved or concatenated these attributes into a single
|
||||
buffer slot.</p>
|
||||
<p>Next we'll construct an index buffer. The index buffer for our triangle is trivial: it simply holds
|
||||
the integers 0,1,2.</p>
|
||||
<pre><code class="language-js">this.ib = Filament.IndexBuffer.Builder()
|
||||
.indexCount(3)
|
||||
.bufferType(Filament.IndexBuffer$IndexType.USHORT)
|
||||
.build(engine);
|
||||
|
||||
this.ib.setBuffer(engine, new Uint16Array([0, 1, 2]));
|
||||
</code></pre>
|
||||
<p>Note that constructing an index buffer is similar to constructing a vertex buffer, but it only has
|
||||
one buffer slot, and it can only contain two types of data (USHORT or UINT).</p>
|
||||
<h2 id="finish-up-initialization"><a class="header" href="#finish-up-initialization">Finish up initialization</a></h2>
|
||||
<p>Next let's construct an actual <code>Material</code> from the material package that was downloaded (the
|
||||
material is an object; the package is just a binary blob), then extract the default
|
||||
<code>MaterialInstance</code> from the material object. Material instances have concrete values for their
|
||||
parameters, and they can be bound to renderables. We'll learn more about material instances in the
|
||||
next tutorial.</p>
|
||||
<p>After extracting the material instance, we can finally create a renderable component for the
|
||||
triangle by setting up a bounding box and passing in the vertex and index buffers.</p>
|
||||
<pre><code class="language-js">const mat = engine.createMaterial('../../web/assets/triangle/triangle.filamat');
|
||||
const matinst = mat.getDefaultInstance();
|
||||
Filament.RenderableManager.Builder(1)
|
||||
.boundingBox({ center: [-1, -1, -1], halfExtent: [1, 1, 1] })
|
||||
.material(0, matinst)
|
||||
.geometry(0, Filament.RenderableManager$PrimitiveType.TRIANGLES, this.vb, this.ib)
|
||||
.build(engine, this.triangle);
|
||||
</code></pre>
|
||||
<p>Next let's wrap up the initialization routine by creating the swap chain, renderer, camera, and
|
||||
view.</p>
|
||||
<pre><code class="language-js">this.swapChain = engine.createSwapChain();
|
||||
this.renderer = engine.createRenderer();
|
||||
this.camera = engine.createCamera(Filament.EntityManager.get().create());
|
||||
this.view = engine.createView();
|
||||
this.view.setCamera(this.camera);
|
||||
this.view.setScene(this.scene);
|
||||
|
||||
// Set up a blue-green background:
|
||||
this.renderer.setClearOptions({clearColor: [0.0, 0.1, 0.2, 1.0], clear: true});
|
||||
|
||||
// Adjust the initial viewport:
|
||||
this.resize();
|
||||
</code></pre>
|
||||
<p>At this point, we're done creating all Filament entities, and the code should run without errors.
|
||||
However the canvas is still blank!</p>
|
||||
<h2 id="render-and-resize-handlers"><a class="header" href="#render-and-resize-handlers">Render and resize handlers</a></h2>
|
||||
<p>Recall that our App class has a skeletal render method, which the browser calls every time it needs
|
||||
to repaint. Often this is 60 times a second.</p>
|
||||
<pre><code class="language-js">render() {
|
||||
// Rotate the triangle.
|
||||
const radians = Date.now() / 1000;
|
||||
const transform = mat4.fromRotation(mat4.create(), radians, [0, 0, 1]);
|
||||
const tcm = this.engine.getTransformManager();
|
||||
const inst = tcm.getInstance(this.triangle);
|
||||
tcm.setTransform(inst, transform);
|
||||
inst.delete();
|
||||
|
||||
// Render the frame.
|
||||
this.renderer.render(this.swapChain, this.view);
|
||||
window.requestAnimationFrame(this.render);
|
||||
}
|
||||
</code></pre>
|
||||
<p>Let's flesh this out by rotating the triangle and invoking the Filament renderer. Add the following
|
||||
code to the top of the render method.</p>
|
||||
<pre><code class="language-js">// Rotate the triangle.
|
||||
const radians = Date.now() / 1000;
|
||||
const transform = mat4.fromRotation(mat4.create(), radians, [0, 0, 1]);
|
||||
const tcm = this.engine.getTransformManager();
|
||||
const inst = tcm.getInstance(this.triangle);
|
||||
tcm.setTransform(inst, transform);
|
||||
inst.delete();
|
||||
|
||||
// Render the frame.
|
||||
this.renderer.render(this.swapChain, this.view);
|
||||
</code></pre>
|
||||
<p>The first half of our render method obtains the transform component of the triangle entity and uses
|
||||
gl-matrix to generate a rotation matrix.</p>
|
||||
<p>The second half of our render method invokes the Filament renderer on the view, and tells the
|
||||
Filament engine to execute its internal command buffer. The Filament renderer can tell the app
|
||||
that it wants to skip a frame, hence the <code>if</code> statement.</p>
|
||||
<p>One last step. Add the following code to the resize method. This adjusts the resolution of the
|
||||
rendering surface when the window size changes, taking <code>devicePixelRatio</code> into account for high-DPI
|
||||
displays. It also adjusts the camera frustum accordingly.</p>
|
||||
<pre><code class="language-js">const dpr = window.devicePixelRatio;
|
||||
const width = this.canvas.width = this.canvas.clientWidth * dpr;
|
||||
const height = this.canvas.height = this.canvas.clientHeight * dpr;
|
||||
this.view.setViewport([0, 0, width, height]);
|
||||
|
||||
const aspect = width / height;
|
||||
const Projection = Filament.Camera$Projection;
|
||||
this.camera.setProjection(Projection.ORTHO, -aspect, aspect, -1, 1, 0, 1);
|
||||
</code></pre>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../../samples/web/tutorials.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../samples/web/redball.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../../samples/web/tutorials.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../../samples/web/redball.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
window.playground_copyable = true;
|
||||
</script>
|
||||
|
||||
|
||||
<script src="../../elasticlunr.min.js"></script>
|
||||
<script src="../../mark.min.js"></script>
|
||||
<script src="../../searcher.js"></script>
|
||||
|
||||
<script src="../../clipboard.min.js"></script>
|
||||
<script src="../../highlight.js"></script>
|
||||
<script src="../../book.js"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>Web Tutorial - Filament</title>
|
||||
<title>Web Tutorials - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
@@ -12,19 +12,19 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="shortcut icon" href="../favicon.png">
|
||||
<link rel="stylesheet" href="../css/variables.css">
|
||||
<link rel="stylesheet" href="../css/general.css">
|
||||
<link rel="stylesheet" href="../css/chrome.css">
|
||||
<link rel="shortcut icon" href="../../favicon.png">
|
||||
<link rel="stylesheet" href="../../css/variables.css">
|
||||
<link rel="stylesheet" href="../../css/general.css">
|
||||
<link rel="stylesheet" href="../../css/chrome.css">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
||||
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../../fonts/fonts.css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../highlight.css">
|
||||
<link rel="stylesheet" href="../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../ayu-highlight.css">
|
||||
<link rel="stylesheet" href="../../highlight.css">
|
||||
<link rel="stylesheet" href="../../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
@@ -33,11 +33,11 @@
|
||||
|
||||
<!-- Provide site root to javascript -->
|
||||
<script>
|
||||
var path_to_root = "../";
|
||||
var path_to_root = "../../";
|
||||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../toc.js"></script>
|
||||
<script src="../../toc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body-container">
|
||||
@@ -87,12 +87,12 @@
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div style="display:flex;align-items:center;justify-content:center">
|
||||
<img class="flogo" src="../images/filament_logo_small.png"></img>
|
||||
<img class="flogo" src="../../images/filament_logo_small.png"></img>
|
||||
</div>
|
||||
<!-- populated by js -->
|
||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||||
<noscript>
|
||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
||||
<iframe class="sidebar-iframe-outer" src="../../toc.html"></iframe>
|
||||
</noscript>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||||
<div class="sidebar-resize-indicator"></div>
|
||||
@@ -158,35 +158,66 @@
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<h1 id="web-docs"><a class="header" href="#web-docs">Web Docs</a></h1>
|
||||
<h2 id="this-page-is-under-construction-links-are-not-working-at-the-moment"><a class="header" href="#this-page-is-under-construction-links-are-not-working-at-the-moment">[This page is under construction. Links are not working at the moment]</a></h2>
|
||||
<h2 id="tutorials"><a class="header" href="#tutorials">tutorials</a></h2>
|
||||
<ol>
|
||||
<li><a href="tutorial_triangle.html">Triangle Tutorial</a></li>
|
||||
<li><a href="tutorial_redball.html">Redball Tutorial</a></li>
|
||||
<li><a href="tutorial_suzanne.html">Suzanne Tutorial</a></li>
|
||||
</ol>
|
||||
<h2 id="demos"><a class="header" href="#demos">demos</a></h2>
|
||||
<ul>
|
||||
<li><a href="parquet.html">parquet</a></li>
|
||||
<li><a href="suzanne.html">suzanne</a></li>
|
||||
<li><a href="helmet.html">helmet</a></li>
|
||||
<li><a href="https://prideout.net/knotess/">knotess</a></li>
|
||||
</ul>
|
||||
<h2 id="other-documentation"><a class="header" href="#other-documentation">other documentation</a></h2>
|
||||
<ul>
|
||||
<li><a href="https://prideout.net/slides/filawasm">WebGL Meetup Slides</a> (2018)</li>
|
||||
</ul>
|
||||
<h1 id="web-tutorials"><a class="header" href="#web-tutorials">Web Tutorials</a></h1>
|
||||
<p>Here are the step-by-step tutorials to get you started with Filament on the Web.</p>
|
||||
<style>
|
||||
.sample-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
|
||||
gap: 20px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.sample-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
border: 1px solid var(--sidebar-bg);
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
background-color: var(--bg);
|
||||
}
|
||||
.sample-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
||||
text-decoration: none;
|
||||
}
|
||||
.sample-card img {
|
||||
border-radius: 4px;
|
||||
margin-bottom: 10px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
</style>
|
||||
<div class="sample-grid">
|
||||
<a href="triangle.html" class="sample-card">
|
||||
<img src="../../images/web_sample_triangle.png" alt="triangle" />
|
||||
<span>triangle</span>
|
||||
</a>
|
||||
<a href="redball.html" class="sample-card">
|
||||
<img src="../../images/web_sample_redball.png" alt="redball" />
|
||||
<span>redball</span>
|
||||
</a>
|
||||
<a href="suzanne.html" class="sample-card">
|
||||
<img src="../../images/web_sample_suzanne.png" alt="suzanne" />
|
||||
<span>suzanne</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../samples/ios.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../../samples/ios.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../notes/index.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../../samples/web/triangle.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
@@ -196,11 +227,11 @@
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../samples/ios.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../../samples/ios.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../notes/index.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../../samples/web/triangle.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
@@ -215,13 +246,13 @@
|
||||
</script>
|
||||
|
||||
|
||||
<script src="../elasticlunr.min.js"></script>
|
||||
<script src="../mark.min.js"></script>
|
||||
<script src="../searcher.js"></script>
|
||||
<script src="../../elasticlunr.min.js"></script>
|
||||
<script src="../../mark.min.js"></script>
|
||||
<script src="../../searcher.js"></script>
|
||||
|
||||
<script src="../clipboard.min.js"></script>
|
||||
<script src="../highlight.js"></script>
|
||||
<script src="../book.js"></script>
|
||||
<script src="../../clipboard.min.js"></script>
|
||||
<script src="../../highlight.js"></script>
|
||||
<script src="../../book.js"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
@@ -38,12 +38,12 @@ filament-viewer::part(canvas) {
|
||||
<p>
|
||||
<filament-viewer
|
||||
enableDrop="true"
|
||||
ibl="../webgl/default_env/default_env_ibl.ktx"
|
||||
ibl="../web/assets/helmet/default_env/default_env_ibl.ktx"
|
||||
intensity="20000" />
|
||||
</p>
|
||||
|
||||
</main>
|
||||
<script src="https://unpkg.com/filament@1.51.6/filament.js"></script>
|
||||
<script src="../web/lib/filament.js"></script>
|
||||
<script src="https://unpkg.com/gltumble"></script>
|
||||
<script src="filament-viewer.js" type="module"></script>
|
||||
</body>
|
||||
|
||||
117
docs/web/assets/animation/AnimatedTriangle.gltf
Normal file
@@ -0,0 +1,117 @@
|
||||
{
|
||||
"scenes" : [
|
||||
{
|
||||
"nodes" : [ 0 ]
|
||||
}
|
||||
],
|
||||
|
||||
"nodes" : [
|
||||
{
|
||||
"mesh" : 0,
|
||||
"rotation" : [ 0.0, 0.0, 0.0, 1.0 ]
|
||||
}
|
||||
],
|
||||
|
||||
"meshes" : [
|
||||
{
|
||||
"primitives" : [ {
|
||||
"attributes" : {
|
||||
"POSITION" : 1
|
||||
},
|
||||
"indices" : 0
|
||||
} ]
|
||||
}
|
||||
],
|
||||
|
||||
"animations": [
|
||||
{
|
||||
"samplers" : [
|
||||
{
|
||||
"input" : 2,
|
||||
"interpolation" : "LINEAR",
|
||||
"output" : 3
|
||||
}
|
||||
],
|
||||
"channels" : [ {
|
||||
"sampler" : 0,
|
||||
"target" : {
|
||||
"node" : 0,
|
||||
"path" : "rotation"
|
||||
}
|
||||
} ]
|
||||
}
|
||||
],
|
||||
|
||||
"buffers" : [
|
||||
{
|
||||
"uri" : "simpleTriangle.bin",
|
||||
"byteLength" : 44
|
||||
},
|
||||
{
|
||||
"uri" : "animation.bin",
|
||||
"byteLength" : 100
|
||||
}
|
||||
],
|
||||
"bufferViews" : [
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteOffset" : 0,
|
||||
"byteLength" : 6,
|
||||
"target" : 34963
|
||||
},
|
||||
{
|
||||
"buffer" : 0,
|
||||
"byteOffset" : 8,
|
||||
"byteLength" : 36,
|
||||
"target" : 34962
|
||||
},
|
||||
{
|
||||
"buffer" : 1,
|
||||
"byteOffset" : 0,
|
||||
"byteLength" : 100
|
||||
}
|
||||
],
|
||||
"accessors" : [
|
||||
{
|
||||
"bufferView" : 0,
|
||||
"byteOffset" : 0,
|
||||
"componentType" : 5123,
|
||||
"count" : 3,
|
||||
"type" : "SCALAR",
|
||||
"max" : [ 2 ],
|
||||
"min" : [ 0 ]
|
||||
},
|
||||
{
|
||||
"bufferView" : 1,
|
||||
"byteOffset" : 0,
|
||||
"componentType" : 5126,
|
||||
"count" : 3,
|
||||
"type" : "VEC3",
|
||||
"max" : [ 1.0, 1.0, 0.0 ],
|
||||
"min" : [ 0.0, 0.0, 0.0 ]
|
||||
},
|
||||
{
|
||||
"bufferView" : 2,
|
||||
"byteOffset" : 0,
|
||||
"componentType" : 5126,
|
||||
"count" : 5,
|
||||
"type" : "SCALAR",
|
||||
"max" : [ 1.0 ],
|
||||
"min" : [ 0.0 ]
|
||||
},
|
||||
{
|
||||
"bufferView" : 2,
|
||||
"byteOffset" : 20,
|
||||
"componentType" : 5126,
|
||||
"count" : 5,
|
||||
"type" : "VEC4",
|
||||
"max" : [ 0.0, 0.0, 1.0, 1.0 ],
|
||||
"min" : [ 0.0, 0.0, 0.0, -0.707 ]
|
||||
}
|
||||
],
|
||||
|
||||
"asset" : {
|
||||
"version" : "2.0"
|
||||
}
|
||||
|
||||
}
|
||||
BIN
docs/web/assets/animation/animation.bin
Normal file
BIN
docs/web/assets/animation/default_env/default_env_ibl.ktx
Normal file
BIN
docs/web/assets/animation/default_env/default_env_skybox.ktx
Normal file
BIN
docs/web/assets/animation/simpleTriangle.bin
Normal file
|
After Width: | Height: | Size: 44 B |
BIN
docs/web/assets/cube_fl0/nonlit_fl0.filamat
Normal file
BIN
docs/web/assets/favicon.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
docs/web/assets/helmet/FlightHelmet.bin
Normal file
755
docs/web/assets/helmet/FlightHelmet.gltf
Normal file
@@ -0,0 +1,755 @@
|
||||
{
|
||||
"accessors": [
|
||||
{
|
||||
"componentType": 5123,
|
||||
"count": 24408,
|
||||
"type": "SCALAR"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 8468,
|
||||
"type": "VEC2"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 8468,
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 8468,
|
||||
"type": "VEC4"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 8468,
|
||||
"type": "VEC3",
|
||||
"max": [
|
||||
0.131662,
|
||||
0.137638986,
|
||||
0.10078799
|
||||
],
|
||||
"min": [
|
||||
-0.131333,
|
||||
-0.028128,
|
||||
-0.137763992
|
||||
]
|
||||
},
|
||||
{
|
||||
"componentType": 5123,
|
||||
"count": 65688,
|
||||
"type": "SCALAR"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 12552,
|
||||
"type": "VEC2"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 12552,
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 12552,
|
||||
"type": "VEC4"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 12552,
|
||||
"type": "VEC3",
|
||||
"max": [
|
||||
0.11722149,
|
||||
0.196387976,
|
||||
0.132422984
|
||||
],
|
||||
"min": [
|
||||
-0.11722149,
|
||||
-0.196387976,
|
||||
-0.132422984
|
||||
]
|
||||
},
|
||||
{
|
||||
"componentType": 5123,
|
||||
"count": 2208,
|
||||
"type": "SCALAR"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 436,
|
||||
"type": "VEC2"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 436,
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 436,
|
||||
"type": "VEC4"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 436,
|
||||
"type": "VEC3",
|
||||
"max": [
|
||||
0.09527509,
|
||||
0.114654,
|
||||
-0.08429489
|
||||
],
|
||||
"min": [
|
||||
-0.0952748954,
|
||||
0.0551489964,
|
||||
-0.14295499
|
||||
]
|
||||
},
|
||||
{
|
||||
"componentType": 5123,
|
||||
"count": 60288,
|
||||
"type": "SCALAR"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 17186,
|
||||
"type": "VEC2"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 17186,
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 17186,
|
||||
"type": "VEC4"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 17186,
|
||||
"type": "VEC3",
|
||||
"max": [
|
||||
0.1572095,
|
||||
0.2716865,
|
||||
0.162181988
|
||||
],
|
||||
"min": [
|
||||
-0.1572095,
|
||||
-0.2716865,
|
||||
-0.162181988
|
||||
]
|
||||
},
|
||||
{
|
||||
"componentType": 5123,
|
||||
"count": 131574,
|
||||
"type": "SCALAR"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 24148,
|
||||
"type": "VEC2"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 24148,
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 24148,
|
||||
"type": "VEC4"
|
||||
},
|
||||
{
|
||||
"componentType": 5126,
|
||||
"count": 24148,
|
||||
"type": "VEC3",
|
||||
"max": [
|
||||
0.1504075,
|
||||
0.328366965,
|
||||
0.173673
|
||||
],
|
||||
"min": [
|
||||
-0.1504075,
|
||||
-0.328366965,
|
||||
-0.173673
|
||||
]
|
||||
}
|
||||
],
|
||||
"asset": {
|
||||
"generator": "glTF Tools for Unity",
|
||||
"version": "2.0"
|
||||
},
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 0,
|
||||
"byteLength": 59806
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 59808,
|
||||
"byteLength": 99674
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 159484,
|
||||
"byteLength": 4875
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 164360,
|
||||
"byteLength": 133545
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 297908,
|
||||
"byteLength": 203914
|
||||
}
|
||||
],
|
||||
"buffers": [
|
||||
{
|
||||
"name": "FlightHelmet",
|
||||
"byteLength": 501824,
|
||||
"uri": "FlightHelmet.bin"
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
{
|
||||
"name": "FlightHelmet_baseColor",
|
||||
"uri": "FlightHelmet_baseColor.png"
|
||||
},
|
||||
{
|
||||
"name": "FlightHelmet_occlusionRoughnessMetallic",
|
||||
"uri": "FlightHelmet_occlusionRoughnessMetallic.png"
|
||||
},
|
||||
{
|
||||
"name": "FlightHelmet_normal",
|
||||
"uri": "FlightHelmet_normal.png"
|
||||
},
|
||||
{
|
||||
"name": "FlightHelmet_baseColor1",
|
||||
"uri": "FlightHelmet_baseColor1.png"
|
||||
},
|
||||
{
|
||||
"name": "FlightHelmet_occlusionRoughnessMetallic1",
|
||||
"uri": "FlightHelmet_occlusionRoughnessMetallic1.png"
|
||||
},
|
||||
{
|
||||
"name": "FlightHelmet_normal1",
|
||||
"uri": "FlightHelmet_normal1.png"
|
||||
},
|
||||
{
|
||||
"name": "FlightHelmet_baseColor2",
|
||||
"uri": "FlightHelmet_baseColor2.png"
|
||||
},
|
||||
{
|
||||
"name": "FlightHelmet_occlusionRoughnessMetallic2",
|
||||
"uri": "FlightHelmet_occlusionRoughnessMetallic2.png"
|
||||
},
|
||||
{
|
||||
"name": "FlightHelmet_normal2",
|
||||
"uri": "FlightHelmet_normal2.png"
|
||||
},
|
||||
{
|
||||
"name": "FlightHelmet_baseColor3",
|
||||
"uri": "FlightHelmet_baseColor3.png"
|
||||
},
|
||||
{
|
||||
"name": "FlightHelmet_occlusionRoughnessMetallic3",
|
||||
"uri": "FlightHelmet_occlusionRoughnessMetallic3.png"
|
||||
},
|
||||
{
|
||||
"name": "FlightHelmet_normal3",
|
||||
"uri": "FlightHelmet_normal3.png"
|
||||
},
|
||||
{
|
||||
"name": "FlightHelmet_baseColor4",
|
||||
"uri": "FlightHelmet_baseColor4.png"
|
||||
},
|
||||
{
|
||||
"name": "FlightHelmet_occlusionRoughnessMetallic4",
|
||||
"uri": "FlightHelmet_occlusionRoughnessMetallic4.png"
|
||||
},
|
||||
{
|
||||
"name": "FlightHelmet_normal4",
|
||||
"uri": "FlightHelmet_normal4.png"
|
||||
}
|
||||
],
|
||||
"meshes": [
|
||||
{
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"TEXCOORD_0": 1,
|
||||
"NORMAL": 2,
|
||||
"TANGENT": 3,
|
||||
"POSITION": 4
|
||||
},
|
||||
"indices": 0,
|
||||
"material": 0,
|
||||
"mode": 4,
|
||||
"extensions": {
|
||||
"KHR_draco_mesh_compression": {
|
||||
"bufferView": 0,
|
||||
"attributes": {
|
||||
"TEXCOORD_0": 0,
|
||||
"NORMAL": 1,
|
||||
"TANGENT": 2,
|
||||
"POSITION": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "GlassPlastic_low"
|
||||
},
|
||||
{
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"TEXCOORD_0": 6,
|
||||
"NORMAL": 7,
|
||||
"TANGENT": 8,
|
||||
"POSITION": 9
|
||||
},
|
||||
"indices": 5,
|
||||
"material": 1,
|
||||
"mode": 4,
|
||||
"extensions": {
|
||||
"KHR_draco_mesh_compression": {
|
||||
"bufferView": 1,
|
||||
"attributes": {
|
||||
"TEXCOORD_0": 0,
|
||||
"NORMAL": 1,
|
||||
"TANGENT": 2,
|
||||
"POSITION": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "LeatherParts_low"
|
||||
},
|
||||
{
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"TEXCOORD_0": 11,
|
||||
"NORMAL": 12,
|
||||
"TANGENT": 13,
|
||||
"POSITION": 14
|
||||
},
|
||||
"indices": 10,
|
||||
"material": 2,
|
||||
"mode": 4,
|
||||
"extensions": {
|
||||
"KHR_draco_mesh_compression": {
|
||||
"bufferView": 2,
|
||||
"attributes": {
|
||||
"TEXCOORD_0": 0,
|
||||
"NORMAL": 1,
|
||||
"TANGENT": 2,
|
||||
"POSITION": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "Lenses_low"
|
||||
},
|
||||
{
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"TEXCOORD_0": 16,
|
||||
"NORMAL": 17,
|
||||
"TANGENT": 18,
|
||||
"POSITION": 19
|
||||
},
|
||||
"indices": 15,
|
||||
"material": 3,
|
||||
"mode": 4,
|
||||
"extensions": {
|
||||
"KHR_draco_mesh_compression": {
|
||||
"bufferView": 3,
|
||||
"attributes": {
|
||||
"TEXCOORD_0": 0,
|
||||
"NORMAL": 1,
|
||||
"TANGENT": 2,
|
||||
"POSITION": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "MetalParts_low"
|
||||
},
|
||||
{
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"TEXCOORD_0": 21,
|
||||
"NORMAL": 22,
|
||||
"TANGENT": 23,
|
||||
"POSITION": 24
|
||||
},
|
||||
"indices": 20,
|
||||
"material": 4,
|
||||
"mode": 4,
|
||||
"extensions": {
|
||||
"KHR_draco_mesh_compression": {
|
||||
"bufferView": 4,
|
||||
"attributes": {
|
||||
"TEXCOORD_0": 0,
|
||||
"NORMAL": 1,
|
||||
"TANGENT": 2,
|
||||
"POSITION": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"name": "RubberWood_low"
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"pbrMetallicRoughness": {
|
||||
"baseColorTexture": {
|
||||
"index": 0,
|
||||
"texCoord": 0
|
||||
},
|
||||
"metallicRoughnessTexture": {
|
||||
"index": 1,
|
||||
"texCoord": 0
|
||||
},
|
||||
"baseColorFactor": [
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"metallicFactor": 1,
|
||||
"roughnessFactor": 1
|
||||
},
|
||||
"normalTexture": {
|
||||
"index": 2,
|
||||
"texCoord": 0
|
||||
},
|
||||
"occlusionTexture": {
|
||||
"index": 1,
|
||||
"texCoord": 0
|
||||
},
|
||||
"name": "GlassPlasticMat",
|
||||
"emissiveFactor": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"alphaMode": "OPAQUE",
|
||||
"doubleSided": false
|
||||
},
|
||||
{
|
||||
"pbrMetallicRoughness": {
|
||||
"baseColorTexture": {
|
||||
"index": 3,
|
||||
"texCoord": 0
|
||||
},
|
||||
"metallicRoughnessTexture": {
|
||||
"index": 4,
|
||||
"texCoord": 0
|
||||
},
|
||||
"baseColorFactor": [
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"metallicFactor": 1,
|
||||
"roughnessFactor": 1
|
||||
},
|
||||
"normalTexture": {
|
||||
"index": 5,
|
||||
"texCoord": 0
|
||||
},
|
||||
"occlusionTexture": {
|
||||
"index": 4,
|
||||
"texCoord": 0
|
||||
},
|
||||
"name": "LeatherPartsMat",
|
||||
"emissiveFactor": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"alphaMode": "OPAQUE",
|
||||
"doubleSided": false
|
||||
},
|
||||
{
|
||||
"pbrMetallicRoughness": {
|
||||
"baseColorTexture": {
|
||||
"index": 6,
|
||||
"texCoord": 0
|
||||
},
|
||||
"metallicRoughnessTexture": {
|
||||
"index": 7,
|
||||
"texCoord": 0
|
||||
},
|
||||
"baseColorFactor": [
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"metallicFactor": 1,
|
||||
"roughnessFactor": 1
|
||||
},
|
||||
"normalTexture": {
|
||||
"index": 8,
|
||||
"texCoord": 0
|
||||
},
|
||||
"occlusionTexture": {
|
||||
"index": 7,
|
||||
"texCoord": 0
|
||||
},
|
||||
"alphaMode": "BLEND",
|
||||
"name": "LensesMat",
|
||||
"emissiveFactor": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"doubleSided": false
|
||||
},
|
||||
{
|
||||
"pbrMetallicRoughness": {
|
||||
"baseColorTexture": {
|
||||
"index": 9,
|
||||
"texCoord": 0
|
||||
},
|
||||
"metallicRoughnessTexture": {
|
||||
"index": 10,
|
||||
"texCoord": 0
|
||||
},
|
||||
"baseColorFactor": [
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"metallicFactor": 1,
|
||||
"roughnessFactor": 1
|
||||
},
|
||||
"normalTexture": {
|
||||
"index": 11,
|
||||
"texCoord": 0
|
||||
},
|
||||
"occlusionTexture": {
|
||||
"index": 10,
|
||||
"texCoord": 0
|
||||
},
|
||||
"name": "MetalPartsMat",
|
||||
"emissiveFactor": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"alphaMode": "OPAQUE",
|
||||
"doubleSided": false
|
||||
},
|
||||
{
|
||||
"doubleSided": true,
|
||||
"pbrMetallicRoughness": {
|
||||
"baseColorTexture": {
|
||||
"index": 12,
|
||||
"texCoord": 0
|
||||
},
|
||||
"metallicRoughnessTexture": {
|
||||
"index": 13,
|
||||
"texCoord": 0
|
||||
},
|
||||
"baseColorFactor": [
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"metallicFactor": 1,
|
||||
"roughnessFactor": 1
|
||||
},
|
||||
"normalTexture": {
|
||||
"index": 14,
|
||||
"texCoord": 0
|
||||
},
|
||||
"occlusionTexture": {
|
||||
"index": 13,
|
||||
"texCoord": 0
|
||||
},
|
||||
"name": "RubberWoodMat",
|
||||
"emissiveFactor": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"alphaMode": "OPAQUE"
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"mesh": 0,
|
||||
"name": "GlassPlastic_low"
|
||||
},
|
||||
{
|
||||
"mesh": 1,
|
||||
"translation": [
|
||||
0.000434499962,
|
||||
0.032592997,
|
||||
0.011676996
|
||||
],
|
||||
"name": "LeatherParts_low",
|
||||
"rotation": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"scale": [
|
||||
1,
|
||||
1,
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"mesh": 2,
|
||||
"name": "Lenses_low"
|
||||
},
|
||||
{
|
||||
"mesh": 3,
|
||||
"translation": [
|
||||
0.0331545,
|
||||
-0.1488645,
|
||||
-0.0242879968
|
||||
],
|
||||
"name": "MetalParts_low",
|
||||
"rotation": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"scale": [
|
||||
1,
|
||||
1,
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"mesh": 4,
|
||||
"translation": [
|
||||
-0.00190849893,
|
||||
-0.111985,
|
||||
-0.013313001
|
||||
],
|
||||
"name": "RubberWood_low",
|
||||
"rotation": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"scale": [
|
||||
1,
|
||||
1,
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
],
|
||||
"rotation": [
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"name": "FlightHelmet",
|
||||
"translation": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"scale": [
|
||||
1,
|
||||
1,
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"scene": 0,
|
||||
"scenes": [
|
||||
{
|
||||
"nodes": [
|
||||
5
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures": [
|
||||
{
|
||||
"source": 0
|
||||
},
|
||||
{
|
||||
"source": 1
|
||||
},
|
||||
{
|
||||
"source": 2
|
||||
},
|
||||
{
|
||||
"source": 3
|
||||
},
|
||||
{
|
||||
"source": 4
|
||||
},
|
||||
{
|
||||
"source": 5
|
||||
},
|
||||
{
|
||||
"source": 6
|
||||
},
|
||||
{
|
||||
"source": 7
|
||||
},
|
||||
{
|
||||
"source": 8
|
||||
},
|
||||
{
|
||||
"source": 9
|
||||
},
|
||||
{
|
||||
"source": 10
|
||||
},
|
||||
{
|
||||
"source": 11
|
||||
},
|
||||
{
|
||||
"source": 12
|
||||
},
|
||||
{
|
||||
"source": 13
|
||||
},
|
||||
{
|
||||
"source": 14
|
||||
}
|
||||
],
|
||||
"extensionsRequired": [
|
||||
"KHR_draco_mesh_compression"
|
||||
],
|
||||
"extensionsUsed": [
|
||||
"KHR_draco_mesh_compression"
|
||||
]
|
||||
}
|
||||
BIN
docs/web/assets/helmet/FlightHelmet_baseColor.png
Normal file
|
After Width: | Height: | Size: 2.6 MiB |
BIN
docs/web/assets/helmet/FlightHelmet_baseColor1.png
Normal file
|
After Width: | Height: | Size: 5.1 MiB |
BIN
docs/web/assets/helmet/FlightHelmet_baseColor2.png
Normal file
|
After Width: | Height: | Size: 806 KiB |
BIN
docs/web/assets/helmet/FlightHelmet_baseColor3.png
Normal file
|
After Width: | Height: | Size: 2.9 MiB |
BIN
docs/web/assets/helmet/FlightHelmet_baseColor4.png
Normal file
|
After Width: | Height: | Size: 3.8 MiB |
BIN
docs/web/assets/helmet/FlightHelmet_normal.png
Normal file
|
After Width: | Height: | Size: 3.0 MiB |
BIN
docs/web/assets/helmet/FlightHelmet_normal1.png
Normal file
|
After Width: | Height: | Size: 5.4 MiB |
BIN
docs/web/assets/helmet/FlightHelmet_normal2.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
docs/web/assets/helmet/FlightHelmet_normal3.png
Normal file
|
After Width: | Height: | Size: 3.5 MiB |
BIN
docs/web/assets/helmet/FlightHelmet_normal4.png
Normal file
|
After Width: | Height: | Size: 3.5 MiB |
|
After Width: | Height: | Size: 4.4 MiB |
|
After Width: | Height: | Size: 5.1 MiB |
|
After Width: | Height: | Size: 737 KiB |
|
After Width: | Height: | Size: 3.6 MiB |
|
After Width: | Height: | Size: 4.3 MiB |
BIN
docs/web/assets/helmet/default_env/default_env_ibl.ktx
Normal file
BIN
docs/web/assets/helmet/default_env/default_env_skybox.ktx
Normal file
BIN
docs/web/assets/helmet/default_env/default_env_skybox_tiny.ktx
Normal file
121
docs/web/assets/main.css
Normal file
@@ -0,0 +1,121 @@
|
||||
body {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
font-size: 10.5pt;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
div.highlight {
|
||||
padding-left: 5px;
|
||||
border-left: solid 1px gray;
|
||||
}
|
||||
|
||||
code, div.highlight pre {
|
||||
font-family: 'Inconsolata', monospace;
|
||||
}
|
||||
|
||||
.verbiage {
|
||||
max-width: 800px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: solid 1px #ccc;
|
||||
}
|
||||
|
||||
.verbiage a {
|
||||
color: rgb(0, 137, 235);
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: rgb(0, 157, 255);
|
||||
}
|
||||
|
||||
.active {
|
||||
color: rgb(0, 137, 235);
|
||||
}
|
||||
|
||||
.disabled, .disabled:hover {
|
||||
color: #ccc;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: 'Tangerine', cursive;
|
||||
font-weight: 700;
|
||||
font-size: 50px;
|
||||
margin: 10px 0 0 0;
|
||||
}
|
||||
|
||||
nav {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
nav h2 {
|
||||
font-size: 12px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
nav li {
|
||||
margin: 2px 0;
|
||||
}
|
||||
|
||||
.HolyGrail,
|
||||
.HolyGrail-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.HolyGrail-nav {
|
||||
order: -1;
|
||||
}
|
||||
|
||||
@media (min-width: 500px) {
|
||||
.HolyGrail-body {
|
||||
flex-direction: row;
|
||||
flex: 1;
|
||||
}
|
||||
.HolyGrail-content {
|
||||
flex: 1;
|
||||
}
|
||||
.HolyGrail-nav {
|
||||
/* 12em is the width of the columns */
|
||||
flex: 0 0 12em;
|
||||
}
|
||||
article {
|
||||
padding: 10px;
|
||||
border-left: solid 1px #ccc;
|
||||
}
|
||||
nav {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
div.demo_frame {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
div.demo_frame > a {
|
||||
position: relative;
|
||||
float: right;
|
||||
right: 10px;
|
||||
bottom: 35px;
|
||||
}
|
||||
BIN
docs/web/assets/morphing/AnimatedMorphCube.glb
Normal file
BIN
docs/web/assets/morphing/default_env/default_env_ibl.ktx
Normal file
BIN
docs/web/assets/morphing/default_env/default_env_skybox.ktx
Normal file
BIN
docs/web/assets/morphing/default_env/default_env_skybox_tiny.ktx
Normal file
BIN
docs/web/assets/parquet/default_env/default_env_ibl.ktx
Normal file
BIN
docs/web/assets/parquet/default_env/default_env_skybox.ktx
Normal file
BIN
docs/web/assets/parquet/default_env/default_env_skybox_tiny.ktx
Normal file
BIN
docs/web/assets/parquet/floor_ao_roughness_metallic.png
Normal file
|
After Width: | Height: | Size: 678 KiB |
BIN
docs/web/assets/parquet/floor_basecolor.jpg
Normal file
|
After Width: | Height: | Size: 226 KiB |
BIN
docs/web/assets/parquet/floor_normal.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
docs/web/assets/parquet/parquet.filamat
Normal file
BIN
docs/web/assets/parquet/shader_ball.filamesh
Normal file
BIN
docs/web/assets/redball/pillars_2k/pillars_2k_ibl.ktx
Normal file
BIN
docs/web/assets/redball/pillars_2k/pillars_2k_skybox.ktx
Normal file
BIN
docs/web/assets/redball/pillars_2k/pillars_2k_skybox_tiny.ktx
Normal file
BIN
docs/web/assets/redball/plastic.filamat
Normal file
BIN
docs/web/assets/skinning/default_env/default_env_ibl.ktx
Normal file
BIN
docs/web/assets/skinning/default_env/default_env_skybox.ktx
Normal file
BIN
docs/web/assets/skinning/default_env/default_env_skybox_tiny.ktx
Normal file
BIN
docs/web/assets/skinning/simpleTriangle.bin
Normal file
|
After Width: | Height: | Size: 44 B |