Compare commits
21
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d59459f90 | ||
|
|
4249ff6cfb | ||
|
|
1076433fc0 | ||
|
|
3bd0039ee9 | ||
|
|
67b9c72442 | ||
|
|
c1a8d73384 | ||
|
|
2d98ac878e | ||
|
|
35ab5f768d | ||
|
|
705b3c39f4 | ||
|
|
56231db326 | ||
|
|
e97f7ef628 | ||
|
|
4570c2e710 | ||
|
|
4759237e66 | ||
|
|
543b93939a | ||
|
|
9b356926b8 | ||
|
|
7179ab5b9d | ||
|
|
0a6bbdb35c | ||
|
|
29919e64cd | ||
|
|
a7660e40f8 | ||
|
|
22e1f9b930 | ||
|
|
e205611128 |
@@ -31,7 +31,7 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.google.android.filament:filament-android:1.59.3'
|
implementation 'com.google.android.filament:filament-android:1.59.4'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
|||||||
iOS projects can use CocoaPods to install the latest release:
|
iOS projects can use CocoaPods to install the latest release:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
pod 'Filament', '~> 1.59.3'
|
pod 'Filament', '~> 1.59.4'
|
||||||
```
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ A new header is inserted each time a *tag* is created.
|
|||||||
Instead, if you are authoring a PR for the main branch, add your release note to
|
Instead, if you are authoring a PR for the main branch, add your release note to
|
||||||
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
||||||
|
|
||||||
|
## v1.59.5
|
||||||
|
|
||||||
|
|
||||||
## v1.59.4
|
## v1.59.4
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1980,7 +1980,7 @@ public class View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* reconstruction filter width typically between 0.2 (sharper, aliased) and 1.5 (smoother)
|
* reconstruction filter width typically between 1 (sharper) and 2 (smoother)
|
||||||
*/
|
*/
|
||||||
public float filterWidth = 1.0f;
|
public float filterWidth = 1.0f;
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
GROUP=com.google.android.filament
|
GROUP=com.google.android.filament
|
||||||
VERSION_NAME=1.59.3
|
VERSION_NAME=1.59.4
|
||||||
|
|
||||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||||
|
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
+36
-19
@@ -166,7 +166,7 @@ This document is part of the <a href="https://github.com/google/filament">Filame
|
|||||||
</p><ul>
|
</p><ul>
|
||||||
<li class="minus"><a href="https://github.com/romainguy">Romain Guy</a>, <a href="https://twitter.com/romainguy">@romainguy</a>
|
<li class="minus"><a href="https://github.com/romainguy">Romain Guy</a>, <a href="https://twitter.com/romainguy">@romainguy</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="minus"><a href="https://github.com/pixelflinger">Mathias Agopian</a>, <a href="https://twitter.com/darthmoosious">@darthmoosious</a></li></ul>
|
<li class="minus"><a href="https://github.com/pixelflinger">Mathias Agopian</a>, <a href="https://bsky.app/profile/pixelflinger.bsky.social">@pixelflinger</a></li></ul>
|
||||||
|
|
||||||
<p></p>
|
<p></p>
|
||||||
<a class="target" name="overview"> </a><a class="target" name="overview"> </a><a class="target" name="toc2"> </a><h1>Overview</h1>
|
<a class="target" name="overview"> </a><a class="target" name="overview"> </a><a class="target" name="toc2"> </a><h1>Overview</h1>
|
||||||
@@ -259,26 +259,27 @@ in <a href="#table_standardproperties">table 1</a>.
|
|||||||
</p><div class="table">
|
</p><div class="table">
|
||||||
<table class="table"><tbody><tr><th style="text-align:right"> Property </th><th style="text-align:left"> Definition </th></tr>
|
<table class="table"><tbody><tr><th style="text-align:right"> Property </th><th style="text-align:left"> Definition </th></tr>
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">baseColor</strong> </td><td style="text-align:left"> Diffuse albedo for non-metallic surfaces, and specular color for metallic surfaces </td></tr>
|
<tr><td style="text-align:right"> <strong class="asterisk">baseColor</strong> </td><td style="text-align:left"> Diffuse albedo for non-metallic surfaces, and specular color for metallic surfaces </td></tr>
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">metallic</strong> </td><td style="text-align:left"> Whether a surface appears to be dielectric (0.0) or conductor (1.0). Often used as a binary value (0 or 1) </td></tr>
|
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">roughness</strong> </td><td style="text-align:left"> Perceived smoothness (1.0) or roughness (0.0) of a surface. Smooth surfaces exhibit sharp reflections </td></tr>
|
<tr><td style="text-align:right"> <strong class="asterisk">roughness</strong> </td><td style="text-align:left"> Perceived smoothness (1.0) or roughness (0.0) of a surface. Smooth surfaces exhibit sharp reflections </td></tr>
|
||||||
|
<tr><td style="text-align:right"> <strong class="asterisk">metallic</strong> </td><td style="text-align:left"> Whether a surface appears to be dielectric (0.0) or conductor (1.0). Often used as a binary value (0 or 1) </td></tr>
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">reflectance</strong> </td><td style="text-align:left"> Fresnel reflectance at normal incidence for dielectric surfaces. This directly controls the strength of the reflections </td></tr>
|
<tr><td style="text-align:right"> <strong class="asterisk">reflectance</strong> </td><td style="text-align:left"> Fresnel reflectance at normal incidence for dielectric surfaces. This directly controls the strength of the reflections </td></tr>
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">sheenColor</strong> </td><td style="text-align:left"> Strength of the sheen layer </td></tr>
|
<tr><td style="text-align:right"> <strong class="asterisk">ambientOcclusion</strong> </td><td style="text-align:left"> Defines how much of the ambient light is accessible to a surface point. It is a per-pixel shadowing factor between 0.0 and 1.0 </td></tr>
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">sheenRoughness</strong> </td><td style="text-align:left"> Perceived smoothness or roughness of the sheen layer </td></tr>
|
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">clearCoat</strong> </td><td style="text-align:left"> Strength of the clear coat layer </td></tr>
|
<tr><td style="text-align:right"> <strong class="asterisk">clearCoat</strong> </td><td style="text-align:left"> Strength of the clear coat layer </td></tr>
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">clearCoatRoughness</strong> </td><td style="text-align:left"> Perceived smoothness or roughness of the clear coat layer </td></tr>
|
<tr><td style="text-align:right"> <strong class="asterisk">clearCoatRoughness</strong> </td><td style="text-align:left"> Perceived smoothness or roughness of the clear coat layer </td></tr>
|
||||||
|
<tr><td style="text-align:right"> <strong class="asterisk">clearCoatNormal</strong> </td><td style="text-align:left"> A detail normal used to perturb the clear coat layer using <em class="underscore">bump mapping</em> (<em class="underscore">normal mapping</em>) </td></tr>
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">anisotropy</strong> </td><td style="text-align:left"> Amount of anisotropy in either the tangent or bitangent direction </td></tr>
|
<tr><td style="text-align:right"> <strong class="asterisk">anisotropy</strong> </td><td style="text-align:left"> Amount of anisotropy in either the tangent or bitangent direction </td></tr>
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">anisotropyDirection</strong> </td><td style="text-align:left"> Local surface direction in tangent space </td></tr>
|
<tr><td style="text-align:right"> <strong class="asterisk">anisotropyDirection</strong> </td><td style="text-align:left"> Local surface direction in tangent space </td></tr>
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">ambientOcclusion</strong> </td><td style="text-align:left"> Defines how much of the ambient light is accessible to a surface point. It is a per-pixel shadowing factor between 0.0 and 1.0 </td></tr>
|
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">normal</strong> </td><td style="text-align:left"> A detail normal used to perturb the surface using <em class="underscore">bump mapping</em> (<em class="underscore">normal mapping</em>) </td></tr>
|
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">bentNormal</strong> </td><td style="text-align:left"> A normal pointing in the average unoccluded direction. Can be used to improve indirect lighting quality </td></tr>
|
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">clearCoatNormal</strong> </td><td style="text-align:left"> A detail normal used to perturb the clear coat layer using <em class="underscore">bump mapping</em> (<em class="underscore">normal mapping</em>) </td></tr>
|
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">emissive</strong> </td><td style="text-align:left"> Additional diffuse albedo to simulate emissive surfaces (such as neons, etc.) This property is mostly useful in an HDR pipeline with a bloom pass </td></tr>
|
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">postLightingColor</strong> </td><td style="text-align:left"> Additional color that can be blended with the result of the lighting computations. See <code>postLightingBlending</code> </td></tr>
|
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">ior</strong> </td><td style="text-align:left"> Index of refraction, either for refractive objects or as an alternative to reflectance </td></tr>
|
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">transmission</strong> </td><td style="text-align:left"> Defines how much of the diffuse light of a dielectric is transmitted through the object, in other words this defines how transparent an object is </td></tr>
|
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">absorption</strong> </td><td style="text-align:left"> Absorption factor for refractive objects </td></tr>
|
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">microThickness</strong> </td><td style="text-align:left"> Thickness of the thin layer of refractive objects </td></tr>
|
|
||||||
<tr><td style="text-align:right"> <strong class="asterisk">thickness</strong> </td><td style="text-align:left"> Thickness of the solid volume of refractive objects </td></tr>
|
<tr><td style="text-align:right"> <strong class="asterisk">thickness</strong> </td><td style="text-align:left"> Thickness of the solid volume of refractive objects </td></tr>
|
||||||
|
<tr><td style="text-align:right"> <strong class="asterisk">sheenColor</strong> </td><td style="text-align:left"> Strength of the sheen layer </td></tr>
|
||||||
|
<tr><td style="text-align:right"> <strong class="asterisk">sheenRoughness</strong> </td><td style="text-align:left"> Perceived smoothness or roughness of the sheen layer </td></tr>
|
||||||
|
<tr><td style="text-align:right"> <strong class="asterisk">emissive</strong> </td><td style="text-align:left"> Additional diffuse albedo to simulate emissive surfaces (such as neons, etc.) This property is mostly useful in an HDR pipeline with a bloom pass </td></tr>
|
||||||
|
<tr><td style="text-align:right"> <strong class="asterisk">normal</strong> </td><td style="text-align:left"> A detail normal used to perturb the surface using <em class="underscore">bump mapping</em> (<em class="underscore">normal mapping</em>) </td></tr>
|
||||||
|
<tr><td style="text-align:right"> <strong class="asterisk">postLightingColor</strong> </td><td style="text-align:left"> Additional color that can be blended with the result of the lighting computations. See <code>postLightingBlending</code> </td></tr>
|
||||||
|
<tr><td style="text-align:right"> <strong class="asterisk">absorption</strong> </td><td style="text-align:left"> Absorption factor for refractive objects </td></tr>
|
||||||
|
<tr><td style="text-align:right"> <strong class="asterisk">transmission</strong> </td><td style="text-align:left"> Defines how much of the diffuse light of a dielectric is transmitted through the object, in other words this defines how transparent an object is </td></tr>
|
||||||
|
<tr><td style="text-align:right"> <strong class="asterisk">ior</strong> </td><td style="text-align:left"> Index of refraction, either for refractive objects or as an alternative to reflectance </td></tr>
|
||||||
|
<tr><td style="text-align:right"> <strong class="asterisk">microThickness</strong> </td><td style="text-align:left"> Thickness of the thin layer of refractive objects </td></tr>
|
||||||
|
<tr><td style="text-align:right"> <strong class="asterisk">bentNormal</strong> </td><td style="text-align:left"> A normal pointing in the average unoccluded direction. Can be used to improve indirect lighting quality </td></tr>
|
||||||
|
<tr><td style="text-align:right"> <strong class="asterisk">shadowStrength</strong> </td><td style="text-align:left"> Strength factor between 0 and 1 for all shadows received by this material </td></tr>
|
||||||
</tbody></table><center><div class="tablecaption"><a class="target" name="table_standardproperties"> </a><b style="font-style:normal;">Table 1:</b> Properties of the standard model</div></center></div>
|
</tbody></table><center><div class="tablecaption"><a class="target" name="table_standardproperties"> </a><b style="font-style:normal;">Table 1:</b> Properties of the standard model</div></center></div>
|
||||||
|
|
||||||
<p></p><p>
|
<p></p><p>
|
||||||
@@ -1486,10 +1487,13 @@ non-shader data.
|
|||||||
</p><dl><dt>Type</dt><dd><p> array of parameter objects
|
</p><dl><dt>Type</dt><dd><p> array of parameter objects
|
||||||
|
|
||||||
</p></dd><dt>Value</dt><dd><p> Each entry is an object with the properties <code>name</code> and <code>type</code>, both of <code>string</code> type. The
|
</p></dd><dt>Value</dt><dd><p> Each entry is an object with the properties <code>name</code> and <code>type</code>, both of <code>string</code> type. The
|
||||||
name must be a valid GLSL identifier. Entries also have an optional <code>precision</code>, which can be
|
name must be a valid GLSL identifier. Entries have an optional <code>precision</code>, which can be
|
||||||
one of <code>default</code> (best precision for the platform, typically <code>high</code> on desktop, <code>medium</code> on
|
one of <code>default</code> (best precision for the platform, typically <code>high</code> on desktop, <code>medium</code> on
|
||||||
mobile), <code>low</code>, <code>medium</code>, <code>high</code>. The type must be one of the types described in
|
mobile), <code>low</code>, <code>medium</code>, <code>high</code>. The type must be one of the types described in
|
||||||
<a href="#table_materialparamstypes">table 14</a>.
|
<a href="#table_materialparamstypes">table 14</a>. For Android external textures, entries also have an optional
|
||||||
|
transformName parameter to specify the name of the material parameter that will be
|
||||||
|
used to expose the transform matrix associated with the external sampler. In iOS and Vulkan,
|
||||||
|
this will always be identity.
|
||||||
|
|
||||||
</p></dd></dl><div class="table">
|
</p></dd></dl><div class="table">
|
||||||
<table class="table"><tbody><tr><th style="text-align:left"> Type </th><th style="text-align:left"> Description </th></tr>
|
<table class="table"><tbody><tr><th style="text-align:left"> Type </th><th style="text-align:left"> Description </th></tr>
|
||||||
@@ -1752,7 +1756,13 @@ non-shader data.
|
|||||||
when selecting any shading model that is not <code>unlit</code>. See the shader sections of this document
|
when selecting any shading model that is not <code>unlit</code>. See the shader sections of this document
|
||||||
for more information on how to access these attributes from the shaders.
|
for more information on how to access these attributes from the shaders.
|
||||||
|
|
||||||
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
</p></dd></dl><div class="admonition note"><div class="admonition-title"> Interaction with custom variables</div>
|
||||||
|
|
||||||
|
<p></p><p>
|
||||||
|
|
||||||
|
When the <code>color</code> attribute is specified, only four custom variables are available instead of five.</p></div>
|
||||||
|
|
||||||
|
<p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||||
<span class="line"> parameters : [</span>
|
<span class="line"> parameters : [</span>
|
||||||
<span class="line"> {</span>
|
<span class="line"> {</span>
|
||||||
<span class="line"> type : sampler2d,</span>
|
<span class="line"> type : sampler2d,</span>
|
||||||
@@ -1779,7 +1789,7 @@ non-shader data.
|
|||||||
|
|
||||||
</p><dl><dt>Type</dt><dd><p> array of <code>string</code>
|
</p><dl><dt>Type</dt><dd><p> array of <code>string</code>
|
||||||
|
|
||||||
</p></dd><dt>Value</dt><dd><p> Up to 4 strings, each must be a valid GLSL identifier.
|
</p></dd><dt>Value</dt><dd><p> Up to 5 strings, each must be a valid GLSL identifier.
|
||||||
|
|
||||||
</p></dd><dt>Description</dt><dd><p> Defines custom interpolants (or variables) that are output by the material's vertex shader.
|
</p></dd><dt>Description</dt><dd><p> Defines custom interpolants (or variables) that are output by the material's vertex shader.
|
||||||
Each entry of the array defines the name of an interpolant. The full name in the fragment
|
Each entry of the array defines the name of an interpolant. The full name in the fragment
|
||||||
@@ -1794,7 +1804,14 @@ non-shader data.
|
|||||||
particular if <code>default</code> is specified the default precision is used is the fragment shader
|
particular if <code>default</code> is specified the default precision is used is the fragment shader
|
||||||
(<code>mediump</code>) and in the vertex shader (<code>highp</code>).
|
(<code>mediump</code>) and in the vertex shader (<code>highp</code>).
|
||||||
|
|
||||||
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
</p></dd></dl><div class="admonition warning"><div class="admonition-title"> Interaction with required attributes</div>
|
||||||
|
|
||||||
|
<p></p><p>
|
||||||
|
|
||||||
|
If the <code>color</code> attribute is specified in the <code>required</code> list, then only four variables can be used
|
||||||
|
instead of five.</p></div>
|
||||||
|
|
||||||
|
<p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||||
<span class="line"> name : Skybox,</span>
|
<span class="line"> name : Skybox,</span>
|
||||||
<span class="line"> parameters : [</span>
|
<span class="line"> parameters : [</span>
|
||||||
<span class="line"> {</span>
|
<span class="line"> {</span>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
+16
-16
@@ -49,7 +49,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="left"><a href="#EntityManager">EntityManager</a></td>
|
<td align="left"><a href="#EntityManager">EntityManager</a></td>
|
||||||
<td align="left">Singleton used for constructing entities in Filament's ECS.</td>
|
<td align="left">Singleton used for constructing entities in Filament's ECS.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="left"><a href="#Frustum">Frustum</a></td>
|
<td align="left"><a href="#Frustum">Frustum</a></td>
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="left"><a href="#Renderer">Renderer</a></td>
|
<td align="left"><a href="#Renderer">Renderer</a></td>
|
||||||
<td align="left">Represents the platform's native window.</td>
|
<td align="left">Represents the platform's native window.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="left"><a href="#Scene">Scene</a></td>
|
<td align="left"><a href="#Scene">Scene</a></td>
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="left"><a href="#SwapChain">SwapChain</a></td>
|
<td align="left"><a href="#SwapChain">SwapChain</a></td>
|
||||||
<td align="left">Represents the platform's native rendering surface.</td>
|
<td align="left">Represents the platform's native rendering surface.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="left"><a href="#Texture">Texture</a></td>
|
<td align="left"><a href="#Texture">Texture</a></td>
|
||||||
@@ -604,11 +604,11 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<p>To create an entity with no components, use <a href="#EntityManager">EntityManager</a>.
|
<p>To create an entity with no components, use <a href="#EntityManager">EntityManager</a>.
|
||||||
TODO: It would be better to expose these as JS numbers rather than as JS objects.
|
TODO: It would be better to expose these as JS numbers rather than as JS objects.
|
||||||
This would also be more consistent with Filament's Java bindings.</p>
|
This would also be more consistent with Filament's Java bindings.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class='classdoc'>
|
<div class='classdoc'>
|
||||||
<h2>class <a id='EntityManager' href='#EntityManager'>EntityManager</a></h2>
|
<h2>class <a id='EntityManager' href='#EntityManager'>EntityManager</a></h2>
|
||||||
<p>Singleton used for constructing entities in Filament's ECS.</p>
|
<p>Singleton used for constructing entities in Filament's ECS.</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><strong>entityManager.create()</strong>
|
<li><strong>entityManager.create()</strong>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -742,7 +742,7 @@ properties.</p>
|
|||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Be sure to call the instance's <code>delete</code> method when you're done with it.</p>
|
<p>Be sure to call the instance's <code>delete</code> method when you're done with it.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class='classdoc'>
|
<div class='classdoc'>
|
||||||
<h2>class <a id='PixelBufferDescriptor' href='#PixelBufferDescriptor'>PixelBufferDescriptor</a></h2>
|
<h2>class <a id='PixelBufferDescriptor' href='#PixelBufferDescriptor'>PixelBufferDescriptor</a></h2>
|
||||||
@@ -780,11 +780,11 @@ properties.</p>
|
|||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Be sure to call the instance's <code>delete</code> method when you're done with it.</p>
|
<p>Be sure to call the instance's <code>delete</code> method when you're done with it.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class='classdoc'>
|
<div class='classdoc'>
|
||||||
<h2>class <a id='Renderer' href='#Renderer'>Renderer</a></h2>
|
<h2>class <a id='Renderer' href='#Renderer'>Renderer</a></h2>
|
||||||
<p>Represents the platform's native window.</p>
|
<p>Represents the platform's native window.</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><strong>renderer.render(swapChain, view)</strong>
|
<li><strong>renderer.render(swapChain, view)</strong>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -803,7 +803,7 @@ properties.</p>
|
|||||||
</div>
|
</div>
|
||||||
<div class='classdoc'>
|
<div class='classdoc'>
|
||||||
<h2>class <a id='SwapChain' href='#SwapChain'>SwapChain</a></h2>
|
<h2>class <a id='SwapChain' href='#SwapChain'>SwapChain</a></h2>
|
||||||
<p>Represents the platform's native rendering surface.</p>
|
<p>Represents the platform's native rendering surface.</p>
|
||||||
<p>See also the <a href="#Engine">Engine</a> methods <code>createSwapChain</code> and <code>destroySwapChain</code>.</p>
|
<p>See also the <a href="#Engine">Engine</a> methods <code>createSwapChain</code> and <code>destroySwapChain</code>.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class='classdoc'>
|
<div class='classdoc'>
|
||||||
@@ -847,7 +847,7 @@ properties.</p>
|
|||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Be sure to call the instance's <code>delete</code> method when you're done with it.</p>
|
<p>Be sure to call the instance's <code>delete</code> method when you're done with it.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class='classdoc'>
|
<div class='classdoc'>
|
||||||
<h2>class <a id='VertexBuffer' href='#VertexBuffer'>VertexBuffer</a></h2>
|
<h2>class <a id='VertexBuffer' href='#VertexBuffer'>VertexBuffer</a></h2>
|
||||||
@@ -944,7 +944,7 @@ See also the <a href="#Engine">Engine</a> methods <code>createView</code> and <c
|
|||||||
<ul>
|
<ul>
|
||||||
<li><strong>assets</strong>
|
<li><strong>assets</strong>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Array of strings containing URL's of required assets.</li>
|
<li>Array of strings containing URL's of required assets.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><strong>onDone</strong>
|
<li><strong>onDone</strong>
|
||||||
@@ -954,7 +954,7 @@ See also the <a href="#Engine">Engine</a> methods <code>createView</code> and <c
|
|||||||
</li>
|
</li>
|
||||||
<li><strong>onFetched</strong>
|
<li><strong>onFetched</strong>
|
||||||
<ul>
|
<ul>
|
||||||
<li>optional callback that's invoked after each asset is downloaded.</li>
|
<li>optional callback that's invoked after each asset is downloaded.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -1001,7 +1001,7 @@ useful for compressed textures. For example, some platforms accept ETC and other
|
|||||||
<ul>
|
<ul>
|
||||||
<li><strong>assets</strong>
|
<li><strong>assets</strong>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Array of strings containing URL's of required assets.</li>
|
<li>Array of strings containing URL's of required assets.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><strong>onready</strong>
|
<li><strong>onready</strong>
|
||||||
@@ -1010,12 +1010,12 @@ useful for compressed textures. For example, some platforms accept ETC and other
|
|||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>All JavaScript clients must call the init function, passing in a list of asset URL's and a
|
<p>All JavaScript clients must call the init function, passing in a list of asset URL's and a
|
||||||
callback. This callback gets invoked only after all assets have been downloaded and the Filament
|
callback. This callback gets invoked only after all assets have been downloaded and the Filament
|
||||||
WebAssembly module has been loaded. Clients should only pass asset URL's that absolutely must
|
WebAssembly module has been loaded. Clients should only pass asset URL's that absolutely must
|
||||||
be ready at initialization time.
|
be ready at initialization time.
|
||||||
When the callback is called, each downloaded asset is available in the <code>Filament.assets</code> global
|
When the callback is called, each downloaded asset is available in the <code>Filament.assets</code> global
|
||||||
object, which contains a mapping from URL's to Uint8Array objects.</p>
|
object, which contains a mapping from URL's to Uint8Array objects.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class='funcdoc'>
|
<div class='funcdoc'>
|
||||||
<h2>function <a id='loadMathExtensions' href='#loadMathExtensions'>loadMathExtensions</a>()</h2>
|
<h2>function <a id='loadMathExtensions' href='#loadMathExtensions'>loadMathExtensions</a>()</h2>
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
+157
-157
@@ -10,7 +10,7 @@
|
|||||||
textures.</p>
|
textures.</p>
|
||||||
<p>For starters, create a text file called <code>redball.html</code> and copy over the HTML that we used in the
|
<p>For starters, create a text file called <code>redball.html</code> and copy over the HTML that we used in the
|
||||||
<a href="tutorial_triangle.html">previous tutorial</a>. Change the last script tag from <code>triangle.js</code> to <code>redball.js</code>.</p>
|
<a href="tutorial_triangle.html">previous tutorial</a>. 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
|
<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
|
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
|
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
|
that matches the <code>unpkg.com/filament@x.x.x</code> url in the script tag of <code>redball.html</code> (you may check
|
||||||
@@ -19,7 +19,7 @@ out the last available release of <a href="https://www.npmjs.com/package/filamen
|
|||||||
<p>The <code>matc</code> tool consumes a text file containing a high-level description of a PBR material, and
|
<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
|
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>
|
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
|
<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>
|
<code>plastic.mat</code>.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>material {
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>material {
|
||||||
name : Lit,
|
name : Lit,
|
||||||
@@ -44,16 +44,16 @@ fragment {
|
|||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>Next, invoke <code>matc</code> as follows.</p>
|
<p>Next, invoke <code>matc</code> as follows.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>matc -a opengl -p mobile -o plastic.filamat plastic.mat
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>matc<span style="color: #BBB"> </span>-a<span style="color: #BBB"> </span>opengl<span style="color: #BBB"> </span>-p<span style="color: #BBB"> </span>mobile<span style="color: #BBB"> </span>-o<span style="color: #BBB"> </span>plastic.filamat<span style="color: #BBB"> </span>plastic.mat
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>You should now have a material archive in your working directory, which we'll use later in the
|
<p>You should now have a material archive in your working directory, which we'll use later in the
|
||||||
tutorial.</p>
|
tutorial.</p>
|
||||||
<h2>Bake environment map</h2>
|
<h2>Bake environment map</h2>
|
||||||
<p>Next we'll use Filament's <code>cmgen</code> tool to consume a HDR environment map in latlong format, and
|
<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>
|
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>
|
<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>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>cmgen -x pillars_2k --format<span style="color: #666666">=</span>ktx --size<span style="color: #666666">=256</span> --extract-blur<span style="color: #666666">=0</span>.1 pillars_2k.hdr
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>cmgen<span style="color: #BBB"> </span>-x<span style="color: #BBB"> </span>pillars_2k<span style="color: #BBB"> </span>--format<span style="color: #666">=</span>ktx<span style="color: #BBB"> </span>--size<span style="color: #666">=256</span><span style="color: #BBB"> </span>--extract-blur<span style="color: #666">=0</span>.1<span style="color: #BBB"> </span>pillars_2k.hdr
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>You should now have a <code>pillars_2k</code> folder containing a couple KTX files for the IBL and skybox, as
|
<p>You should now have a <code>pillars_2k</code> folder containing a couple KTX files for the IBL and skybox, as
|
||||||
@@ -61,84 +61,84 @@ well as a text file with spherical harmonics coefficients. You can discard the t
|
|||||||
IBL KTX contains these coefficients in its metadata.</p>
|
IBL KTX contains these coefficients in its metadata.</p>
|
||||||
<h2>Create JavaScript</h2>
|
<h2>Create JavaScript</h2>
|
||||||
<p>Next, create <code>redball.js</code> with the following content.</p>
|
<p>Next, create <code>redball.js</code> with the following content.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>environ<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">'pillars_2k'</span>;<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>environ<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">'pillars_2k'</span>;
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ibl_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_ibl.ktx`</span>;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ibl_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_ibl.ktx`</span>;
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sky_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox.ktx`</span>;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>sky_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox.ktx`</span>;
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>filamat_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">'plastic.filamat'</span><span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>filamat_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">'plastic.filamat'</span>
|
||||||
|
|
||||||
Filament.init([<span style="color: #bbbbbb"> </span>filamat_url,<span style="color: #bbbbbb"> </span>ibl_url,<span style="color: #bbbbbb"> </span>sky_url<span style="color: #bbbbbb"> </span>],<span style="color: #bbbbbb"> </span>()<span style="color: #bbbbbb"> </span>=><span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
Filament.init([<span style="color: #BBB"> </span>filamat_url,<span style="color: #BBB"> </span>ibl_url,<span style="color: #BBB"> </span>sky_url<span style="color: #BBB"> </span>],<span style="color: #BBB"> </span>()<span style="color: #BBB"> </span>=><span style="color: #BBB"> </span>{
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// Create some global aliases to enums for convenience.</span><span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// Create some global aliases to enums for convenience.</span>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.VertexAttribute<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.VertexAttribute;<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.VertexAttribute<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.VertexAttribute;
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.AttributeType<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.VertexBuffer$AttributeType;<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.AttributeType<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.VertexBuffer$AttributeType;
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.PrimitiveType<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.RenderableManager$PrimitiveType;<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.PrimitiveType<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.RenderableManager$PrimitiveType;
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.IndexType<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.IndexBuffer$IndexType;<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.IndexType<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.IndexBuffer$IndexType;
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.Fov<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Camera$Fov;<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.Fov<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Camera$Fov;
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.LightType<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.LightManager$Type;<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.LightType<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.LightManager$Type;
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// Obtain the canvas DOM object and pass it to the App.</span><span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// Obtain the canvas DOM object and pass it to the App.</span>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>canvas<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">'canvas'</span>)[<span style="color: #666666">0</span>];<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>canvas<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">'canvas'</span>)[<span style="color: #666">0</span>];
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.app<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>App(canvas);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.app<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>App(canvas);
|
||||||
}<span style="color: #bbbbbb"> </span>);<span style="color: #bbbbbb"></span>
|
}<span style="color: #BBB"> </span>);
|
||||||
|
|
||||||
<span style="color: #008000; font-weight: bold">class</span><span style="color: #bbbbbb"> </span>App<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">class</span><span style="color: #BBB"> </span>App<span style="color: #BBB"> </span>{
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">constructor</span>(canvas)<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">constructor</span>(canvas)<span style="color: #BBB"> </span>{
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>canvas;<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>canvas;
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>engine<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Engine.create(canvas);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>engine<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Engine.create(canvas);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>scene<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createScene();<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>scene<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createScene();
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create material</span><span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create material</span>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create sphere</span><span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create sphere</span>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create lights</span><span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create lights</span>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create IBL</span><span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create IBL</span>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create skybox</span><span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create skybox</span>
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.swapChain<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createSwapChain();<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.swapChain<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createSwapChain();
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createRenderer();<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createRenderer();
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.camera<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createCamera(Filament.EntityManager.get().create());<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.camera<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createCamera(Filament.EntityManager.get().create());
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createView();<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createView();
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setScene(scene);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setScene(scene);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize();<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize();
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.render<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.render<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">'resize'</span>,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">'resize'</span>,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||||
<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>}
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span>render()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>render()<span style="color: #BBB"> </span>{
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>eye<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">4</span>],<span style="color: #bbbbbb"> </span>center<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>],<span style="color: #bbbbbb"> </span>up<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>];<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>eye<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">4</span>],<span style="color: #BBB"> </span>center<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>],<span style="color: #BBB"> </span>up<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>];
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>radians<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">Date</span>.now()<span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">10000</span>;<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>radians<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">Date</span>.now()<span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">10000</span>;
|
||||||
<span style="color: #bbbbbb"> </span>vec3.rotateY(eye,<span style="color: #bbbbbb"> </span>eye,<span style="color: #bbbbbb"> </span>center,<span style="color: #bbbbbb"> </span>radians);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>vec3.rotateY(eye,<span style="color: #BBB"> </span>eye,<span style="color: #BBB"> </span>center,<span style="color: #BBB"> </span>radians);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.lookAt(eye,<span style="color: #bbbbbb"> </span>center,<span style="color: #bbbbbb"> </span>up);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.lookAt(eye,<span style="color: #BBB"> </span>center,<span style="color: #BBB"> </span>up);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||||
<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>}
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span>resize()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>resize()<span style="color: #BBB"> </span>{
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>dpr<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.devicePixelRatio;<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>dpr<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.devicePixelRatio;
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>width<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.width<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.innerWidth<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span>dpr;<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>width<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.width<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.innerWidth<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span>dpr;
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>height<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.height<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.innerHeight<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span>dpr;<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>height<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.height<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.innerHeight<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span>dpr;
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>width,<span style="color: #bbbbbb"> </span>height]);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>width,<span style="color: #BBB"> </span>height]);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.setProjectionFov(<span style="color: #666666">45</span>,<span style="color: #bbbbbb"> </span>width<span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span>height,<span style="color: #bbbbbb"> </span><span style="color: #666666">1.0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">10.0</span>,<span style="color: #bbbbbb"> </span>Fov.VERTICAL);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.setProjectionFov(<span style="color: #666">45</span>,<span style="color: #BBB"> </span>width<span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span>height,<span style="color: #BBB"> </span><span style="color: #666">1.0</span>,<span style="color: #BBB"> </span><span style="color: #666">10.0</span>,<span style="color: #BBB"> </span>Fov.VERTICAL);
|
||||||
<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>}
|
||||||
}<span style="color: #bbbbbb"></span>
|
}
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>The above boilerplate should be familiar to you from the previous tutorial, although it loads in a
|
<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>
|
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.
|
<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>
|
Replace the <strong>create material</strong> comment with the following snippet.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>material<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createMaterial(filamat_url);<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>material<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createMaterial(filamat_url);
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>matinstance<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>material.createInstance();<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>matinstance<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>material.createInstance();
|
||||||
|
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>red<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0.8</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.0</span>];<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>red<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0.8</span>,<span style="color: #BBB"> </span><span style="color: #666">0.0</span>,<span style="color: #BBB"> </span><span style="color: #666">0.0</span>];
|
||||||
matinstance.setColor3Parameter(<span style="color: #BA2121">'baseColor'</span>,<span style="color: #bbbbbb"> </span>Filament.RgbType.sRGB,<span style="color: #bbbbbb"> </span>red);<span style="color: #bbbbbb"></span>
|
matinstance.setColor3Parameter(<span style="color: #BA2121">'baseColor'</span>,<span style="color: #BBB"> </span>Filament.RgbType.sRGB,<span style="color: #BBB"> </span>red);
|
||||||
matinstance.setFloatParameter(<span style="color: #BA2121">'roughness'</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.5</span>);<span style="color: #bbbbbb"></span>
|
matinstance.setFloatParameter(<span style="color: #BA2121">'roughness'</span>,<span style="color: #BBB"> </span><span style="color: #666">0.5</span>);
|
||||||
matinstance.setFloatParameter(<span style="color: #BA2121">'clearCoat'</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1.0</span>);<span style="color: #bbbbbb"></span>
|
matinstance.setFloatParameter(<span style="color: #BA2121">'clearCoat'</span>,<span style="color: #BBB"> </span><span style="color: #666">1.0</span>);
|
||||||
matinstance.setFloatParameter(<span style="color: #BA2121">'clearCoatRoughness'</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.3</span>);<span style="color: #bbbbbb"></span>
|
matinstance.setFloatParameter(<span style="color: #BA2121">'clearCoatRoughness'</span>,<span style="color: #BBB"> </span><span style="color: #666">0.3</span>);
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>The next step is to create a renderable for the sphere. To help with this, we'll use the <code>IcoSphere</code>
|
<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
|
utility class, whose constructor takes a LOD. Its job is to subdivide an icosadedron, producing
|
||||||
three arrays:</p>
|
three arrays:</p>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -147,137 +147,137 @@ three arrays:</p>
|
|||||||
as quaternions.</li>
|
as quaternions.</li>
|
||||||
<li><code>icosphere.triangles</code> Uint16Array with triangle indices.</li>
|
<li><code>icosphere.triangles</code> Uint16Array with triangle indices.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Let's go ahead use these arrays to build the vertex buffer and index buffer. Replace <strong>create
|
<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>
|
sphere</strong> with the following snippet.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>renderable<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.EntityManager.get().create();<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>renderable<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.EntityManager.get().create();
|
||||||
scene.addEntity(renderable);<span style="color: #bbbbbb"></span>
|
scene.addEntity(renderable);
|
||||||
|
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>icosphere<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>Filament.IcoSphere(<span style="color: #666666">5</span>);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>icosphere<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>Filament.IcoSphere(<span style="color: #666">5</span>);
|
||||||
|
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>vb<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.VertexBuffer.Builder()<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>vb<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.VertexBuffer.Builder()
|
||||||
<span style="color: #bbbbbb"> </span>.vertexCount(icosphere.vertices.length<span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">3</span>)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.vertexCount(icosphere.vertices.length<span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">3</span>)
|
||||||
<span style="color: #bbbbbb"> </span>.bufferCount(<span style="color: #666666">2</span>)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.bufferCount(<span style="color: #666">2</span>)
|
||||||
<span style="color: #bbbbbb"> </span>.attribute(VertexAttribute.POSITION,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>AttributeType.FLOAT3,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.attribute(VertexAttribute.POSITION,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>AttributeType.FLOAT3,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>)
|
||||||
<span style="color: #bbbbbb"> </span>.attribute(VertexAttribute.TANGENTS,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span>AttributeType.SHORT4,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.attribute(VertexAttribute.TANGENTS,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span>AttributeType.SHORT4,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>)
|
||||||
<span style="color: #bbbbbb"> </span>.normalized(VertexAttribute.TANGENTS)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.normalized(VertexAttribute.TANGENTS)
|
||||||
<span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.build(engine);
|
||||||
|
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ib<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.IndexBuffer.Builder()<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ib<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.IndexBuffer.Builder()
|
||||||
<span style="color: #bbbbbb"> </span>.indexCount(icosphere.triangles.length)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.indexCount(icosphere.triangles.length)
|
||||||
<span style="color: #bbbbbb"> </span>.bufferType(IndexType.USHORT)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.bufferType(IndexType.USHORT)
|
||||||
<span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.build(engine);
|
||||||
|
|
||||||
vb.setBufferAt(engine,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>icosphere.vertices);<span style="color: #bbbbbb"></span>
|
vb.setBufferAt(engine,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>icosphere.vertices);
|
||||||
vb.setBufferAt(engine,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span>icosphere.tangents);<span style="color: #bbbbbb"></span>
|
vb.setBufferAt(engine,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span>icosphere.tangents);
|
||||||
ib.setBuffer(engine,<span style="color: #bbbbbb"> </span>icosphere.triangles);<span style="color: #bbbbbb"></span>
|
ib.setBuffer(engine,<span style="color: #BBB"> </span>icosphere.triangles);
|
||||||
|
|
||||||
Filament.RenderableManager.Builder(<span style="color: #666666">1</span>)<span style="color: #bbbbbb"></span>
|
Filament.RenderableManager.Builder(<span style="color: #666">1</span>)
|
||||||
<span style="color: #bbbbbb"> </span>.boundingBox({<span style="color: #bbbbbb"> </span>center<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">-1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">-1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">-1</span>],<span style="color: #bbbbbb"> </span>halfExtent<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>]<span style="color: #bbbbbb"> </span>})<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.boundingBox({<span style="color: #BBB"> </span>center<span style="color: #666">:</span><span style="color: #BBB"> </span>[<span style="color: #666">-1</span>,<span style="color: #BBB"> </span><span style="color: #666">-1</span>,<span style="color: #BBB"> </span><span style="color: #666">-1</span>],<span style="color: #BBB"> </span>halfExtent<span style="color: #666">:</span><span style="color: #BBB"> </span>[<span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>]<span style="color: #BBB"> </span>})
|
||||||
<span style="color: #bbbbbb"> </span>.material(<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>matinstance)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.material(<span style="color: #666">0</span>,<span style="color: #BBB"> </span>matinstance)
|
||||||
<span style="color: #bbbbbb"> </span>.geometry(<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>PrimitiveType.TRIANGLES,<span style="color: #bbbbbb"> </span>vb,<span style="color: #bbbbbb"> </span>ib)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.geometry(<span style="color: #666">0</span>,<span style="color: #BBB"> </span>PrimitiveType.TRIANGLES,<span style="color: #BBB"> </span>vb,<span style="color: #BBB"> </span>ib)
|
||||||
<span style="color: #bbbbbb"> </span>.build(engine,<span style="color: #bbbbbb"> </span>renderable);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.build(engine,<span style="color: #BBB"> </span>renderable);
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>At this point, the app is rendering a sphere, but it is black so it doesn't show up. To prove that
|
<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
|
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>
|
did in the first tutorial.</p>
|
||||||
<h2>Add lighting</h2>
|
<h2>Add lighting</h2>
|
||||||
<p>In this section we will create some directional light sources, as well as an image-based light (IBL)
|
<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
|
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>
|
lights</strong> comment with the following snippet.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sunlight<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.EntityManager.get().create();<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>sunlight<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.EntityManager.get().create();
|
||||||
scene.addEntity(sunlight);<span style="color: #bbbbbb"></span>
|
scene.addEntity(sunlight);
|
||||||
Filament.LightManager.Builder(LightType.SUN)<span style="color: #bbbbbb"></span>
|
Filament.LightManager.Builder(LightType.SUN)
|
||||||
<span style="color: #bbbbbb"> </span>.color([<span style="color: #666666">0.98</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.92</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.89</span>])<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.color([<span style="color: #666">0.98</span>,<span style="color: #BBB"> </span><span style="color: #666">0.92</span>,<span style="color: #BBB"> </span><span style="color: #666">0.89</span>])
|
||||||
<span style="color: #bbbbbb"> </span>.intensity(<span style="color: #666666">110000.0</span>)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.intensity(<span style="color: #666">110000.0</span>)
|
||||||
<span style="color: #bbbbbb"> </span>.direction([<span style="color: #666666">0.6</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">-1.0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">-0.8</span>])<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.direction([<span style="color: #666">0.6</span>,<span style="color: #BBB"> </span><span style="color: #666">-1.0</span>,<span style="color: #BBB"> </span><span style="color: #666">-0.8</span>])
|
||||||
<span style="color: #bbbbbb"> </span>.sunAngularRadius(<span style="color: #666666">1.9</span>)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.sunAngularRadius(<span style="color: #666">1.9</span>)
|
||||||
<span style="color: #bbbbbb"> </span>.sunHaloSize(<span style="color: #666666">10.0</span>)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.sunHaloSize(<span style="color: #666">10.0</span>)
|
||||||
<span style="color: #bbbbbb"> </span>.sunHaloFalloff(<span style="color: #666666">80.0</span>)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.sunHaloFalloff(<span style="color: #666">80.0</span>)
|
||||||
<span style="color: #bbbbbb"> </span>.build(engine,<span style="color: #bbbbbb"> </span>sunlight);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.build(engine,<span style="color: #BBB"> </span>sunlight);
|
||||||
|
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>backlight<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.EntityManager.get().create();<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>backlight<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.EntityManager.get().create();
|
||||||
scene.addEntity(backlight);<span style="color: #bbbbbb"></span>
|
scene.addEntity(backlight);
|
||||||
Filament.LightManager.Builder(LightType.DIRECTIONAL)<span style="color: #bbbbbb"></span>
|
Filament.LightManager.Builder(LightType.DIRECTIONAL)
|
||||||
<span style="color: #bbbbbb"> </span>.direction([<span style="color: #666666">-1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>])<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.direction([<span style="color: #666">-1</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>])
|
||||||
<span style="color: #bbbbbb"> </span>.intensity(<span style="color: #666666">50000.0</span>)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.intensity(<span style="color: #666">50000.0</span>)
|
||||||
<span style="color: #bbbbbb"> </span>.build(engine,<span style="color: #bbbbbb"> </span>backlight);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.build(engine,<span style="color: #BBB"> </span>backlight);
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>The <code>SUN</code> light source is similar to the <code>DIRECTIONAL</code> light source, but has some extra
|
<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>
|
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
|
<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>
|
following (don't type this out, there's an easier way).</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>format<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.PixelDataFormat.RGB;<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>format<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.PixelDataFormat.RGB;
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>datatype<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.PixelDataType.UINT_10F_11F_11F_REV;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>datatype<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.PixelDataType.UINT_10F_11F_11F_REV;
|
||||||
|
|
||||||
<span style="color: #3D7B7B; font-style: italic">// Create a Texture object for the mipmapped cubemap.</span><span style="color: #bbbbbb"></span>
|
<span style="color: #3D7B7B; font-style: italic">// Create a Texture object for the mipmapped cubemap.</span>
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ibl_package<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Buffer(Filament.assets[ibl_url]);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ibl_package<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Buffer(Filament.assets[ibl_url]);
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>iblktx<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>Filament.Ktx1Bundle(ibl_package);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>iblktx<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>Filament.Ktx1Bundle(ibl_package);
|
||||||
|
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ibltex<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Texture.Builder()<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ibltex<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Texture.Builder()
|
||||||
<span style="color: #bbbbbb"> </span>.width(iblktx.info().pixelWidth)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.width(iblktx.info().pixelWidth)
|
||||||
<span style="color: #bbbbbb"> </span>.height(iblktx.info().pixelHeight)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.height(iblktx.info().pixelHeight)
|
||||||
<span style="color: #bbbbbb"> </span>.levels(iblktx.getNumMipLevels())<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.levels(iblktx.getNumMipLevels())
|
||||||
<span style="color: #bbbbbb"> </span>.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)
|
||||||
<span style="color: #bbbbbb"> </span>.format(Filament.Texture$InternalFormat.RGBA8)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.format(Filament.Texture$InternalFormat.RGBA8)
|
||||||
<span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.build(engine);
|
||||||
|
|
||||||
<span style="color: #008000; font-weight: bold">for</span><span style="color: #bbbbbb"> </span>(<span style="color: #008000; font-weight: bold">let</span><span style="color: #bbbbbb"> </span>level<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>;<span style="color: #bbbbbb"> </span>level<span style="color: #bbbbbb"> </span><span style="color: #666666"><</span><span style="color: #bbbbbb"> </span>iblktx.getNumMipLevels();<span style="color: #bbbbbb"> </span><span style="color: #666666">++</span>level)<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">for</span><span style="color: #BBB"> </span>(<span style="color: #008000; font-weight: bold">let</span><span style="color: #BBB"> </span>level<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #666">0</span>;<span style="color: #BBB"> </span>level<span style="color: #BBB"> </span><span style="color: #666"><</span><span style="color: #BBB"> </span>iblktx.getNumMipLevels();<span style="color: #BBB"> </span><span style="color: #666">++</span>level)<span style="color: #BBB"> </span>{
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>uint8array<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>iblktx.getCubeBlob(level).getBytes();<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>uint8array<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>iblktx.getCubeBlob(level).getBytes();
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>pixelbuffer<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.PixelBuffer(uint8array,<span style="color: #bbbbbb"> </span>format,<span style="color: #bbbbbb"> </span>datatype);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>pixelbuffer<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.PixelBuffer(uint8array,<span style="color: #BBB"> </span>format,<span style="color: #BBB"> </span>datatype);
|
||||||
<span style="color: #bbbbbb"> </span>ibltex.setImageCube(engine,<span style="color: #bbbbbb"> </span>level,<span style="color: #bbbbbb"> </span>pixelbuffer);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>ibltex.setImageCube(engine,<span style="color: #BBB"> </span>level,<span style="color: #BBB"> </span>pixelbuffer);
|
||||||
}<span style="color: #bbbbbb"></span>
|
}
|
||||||
|
|
||||||
<span style="color: #3D7B7B; font-style: italic">// Parse the spherical harmonics metadata.</span><span style="color: #bbbbbb"></span>
|
<span style="color: #3D7B7B; font-style: italic">// Parse the spherical harmonics metadata.</span>
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>shstring<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>iblktx.getMetadata(<span style="color: #BA2121">'sh'</span>);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>shstring<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>iblktx.getMetadata(<span style="color: #BA2121">'sh'</span>);
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>shfloats<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>shstring.split(<span style="color: #A45A77">/\s/</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">9</span><span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span><span style="color: #666666">3</span>).map(<span style="color: #008000">parseFloat</span>);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>shfloats<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>shstring.split(<span style="color: #A45A77">/\s/</span>,<span style="color: #BBB"> </span><span style="color: #666">9</span><span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span><span style="color: #666">3</span>).map(<span style="color: #008000">parseFloat</span>);
|
||||||
|
|
||||||
<span style="color: #3D7B7B; font-style: italic">// Build the IBL object and insert it into the scene.</span><span style="color: #bbbbbb"></span>
|
<span style="color: #3D7B7B; font-style: italic">// Build the IBL object and insert it into the scene.</span>
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>indirectLight<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.IndirectLight.Builder()<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>indirectLight<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.IndirectLight.Builder()
|
||||||
<span style="color: #bbbbbb"> </span>.reflections(ibltex)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.reflections(ibltex)
|
||||||
<span style="color: #bbbbbb"> </span>.irradianceSh(<span style="color: #666666">3</span>,<span style="color: #bbbbbb"> </span>shfloats)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.irradianceSh(<span style="color: #666">3</span>,<span style="color: #BBB"> </span>shfloats)
|
||||||
<span style="color: #bbbbbb"> </span>.intensity(<span style="color: #666666">50000.0</span>)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.intensity(<span style="color: #666">50000.0</span>)
|
||||||
<span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.build(engine);
|
||||||
|
|
||||||
scene.setIndirectLight(indirectLight);<span style="color: #bbbbbb"></span>
|
scene.setIndirectLight(indirectLight);
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>Filament provides a JavaScript utility to make this simpler,
|
<p>Filament provides a JavaScript utility to make this simpler,
|
||||||
simply replace the <strong>create IBL</strong> comment with the following snippet.</p>
|
simply replace the <strong>create IBL</strong> comment with the following snippet.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>indirectLight<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createIblFromKtx1(ibl_url);<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>indirectLight<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createIblFromKtx1(ibl_url);
|
||||||
indirectLight.setIntensity(<span style="color: #666666">50000</span>);<span style="color: #bbbbbb"></span>
|
indirectLight.setIntensity(<span style="color: #666">50000</span>);
|
||||||
scene.setIndirectLight(indirectLight);<span style="color: #bbbbbb"></span>
|
scene.setIndirectLight(indirectLight);
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<h2>Add background</h2>
|
<h2>Add background</h2>
|
||||||
<p>At this point you can run the demo and you should see a red plastic ball against a black background.
|
<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.
|
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>
|
Here's one way to create a texture for the skybox:</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sky_package<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Buffer(Filament.assets[sky_url]);<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>sky_package<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Buffer(Filament.assets[sky_url]);
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>skyktx<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>Filament.Ktx1Bundle(sky_package);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>skyktx<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>Filament.Ktx1Bundle(sky_package);
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>skytex<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Texture.Builder()<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>skytex<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Texture.Builder()
|
||||||
<span style="color: #bbbbbb"> </span>.width(skyktx.info().pixelWidth)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.width(skyktx.info().pixelWidth)
|
||||||
<span style="color: #bbbbbb"> </span>.height(skyktx.info().pixelHeight)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.height(skyktx.info().pixelHeight)
|
||||||
<span style="color: #bbbbbb"> </span>.levels(<span style="color: #666666">1</span>)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.levels(<span style="color: #666">1</span>)
|
||||||
<span style="color: #bbbbbb"> </span>.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)
|
||||||
<span style="color: #bbbbbb"> </span>.format(Filament.Texture$InternalFormat.RGBA8)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.format(Filament.Texture$InternalFormat.RGBA8)
|
||||||
<span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.build(engine);
|
||||||
|
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>uint8array<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>skyktx.getCubeBlob(<span style="color: #666666">0</span>).getBytes();<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>uint8array<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>skyktx.getCubeBlob(<span style="color: #666">0</span>).getBytes();
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>pixelbuffer<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.PixelBuffer(uint8array,<span style="color: #bbbbbb"> </span>format,<span style="color: #bbbbbb"> </span>datatype);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>pixelbuffer<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.PixelBuffer(uint8array,<span style="color: #BBB"> </span>format,<span style="color: #BBB"> </span>datatype);
|
||||||
skytex.setImageCube(engine,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>pixelbuffer);<span style="color: #bbbbbb"></span>
|
skytex.setImageCube(engine,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>pixelbuffer);
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>Filament provides a Javascript utility to make this easier.
|
<p>Filament provides a Javascript utility to make this easier.
|
||||||
Replace <strong>create skybox</strong> with the following.</p>
|
Replace <strong>create skybox</strong> with the following.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>skybox<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createSkyFromKtx1(sky_url);<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>skybox<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createSkyFromKtx1(sky_url);
|
||||||
scene.setSkybox(skybox);<span style="color: #bbbbbb"></span>
|
scene.setSkybox(skybox);
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>That's it, we now have a shiny red ball floating in an environment! The complete JavaScript file is
|
<p>That's it, we now have a shiny red ball floating in an environment! The complete JavaScript file is
|
||||||
available <a href="tutorial_redball.js">here</a>.</p>
|
available <a href="tutorial_redball.js">here</a>.</p>
|
||||||
<p>In the <a href="tutorial_suzanne.html">next tutorial</a>, we'll take a closer look at textures and interaction.</p>
|
<p>In the <a href="tutorial_suzanne.html">next tutorial</a>, we'll take a closer look at textures and interaction.</p>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+121
-121
@@ -8,58 +8,58 @@
|
|||||||
<div class="demo_frame"><iframe src="demo_suzanne.html"></iframe><a href="demo_suzanne.html">🔗</a></div>
|
<div class="demo_frame"><iframe src="demo_suzanne.html"></iframe><a href="demo_suzanne.html">🔗</a></div>
|
||||||
<p>This tutorial will describe how to create the <strong>suzanne</strong> demo, introducing you to compressed
|
<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>
|
textures, mipmap generation, asynchronous texture loading, and trackball rotation.</p>
|
||||||
<p>Much like the <a href="tutorial_redball.html">previous tutorial</a>, you'll need to use the command-line tools that can be found in
|
<p>Much like the <a href="tutorial_redball.html">previous tutorial</a>, 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>,
|
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>
|
we'll also be using <code>filamesh</code> and <code>mipgen</code>.</p>
|
||||||
<h2>Create filamesh file</h2>
|
<h2>Create filamesh file</h2>
|
||||||
<p>Filament does not have an asset loading system, but it does provide a binary mesh format
|
<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
|
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>
|
converting <a href="https://github.com/google/filament/blob/main/assets/models/monkey/monkey.obj">this OBJ file</a>:</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>filamesh --compress monkey.obj suzanne.filamesh
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>filamesh<span style="color: #BBB"> </span>--compress<span style="color: #BBB"> </span>monkey.obj<span style="color: #BBB"> </span>suzanne.filamesh
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<h2>Create mipmapped textures</h2>
|
<h2>Create mipmapped textures</h2>
|
||||||
<p>Next, let's create mipmapped KTX files using filament's <code>mipgen</code> tool. We'll create compressed and
|
<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
|
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>
|
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>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic"># Create mipmaps for base color</span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic"># Create mipmaps for base color</span>
|
||||||
mipgen albedo.png albedo.ktx2
|
mipgen<span style="color: #BBB"> </span>albedo.png<span style="color: #BBB"> </span>albedo.ktx2
|
||||||
mipgen --compression<span style="color: #666666">=</span>uastc albedo.png albedo.ktx2
|
mipgen<span style="color: #BBB"> </span>--compression<span style="color: #666">=</span>uastc<span style="color: #BBB"> </span>albedo.png<span style="color: #BBB"> </span>albedo.ktx2
|
||||||
|
|
||||||
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the normal map and a compressed variant.</span>
|
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the normal map and a compressed variant.</span>
|
||||||
mipgen --strip-alpha --kernel<span style="color: #666666">=</span>NORMALS --linear normal.png normal.ktx
|
mipgen<span style="color: #BBB"> </span>--strip-alpha<span style="color: #BBB"> </span>--kernel<span style="color: #666">=</span>NORMALS<span style="color: #BBB"> </span>--linear<span style="color: #BBB"> </span>normal.png<span style="color: #BBB"> </span>normal.ktx
|
||||||
mipgen --strip-alpha --kernel<span style="color: #666666">=</span>NORMALS --linear --compression<span style="color: #666666">=</span>uastc_normals <span style="color: #AA5D1F; font-weight: bold">\</span>
|
mipgen<span style="color: #BBB"> </span>--strip-alpha<span style="color: #BBB"> </span>--kernel<span style="color: #666">=</span>NORMALS<span style="color: #BBB"> </span>--linear<span style="color: #BBB"> </span>--compression<span style="color: #666">=</span>uastc_normals<span style="color: #BBB"> </span><span style="color: #AA5D1F; font-weight: bold">\</span>
|
||||||
normal.png normal.ktx2
|
<span style="color: #BBB"> </span>normal.png<span style="color: #BBB"> </span>normal.ktx2
|
||||||
|
|
||||||
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component roughness map and a compressed variant.</span>
|
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component roughness map and a compressed variant.</span>
|
||||||
mipgen --grayscale roughness.png roughness.ktx
|
mipgen<span style="color: #BBB"> </span>--grayscale<span style="color: #BBB"> </span>roughness.png<span style="color: #BBB"> </span>roughness.ktx
|
||||||
mipgen --grayscale --compression<span style="color: #666666">=</span>uastc roughness.png roughness.ktx2
|
mipgen<span style="color: #BBB"> </span>--grayscale<span style="color: #BBB"> </span>--compression<span style="color: #666">=</span>uastc<span style="color: #BBB"> </span>roughness.png<span style="color: #BBB"> </span>roughness.ktx2
|
||||||
|
|
||||||
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component metallic map and a compressed variant.</span>
|
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component metallic map and a compressed variant.</span>
|
||||||
mipgen --grayscale metallic.png metallic.ktx
|
mipgen<span style="color: #BBB"> </span>--grayscale<span style="color: #BBB"> </span>metallic.png<span style="color: #BBB"> </span>metallic.ktx
|
||||||
mipgen --grayscale --compression<span style="color: #666666">=</span>uastc metallic.png metallic.ktx2
|
mipgen<span style="color: #BBB"> </span>--grayscale<span style="color: #BBB"> </span>--compression<span style="color: #666">=</span>uastc<span style="color: #BBB"> </span>metallic.png<span style="color: #BBB"> </span>metallic.ktx2
|
||||||
|
|
||||||
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component occlusion map and a compressed variant.</span>
|
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component occlusion map and a compressed variant.</span>
|
||||||
mipgen --grayscale ao.png ao.ktx
|
mipgen<span style="color: #BBB"> </span>--grayscale<span style="color: #BBB"> </span>ao.png<span style="color: #BBB"> </span>ao.ktx
|
||||||
mipgen --grayscale --compression<span style="color: #666666">=</span>uastc ao.png ao.ktx2
|
mipgen<span style="color: #BBB"> </span>--grayscale<span style="color: #BBB"> </span>--compression<span style="color: #666">=</span>uastc<span style="color: #BBB"> </span>ao.png<span style="color: #BBB"> </span>ao.ktx2
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>For more information on mipgen's arguments and supported formats, do <code>mipgen --help</code>.</p>
|
<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>
|
<p>In a production setting, you'd want to invoke these commands with a script or build system.</p>
|
||||||
<h2>Bake environment map</h2>
|
<h2>Bake environment map</h2>
|
||||||
<p>Much like the <a href="tutorial_redball.html">previous tutorial</a> we need to use Filament's <code>cmgen</code> tool to produce cubemap files.</p>
|
<p>Much like the <a href="tutorial_redball.html">previous tutorial</a> 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>
|
<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>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>cmgen -x . --format<span style="color: #666666">=</span>ktx --size<span style="color: #666666">=64</span> --extract-blur<span style="color: #666666">=0</span>.1 venetian_crossroads_2k.hdr
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>cmgen<span style="color: #BBB"> </span>-x<span style="color: #BBB"> </span>.<span style="color: #BBB"> </span>--format<span style="color: #666">=</span>ktx<span style="color: #BBB"> </span>--size<span style="color: #666">=64</span><span style="color: #BBB"> </span>--extract-blur<span style="color: #666">=0</span>.1<span style="color: #BBB"> </span>venetian_crossroads_2k.hdr
|
||||||
<span style="color: #008000">cd</span> venetian* ; mv venetian*_ibl.ktx venetian_crossroads_2k_skybox_tiny.ktx ; <span style="color: #008000">cd</span> -
|
<span style="color: #008000">cd</span><span style="color: #BBB"> </span>venetian*<span style="color: #BBB"> </span>;<span style="color: #BBB"> </span>mv<span style="color: #BBB"> </span>venetian*_ibl.ktx<span style="color: #BBB"> </span>venetian_crossroads_2k_skybox_tiny.ktx<span style="color: #BBB"> </span>;<span style="color: #BBB"> </span><span style="color: #008000">cd</span><span style="color: #BBB"> </span>-
|
||||||
|
|
||||||
cmgen -x . --format<span style="color: #666666">=</span>ktx --size<span style="color: #666666">=256</span> --extract-blur<span style="color: #666666">=0</span>.1 venetian_crossroads_2k.hdr
|
cmgen<span style="color: #BBB"> </span>-x<span style="color: #BBB"> </span>.<span style="color: #BBB"> </span>--format<span style="color: #666">=</span>ktx<span style="color: #BBB"> </span>--size<span style="color: #666">=256</span><span style="color: #BBB"> </span>--extract-blur<span style="color: #666">=0</span>.1<span style="color: #BBB"> </span>venetian_crossroads_2k.hdr
|
||||||
cmgen -x . --format<span style="color: #666666">=</span>ktx --size<span style="color: #666666">=256</span> --extract-blur<span style="color: #666666">=0</span>.1 venetian_crossroads_2k.hdr
|
cmgen<span style="color: #BBB"> </span>-x<span style="color: #BBB"> </span>.<span style="color: #BBB"> </span>--format<span style="color: #666">=</span>ktx<span style="color: #BBB"> </span>--size<span style="color: #666">=256</span><span style="color: #BBB"> </span>--extract-blur<span style="color: #666">=0</span>.1<span style="color: #BBB"> </span>venetian_crossroads_2k.hdr
|
||||||
cmgen -x . --format<span style="color: #666666">=</span>ktx --size<span style="color: #666666">=256</span> --extract-blur<span style="color: #666666">=0</span>.1 venetian_crossroads_2k.hdr
|
cmgen<span style="color: #BBB"> </span>-x<span style="color: #BBB"> </span>.<span style="color: #BBB"> </span>--format<span style="color: #666">=</span>ktx<span style="color: #BBB"> </span>--size<span style="color: #666">=256</span><span style="color: #BBB"> </span>--extract-blur<span style="color: #666">=0</span>.1<span style="color: #BBB"> </span>venetian_crossroads_2k.hdr
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<h2>Define textured material</h2>
|
<h2>Define textured material</h2>
|
||||||
<p>You might recall the <code>filamat</code> file we generated in the previous tutorial for red plastic. For this
|
<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>
|
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
|
<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>
|
requires a <code>uv0</code> attribute.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>material {
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>material {
|
||||||
@@ -90,7 +90,7 @@ fragment {
|
|||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>Next, invoke <code>matc</code> as follows.</p>
|
<p>Next, invoke <code>matc</code> as follows.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>matc -a opengl -p mobile -o textured.filamat textured.mat
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>matc<span style="color: #BBB"> </span>-a<span style="color: #BBB"> </span>opengl<span style="color: #BBB"> </span>-p<span style="color: #BBB"> </span>mobile<span style="color: #BBB"> </span>-o<span style="color: #BBB"> </span>textured.filamat<span style="color: #BBB"> </span>textured.mat
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>You should now have a material archive in your working directory. For the suzanne asset, the normal
|
<p>You should now have a material archive in your working directory. For the suzanne asset, the normal
|
||||||
@@ -100,65 +100,65 @@ materials, consult the official document describing the <a href="https://google.
|
|||||||
<p>Create a text file called <code>suzanne.html</code> and copy over the HTML that we used in the <a href="tutorial_redball.html">previous
|
<p>Create a text file called <code>suzanne.html</code> and copy over the HTML that we used in the <a href="tutorial_redball.html">previous
|
||||||
tutorial</a>. Change the last script tag from <code>redball.js</code> to <code>suzanne.js</code>. Next, create <code>suzanne.js</code>
|
tutorial</a>. 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>
|
with the following content.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic">// TODO: declare asset URLs</span><span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic">// TODO: declare asset URLs</span>
|
||||||
|
|
||||||
Filament.init([<span style="color: #bbbbbb"> </span>filamat_url,<span style="color: #bbbbbb"> </span>filamesh_url,<span style="color: #bbbbbb"> </span>sky_small_url,<span style="color: #bbbbbb"> </span>ibl_url<span style="color: #bbbbbb"> </span>],<span style="color: #bbbbbb"> </span>()<span style="color: #bbbbbb"> </span>=><span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
Filament.init([<span style="color: #BBB"> </span>filamat_url,<span style="color: #BBB"> </span>filamesh_url,<span style="color: #BBB"> </span>sky_small_url,<span style="color: #BBB"> </span>ibl_url<span style="color: #BBB"> </span>],<span style="color: #BBB"> </span>()<span style="color: #BBB"> </span>=><span style="color: #BBB"> </span>{
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.app<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>App(<span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">'canvas'</span>)[<span style="color: #666666">0</span>]);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.app<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>App(<span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">'canvas'</span>)[<span style="color: #666">0</span>]);
|
||||||
});<span style="color: #bbbbbb"></span>
|
});
|
||||||
|
|
||||||
<span style="color: #008000; font-weight: bold">class</span><span style="color: #bbbbbb"> </span>App<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">class</span><span style="color: #BBB"> </span>App<span style="color: #BBB"> </span>{
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">constructor</span>(canvas)<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">constructor</span>(canvas)<span style="color: #BBB"> </span>{
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>canvas;<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>canvas;
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Engine.create(canvas);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Engine.create(canvas);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.scene<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createScene();<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.scene<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createScene();
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>material<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createMaterial(filamat_url);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>material<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createMaterial(filamat_url);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>material.createInstance();<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>material.createInstance();
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>filamesh<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.loadFilamesh(filamesh_url,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>filamesh<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.loadFilamesh(filamesh_url,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.suzanne<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>filamesh.renderable;<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.suzanne<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>filamesh.renderable;
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create sky box and IBL</span><span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create sky box and IBL</span>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: initialize gltumble</span><span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: initialize gltumble</span>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: fetch larger assets</span><span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: fetch larger assets</span>
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.swapChain<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createSwapChain();<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.swapChain<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createSwapChain();
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createRenderer();<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createRenderer();
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.camera<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createCamera(Filament.EntityManager.get().create());<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.camera<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createCamera(Filament.EntityManager.get().create());
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createView();<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createView();
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setScene(<span style="color: #008000; font-weight: bold">this</span>.scene);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setScene(<span style="color: #008000; font-weight: bold">this</span>.scene);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.render<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.render<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">'resize'</span>,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">'resize'</span>,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize);
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>eye<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">4</span>],<span style="color: #bbbbbb"> </span>center<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>],<span style="color: #bbbbbb"> </span>up<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>];<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>eye<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">4</span>],<span style="color: #BBB"> </span>center<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>],<span style="color: #BBB"> </span>up<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>];
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.lookAt(eye,<span style="color: #bbbbbb"> </span>center,<span style="color: #bbbbbb"> </span>up);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.lookAt(eye,<span style="color: #BBB"> </span>center,<span style="color: #BBB"> </span>up);
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize();<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize();
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||||
<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>}
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span>render()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>render()<span style="color: #BBB"> </span>{
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: apply gltumble matrix</span><span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: apply gltumble matrix</span>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||||
<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>}
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span>resize()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>resize()<span style="color: #BBB"> </span>{
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>dpr<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.devicePixelRatio;<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>dpr<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.devicePixelRatio;
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>width<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.width<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.innerWidth<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span>dpr;<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>width<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.width<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.innerWidth<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span>dpr;
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>height<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.height<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.innerHeight<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span>dpr;<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>height<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.height<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.innerHeight<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span>dpr;
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>width,<span style="color: #bbbbbb"> </span>height]);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>width,<span style="color: #BBB"> </span>height]);
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>aspect<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>width<span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span>height;<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>aspect<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>width<span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span>height;
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>Fov<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Camera$Fov,<span style="color: #bbbbbb"> </span>fov<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>aspect<span style="color: #bbbbbb"> </span><span style="color: #666666"><</span><span style="color: #bbbbbb"> </span><span style="color: #666666">1</span><span style="color: #bbbbbb"> </span><span style="color: #666666">?</span><span style="color: #bbbbbb"> </span>Fov.HORIZONTAL<span style="color: #bbbbbb"> </span><span style="color: #666666">:</span><span style="color: #bbbbbb"> </span>Fov.VERTICAL;<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>Fov<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Camera$Fov,<span style="color: #BBB"> </span>fov<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>aspect<span style="color: #BBB"> </span><span style="color: #666"><</span><span style="color: #BBB"> </span><span style="color: #666">1</span><span style="color: #BBB"> </span><span style="color: #666">?</span><span style="color: #BBB"> </span>Fov.HORIZONTAL<span style="color: #BBB"> </span><span style="color: #666">:</span><span style="color: #BBB"> </span>Fov.VERTICAL;
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.setProjectionFov(<span style="color: #666666">45</span>,<span style="color: #bbbbbb"> </span>aspect,<span style="color: #bbbbbb"> </span><span style="color: #666666">1.0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">10.0</span>,<span style="color: #bbbbbb"> </span>fov);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.setProjectionFov(<span style="color: #666">45</span>,<span style="color: #BBB"> </span>aspect,<span style="color: #BBB"> </span><span style="color: #666">1.0</span>,<span style="color: #BBB"> </span><span style="color: #666">10.0</span>,<span style="color: #BBB"> </span>fov);
|
||||||
<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>}
|
||||||
}<span style="color: #bbbbbb"></span>
|
}
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>Our app will only require a subset of assets to be present for <code>App</code> construction. We'll download
|
<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
|
the other assets after construction. By using a progressive loading strategy, we can reduce the
|
||||||
perceived load time.</p>
|
perceived load time.</p>
|
||||||
<p>Next we need to supply the URLs for various assets. This is actually a bit tricky, because different
|
<p>Next we need to supply the URLs for various assets. This is actually a bit tricky, because different
|
||||||
@@ -171,85 +171,85 @@ 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>
|
<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
|
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>
|
last resort. Go ahead and replace the <strong>declare asset URLs</strong> comment with the following snippet.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>albedo_suffix<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.getSupportedFormatSuffix(<span style="color: #BA2121">'astc s3tc_srgb'</span>);<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>albedo_suffix<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.getSupportedFormatSuffix(<span style="color: #BA2121">'astc s3tc_srgb'</span>);
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>texture_suffix<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.getSupportedFormatSuffix(<span style="color: #BA2121">'etc'</span>);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>texture_suffix<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.getSupportedFormatSuffix(<span style="color: #BA2121">'etc'</span>);
|
||||||
|
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>environ<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">'venetian_crossroads_2k'</span><span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>environ<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">'venetian_crossroads_2k'</span>
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ibl_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_ibl.ktx`</span>;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ibl_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_ibl.ktx`</span>;
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sky_small_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox_tiny.ktx`</span>;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>sky_small_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox_tiny.ktx`</span>;
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sky_large_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox.ktx`</span>;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>sky_large_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox.ktx`</span>;
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>albedo_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`albedo</span><span style="color: #A45A77; font-weight: bold">${</span>albedo_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>albedo_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`albedo</span><span style="color: #A45A77; font-weight: bold">${</span>albedo_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ao_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`ao</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ao_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`ao</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>metallic_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`metallic</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>metallic_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`metallic</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>normal_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`normal</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>normal_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`normal</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>roughness_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`roughness</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>roughness_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`roughness</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>filamat_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">'textured.filamat'</span>;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>filamat_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">'textured.filamat'</span>;
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>filamesh_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">'suzanne.filamesh'</span>;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>filamesh_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">'suzanne.filamesh'</span>;
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<h2>Create skybox and IBL</h2>
|
<h2>Create skybox and IBL</h2>
|
||||||
<p>Next, let's create the low-resolution skybox and IBL in the <code>App</code> constructor.</p>
|
<p>Next, let's create the low-resolution skybox and IBL in the <code>App</code> constructor.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.skybox<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createSkyFromKtx1(sky_small_url);<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.skybox<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createSkyFromKtx1(sky_small_url);
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.scene.setSkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.scene.setSkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox);
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.indirectLight<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createIblFromKtx1(ibl_url);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.indirectLight<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createIblFromKtx1(ibl_url);
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.indirectLight.setIntensity(<span style="color: #666666">100000</span>);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.indirectLight.setIntensity(<span style="color: #666">100000</span>);
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.scene.setIndirectLight(<span style="color: #008000; font-weight: bold">this</span>.indirectLight);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.scene.setIndirectLight(<span style="color: #008000; font-weight: bold">this</span>.indirectLight);
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>This allows users to see a reasonable background fairly quickly, before larger assets have finished
|
<p>This allows users to see a reasonable background fairly quickly, before larger assets have finished
|
||||||
loading in.</p>
|
loading in.</p>
|
||||||
<h2>Fetch assets asychronously</h2>
|
<h2>Fetch assets asychronously</h2>
|
||||||
<p>Next we'll invoke the <code>Filament.fetch</code> function from within the app constructor. This function is
|
<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
|
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>
|
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
|
<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
|
recreate the skybox using a higher-resolution texture. As a last step we unhide the renderable that
|
||||||
was created in the app constructor.</p>
|
was created in the app constructor.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>Filament.fetch([sky_large_url,<span style="color: #bbbbbb"> </span>albedo_url,<span style="color: #bbbbbb"> </span>roughness_url,<span style="color: #bbbbbb"> </span>metallic_url,<span style="color: #bbbbbb"> </span>normal_url,<span style="color: #bbbbbb"> </span>ao_url],<span style="color: #bbbbbb"> </span>()<span style="color: #bbbbbb"> </span>=><span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>Filament.fetch([sky_large_url,<span style="color: #BBB"> </span>albedo_url,<span style="color: #BBB"> </span>roughness_url,<span style="color: #BBB"> </span>metallic_url,<span style="color: #BBB"> </span>normal_url,<span style="color: #BBB"> </span>ao_url],<span style="color: #BBB"> </span>()<span style="color: #BBB"> </span>=><span style="color: #BBB"> </span>{
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>albedo<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(albedo_url,<span style="color: #bbbbbb"> </span>{srgb<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">true</span>});<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>albedo<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(albedo_url,<span style="color: #BBB"> </span>{srgb<span style="color: #666">:</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">true</span>});
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>roughness<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(roughness_url);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>roughness<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(roughness_url);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>metallic<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(metallic_url);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>metallic<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(metallic_url);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>normal<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(normal_url);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>normal<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(normal_url);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ao<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(ao_url);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ao<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(ao_url);
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sampler<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>Filament.TextureSampler(<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>sampler<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>Filament.TextureSampler(
|
||||||
<span style="color: #bbbbbb"> </span>Filament.MinFilter.LINEAR_MIPMAP_LINEAR,<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>Filament.MinFilter.LINEAR_MIPMAP_LINEAR,
|
||||||
<span style="color: #bbbbbb"> </span>Filament.MagFilter.LINEAR,<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>Filament.MagFilter.LINEAR,
|
||||||
<span style="color: #bbbbbb"> </span>Filament.WrapMode.CLAMP_TO_EDGE);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>Filament.WrapMode.CLAMP_TO_EDGE);
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'albedo'</span>,<span style="color: #bbbbbb"> </span>albedo,<span style="color: #bbbbbb"> </span>sampler);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'albedo'</span>,<span style="color: #BBB"> </span>albedo,<span style="color: #BBB"> </span>sampler);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'roughness'</span>,<span style="color: #bbbbbb"> </span>roughness,<span style="color: #bbbbbb"> </span>sampler);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'roughness'</span>,<span style="color: #BBB"> </span>roughness,<span style="color: #BBB"> </span>sampler);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'metallic'</span>,<span style="color: #bbbbbb"> </span>metallic,<span style="color: #bbbbbb"> </span>sampler);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'metallic'</span>,<span style="color: #BBB"> </span>metallic,<span style="color: #BBB"> </span>sampler);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'normal'</span>,<span style="color: #bbbbbb"> </span>normal,<span style="color: #bbbbbb"> </span>sampler);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'normal'</span>,<span style="color: #BBB"> </span>normal,<span style="color: #BBB"> </span>sampler);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'ao'</span>,<span style="color: #bbbbbb"> </span>ao,<span style="color: #bbbbbb"> </span>sampler);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'ao'</span>,<span style="color: #BBB"> </span>ao,<span style="color: #BBB"> </span>sampler);
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// Replace low-res skybox with high-res skybox.</span><span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// Replace low-res skybox with high-res skybox.</span>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.destroySkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.destroySkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.skybox<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createSkyFromKtx1(sky_large_url);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.skybox<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createSkyFromKtx1(sky_large_url);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.scene.setSkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.scene.setSkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox);
|
||||||
|
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.scene.addEntity(<span style="color: #008000; font-weight: bold">this</span>.suzanne);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.scene.addEntity(<span style="color: #008000; font-weight: bold">this</span>.suzanne);
|
||||||
});<span style="color: #bbbbbb"></span>
|
});
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<h2>Introduce trackball rotation</h2>
|
<h2>Introduce trackball rotation</h2>
|
||||||
<p>Add the following script tag to your HTML file. This imports a small third-party library that
|
<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>
|
listens for drag events and computes a rotation matrix.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666666">=</span><span style="color: #BA2121">"//unpkg.com/gltumble"</span>></<span style="color: #008000; font-weight: bold">script</span>>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666">=</span><span style="color: #BA2121">"//unpkg.com/gltumble"</span>></<span style="color: #008000; font-weight: bold">script</span>>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>Next, replace the <strong>initialize gltumble</strong> and <strong>apply gltumble matrix</strong> comments with the following
|
<p>Next, replace the <strong>initialize gltumble</strong> and <strong>apply gltumble matrix</strong> comments with the following
|
||||||
two code snippets.</p>
|
two code snippets.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.trackball<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>Trackball(canvas,<span style="color: #bbbbbb"> </span>{startSpin<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span><span style="color: #666666">0.035</span>});<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.trackball<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>Trackball(canvas,<span style="color: #BBB"> </span>{startSpin<span style="color: #666">:</span><span style="color: #BBB"> </span><span style="color: #666">0.035</span>});
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>tcm<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.getTransformManager();<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>tcm<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.getTransformManager();
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>inst<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>tcm.getInstance(<span style="color: #008000; font-weight: bold">this</span>.suzanne);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>inst<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>tcm.getInstance(<span style="color: #008000; font-weight: bold">this</span>.suzanne);
|
||||||
tcm.setTransform(inst,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.trackball.getMatrix());<span style="color: #bbbbbb"></span>
|
tcm.setTransform(inst,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.trackball.getMatrix());
|
||||||
inst.<span style="color: #AA22FF; font-weight: bold">delete</span>();<span style="color: #bbbbbb"></span>
|
inst.<span style="color: #A2F; font-weight: bold">delete</span>();
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>That's it, we now have a fast-loading interactive demo. The complete JavaScript file is available
|
<p>That's it, we now have a fast-loading interactive demo. The complete JavaScript file is available
|
||||||
<a href="tutorial_suzanne.js">here</a>.</p>
|
<a href="tutorial_suzanne.js">here</a>.</p>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+110
-110
@@ -8,30 +8,30 @@
|
|||||||
<div class="demo_frame"><iframe src="demo_triangle.html"></iframe><a href="demo_triangle.html">🔗</a></div>
|
<div class="demo_frame"><iframe src="demo_triangle.html"></iframe><a href="demo_triangle.html">🔗</a></div>
|
||||||
<h2>Literate programming</h2>
|
<h2>Literate programming</h2>
|
||||||
<p>The markdown source for this tutorial is not only used to generate this
|
<p>The markdown source for this tutorial is not only used to generate this
|
||||||
web page, it's also used to generate the JavaScript for the above demo.
|
web page, it's also used to generate the JavaScript for the above demo.
|
||||||
We use a small Python script for weaving (generating HTML) and tangling
|
We use a small Python script for weaving (generating HTML) and tangling
|
||||||
(generating JS). In the code samples, you'll often see
|
(generating JS). In the code samples, you'll often see
|
||||||
<code>// TODO: <some task></code>. These are special markers that get replaced by
|
<code>// TODO: <some task></code>. These are special markers that get replaced by
|
||||||
subsequent code blocks.</p>
|
subsequent code blocks.</p>
|
||||||
<h2>Start your project</h2>
|
<h2>Start your project</h2>
|
||||||
<p>First, create a text file called <code>triangle.html</code> and fill it with the following HTML. This creates
|
<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>
|
a mobile-friendly page with a full-screen canvas.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #9C6500"><!DOCTYPE html></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #9C6500"><!DOCTYPE html></span>
|
||||||
<<span style="color: #008000; font-weight: bold">html</span> <span style="color: #687822">lang</span><span style="color: #666666">=</span><span style="color: #BA2121">"en"</span>>
|
<<span style="color: #008000; font-weight: bold">html</span> <span style="color: #687822">lang</span><span style="color: #666">=</span><span style="color: #BA2121">"en"</span>>
|
||||||
<<span style="color: #008000; font-weight: bold">head</span>>
|
<<span style="color: #008000; font-weight: bold">head</span>>
|
||||||
<<span style="color: #008000; font-weight: bold">title</span>>Filament Tutorial</<span style="color: #008000; font-weight: bold">title</span>>
|
<<span style="color: #008000; font-weight: bold">title</span>>Filament Tutorial</<span style="color: #008000; font-weight: bold">title</span>>
|
||||||
<<span style="color: #008000; font-weight: bold">meta</span> <span style="color: #687822">charset</span><span style="color: #666666">=</span><span style="color: #BA2121">"utf-8"</span>>
|
<<span style="color: #008000; font-weight: bold">meta</span> <span style="color: #687822">charset</span><span style="color: #666">=</span><span style="color: #BA2121">"utf-8"</span>>
|
||||||
<<span style="color: #008000; font-weight: bold">meta</span> <span style="color: #687822">name</span><span style="color: #666666">=</span><span style="color: #BA2121">"viewport"</span> <span style="color: #687822">content</span><span style="color: #666666">=</span><span style="color: #BA2121">"width=device-width,user-scalable=no,initial-scale=1"</span>>
|
<<span style="color: #008000; font-weight: bold">meta</span> <span style="color: #687822">name</span><span style="color: #666">=</span><span style="color: #BA2121">"viewport"</span> <span style="color: #687822">content</span><span style="color: #666">=</span><span style="color: #BA2121">"width=device-width,user-scalable=no,initial-scale=1"</span>>
|
||||||
<<span style="color: #008000; font-weight: bold">style</span>><span style="color: #bbbbbb"></span>
|
<<span style="color: #008000; font-weight: bold">style</span>>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">body</span><span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">margin</span>:<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>;<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">overflow</span>:<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">hidden</span>;<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">body</span><span style="color: #BBB"> </span>{<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">margin</span>:<span style="color: #BBB"> </span><span style="color: #666">0</span>;<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">overflow</span>:<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">hidden</span>;<span style="color: #BBB"> </span>}
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">canvas</span><span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"> </span>touch-action:<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">none</span>;<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">width</span>:<span style="color: #bbbbbb"> </span><span style="color: #666666">100</span><span style="color: #B00040">%</span>;<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">height</span>:<span style="color: #bbbbbb"> </span><span style="color: #666666">100</span><span style="color: #B00040">%</span>;<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">canvas</span><span style="color: #BBB"> </span>{<span style="color: #BBB"> </span>touch-action:<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">none</span>;<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">width</span>:<span style="color: #BBB"> </span><span style="color: #666">100</span><span style="color: #B00040">%</span>;<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">height</span>:<span style="color: #BBB"> </span><span style="color: #666">100</span><span style="color: #B00040">%</span>;<span style="color: #BBB"> </span>}
|
||||||
<span style="color: #bbbbbb"> </span></<span style="color: #008000; font-weight: bold">style</span>>
|
<span style="color: #BBB"> </span></<span style="color: #008000; font-weight: bold">style</span>>
|
||||||
</<span style="color: #008000; font-weight: bold">head</span>>
|
</<span style="color: #008000; font-weight: bold">head</span>>
|
||||||
<<span style="color: #008000; font-weight: bold">body</span>>
|
<<span style="color: #008000; font-weight: bold">body</span>>
|
||||||
<<span style="color: #008000; font-weight: bold">canvas</span>></<span style="color: #008000; font-weight: bold">canvas</span>>
|
<<span style="color: #008000; font-weight: bold">canvas</span>></<span style="color: #008000; font-weight: bold">canvas</span>>
|
||||||
<<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666666">=</span><span style="color: #BA2121">"filament.js"</span>></<span style="color: #008000; font-weight: bold">script</span>>
|
<<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666">=</span><span style="color: #BA2121">"filament.js"</span>></<span style="color: #008000; font-weight: bold">script</span>>
|
||||||
<<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666666">=</span><span style="color: #BA2121">"//unpkg.com/gl-matrix@2.8.1"</span>></<span style="color: #008000; font-weight: bold">script</span>>
|
<<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666">=</span><span style="color: #BA2121">"//unpkg.com/gl-matrix@2.8.1"</span>></<span style="color: #008000; font-weight: bold">script</span>>
|
||||||
<<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666666">=</span><span style="color: #BA2121">"triangle.js"</span>></<span style="color: #008000; font-weight: bold">script</span>>
|
<<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666">=</span><span style="color: #BA2121">"triangle.js"</span>></<span style="color: #008000; font-weight: bold">script</span>>
|
||||||
</<span style="color: #008000; font-weight: bold">body</span>>
|
</<span style="color: #008000; font-weight: bold">body</span>>
|
||||||
</<span style="color: #008000; font-weight: bold">html</span>>
|
</<span style="color: #008000; font-weight: bold">html</span>>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
@@ -48,63 +48,63 @@ a mobile-friendly page with a full-screen canvas.</p>
|
|||||||
<li><code>triangle.js</code> will contain your application code.</li>
|
<li><code>triangle.js</code> will contain your application code.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Go ahead and create <code>triangle.js</code> with the following content.</p>
|
<p>Go ahead and create <code>triangle.js</code> with the following content.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">class</span><span style="color: #bbbbbb"> </span>App<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">class</span><span style="color: #BBB"> </span>App<span style="color: #BBB"> </span>{
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">constructor</span>()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">constructor</span>()<span style="color: #BBB"> </span>{
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create entities</span><span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create entities</span>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.render<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.render<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">'resize'</span>,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">'resize'</span>,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize);
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||||
<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>}
|
||||||
<span style="color: #bbbbbb"> </span>render()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>render()<span style="color: #BBB"> </span>{
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: render scene</span><span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: render scene</span>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||||
<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>}
|
||||||
<span style="color: #bbbbbb"> </span>resize()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>resize()<span style="color: #BBB"> </span>{
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: adjust viewport and canvas</span><span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: adjust viewport and canvas</span>
|
||||||
<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>}
|
||||||
}<span style="color: #bbbbbb"></span>
|
}
|
||||||
|
|
||||||
Filament.init([<span style="color: #BA2121">'triangle.filamat'</span>],<span style="color: #bbbbbb"> </span>()<span style="color: #bbbbbb"> </span>=><span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.app<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>App()<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"> </span>);<span style="color: #bbbbbb"></span>
|
Filament.init([<span style="color: #BA2121">'triangle.filamat'</span>],<span style="color: #BBB"> </span>()<span style="color: #BBB"> </span>=><span style="color: #BBB"> </span>{<span style="color: #BBB"> </span><span style="color: #008000">window</span>.app<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>App()<span style="color: #BBB"> </span>}<span style="color: #BBB"> </span>);
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>The two calls to <code>bind()</code> allow us to pass instance methods as callbacks for animation and resize
|
<p>The two calls to <code>bind()</code> allow us to pass instance methods as callbacks for animation and resize
|
||||||
events.</p>
|
events.</p>
|
||||||
<p><code>Filament.init()</code> consumes two things: a list of asset URLs and a callback.</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
|
<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
|
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
|
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>
|
from the developer console.</p>
|
||||||
<p>Go ahead and download <a href="triangle.filamat">triangle.filamat</a> and place it in your project folder.
|
<p>Go ahead and download <a href="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
|
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>
|
that define a PBR material. We'll learn more about material packages in the next tutorial.</p>
|
||||||
<h2>Spawn a local server</h2>
|
<h2>Spawn a local server</h2>
|
||||||
<p>Because of CORS restrictions, your web app cannot fetch the material package directly from the
|
<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>
|
file system. One way around this is to create a temporary server using Python or node:</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>python3 -m http.server <span style="color: #3D7B7B; font-style: italic"># Python 3</span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>python3<span style="color: #BBB"> </span>-m<span style="color: #BBB"> </span>http.server<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic"># Python 3</span>
|
||||||
python -m SimpleHTTPServer <span style="color: #3D7B7B; font-style: italic"># Python 2.7</span>
|
python<span style="color: #BBB"> </span>-m<span style="color: #BBB"> </span>SimpleHTTPServer<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic"># Python 2.7</span>
|
||||||
npx http-server -p <span style="color: #666666">8000</span> <span style="color: #3D7B7B; font-style: italic"># nodejs</span>
|
npx<span style="color: #BBB"> </span>http-server<span style="color: #BBB"> </span>-p<span style="color: #BBB"> </span><span style="color: #666">8000</span><span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic"># nodejs</span>
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>To see if this works, navigate to <a href="http://localhost:8000">http://localhost:8000</a> and check if you
|
<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>
|
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
|
<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>
|
with the correct MIME type.</p>
|
||||||
<h2>Create the Engine and Scene</h2>
|
<h2>Create the Engine and Scene</h2>
|
||||||
<p>We now have a basic skeleton that can respond to paint and resize events. Let's start adding
|
<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>
|
Filament objects to the app. Insert the following code into the top of the app constructor.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.canvas<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">'canvas'</span>)[<span style="color: #666666">0</span>];<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.canvas<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">'canvas'</span>)[<span style="color: #666">0</span>];
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>engine<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Engine.create(<span style="color: #008000; font-weight: bold">this</span>.canvas);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>engine<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Engine.create(<span style="color: #008000; font-weight: bold">this</span>.canvas);
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>The above snippet creates the <code>Engine</code> by passing it a canvas DOM object. The engine needs the
|
<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>
|
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
|
<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
|
entities. Let's go ahead and create a scene, then add a blank entity called <code>triangle</code> into the
|
||||||
scene.</p>
|
scene.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.scene<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createScene();<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.scene<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createScene();
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.triangle<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.EntityManager.get().create();<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.triangle<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.EntityManager.get().create();
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.scene.addEntity(<span style="color: #008000; font-weight: bold">this</span>.triangle);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.scene.addEntity(<span style="color: #008000; font-weight: bold">this</span>.triangle);
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>Filament uses an <a href="//en.wikipedia.org/wiki/Entity-component-system">Entity-Component System</a>.
|
<p>Filament uses an <a href="//en.wikipedia.org/wiki/Entity-component-system">Entity-Component System</a>.
|
||||||
@@ -112,30 +112,30 @@ The triangle entity in the above snippet does not yet have an associated compone
|
|||||||
tutorial we will make it into a <em>renderable</em>. Renderables are entities that have associated draw
|
tutorial we will make it into a <em>renderable</em>. Renderables are entities that have associated draw
|
||||||
calls.</p>
|
calls.</p>
|
||||||
<h2>Construct typed arrays</h2>
|
<h2>Construct typed arrays</h2>
|
||||||
<p>Next we'll create two typed arrays: a positions array with XY coordinates for each vertex, and a
|
<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>
|
colors array with a 32-bit word for each vertex.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>TRIANGLE_POSITIONS<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span><span style="color: #008000">Float32Array</span>([<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>TRIANGLE_POSITIONS<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span><span style="color: #008000">Float32Array</span>([
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">Math</span>.cos(<span style="color: #008000">Math</span>.PI<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span><span style="color: #666666">2</span><span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">3</span>),<span style="color: #bbbbbb"> </span><span style="color: #008000">Math</span>.sin(<span style="color: #008000">Math</span>.PI<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span><span style="color: #666666">2</span><span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">3</span>),<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">Math</span>.cos(<span style="color: #008000">Math</span>.PI<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span><span style="color: #666">2</span><span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">3</span>),<span style="color: #BBB"> </span><span style="color: #008000">Math</span>.sin(<span style="color: #008000">Math</span>.PI<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span><span style="color: #666">2</span><span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">3</span>),
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">Math</span>.cos(<span style="color: #008000">Math</span>.PI<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span><span style="color: #666666">4</span><span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">3</span>),<span style="color: #bbbbbb"> </span><span style="color: #008000">Math</span>.sin(<span style="color: #008000">Math</span>.PI<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span><span style="color: #666666">4</span><span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">3</span>),<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">Math</span>.cos(<span style="color: #008000">Math</span>.PI<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span><span style="color: #666">4</span><span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">3</span>),<span style="color: #BBB"> </span><span style="color: #008000">Math</span>.sin(<span style="color: #008000">Math</span>.PI<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span><span style="color: #666">4</span><span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">3</span>),
|
||||||
]);<span style="color: #bbbbbb"></span>
|
]);
|
||||||
|
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>TRIANGLE_COLORS<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span><span style="color: #008000">Uint32Array</span>([<span style="color: #666666">0xffff0000</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0xff00ff00</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0xff0000ff</span>]);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>TRIANGLE_COLORS<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span><span style="color: #008000">Uint32Array</span>([<span style="color: #666">0xffff0000</span>,<span style="color: #BBB"> </span><span style="color: #666">0xff00ff00</span>,<span style="color: #BBB"> </span><span style="color: #666">0xff0000ff</span>]);
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>Next we'll use the positions and colors buffers to create a single <code>VertexBuffer</code> object.</p>
|
<p>Next we'll use the positions and colors buffers to create a single <code>VertexBuffer</code> object.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>VertexAttribute<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.VertexAttribute;<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>VertexAttribute<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.VertexAttribute;
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>AttributeType<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.VertexBuffer$AttributeType;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>AttributeType<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.VertexBuffer$AttributeType;
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.vb<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.VertexBuffer.Builder()<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.vb<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.VertexBuffer.Builder()
|
||||||
<span style="color: #bbbbbb"> </span>.vertexCount(<span style="color: #666666">3</span>)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.vertexCount(<span style="color: #666">3</span>)
|
||||||
<span style="color: #bbbbbb"> </span>.bufferCount(<span style="color: #666666">2</span>)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.bufferCount(<span style="color: #666">2</span>)
|
||||||
<span style="color: #bbbbbb"> </span>.attribute(VertexAttribute.POSITION,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>AttributeType.FLOAT2,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">8</span>)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.attribute(VertexAttribute.POSITION,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>AttributeType.FLOAT2,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">8</span>)
|
||||||
<span style="color: #bbbbbb"> </span>.attribute(VertexAttribute.COLOR,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span>AttributeType.UBYTE4,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">4</span>)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.attribute(VertexAttribute.COLOR,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span>AttributeType.UBYTE4,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">4</span>)
|
||||||
<span style="color: #bbbbbb"> </span>.normalized(VertexAttribute.COLOR)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.normalized(VertexAttribute.COLOR)
|
||||||
<span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.build(engine);
|
||||||
|
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.vb.setBufferAt(engine,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>TRIANGLE_POSITIONS);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.vb.setBufferAt(engine,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>TRIANGLE_POSITIONS);
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.vb.setBufferAt(engine,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span>TRIANGLE_COLORS);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.vb.setBufferAt(engine,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span>TRIANGLE_COLORS);
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>The above snippet first creates aliases for two enum types, then constructs the vertex buffer using
|
<p>The above snippet first creates aliases for two enum types, then constructs the vertex buffer using
|
||||||
@@ -147,74 +147,74 @@ self-documenting.</p>
|
|||||||
<p>Our app sets up two buffer slots in the vertex buffer, and each slot is associated with a single
|
<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
|
attribute. Alternatively, we could have interleaved or concatenated these attributes into a single
|
||||||
buffer slot.</p>
|
buffer slot.</p>
|
||||||
<p>Next we'll construct an index buffer. The index buffer for our triangle is trivial: it simply holds
|
<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>
|
the integers 0,1,2.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.ib<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.IndexBuffer.Builder()<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.ib<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.IndexBuffer.Builder()
|
||||||
<span style="color: #bbbbbb"> </span>.indexCount(<span style="color: #666666">3</span>)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.indexCount(<span style="color: #666">3</span>)
|
||||||
<span style="color: #bbbbbb"> </span>.bufferType(Filament.IndexBuffer$IndexType.USHORT)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.bufferType(Filament.IndexBuffer$IndexType.USHORT)
|
||||||
<span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.build(engine);
|
||||||
|
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.ib.setBuffer(engine,<span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span><span style="color: #008000">Uint16Array</span>([<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">2</span>]));<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.ib.setBuffer(engine,<span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span><span style="color: #008000">Uint16Array</span>([<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">2</span>]));
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>Note that constructing an index buffer is similar to constructing a vertex buffer, but it only has
|
<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>
|
one buffer slot, and it can only contain two types of data (USHORT or UINT).</p>
|
||||||
<h2>Finish up initialization</h2>
|
<h2>Finish up initialization</h2>
|
||||||
<p>Next let's construct an actual <code>Material</code> from the material package that was downloaded (the
|
<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
|
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
|
<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
|
parameters, and they can be bound to renderables. We'll learn more about material instances in the
|
||||||
next tutorial.</p>
|
next tutorial.</p>
|
||||||
<p>After extracting the material instance, we can finally create a renderable component for the
|
<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>
|
triangle by setting up a bounding box and passing in the vertex and index buffers.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>mat<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createMaterial(<span style="color: #BA2121">'triangle.filamat'</span>);<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>mat<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createMaterial(<span style="color: #BA2121">'triangle.filamat'</span>);
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>matinst<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>mat.getDefaultInstance();<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>matinst<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>mat.getDefaultInstance();
|
||||||
Filament.RenderableManager.Builder(<span style="color: #666666">1</span>)<span style="color: #bbbbbb"></span>
|
Filament.RenderableManager.Builder(<span style="color: #666">1</span>)
|
||||||
<span style="color: #bbbbbb"> </span>.boundingBox({<span style="color: #bbbbbb"> </span>center<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">-1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">-1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">-1</span>],<span style="color: #bbbbbb"> </span>halfExtent<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>]<span style="color: #bbbbbb"> </span>})<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.boundingBox({<span style="color: #BBB"> </span>center<span style="color: #666">:</span><span style="color: #BBB"> </span>[<span style="color: #666">-1</span>,<span style="color: #BBB"> </span><span style="color: #666">-1</span>,<span style="color: #BBB"> </span><span style="color: #666">-1</span>],<span style="color: #BBB"> </span>halfExtent<span style="color: #666">:</span><span style="color: #BBB"> </span>[<span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>]<span style="color: #BBB"> </span>})
|
||||||
<span style="color: #bbbbbb"> </span>.material(<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>matinst)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.material(<span style="color: #666">0</span>,<span style="color: #BBB"> </span>matinst)
|
||||||
<span style="color: #bbbbbb"> </span>.geometry(<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>Filament.RenderableManager$PrimitiveType.TRIANGLES,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.vb,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.ib)<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.geometry(<span style="color: #666">0</span>,<span style="color: #BBB"> </span>Filament.RenderableManager$PrimitiveType.TRIANGLES,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.vb,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.ib)
|
||||||
<span style="color: #bbbbbb"> </span>.build(engine,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.triangle);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span>.build(engine,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.triangle);
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>Next let's wrap up the initialization routine by creating the swap chain, renderer, camera, and
|
<p>Next let's wrap up the initialization routine by creating the swap chain, renderer, camera, and
|
||||||
view.</p>
|
view.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.swapChain<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createSwapChain();<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.swapChain<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createSwapChain();
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.renderer<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createRenderer();<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.renderer<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createRenderer();
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.camera<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createCamera(Filament.EntityManager.get().create());<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.camera<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createCamera(Filament.EntityManager.get().create());
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.view<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createView();<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.view<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createView();
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera);
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.view.setScene(<span style="color: #008000; font-weight: bold">this</span>.scene);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.view.setScene(<span style="color: #008000; font-weight: bold">this</span>.scene);
|
||||||
|
|
||||||
<span style="color: #3D7B7B; font-style: italic">// Set up a blue-green background:</span><span style="color: #bbbbbb"></span>
|
<span style="color: #3D7B7B; font-style: italic">// Set up a blue-green background:</span>
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.renderer.setClearOptions({clearColor<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0.0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.2</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1.0</span>],<span style="color: #bbbbbb"> </span>clear<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">true</span>});<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.renderer.setClearOptions({clearColor<span style="color: #666">:</span><span style="color: #BBB"> </span>[<span style="color: #666">0.0</span>,<span style="color: #BBB"> </span><span style="color: #666">0.1</span>,<span style="color: #BBB"> </span><span style="color: #666">0.2</span>,<span style="color: #BBB"> </span><span style="color: #666">1.0</span>],<span style="color: #BBB"> </span>clear<span style="color: #666">:</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">true</span>});
|
||||||
|
|
||||||
<span style="color: #3D7B7B; font-style: italic">// Adjust the initial viewport:</span><span style="color: #bbbbbb"></span>
|
<span style="color: #3D7B7B; font-style: italic">// Adjust the initial viewport:</span>
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.resize();<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.resize();
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>At this point, we're done creating all Filament entities, and the code should run without errors.
|
<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>
|
However the canvas is still blank!</p>
|
||||||
<h2>Render and resize handlers</h2>
|
<h2>Render and resize handlers</h2>
|
||||||
<p>Recall that our App class has a skeletal render method, which the browser calls every time it needs
|
<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>
|
to repaint. Often this is 60 times a second.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>render()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>render()<span style="color: #BBB"> </span>{
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: render scene</span><span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: render scene</span>
|
||||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
|
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||||
}<span style="color: #bbbbbb"></span>
|
}
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>Let's flesh this out by rotating the triangle and invoking the Filament renderer. Add the following
|
<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>
|
code to the top of the render method.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic">// Rotate the triangle.</span><span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic">// Rotate the triangle.</span>
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>radians<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">Date</span>.now()<span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">1000</span>;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>radians<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">Date</span>.now()<span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">1000</span>;
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>transform<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>mat4.fromRotation(mat4.create(),<span style="color: #bbbbbb"> </span>radians,<span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>]);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>transform<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>mat4.fromRotation(mat4.create(),<span style="color: #BBB"> </span>radians,<span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>]);
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>tcm<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.getTransformManager();<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>tcm<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.getTransformManager();
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>inst<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>tcm.getInstance(<span style="color: #008000; font-weight: bold">this</span>.triangle);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>inst<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>tcm.getInstance(<span style="color: #008000; font-weight: bold">this</span>.triangle);
|
||||||
tcm.setTransform(inst,<span style="color: #bbbbbb"> </span>transform);<span style="color: #bbbbbb"></span>
|
tcm.setTransform(inst,<span style="color: #BBB"> </span>transform);
|
||||||
inst.<span style="color: #AA22FF; font-weight: bold">delete</span>();<span style="color: #bbbbbb"></span>
|
inst.<span style="color: #A2F; font-weight: bold">delete</span>();
|
||||||
|
|
||||||
<span style="color: #3D7B7B; font-style: italic">// Render the frame.</span><span style="color: #bbbbbb"></span>
|
<span style="color: #3D7B7B; font-style: italic">// Render the frame.</span>
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view);
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>The first half of our render method obtains the transform component of the triangle entity and uses
|
<p>The first half of our render method obtains the transform component of the triangle entity and uses
|
||||||
@@ -225,19 +225,19 @@ 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
|
<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
|
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>
|
displays. It also adjusts the camera frustum accordingly.</p>
|
||||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>dpr<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.devicePixelRatio;<span style="color: #bbbbbb"></span>
|
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>dpr<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.devicePixelRatio;
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>width<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.width<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.innerWidth<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span>dpr;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>width<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.width<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.innerWidth<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span>dpr;
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>height<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.height<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.innerHeight<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span>dpr;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>height<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.height<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.innerHeight<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span>dpr;
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>width,<span style="color: #bbbbbb"> </span>height]);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>width,<span style="color: #BBB"> </span>height]);
|
||||||
|
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>aspect<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>width<span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span>height;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>aspect<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>width<span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span>height;
|
||||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>Projection<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Camera$Projection;<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>Projection<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Camera$Projection;
|
||||||
<span style="color: #008000; font-weight: bold">this</span>.camera.setProjection(Projection.ORTHO,<span style="color: #bbbbbb"> </span><span style="color: #666666">-</span>aspect,<span style="color: #bbbbbb"> </span>aspect,<span style="color: #bbbbbb"> </span><span style="color: #666666">-1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>);<span style="color: #bbbbbb"></span>
|
<span style="color: #008000; font-weight: bold">this</span>.camera.setProjection(Projection.ORTHO,<span style="color: #BBB"> </span><span style="color: #666">-</span>aspect,<span style="color: #BBB"> </span>aspect,<span style="color: #BBB"> </span><span style="color: #666">-1</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>);
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
<p>You should now have a spinning triangle! The completed JavaScript is available
|
<p>You should now have a spinning triangle! The completed JavaScript is available
|
||||||
<a href="tutorial_triangle.js">here</a>.</p>
|
<a href="tutorial_triangle.js">here</a>.</p>
|
||||||
<p>In the <a href="tutorial_redball.html">next tutorial</a>, we'll take a closer look at Filament materials and 3D rendering.</p>
|
<p>In the <a href="tutorial_redball.html">next tutorial</a>, we'll take a closer look at Filament materials and 3D rendering.</p>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -5,6 +5,18 @@ set(TARGET backend)
|
|||||||
set(PUBLIC_HDR_DIR include)
|
set(PUBLIC_HDR_DIR include)
|
||||||
set(GENERATION_ROOT ${CMAKE_CURRENT_BINARY_DIR})
|
set(GENERATION_ROOT ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
# ==================================================================================================
|
||||||
|
# Compilation options
|
||||||
|
# ==================================================================================================
|
||||||
|
#
|
||||||
|
set(BACKEND_SANITIZATION "" CACHE STRING "Sanitization option")
|
||||||
|
set_property(CACHE BACKEND_SANITIZATION PROPERTY STRINGS ";ASAN")
|
||||||
|
|
||||||
|
set(BACKEND_SANITIZERS)
|
||||||
|
if (BACKEND_SANITIZATION STREQUAL "ASAN")
|
||||||
|
set(BACKEND_SANITIZERS -fsanitize=address)
|
||||||
|
endif()
|
||||||
|
|
||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
# Sources and headers
|
# Sources and headers
|
||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
@@ -472,6 +484,7 @@ target_compile_options(${TARGET} PRIVATE
|
|||||||
${OSMESA_COMPILE_FLAGS}
|
${OSMESA_COMPILE_FLAGS}
|
||||||
$<$<CONFIG:Release>:${OPTIMIZATION_FLAGS}>
|
$<$<CONFIG:Release>:${OPTIMIZATION_FLAGS}>
|
||||||
$<$<AND:$<PLATFORM_ID:Darwin>,$<CONFIG:Release>>:${DARWIN_OPTIMIZATION_FLAGS}>
|
$<$<AND:$<PLATFORM_ID:Darwin>,$<CONFIG:Release>>:${DARWIN_OPTIMIZATION_FLAGS}>
|
||||||
|
${BACKEND_SANITIZERS}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (FILAMENT_SUPPORTS_METAL)
|
if (FILAMENT_SUPPORTS_METAL)
|
||||||
@@ -482,6 +495,8 @@ if (FILAMENT_SUPPORTS_WEBGPU)
|
|||||||
target_compile_definitions(${TARGET} PRIVATE $<$<BOOL:${FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING}>:FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING>)
|
target_compile_definitions(${TARGET} PRIVATE $<$<BOOL:${FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING}>:FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING>)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
target_link_options(${TARGET} PRIVATE ${BACKEND_SANITIZERS})
|
||||||
|
|
||||||
target_link_libraries(${TARGET} PRIVATE
|
target_link_libraries(${TARGET} PRIVATE
|
||||||
${OSMESA_LINKER_FLAGS}
|
${OSMESA_LINKER_FLAGS}
|
||||||
$<$<AND:$<PLATFORM_ID:Linux>,$<CONFIG:Release>>:${LINUX_LINKER_OPTIMIZATION_FLAGS}>
|
$<$<AND:$<PLATFORM_ID:Linux>,$<CONFIG:Release>>:${LINUX_LINKER_OPTIMIZATION_FLAGS}>
|
||||||
@@ -551,6 +566,8 @@ if (APPLE AND NOT IOS)
|
|||||||
test/test_RenderExternalImage.cpp)
|
test/test_RenderExternalImage.cpp)
|
||||||
add_library(backend_test STATIC ${BACKEND_TEST_SRC})
|
add_library(backend_test STATIC ${BACKEND_TEST_SRC})
|
||||||
target_link_libraries(backend_test PUBLIC ${BACKEND_TEST_LIBS})
|
target_link_libraries(backend_test PUBLIC ${BACKEND_TEST_LIBS})
|
||||||
|
target_compile_options(backend_test PRIVATE ${BACKEND_SANITIZERS})
|
||||||
|
target_link_options(backend_test PRIVATE ${BACKEND_SANITIZERS})
|
||||||
|
|
||||||
set(BACKEND_TEST_DEPS
|
set(BACKEND_TEST_DEPS
|
||||||
OSDependent
|
OSDependent
|
||||||
@@ -589,6 +606,7 @@ if (APPLE AND NOT IOS)
|
|||||||
# linker from removing "unused" symbols.
|
# linker from removing "unused" symbols.
|
||||||
target_link_libraries(backend_test_mac PRIVATE -force_load backend_test)
|
target_link_libraries(backend_test_mac PRIVATE -force_load backend_test)
|
||||||
set_target_properties(backend_test_mac PROPERTIES FOLDER Tests)
|
set_target_properties(backend_test_mac PROPERTIES FOLDER Tests)
|
||||||
|
target_link_options(backend_test_mac PRIVATE ${BACKEND_SANITIZERS})
|
||||||
|
|
||||||
# This is needed after XCode 15.3
|
# This is needed after XCode 15.3
|
||||||
set_target_properties(backend_test_mac PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
|
set_target_properties(backend_test_mac PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
|
||||||
@@ -598,6 +616,8 @@ endif()
|
|||||||
|
|
||||||
if (LINUX)
|
if (LINUX)
|
||||||
add_executable(backend_test_linux test/linux_runner.cpp ${BACKEND_TEST_SRC})
|
add_executable(backend_test_linux test/linux_runner.cpp ${BACKEND_TEST_SRC})
|
||||||
|
target_compile_options(backend_test_linux PRIVATE ${BACKEND_SANITIZERS})
|
||||||
|
target_link_options(backend_test_linux PRIVATE ${BACKEND_SANITIZERS})
|
||||||
target_link_libraries(backend_test_linux PRIVATE ${BACKEND_TEST_LIBS})
|
target_link_libraries(backend_test_linux PRIVATE ${BACKEND_TEST_LIBS})
|
||||||
set_target_properties(backend_test_linux PROPERTIES FOLDER Tests)
|
set_target_properties(backend_test_linux PROPERTIES FOLDER Tests)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <utils/StaticString.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Types and enums used by filament's driver.
|
* Types and enums used by filament's driver.
|
||||||
@@ -1139,6 +1140,7 @@ struct ExternalSamplerDatum {
|
|||||||
static_assert(sizeof(ExternalSamplerDatum) == 12);
|
static_assert(sizeof(ExternalSamplerDatum) == 12);
|
||||||
|
|
||||||
struct DescriptorSetLayout {
|
struct DescriptorSetLayout {
|
||||||
|
std::variant<utils::StaticString, utils::CString, std::monostate> label;
|
||||||
utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings;
|
utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings;
|
||||||
|
|
||||||
// TODO: uncomment when needed
|
// TODO: uncomment when needed
|
||||||
@@ -1455,6 +1457,11 @@ enum class Workaround : uint16_t {
|
|||||||
DISABLE_BLIT_INTO_TEXTURE_ARRAY,
|
DISABLE_BLIT_INTO_TEXTURE_ARRAY,
|
||||||
// Multiple workarounds needed for PowerVR GPUs
|
// Multiple workarounds needed for PowerVR GPUs
|
||||||
POWER_VR_SHADER_WORKAROUNDS,
|
POWER_VR_SHADER_WORKAROUNDS,
|
||||||
|
// Some browsers, such as Firefox on Mac, struggle with slow shader compile/link times when
|
||||||
|
// creating programs for the default material, leading to startup stutters. This workaround
|
||||||
|
// prevents these stutters by not precaching depth variants of the default material for those
|
||||||
|
// particular browsers.
|
||||||
|
DISABLE_DEPTH_PRECACHE_FOR_DEFAULT_MATERIAL,
|
||||||
};
|
};
|
||||||
|
|
||||||
using StereoscopicType = backend::Platform::StereoscopicType;
|
using StereoscopicType = backend::Platform::StereoscopicType;
|
||||||
|
|||||||
@@ -600,6 +600,12 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
|
|||||||
// For Mozilla, the issue appears to be observed regardless of whether the renderer is
|
// For Mozilla, the issue appears to be observed regardless of whether the renderer is
|
||||||
// ANGLE or not. (b/376125497)
|
// ANGLE or not. (b/376125497)
|
||||||
bugs->rebind_buffer_after_deletion = true;
|
bugs->rebind_buffer_after_deletion = true;
|
||||||
|
|
||||||
|
// We disable depth precache for the default material on Mozilla FireFox. It struggles with
|
||||||
|
// slow shader compile/link times if the shader contains large arrays of uniform. Some depth
|
||||||
|
// program variants have skinning-related data, which incurs this slowness and end up
|
||||||
|
// causing an initial startup stalls. (b/392917621)
|
||||||
|
bugs->disable_depth_precache_for_default_material = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BACKEND_OPENGL_VERSION_GLES
|
#ifdef BACKEND_OPENGL_VERSION_GLES
|
||||||
|
|||||||
@@ -328,6 +328,11 @@ public:
|
|||||||
// bugs or performance issues.
|
// bugs or performance issues.
|
||||||
bool force_feature_level0;
|
bool force_feature_level0;
|
||||||
|
|
||||||
|
// Some browsers, such as Firefox on Mac, struggle with slow shader compile/link times when
|
||||||
|
// creating programs for the default material, leading to startup stutters. This workaround
|
||||||
|
// prevents these stutters by not precaching depth variants of the default material for
|
||||||
|
// those particular browsers.
|
||||||
|
bool disable_depth_precache_for_default_material;
|
||||||
|
|
||||||
} bugs = {};
|
} bugs = {};
|
||||||
|
|
||||||
@@ -569,6 +574,9 @@ private:
|
|||||||
{ bugs.force_feature_level0,
|
{ bugs.force_feature_level0,
|
||||||
"force_feature_level0",
|
"force_feature_level0",
|
||||||
""},
|
""},
|
||||||
|
{ bugs.disable_depth_precache_for_default_material,
|
||||||
|
"disable_depth_precache_for_default_material",
|
||||||
|
""},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// this is chosen to minimize code size
|
// this is chosen to minimize code size
|
||||||
|
|||||||
@@ -2435,6 +2435,8 @@ bool OpenGLDriver::isWorkaroundNeeded(Workaround workaround) {
|
|||||||
return mContext.bugs.disable_blit_into_texture_array;
|
return mContext.bugs.disable_blit_into_texture_array;
|
||||||
case Workaround::POWER_VR_SHADER_WORKAROUNDS:
|
case Workaround::POWER_VR_SHADER_WORKAROUNDS:
|
||||||
return mContext.bugs.powervr_shader_workarounds;
|
return mContext.bugs.powervr_shader_workarounds;
|
||||||
|
case Workaround::DISABLE_DEPTH_PRECACHE_FOR_DEFAULT_MATERIAL:
|
||||||
|
return mContext.bugs.disable_depth_precache_for_default_material;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include <webgpu/webgpu_cpp.h>
|
#include <webgpu/webgpu_cpp.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -125,21 +126,64 @@ namespace {
|
|||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is a 1 to 1 mapping of the ReservedSpecializationConstants enum in EngineEnums.h
|
||||||
|
// The _hack is a workaround until https://issues.chromium.org/issues/42250586 is resolved
|
||||||
|
// This workaround is the same one being used on the generateSpecializationConstant() function
|
||||||
|
wgpu::StringView getSpecConstantStringId(uint32_t id) {
|
||||||
|
switch (id) {
|
||||||
|
case 0:
|
||||||
|
return "0";// BACKEND_FEATURE_LEVEL_hack
|
||||||
|
case 1:
|
||||||
|
return "1";// CONFIG_MAX_INSTANCES_hack
|
||||||
|
case 2:
|
||||||
|
return "2";// ONFIG_STATIC_TEXTURE_TARGET_WORKAROUND_hack
|
||||||
|
case 3:
|
||||||
|
return "3";// CONFIG_SRGB_SWAPCHAIN_EMULATION_hack
|
||||||
|
case 4:
|
||||||
|
return "4";// CONFIG_FROXEL_BUFFER_HEIGHT_hack
|
||||||
|
case 5:
|
||||||
|
return "5";// CONFIG_POWER_VR_SHADER_WORKAROUNDS_hack
|
||||||
|
case 6:
|
||||||
|
return "6";// CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP_hack
|
||||||
|
case 7:
|
||||||
|
return "7";// CONFIG_DEBUG_FROXEL_VISUALIZATION_hack
|
||||||
|
case 8:
|
||||||
|
return "8";// CONFIG_STEREO_EYE_COUNT_hack
|
||||||
|
case 9:
|
||||||
|
return "9";// CONFIG_SH_BANDS_COUNT_hack
|
||||||
|
case 10:
|
||||||
|
return "10";// CONFIG_SHADOW_SAMPLING_METHOD_hack
|
||||||
|
default:
|
||||||
|
PANIC_POSTCONDITION("Unknown/unhandled spec constant key/id: %d", id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<wgpu::ConstantEntry> convertConstants(
|
std::vector<wgpu::ConstantEntry> convertConstants(
|
||||||
utils::FixedCapacityVector<filament::backend::Program::SpecializationConstant> const&
|
utils::FixedCapacityVector<filament::backend::Program::SpecializationConstant> const&
|
||||||
constantsInfo) {
|
constantsInfo) {
|
||||||
std::vector<wgpu::ConstantEntry> constants(constantsInfo.size());
|
std::vector<wgpu::ConstantEntry> constants;
|
||||||
for (size_t i = 0; i < constantsInfo.size(); i++) {
|
constants.reserve(constantsInfo.size());
|
||||||
filament::backend::Program::SpecializationConstant const& specConstant = constantsInfo[i];
|
for (filament::backend::Program::SpecializationConstant const& constant: constantsInfo) {
|
||||||
wgpu::ConstantEntry& constantEntry = constants[i];
|
// CONFIG_MAX_INSTANCES (1) and CONFIG_FROXEL_BUFFER_HEIGHT (4) will not be present
|
||||||
constantEntry.key = wgpu::StringView(std::to_string(specConstant.id));
|
// as constant overrides in the generated WGSL, because WGSL doesn't support specialization
|
||||||
if (auto* v = std::get_if<int32_t>(&specConstant.value)) {
|
// constants as an array length
|
||||||
constantEntry.value = static_cast<double>(*v);
|
// More information at https://github.com/gpuweb/gpuweb/issues/572#issuecomment-649760005
|
||||||
} else if (auto* f = std::get_if<float>(&specConstant.value)) {
|
// CONFIG_SRGB_SWAPCHAIN_EMULATION (3) is being skipped all together since it's only
|
||||||
constantEntry.value = static_cast<double>(*f);
|
// included for the case of mFeatureLevel == FeatureLevel::FEATURE_LEVEL_0, which should
|
||||||
} else if (auto* b = std::get_if<bool>(&specConstant.value)) {
|
// not be possible for WebGPU
|
||||||
constantEntry.value = *b ? 0.0 : 1.0;
|
if (constant.id == 1 || constant.id == 3 || constant.id == 4) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
double value = 0.0;
|
||||||
|
if (auto* v = std::get_if<int32_t>(&constant.value)) {
|
||||||
|
value = static_cast<double>(*v);
|
||||||
|
} else if (auto* f = std::get_if<float>(&constant.value)) {
|
||||||
|
value = static_cast<double>(*f);
|
||||||
|
} else if (auto* b = std::get_if<bool>(&constant.value)) {
|
||||||
|
value = *b ? 0.0 : 1.0;
|
||||||
|
}
|
||||||
|
constants.push_back(
|
||||||
|
wgpu::ConstantEntry{ .key = getSpecConstantStringId(constant.id), .value = value });
|
||||||
}
|
}
|
||||||
return constants;
|
return constants;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -292,7 +292,22 @@ void WebGPUDriver::endFrame(uint32_t frameId) {
|
|||||||
void WebGPUDriver::flush(int) {
|
void WebGPUDriver::flush(int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::finish(int) {
|
void WebGPUDriver::finish(int /* dummy */) {
|
||||||
|
if (mCommandEncoder != nullptr) {
|
||||||
|
// submit the command buffer thus far...
|
||||||
|
assert_invariant(mRenderPassEncoder == nullptr);
|
||||||
|
wgpu::CommandBufferDescriptor commandBufferDescriptor{
|
||||||
|
.label = "command_buffer",
|
||||||
|
};
|
||||||
|
mCommandBuffer = mCommandEncoder.Finish(&commandBufferDescriptor);
|
||||||
|
assert_invariant(mCommandBuffer);
|
||||||
|
mQueue.Submit(1, &mCommandBuffer);
|
||||||
|
mCommandBuffer = nullptr;
|
||||||
|
// create a new command buffer encoder to continue recording the next command for frame...
|
||||||
|
wgpu::CommandEncoderDescriptor commandEncoderDescriptor = { .label = "command_encoder" };
|
||||||
|
mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
|
||||||
|
assert_invariant(mCommandEncoder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
void WebGPUDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
||||||
@@ -374,9 +389,7 @@ Handle<HwTexture> WebGPUDriver::createTextureS() noexcept {
|
|||||||
return allocHandle<WGPUTexture>();
|
return allocHandle<WGPUTexture>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::importTextureS() noexcept {
|
Handle<HwTexture> WebGPUDriver::importTextureS() noexcept { return allocHandle<WGPUTexture>(); }
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle<HwProgram> WebGPUDriver::createProgramS() noexcept {
|
Handle<HwProgram> WebGPUDriver::createProgramS() noexcept {
|
||||||
return allocHandle<WGPUProgram>();
|
return allocHandle<WGPUProgram>();
|
||||||
@@ -395,7 +408,7 @@ Handle<HwIndexBuffer> WebGPUDriver::createIndexBufferS() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureViewS() noexcept {
|
Handle<HwTexture> WebGPUDriver::createTextureViewS() noexcept {
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
return allocHandle<WGPUTexture>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwBufferObject> WebGPUDriver::createBufferObjectS() noexcept {
|
Handle<HwBufferObject> WebGPUDriver::createBufferObjectS() noexcept {
|
||||||
@@ -423,7 +436,7 @@ Handle<HwVertexBufferInfo> WebGPUDriver::createVertexBufferInfoS() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureViewSwizzleS() noexcept {
|
Handle<HwTexture> WebGPUDriver::createTextureViewSwizzleS() noexcept {
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
return allocHandle<WGPUTexture>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwRenderTarget> WebGPUDriver::createDefaultRenderTargetS() noexcept {
|
Handle<HwRenderTarget> WebGPUDriver::createDefaultRenderTargetS() noexcept {
|
||||||
@@ -435,15 +448,15 @@ Handle<HwDescriptorSetLayout> WebGPUDriver::createDescriptorSetLayoutS() noexcep
|
|||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureExternalImageS() noexcept {
|
Handle<HwTexture> WebGPUDriver::createTextureExternalImageS() noexcept {
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
return allocHandle<WGPUTexture>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureExternalImage2S() noexcept {
|
Handle<HwTexture> WebGPUDriver::createTextureExternalImage2S() noexcept {
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
return allocHandle<WGPUTexture>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwTexture> WebGPUDriver::createTextureExternalImagePlaneS() noexcept {
|
Handle<HwTexture> WebGPUDriver::createTextureExternalImagePlaneS() noexcept {
|
||||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
return allocHandle<WGPUTexture>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
|
void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
|
||||||
@@ -455,6 +468,8 @@ void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
|
|||||||
mSwapChain = constructHandle<WebGPUSwapChain>(sch, std::move(surface), surfaceSize, mAdapter,
|
mSwapChain = constructHandle<WebGPUSwapChain>(sch, std::move(surface), surfaceSize, mAdapter,
|
||||||
mDevice, flags);
|
mDevice, flags);
|
||||||
assert_invariant(mSwapChain);
|
assert_invariant(mSwapChain);
|
||||||
|
WebGPUDescriptorSet::initializeDummyResourcesIfNotAlready(mDevice,
|
||||||
|
mSwapChain->getColorFormat());
|
||||||
FWGPU_LOGW << "WebGPU support is still essentially a no-op at this point in development (only "
|
FWGPU_LOGW << "WebGPU support is still essentially a no-op at this point in development (only "
|
||||||
"background components have been instantiated/selected, such as surface/screen, "
|
"background components have been instantiated/selected, such as surface/screen, "
|
||||||
"graphics device/GPU, etc.), thus nothing is being drawn to the screen."
|
"graphics device/GPU, etc.), thus nothing is being drawn to the screen."
|
||||||
@@ -497,30 +512,46 @@ void WebGPUDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byte
|
|||||||
|
|
||||||
void WebGPUDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
void WebGPUDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
||||||
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
|
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
|
||||||
TextureUsage usage) {}
|
TextureUsage usage) {
|
||||||
|
constructHandle<WGPUTexture>(th, target, levels, format, samples, w, h, depth, usage, mDevice);
|
||||||
|
}
|
||||||
|
|
||||||
void WebGPUDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
void WebGPUDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||||
uint8_t baseLevel, uint8_t levelCount) {}
|
uint8_t baseLevel, uint8_t levelCount) {
|
||||||
|
auto source = handleCast<WGPUTexture>(srch);
|
||||||
|
|
||||||
|
constructHandle<WGPUTexture>(th, source, baseLevel, levelCount);
|
||||||
|
}
|
||||||
|
|
||||||
void WebGPUDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
void WebGPUDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||||
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
|
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
|
||||||
backend::TextureSwizzle a) {}
|
backend::TextureSwizzle a) {
|
||||||
|
PANIC_POSTCONDITION("Swizzle WebGPU Texture is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
void WebGPUDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::SamplerType target,
|
void WebGPUDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::SamplerType target,
|
||||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||||
Platform::ExternalImageHandleRef externalImage) {}
|
Platform::ExternalImageHandleRef externalImage) {
|
||||||
|
PANIC_POSTCONDITION("External WebGPU Texture is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
void WebGPUDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
|
void WebGPUDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
|
||||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||||
void* externalImage) {}
|
void* externalImage) {
|
||||||
|
PANIC_POSTCONDITION("External WebGPU Texture is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
void WebGPUDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
void WebGPUDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
||||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||||
void* image, uint32_t plane) {}
|
void* image, uint32_t plane) {
|
||||||
|
PANIC_POSTCONDITION("External WebGPU Texture is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
void WebGPUDriver::importTextureR(Handle<HwTexture> th, intptr_t id, SamplerType target,
|
void WebGPUDriver::importTextureR(Handle<HwTexture> th, intptr_t id, SamplerType target,
|
||||||
uint8_t levels, TextureFormat format, uint8_t samples, uint32_t w, uint32_t h,
|
uint8_t levels, TextureFormat format, uint8_t samples, uint32_t w, uint32_t h,
|
||||||
uint32_t depth, TextureUsage usage) {}
|
uint32_t depth, TextureUsage usage) {
|
||||||
|
PANIC_POSTCONDITION("Import WebGPU Texture is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
void WebGPUDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph, Handle<HwVertexBuffer> vbh,
|
void WebGPUDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph, Handle<HwVertexBuffer> vbh,
|
||||||
Handle<HwIndexBuffer> ibh, PrimitiveType pt) {
|
Handle<HwIndexBuffer> ibh, PrimitiveType pt) {
|
||||||
@@ -560,7 +591,7 @@ void WebGPUDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh
|
|||||||
void WebGPUDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
|
void WebGPUDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
|
||||||
Handle<HwDescriptorSetLayout> dslh) {
|
Handle<HwDescriptorSetLayout> dslh) {
|
||||||
auto layout = handleCast<WebGPUDescriptorSetLayout>(dslh);
|
auto layout = handleCast<WebGPUDescriptorSetLayout>(dslh);
|
||||||
constructHandle<WebGPUDescriptorSet>(dsh, layout->getLayout(), layout->getLayoutSize());
|
constructHandle<WebGPUDescriptorSet>(dsh, layout->getLayout(), layout->getBindGroupEntries());
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<HwStream> WebGPUDriver::createStreamNative(void* nativeStream) {
|
Handle<HwStream> WebGPUDriver::createStreamNative(void* nativeStream) {
|
||||||
@@ -597,7 +628,7 @@ FenceStatus WebGPUDriver::getFenceStatus(Handle<HwFence> fh) {
|
|||||||
// We create all textures using VK_IMAGE_TILING_OPTIMAL, so our definition of "supported" is that
|
// We create all textures using VK_IMAGE_TILING_OPTIMAL, so our definition of "supported" is that
|
||||||
// the GPU supports the given texture format with non-zero optimal tiling features.
|
// the GPU supports the given texture format with non-zero optimal tiling features.
|
||||||
bool WebGPUDriver::isTextureFormatSupported(TextureFormat format) {
|
bool WebGPUDriver::isTextureFormatSupported(TextureFormat format) {
|
||||||
return true;
|
return WGPUTexture::fToWGPUTextureFormat(format) != wgpu::TextureFormat::Undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebGPUDriver::isTextureSwizzleSupported() {
|
bool WebGPUDriver::isTextureSwizzleSupported() {
|
||||||
@@ -745,13 +776,31 @@ void WebGPUDriver::compilePrograms(CompilerPriorityQueue priority,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassParams& params) {
|
void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> rth, RenderPassParams const& params) {
|
||||||
wgpu::CommandEncoderDescriptor commandEncoderDescriptor = {
|
|
||||||
.label = "command_encoder"
|
|
||||||
};
|
|
||||||
mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
|
|
||||||
assert_invariant(mCommandEncoder);
|
assert_invariant(mCommandEncoder);
|
||||||
|
|
||||||
|
auto* renderTarget = handleCast<WGPURenderTarget>(rth);
|
||||||
|
// if (renderTarget == mDefaultRenderTarget) {
|
||||||
|
// FWGPU_LOGW << "Default render target"
|
||||||
|
// << utils::io::endl;
|
||||||
|
// } else {
|
||||||
|
// FWGPU_LOGW << "Non Default render target"
|
||||||
|
// << utils::io::endl;
|
||||||
|
// }
|
||||||
|
wgpu::RenderPassDescriptor renderPassDescriptor2;
|
||||||
|
wgpu::RenderPassDepthStencilAttachment depthStencilAttachment{
|
||||||
|
.view = mSwapChain->getDepthTextureView(),
|
||||||
|
.depthLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::DEPTH),
|
||||||
|
.depthStoreOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::DEPTH),
|
||||||
|
.depthClearValue = static_cast<float>(params.clearDepth),
|
||||||
|
.depthReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH) > 0,
|
||||||
|
.stencilLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::STENCIL),
|
||||||
|
.stencilStoreOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::STENCIL),
|
||||||
|
.stencilClearValue = params.clearStencil,
|
||||||
|
.stencilReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_STENCIL) > 0
|
||||||
|
};
|
||||||
|
renderTarget->setUpRenderPassAttachments(renderPassDescriptor2, mTextureView, params);
|
||||||
|
renderPassDescriptor2.depthStencilAttachment = &depthStencilAttachment;
|
||||||
// TODO: Remove this code once WebGPU pipeline is implemented
|
// TODO: Remove this code once WebGPU pipeline is implemented
|
||||||
static float red = 1.0f;
|
static float red = 1.0f;
|
||||||
if (red - 0.01 > 0) {
|
if (red - 0.01 > 0) {
|
||||||
@@ -776,19 +825,14 @@ void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
|||||||
.timestampWrites = nullptr,
|
.timestampWrites = nullptr,
|
||||||
};
|
};
|
||||||
|
|
||||||
mRenderPassEncoder = mCommandEncoder.BeginRenderPass(&renderPassDescriptor);
|
mRenderPassEncoder = mCommandEncoder.BeginRenderPass(&renderPassDescriptor2);
|
||||||
mRenderPassEncoder.SetViewport(params.viewport.left, params.viewport.bottom,
|
mRenderPassEncoder.SetViewport(params.viewport.left, params.viewport.bottom,
|
||||||
params.viewport.width, params.viewport.height, params.depthRange.near, params.depthRange.far);
|
params.viewport.width, params.viewport.height, params.depthRange.near, params.depthRange.far);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::endRenderPass(int) {
|
void WebGPUDriver::endRenderPass(int /* dummy */) {
|
||||||
mRenderPassEncoder.End();
|
mRenderPassEncoder.End();
|
||||||
mRenderPassEncoder = nullptr;
|
mRenderPassEncoder = nullptr;
|
||||||
wgpu::CommandBufferDescriptor commandBufferDescriptor {
|
|
||||||
.label = "command_buffer",
|
|
||||||
};
|
|
||||||
mCommandBuffer = mCommandEncoder.Finish(&commandBufferDescriptor);
|
|
||||||
assert_invariant(mCommandBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::nextSubpass(int) {
|
void WebGPUDriver::nextSubpass(int) {
|
||||||
@@ -803,9 +847,19 @@ void WebGPUDriver::makeCurrent(Handle<HwSwapChain> drawSch, Handle<HwSwapChain>
|
|||||||
wgpu::Extent2D surfaceSize = mPlatform.getSurfaceExtent(mNativeWindow);
|
wgpu::Extent2D surfaceSize = mPlatform.getSurfaceExtent(mNativeWindow);
|
||||||
mTextureView = mSwapChain->getCurrentSurfaceTextureView(surfaceSize);
|
mTextureView = mSwapChain->getCurrentSurfaceTextureView(surfaceSize);
|
||||||
assert_invariant(mTextureView);
|
assert_invariant(mTextureView);
|
||||||
|
wgpu::CommandEncoderDescriptor commandEncoderDescriptor = {
|
||||||
|
.label = "command_encoder"
|
||||||
|
};
|
||||||
|
mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
|
||||||
|
assert_invariant(mCommandEncoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::commit(Handle<HwSwapChain> sch) {
|
void WebGPUDriver::commit(Handle<HwSwapChain> sch) {
|
||||||
|
wgpu::CommandBufferDescriptor commandBufferDescriptor{
|
||||||
|
.label = "command_buffer",
|
||||||
|
};
|
||||||
|
mCommandBuffer = mCommandEncoder.Finish(&commandBufferDescriptor);
|
||||||
|
assert_invariant(mCommandBuffer);
|
||||||
mCommandEncoder = nullptr;
|
mCommandEncoder = nullptr;
|
||||||
mQueue.Submit(1, &mCommandBuffer);
|
mQueue.Submit(1, &mCommandBuffer);
|
||||||
mCommandBuffer = nullptr;
|
mCommandBuffer = nullptr;
|
||||||
@@ -899,7 +953,7 @@ void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
|
|||||||
pipelineState.polygonOffset, pipelineState.primitiveType, mSwapChain->getColorFormat(),
|
pipelineState.polygonOffset, pipelineState.primitiveType, mSwapChain->getColorFormat(),
|
||||||
mSwapChain->getDepthFormat());
|
mSwapChain->getDepthFormat());
|
||||||
// TODO: uncomment once we have a valid pipeline to set
|
// TODO: uncomment once we have a valid pipeline to set
|
||||||
// mRenderPassEncoder.SetPipeline(pipeline);
|
mRenderPassEncoder.SetPipeline(pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
void WebGPUDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
||||||
@@ -919,10 +973,18 @@ void WebGPUDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
|
void WebGPUDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
|
||||||
|
// Calling DrawIndexed with "firstInstance = 0" results in a NON spinning triangle
|
||||||
|
// mRenderPassEncoder.DrawIndexed(indexCount, instanceCount, indexOffset, 0, 0);
|
||||||
|
// Calling DrawIndexed with "firstInstance = 1" results in a spinning triangle
|
||||||
|
mRenderPassEncoder.DrawIndexed(indexCount, instanceCount, indexOffset, 0, 1);
|
||||||
|
// Calling Draw with "firstInstance = 0" results in a NON spinning triangle
|
||||||
|
// Calling Draw with "firstInstance = 1" results in a spinning triangle
|
||||||
|
// mRenderPassEncoder.Draw(indexCount, instanceCount, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::draw(PipelineState pipelineState, Handle<HwRenderPrimitive> rph,
|
void WebGPUDriver::draw(PipelineState, Handle<HwRenderPrimitive>, uint32_t indexOffset,
|
||||||
uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
|
uint32_t indexCount, uint32_t instanceCount) {
|
||||||
|
draw2(indexOffset, indexCount, instanceCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGroupCount) {
|
void WebGPUDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGroupCount) {
|
||||||
@@ -958,34 +1020,156 @@ void WebGPUDriver::updateDescriptorSetBuffer(Handle<HwDescriptorSet> dsh,
|
|||||||
|
|
||||||
void WebGPUDriver::updateDescriptorSetTexture(Handle<HwDescriptorSet> dsh,
|
void WebGPUDriver::updateDescriptorSetTexture(Handle<HwDescriptorSet> dsh,
|
||||||
backend::descriptor_binding_t binding, Handle<HwTexture> th, SamplerParams params) {
|
backend::descriptor_binding_t binding, Handle<HwTexture> th, SamplerParams params) {
|
||||||
/*
|
|
||||||
auto bindGroup = handleCast<WebGPUDescriptorSet>(dsh);
|
auto bindGroup = handleCast<WebGPUDescriptorSet>(dsh);
|
||||||
auto texture = handleCast<WGPUTexture>(th);
|
auto texture = handleCast<WGPUTexture>(th);
|
||||||
|
|
||||||
// TODO very high odds badd assumptions are in here about handling HwTexture. Revisit with more
|
|
||||||
// understanding. Right now assuming there is a wgpu::TextureView filled in
|
|
||||||
if (!bindGroup->getIsLocked()) {
|
if (!bindGroup->getIsLocked()) {
|
||||||
|
// Dawn will cache duplicate samplers, so we don't strictly need to maintain a cache.
|
||||||
|
// Making a cache might save us minor perf by reducing param translation
|
||||||
|
auto sampler = makeSampler(params);
|
||||||
// TODO making assumptions that size and offset mean the same thing here.
|
// TODO making assumptions that size and offset mean the same thing here.
|
||||||
wgpu::BindGroupEntry tEntry{ .binding = static_cast<uint32_t>(binding * 2),
|
wgpu::BindGroupEntry tEntry{ .binding = static_cast<uint32_t>(binding * 2),
|
||||||
.textureView = texture->texView };
|
.textureView = texture->getTexView() };
|
||||||
bindGroup->addEntry(tEntry.binding, std::move(tEntry));
|
bindGroup->addEntry(tEntry.binding, std::move(tEntry));
|
||||||
|
|
||||||
wgpu::BindGroupEntry sEntry{ .binding = static_cast<uint32_t>(binding * 2 + 1),
|
wgpu::BindGroupEntry sEntry{ .binding = static_cast<uint32_t>(binding * 2 + 1),
|
||||||
.sampler = texture->sampler };
|
.sampler = sampler };
|
||||||
bindGroup->addEntry(sEntry.binding, std::move(sEntry));
|
bindGroup->addEntry(sEntry.binding, std::move(sEntry));
|
||||||
}
|
}
|
||||||
//TODO Just the setup, this function stilll needs the rest of logic implemented
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::bindDescriptorSet(Handle<HwDescriptorSet> dsh, backend::descriptor_set_t set,
|
void WebGPUDriver::bindDescriptorSet(Handle<HwDescriptorSet> dsh,
|
||||||
backend::DescriptorSetOffsetArray&& offsets) {
|
backend::descriptor_set_t setIndex, backend::DescriptorSetOffsetArray&& offsets) {
|
||||||
auto bindGroup = handleCast<WebGPUDescriptorSet>(dsh);
|
const auto bindGroup = handleCast<WebGPUDescriptorSet>(dsh);
|
||||||
// TODO: presume we need this, use it. Probably Encoder::SetBindGroup
|
const auto wbg = bindGroup->lockAndReturn(mDevice);
|
||||||
auto wbg = bindGroup->lockAndReturn(mDevice);
|
assert_invariant(mRenderPassEncoder);
|
||||||
|
// TODO is this how we should be getting the dynamic offsets?
|
||||||
|
// should we add offsets for unused entries or is the input already have them?
|
||||||
|
// this implementation assumes unused entries are not provided, and adds dummy values.
|
||||||
|
// The count also includes unused entities, as not doing so produces errors
|
||||||
|
const size_t dynamicOffsetCount = bindGroup->countEntitiesWithDynamicOffsets();
|
||||||
|
uint32_t const* const dynamicOffsetsWithUnused = bindGroup->setDynamicOffsets(offsets.data());
|
||||||
|
mRenderPassEncoder.SetBindGroup(setIndex, wbg, dynamicOffsetCount, dynamicOffsetsWithUnused);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
|
void WebGPUDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
|
||||||
}
|
}
|
||||||
|
wgpu::Sampler WebGPUDriver::makeSampler(SamplerParams const& params) {
|
||||||
|
wgpu::SamplerDescriptor desc;
|
||||||
|
|
||||||
|
desc.label = "TODO";
|
||||||
|
desc.addressModeU = fWrapModeToWAddressMode(params.wrapS);
|
||||||
|
desc.addressModeV = fWrapModeToWAddressMode(params.wrapR);
|
||||||
|
desc.addressModeW = fWrapModeToWAddressMode(params.wrapT);
|
||||||
|
switch (params.filterMag) {
|
||||||
|
case SamplerMagFilter::NEAREST: {
|
||||||
|
desc.magFilter = wgpu::FilterMode::Nearest;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SamplerMagFilter::LINEAR: {
|
||||||
|
desc.magFilter = wgpu::FilterMode::Linear;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (params.filterMin) {
|
||||||
|
case SamplerMinFilter::NEAREST: {
|
||||||
|
desc.minFilter = wgpu::FilterMode::Nearest;
|
||||||
|
// Metal Driver uses an explicit not-mipmapped value webgpu lacks. Nearest should
|
||||||
|
// suffice
|
||||||
|
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SamplerMinFilter::LINEAR: {
|
||||||
|
desc.minFilter = wgpu::FilterMode::Linear;
|
||||||
|
// Metal Driver uses an explicit not-mipmapped value webgpu lacks. Nearest should
|
||||||
|
// suffice
|
||||||
|
|
||||||
|
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST: {
|
||||||
|
desc.minFilter = wgpu::FilterMode::Nearest;
|
||||||
|
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST: {
|
||||||
|
desc.minFilter = wgpu::FilterMode::Linear;
|
||||||
|
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR: {
|
||||||
|
desc.minFilter = wgpu::FilterMode::Nearest;
|
||||||
|
desc.mipmapFilter = wgpu::MipmapFilterMode::Linear;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR: {
|
||||||
|
desc.minFilter = wgpu::FilterMode::Linear;
|
||||||
|
desc.mipmapFilter = wgpu::MipmapFilterMode::Linear;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (params.compareFunc) {
|
||||||
|
case SamplerCompareFunc::LE: {
|
||||||
|
desc.compare = wgpu::CompareFunction::LessEqual;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SamplerCompareFunc::GE: {
|
||||||
|
desc.compare = wgpu::CompareFunction::GreaterEqual;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SamplerCompareFunc::L: {
|
||||||
|
desc.compare = wgpu::CompareFunction::Less;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SamplerCompareFunc::G: {
|
||||||
|
desc.compare = wgpu::CompareFunction::Greater;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SamplerCompareFunc::E: {
|
||||||
|
desc.compare = wgpu::CompareFunction::Equal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SamplerCompareFunc::NE: {
|
||||||
|
desc.compare = wgpu::CompareFunction::NotEqual;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SamplerCompareFunc::A: {
|
||||||
|
desc.compare = wgpu::CompareFunction::Always;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SamplerCompareFunc::N: {
|
||||||
|
desc.compare = wgpu::CompareFunction::Never;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
desc.maxAnisotropy = 1u << params.anisotropyLog2;
|
||||||
|
|
||||||
|
|
||||||
|
// Unused: Filament's compareMode, WGPU lodMinClamp/lodMaxClamp
|
||||||
|
|
||||||
|
//TODO Once we can properly map to descriptorsetlayout use the sampler.
|
||||||
|
return mDevice.CreateSampler(/*&desc*/);
|
||||||
|
}
|
||||||
|
wgpu::AddressMode WebGPUDriver::fWrapModeToWAddressMode(const SamplerWrapMode& fWrapMode) {
|
||||||
|
switch (fWrapMode) {
|
||||||
|
case SamplerWrapMode::CLAMP_TO_EDGE: {
|
||||||
|
return wgpu::AddressMode::ClampToEdge;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SamplerWrapMode::REPEAT: {
|
||||||
|
return wgpu::AddressMode::Repeat;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SamplerWrapMode::MIRRORED_REPEAT: {
|
||||||
|
return wgpu::AddressMode::MirrorRepeat;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wgpu::AddressMode::Undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace filament
|
} // namespace filament
|
||||||
|
|||||||
@@ -56,7 +56,8 @@ private:
|
|||||||
explicit WebGPUDriver(WebGPUPlatform& platform, const Platform::DriverConfig& driverConfig) noexcept;
|
explicit WebGPUDriver(WebGPUPlatform& platform, const Platform::DriverConfig& driverConfig) noexcept;
|
||||||
[[nodiscard]] ShaderModel getShaderModel() const noexcept final;
|
[[nodiscard]] ShaderModel getShaderModel() const noexcept final;
|
||||||
[[nodiscard]] ShaderLanguage getShaderLanguage() const noexcept final;
|
[[nodiscard]] ShaderLanguage getShaderLanguage() const noexcept final;
|
||||||
|
[[nodiscard]] wgpu::Sampler makeSampler(SamplerParams const& params);
|
||||||
|
[[nodiscard]] static wgpu::AddressMode fWrapModeToWAddressMode(const filament::backend::SamplerWrapMode& fUsage);
|
||||||
template<typename GPUBufferObject>
|
template<typename GPUBufferObject>
|
||||||
void updateGPUBuffer(GPUBufferObject* gpuBufferObject, BufferDescriptor&& bufferDescriptor,
|
void updateGPUBuffer(GPUBufferObject* gpuBufferObject, BufferDescriptor&& bufferDescriptor,
|
||||||
uint32_t byteOffset) {
|
uint32_t byteOffset) {
|
||||||
|
|||||||
@@ -16,7 +16,16 @@
|
|||||||
|
|
||||||
#include "WebGPUHandles.h"
|
#include "WebGPUHandles.h"
|
||||||
|
|
||||||
|
#include <backend/DriverEnums.h>
|
||||||
|
|
||||||
|
#include <utils/BitmaskEnum.h>
|
||||||
|
|
||||||
|
#include <webgpu/webgpu_cpp.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdint>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr wgpu::BufferUsage getBufferObjectUsage(
|
constexpr wgpu::BufferUsage getBufferObjectUsage(
|
||||||
@@ -110,6 +119,44 @@ wgpu::VertexFormat getVertexFormat(filament::backend::ElementType type, bool nor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wgpu::StringView getUserTextureLabel(filament::backend::SamplerType target) {
|
||||||
|
// TODO will be helpful to get more useful info than this
|
||||||
|
using filament::backend::SamplerType;
|
||||||
|
switch (target) {
|
||||||
|
case SamplerType::SAMPLER_2D:
|
||||||
|
return "a_2D_user_texture";
|
||||||
|
case SamplerType::SAMPLER_2D_ARRAY:
|
||||||
|
return "a_2D_array_user_texture";
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP:
|
||||||
|
return "a_cube_map_user_texture";
|
||||||
|
case SamplerType::SAMPLER_EXTERNAL:
|
||||||
|
return "an_external_user_texture";
|
||||||
|
case SamplerType::SAMPLER_3D:
|
||||||
|
return "a_3D_user_texture";
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||||
|
return "a_cube_mape_array_user_texture";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::StringView getUserTextureViewLabel(filament::backend::SamplerType target) {
|
||||||
|
// TODO will be helpful to get more useful info than this
|
||||||
|
using filament::backend::SamplerType;
|
||||||
|
switch (target) {
|
||||||
|
case SamplerType::SAMPLER_2D:
|
||||||
|
return "a_2D_user_texture_view";
|
||||||
|
case SamplerType::SAMPLER_2D_ARRAY:
|
||||||
|
return "a_2D_array_user_texture_view";
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP:
|
||||||
|
return "a_cube_map_user_texture_view";
|
||||||
|
case SamplerType::SAMPLER_EXTERNAL:
|
||||||
|
return "an_external_user_texture_view";
|
||||||
|
case SamplerType::SAMPLER_3D:
|
||||||
|
return "a_3D_user_texture_view";
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||||
|
return "a_cube_mape_array_user_texture_view";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}// namespace
|
}// namespace
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
@@ -137,7 +184,7 @@ WGPUVertexBufferInfo::WGPUVertexBufferInfo(uint8_t bufferCount, uint8_t attribut
|
|||||||
mAttributes[attrib.buffer].push_back({
|
mAttributes[attrib.buffer].push_back({
|
||||||
.format = vertexFormat,
|
.format = vertexFormat,
|
||||||
.offset = attrib.offset,
|
.offset = attrib.offset,
|
||||||
.shaderLocation = static_cast<uint32_t>(mAttributes[attrib.buffer].size()),
|
.shaderLocation = attribIndex,
|
||||||
});
|
});
|
||||||
|
|
||||||
mVertexBufferLayout[attrib.buffer].stepMode = wgpu::VertexStepMode::Vertex;
|
mVertexBufferLayout[attrib.buffer].stepMode = wgpu::VertexStepMode::Vertex;
|
||||||
@@ -192,11 +239,20 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
|
|||||||
wgpu::Device const& device) {
|
wgpu::Device const& device) {
|
||||||
assert_invariant(device);
|
assert_invariant(device);
|
||||||
|
|
||||||
|
std::string baseLabel;
|
||||||
|
if (std::holds_alternative<utils::StaticString>(layout.label)) {
|
||||||
|
const auto& temp = std::get_if<utils::StaticString>(&layout.label);
|
||||||
|
baseLabel = temp->c_str();
|
||||||
|
} else if (std::holds_alternative<utils::CString>(layout.label)) {
|
||||||
|
const auto& temp = std::get_if<utils::CString>(&layout.label);
|
||||||
|
baseLabel = temp->c_str();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: layoutDescriptor has a "Label". Ideally we can get info on what this layout is for
|
// TODO: layoutDescriptor has a "Label". Ideally we can get info on what this layout is for
|
||||||
// debugging. For now, hack an incrementing value.
|
// debugging. For now, hack an incrementing value.
|
||||||
static int layoutNum = 0;
|
static int layoutNum = 0;
|
||||||
|
|
||||||
uint samplerCount =
|
unsigned int samplerCount =
|
||||||
std::count_if(layout.bindings.begin(), layout.bindings.end(), [](auto& fEntry) {
|
std::count_if(layout.bindings.begin(), layout.bindings.end(), [](auto& fEntry) {
|
||||||
return fEntry.type == DescriptorType::SAMPLER ||
|
return fEntry.type == DescriptorType::SAMPLER ||
|
||||||
fEntry.type == DescriptorType::SAMPLER_EXTERNAL;
|
fEntry.type == DescriptorType::SAMPLER_EXTERNAL;
|
||||||
@@ -205,86 +261,204 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
|
|||||||
|
|
||||||
std::vector<wgpu::BindGroupLayoutEntry> wEntries;
|
std::vector<wgpu::BindGroupLayoutEntry> wEntries;
|
||||||
wEntries.reserve(layout.bindings.size() + samplerCount);
|
wEntries.reserve(layout.bindings.size() + samplerCount);
|
||||||
|
mBindGroupEntries.reserve(wEntries.capacity());
|
||||||
|
|
||||||
for (auto fEntry: layout.bindings) {
|
for (auto fEntry: layout.bindings) {
|
||||||
auto& wEntry = wEntries.emplace_back();
|
auto& wEntry = wEntries.emplace_back();
|
||||||
|
auto& entryInfo = mBindGroupEntries.emplace_back();
|
||||||
wEntry.visibility = filamentStageToWGPUStage(fEntry.stageFlags);
|
wEntry.visibility = filamentStageToWGPUStage(fEntry.stageFlags);
|
||||||
wEntry.binding = fEntry.binding * 2;
|
wEntry.binding = fEntry.binding * 2;
|
||||||
|
entryInfo.binding = wEntry.binding;
|
||||||
|
|
||||||
switch (fEntry.type) {
|
switch (fEntry.type) {
|
||||||
// TODO Metal treats these the same. Is this fine?
|
|
||||||
case DescriptorType::SAMPLER_EXTERNAL:
|
case DescriptorType::SAMPLER_EXTERNAL:
|
||||||
case DescriptorType::SAMPLER: {
|
case DescriptorType::SAMPLER: {
|
||||||
// Sampler binding is 2n+1 due to split.
|
|
||||||
auto& samplerEntry = wEntries.emplace_back();
|
auto& samplerEntry = wEntries.emplace_back();
|
||||||
|
auto& samplerEntryInfo = mBindGroupEntries.emplace_back();
|
||||||
samplerEntry.binding = fEntry.binding * 2 + 1;
|
samplerEntry.binding = fEntry.binding * 2 + 1;
|
||||||
|
samplerEntryInfo.binding = samplerEntry.binding;
|
||||||
|
samplerEntryInfo.type = WebGPUDescriptorSetLayout::BindGroupEntryType::SAMPLER;
|
||||||
samplerEntry.visibility = wEntry.visibility;
|
samplerEntry.visibility = wEntry.visibility;
|
||||||
// We are simply hoping that undefined and defaults suffices here.
|
// We are simply hoping that undefined and defaults suffices here.
|
||||||
samplerEntry.sampler.type = wgpu::SamplerBindingType::Undefined;
|
samplerEntry.sampler.type = wgpu::SamplerBindingType::NonFiltering; // Example default
|
||||||
wEntry.texture.sampleType = wgpu::TextureSampleType::Undefined;
|
wEntry.texture.sampleType = wgpu::TextureSampleType::Float; // Example default
|
||||||
|
// TODO: FIX! THIS IS HACK FOR HELLO-TRIANGLE!
|
||||||
|
if (baseLabel.find("Skybox") != std::string::npos ||
|
||||||
|
(baseLabel == "Filament Default Material_perView" && wEntry.binding == 22)) {
|
||||||
|
wEntry.texture.viewDimension = wgpu::TextureViewDimension::Cube;
|
||||||
|
} else {
|
||||||
|
wEntry.texture.viewDimension =
|
||||||
|
wgpu::TextureViewDimension::e2D;// Example default
|
||||||
|
}
|
||||||
|
entryInfo.type = WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DescriptorType::UNIFORM_BUFFER: {
|
case DescriptorType::UNIFORM_BUFFER: {
|
||||||
wEntry.buffer.hasDynamicOffset =
|
wEntry.buffer.hasDynamicOffset =
|
||||||
any(fEntry.flags & DescriptorFlags::DYNAMIC_OFFSET);
|
any(fEntry.flags & DescriptorFlags::DYNAMIC_OFFSET);
|
||||||
|
entryInfo.hasDynamicOffset = wEntry.buffer.hasDynamicOffset;
|
||||||
wEntry.buffer.type = wgpu::BufferBindingType::Uniform;
|
wEntry.buffer.type = wgpu::BufferBindingType::Uniform;
|
||||||
// TODO: Ideally we fill minBindingSize
|
// TODO: Ideally we fill minBindingSize
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DescriptorType::INPUT_ATTACHMENT: {
|
case DescriptorType::INPUT_ATTACHMENT: {
|
||||||
// TODO: support INPUT_ATTACHMENT. Metal does not currently.
|
|
||||||
PANIC_POSTCONDITION("Input Attachment is not supported");
|
PANIC_POSTCONDITION("Input Attachment is not supported");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DescriptorType::SHADER_STORAGE_BUFFER: {
|
case DescriptorType::SHADER_STORAGE_BUFFER: {
|
||||||
// TODO: Vulkan does not support this, can we?
|
|
||||||
PANIC_POSTCONDITION("Shader storage is not supported");
|
PANIC_POSTCONDITION("Shader storage is not supported");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// fEntry.count is unused currently
|
||||||
// Currently flags are only used to specify dynamic offset.
|
|
||||||
|
|
||||||
// UNUSED
|
|
||||||
// fEntry.count
|
|
||||||
}
|
}
|
||||||
|
std::string label = "layout_" + baseLabel + std::to_string(++layoutNum) ;
|
||||||
wgpu::BindGroupLayoutDescriptor layoutDescriptor{
|
wgpu::BindGroupLayoutDescriptor layoutDescriptor{
|
||||||
// TODO: layoutDescriptor has a "Label". Ideally we can get info on what this layout is for
|
.label{label.c_str()}, // Use .c_str() if label needs to be const char*
|
||||||
// debugging. For now, hack an incrementing value.
|
|
||||||
.label{ "layout_" + std::to_string(++layoutNum) },
|
|
||||||
.entryCount = wEntries.size(),
|
.entryCount = wEntries.size(),
|
||||||
.entries = wEntries.data()
|
.entries = wEntries.data()
|
||||||
};
|
};
|
||||||
// TODO Do we need to defer this until we have more info on textures and samplers??
|
|
||||||
mLayoutSize = wEntries.size();
|
|
||||||
mLayout = device.CreateBindGroupLayout(&layoutDescriptor);
|
mLayout = device.CreateBindGroupLayout(&layoutDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
WebGPUDescriptorSetLayout::~WebGPUDescriptorSetLayout() {}
|
WebGPUDescriptorSetLayout::~WebGPUDescriptorSetLayout() {}
|
||||||
|
|
||||||
WebGPUDescriptorSet::WebGPUDescriptorSet(const wgpu::BindGroupLayout& layout, uint layoutSize)
|
wgpu::Buffer WebGPUDescriptorSet::sDummyUniformBuffer = nullptr;
|
||||||
|
wgpu::Texture WebGPUDescriptorSet::sDummyTexture = nullptr;
|
||||||
|
wgpu::TextureView WebGPUDescriptorSet::sDummyTextureView = nullptr;
|
||||||
|
wgpu::Sampler WebGPUDescriptorSet::sDummySampler = nullptr;
|
||||||
|
|
||||||
|
void WebGPUDescriptorSet::initializeDummyResourcesIfNotAlready(wgpu::Device const& device,
|
||||||
|
wgpu::TextureFormat aColorFormat) {
|
||||||
|
if (!sDummyUniformBuffer) {
|
||||||
|
wgpu::BufferDescriptor bufferDescriptor{
|
||||||
|
.label = "dummy_uniform_not_to_be_used",
|
||||||
|
.usage = wgpu::BufferUsage::Uniform,
|
||||||
|
.size = 4
|
||||||
|
};
|
||||||
|
sDummyUniformBuffer = device.CreateBuffer(&bufferDescriptor);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer)
|
||||||
|
<< "Failed to create dummy uniform buffer?";
|
||||||
|
}
|
||||||
|
if (!sDummyTexture || !sDummyTextureView) {
|
||||||
|
wgpu::TextureDescriptor textureDescriptor{
|
||||||
|
.label = "dummy_texture_not_to_be_used",
|
||||||
|
.usage = wgpu::TextureUsage::TextureBinding,
|
||||||
|
.dimension = wgpu::TextureDimension::e2D,
|
||||||
|
.size = wgpu::Extent3D{ .width = 4, .height = 4, .depthOrArrayLayers = 1 },
|
||||||
|
.format = aColorFormat,
|
||||||
|
};
|
||||||
|
if (!sDummyTexture) {
|
||||||
|
sDummyTexture = device.CreateTexture(&textureDescriptor);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer) << "Failed to create dummy texture?";
|
||||||
|
}
|
||||||
|
if (!sDummyTextureView) {
|
||||||
|
wgpu::TextureViewDescriptor textureViewDescriptor{
|
||||||
|
.label = "dummy_texture_view_not_to_be_used"
|
||||||
|
};
|
||||||
|
sDummyTextureView = sDummyTexture.CreateView(&textureViewDescriptor);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer)
|
||||||
|
<< "Failed to create dummy texture view?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!sDummySampler) {
|
||||||
|
wgpu::SamplerDescriptor samplerDescriptor{
|
||||||
|
.label = "dummy_sampler_not_to_be_used"
|
||||||
|
};
|
||||||
|
sDummySampler = device.CreateSampler(&samplerDescriptor);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer) << "Failed to create dummy sampler?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<wgpu::BindGroupEntry> WebGPUDescriptorSet::createDummyEntriesSortedByBinding(
|
||||||
|
std::vector<filament::backend::WebGPUDescriptorSetLayout::BindGroupEntryInfo> const&
|
||||||
|
bindGroupEntries) {
|
||||||
|
assert_invariant(WebGPUDescriptorSet::sDummyUniformBuffer &&
|
||||||
|
"Dummy uniform buffer must have been created before "
|
||||||
|
"creating dummy bind group entries.");
|
||||||
|
assert_invariant(
|
||||||
|
WebGPUDescriptorSet::sDummyTexture &&
|
||||||
|
"Dummy texture must have been created before creating dummy bind group entries.");
|
||||||
|
assert_invariant(
|
||||||
|
WebGPUDescriptorSet::sDummyTextureView &&
|
||||||
|
"Dummy texture view must have been created before creating dummy bind group entries.");
|
||||||
|
assert_invariant(
|
||||||
|
WebGPUDescriptorSet::sDummySampler &&
|
||||||
|
"Dummy sampler must have been created before creating dummy bind group entries.");
|
||||||
|
using filament::backend::WebGPUDescriptorSetLayout;
|
||||||
|
std::vector<wgpu::BindGroupEntry> entries;
|
||||||
|
entries.reserve(bindGroupEntries.size());
|
||||||
|
for (auto const& entryInfo: bindGroupEntries) {
|
||||||
|
auto& entry = entries.emplace_back();
|
||||||
|
entry.binding = entryInfo.binding;
|
||||||
|
switch (entryInfo.type) {
|
||||||
|
case WebGPUDescriptorSetLayout::BindGroupEntryType::UNIFORM_BUFFER:
|
||||||
|
entry.buffer = WebGPUDescriptorSet::sDummyUniformBuffer;
|
||||||
|
break;
|
||||||
|
case WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW:
|
||||||
|
entry.textureView = WebGPUDescriptorSet::sDummyTextureView;
|
||||||
|
break;
|
||||||
|
case WebGPUDescriptorSetLayout::BindGroupEntryType::SAMPLER:
|
||||||
|
entry.sampler = WebGPUDescriptorSet::sDummySampler;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::sort(entries.begin(), entries.end(),
|
||||||
|
[](wgpu::BindGroupEntry const& a, wgpu::BindGroupEntry const& b) {
|
||||||
|
return a.binding < b.binding;
|
||||||
|
});
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebGPUDescriptorSet::WebGPUDescriptorSet(wgpu::BindGroupLayout const& layout,
|
||||||
|
std::vector<WebGPUDescriptorSetLayout::BindGroupEntryInfo> const& bindGroupEntries)
|
||||||
: mLayout(layout),
|
: mLayout(layout),
|
||||||
entries(layoutSize, wgpu::BindGroupEntry{}) {
|
mEntriesSortedByBinding(createDummyEntriesSortedByBinding(bindGroupEntries)) {
|
||||||
// Establish the size of entries based on the layout. This should be reliable and efficient.
|
// Establish the size of entries based on the layout. This should be reliable and efficient.
|
||||||
|
assert_invariant(INVALID_INDEX > mEntryIndexByBinding.size());
|
||||||
|
for (size_t i = 0; i < mEntryIndexByBinding.size(); i++) {
|
||||||
|
mEntryIndexByBinding[i] = INVALID_INDEX;
|
||||||
|
}
|
||||||
|
for (size_t index = 0; index < mEntriesSortedByBinding.size(); index++) {
|
||||||
|
wgpu::BindGroupEntry const& entry = mEntriesSortedByBinding[index];
|
||||||
|
assert_invariant(entry.binding < mEntryIndexByBinding.size());
|
||||||
|
mEntryIndexByBinding[entry.binding] = static_cast<uint8_t>(index);
|
||||||
|
}
|
||||||
|
for (auto const& entry : bindGroupEntries) {
|
||||||
|
if (entry.hasDynamicOffset) {
|
||||||
|
assert_invariant(entry.binding < mEntriesByBindingWithDynamicOffsets.size());
|
||||||
|
mEntriesByBindingWithDynamicOffsets[entry.binding] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mDynamicOffsets.reserve(mEntriesSortedByBinding.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
WebGPUDescriptorSet::~WebGPUDescriptorSet() {
|
||||||
|
mBindGroup = nullptr;
|
||||||
|
mLayout = nullptr;
|
||||||
}
|
}
|
||||||
WebGPUDescriptorSet::~WebGPUDescriptorSet() {}
|
|
||||||
|
|
||||||
wgpu::BindGroup WebGPUDescriptorSet::lockAndReturn(const wgpu::Device& device) {
|
wgpu::BindGroup WebGPUDescriptorSet::lockAndReturn(const wgpu::Device& device) {
|
||||||
if (mBindGroup) {
|
if (mBindGroup) {
|
||||||
return mBindGroup;
|
return mBindGroup;
|
||||||
}
|
}
|
||||||
// TODO label? Should we just copy layout label?
|
// TODO label? Should we just copy layout label?
|
||||||
wgpu::BindGroupDescriptor desc{ .layout = mLayout,
|
wgpu::BindGroupDescriptor desc{
|
||||||
.entryCount = entries.size(),
|
.layout = mLayout,
|
||||||
.entries = entries.data() };
|
.entryCount = mEntriesSortedByBinding.size(),
|
||||||
|
.entries = mEntriesSortedByBinding.data()
|
||||||
|
};
|
||||||
mBindGroup = device.CreateBindGroup(&desc);
|
mBindGroup = device.CreateBindGroup(&desc);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(mBindGroup) << "Failed to create bind group?";
|
||||||
|
// once we have created the bind group itself we should no longer need any other state
|
||||||
|
mLayout = nullptr;
|
||||||
|
mEntriesSortedByBinding.clear();
|
||||||
|
mEntriesSortedByBinding.shrink_to_fit();
|
||||||
return mBindGroup;
|
return mBindGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDescriptorSet::addEntry(uint index, wgpu::BindGroupEntry&& entry) {
|
void WebGPUDescriptorSet::addEntry(unsigned int index, wgpu::BindGroupEntry&& entry) {
|
||||||
if (mBindGroup) {
|
if (mBindGroup) {
|
||||||
// We will keep getting hits from future updates, but shouldn't do anything
|
// We will keep getting hits from future updates, but shouldn't do anything
|
||||||
// Filament guarantees this won't change after things have locked.
|
// Filament guarantees this won't change after things have locked.
|
||||||
@@ -292,6 +466,490 @@ void WebGPUDescriptorSet::addEntry(uint index, wgpu::BindGroupEntry&& entry) {
|
|||||||
}
|
}
|
||||||
// TODO: Putting some level of trust that Filament is not going to reuse indexes or go past the
|
// TODO: Putting some level of trust that Filament is not going to reuse indexes or go past the
|
||||||
// layout index for efficiency. Add guards if wrong.
|
// layout index for efficiency. Add guards if wrong.
|
||||||
entries[index] = std::move(entry);
|
FILAMENT_CHECK_POSTCONDITION(index < mEntryIndexByBinding.size())
|
||||||
|
<< "impossible/invalid index for a descriptor/binding (our of range or >= "
|
||||||
|
"MAX_DESCRIPTOR_COUNT) "
|
||||||
|
<< index;
|
||||||
|
uint8_t entryIndex = mEntryIndexByBinding[index];
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(
|
||||||
|
entryIndex != INVALID_INDEX && entryIndex < mEntriesSortedByBinding.size())
|
||||||
|
<< "Invalid binding " << index;
|
||||||
|
entry.binding = index;
|
||||||
|
mEntriesSortedByBinding[entryIndex] = std::move(entry);
|
||||||
|
mEntriesByBindingAdded[index] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t const* WebGPUDescriptorSet::setDynamicOffsets(uint32_t const* offsets) {
|
||||||
|
// mDynamicOffsets already reserves enough memory for the number of entries in the set
|
||||||
|
mDynamicOffsets.clear();
|
||||||
|
// this implementation copies the offsets to mDynamicOffsets, but also adds values for
|
||||||
|
// unused entries TODO: is this necessary?
|
||||||
|
size_t inputIndex = 0;
|
||||||
|
size_t outputIndex = 0;
|
||||||
|
for (auto const& entry : mEntriesSortedByBinding) {
|
||||||
|
if (mEntriesByBindingWithDynamicOffsets[entry.binding]) {
|
||||||
|
if (mEntriesByBindingAdded[entry.binding]) {
|
||||||
|
mDynamicOffsets[outputIndex++] = offsets[inputIndex++];
|
||||||
|
} else {
|
||||||
|
mDynamicOffsets[outputIndex++] = 0; // dummy offset, as it was never added
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mDynamicOffsets.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WebGPUDescriptorSet::countEntitiesWithDynamicOffsets() const {
|
||||||
|
return mEntriesByBindingWithDynamicOffsets.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
// From createTextureR
|
||||||
|
WGPUTexture::WGPUTexture(SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
||||||
|
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage,
|
||||||
|
wgpu::Device const& device) noexcept {
|
||||||
|
assert_invariant(
|
||||||
|
samples == 1 ||
|
||||||
|
samples == 4 &&
|
||||||
|
"An invalid number of samples were requested, as WGPU requires the sample "
|
||||||
|
"count to either be 1 (no multisampling) or 4, at least as of April 2025 of "
|
||||||
|
"the spec. See https://www.w3.org/TR/webgpu/#texture-creation or "
|
||||||
|
"https://gpuweb.github.io/gpuweb/#multisample-state");
|
||||||
|
// First, the texture aspect, starting with the defaults/basic configuration
|
||||||
|
mUsage = fToWGPUTextureUsage(usage);
|
||||||
|
mFormat = fToWGPUTextureFormat(format);
|
||||||
|
wgpu::TextureDescriptor textureDescriptor{
|
||||||
|
.label = getUserTextureLabel(target),
|
||||||
|
.usage = mUsage,
|
||||||
|
.dimension = target == SamplerType::SAMPLER_3D ? wgpu::TextureDimension::e3D
|
||||||
|
: wgpu::TextureDimension::e2D,
|
||||||
|
.size = { .width = width, .height = height, .depthOrArrayLayers = depth },
|
||||||
|
.format = mFormat,
|
||||||
|
.mipLevelCount = levels,
|
||||||
|
.sampleCount = samples,
|
||||||
|
// TODO Is this fine? Could do all-the-things, a naive mapping or get something from
|
||||||
|
// Filament
|
||||||
|
.viewFormatCount = 0,
|
||||||
|
.viewFormats = nullptr,
|
||||||
|
};
|
||||||
|
// adjust for specific cases
|
||||||
|
switch (target) {
|
||||||
|
case SamplerType::SAMPLER_2D:
|
||||||
|
mArrayLayerCount = 1;
|
||||||
|
break;
|
||||||
|
case SamplerType::SAMPLER_2D_ARRAY:
|
||||||
|
mArrayLayerCount = textureDescriptor.size.depthOrArrayLayers;
|
||||||
|
break;
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP:
|
||||||
|
textureDescriptor.size.depthOrArrayLayers = 6;
|
||||||
|
mArrayLayerCount = textureDescriptor.size.depthOrArrayLayers;
|
||||||
|
break;
|
||||||
|
case SamplerType::SAMPLER_EXTERNAL:
|
||||||
|
case SamplerType::SAMPLER_3D:
|
||||||
|
mArrayLayerCount = 1;
|
||||||
|
break;
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||||
|
textureDescriptor.size.depthOrArrayLayers = depth * 6;
|
||||||
|
mArrayLayerCount = textureDescriptor.size.depthOrArrayLayers;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assert_invariant(textureDescriptor.format != wgpu::TextureFormat::Undefined &&
|
||||||
|
"Could not find appropriate WebGPU format");
|
||||||
|
mTexture = device.CreateTexture(&textureDescriptor);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(mTexture)
|
||||||
|
<< "Failed to create texture for " << textureDescriptor.label;
|
||||||
|
// Second, the texture view aspect
|
||||||
|
mTexView = makeTextureView(0, levels, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
// From createTextureViewR
|
||||||
|
WGPUTexture::WGPUTexture(WGPUTexture* src, uint8_t baseLevel, uint8_t levelCount) noexcept {
|
||||||
|
mTexture = src->mTexture;
|
||||||
|
mTexView = makeTextureView(baseLevel, levelCount, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::TextureUsage WGPUTexture::fToWGPUTextureUsage(const TextureUsage& fUsage) {
|
||||||
|
wgpu::TextureUsage retUsage = wgpu::TextureUsage::None;
|
||||||
|
|
||||||
|
// Basing this mapping off of VulkanTexture.cpp's getUsage func and suggestions from Gemini
|
||||||
|
// TODO Validate assumptions, revisit if issues.
|
||||||
|
if (any(TextureUsage::BLIT_SRC & fUsage)) {
|
||||||
|
retUsage |= wgpu::TextureUsage::CopySrc;
|
||||||
|
}
|
||||||
|
if (any((TextureUsage::BLIT_DST | TextureUsage::UPLOADABLE) & fUsage)) {
|
||||||
|
retUsage |= wgpu::TextureUsage::CopyDst;
|
||||||
|
}
|
||||||
|
if (any(TextureUsage::SAMPLEABLE & fUsage)) {
|
||||||
|
retUsage |= wgpu::TextureUsage::TextureBinding;
|
||||||
|
}
|
||||||
|
// WGPU Render attachment covers either color or stencil situation dependant
|
||||||
|
// NOTE: Depth attachment isn't used this way in Vulkan but logically maps to WGPU docs. If
|
||||||
|
// issues, investigate here.
|
||||||
|
if (any((TextureUsage::COLOR_ATTACHMENT | TextureUsage::STENCIL_ATTACHMENT |
|
||||||
|
TextureUsage::DEPTH_ATTACHMENT) &
|
||||||
|
fUsage)) {
|
||||||
|
retUsage |= wgpu::TextureUsage::RenderAttachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is from Vulkan logic- if there are any issues try disabling this first, allows perf
|
||||||
|
// benefit though
|
||||||
|
const bool useTransientAttachment =
|
||||||
|
// Usage consists of attachment flags only.
|
||||||
|
none(fUsage & ~TextureUsage::ALL_ATTACHMENTS) &&
|
||||||
|
// Usage contains at least one attachment flag.
|
||||||
|
any(fUsage & TextureUsage::ALL_ATTACHMENTS) &&
|
||||||
|
// Depth resolve cannot use transient attachment because it uses a custom shader.
|
||||||
|
// TODO: see VulkanDriver::isDepthStencilResolveSupported() to know when to remove this
|
||||||
|
// restriction.
|
||||||
|
// Note that the custom shader does not resolve stencil. We do need to move to vk 1.2
|
||||||
|
// and above to be able to support stencil resolve (along with depth).
|
||||||
|
!(any(fUsage & TextureUsage::DEPTH_ATTACHMENT) && samples > 1);
|
||||||
|
if (useTransientAttachment) {
|
||||||
|
retUsage |= wgpu::TextureUsage::TransientAttachment;
|
||||||
|
}
|
||||||
|
// NOTE: Unused wgpu flags:
|
||||||
|
// StorageBinding
|
||||||
|
// StorageAttachment
|
||||||
|
|
||||||
|
// NOTE: Unused Filament flags:
|
||||||
|
// SUBPASS_INPUT VK goes to input attachment which we don't support right now
|
||||||
|
// PROTECTED
|
||||||
|
return retUsage;
|
||||||
|
}
|
||||||
|
wgpu::TextureFormat WGPUTexture::fToWGPUTextureFormat(const TextureFormat& fUsage) {
|
||||||
|
switch (fUsage) {
|
||||||
|
case filament::backend::TextureFormat::R8:
|
||||||
|
return wgpu::TextureFormat::R8Unorm;
|
||||||
|
case filament::backend::TextureFormat::R8_SNORM:
|
||||||
|
return wgpu::TextureFormat::R8Snorm;
|
||||||
|
case filament::backend::TextureFormat::R8UI:
|
||||||
|
return wgpu::TextureFormat::R8Uint;
|
||||||
|
case filament::backend::TextureFormat::R8I:
|
||||||
|
return wgpu::TextureFormat::R8Sint;
|
||||||
|
case filament::backend::TextureFormat::STENCIL8:
|
||||||
|
return wgpu::TextureFormat::Stencil8;
|
||||||
|
case filament::backend::TextureFormat::R16F:
|
||||||
|
return wgpu::TextureFormat::R16Float;
|
||||||
|
case filament::backend::TextureFormat::R16UI:
|
||||||
|
return wgpu::TextureFormat::R16Uint;
|
||||||
|
case filament::backend::TextureFormat::R16I:
|
||||||
|
return wgpu::TextureFormat::R16Sint;
|
||||||
|
case filament::backend::TextureFormat::RG8:
|
||||||
|
return wgpu::TextureFormat::RG8Unorm;
|
||||||
|
case filament::backend::TextureFormat::RG8_SNORM:
|
||||||
|
return wgpu::TextureFormat::RG8Snorm;
|
||||||
|
case filament::backend::TextureFormat::RG8UI:
|
||||||
|
return wgpu::TextureFormat::RG8Uint;
|
||||||
|
case filament::backend::TextureFormat::RG8I:
|
||||||
|
return wgpu::TextureFormat::RG8Sint;
|
||||||
|
case filament::backend::TextureFormat::R32F:
|
||||||
|
return wgpu::TextureFormat::R32Float;
|
||||||
|
case filament::backend::TextureFormat::R32UI:
|
||||||
|
return wgpu::TextureFormat::R32Uint;
|
||||||
|
case filament::backend::TextureFormat::R32I:
|
||||||
|
return wgpu::TextureFormat::R32Sint;
|
||||||
|
case filament::backend::TextureFormat::RG16F:
|
||||||
|
return wgpu::TextureFormat::RG16Float;
|
||||||
|
case filament::backend::TextureFormat::RG16UI:
|
||||||
|
return wgpu::TextureFormat::RG16Uint;
|
||||||
|
case filament::backend::TextureFormat::RG16I:
|
||||||
|
return wgpu::TextureFormat::RG16Sint;
|
||||||
|
case filament::backend::TextureFormat::RGBA8:
|
||||||
|
return wgpu::TextureFormat::RGBA8Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_A8:
|
||||||
|
return wgpu::TextureFormat::RGBA8UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA8_SNORM:
|
||||||
|
return wgpu::TextureFormat::RGBA8Snorm;
|
||||||
|
case filament::backend::TextureFormat::RGBA8UI:
|
||||||
|
return wgpu::TextureFormat::RGBA8Uint;
|
||||||
|
case filament::backend::TextureFormat::RGBA8I:
|
||||||
|
return wgpu::TextureFormat::RGBA8Sint;
|
||||||
|
case filament::backend::TextureFormat::DEPTH16:
|
||||||
|
return wgpu::TextureFormat::Depth16Unorm;
|
||||||
|
case filament::backend::TextureFormat::DEPTH24:
|
||||||
|
return wgpu::TextureFormat::Depth24Plus;
|
||||||
|
case filament::backend::TextureFormat::DEPTH32F:
|
||||||
|
return wgpu::TextureFormat::Depth32Float;
|
||||||
|
case filament::backend::TextureFormat::DEPTH24_STENCIL8:
|
||||||
|
return wgpu::TextureFormat::Depth24PlusStencil8;
|
||||||
|
case filament::backend::TextureFormat::DEPTH32F_STENCIL8:
|
||||||
|
return wgpu::TextureFormat::Depth32FloatStencil8;
|
||||||
|
case filament::backend::TextureFormat::RG32F:
|
||||||
|
return wgpu::TextureFormat::RG32Float;
|
||||||
|
case filament::backend::TextureFormat::RG32UI:
|
||||||
|
return wgpu::TextureFormat::RG32Uint;
|
||||||
|
case filament::backend::TextureFormat::RG32I:
|
||||||
|
return wgpu::TextureFormat::RG32Sint;
|
||||||
|
case filament::backend::TextureFormat::RGBA16F:
|
||||||
|
return wgpu::TextureFormat::RGBA16Float;
|
||||||
|
case filament::backend::TextureFormat::RGBA16UI:
|
||||||
|
return wgpu::TextureFormat::RGBA16Uint;
|
||||||
|
case filament::backend::TextureFormat::RGBA16I:
|
||||||
|
return wgpu::TextureFormat::RGBA16Sint;
|
||||||
|
case filament::backend::TextureFormat::RGBA32F:
|
||||||
|
return wgpu::TextureFormat::RGBA32Float;
|
||||||
|
case filament::backend::TextureFormat::RGBA32UI:
|
||||||
|
return wgpu::TextureFormat::RGBA32Uint;
|
||||||
|
case filament::backend::TextureFormat::RGBA32I:
|
||||||
|
return wgpu::TextureFormat::RGBA32Sint;
|
||||||
|
case filament::backend::TextureFormat::EAC_R11:
|
||||||
|
return wgpu::TextureFormat::EACR11Unorm;
|
||||||
|
case filament::backend::TextureFormat::EAC_R11_SIGNED:
|
||||||
|
return wgpu::TextureFormat::EACR11Snorm;
|
||||||
|
case filament::backend::TextureFormat::EAC_RG11:
|
||||||
|
return wgpu::TextureFormat::EACRG11Unorm;
|
||||||
|
case filament::backend::TextureFormat::EAC_RG11_SIGNED:
|
||||||
|
return wgpu::TextureFormat::EACRG11Snorm;
|
||||||
|
case filament::backend::TextureFormat::ETC2_RGB8:
|
||||||
|
return wgpu::TextureFormat::ETC2RGB8Unorm;
|
||||||
|
case filament::backend::TextureFormat::ETC2_SRGB8:
|
||||||
|
return wgpu::TextureFormat::ETC2RGB8UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::ETC2_RGB8_A1:
|
||||||
|
return wgpu::TextureFormat::ETC2RGB8A1Unorm;
|
||||||
|
case filament::backend::TextureFormat::ETC2_SRGB8_A1:
|
||||||
|
return wgpu::TextureFormat::ETC2RGB8A1UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::ETC2_EAC_RGBA8:
|
||||||
|
return wgpu::TextureFormat::ETC2RGBA8Unorm;
|
||||||
|
case filament::backend::TextureFormat::ETC2_EAC_SRGBA8:
|
||||||
|
return wgpu::TextureFormat::ETC2RGBA8UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_4x4:
|
||||||
|
return wgpu::TextureFormat::ASTC4x4Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_4x4:
|
||||||
|
return wgpu::TextureFormat::ASTC4x4UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_5x4:
|
||||||
|
return wgpu::TextureFormat::ASTC5x4Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_5x4:
|
||||||
|
return wgpu::TextureFormat::ASTC5x4UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_5x5:
|
||||||
|
return wgpu::TextureFormat::ASTC5x5Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_5x5:
|
||||||
|
return wgpu::TextureFormat::ASTC5x5UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_6x5:
|
||||||
|
return wgpu::TextureFormat::ASTC6x5Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_6x5:
|
||||||
|
return wgpu::TextureFormat::ASTC6x5UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_6x6:
|
||||||
|
return wgpu::TextureFormat::ASTC6x6Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_6x6:
|
||||||
|
return wgpu::TextureFormat::ASTC6x6UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_8x5:
|
||||||
|
return wgpu::TextureFormat::ASTC8x5Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_8x5:
|
||||||
|
return wgpu::TextureFormat::ASTC8x5UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_8x6:
|
||||||
|
return wgpu::TextureFormat::ASTC8x6Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_8x6:
|
||||||
|
return wgpu::TextureFormat::ASTC8x6UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_8x8:
|
||||||
|
return wgpu::TextureFormat::ASTC8x8Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_8x8:
|
||||||
|
return wgpu::TextureFormat::ASTC8x8UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_10x5:
|
||||||
|
return wgpu::TextureFormat::ASTC10x5Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_10x5:
|
||||||
|
return wgpu::TextureFormat::ASTC10x5UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_10x6:
|
||||||
|
return wgpu::TextureFormat::ASTC10x6Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_10x6:
|
||||||
|
return wgpu::TextureFormat::ASTC10x6UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_10x8:
|
||||||
|
return wgpu::TextureFormat::ASTC10x8Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_10x8:
|
||||||
|
return wgpu::TextureFormat::ASTC10x8UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_10x10:
|
||||||
|
return wgpu::TextureFormat::ASTC10x10Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_10x10:
|
||||||
|
return wgpu::TextureFormat::ASTC10x10UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_12x10:
|
||||||
|
return wgpu::TextureFormat::ASTC12x10Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_12x10:
|
||||||
|
return wgpu::TextureFormat::ASTC12x10UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGBA_ASTC_12x12:
|
||||||
|
return wgpu::TextureFormat::ASTC12x12Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_12x12:
|
||||||
|
return wgpu::TextureFormat::ASTC12x12UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RED_RGTC1:
|
||||||
|
return wgpu::TextureFormat::BC4RUnorm;
|
||||||
|
case filament::backend::TextureFormat::SIGNED_RED_RGTC1:
|
||||||
|
return wgpu::TextureFormat::BC4RSnorm;
|
||||||
|
case filament::backend::TextureFormat::RED_GREEN_RGTC2:
|
||||||
|
return wgpu::TextureFormat::BC5RGUnorm;
|
||||||
|
case filament::backend::TextureFormat::SIGNED_RED_GREEN_RGTC2:
|
||||||
|
return wgpu::TextureFormat::BC5RGSnorm;
|
||||||
|
case filament::backend::TextureFormat::RGB_BPTC_UNSIGNED_FLOAT:
|
||||||
|
return wgpu::TextureFormat::BC6HRGBUfloat;
|
||||||
|
case filament::backend::TextureFormat::RGB_BPTC_SIGNED_FLOAT:
|
||||||
|
return wgpu::TextureFormat::BC6HRGBFloat;
|
||||||
|
case filament::backend::TextureFormat::RGBA_BPTC_UNORM:
|
||||||
|
return wgpu::TextureFormat::BC7RGBAUnorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB_ALPHA_BPTC_UNORM:
|
||||||
|
return wgpu::TextureFormat::BC7RGBAUnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGB565:
|
||||||
|
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
|
||||||
|
// and discard the alpha and lower precision.
|
||||||
|
return wgpu::TextureFormat::Undefined;
|
||||||
|
case filament::backend::TextureFormat::RGB9_E5:
|
||||||
|
return wgpu::TextureFormat::RGB9E5Ufloat;
|
||||||
|
case filament::backend::TextureFormat::RGB5_A1:
|
||||||
|
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
|
||||||
|
// and handle the packing/unpacking in shaders.
|
||||||
|
return wgpu::TextureFormat::Undefined;
|
||||||
|
case filament::backend::TextureFormat::RGBA4:
|
||||||
|
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
|
||||||
|
// and handle the packing/unpacking in shaders.
|
||||||
|
return wgpu::TextureFormat::Undefined;
|
||||||
|
case filament::backend::TextureFormat::RGB8:
|
||||||
|
// No direct sRGB equivalent in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA8Unorm;
|
||||||
|
case filament::backend::TextureFormat::SRGB8:
|
||||||
|
// No direct sRGB equivalent in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA8UnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::RGB8_SNORM:
|
||||||
|
// No direct mapping in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA8Snorm;
|
||||||
|
case filament::backend::TextureFormat::RGB8UI:
|
||||||
|
// No direct mapping in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA8Uint;
|
||||||
|
case filament::backend::TextureFormat::RGB8I:
|
||||||
|
// No direct mapping in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA8Sint;
|
||||||
|
case filament::backend::TextureFormat::R11F_G11F_B10F:
|
||||||
|
return wgpu::TextureFormat::RG11B10Ufloat;
|
||||||
|
case filament::backend::TextureFormat::UNUSED:
|
||||||
|
return wgpu::TextureFormat::Undefined;
|
||||||
|
case filament::backend::TextureFormat::RGB10_A2:
|
||||||
|
return wgpu::TextureFormat::RGB10A2Unorm;
|
||||||
|
case filament::backend::TextureFormat::RGB16F:
|
||||||
|
// No direct mapping in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA16Float;
|
||||||
|
case filament::backend::TextureFormat::RGB16UI:
|
||||||
|
// No direct mapping in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA16Uint;
|
||||||
|
case filament::backend::TextureFormat::RGB16I:
|
||||||
|
// No direct mapping in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA16Sint;
|
||||||
|
case filament::backend::TextureFormat::RGB32F:
|
||||||
|
// No direct mapping in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA32Float;
|
||||||
|
case filament::backend::TextureFormat::RGB32UI:
|
||||||
|
// No direct mapping in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA32Uint;
|
||||||
|
case filament::backend::TextureFormat::RGB32I:
|
||||||
|
// No direct mapping in wgpu without alpha.
|
||||||
|
return wgpu::TextureFormat::RGBA32Sint;
|
||||||
|
case filament::backend::TextureFormat::DXT1_RGB:
|
||||||
|
return wgpu::TextureFormat::BC1RGBAUnorm;
|
||||||
|
case filament::backend::TextureFormat::DXT1_RGBA:
|
||||||
|
return wgpu::TextureFormat::BC1RGBAUnorm;
|
||||||
|
case filament::backend::TextureFormat::DXT3_RGBA:
|
||||||
|
return wgpu::TextureFormat::BC2RGBAUnorm;
|
||||||
|
case filament::backend::TextureFormat::DXT5_RGBA:
|
||||||
|
return wgpu::TextureFormat::BC3RGBAUnorm;
|
||||||
|
case filament::backend::TextureFormat::DXT1_SRGB:
|
||||||
|
return wgpu::TextureFormat::BC1RGBAUnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::DXT1_SRGBA:
|
||||||
|
return wgpu::TextureFormat::BC1RGBAUnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::DXT3_SRGBA:
|
||||||
|
return wgpu::TextureFormat::BC2RGBAUnormSrgb;
|
||||||
|
case filament::backend::TextureFormat::DXT5_SRGBA:
|
||||||
|
return wgpu::TextureFormat::BC3RGBAUnormSrgb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::TextureView WGPUTexture::makeTextureView(const uint8_t& baseLevel, const uint8_t& levelCount,
|
||||||
|
SamplerType target) {
|
||||||
|
// starting with the defaults/basic configuration
|
||||||
|
wgpu::TextureViewDescriptor textureViewDescriptor{
|
||||||
|
.label = getUserTextureViewLabel(target),
|
||||||
|
.format = mFormat,
|
||||||
|
// dimension depends on target and is set below
|
||||||
|
.baseMipLevel = baseLevel,
|
||||||
|
.mipLevelCount = levelCount,
|
||||||
|
// baseArrayLayer is required, making a guess
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.arrayLayerCount = mArrayLayerCount,
|
||||||
|
// Have not found an analog to aspect in other drivers, but ALL should be unrestrictive.
|
||||||
|
// TODO Can we make this better?
|
||||||
|
.aspect = wgpu::TextureAspect::All,
|
||||||
|
.usage = mUsage
|
||||||
|
};
|
||||||
|
// adjust for specific cases
|
||||||
|
switch (target) {
|
||||||
|
case SamplerType::SAMPLER_2D:
|
||||||
|
textureViewDescriptor.dimension = wgpu::TextureViewDimension::e2D;
|
||||||
|
break;
|
||||||
|
case SamplerType::SAMPLER_2D_ARRAY:
|
||||||
|
textureViewDescriptor.dimension = wgpu::TextureViewDimension::e2DArray;
|
||||||
|
break;
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP:
|
||||||
|
textureViewDescriptor.dimension = wgpu::TextureViewDimension::Cube;
|
||||||
|
break;
|
||||||
|
case SamplerType::SAMPLER_EXTERNAL:
|
||||||
|
textureViewDescriptor.dimension = wgpu::TextureViewDimension::e2D;
|
||||||
|
break;
|
||||||
|
case SamplerType::SAMPLER_3D:
|
||||||
|
textureViewDescriptor.dimension = wgpu::TextureViewDimension::e3D;
|
||||||
|
break;
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||||
|
textureViewDescriptor.dimension = wgpu::TextureViewDimension::CubeArray;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
wgpu::TextureView textureView = mTexture.CreateView(&textureViewDescriptor);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(textureView)
|
||||||
|
<< "Failed to create texture view " << textureViewDescriptor.label;
|
||||||
|
return textureView;
|
||||||
|
}
|
||||||
|
|
||||||
|
WGPURenderTarget::Attachment WGPURenderTarget::getDrawColorAttachment(size_t index) {
|
||||||
|
assert_invariant( index < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT);
|
||||||
|
auto result = color[index];
|
||||||
|
if (index == 0 && defaultRenderTarget) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::LoadOp WGPURenderTarget::getLoadOperation(RenderPassParams const& params,
|
||||||
|
TargetBufferFlags buffer) {
|
||||||
|
auto clearFlags = params.flags.clear;
|
||||||
|
auto discardStartFlags = params.flags.discardStart;
|
||||||
|
if (any(clearFlags & buffer)) {
|
||||||
|
return wgpu::LoadOp::Clear;
|
||||||
|
} else if (any(discardStartFlags & buffer)) {
|
||||||
|
return wgpu::LoadOp::Clear;
|
||||||
|
}
|
||||||
|
return wgpu::LoadOp::Load;
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::StoreOp WGPURenderTarget::getStoreOperation(RenderPassParams const& params,
|
||||||
|
TargetBufferFlags buffer) {
|
||||||
|
const auto discardEndFlags = params.flags.discardEnd;
|
||||||
|
if (any(discardEndFlags & buffer)) {
|
||||||
|
return wgpu::StoreOp::Discard;
|
||||||
|
}
|
||||||
|
return wgpu::StoreOp::Store;
|
||||||
|
}
|
||||||
|
void WGPURenderTarget::setUpRenderPassAttachments(wgpu::RenderPassDescriptor& descriptor,
|
||||||
|
wgpu::TextureView const& textureView, RenderPassParams const& params) {
|
||||||
|
// auto discardFlags = params.flags.discardEnd;
|
||||||
|
// (void) discardFlags;
|
||||||
|
// std::vector<wgpu::RenderPassColorAttachment> colorAttachments;
|
||||||
|
colorAttachments.clear();
|
||||||
|
for (size_t i = 0; i < 1/*MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT*/; i++) {
|
||||||
|
// auto attachment = getDrawColorAttachment(i);
|
||||||
|
// if (attachment) {
|
||||||
|
wgpu::RenderPassColorAttachment colorAttachment;
|
||||||
|
colorAttachment.view = textureView;
|
||||||
|
colorAttachment.loadOp = getLoadOperation(params, getTargetBufferFlagsAt(i));
|
||||||
|
colorAttachment.storeOp = getStoreOperation(params, getTargetBufferFlagsAt(i));
|
||||||
|
colorAttachment.clearValue = { params.clearColor.r, params.clearColor.g, params.clearColor.b, params.clearColor.a };
|
||||||
|
colorAttachments.emplace_back(colorAttachment);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
descriptor.colorAttachments = colorAttachments.data();
|
||||||
|
descriptor.colorAttachmentCount = colorAttachments.size();
|
||||||
|
descriptor.depthStencilAttachment = nullptr;
|
||||||
|
descriptor.timestampWrites = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}// namespace filament::backend
|
}// namespace filament::backend
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#include <webgpu/webgpu_cpp.h>
|
#include <webgpu/webgpu_cpp.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <bitset>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -98,80 +100,124 @@ struct WGPUBufferObject : HwBufferObject {
|
|||||||
wgpu::Buffer buffer = nullptr;
|
wgpu::Buffer buffer = nullptr;
|
||||||
const BufferObjectBinding bufferObjectBinding;
|
const BufferObjectBinding bufferObjectBinding;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WebGPUDescriptorSetLayout final : public HwDescriptorSetLayout {
|
class WebGPUDescriptorSetLayout final : public HwDescriptorSetLayout {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
enum class BindGroupEntryType : uint8_t {
|
||||||
|
UNIFORM_BUFFER,
|
||||||
|
TEXTURE_VIEW,
|
||||||
|
SAMPLER
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BindGroupEntryInfo final {
|
||||||
|
uint8_t binding = 0;
|
||||||
|
BindGroupEntryType type = BindGroupEntryType::UNIFORM_BUFFER;
|
||||||
|
bool hasDynamicOffset = false;
|
||||||
|
};
|
||||||
|
|
||||||
WebGPUDescriptorSetLayout(DescriptorSetLayout const& layout, wgpu::Device const& device);
|
WebGPUDescriptorSetLayout(DescriptorSetLayout const& layout, wgpu::Device const& device);
|
||||||
~WebGPUDescriptorSetLayout();
|
~WebGPUDescriptorSetLayout();
|
||||||
[[nodiscard]] const wgpu::BindGroupLayout& getLayout() const { return mLayout; }
|
[[nodiscard]] const wgpu::BindGroupLayout& getLayout() const { return mLayout; }
|
||||||
[[nodiscard]] uint getLayoutSize() const { return mLayoutSize; }
|
[[nodiscard]] std::vector<BindGroupEntryInfo> const& getBindGroupEntries() const {
|
||||||
|
return mBindGroupEntries;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// TODO: If this is useful elsewhere, remove it from this class
|
// TODO: If this is useful elsewhere, remove it from this class
|
||||||
// Convert Filament Shader Stage Flags bitmask to webgpu equivilant
|
// Convert Filament Shader Stage Flags bitmask to webgpu equivilant
|
||||||
static wgpu::ShaderStage filamentStageToWGPUStage(ShaderStageFlags fFlags);
|
static wgpu::ShaderStage filamentStageToWGPUStage(ShaderStageFlags fFlags);
|
||||||
uint mLayoutSize;
|
std::vector<BindGroupEntryInfo> mBindGroupEntries;
|
||||||
wgpu::BindGroupLayout mLayout;
|
wgpu::BindGroupLayout mLayout;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WebGPUDescriptorSet final : public HwDescriptorSet {
|
class WebGPUDescriptorSet final : public HwDescriptorSet {
|
||||||
public:
|
public:
|
||||||
WebGPUDescriptorSet(const wgpu::BindGroupLayout& layout, uint layoutSize);
|
static void initializeDummyResourcesIfNotAlready(wgpu::Device const&,
|
||||||
|
wgpu::TextureFormat aColorFormat);
|
||||||
|
|
||||||
|
WebGPUDescriptorSet(wgpu::BindGroupLayout const& layout,
|
||||||
|
std::vector<WebGPUDescriptorSetLayout::BindGroupEntryInfo> const& bindGroupEntries);
|
||||||
~WebGPUDescriptorSet();
|
~WebGPUDescriptorSet();
|
||||||
|
|
||||||
wgpu::BindGroup lockAndReturn(wgpu::Device const& device);
|
wgpu::BindGroup lockAndReturn(wgpu::Device const&);
|
||||||
void addEntry(uint index, wgpu::BindGroupEntry&& entry);
|
void addEntry(unsigned int index, wgpu::BindGroupEntry&& entry);
|
||||||
|
[[nodiscard]] uint32_t const* setDynamicOffsets(uint32_t const* offsets);
|
||||||
[[nodiscard]] bool getIsLocked() const { return mBindGroup != nullptr; }
|
[[nodiscard]] bool getIsLocked() const { return mBindGroup != nullptr; }
|
||||||
|
[[nodiscard]] size_t countEntitiesWithDynamicOffsets() const;
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
static wgpu::Buffer sDummyUniformBuffer;
|
||||||
|
static wgpu::Texture sDummyTexture;
|
||||||
|
static wgpu::TextureView sDummyTextureView;
|
||||||
|
static wgpu::Sampler sDummySampler;
|
||||||
|
|
||||||
|
static std::vector<wgpu::BindGroupEntry> createDummyEntriesSortedByBinding(
|
||||||
|
std::vector<filament::backend::WebGPUDescriptorSetLayout::BindGroupEntryInfo> const&);
|
||||||
|
|
||||||
// TODO: Consider storing what we used to make the layout. However we need to essentially
|
// TODO: Consider storing what we used to make the layout. However we need to essentially
|
||||||
// Recreate some of the info (Sampler in slot X with the actual sampler) so letting Dawn confirm
|
// Recreate some of the info (Sampler in slot X with the actual sampler) so letting Dawn confirm
|
||||||
// there isn't a mismatch may be easiest.
|
// there isn't a mismatch may be easiest.
|
||||||
// Also storing the wgpu ObjectBase takes care of ownership challenges in theory
|
// Also storing the wgpu ObjectBase takes care of ownership challenges in theory
|
||||||
wgpu::BindGroupLayout mLayout;
|
wgpu::BindGroupLayout mLayout = nullptr;
|
||||||
std::vector<wgpu::BindGroupEntry> entries;
|
static constexpr uint8_t INVALID_INDEX = MAX_DESCRIPTOR_COUNT + 1;
|
||||||
wgpu::BindGroup mBindGroup;
|
std::array<uint8_t, MAX_DESCRIPTOR_COUNT> mEntryIndexByBinding {};
|
||||||
|
std::vector<wgpu::BindGroupEntry> mEntriesSortedByBinding;
|
||||||
|
std::bitset<MAX_DESCRIPTOR_COUNT> mEntriesByBindingWithDynamicOffsets {};
|
||||||
|
std::bitset<MAX_DESCRIPTOR_COUNT> mEntriesByBindingAdded {};
|
||||||
|
std::vector<uint32_t> mDynamicOffsets;
|
||||||
|
wgpu::BindGroup mBindGroup = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Currently WGPUTexture is not used by WebGPU for useful task.
|
class WGPUTexture : public HwTexture {
|
||||||
// Update the struct when used by WebGPU driver.
|
public:
|
||||||
struct WGPUTexture : public HwTexture {
|
|
||||||
WGPUTexture(SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
WGPUTexture(SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
||||||
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage) noexcept;
|
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage,
|
||||||
|
wgpu::Device const& device) noexcept;
|
||||||
|
|
||||||
// constructors for creating texture views
|
WGPUTexture(WGPUTexture* src, uint8_t baseLevel, uint8_t levelCount) noexcept;
|
||||||
WGPUTexture(WGPUTexture const* src, uint8_t baseLevel, uint8_t levelCount) noexcept;
|
|
||||||
|
|
||||||
wgpu::Texture texture = nullptr;
|
const wgpu::Texture& getTexture() const { return mTexture; }
|
||||||
// TODO: Adding this but not yet setting it up. Filament "Textures" are combined image samplers,
|
const wgpu::TextureView& getTexView() const { return mTexView; }
|
||||||
// rep both.
|
|
||||||
wgpu::Sampler sampler = nullptr;
|
// Public to allow checking for support of a texture format
|
||||||
//TODO: Not sure all the ways HwTexture is used. Overloading like this might be entirely wrong.
|
static wgpu::TextureFormat fToWGPUTextureFormat(const filament::backend::TextureFormat& fUsage);
|
||||||
wgpu::TextureView texView = nullptr;
|
|
||||||
|
private:
|
||||||
|
wgpu::TextureView makeTextureView(const uint8_t& baseLevel, const uint8_t& levelCount,
|
||||||
|
SamplerType target);
|
||||||
|
// CreateTextureR has info for a texture and sampler. Texture Views are needed for binding,
|
||||||
|
// along with a sampler Current plan: Inherit the sampler and Texture to always exist (It is a
|
||||||
|
// ref counted pointer) when making views. View is optional
|
||||||
|
wgpu::Texture mTexture = nullptr;
|
||||||
|
wgpu::TextureUsage mUsage = wgpu::TextureUsage::None;
|
||||||
|
wgpu::TextureFormat mFormat = wgpu::TextureFormat::Undefined;
|
||||||
|
uint32_t mArrayLayerCount = 1;
|
||||||
|
wgpu::TextureView mTexView = nullptr;
|
||||||
|
wgpu::TextureUsage fToWGPUTextureUsage(const filament::backend::TextureUsage& fUsage);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WGPURenderPrimitive : public HwRenderPrimitive {
|
struct WGPURenderPrimitive : public HwRenderPrimitive {
|
||||||
WGPURenderPrimitive() {}
|
|
||||||
|
|
||||||
void setBuffers(WGPUVertexBufferInfo const* const vbi,
|
|
||||||
WGPUVertexBuffer* vertexBuffer, WGPUIndexBuffer* indexBuffer);
|
|
||||||
|
|
||||||
WGPUVertexBuffer* vertexBuffer = nullptr;
|
WGPUVertexBuffer* vertexBuffer = nullptr;
|
||||||
WGPUIndexBuffer* indexBuffer = nullptr;
|
WGPUIndexBuffer* indexBuffer = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Currently WGPURenderTarget is not used by WebGPU for useful task.
|
class WGPURenderTarget : public HwRenderTarget {
|
||||||
// Update the struct when used by WebGPU driver.
|
public:
|
||||||
struct WGPURenderTarget : public HwRenderTarget {
|
|
||||||
class Attachment {
|
class Attachment {
|
||||||
public:
|
public:
|
||||||
friend struct WGPURenderTarget;
|
friend class WGPURenderTarget;
|
||||||
|
|
||||||
Attachment() = default;
|
Attachment() = default;
|
||||||
Attachment(WGPUTexture* gpuTexture, uint8_t level = 0, uint16_t layer = 0)
|
Attachment(WGPUTexture* gpuTexture, uint8_t level = 0, uint16_t layer = 0)
|
||||||
: level(level),
|
: level(level),
|
||||||
layer(layer),
|
layer(layer),
|
||||||
texture(gpuTexture->texture),
|
texture(gpuTexture->getTexture()),
|
||||||
mWGPUTexture(gpuTexture) {}
|
mWGPUTexture(gpuTexture) {}
|
||||||
|
operator bool() const {
|
||||||
|
return mWGPUTexture != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t level = 0;
|
uint8_t level = 0;
|
||||||
uint16_t layer = 0;
|
uint16_t layer = 0;
|
||||||
@@ -187,8 +233,8 @@ struct WGPURenderTarget : public HwRenderTarget {
|
|||||||
: HwRenderTarget(0, 0),
|
: HwRenderTarget(0, 0),
|
||||||
defaultRenderTarget(true) {}
|
defaultRenderTarget(true) {}
|
||||||
|
|
||||||
void setUpRenderPassAttachments(wgpu::RenderPassDescriptor* descriptor,
|
void setUpRenderPassAttachments(wgpu::RenderPassDescriptor& descriptor,
|
||||||
const RenderPassParams& params);
|
wgpu::TextureView const& textureView, RenderPassParams const& params);
|
||||||
|
|
||||||
math::uint2 getAttachmentSize() noexcept;
|
math::uint2 getAttachmentSize() noexcept;
|
||||||
|
|
||||||
@@ -198,15 +244,15 @@ struct WGPURenderTarget : public HwRenderTarget {
|
|||||||
Attachment getDrawColorAttachment(size_t index);
|
Attachment getDrawColorAttachment(size_t index);
|
||||||
Attachment getReadColorAttachment(size_t index);
|
Attachment getReadColorAttachment(size_t index);
|
||||||
|
|
||||||
|
static wgpu::LoadOp getLoadOperation(const RenderPassParams& params, TargetBufferFlags buffer);
|
||||||
|
static wgpu::StoreOp getStoreOperation(const RenderPassParams& params, TargetBufferFlags buffer);
|
||||||
private:
|
private:
|
||||||
static wgpu::LoadOp getLoadAction(const RenderPassParams& params, TargetBufferFlags buffer);
|
|
||||||
static wgpu::LoadOp getStoreAction(const RenderPassParams& params, TargetBufferFlags buffer);
|
|
||||||
|
|
||||||
bool defaultRenderTarget = false;
|
bool defaultRenderTarget = false;
|
||||||
uint8_t samples = 1;
|
uint8_t samples = 1;
|
||||||
|
|
||||||
Attachment color[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
|
Attachment color[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
|
||||||
math::uint2 attachmentSize = {};
|
math::uint2 attachmentSize = {};
|
||||||
|
std::vector<wgpu::RenderPassColorAttachment> colorAttachments {};
|
||||||
};
|
};
|
||||||
|
|
||||||
}// namespace filament::backend
|
}// namespace filament::backend
|
||||||
|
|||||||
@@ -235,6 +235,7 @@ wgpu::RenderPipeline createWebGPURenderPipeline(wgpu::Device const& device,
|
|||||||
fragmentState.constantCount = program.constants.size(),
|
fragmentState.constantCount = program.constants.size(),
|
||||||
fragmentState.constants = program.constants.data(),
|
fragmentState.constants = program.constants.data(),
|
||||||
fragmentState.targetCount = 1; // TODO need to get this from the render target
|
fragmentState.targetCount = 1; // TODO need to get this from the render target
|
||||||
|
fragmentState.targets = colorTargets.data();
|
||||||
assert_invariant(fragmentState.targetCount <= MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT);
|
assert_invariant(fragmentState.targetCount <= MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT);
|
||||||
for (size_t targetIndex = 0; targetIndex < fragmentState.targetCount; targetIndex++) {
|
for (size_t targetIndex = 0; targetIndex < fragmentState.targetCount; targetIndex++) {
|
||||||
auto& colorTarget = colorTargets[targetIndex];
|
auto& colorTarget = colorTargets[targetIndex];
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ void printSurfaceConfiguration(wgpu::SurfaceConfiguration const& config,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr wgpu::TextureFormat selectColorFormat(size_t availableFormatsCount,
|
[[nodiscard]] constexpr wgpu::TextureFormat selectColorFormat(size_t availableFormatsCount,
|
||||||
wgpu::TextureFormat const* availableFormats, bool useSRGBColorSpace) {
|
wgpu::TextureFormat const* availableFormats, bool useSRGBColorSpace) {
|
||||||
const std::array expectedColorFormats =
|
const std::array expectedColorFormats =
|
||||||
useSRGBColorSpace ?
|
useSRGBColorSpace ?
|
||||||
@@ -123,7 +123,7 @@ constexpr wgpu::TextureFormat selectColorFormat(size_t availableFormatsCount,
|
|||||||
return *firstFoundColorFormat;
|
return *firstFoundColorFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr wgpu::TextureFormat selectDepthFormat(bool depth32FloatStencil8Enabled,
|
[[nodiscard]] constexpr wgpu::TextureFormat selectDepthFormat(bool depth32FloatStencil8Enabled,
|
||||||
bool needStencil) {
|
bool needStencil) {
|
||||||
if (needStencil) {
|
if (needStencil) {
|
||||||
if (depth32FloatStencil8Enabled) {
|
if (depth32FloatStencil8Enabled) {
|
||||||
@@ -137,7 +137,7 @@ constexpr wgpu::TextureFormat selectDepthFormat(bool depth32FloatStencil8Enabled
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr wgpu::PresentMode selectPresentMode(size_t availablePresentModesCount,
|
[[nodiscard]] constexpr wgpu::PresentMode selectPresentMode(size_t availablePresentModesCount,
|
||||||
wgpu::PresentMode const* availablePresentModes) {
|
wgpu::PresentMode const* availablePresentModes) {
|
||||||
// Verify that our chosen present mode is supported. In practice all devices support the FIFO
|
// Verify that our chosen present mode is supported. In practice all devices support the FIFO
|
||||||
// mode, but we check for it anyway for completeness. (and to avoid validation warnings)
|
// mode, but we check for it anyway for completeness. (and to avoid validation warnings)
|
||||||
@@ -151,7 +151,7 @@ constexpr wgpu::PresentMode selectPresentMode(size_t availablePresentModesCount,
|
|||||||
return desiredPresentMode;
|
return desiredPresentMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr wgpu::CompositeAlphaMode selectAlphaMode(size_t availableAlphaModesCount,
|
[[nodiscard]] constexpr wgpu::CompositeAlphaMode selectAlphaMode(size_t availableAlphaModesCount,
|
||||||
wgpu::CompositeAlphaMode const* availableAlphaModes) {
|
wgpu::CompositeAlphaMode const* availableAlphaModes) {
|
||||||
bool autoAvailable = false;
|
bool autoAvailable = false;
|
||||||
bool inheritAvailable = false;
|
bool inheritAvailable = false;
|
||||||
@@ -222,13 +222,58 @@ void initConfig(wgpu::SurfaceConfiguration& config, wgpu::Device const& device,
|
|||||||
config.alphaMode = selectAlphaMode(capabilities.alphaModeCount, capabilities.alphaModes);
|
config.alphaMode = selectAlphaMode(capabilities.alphaModeCount, capabilities.alphaModes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] wgpu::Texture createDepthTexture(wgpu::Device const& device,
|
||||||
|
wgpu::Extent2D const& extent, wgpu::TextureFormat depthFormat) {
|
||||||
|
wgpu::TextureDescriptor descriptor{ .label = "depth_texture",
|
||||||
|
.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment,
|
||||||
|
.dimension = wgpu::TextureDimension::e2D,
|
||||||
|
.size = { .width = extent.width, .height = extent.height, .depthOrArrayLayers = 1 },
|
||||||
|
.format = depthFormat,
|
||||||
|
.mipLevelCount = 1,
|
||||||
|
.sampleCount = 1,
|
||||||
|
.viewFormatCount = 1,
|
||||||
|
.viewFormats = &depthFormat
|
||||||
|
};
|
||||||
|
wgpu::Texture depthTexture = device.CreateTexture(&descriptor);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(depthTexture) << "Failed to create depth texture with width "
|
||||||
|
<< extent.width << " and height " << extent.height;
|
||||||
|
return depthTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] wgpu::TextureView createDepthTextureView(wgpu::Texture const& depthTexture,
|
||||||
|
wgpu::TextureFormat depthFormat, bool needStencil) {
|
||||||
|
wgpu::TextureViewDescriptor descriptor{
|
||||||
|
.label = "depth_texture_view",
|
||||||
|
.format = depthFormat,
|
||||||
|
.dimension = wgpu::TextureViewDimension::e2D,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.mipLevelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.arrayLayerCount = 1,
|
||||||
|
.aspect = wgpu::TextureAspect::DepthOnly,
|
||||||
|
.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment
|
||||||
|
};
|
||||||
|
if (needStencil) {
|
||||||
|
descriptor.aspect = wgpu::TextureAspect::All;
|
||||||
|
}
|
||||||
|
wgpu::TextureView depthTextureView = depthTexture.CreateView(&descriptor);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(depthTextureView) << "Failed to create depth texture view";
|
||||||
|
return depthTextureView;
|
||||||
|
}
|
||||||
|
|
||||||
}// namespace
|
}// namespace
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
WebGPUSwapChain::WebGPUSwapChain(wgpu::Surface&& surface, wgpu::Extent2D const& surfaceSize,
|
WebGPUSwapChain::WebGPUSwapChain(wgpu::Surface&& surface, wgpu::Extent2D const& surfaceSize,
|
||||||
wgpu::Adapter const& adapter, wgpu::Device const& device, uint64_t flags)
|
wgpu::Adapter const& adapter, wgpu::Device const& device, uint64_t flags)
|
||||||
: mSurface(surface) {
|
: mDevice(device),
|
||||||
|
mSurface(surface),
|
||||||
|
mNeedStencil((flags & SWAP_CHAIN_HAS_STENCIL_BUFFER) != 0),
|
||||||
|
mDepthFormat(selectDepthFormat(device.HasFeature(wgpu::FeatureName::Depth32FloatStencil8),
|
||||||
|
mNeedStencil)),
|
||||||
|
mDepthTexture(createDepthTexture(device, surfaceSize, mDepthFormat)),
|
||||||
|
mDepthTextureView(createDepthTextureView(mDepthTexture, mDepthFormat, mNeedStencil)) {
|
||||||
wgpu::SurfaceCapabilities capabilities = {};
|
wgpu::SurfaceCapabilities capabilities = {};
|
||||||
if (!mSurface.GetCapabilities(adapter, &capabilities)) {
|
if (!mSurface.GetCapabilities(adapter, &capabilities)) {
|
||||||
FWGPU_LOGW << "Failed to get WebGPU surface capabilities" << utils::io::endl;
|
FWGPU_LOGW << "Failed to get WebGPU surface capabilities" << utils::io::endl;
|
||||||
@@ -238,19 +283,14 @@ WebGPUSwapChain::WebGPUSwapChain(wgpu::Surface&& surface, wgpu::Extent2D const&
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
const bool useSRGBColorSpace = (flags & SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) != 0;
|
const bool useSRGBColorSpace = (flags & SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) != 0;
|
||||||
const bool needStencil = (flags & SWAP_CHAIN_HAS_STENCIL_BUFFER) != 0;
|
|
||||||
initConfig(mConfig, device, capabilities, surfaceSize, useSRGBColorSpace);
|
initConfig(mConfig, device, capabilities, surfaceSize, useSRGBColorSpace);
|
||||||
mDepthFormat = selectDepthFormat(device.HasFeature(wgpu::FeatureName::Depth32FloatStencil8),
|
|
||||||
needStencil);
|
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||||
printSurfaceConfiguration(mConfig, mDepthFormat);
|
printSurfaceConfiguration(mConfig, mDepthFormat);
|
||||||
#endif
|
#endif
|
||||||
mSurface.Configure(&mConfig);
|
mSurface.Configure(&mConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
WebGPUSwapChain::~WebGPUSwapChain() {
|
WebGPUSwapChain::~WebGPUSwapChain() { mSurface.Unconfigure(); }
|
||||||
mSurface.Unconfigure();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebGPUSwapChain::setExtent(wgpu::Extent2D const& currentSurfaceSize) {
|
void WebGPUSwapChain::setExtent(wgpu::Extent2D const& currentSurfaceSize) {
|
||||||
FILAMENT_CHECK_POSTCONDITION(currentSurfaceSize.width > 0 || currentSurfaceSize.height > 0)
|
FILAMENT_CHECK_POSTCONDITION(currentSurfaceSize.width > 0 || currentSurfaceSize.height > 0)
|
||||||
@@ -267,6 +307,8 @@ void WebGPUSwapChain::setExtent(wgpu::Extent2D const& currentSurfaceSize) {
|
|||||||
// TODO we may need to ensure no surface texture is in flight when we do this. some
|
// TODO we may need to ensure no surface texture is in flight when we do this. some
|
||||||
// synchronization may be necessary
|
// synchronization may be necessary
|
||||||
mSurface.Configure(&mConfig);
|
mSurface.Configure(&mConfig);
|
||||||
|
mDepthTexture = createDepthTexture(mDevice, currentSurfaceSize, mDepthFormat);
|
||||||
|
mDepthTextureView = createDepthTextureView(mDepthTexture, mDepthFormat, mNeedStencil);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,14 +38,20 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] wgpu::TextureView getCurrentSurfaceTextureView(wgpu::Extent2D const&);
|
[[nodiscard]] wgpu::TextureView getCurrentSurfaceTextureView(wgpu::Extent2D const&);
|
||||||
|
|
||||||
|
[[nodiscard]] wgpu::TextureView getDepthTextureView() const { return mDepthTextureView; }
|
||||||
|
|
||||||
void present();
|
void present();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setExtent(wgpu::Extent2D const&);
|
void setExtent(wgpu::Extent2D const&);
|
||||||
|
|
||||||
|
wgpu::Device mDevice = nullptr;
|
||||||
wgpu::Surface mSurface = {};
|
wgpu::Surface mSurface = {};
|
||||||
wgpu::SurfaceConfiguration mConfig = {};
|
wgpu::SurfaceConfiguration mConfig = {};
|
||||||
|
bool mNeedStencil = false;
|
||||||
wgpu::TextureFormat mDepthFormat = wgpu::TextureFormat::Undefined;
|
wgpu::TextureFormat mDepthFormat = wgpu::TextureFormat::Undefined;
|
||||||
|
wgpu::Texture mDepthTexture = nullptr;
|
||||||
|
wgpu::TextureView mDepthTextureView = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace filament::backend
|
} // namespace filament::backend
|
||||||
|
|||||||
@@ -99,22 +99,45 @@ wgpu::Adapter WebGPUPlatform::requestAdapter(wgpu::Surface const& surface) {
|
|||||||
|
|
||||||
wgpu::Device WebGPUPlatform::requestDevice(wgpu::Adapter const& adapter) {
|
wgpu::Device WebGPUPlatform::requestDevice(wgpu::Adapter const& adapter) {
|
||||||
// TODO consider passing limits
|
// TODO consider passing limits
|
||||||
constexpr std::array desiredFeatures = {
|
constexpr std::array optionalFeatures = { wgpu::FeatureName::DepthClipControl,
|
||||||
wgpu::FeatureName::DepthClipControl,
|
wgpu::FeatureName::Depth32FloatStencil8, wgpu::FeatureName::CoreFeaturesAndLimits };
|
||||||
wgpu::FeatureName::Depth32FloatStencil8,
|
|
||||||
wgpu::FeatureName::CoreFeaturesAndLimits };
|
constexpr std::array requiredFeatures = { wgpu::FeatureName::TransientAttachments };
|
||||||
std::vector<wgpu::FeatureName> requiredFeatures;
|
|
||||||
requiredFeatures.reserve(desiredFeatures.size());
|
|
||||||
wgpu::SupportedFeatures supportedFeatures;
|
wgpu::SupportedFeatures supportedFeatures;
|
||||||
adapter.GetFeatures(&supportedFeatures);
|
adapter.GetFeatures(&supportedFeatures);
|
||||||
|
|
||||||
|
std::vector<wgpu::FeatureName> enabledFeatures;
|
||||||
|
enabledFeatures.reserve(requiredFeatures.size() + optionalFeatures.size());
|
||||||
|
|
||||||
std::set_intersection(supportedFeatures.features,
|
std::set_intersection(supportedFeatures.features,
|
||||||
supportedFeatures.features + supportedFeatures.featureCount, desiredFeatures.begin(),
|
supportedFeatures.features + supportedFeatures.featureCount, requiredFeatures.begin(),
|
||||||
desiredFeatures.end(), std::back_inserter(requiredFeatures));
|
requiredFeatures.end(), std::back_inserter(enabledFeatures));
|
||||||
|
|
||||||
|
if (enabledFeatures.size() != requiredFeatures.size()) {
|
||||||
|
std::vector<wgpu::FeatureName> missingFeatures;
|
||||||
|
std::set_difference(requiredFeatures.begin(), requiredFeatures.end(),
|
||||||
|
supportedFeatures.features,
|
||||||
|
supportedFeatures.features + supportedFeatures.featureCount,
|
||||||
|
std::back_inserter(missingFeatures));
|
||||||
|
|
||||||
|
std::stringstream missingFeaturesStream{};
|
||||||
|
for (const auto& entry: missingFeatures) {
|
||||||
|
missingFeaturesStream << std::to_string(static_cast<uint32_t>(entry)) << " ";
|
||||||
|
}
|
||||||
|
PANIC_POSTCONDITION("Some required features are not available %s/n",
|
||||||
|
missingFeaturesStream.str().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set_intersection(supportedFeatures.features,
|
||||||
|
supportedFeatures.features + supportedFeatures.featureCount, optionalFeatures.begin(),
|
||||||
|
optionalFeatures.end(), std::back_inserter(enabledFeatures));
|
||||||
|
|
||||||
wgpu::DeviceDescriptor deviceDescriptor{};
|
wgpu::DeviceDescriptor deviceDescriptor{};
|
||||||
deviceDescriptor.label = "graphics_device";
|
deviceDescriptor.label = "graphics_device";
|
||||||
deviceDescriptor.defaultQueue.label = "default_queue";
|
deviceDescriptor.defaultQueue.label = "default_queue";
|
||||||
deviceDescriptor.requiredFeatureCount = requiredFeatures.size();
|
deviceDescriptor.requiredFeatureCount = enabledFeatures.size();
|
||||||
deviceDescriptor.requiredFeatures = requiredFeatures.data();
|
deviceDescriptor.requiredFeatures = enabledFeatures.data();
|
||||||
deviceDescriptor.SetDeviceLostCallback(wgpu::CallbackMode::AllowSpontaneous,
|
deviceDescriptor.SetDeviceLostCallback(wgpu::CallbackMode::AllowSpontaneous,
|
||||||
[](wgpu::Device const&, wgpu::DeviceLostReason const& reason,
|
[](wgpu::Device const&, wgpu::DeviceLostReason const& reason,
|
||||||
wgpu::StringView message) {
|
wgpu::StringView message) {
|
||||||
|
|||||||
@@ -21,6 +21,9 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
|
||||||
#include "backend/Handle.h"
|
#include "backend/Handle.h"
|
||||||
#include "backend/DriverApiForward.h"
|
#include "backend/DriverApiForward.h"
|
||||||
#include "BackendTest.h"
|
#include "BackendTest.h"
|
||||||
@@ -71,6 +74,7 @@ private:
|
|||||||
|
|
||||||
template <typename HandleType>
|
template <typename HandleType>
|
||||||
filament::backend::Handle<HandleType> Cleanup::add(filament::backend::Handle<HandleType> handle) {
|
filament::backend::Handle<HandleType> Cleanup::add(filament::backend::Handle<HandleType> handle) {
|
||||||
|
EXPECT_THAT(handle, ::testing::IsTrue()) << "Added a null handle to clean up.";
|
||||||
addInternal(handle);
|
addInternal(handle);
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ Shader::Shader(DriverApi& api, Cleanup& cleanup, ShaderConfig config) : mCleanup
|
|||||||
// This assumes that the uniforms will all be in a single descriptor set at index 1.
|
// This assumes that the uniforms will all be in a single descriptor set at index 1.
|
||||||
// If there are shaders with uniforms in other sets then ShaderConfig will need to be expanded
|
// If there are shaders with uniforms in other sets then ShaderConfig will need to be expanded
|
||||||
// to accommodate that.
|
// to accommodate that.
|
||||||
size_t kDescriptorSetIndex = 1;
|
size_t kDescriptorSetIndex = 0;
|
||||||
filamat::DescriptorSets descriptors;
|
filamat::DescriptorSets descriptors;
|
||||||
descriptors[kDescriptorSetIndex] = filamat::DescriptorSetInfo(config.uniforms.size());
|
descriptors[kDescriptorSetIndex] = filamat::DescriptorSetInfo(config.uniforms.size());
|
||||||
for (unsigned char i = 0; i < config.uniforms.size(); ++i) {
|
for (unsigned char i = 0; i < config.uniforms.size(); ++i) {
|
||||||
@@ -52,7 +52,7 @@ Shader::Shader(DriverApi& api, Cleanup& cleanup, ShaderConfig config) : mCleanup
|
|||||||
config.uniforms[i].name,
|
config.uniforms[i].name,
|
||||||
config.uniforms[i].type.value_or(DescriptorType::UNIFORM_BUFFER), i };
|
config.uniforms[i].type.value_or(DescriptorType::UNIFORM_BUFFER), i };
|
||||||
}
|
}
|
||||||
prog.descriptorBindings(1, bindingsInfo);
|
prog.descriptorBindings(0, bindingsInfo);
|
||||||
mProgram = cleanup.add(api.createProgram(std::move(prog)));
|
mProgram = cleanup.add(api.createProgram(std::move(prog)));
|
||||||
|
|
||||||
if (!kLayouts.empty()) {
|
if (!kLayouts.empty()) {
|
||||||
@@ -66,10 +66,15 @@ filament::backend::DescriptorSetHandle Shader::createDescriptorSet(DriverApi& ap
|
|||||||
}
|
}
|
||||||
|
|
||||||
filament::backend::ProgramHandle Shader::getProgram() const {
|
filament::backend::ProgramHandle Shader::getProgram() const {
|
||||||
|
assert(mProgram);
|
||||||
|
EXPECT_THAT(mProgram, ::testing::IsTrue())
|
||||||
|
<< "Shader program accessed despite being null.";
|
||||||
return mProgram;
|
return mProgram;
|
||||||
}
|
}
|
||||||
|
|
||||||
filament::backend::DescriptorSetLayoutHandle Shader::getDescriptorSetLayout() const {
|
filament::backend::DescriptorSetLayoutHandle Shader::getDescriptorSetLayout() const {
|
||||||
|
EXPECT_THAT(mDescriptorSetLayout, ::testing::IsTrue())
|
||||||
|
<< "Shader descriptor set layout accessed despite being null.";
|
||||||
return mDescriptorSetLayout;
|
return mDescriptorSetLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ ResolvedUniformBindingConfig UniformBindingConfig::resolve() {
|
|||||||
.dataSize = resolvedDataSize,
|
.dataSize = resolvedDataSize,
|
||||||
.bufferSize = bufferSize.value_or(resolvedDataSize),
|
.bufferSize = bufferSize.value_or(resolvedDataSize),
|
||||||
.byteOffset = byteOffset.value_or(0),
|
.byteOffset = byteOffset.value_or(0),
|
||||||
.set = set.value_or(1),
|
.set = set.value_or(0),
|
||||||
.binding = binding.value_or(0),
|
.binding = binding.value_or(0),
|
||||||
.descriptorSet = descriptorSet
|
.descriptorSet = descriptorSet
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ std::optional<std::string> GetGlslUniform(ShaderUniformType type) {
|
|||||||
}
|
}
|
||||||
case ShaderUniformType::Simple: {
|
case ShaderUniformType::Simple: {
|
||||||
return R"(
|
return R"(
|
||||||
layout(binding = 0, set = 1) uniform Params {
|
layout(binding = 0, set = 0) uniform Params {
|
||||||
highp vec4 color;
|
highp vec4 color;
|
||||||
// Use scaleMinusOne instead of scale so that a 0 initialized value is a good default
|
// Use scaleMinusOne instead of scale so that a 0 initialized value is a good default
|
||||||
highp vec4 scaleMinusOne;
|
highp vec4 scaleMinusOne;
|
||||||
@@ -148,7 +148,7 @@ layout(binding = 0, set = 1) uniform Params {
|
|||||||
}
|
}
|
||||||
case ShaderUniformType::SimpleWithPadding: {
|
case ShaderUniformType::SimpleWithPadding: {
|
||||||
return R"(
|
return R"(
|
||||||
layout(binding = 0, set = 1) uniform Params {
|
layout(binding = 0, set = 0) uniform Params {
|
||||||
highp vec4 padding[4]; // offset of 64 bytes
|
highp vec4 padding[4]; // offset of 64 bytes
|
||||||
|
|
||||||
highp vec4 color;
|
highp vec4 color;
|
||||||
@@ -160,7 +160,7 @@ layout(binding = 0, set = 1) uniform Params {
|
|||||||
}
|
}
|
||||||
case ShaderUniformType::Sampler: {
|
case ShaderUniformType::Sampler: {
|
||||||
return R"(
|
return R"(
|
||||||
layout(location = 0, set = 1) uniform sampler2D test_tex;
|
layout(location = 0, set = 0) uniform sampler2D test_tex;
|
||||||
)";
|
)";
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -20,7 +20,8 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include "BackendTest.h"
|
#include "BackendTest.h"
|
||||||
|
|
||||||
// skipEnvironment must be a test::SkipEnvironment
|
// skipEnvironment must be a test::SkipEnvironment or something that can be passed to the type's
|
||||||
|
// constructor
|
||||||
// rationale must be a string
|
// rationale must be a string
|
||||||
#define SKIP_IF(skipEnvironment, rationale) \
|
#define SKIP_IF(skipEnvironment, rationale) \
|
||||||
do { \
|
do { \
|
||||||
@@ -31,6 +32,17 @@ do {
|
|||||||
} \
|
} \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
|
#define FAIL_IF(skipEnvironment, rationale) \
|
||||||
|
do { \
|
||||||
|
SkipEnvironment skip(skipEnvironment); \
|
||||||
|
if (skip.matches()) { \
|
||||||
|
GTEST_FAIL() \
|
||||||
|
<< "Failing test as the " << skip.describe() << "\n" \
|
||||||
|
<< " This test should be able to succeed but it needs to fail early because" \
|
||||||
|
<< rationale; \
|
||||||
|
} \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
namespace test {
|
namespace test {
|
||||||
|
|
||||||
struct SkipEnvironment {
|
struct SkipEnvironment {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "Lifetimes.h"
|
#include "Lifetimes.h"
|
||||||
#include "Shader.h"
|
#include "Shader.h"
|
||||||
#include "SharedShaders.h"
|
#include "SharedShaders.h"
|
||||||
|
#include "Skip.h"
|
||||||
#include "TrianglePrimitive.h"
|
#include "TrianglePrimitive.h"
|
||||||
|
|
||||||
#include <utils/Hash.h>
|
#include <utils/Hash.h>
|
||||||
@@ -309,7 +310,7 @@ TEST_F(BlitTest, ColorResolve) {
|
|||||||
|
|
||||||
PipelineState state = {};
|
PipelineState state = {};
|
||||||
state.program = shader.getProgram();
|
state.program = shader.getProgram();
|
||||||
state.pipelineLayout.setLayout[1] = { shader.getDescriptorSetLayout() };
|
state.pipelineLayout.setLayout[0] = { shader.getDescriptorSetLayout() };
|
||||||
state.rasterState.colorWrite = true;
|
state.rasterState.colorWrite = true;
|
||||||
state.rasterState.depthWrite = false;
|
state.rasterState.depthWrite = false;
|
||||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||||
@@ -489,6 +490,7 @@ TEST_F(BlitTest, BlitRegion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BlitTest, BlitRegionToSwapChain) {
|
TEST_F(BlitTest, BlitRegionToSwapChain) {
|
||||||
|
FAIL_IF(Backend::VULKAN, "Crashes due to not finding color attachment");
|
||||||
auto& api = getDriverApi();
|
auto& api = getDriverApi();
|
||||||
mCleanup.addPostCall([&]() { executeCommands(); });
|
mCleanup.addPostCall([&]() { executeCommands(); });
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ TEST_F(BufferUpdatesTest, VertexBufferUpdate) {
|
|||||||
|
|
||||||
PipelineState state;
|
PipelineState state;
|
||||||
state.program = shader.getProgram();
|
state.program = shader.getProgram();
|
||||||
state.pipelineLayout.setLayout[1] = { shader.getDescriptorSetLayout() };
|
state.pipelineLayout.setLayout[0] = { shader.getDescriptorSetLayout() };
|
||||||
state.rasterState.colorWrite = true;
|
state.rasterState.colorWrite = true;
|
||||||
state.rasterState.depthWrite = false;
|
state.rasterState.depthWrite = false;
|
||||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||||
@@ -199,8 +199,8 @@ TEST_F(BufferUpdatesTest, BufferObjectUpdateWithOffset) {
|
|||||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||||
params.viewport.height = 512;
|
params.viewport.height = 512;
|
||||||
params.viewport.width = 512;
|
params.viewport.width = 512;
|
||||||
renderTriangle({{ DescriptorSetLayoutHandle{}, shader.getDescriptorSetLayout() }},
|
renderTriangle({ { shader.getDescriptorSetLayout() } }, renderTarget, swapChain,
|
||||||
renderTarget, swapChain, shader.getProgram(), params);
|
shader.getProgram(), params);
|
||||||
|
|
||||||
// Upload uniforms for the second triangle. To test partial buffer updates, we'll only update
|
// Upload uniforms for the second triangle. To test partial buffer updates, we'll only update
|
||||||
// color.b, color.a, scaleMinusOne, offset.x, and offset.y.
|
// color.b, color.a, scaleMinusOne, offset.x, and offset.y.
|
||||||
@@ -218,7 +218,7 @@ TEST_F(BufferUpdatesTest, BufferObjectUpdateWithOffset) {
|
|||||||
|
|
||||||
params.flags.clear = TargetBufferFlags::NONE;
|
params.flags.clear = TargetBufferFlags::NONE;
|
||||||
params.flags.discardStart = TargetBufferFlags::NONE;
|
params.flags.discardStart = TargetBufferFlags::NONE;
|
||||||
renderTriangle({{ DescriptorSetLayoutHandle{}, shader.getDescriptorSetLayout() }},
|
renderTriangle({{ shader.getDescriptorSetLayout() }},
|
||||||
renderTarget, swapChain, shader.getProgram(), params);
|
renderTarget, swapChain, shader.getProgram(), params);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -57,9 +57,9 @@ layout(location = 0) out vec4 fragColor;
|
|||||||
|
|
||||||
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
|
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
|
||||||
// This parameter is ignored for other backends.
|
// This parameter is ignored for other backends.
|
||||||
layout(binding = 0, set = 1) uniform sampler2D test_tex;
|
layout(binding = 0, set = 0) uniform sampler2D test_tex;
|
||||||
|
|
||||||
layout(binding = 1, set = 1) uniform Params {
|
layout(binding = 1, set = 0) uniform Params {
|
||||||
highp float fbWidth;
|
highp float fbWidth;
|
||||||
highp float fbHeight;
|
highp float fbHeight;
|
||||||
highp float sourceLevel;
|
highp float sourceLevel;
|
||||||
@@ -167,7 +167,7 @@ TEST_F(BackendTest, FeedbackLoops) {
|
|||||||
state.rasterState.depthWrite = false;
|
state.rasterState.depthWrite = false;
|
||||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||||
state.program = shader.getProgram();
|
state.program = shader.getProgram();
|
||||||
state.pipelineLayout.setLayout[1] = { shader.getDescriptorSetLayout() };
|
state.pipelineLayout.setLayout[0] = { shader.getDescriptorSetLayout() };
|
||||||
|
|
||||||
api.makeCurrent(swapChain, swapChain);
|
api.makeCurrent(swapChain, swapChain);
|
||||||
api.beginFrame(0, 0, 0);
|
api.beginFrame(0, 0, 0);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "Lifetimes.h"
|
#include "Lifetimes.h"
|
||||||
#include "Shader.h"
|
#include "Shader.h"
|
||||||
#include "SharedShaders.h"
|
#include "SharedShaders.h"
|
||||||
|
#include "Skip.h"
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
#include <backend/Handle.h>
|
#include <backend/Handle.h>
|
||||||
@@ -46,7 +47,7 @@ layout(location = 0) out vec4 fragColor;
|
|||||||
|
|
||||||
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
|
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
|
||||||
// This parameter is ignored for other backends.
|
// This parameter is ignored for other backends.
|
||||||
layout(location = 0, set = 1) uniform {samplerType} test_tex;
|
layout(location = 0, set = 0) uniform {samplerType} test_tex;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 fbsize = vec2(512);
|
vec2 fbsize = vec2(512);
|
||||||
@@ -64,7 +65,7 @@ std::string fragmentUpdateImage3DTemplate (R"(#version 450 core
|
|||||||
layout(location = 0) out vec4 fragColor;
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
|
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
|
||||||
layout(location = 0, set = 1) uniform {samplerType} test_tex;
|
layout(location = 0, set = 0) uniform {samplerType} test_tex;
|
||||||
|
|
||||||
float getLayer(in sampler3D s) { return 2.5f / 4.0f; }
|
float getLayer(in sampler3D s) { return 2.5f / 4.0f; }
|
||||||
float getLayer(in sampler2DArray s) { return 2.0f; }
|
float getLayer(in sampler2DArray s) { return 2.0f; }
|
||||||
@@ -85,7 +86,7 @@ std::string fragmentUpdateImageMip (R"(#version 450 core
|
|||||||
layout(location = 0) out vec4 fragColor;
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
|
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
|
||||||
layout(location = 0, set = 1) uniform sampler2D test_tex;
|
layout(location = 0, set = 0) uniform sampler2D test_tex;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 fbsize = vec2(512);
|
vec2 fbsize = vec2(512);
|
||||||
@@ -211,6 +212,7 @@ static SamplerFormat getSamplerFormat(TextureFormat textureFormat) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(LoadImageTest, UpdateImage2D) {
|
TEST_F(LoadImageTest, UpdateImage2D) {
|
||||||
|
FAIL_IF(Backend::VULKAN, "Multiple test cases crash");
|
||||||
|
|
||||||
// All of these test cases should result in the same rendered image, and thus the same hash.
|
// All of these test cases should result in the same rendered image, and thus the same hash.
|
||||||
static const uint32_t expectedHash = 3644679986;
|
static const uint32_t expectedHash = 3644679986;
|
||||||
@@ -334,9 +336,9 @@ TEST_F(LoadImageTest, UpdateImage2D) {
|
|||||||
.filterMag = SamplerMagFilter::NEAREST,
|
.filterMag = SamplerMagFilter::NEAREST,
|
||||||
.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
|
.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
|
||||||
|
|
||||||
api.bindDescriptorSet(descriptorSet, 1, {});
|
api.bindDescriptorSet(descriptorSet, 0, {});
|
||||||
|
|
||||||
renderTriangle({{ DescriptorSetLayoutHandle{}, shader.getDescriptorSetLayout() }},
|
renderTriangle({{ shader.getDescriptorSetLayout() }},
|
||||||
defaultRenderTarget, swapChain, shader.getProgram());
|
defaultRenderTarget, swapChain, shader.getProgram());
|
||||||
|
|
||||||
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
|
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
|
||||||
@@ -409,9 +411,9 @@ TEST_F(LoadImageTest, UpdateImageSRGB) {
|
|||||||
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST
|
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST
|
||||||
});
|
});
|
||||||
|
|
||||||
api.bindDescriptorSet(descriptorSet, 1, {});
|
api.bindDescriptorSet(descriptorSet, 0, {});
|
||||||
|
|
||||||
renderTriangle({{ DescriptorSetLayoutHandle{}, shader.getDescriptorSetLayout() }},
|
renderTriangle({{ shader.getDescriptorSetLayout() }},
|
||||||
defaultRenderTarget, swapChain, shader.getProgram());
|
defaultRenderTarget, swapChain, shader.getProgram());
|
||||||
|
|
||||||
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
|
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
|
||||||
@@ -468,9 +470,9 @@ TEST_F(LoadImageTest, UpdateImageMipLevel) {
|
|||||||
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST
|
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST
|
||||||
});
|
});
|
||||||
|
|
||||||
api.bindDescriptorSet(descriptorSet, 1, {});
|
api.bindDescriptorSet(descriptorSet, 0, {});
|
||||||
|
|
||||||
renderTriangle({{ DescriptorSetLayoutHandle{}, shader.getDescriptorSetLayout() }},
|
renderTriangle({{ shader.getDescriptorSetLayout() }},
|
||||||
defaultRenderTarget, swapChain, shader.getProgram());
|
defaultRenderTarget, swapChain, shader.getProgram());
|
||||||
|
|
||||||
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
|
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
|
||||||
@@ -539,9 +541,9 @@ TEST_F(LoadImageTest, UpdateImage3D) {
|
|||||||
{ .filterMag = SamplerMagFilter::LINEAR,
|
{ .filterMag = SamplerMagFilter::LINEAR,
|
||||||
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST });
|
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST });
|
||||||
|
|
||||||
api.bindDescriptorSet(descriptorSet, 1, {});
|
api.bindDescriptorSet(descriptorSet, 0, {});
|
||||||
|
|
||||||
renderTriangle({ { DescriptorSetLayoutHandle{}, shader.getDescriptorSetLayout() } },
|
renderTriangle({ { shader.getDescriptorSetLayout() } },
|
||||||
defaultRenderTarget, swapChain, shader.getProgram());
|
defaultRenderTarget, swapChain, shader.getProgram());
|
||||||
|
|
||||||
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
|
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ std::string fragmentTexturedLod (R"(#version 450 core
|
|||||||
layout(location = 0) out vec4 fragColor;
|
layout(location = 0) out vec4 fragColor;
|
||||||
layout(location = 0) in vec2 uv;
|
layout(location = 0) in vec2 uv;
|
||||||
|
|
||||||
layout(location = 0, set = 1) uniform sampler2D backend_test_sib_tex;
|
layout(location = 0, set = 0) uniform sampler2D backend_test_sib_tex;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
fragColor = textureLod(backend_test_sib_tex, uv, 1);
|
fragColor = textureLod(backend_test_sib_tex, uv, 1);
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ void main() {
|
|||||||
|
|
||||||
TEST_F(BackendTest, PushConstants) {
|
TEST_F(BackendTest, PushConstants) {
|
||||||
SKIP_IF(Backend::OPENGL, "Push constants not supported on OpenGL");
|
SKIP_IF(Backend::OPENGL, "Push constants not supported on OpenGL");
|
||||||
|
FAIL_IF(Backend::VULKAN, "Crashing due to no program set when setting push constants");
|
||||||
|
|
||||||
auto& api = getDriverApi();
|
auto& api = getDriverApi();
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ Shader createShader(DriverApi& api, Cleanup& cleanup, Backend backend) {
|
|||||||
// Rendering an external image without setting any data should not crash.
|
// Rendering an external image without setting any data should not crash.
|
||||||
TEST_F(BackendTest, RenderExternalImageWithoutSet) {
|
TEST_F(BackendTest, RenderExternalImageWithoutSet) {
|
||||||
SKIP_IF(Backend::METAL, "External images aren't supported in metal");
|
SKIP_IF(Backend::METAL, "External images aren't supported in metal");
|
||||||
|
SKIP_IF(Backend::VULKAN, "External images aren't supported in vulkan");
|
||||||
auto& api = getDriverApi();
|
auto& api = getDriverApi();
|
||||||
Cleanup cleanup(api);
|
Cleanup cleanup(api);
|
||||||
|
|
||||||
@@ -81,7 +82,7 @@ TEST_F(BackendTest, RenderExternalImageWithoutSet) {
|
|||||||
|
|
||||||
PipelineState state;
|
PipelineState state;
|
||||||
state.program = shader.getProgram();
|
state.program = shader.getProgram();
|
||||||
state.pipelineLayout.setLayout[1] = { shader.getDescriptorSetLayout() };
|
state.pipelineLayout.setLayout[0] = { shader.getDescriptorSetLayout() };
|
||||||
state.rasterState.colorWrite = true;
|
state.rasterState.colorWrite = true;
|
||||||
state.rasterState.depthWrite = false;
|
state.rasterState.depthWrite = false;
|
||||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||||
@@ -94,7 +95,7 @@ TEST_F(BackendTest, RenderExternalImageWithoutSet) {
|
|||||||
api.beginFrame(0, 0, 0);
|
api.beginFrame(0, 0, 0);
|
||||||
|
|
||||||
api.updateDescriptorSetTexture(descriptorSet, 0, texture, {});
|
api.updateDescriptorSetTexture(descriptorSet, 0, texture, {});
|
||||||
api.bindDescriptorSet(descriptorSet, 1, {});
|
api.bindDescriptorSet(descriptorSet, 0, {});
|
||||||
|
|
||||||
// Render a triangle.
|
// Render a triangle.
|
||||||
api.beginRenderPass(defaultRenderTarget, params);
|
api.beginRenderPass(defaultRenderTarget, params);
|
||||||
@@ -114,6 +115,7 @@ TEST_F(BackendTest, RenderExternalImageWithoutSet) {
|
|||||||
|
|
||||||
TEST_F(BackendTest, RenderExternalImage) {
|
TEST_F(BackendTest, RenderExternalImage) {
|
||||||
SKIP_IF(Backend::METAL, "External images aren't supported in metal");
|
SKIP_IF(Backend::METAL, "External images aren't supported in metal");
|
||||||
|
SKIP_IF(Backend::VULKAN, "External images aren't supported in vulkan");
|
||||||
auto& api = getDriverApi();
|
auto& api = getDriverApi();
|
||||||
Cleanup cleanup(api);
|
Cleanup cleanup(api);
|
||||||
|
|
||||||
@@ -186,7 +188,7 @@ TEST_F(BackendTest, RenderExternalImage) {
|
|||||||
|
|
||||||
PipelineState state;
|
PipelineState state;
|
||||||
state.program = shader.getProgram();
|
state.program = shader.getProgram();
|
||||||
state.pipelineLayout.setLayout[1] = { shader.getDescriptorSetLayout() };
|
state.pipelineLayout.setLayout[0] = { shader.getDescriptorSetLayout() };
|
||||||
state.rasterState.colorWrite = true;
|
state.rasterState.colorWrite = true;
|
||||||
state.rasterState.depthWrite = false;
|
state.rasterState.depthWrite = false;
|
||||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||||
@@ -197,7 +199,7 @@ TEST_F(BackendTest, RenderExternalImage) {
|
|||||||
api.beginFrame(0, 0, 0);
|
api.beginFrame(0, 0, 0);
|
||||||
|
|
||||||
api.updateDescriptorSetTexture(descriptorSet, 0, texture, {});
|
api.updateDescriptorSetTexture(descriptorSet, 0, texture, {});
|
||||||
api.bindDescriptorSet(descriptorSet, 1, {});
|
api.bindDescriptorSet(descriptorSet, 0, {});
|
||||||
|
|
||||||
// Render a triangle.
|
// Render a triangle.
|
||||||
api.beginRenderPass(defaultRenderTarget, params);
|
api.beginRenderPass(defaultRenderTarget, params);
|
||||||
|
|||||||
@@ -1098,12 +1098,16 @@ void FMaterial::processPushConstants(FEngine&, MaterialParser const* parser) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void FMaterial::precacheDepthVariants(FEngine const& engine) {
|
void FMaterial::precacheDepthVariants(FEngine& engine) {
|
||||||
|
|
||||||
|
bool const disableDepthPrecacheForDefaultMaterial = engine.getDriverApi().isWorkaroundNeeded(
|
||||||
|
Workaround::DISABLE_DEPTH_PRECACHE_FOR_DEFAULT_MATERIAL);
|
||||||
|
|
||||||
// pre-cache all depth variants inside the default material. Note that this should be
|
// pre-cache all depth variants inside the default material. Note that this should be
|
||||||
// entirely optional; if we remove this pre-caching, these variants will be populated
|
// entirely optional; if we remove this pre-caching, these variants will be populated
|
||||||
// later, when/if needed by createAndCacheProgram(). Doing it now potentially uses more
|
// later, when/if needed by createAndCacheProgram(). Doing it now potentially uses more
|
||||||
// memory and increases init time, but reduces hiccups during the first frame.
|
// memory and increases init time, but reduces hiccups during the first frame.
|
||||||
if (UTILS_UNLIKELY(mIsDefaultMaterial)) {
|
if (UTILS_UNLIKELY(mIsDefaultMaterial && !disableDepthPrecacheForDefaultMaterial)) {
|
||||||
const bool stereoSupported = mEngine.getDriverApi().isStereoSupported();
|
const bool stereoSupported = mEngine.getDriverApi().isStereoSupported();
|
||||||
auto const allDepthVariants = VariantUtils::getDepthVariants();
|
auto const allDepthVariants = VariantUtils::getDepthVariants();
|
||||||
for (auto const variant: allDepthVariants) {
|
for (auto const variant: allDepthVariants) {
|
||||||
@@ -1136,6 +1140,7 @@ void FMaterial::precacheDepthVariants(FEngine const& engine) {
|
|||||||
void FMaterial::processDescriptorSets(FEngine& engine, MaterialParser const* const parser) {
|
void FMaterial::processDescriptorSets(FEngine& engine, MaterialParser const* const parser) {
|
||||||
UTILS_UNUSED_IN_RELEASE bool success;
|
UTILS_UNUSED_IN_RELEASE bool success;
|
||||||
|
|
||||||
|
|
||||||
success = parser->getDescriptorBindings(&mProgramDescriptorBindings);
|
success = parser->getDescriptorBindings(&mProgramDescriptorBindings);
|
||||||
assert_invariant(success);
|
assert_invariant(success);
|
||||||
|
|
||||||
@@ -1143,6 +1148,22 @@ void FMaterial::processDescriptorSets(FEngine& engine, MaterialParser const* con
|
|||||||
success = parser->getDescriptorSetLayout(&descriptorSetLayout);
|
success = parser->getDescriptorSetLayout(&descriptorSetLayout);
|
||||||
assert_invariant(success);
|
assert_invariant(success);
|
||||||
|
|
||||||
|
// Setup Labels for debugging
|
||||||
|
utils::CString namestr;
|
||||||
|
utils::StaticString perViewStr = "_perView";
|
||||||
|
utils::StaticString singleStr = "_single";
|
||||||
|
|
||||||
|
parser->getName(&namestr);
|
||||||
|
|
||||||
|
utils::CString singleLabel(namestr.c_str(), namestr.length() + singleStr.length());
|
||||||
|
memccpy(singleLabel.c_str() + namestr.length(), singleStr.c_str(), '\0', singleStr.length());
|
||||||
|
|
||||||
|
utils::CString perViewLabel(namestr.c_str(), namestr.length() + perViewStr.length());
|
||||||
|
memccpy(perViewLabel.c_str() + namestr.length(), perViewStr.c_str(), '\0', perViewStr.length());
|
||||||
|
|
||||||
|
descriptorSetLayout[0].label = namestr;
|
||||||
|
descriptorSetLayout[1].label = perViewLabel;
|
||||||
|
|
||||||
mDescriptorSetLayout = {
|
mDescriptorSetLayout = {
|
||||||
engine.getDescriptorSetLayoutFactory(),
|
engine.getDescriptorSetLayoutFactory(),
|
||||||
engine.getDriverApi(), std::move(descriptorSetLayout[0]) };
|
engine.getDriverApi(), std::move(descriptorSetLayout[0]) };
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ private:
|
|||||||
|
|
||||||
void processPushConstants(FEngine& engine, MaterialParser const* parser);
|
void processPushConstants(FEngine& engine, MaterialParser const* parser);
|
||||||
|
|
||||||
void precacheDepthVariants(FEngine const& engine);
|
void precacheDepthVariants(FEngine& engine);
|
||||||
|
|
||||||
void processDescriptorSets(FEngine& engine, MaterialParser const* parser);
|
void processDescriptorSets(FEngine& engine, MaterialParser const* parser);
|
||||||
|
|
||||||
|
|||||||
@@ -824,6 +824,9 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
|||||||
variant.setDirectionalLighting(view.hasDirectionalLighting());
|
variant.setDirectionalLighting(view.hasDirectionalLighting());
|
||||||
variant.setDynamicLighting(view.hasDynamicLighting());
|
variant.setDynamicLighting(view.hasDynamicLighting());
|
||||||
variant.setFog(view.hasFog());
|
variant.setFog(view.hasFog());
|
||||||
|
// The VSM bit has a different meaning for STANDARD_VARIANT (as opposed to DEPTH_VARIANT),
|
||||||
|
// In the STANDARD_VARIANT case, we are *using* the shadow-map, and the VSM only decides which
|
||||||
|
// type of sampler is used (samplerShadow or sampler2D).
|
||||||
variant.setVsm(view.hasShadowing() && view.getShadowType() != ShadowType::PCF);
|
variant.setVsm(view.hasShadowing() && view.getShadowType() != ShadowType::PCF);
|
||||||
variant.setStereo(view.hasStereo());
|
variant.setStereo(view.hasStereo());
|
||||||
|
|
||||||
@@ -841,7 +844,11 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
|||||||
|
|
||||||
if (view.needsShadowMap()) {
|
if (view.needsShadowMap()) {
|
||||||
Variant shadowVariant(Variant::DEPTH_VARIANT);
|
Variant shadowVariant(Variant::DEPTH_VARIANT);
|
||||||
|
// The VSM bit has a different meaning for DEPTH_VARIANT (as opposed to STANDARD_VARIANT),
|
||||||
|
// In the DEPTH_VARIANT case, we are *generating* the shadow-map, and some computations
|
||||||
|
// are handled differently. In addition, the color buffer is used.
|
||||||
shadowVariant.setVsm(view.getShadowType() == ShadowType::VSM);
|
shadowVariant.setVsm(view.getShadowType() == ShadowType::VSM);
|
||||||
|
|
||||||
auto shadows = view.renderShadowMaps(engine, fg, cameraInfo, mShaderUserTime,
|
auto shadows = view.renderShadowMaps(engine, fg, cameraInfo, mShaderUserTime,
|
||||||
RenderPassBuilder{ commandArena }
|
RenderPassBuilder{ commandArena }
|
||||||
.renderFlags(renderFlags)
|
.renderFlags(renderFlags)
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
Pod::Spec.new do |spec|
|
Pod::Spec.new do |spec|
|
||||||
spec.name = "Filament"
|
spec.name = "Filament"
|
||||||
spec.version = "1.59.3"
|
spec.version = "1.59.4"
|
||||||
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
||||||
spec.homepage = "https://google.github.io/filament"
|
spec.homepage = "https://google.github.io/filament"
|
||||||
spec.authors = "Google LLC."
|
spec.authors = "Google LLC."
|
||||||
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
||||||
spec.platform = :ios, "11.0"
|
spec.platform = :ios, "11.0"
|
||||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.59.3/filament-v1.59.3-ios.tgz" }
|
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.59.4/filament-v1.59.4-ios.tgz" }
|
||||||
|
|
||||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||||
spec.pod_target_xcconfig = {
|
spec.pod_target_xcconfig = {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ struct Variant {
|
|||||||
// DEP: Depth only
|
// DEP: Depth only
|
||||||
// FOG: Fog
|
// FOG: Fog
|
||||||
// PCK: Picking (depth variant only)
|
// PCK: Picking (depth variant only)
|
||||||
// VSM: Variance shadow maps
|
// VSM: Variance shadow maps (depth) / sampler type (standard)
|
||||||
// STE: Instanced stereo rendering
|
// STE: Instanced stereo rendering
|
||||||
//
|
//
|
||||||
// X: either 1 or 0
|
// X: either 1 or 0
|
||||||
@@ -75,7 +75,8 @@ struct Variant {
|
|||||||
// | STE | VSM | PCK | 1 | SKN | 0 | 0 | 0 | 16 - 4 = 12
|
// | STE | VSM | PCK | 1 | SKN | 0 | 0 | 0 | 16 - 4 = 12
|
||||||
// +-----+-----+-----+-----+-----+-----+-----+-----+
|
// +-----+-----+-----+-----+-----+-----+-----+-----+
|
||||||
// Vertex depth X X 0 1 X 0 0 0
|
// Vertex depth X X 0 1 X 0 0 0
|
||||||
// Fragment depth 0 X X 1 0 0 0 0
|
// Fragment depth 0 0 X 1 0 0 0 0
|
||||||
|
// Fragment depth 0 1 0 1 0 0 0 0
|
||||||
// Reserved X 1 1 1 X 0 0 0 [ -4]
|
// Reserved X 1 1 1 X 0 0 0 [ -4]
|
||||||
//
|
//
|
||||||
// 96 variants used, 160 reserved (256 - 96)
|
// 96 variants used, 160 reserved (256 - 96)
|
||||||
@@ -95,7 +96,7 @@ struct Variant {
|
|||||||
static constexpr type_t DEP = 0x10; // depth only variants
|
static constexpr type_t DEP = 0x10; // depth only variants
|
||||||
static constexpr type_t FOG = 0x20; // fog (standard)
|
static constexpr type_t FOG = 0x20; // fog (standard)
|
||||||
static constexpr type_t PCK = 0x20; // picking (depth)
|
static constexpr type_t PCK = 0x20; // picking (depth)
|
||||||
static constexpr type_t VSM = 0x40; // variance shadow maps
|
static constexpr type_t VSM = 0x40; // variance shadow maps / sampler type
|
||||||
static constexpr type_t STE = 0x80; // instanced stereo
|
static constexpr type_t STE = 0x80; // instanced stereo
|
||||||
|
|
||||||
// special variants (variants that use the reserved space)
|
// special variants (variants that use the reserved space)
|
||||||
@@ -113,21 +114,21 @@ struct Variant {
|
|||||||
static constexpr type_t UNLIT_MASK = STE | SKN | FOG;
|
static constexpr type_t UNLIT_MASK = STE | SKN | FOG;
|
||||||
|
|
||||||
// returns raw variant bits
|
// returns raw variant bits
|
||||||
inline bool hasDirectionalLighting() const noexcept { return key & DIR; }
|
bool hasDirectionalLighting() const noexcept { return key & DIR; }
|
||||||
inline bool hasDynamicLighting() const noexcept { return key & DYN; }
|
bool hasDynamicLighting() const noexcept { return key & DYN; }
|
||||||
inline bool hasSkinningOrMorphing() const noexcept { return key & SKN; }
|
bool hasSkinningOrMorphing() const noexcept { return key & SKN; }
|
||||||
inline bool hasStereo() const noexcept { return key & STE; }
|
bool hasStereo() const noexcept { return key & STE; }
|
||||||
|
|
||||||
inline void setDirectionalLighting(bool v) noexcept { set(v, DIR); }
|
void setDirectionalLighting(bool v) noexcept { set(v, DIR); }
|
||||||
inline void setDynamicLighting(bool v) noexcept { set(v, DYN); }
|
void setDynamicLighting(bool v) noexcept { set(v, DYN); }
|
||||||
inline void setShadowReceiver(bool v) noexcept { set(v, SRE); }
|
void setShadowReceiver(bool v) noexcept { set(v, SRE); }
|
||||||
inline void setSkinning(bool v) noexcept { set(v, SKN); }
|
void setSkinning(bool v) noexcept { set(v, SKN); }
|
||||||
inline void setFog(bool v) noexcept { set(v, FOG); }
|
void setFog(bool v) noexcept { set(v, FOG); }
|
||||||
inline void setPicking(bool v) noexcept { set(v, PCK); }
|
void setPicking(bool v) noexcept { set(v, PCK); }
|
||||||
inline void setVsm(bool v) noexcept { set(v, VSM); }
|
void setVsm(bool v) noexcept { set(v, VSM); }
|
||||||
inline void setStereo(bool v) noexcept { set(v, STE); }
|
void setStereo(bool v) noexcept { set(v, STE); }
|
||||||
|
|
||||||
inline static constexpr bool isValidDepthVariant(Variant variant) noexcept {
|
static constexpr bool isValidDepthVariant(Variant variant) noexcept {
|
||||||
// Can't have VSM and PICKING together with DEPTH variants
|
// Can't have VSM and PICKING together with DEPTH variants
|
||||||
constexpr type_t RESERVED_MASK = VSM | PCK | DEP | SRE | DYN | DIR;
|
constexpr type_t RESERVED_MASK = VSM | PCK | DEP | SRE | DYN | DIR;
|
||||||
constexpr type_t RESERVED_VALUE = VSM | PCK | DEP;
|
constexpr type_t RESERVED_VALUE = VSM | PCK | DEP;
|
||||||
@@ -135,7 +136,7 @@ struct Variant {
|
|||||||
((variant.key & RESERVED_MASK) != RESERVED_VALUE);
|
((variant.key & RESERVED_MASK) != RESERVED_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static constexpr bool isValidStandardVariant(Variant variant) noexcept {
|
static constexpr bool isValidStandardVariant(Variant variant) noexcept {
|
||||||
// can't have shadow receiver if we don't have any lighting
|
// can't have shadow receiver if we don't have any lighting
|
||||||
constexpr type_t RESERVED0_MASK = VSM | FOG | SRE | DYN | DIR;
|
constexpr type_t RESERVED0_MASK = VSM | FOG | SRE | DYN | DIR;
|
||||||
constexpr type_t RESERVED0_VALUE = VSM | FOG | SRE;
|
constexpr type_t RESERVED0_VALUE = VSM | FOG | SRE;
|
||||||
@@ -154,11 +155,11 @@ struct Variant {
|
|||||||
((variant.key & RESERVED2_MASK) != RESERVED2_VALUE);
|
((variant.key & RESERVED2_MASK) != RESERVED2_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static constexpr bool isVertexVariant(Variant variant) noexcept {
|
static constexpr bool isVertexVariant(Variant variant) noexcept {
|
||||||
return filterVariantVertex(variant) == variant;
|
return filterVariantVertex(variant) == variant;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static constexpr bool isFragmentVariant(Variant variant) noexcept {
|
static constexpr bool isFragmentVariant(Variant variant) noexcept {
|
||||||
return filterVariantFragment(variant) == variant;
|
return filterVariantFragment(variant) == variant;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,32 +171,32 @@ struct Variant {
|
|||||||
return isValidStandardVariant(variant) || isValidDepthVariant(variant);
|
return isValidStandardVariant(variant) || isValidDepthVariant(variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static constexpr bool isSSRVariant(Variant variant) noexcept {
|
static constexpr bool isSSRVariant(Variant variant) noexcept {
|
||||||
return (variant.key & (STE | VSM | DEP | SRE | DYN | DIR)) == (VSM | SRE);
|
return (variant.key & (STE | VSM | DEP | SRE | DYN | DIR)) == (VSM | SRE);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static constexpr bool isVSMVariant(Variant variant) noexcept {
|
static constexpr bool isVSMVariant(Variant variant) noexcept {
|
||||||
return !isSSRVariant(variant) && ((variant.key & VSM) == VSM);
|
return !isSSRVariant(variant) && ((variant.key & VSM) == VSM);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static constexpr bool isShadowReceiverVariant(Variant variant) noexcept {
|
static constexpr bool isShadowReceiverVariant(Variant variant) noexcept {
|
||||||
return !isSSRVariant(variant) && ((variant.key & SRE) == SRE);
|
return !isSSRVariant(variant) && ((variant.key & SRE) == SRE);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static constexpr bool isFogVariant(Variant variant) noexcept {
|
static constexpr bool isFogVariant(Variant variant) noexcept {
|
||||||
return (variant.key & (FOG | DEP)) == FOG;
|
return (variant.key & (FOG | DEP)) == FOG;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static constexpr bool isPickingVariant(Variant variant) noexcept {
|
static constexpr bool isPickingVariant(Variant variant) noexcept {
|
||||||
return (variant.key & (PCK | DEP)) == (PCK | DEP);
|
return (variant.key & (PCK | DEP)) == (PCK | DEP);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static constexpr bool isStereoVariant(Variant variant) noexcept {
|
static constexpr bool isStereoVariant(Variant variant) noexcept {
|
||||||
return (variant.key & STE) == STE;
|
return (variant.key & STE) == STE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr Variant filterVariantVertex(Variant variant) noexcept {
|
static constexpr Variant filterVariantVertex(Variant variant) noexcept {
|
||||||
// filter out vertex variants that are not needed. For e.g. fog doesn't affect the
|
// Filter out vertex variants that are not needed. For e.g. fog doesn't affect the
|
||||||
// vertex shader.
|
// vertex shader.
|
||||||
if ((variant.key & STANDARD_MASK) == STANDARD_VARIANT) {
|
if ((variant.key & STANDARD_MASK) == STANDARD_VARIANT) {
|
||||||
if (isSSRVariant(variant)) {
|
if (isSSRVariant(variant)) {
|
||||||
|
|||||||
@@ -33,11 +33,13 @@ namespace filament::descriptor_sets {
|
|||||||
|
|
||||||
using namespace backend;
|
using namespace backend;
|
||||||
|
|
||||||
static DescriptorSetLayout const postProcessDescriptorSetLayout{{
|
static DescriptorSetLayout const postProcessDescriptorSetLayout{
|
||||||
|
utils::StaticString("postProcess"),{
|
||||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
|
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
|
||||||
}};
|
}};
|
||||||
|
|
||||||
static DescriptorSetLayout const depthVariantDescriptorSetLayout{{
|
static DescriptorSetLayout const depthVariantDescriptorSetLayout{
|
||||||
|
utils::StaticString("depthVariant"),{
|
||||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
|
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
|
||||||
}};
|
}};
|
||||||
|
|
||||||
@@ -46,14 +48,16 @@ static DescriptorSetLayout const depthVariantDescriptorSetLayout{{
|
|||||||
// dedicated SSR vertex shader), which uses perViewDescriptorSetLayout.
|
// dedicated SSR vertex shader), which uses perViewDescriptorSetLayout.
|
||||||
// This means that PerViewBindingPoints::SHADOWS must be in the layout even though it's not used
|
// This means that PerViewBindingPoints::SHADOWS must be in the layout even though it's not used
|
||||||
// by the SSR variant.
|
// by the SSR variant.
|
||||||
static DescriptorSetLayout const ssrVariantDescriptorSetLayout{{
|
static DescriptorSetLayout const ssrVariantDescriptorSetLayout{
|
||||||
|
utils::StaticString("ssrVariant"),{
|
||||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
|
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
|
||||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SHADOWS },
|
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SHADOWS },
|
||||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::STRUCTURE },
|
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::STRUCTURE },
|
||||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SSR },
|
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SSR },
|
||||||
}};
|
}};
|
||||||
|
|
||||||
static DescriptorSetLayout perViewDescriptorSetLayout = {{
|
static DescriptorSetLayout perViewDescriptorSetLayout = {
|
||||||
|
utils::StaticString("perView"),{
|
||||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
|
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
|
||||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SHADOWS },
|
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::SHADOWS },
|
||||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::LIGHTS },
|
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::LIGHTS },
|
||||||
@@ -68,7 +72,8 @@ static DescriptorSetLayout perViewDescriptorSetLayout = {{
|
|||||||
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FOG },
|
{ DescriptorType::SAMPLER, ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FOG },
|
||||||
}};
|
}};
|
||||||
|
|
||||||
static DescriptorSetLayout perRenderableDescriptorSetLayout = {{
|
static DescriptorSetLayout perRenderableDescriptorSetLayout = {
|
||||||
|
utils::StaticString("perRenderable"),{
|
||||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerRenderableBindingPoints::OBJECT_UNIFORMS, DescriptorFlags::DYNAMIC_OFFSET },
|
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerRenderableBindingPoints::OBJECT_UNIFORMS, DescriptorFlags::DYNAMIC_OFFSET },
|
||||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerRenderableBindingPoints::BONES_UNIFORMS, DescriptorFlags::DYNAMIC_OFFSET },
|
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerRenderableBindingPoints::BONES_UNIFORMS, DescriptorFlags::DYNAMIC_OFFSET },
|
||||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerRenderableBindingPoints::MORPHING_UNIFORMS },
|
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerRenderableBindingPoints::MORPHING_UNIFORMS },
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn,
|
|||||||
std::string_view const essl1("essl1");
|
std::string_view const essl1("essl1");
|
||||||
std::string_view const msl("msl");
|
std::string_view const msl("msl");
|
||||||
std::string_view const spirv("spirv");
|
std::string_view const spirv("spirv");
|
||||||
|
std::string_view const wgsl("wgsl");
|
||||||
size_t const qlength = strlen(request->query_string);
|
size_t const qlength = strlen(request->query_string);
|
||||||
|
|
||||||
char type[6] = {};
|
char type[6] = {};
|
||||||
@@ -102,11 +103,13 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn,
|
|||||||
char glindex[4] = {};
|
char glindex[4] = {};
|
||||||
char vkindex[4] = {};
|
char vkindex[4] = {};
|
||||||
char metalindex[4] = {};
|
char metalindex[4] = {};
|
||||||
|
char wgpuindex[4] = {};
|
||||||
mg_get_var(request->query_string, qlength, "glindex", glindex, sizeof(glindex));
|
mg_get_var(request->query_string, qlength, "glindex", glindex, sizeof(glindex));
|
||||||
mg_get_var(request->query_string, qlength, "vkindex", vkindex, sizeof(vkindex));
|
mg_get_var(request->query_string, qlength, "vkindex", vkindex, sizeof(vkindex));
|
||||||
mg_get_var(request->query_string, qlength, "metalindex", metalindex, sizeof(metalindex));
|
mg_get_var(request->query_string, qlength, "metalindex", metalindex, sizeof(metalindex));
|
||||||
|
mg_get_var(request->query_string, qlength, "wgpuindex", wgpuindex, sizeof(wgpuindex));
|
||||||
|
|
||||||
if (!glindex[0] && !vkindex[0] && !metalindex[0]) {
|
if (!glindex[0] && !vkindex[0] && !metalindex[0] && !wgpuindex[0]) {
|
||||||
return error(__LINE__, uri);
|
return error(__LINE__, uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,6 +221,37 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn,
|
|||||||
|
|
||||||
return softError("Only MSL is supported.");
|
return softError("Only MSL is supported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wgpuindex[0]) {
|
||||||
|
ShaderExtractor extractor(ShaderLanguage::WGSL, result->package, result->packageSize);
|
||||||
|
if (!extractor.parse()) {
|
||||||
|
return error(__LINE__, uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
FixedCapacityVector<ShaderInfo> info(getShaderCount(package, ChunkType::MaterialWgsl));
|
||||||
|
if (!getShaderInfo(package, info.data(), ChunkType::MaterialWgsl)) {
|
||||||
|
return error(__LINE__, uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
int const shaderIndex = std::stoi(wgpuindex);
|
||||||
|
if (shaderIndex >= info.size()) {
|
||||||
|
return error(__LINE__, uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const& item = info[shaderIndex];
|
||||||
|
filaflat::ShaderContent content;
|
||||||
|
extractor.getShader(item.shaderModel, item.variant, item.pipelineStage, content);
|
||||||
|
|
||||||
|
if (language == wgsl) {
|
||||||
|
std::string const shader = mFormatter.format((char const*) content.data());
|
||||||
|
mg_printf(conn, kSuccessHeader.data(), "application/txt");
|
||||||
|
mg_write(conn, shader.c_str(), shader.size());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return softError("Only WGSL is supported.");
|
||||||
|
}
|
||||||
|
|
||||||
return error(__LINE__, uri);
|
return error(__LINE__, uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -181,6 +181,18 @@ static bool printMetalInfo(ostream& json, const ChunkContainer& container) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool printWGPUInfo(ostream& json, const ChunkContainer& container) {
|
||||||
|
std::vector<ShaderInfo> info;
|
||||||
|
info.resize(getShaderCount(container, ChunkType::MaterialWgsl));
|
||||||
|
if (!getShaderInfo(container, info.data(), ChunkType::MaterialWgsl)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
json << "\"webgpu\": [\n";
|
||||||
|
printShaderInfo(json, info, container);
|
||||||
|
json << "],\n";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool JsonWriter::writeMaterialInfo(const filaflat::ChunkContainer& container) {
|
bool JsonWriter::writeMaterialInfo(const filaflat::ChunkContainer& container) {
|
||||||
ostringstream json;
|
ostringstream json;
|
||||||
if (!printMaterial(json, container)) {
|
if (!printMaterial(json, container)) {
|
||||||
@@ -201,6 +213,9 @@ bool JsonWriter::writeMaterialInfo(const filaflat::ChunkContainer& container) {
|
|||||||
if (!printMetalInfo(json, container)) {
|
if (!printMetalInfo(json, container)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!printWGPUInfo(json, container)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
json << "\"required_attributes\": [\n";
|
json << "\"required_attributes\": [\n";
|
||||||
uint32_t requiredAttributes;
|
uint32_t requiredAttributes;
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ async function fetchShaderCode(matid, backend, language, index) {
|
|||||||
case "metal":
|
case "metal":
|
||||||
query = `type=${language}&metalindex=${index}`;
|
query = `type=${language}&metalindex=${index}`;
|
||||||
break;
|
break;
|
||||||
|
case "webgpu":
|
||||||
|
query = `type=${language}&wgpuindex=${index}`;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return await _fetchText(`api/shader?matid=${matid}&${query}`);
|
return await _fetchText(`api/shader?matid=${matid}&${query}`);
|
||||||
}
|
}
|
||||||
@@ -88,6 +91,7 @@ function rebuildMaterial(materialId, backend, shaderIndex, editedText) {
|
|||||||
break;
|
break;
|
||||||
case "vulkan": api = 2; break;
|
case "vulkan": api = 2; break;
|
||||||
case "metal": api = 3; break;
|
case "metal": api = 3; break;
|
||||||
|
case "webgpu": api = 4; break;
|
||||||
}
|
}
|
||||||
return new Promise((ok, fail) => {
|
return new Promise((ok, fail) => {
|
||||||
const req = new XMLHttpRequest();
|
const req = new XMLHttpRequest();
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { LitElement, html, css, unsafeCSS, nothing } from "https://unpkg.com/lit@2.8.0?module";
|
import { LitElement, html, css, unsafeCSS, nothing } from "https://cdn.jsdelivr.net/gh/lit/dist@3/all/lit-all.min.js";
|
||||||
|
|
||||||
const kUntitledPlaceholder = "untitled";
|
const kUntitledPlaceholder = "untitled";
|
||||||
|
|
||||||
@@ -24,6 +24,7 @@ const LANGUAGE_CHOICES = {
|
|||||||
'essl1': ['essl3', 'essl1'],
|
'essl1': ['essl3', 'essl1'],
|
||||||
'vulkan': ['glsl', 'spirv'],
|
'vulkan': ['glsl', 'spirv'],
|
||||||
'metal': ['msl'],
|
'metal': ['msl'],
|
||||||
|
'webgpu': ['wgsl'],
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_LANGUAGE_FOR_BACKEND = {
|
const DEFAULT_LANGUAGE_FOR_BACKEND = {
|
||||||
@@ -31,6 +32,7 @@ const DEFAULT_LANGUAGE_FOR_BACKEND = {
|
|||||||
'essl1': 'essl1',
|
'essl1': 'essl1',
|
||||||
'vulkan': 'glsl',
|
'vulkan': 'glsl',
|
||||||
'metal': 'msl',
|
'metal': 'msl',
|
||||||
|
'webgpu': 'wgsl',
|
||||||
};
|
};
|
||||||
|
|
||||||
const BACKENDS = Object.keys(LANGUAGE_CHOICES);
|
const BACKENDS = Object.keys(LANGUAGE_CHOICES);
|
||||||
|
|||||||
+4
-4
@@ -229,10 +229,10 @@ MaybeError ValidateWriteBuffer(const DeviceBase* device,
|
|||||||
uint64_t size) {
|
uint64_t size) {
|
||||||
DAWN_TRY(device->ValidateObject(buffer));
|
DAWN_TRY(device->ValidateObject(buffer));
|
||||||
|
|
||||||
DAWN_INVALID_IF(bufferOffset % 4 != 0, "BufferOffset (%u) is not a multiple of 4.",
|
// DAWN_INVALID_IF(bufferOffset % 4 != 0, "BufferOffset (%u) is not a multiple of 4.",
|
||||||
bufferOffset);
|
// bufferOffset);
|
||||||
|
//
|
||||||
DAWN_INVALID_IF(size % 4 != 0, "Size (%u) is not a multiple of 4.", size);
|
// DAWN_INVALID_IF(size % 4 != 0, "Size (%u) is not a multiple of 4.", size);
|
||||||
|
|
||||||
uint64_t bufferSize = buffer->GetSize();
|
uint64_t bufferSize = buffer->GetSize();
|
||||||
DAWN_INVALID_IF(bufferOffset > bufferSize || size > (bufferSize - bufferOffset),
|
DAWN_INVALID_IF(bufferOffset > bufferSize || size > (bufferSize - bufferOffset),
|
||||||
|
|||||||
Vendored
+3
-3
@@ -1176,10 +1176,10 @@ export interface View$DynamicResolutionOptions {
|
|||||||
/**
|
/**
|
||||||
* Upscaling quality
|
* Upscaling quality
|
||||||
* LOW: bilinear filtered blit. Fastest, poor quality
|
* LOW: bilinear filtered blit. Fastest, poor quality
|
||||||
* MEDIUM: AMD FidelityFX FSR1 w/ mobile optimizations
|
* MEDIUM: Qualcomm Snapdragon Game Super Resolution (SGSR) 1.0
|
||||||
* HIGH: AMD FidelityFX FSR1 w/ mobile optimizations
|
* HIGH: AMD FidelityFX FSR1 w/ mobile optimizations
|
||||||
* ULTRA: AMD FidelityFX FSR1
|
* ULTRA: AMD FidelityFX FSR1
|
||||||
* FSR1 require a well anti-aliased (MSAA or TAA), noise free scene.
|
* FSR1 and SGSR require a well anti-aliased (MSAA or TAA), noise free scene. Avoid FXAA and dithering.
|
||||||
*
|
*
|
||||||
* The default upscaling quality is set to LOW.
|
* The default upscaling quality is set to LOW.
|
||||||
*/
|
*/
|
||||||
@@ -1675,7 +1675,7 @@ export enum View$TemporalAntiAliasingOptions$JitterPattern {
|
|||||||
*/
|
*/
|
||||||
export interface View$TemporalAntiAliasingOptions {
|
export interface View$TemporalAntiAliasingOptions {
|
||||||
/**
|
/**
|
||||||
* reconstruction filter width typically between 0.2 (sharper, aliased) and 1.5 (smoother)
|
* reconstruction filter width typically between 1 (sharper) and 2 (smoother)
|
||||||
*/
|
*/
|
||||||
filterWidth?: number;
|
filterWidth?: number;
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "filament",
|
"name": "filament",
|
||||||
"version": "1.59.3",
|
"version": "1.59.4",
|
||||||
"description": "Real-time physically based rendering engine",
|
"description": "Real-time physically based rendering engine",
|
||||||
"main": "filament.js",
|
"main": "filament.js",
|
||||||
"module": "filament.js",
|
"module": "filament.js",
|
||||||
|
|||||||
Reference in New Issue
Block a user