Compare commits
30
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f172cac8f2 | ||
|
|
2a579c460f | ||
|
|
efdc801cff | ||
|
|
dd654c575a | ||
|
|
0c2599b6ca | ||
|
|
7cca872af5 | ||
|
|
3cef1991b2 | ||
|
|
64493d8636 | ||
|
|
df78322bdc | ||
|
|
f1a967d631 | ||
|
|
ec48dfa453 | ||
|
|
5881a13b20 | ||
|
|
efd9e875db | ||
|
|
6f25e8ae5a | ||
|
|
449519c1b4 | ||
|
|
e2e5f7cee9 | ||
|
|
9d30233a38 | ||
|
|
d684fc4096 | ||
|
|
5f3f3f1b24 | ||
|
|
6aa2a2b89b | ||
|
|
47135164ee | ||
|
|
5a75fb9b53 | ||
|
|
7933b08e85 | ||
|
|
a6809b4550 | ||
|
|
8f77308bca | ||
|
|
65f1e64812 | ||
|
|
79942b3bea | ||
|
|
9ee41b9b6a | ||
|
|
21995e4ac9 | ||
|
|
8dc871c86e |
@@ -7,4 +7,3 @@ for next branch cut* header.
|
||||
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
||||
|
||||
## Release notes for next branch cut
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.31.7'
|
||||
implementation 'com.google.android.filament:filament-android:1.32.0'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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:
|
||||
|
||||
```
|
||||
pod 'Filament', '~> 1.31.7'
|
||||
pod 'Filament', '~> 1.32.0'
|
||||
```
|
||||
|
||||
### Snapshots
|
||||
|
||||
@@ -7,6 +7,16 @@ 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
|
||||
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
||||
|
||||
## v1.32.0
|
||||
|
||||
- fog: fixed fog height falloff and computation precision on mobile [⚠️ **Recompile Materials**]
|
||||
- materials: new alphaToCoverage property can be used to control alpha to coverage behavior
|
||||
- materials: added `getUserWorldFromWorldMatrix()` and `getUserWorldPosition()` to retrieve the
|
||||
API-level (user) world position in materials. Deprecated `getWorldOffset()`. [⚠️ **Recompile
|
||||
Materials**]
|
||||
- engine: fix precision issue with `shading_view` in large scenes
|
||||
- vulkan: readPixels is now async (#6560)
|
||||
|
||||
## v1.31.7
|
||||
|
||||
## v1.31.6
|
||||
|
||||
@@ -250,6 +250,13 @@ Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderMaskThr
|
||||
builder->maskThreshold(maskThreshold);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderAlphaToCoverage(JNIEnv*,
|
||||
jclass, jlong nativeBuilder, jboolean enable) {
|
||||
auto builder = (MaterialBuilder*) nativeBuilder;
|
||||
builder->alphaToCoverage(enable);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderShadowMultiplier(
|
||||
JNIEnv*, jclass, jlong nativeBuilder, jboolean shadowMultiplier) {
|
||||
|
||||
+7
@@ -360,6 +360,12 @@ public class MaterialBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public MaterialBuilder alphaToCoverage(boolean enable) {
|
||||
nMaterialBuilderAlphaToCoverage(mNativeObject, enable);
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public MaterialBuilder shadowMultiplier(boolean shadowMultiplier) {
|
||||
nMaterialBuilderShadowMultiplier(mNativeObject, shadowMultiplier);
|
||||
@@ -584,6 +590,7 @@ public class MaterialBuilder {
|
||||
private static native void nMaterialBuilderDepthCulling(long nativeBuilder, boolean enable);
|
||||
private static native void nMaterialBuilderDoubleSided(long nativeBuilder, boolean doubleSided);
|
||||
private static native void nMaterialBuilderMaskThreshold(long nativeBuilder, float mode);
|
||||
private static native void nMaterialBuilderAlphaToCoverage(long nativeBuilder, boolean enable);
|
||||
|
||||
private static native void nMaterialBuilderShadowMultiplier(long mNativeObject,
|
||||
boolean shadowMultiplier);
|
||||
|
||||
@@ -153,6 +153,14 @@ Java_com_google_android_filament_Material_nIsDoubleSided(JNIEnv*, jclass,
|
||||
return (jboolean) material->isDoubleSided();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_Material_nIsAlphaToCoverageEnabled(JNIEnv*, jclass,
|
||||
jlong nativeMaterial) {
|
||||
Material* material = (Material*) nativeMaterial;
|
||||
return (jboolean) material->isAlphaToCoverageEnabled();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jfloat JNICALL
|
||||
Java_com_google_android_filament_Material_nGetMaskThreshold(JNIEnv*, jclass,
|
||||
|
||||
@@ -457,7 +457,6 @@ extern "C"
|
||||
JNIEXPORT jfloat JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetMaskThreshold(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nGetMaskThreshold()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->getMaskThreshold();
|
||||
}
|
||||
@@ -466,7 +465,6 @@ extern "C"
|
||||
JNIEXPORT jfloat JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetSpecularAntiAliasingVariance(JNIEnv* env,
|
||||
jclass clazz, jlong nativeMaterialInstance) {
|
||||
// TODO: implement nGetSpecularAntiAliasingVariance()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->getSpecularAntiAliasingVariance();
|
||||
}
|
||||
@@ -475,7 +473,6 @@ extern "C"
|
||||
JNIEXPORT jfloat JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetSpecularAntiAliasingThreshold(JNIEnv* env,
|
||||
jclass clazz, jlong nativeMaterialInstance) {
|
||||
// TODO: implement nGetSpecularAntiAliasingThreshold()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->getSpecularAntiAliasingThreshold();
|
||||
}
|
||||
@@ -484,7 +481,6 @@ extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nIsDoubleSided(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nIsDoubleSided()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->isDoubleSided();
|
||||
}
|
||||
@@ -493,7 +489,6 @@ extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetCullingMode(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nGetCullingMode()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return (jint)instance->getCullingMode();
|
||||
}
|
||||
@@ -502,7 +497,6 @@ extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nIsColorWriteEnabled(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nIsColorWriteEnabled()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->isColorWriteEnabled();
|
||||
}
|
||||
@@ -511,7 +505,6 @@ extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nIsDepthWriteEnabled(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nIsDepthWriteEnabled()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->isDepthWriteEnabled();
|
||||
}
|
||||
@@ -520,7 +513,6 @@ extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nIsStencilWriteEnabled(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nIsStencilWriteEnabled()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->isStencilWriteEnabled();
|
||||
}
|
||||
@@ -529,7 +521,6 @@ extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nIsDepthCullingEnabled(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nIsDepthCullingEnabled()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->isDepthCullingEnabled();
|
||||
}
|
||||
|
||||
@@ -503,6 +503,17 @@ public class Material {
|
||||
return nIsDoubleSided(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether instances of this material will use alpha to coverage.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:alphatocoverage">
|
||||
* Rasterization: alphaToCoverage</a>
|
||||
*/
|
||||
public boolean isAlphaToCoverageEnabled() {
|
||||
return nIsAlphaToCoverageEnabled(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the alpha mask threshold used when the blending mode is set to masked.
|
||||
*
|
||||
@@ -915,6 +926,7 @@ public class Material {
|
||||
private static native boolean nIsDepthWriteEnabled(long nativeMaterial);
|
||||
private static native boolean nIsDepthCullingEnabled(long nativeMaterial);
|
||||
private static native boolean nIsDoubleSided(long nativeMaterial);
|
||||
private static native boolean nIsAlphaToCoverageEnabled(long nativeMaterial);
|
||||
private static native float nGetMaskThreshold(long nativeMaterial);
|
||||
private static native float nGetSpecularAntiAliasingVariance(long nativeMaterial);
|
||||
private static native float nGetSpecularAntiAliasingThreshold(long nativeMaterial);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.31.7
|
||||
VERSION_NAME=1.32.0
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Image-Based Lighting</string>
|
||||
<string name="app_name">Material Builder</string>
|
||||
</resources>
|
||||
|
||||
+48
-8
@@ -1362,6 +1362,11 @@ Description
|
||||
ALPHA_TO_COVERAGE is enabled for non-translucent views. See the maskThreshold section for more
|
||||
information.
|
||||
|
||||
!!! Note
|
||||
When `blending` is set to `masked`, alpha to coverage is automatically enabled for the material.
|
||||
If this behavior is undesirable, refer to the Rasterization: alphaToCoverage section to turn
|
||||
alpha to coverage off using the `alphaToCoverage` property.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
|
||||
material {
|
||||
blending : transparent
|
||||
@@ -1602,6 +1607,37 @@ fragment {
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
### Rasterization: alphaToCoverage
|
||||
|
||||
Type
|
||||
: `boolean`
|
||||
|
||||
Value
|
||||
: `true` or `false`. Defaults to `false`.
|
||||
|
||||
Description
|
||||
: Enables or disables alpha to coverage. When alpha to coverage is enabled, the coverage of
|
||||
fragment is derived from its alpha. This property is only meaningful when MSAA is enabled.
|
||||
Note: setting `blending` to `masked` automatically enables alpha to coverage. If this is not
|
||||
desired, you can override this behavior by setting alpha to coverage to false as in the
|
||||
example below.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
|
||||
material {
|
||||
name : "Alpha to coverage",
|
||||
shadingModel : lit,
|
||||
blending : masked,
|
||||
alphaToCoverage : false
|
||||
}
|
||||
|
||||
fragment {
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
material.baseColor = materialParams.albedo;
|
||||
}
|
||||
}
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
### Lighting: reflections
|
||||
|
||||
Type
|
||||
@@ -1910,8 +1946,9 @@ struct MaterialVertexInputs {
|
||||
|
||||
!!! TIP: worldPosition
|
||||
To achieve good precision, the `worldPosition` coordinate in the vertex shader is shifted by the
|
||||
camera position. To get the true world-space position, users can add this to
|
||||
`getWorldOffset()`.
|
||||
camera position. To get the true world-space position, users can use
|
||||
`getUserWorldPosition()`, however be aware that the true world-position might not
|
||||
be able to fit in a `float` or might be represented with severely reduced precision.
|
||||
|
||||
!!! TIP: UV attributes
|
||||
By default the vertex shader of a material will flip the Y coordinate of the UV attributes
|
||||
@@ -2264,8 +2301,9 @@ type aliases:
|
||||
Name | Type | Description
|
||||
:-----------------------------------|:--------:|:------------------------------------
|
||||
**getResolution()** | float4 | Dimensions of the view's effective (physical) viewport in pixels: `width`, `height`, `1 / width`, `1 / height`. This might be different from `View::getViewport()` for instance because of added rendering guard-bands.
|
||||
**getWorldCameraPosition()** | float3 | Position of the camera/eye in world space
|
||||
**getWorldOffset()** | float3 | The shift required to obtain API-level world space
|
||||
**getWorldCameraPosition()** | float3 | Position of the camera/eye in world space (see note below)
|
||||
**getWorldOffset()** | float3 | [deprecated] The shift required to obtain API-level world space. Use getUserWorldPosition() instead
|
||||
**getUserWorldFromWorldMatrix()** | float4x4 | Matrix that converts from world space to API-level (user) world space.
|
||||
**getTime()** | float | Current time as a remainder of 1 second. Yields a value between 0 and 1
|
||||
**getUserTime()** | float4 | Current time in seconds: `time`, `(double)time - time`, `0`, `0`
|
||||
**getUserTimeMode(float m)** | float | Current time modulo m in seconds
|
||||
@@ -2275,7 +2313,7 @@ type aliases:
|
||||
!!! TIP: world space
|
||||
To achieve good precision, the "world space" in Filament's shading system does not necessarily
|
||||
match the API-level world space. To obtain the position of the API-level camera, custom
|
||||
materials can add `getWorldOffset()` to `getWorldCameraPosition()`.
|
||||
materials can use `getUserWorldFromWorldMatrix()` to transform `getWorldCameraPosition()`.
|
||||
|
||||
### Vertex only
|
||||
|
||||
@@ -2297,6 +2335,7 @@ The following APIs are only available from the fragment block:
|
||||
:---------------------------------------|:--------:|:------------------------------------
|
||||
**getWorldTangentFrame()** | float3x3 | Matrix containing in each column the `tangent` (`frame[0]`), `bi-tangent` (`frame[1]`) and `normal` (`frame[2]`) of the vertex in world space. If the material does not compute a tangent space normal for bump mapping or if the shading is not anisotropic, only the `normal` is valid in this matrix.
|
||||
**getWorldPosition()** | float3 | Position of the fragment in world space (see note below about world-space)
|
||||
**getUserWorldPosition()** | float3 | Position of the fragment in API-level (user) world-space (see note below about world-space)
|
||||
**getWorldViewVector()** | float3 | Normalized vector in world space from the fragment position to the eye
|
||||
**getWorldNormalVector()** | float3 | Normalized normal in world space, after bump mapping (must be used after `prepareMaterial()`)
|
||||
**getWorldGeometricNormalVector()** | float3 | Normalized normal in world space, before bump mapping (can be used before `prepareMaterial()`)
|
||||
@@ -2313,9 +2352,10 @@ The following APIs are only available from the fragment block:
|
||||
**ycbcrToRgb(float, float2)** | float3 | Converts a luminance and CbCr pair to a sRGB color
|
||||
**uvToRenderTargetUV(float2)** | float2 | Transforms a UV coordinate to allow sampling from a `RenderTarget` attachment
|
||||
|
||||
!!! TIP: world space
|
||||
To obtain API-level world space coordinates, custom materials should add `getWorldOffset()` to
|
||||
`getWorldPosition()` (et al).
|
||||
!!! TIP: world-space
|
||||
To obtain API-level world-space coordinates, custom materials should use `getUserWorldPosition()`
|
||||
or use `getUserWorldFromWorldMatrix()`. Note that API-level world-space coordinates should
|
||||
never or rarely be used because they may not fit in a float3 or have severely reduced precision.
|
||||
|
||||
!!! TIP: sampling from render targets
|
||||
When sampling from a `filament::Texture` that is attached to a `filament::RenderTarget` for
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+145
-145
@@ -44,7 +44,7 @@ fragment {
|
||||
</pre></div>
|
||||
|
||||
<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: #bbbbbb"> </span>-a<span style="color: #bbbbbb"> </span>opengl<span style="color: #bbbbbb"> </span>-p<span style="color: #bbbbbb"> </span>mobile<span style="color: #bbbbbb"> </span>-o<span style="color: #bbbbbb"> </span>plastic.filamat<span style="color: #bbbbbb"> </span>plastic.mat
|
||||
</pre></div>
|
||||
|
||||
<p>You should now have a material archive in your working directory, which we'll use later in the
|
||||
@@ -53,7 +53,7 @@ tutorial.</p>
|
||||
<p>Next we'll use Filament's <code>cmgen</code> tool to consume a HDR environment map in latlong format, and
|
||||
produce two cubemap files: a mipmapped IBL and a blurry skybox.</p>
|
||||
<p>Download <a href="//github.com/google/filament/blob/main/third_party/environments/pillars_2k.hdr">pillars_2k.hdr</a>, then invoke the following command in your terminal.</p>
|
||||
<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: #bbbbbb"> </span>-x<span style="color: #bbbbbb"> </span>pillars_2k<span style="color: #bbbbbb"> </span>--format<span style="color: #666666">=</span>ktx<span style="color: #bbbbbb"> </span>--size<span style="color: #666666">=256</span><span style="color: #bbbbbb"> </span>--extract-blur<span style="color: #666666">=0</span>.1<span style="color: #bbbbbb"> </span>pillars_2k.hdr
|
||||
</pre></div>
|
||||
|
||||
<p>You should now have a <code>pillars_2k</code> folder containing a couple KTX files for the IBL and skybox, as
|
||||
@@ -61,81 +61,81 @@ well as a text file with spherical harmonics coefficients. You can discard the t
|
||||
IBL KTX contains these coefficients in its metadata.</p>
|
||||
<h2>Create JavaScript</h2>
|
||||
<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>
|
||||
<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: #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: #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>
|
||||
<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: #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: #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: #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>
|
||||
|
||||
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>
|
||||
<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: #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: #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: #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: #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: #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: #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>
|
||||
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><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: #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: #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: #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: #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: #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: #3D7B7B; font-style: italic">// Obtain the canvas DOM object and pass it to the App.</span><span style="color: #bbbbbb"></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: #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: #bbbbbb"> </span>);<span style="color: #bbbbbb"></span>
|
||||
<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: #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: #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: #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: #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: #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: #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: #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: #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">constructor</span>(canvas)<span style="color: #bbbbbb"> </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: #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: #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: #3D7B7B; font-style: italic">// TODO: create material</span><span style="color: #bbbbbb"></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: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create lights</span><span style="color: #bbbbbb"></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: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create skybox</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </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: #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: #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: #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: #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: #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: #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: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setScene(scene);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize();<span style="color: #bbbbbb"></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: #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: #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: #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: #bbbbbb"> </span>}<span style="color: #bbbbbb"></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: #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>.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>.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.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: #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: #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: #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: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||
<span style="color: #bbbbbb"> </span>}
|
||||
|
||||
<span style="color: #bbbbbb"> </span>render()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></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: #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: #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: #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: #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: #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: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>render()<span style="color: #bbbbbb"> </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: #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>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: #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: #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">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||
<span style="color: #bbbbbb"> </span>}
|
||||
|
||||
<span style="color: #bbbbbb"> </span>resize()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></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: #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: #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: #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: #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: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
||||
}<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>resize()<span style="color: #bbbbbb"> </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: #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: #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">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>.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>}
|
||||
}
|
||||
</pre></div>
|
||||
|
||||
<p>The above boilerplate should be familiar to you from the previous tutorial, although it loads in a
|
||||
new set of assets. We also added some animation to the camera.</p>
|
||||
<p>Next let's create a material instance from the package that we built at the beginning the tutorial.
|
||||
Replace the <strong>create material</strong> comment with the following snippet.</p>
|
||||
<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>
|
||||
<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>
|
||||
<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: #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: #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>
|
||||
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.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">'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">'clearCoatRoughness'</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.3</span>);<span style="color: #bbbbbb"></span>
|
||||
<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>];
|
||||
matinstance.setColor3Parameter(<span style="color: #BA2121">'baseColor'</span>,<span style="color: #bbbbbb"> </span>Filament.RgbType.sRGB,<span style="color: #bbbbbb"> </span>red);
|
||||
matinstance.setFloatParameter(<span style="color: #BA2121">'roughness'</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.5</span>);
|
||||
matinstance.setFloatParameter(<span style="color: #BA2121">'clearCoat'</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1.0</span>);
|
||||
matinstance.setFloatParameter(<span style="color: #BA2121">'clearCoatRoughness'</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.3</span>);
|
||||
</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>
|
||||
@@ -149,33 +149,33 @@ as quaternions.</li>
|
||||
</ul>
|
||||
<p>Let's go ahead use these arrays to build the vertex buffer and index buffer. Replace <strong>create
|
||||
sphere</strong> with the following snippet.</p>
|
||||
<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>
|
||||
scene.addEntity(renderable);<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: #bbbbbb"> </span>renderable<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.EntityManager.get().create();
|
||||
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: #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: #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: #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: #bbbbbb"> </span>.bufferCount(<span style="color: #666666">2</span>)<span style="color: #bbbbbb"></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: #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: #bbbbbb"> </span>.normalized(VertexAttribute.TANGENTS)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></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>.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>.bufferCount(<span style="color: #666666">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>.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>.normalized(VertexAttribute.TANGENTS)
|
||||
<span style="color: #bbbbbb"> </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: #bbbbbb"> </span>.indexCount(icosphere.triangles.length)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.bufferType(IndexType.USHORT)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
|
||||
<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>.indexCount(icosphere.triangles.length)
|
||||
<span style="color: #bbbbbb"> </span>.bufferType(IndexType.USHORT)
|
||||
<span style="color: #bbbbbb"> </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: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span>icosphere.tangents);<span style="color: #bbbbbb"></span>
|
||||
ib.setBuffer(engine,<span style="color: #bbbbbb"> </span>icosphere.triangles);<span style="color: #bbbbbb"></span>
|
||||
vb.setBufferAt(engine,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>icosphere.vertices);
|
||||
vb.setBufferAt(engine,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span>icosphere.tangents);
|
||||
ib.setBuffer(engine,<span style="color: #bbbbbb"> </span>icosphere.triangles);
|
||||
|
||||
Filament.RenderableManager.Builder(<span style="color: #666666">1</span>)<span style="color: #bbbbbb"></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: #bbbbbb"> </span>.material(<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>matinstance)<span style="color: #bbbbbb"></span>
|
||||
<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: #bbbbbb"> </span>.build(engine,<span style="color: #bbbbbb"> </span>renderable);<span style="color: #bbbbbb"></span>
|
||||
Filament.RenderableManager.Builder(<span style="color: #666666">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>.material(<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </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>.build(engine,<span style="color: #bbbbbb"> </span>renderable);
|
||||
</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
|
||||
@@ -185,94 +185,94 @@ did in the first tutorial.</p>
|
||||
<p>In this section we will create some directional light sources, as well as an image-based light (IBL)
|
||||
defined by one of the KTX files we built at the start of the demo. First, replace the <strong>create
|
||||
lights</strong> comment with the following snippet.</p>
|
||||
<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>
|
||||
scene.addEntity(sunlight);<span style="color: #bbbbbb"></span>
|
||||
Filament.LightManager.Builder(LightType.SUN)<span style="color: #bbbbbb"></span>
|
||||
<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: #bbbbbb"> </span>.intensity(<span style="color: #666666">110000.0</span>)<span style="color: #bbbbbb"></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: #bbbbbb"> </span>.sunAngularRadius(<span style="color: #666666">1.9</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.sunHaloSize(<span style="color: #666666">10.0</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.sunHaloFalloff(<span style="color: #666666">80.0</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine,<span style="color: #bbbbbb"> </span>sunlight);<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: #bbbbbb"> </span>sunlight<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.EntityManager.get().create();
|
||||
scene.addEntity(sunlight);
|
||||
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>.intensity(<span style="color: #666666">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>.sunAngularRadius(<span style="color: #666666">1.9</span>)
|
||||
<span style="color: #bbbbbb"> </span>.sunHaloSize(<span style="color: #666666">10.0</span>)
|
||||
<span style="color: #bbbbbb"> </span>.sunHaloFalloff(<span style="color: #666666">80.0</span>)
|
||||
<span style="color: #bbbbbb"> </span>.build(engine,<span style="color: #bbbbbb"> </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>
|
||||
scene.addEntity(backlight);<span style="color: #bbbbbb"></span>
|
||||
Filament.LightManager.Builder(LightType.DIRECTIONAL)<span style="color: #bbbbbb"></span>
|
||||
<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: #bbbbbb"> </span>.intensity(<span style="color: #666666">50000.0</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine,<span style="color: #bbbbbb"> </span>backlight);<span style="color: #bbbbbb"></span>
|
||||
<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();
|
||||
scene.addEntity(backlight);
|
||||
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>.intensity(<span style="color: #666666">50000.0</span>)
|
||||
<span style="color: #bbbbbb"> </span>.build(engine,<span style="color: #bbbbbb"> </span>backlight);
|
||||
</pre></div>
|
||||
|
||||
<p>The <code>SUN</code> light source is similar to the <code>DIRECTIONAL</code> light source, but has some extra
|
||||
parameters because Filament will automatically draw a disk into the skybox.</p>
|
||||
<p>Next we need to create an <code>IndirectLight</code> object from the KTX IBL. One way of doing this is the
|
||||
following (don't type this out, there's an easier way).</p>
|
||||
<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>
|
||||
<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>
|
||||
<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: #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: #3D7B7B; font-style: italic">// Create a Texture object for the mipmapped cubemap.</span><span style="color: #bbbbbb"></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: #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: #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: #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: #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: #bbbbbb"> </span>.width(iblktx.info().pixelWidth)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.height(iblktx.info().pixelHeight)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.levels(iblktx.getNumMipLevels())<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.format(Filament.Texture$InternalFormat.RGBA8)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
|
||||
<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>.width(iblktx.info().pixelWidth)
|
||||
<span style="color: #bbbbbb"> </span>.height(iblktx.info().pixelHeight)
|
||||
<span style="color: #bbbbbb"> </span>.levels(iblktx.getNumMipLevels())
|
||||
<span style="color: #bbbbbb"> </span>.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)
|
||||
<span style="color: #bbbbbb"> </span>.format(Filament.Texture$InternalFormat.RGBA8)
|
||||
<span style="color: #bbbbbb"> </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: #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: #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: #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: #bbbbbb"></span>
|
||||
<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">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: #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>ibltex.setImageCube(engine,<span style="color: #bbbbbb"> </span>level,<span style="color: #bbbbbb"> </span>pixelbuffer);
|
||||
}
|
||||
|
||||
<span style="color: #3D7B7B; font-style: italic">// Parse the spherical harmonics metadata.</span><span style="color: #bbbbbb"></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: #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: #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: #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: #3D7B7B; font-style: italic">// Build the IBL object and insert it into the scene.</span><span style="color: #bbbbbb"></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: #bbbbbb"> </span>.reflections(ibltex)<span style="color: #bbbbbb"></span>
|
||||
<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: #bbbbbb"> </span>.intensity(<span style="color: #666666">50000.0</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine);<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>.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>.intensity(<span style="color: #666666">50000.0</span>)
|
||||
<span style="color: #bbbbbb"> </span>.build(engine);
|
||||
|
||||
scene.setIndirectLight(indirectLight);<span style="color: #bbbbbb"></span>
|
||||
scene.setIndirectLight(indirectLight);
|
||||
</pre></div>
|
||||
|
||||
<p>Filament provides a JavaScript utility to make this simpler,
|
||||
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>
|
||||
indirectLight.setIntensity(<span style="color: #666666">50000</span>);<span style="color: #bbbbbb"></span>
|
||||
scene.setIndirectLight(indirectLight);<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: #bbbbbb"> </span>indirectLight<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createIblFromKtx1(ibl_url);
|
||||
indirectLight.setIntensity(<span style="color: #666666">50000</span>);
|
||||
scene.setIndirectLight(indirectLight);
|
||||
</pre></div>
|
||||
|
||||
<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.
|
||||
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>
|
||||
<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>
|
||||
<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: #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: #bbbbbb"> </span>.width(skyktx.info().pixelWidth)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.height(skyktx.info().pixelHeight)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.levels(<span style="color: #666666">1</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.format(Filament.Texture$InternalFormat.RGBA8)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine);<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: #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: #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: #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>.width(skyktx.info().pixelWidth)
|
||||
<span style="color: #bbbbbb"> </span>.height(skyktx.info().pixelHeight)
|
||||
<span style="color: #bbbbbb"> </span>.levels(<span style="color: #666666">1</span>)
|
||||
<span style="color: #bbbbbb"> </span>.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)
|
||||
<span style="color: #bbbbbb"> </span>.format(Filament.Texture$InternalFormat.RGBA8)
|
||||
<span style="color: #bbbbbb"> </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: #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>
|
||||
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>
|
||||
<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: #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);
|
||||
skytex.setImageCube(engine,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>pixelbuffer);
|
||||
</pre></div>
|
||||
|
||||
<p>Filament provides a Javascript utility to make this easier.
|
||||
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>
|
||||
scene.setSkybox(skybox);<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: #bbbbbb"> </span>skybox<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createSkyFromKtx1(sky_url);
|
||||
scene.setSkybox(skybox);
|
||||
</pre></div>
|
||||
|
||||
<p>That's it, we now have a shiny red ball floating in an environment! The complete JavaScript file is
|
||||
|
||||
+108
-108
@@ -15,7 +15,7 @@ we'll also be using <code>filamesh</code> and <code>mipgen</code>.</p>
|
||||
<p>Filament does not have an asset loading system, but it does provide a binary mesh format
|
||||
called <code>filamesh</code> for simple use cases. Let's create a compressed filamesh file for suzanne by
|
||||
converting <a href="https://github.com/google/filament/blob/main/assets/models/monkey/monkey.obj">this OBJ file</a>:</p>
|
||||
<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: #bbbbbb"> </span>--compress<span style="color: #bbbbbb"> </span>monkey.obj<span style="color: #bbbbbb"> </span>suzanne.filamesh
|
||||
</pre></div>
|
||||
|
||||
<h2>Create mipmapped textures</h2>
|
||||
@@ -23,26 +23,26 @@ converting <a href="https://github.com/google/filament/blob/main/assets/models/m
|
||||
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>
|
||||
<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 and two compressed variants.</span>
|
||||
mipgen albedo.png albedo.ktx
|
||||
mipgen --compression<span style="color: #666666">=</span>astc_fast_ldr_4x4 albedo.png albedo_astc.ktx
|
||||
mipgen --compression<span style="color: #666666">=</span>s3tc_rgb_dxt1 albedo.png albedo_s3tc_srgb.ktx
|
||||
mipgen<span style="color: #bbbbbb"> </span>albedo.png<span style="color: #bbbbbb"> </span>albedo.ktx
|
||||
mipgen<span style="color: #bbbbbb"> </span>--compression<span style="color: #666666">=</span>astc_fast_ldr_4x4<span style="color: #bbbbbb"> </span>albedo.png<span style="color: #bbbbbb"> </span>albedo_astc.ktx
|
||||
mipgen<span style="color: #bbbbbb"> </span>--compression<span style="color: #666666">=</span>s3tc_rgb_dxt1<span style="color: #bbbbbb"> </span>albedo.png<span style="color: #bbbbbb"> </span>albedo_s3tc_srgb.ktx
|
||||
|
||||
<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 --strip-alpha --kernel<span style="color: #666666">=</span>NORMALS --linear --compression<span style="color: #666666">=</span>etc_rgb8_normalxyz_40 <span style="color: #AA5D1F; font-weight: bold">\</span>
|
||||
normal.png normal_etc.ktx
|
||||
mipgen<span style="color: #bbbbbb"> </span>--strip-alpha<span style="color: #bbbbbb"> </span>--kernel<span style="color: #666666">=</span>NORMALS<span style="color: #bbbbbb"> </span>--linear<span style="color: #bbbbbb"> </span>normal.png<span style="color: #bbbbbb"> </span>normal.ktx
|
||||
mipgen<span style="color: #bbbbbb"> </span>--strip-alpha<span style="color: #bbbbbb"> </span>--kernel<span style="color: #666666">=</span>NORMALS<span style="color: #bbbbbb"> </span>--linear<span style="color: #bbbbbb"> </span>--compression<span style="color: #666666">=</span>etc_rgb8_normalxyz_40<span style="color: #bbbbbb"> </span><span style="color: #AA5D1F; font-weight: bold">\</span>
|
||||
<span style="color: #bbbbbb"> </span>normal.png<span style="color: #bbbbbb"> </span>normal_etc.ktx
|
||||
|
||||
<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 --grayscale --compression<span style="color: #666666">=</span>etc_r11_numeric_40 roughness.png roughness_etc.ktx
|
||||
mipgen<span style="color: #bbbbbb"> </span>--grayscale<span style="color: #bbbbbb"> </span>roughness.png<span style="color: #bbbbbb"> </span>roughness.ktx
|
||||
mipgen<span style="color: #bbbbbb"> </span>--grayscale<span style="color: #bbbbbb"> </span>--compression<span style="color: #666666">=</span>etc_r11_numeric_40<span style="color: #bbbbbb"> </span>roughness.png<span style="color: #bbbbbb"> </span>roughness_etc.ktx
|
||||
|
||||
<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 --grayscale --compression<span style="color: #666666">=</span>etc_r11_numeric_40 metallic.png metallic_etc.ktx
|
||||
mipgen<span style="color: #bbbbbb"> </span>--grayscale<span style="color: #bbbbbb"> </span>metallic.png<span style="color: #bbbbbb"> </span>metallic.ktx
|
||||
mipgen<span style="color: #bbbbbb"> </span>--grayscale<span style="color: #bbbbbb"> </span>--compression<span style="color: #666666">=</span>etc_r11_numeric_40<span style="color: #bbbbbb"> </span>metallic.png<span style="color: #bbbbbb"> </span>metallic_etc.ktx
|
||||
|
||||
<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 --grayscale --compression<span style="color: #666666">=</span>etc_r11_numeric_40 ao.png ao_etc.ktx
|
||||
mipgen<span style="color: #bbbbbb"> </span>--grayscale<span style="color: #bbbbbb"> </span>ao.png<span style="color: #bbbbbb"> </span>ao.ktx
|
||||
mipgen<span style="color: #bbbbbb"> </span>--grayscale<span style="color: #bbbbbb"> </span>--compression<span style="color: #666666">=</span>etc_r11_numeric_40<span style="color: #bbbbbb"> </span>ao.png<span style="color: #bbbbbb"> </span>ao_etc.ktx
|
||||
</pre></div>
|
||||
|
||||
<p>For more information on mipgen's arguments and supported formats, do <code>mipgen --help</code>.</p>
|
||||
@@ -50,12 +50,12 @@ mipgen --grayscale --compression<span style="color: #666666">=</span>etc_r11_num
|
||||
<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>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
|
||||
<span style="color: #008000">cd</span> venetian* ; mv venetian*_ibl.ktx venetian_crossroads_2k_skybox_tiny.ktx ; <span style="color: #008000">cd</span> -
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>cmgen<span style="color: #bbbbbb"> </span>-x<span style="color: #bbbbbb"> </span>.<span style="color: #bbbbbb"> </span>--format<span style="color: #666666">=</span>ktx<span style="color: #bbbbbb"> </span>--size<span style="color: #666666">=64</span><span style="color: #bbbbbb"> </span>--extract-blur<span style="color: #666666">=0</span>.1<span style="color: #bbbbbb"> </span>venetian_crossroads_2k.hdr
|
||||
<span style="color: #008000">cd</span><span style="color: #bbbbbb"> </span>venetian*<span style="color: #bbbbbb"> </span>;<span style="color: #bbbbbb"> </span>mv<span style="color: #bbbbbb"> </span>venetian*_ibl.ktx<span style="color: #bbbbbb"> </span>venetian_crossroads_2k_skybox_tiny.ktx<span style="color: #bbbbbb"> </span>;<span style="color: #bbbbbb"> </span><span style="color: #008000">cd</span><span style="color: #bbbbbb"> </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 -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 -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: #bbbbbb"> </span>-x<span style="color: #bbbbbb"> </span>.<span style="color: #bbbbbb"> </span>--format<span style="color: #666666">=</span>ktx<span style="color: #bbbbbb"> </span>--size<span style="color: #666666">=256</span><span style="color: #bbbbbb"> </span>--extract-blur<span style="color: #666666">=0</span>.1<span style="color: #bbbbbb"> </span>venetian_crossroads_2k.hdr
|
||||
cmgen<span style="color: #bbbbbb"> </span>-x<span style="color: #bbbbbb"> </span>.<span style="color: #bbbbbb"> </span>--format<span style="color: #666666">=</span>ktx<span style="color: #bbbbbb"> </span>--size<span style="color: #666666">=256</span><span style="color: #bbbbbb"> </span>--extract-blur<span style="color: #666666">=0</span>.1<span style="color: #bbbbbb"> </span>venetian_crossroads_2k.hdr
|
||||
cmgen<span style="color: #bbbbbb"> </span>-x<span style="color: #bbbbbb"> </span>.<span style="color: #bbbbbb"> </span>--format<span style="color: #666666">=</span>ktx<span style="color: #bbbbbb"> </span>--size<span style="color: #666666">=256</span><span style="color: #bbbbbb"> </span>--extract-blur<span style="color: #666666">=0</span>.1<span style="color: #bbbbbb"> </span>venetian_crossroads_2k.hdr
|
||||
</pre></div>
|
||||
|
||||
<h2>Define textured material</h2>
|
||||
@@ -91,7 +91,7 @@ fragment {
|
||||
</pre></div>
|
||||
|
||||
<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: #bbbbbb"> </span>-a<span style="color: #bbbbbb"> </span>opengl<span style="color: #bbbbbb"> </span>-p<span style="color: #bbbbbb"> </span>mobile<span style="color: #bbbbbb"> </span>-o<span style="color: #bbbbbb"> </span>textured.filamat<span style="color: #bbbbbb"> </span>textured.mat
|
||||
</pre></div>
|
||||
|
||||
<p>You should now have a material archive in your working directory. For the suzanne asset, the normal
|
||||
@@ -101,62 +101,62 @@ 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
|
||||
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>
|
||||
<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>
|
||||
<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: #bbbbbb"></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><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: #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: #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: #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: #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: #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: #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">constructor</span>(canvas)<span style="color: #bbbbbb"> </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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #3D7B7B; font-style: italic">// TODO: create sky box and IBL</span><span style="color: #bbbbbb"></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: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: fetch larger assets</span><span style="color: #bbbbbb"></span>
|
||||
<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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #008000; font-weight: bold">this</span>.resize();<span style="color: #bbbbbb"></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: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </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: #bbbbbb"> </span>render()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></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: #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: #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: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>render()<span style="color: #bbbbbb"> </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: #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">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||
<span style="color: #bbbbbb"> </span>}
|
||||
|
||||
<span style="color: #bbbbbb"> </span>resize()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></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: #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: #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: #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: #bbbbbb"> </span>resize()<span style="color: #bbbbbb"> </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: #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: #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">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">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: #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: #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: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
||||
}<span style="color: #bbbbbb"></span>
|
||||
<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: #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: #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>}
|
||||
}
|
||||
</pre></div>
|
||||
|
||||
<p>Our app will only require a subset of assets to be present for <code>App</code> construction. We'll download
|
||||
@@ -172,29 +172,29 @@ string -- which might be empty.</p>
|
||||
<p>In our case, we know that our web server will have <code>astc</code> and <code>s3tc</code> variants for albedo, and <code>etc</code>
|
||||
variants for the other textures. The uncompressed variants (empty string) are always available as a
|
||||
last resort. Go ahead and replace the <strong>declare asset URLs</strong> comment with the following snippet.</p>
|
||||
<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>
|
||||
<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>
|
||||
<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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #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>;
|
||||
</pre></div>
|
||||
|
||||
<h2>Create skybox and IBL</h2>
|
||||
<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>
|
||||
<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>.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.setIntensity(<span style="color: #666666">100000</span>);<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);<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: #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: #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: #008000; font-weight: bold">this</span>.indirectLight.setIntensity(<span style="color: #666666">100000</span>);
|
||||
<span style="color: #008000; font-weight: bold">this</span>.scene.setIndirectLight(<span style="color: #008000; font-weight: bold">this</span>.indirectLight);
|
||||
</pre></div>
|
||||
|
||||
<p>This allows users to see a reasonable background fairly quickly, before larger assets have finished
|
||||
@@ -206,31 +206,31 @@ when the assets have finished downloading.</p>
|
||||
<p>In our callback, we'll make several <code>setTextureParameter</code> calls on the material instance, then we'll
|
||||
recreate the skybox using a higher-resolution texture. As a last step we unhide the renderable that
|
||||
was created in the app constructor.</p>
|
||||
<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>
|
||||
<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.createTextureFromKtx1(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: #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.createTextureFromKtx1(roughness_url);<span style="color: #bbbbbb"></span>
|
||||
<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.createTextureFromKtx1(metallic_url);<span style="color: #bbbbbb"></span>
|
||||
<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.createTextureFromKtx1(normal_url);<span style="color: #bbbbbb"></span>
|
||||
<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.createTextureFromKtx1(ao_url);<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: #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><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.createTextureFromKtx1(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: #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.createTextureFromKtx1(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.createTextureFromKtx1(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.createTextureFromKtx1(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.createTextureFromKtx1(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: #bbbbbb"> </span>Filament.MinFilter.LINEAR_MIPMAP_LINEAR,<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>Filament.MagFilter.LINEAR,<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>Filament.WrapMode.CLAMP_TO_EDGE);<span style="color: #bbbbbb"></span>
|
||||
<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>Filament.MinFilter.LINEAR_MIPMAP_LINEAR,
|
||||
<span style="color: #bbbbbb"> </span>Filament.MagFilter.LINEAR,
|
||||
<span style="color: #bbbbbb"> </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: #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: #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: #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: #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: #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: #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: #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: #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: #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: #3D7B7B; font-style: italic">// Replace low-res skybox with high-res skybox.</span><span style="color: #bbbbbb"></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: #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: #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: #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: #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: #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: #bbbbbb"></span>
|
||||
<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);
|
||||
});
|
||||
</pre></div>
|
||||
|
||||
<h2>Introduce trackball rotation</h2>
|
||||
@@ -241,13 +241,13 @@ listens for drag events and computes a rotation matrix.</p>
|
||||
|
||||
<p>Next, replace the <strong>initialize gltumble</strong> and <strong>apply gltumble matrix</strong> comments with the following
|
||||
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: #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>});
|
||||
</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>
|
||||
<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>
|
||||
tcm.setTransform(inst,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.trackball.getMatrix());<span style="color: #bbbbbb"></span>
|
||||
inst.<span style="color: #AA22FF; font-weight: bold">delete</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: #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: #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);
|
||||
tcm.setTransform(inst,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.trackball.getMatrix());
|
||||
inst.<span style="color: #AA22FF; font-weight: bold">delete</span>();
|
||||
</pre></div>
|
||||
|
||||
<p>That's it, we now have a fast-loading interactive demo. The complete JavaScript file is available
|
||||
|
||||
@@ -22,9 +22,9 @@ a mobile-friendly page with a full-screen canvas.</p>
|
||||
<<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">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">style</span>><span style="color: #bbbbbb"></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: #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: #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: #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: #008000; font-weight: bold">style</span>>
|
||||
</<span style="color: #008000; font-weight: bold">head</span>>
|
||||
<<span style="color: #008000; font-weight: bold">body</span>>
|
||||
@@ -48,24 +48,24 @@ a mobile-friendly page with a full-screen canvas.</p>
|
||||
<li><code>triangle.js</code> will contain your application code.</li>
|
||||
</ul>
|
||||
<p>Go ahead and create <code>triangle.js</code> with the following content.</p>
|
||||
<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>
|
||||
<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: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create entities</span><span style="color: #bbbbbb"></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: #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: #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: #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: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>render()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></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: #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: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>resize()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></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: #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><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">constructor</span>()<span style="color: #bbbbbb"> </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: #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: #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: #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: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||
<span style="color: #bbbbbb"> </span>}
|
||||
<span style="color: #bbbbbb"> </span>render()<span style="color: #bbbbbb"> </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: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||
<span style="color: #bbbbbb"> </span>}
|
||||
<span style="color: #bbbbbb"> </span>resize()<span style="color: #bbbbbb"> </span>{
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: adjust viewport and canvas</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: #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>);
|
||||
</pre></div>
|
||||
|
||||
<p>The two calls to <code>bind()</code> allow us to pass instance methods as callbacks for animation and resize
|
||||
@@ -81,9 +81,9 @@ that define a PBR material. We'll learn more about material packages in the
|
||||
<h2>Spawn a local server</h2>
|
||||
<p>Because of CORS restrictions, your web app cannot fetch the material package directly from the
|
||||
file system. One way around this is to create a temporary server using Python or node:</p>
|
||||
<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>
|
||||
python -m SimpleHTTPServer <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>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>python3<span style="color: #bbbbbb"> </span>-m<span style="color: #bbbbbb"> </span>http.server<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic"># Python 3</span>
|
||||
python<span style="color: #bbbbbb"> </span>-m<span style="color: #bbbbbb"> </span>SimpleHTTPServer<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic"># Python 2.7</span>
|
||||
npx<span style="color: #bbbbbb"> </span>http-server<span style="color: #bbbbbb"> </span>-p<span style="color: #bbbbbb"> </span><span style="color: #666666">8000</span><span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic"># nodejs</span>
|
||||
</pre></div>
|
||||
|
||||
<p>To see if this works, navigate to <a href="http://localhost:8000">http://localhost:8000</a> and check if you
|
||||
@@ -93,8 +93,8 @@ with the correct MIME type.</p>
|
||||
<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
|
||||
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>
|
||||
<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>
|
||||
<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: #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);
|
||||
</pre></div>
|
||||
|
||||
<p>The above snippet creates the <code>Engine</code> by passing it a canvas DOM object. The engine needs the
|
||||
@@ -102,9 +102,9 @@ canvas in order to create a WebGL 2.0 context in its contructor.</p>
|
||||
<p>The engine is a factory for many Filament entities, including <code>Scene</code>, which is a flat container of
|
||||
entities. Let's go ahead and create a scene, then add a blank entity called <code>triangle</code> into the
|
||||
scene.</p>
|
||||
<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>
|
||||
<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>.scene.addEntity(<span style="color: #008000; font-weight: bold">this</span>.triangle);<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: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </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: #008000; font-weight: bold">this</span>.scene.addEntity(<span style="color: #008000; font-weight: bold">this</span>.triangle);
|
||||
</pre></div>
|
||||
|
||||
<p>Filament uses an <a href="//en.wikipedia.org/wiki/Entity-component-system">Entity-Component System</a>.
|
||||
@@ -114,28 +114,28 @@ calls.</p>
|
||||
<h2>Construct typed arrays</h2>
|
||||
<p>Next we'll create two typed arrays: a positions array with XY coordinates for each vertex, and a
|
||||
colors array with a 32-bit word for each vertex.</p>
|
||||
<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>
|
||||
<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: #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: #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: #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: #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><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: #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: #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: #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: #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>]);
|
||||
</pre></div>
|
||||
|
||||
<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>
|
||||
<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">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: #bbbbbb"> </span>.vertexCount(<span style="color: #666666">3</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.bufferCount(<span style="color: #666666">2</span>)<span style="color: #bbbbbb"></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: #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: #bbbbbb"> </span>.normalized(VertexAttribute.COLOR)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine);<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: #bbbbbb"> </span>VertexAttribute<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </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: #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>.vertexCount(<span style="color: #666666">3</span>)
|
||||
<span style="color: #bbbbbb"> </span>.bufferCount(<span style="color: #666666">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>.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>.normalized(VertexAttribute.COLOR)
|
||||
<span style="color: #bbbbbb"> </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: #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: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </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);
|
||||
</pre></div>
|
||||
|
||||
<p>The above snippet first creates aliases for two enum types, then constructs the vertex buffer using
|
||||
@@ -149,12 +149,12 @@ attribute. Alternatively, we could have interleaved or concatenated these attrib
|
||||
buffer slot.</p>
|
||||
<p>Next we'll construct an index buffer. The index buffer for our triangle is trivial: it simply holds
|
||||
the integers 0,1,2.</p>
|
||||
<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>
|
||||
<span style="color: #bbbbbb"> </span>.indexCount(<span style="color: #666666">3</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.bufferType(Filament.IndexBuffer$IndexType.USHORT)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine);<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: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.IndexBuffer.Builder()
|
||||
<span style="color: #bbbbbb"> </span>.indexCount(<span style="color: #666666">3</span>)
|
||||
<span style="color: #bbbbbb"> </span>.bufferType(Filament.IndexBuffer$IndexType.USHORT)
|
||||
<span style="color: #bbbbbb"> </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: #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>]));
|
||||
</pre></div>
|
||||
|
||||
<p>Note that constructing an index buffer is similar to constructing a vertex buffer, but it only has
|
||||
@@ -167,29 +167,29 @@ parameters, and they can be bound to renderables. We'll learn more about ma
|
||||
next tutorial.</p>
|
||||
<p>After extracting the material instance, we can finally create a renderable component for the
|
||||
triangle by setting up a bounding box and passing in the vertex and index buffers.</p>
|
||||
<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>
|
||||
<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>
|
||||
Filament.RenderableManager.Builder(<span style="color: #666666">1</span>)<span style="color: #bbbbbb"></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: #bbbbbb"> </span>.material(<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>matinst)<span style="color: #bbbbbb"></span>
|
||||
<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: #bbbbbb"> </span>.build(engine,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.triangle);<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: #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: #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();
|
||||
Filament.RenderableManager.Builder(<span style="color: #666666">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>.material(<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </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>.build(engine,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.triangle);
|
||||
</pre></div>
|
||||
|
||||
<p>Next let's wrap up the initialization routine by creating the swap chain, renderer, camera, and
|
||||
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>
|
||||
<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>.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>.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.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>
|
||||
<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: #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: #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: #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: #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: #3D7B7B; font-style: italic">// Set up a blue-green background:</span><span style="color: #bbbbbb"></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: #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: #3D7B7B; font-style: italic">// Adjust the initial viewport:</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.resize();<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();
|
||||
</pre></div>
|
||||
|
||||
<p>At this point, we're done creating all Filament entities, and the code should run without errors.
|
||||
@@ -197,24 +197,24 @@ However the canvas is still blank!</p>
|
||||
<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
|
||||
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>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: render scene</span><span style="color: #bbbbbb"></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: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>render()<span style="color: #bbbbbb"> </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: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||
}
|
||||
</pre></div>
|
||||
|
||||
<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>
|
||||
<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>
|
||||
<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: #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: #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: #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>
|
||||
tcm.setTransform(inst,<span style="color: #bbbbbb"> </span>transform);<span style="color: #bbbbbb"></span>
|
||||
inst.<span style="color: #AA22FF; font-weight: bold">delete</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: #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: #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: #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);
|
||||
tcm.setTransform(inst,<span style="color: #bbbbbb"> </span>transform);
|
||||
inst.<span style="color: #AA22FF; font-weight: bold">delete</span>();
|
||||
|
||||
<span style="color: #3D7B7B; font-style: italic">// Render the frame.</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: #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);
|
||||
</pre></div>
|
||||
|
||||
<p>The first half of our render method obtains the transform component of the triangle entity and uses
|
||||
@@ -225,14 +225,14 @@ that it wants to skip a frame, hence the <code>if</code> statement.</p>
|
||||
<p>One last step. Add the following code to the resize method. This adjusts the resolution of the
|
||||
rendering surface when the window size changes, taking <code>devicePixelRatio</code> into account for high-DPI
|
||||
displays. It also adjusts the camera frustum accordingly.</p>
|
||||
<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>
|
||||
<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: #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">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>
|
||||
<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: #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: #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: #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: #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: #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">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">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: #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: #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>);
|
||||
</pre></div>
|
||||
|
||||
<p>You should now have a spinning triangle! The completed JavaScript is available
|
||||
|
||||
@@ -179,12 +179,15 @@ if (FILAMENT_SUPPORTS_VULKAN)
|
||||
src/vulkan/VulkanPipelineCache.cpp
|
||||
src/vulkan/VulkanPipelineCache.h
|
||||
src/vulkan/VulkanPlatform.cpp
|
||||
src/vulkan/VulkanReadPixels.cpp
|
||||
src/vulkan/VulkanReadPixels.h
|
||||
src/vulkan/VulkanSamplerCache.cpp
|
||||
src/vulkan/VulkanSamplerCache.h
|
||||
src/vulkan/VulkanStagePool.cpp
|
||||
src/vulkan/VulkanStagePool.h
|
||||
src/vulkan/VulkanSwapChain.cpp
|
||||
src/vulkan/VulkanSwapChain.h
|
||||
src/vulkan/VulkanTaskHandler.h
|
||||
src/vulkan/VulkanTexture.cpp
|
||||
src/vulkan/VulkanTexture.h
|
||||
src/vulkan/VulkanUtility.cpp
|
||||
|
||||
@@ -1287,6 +1287,7 @@ void MetalDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y,
|
||||
fromRegion:srcRegion
|
||||
mipmapLevel:0];
|
||||
scheduleDestroy(std::move(*p));
|
||||
delete p;
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ constexpr inline GLenum getBufferBindingType(BufferObjectBinding bindingType) no
|
||||
case BufferObjectBinding::UNIFORM:
|
||||
return GL_UNIFORM_BUFFER;
|
||||
case BufferObjectBinding::SHADER_STORAGE:
|
||||
#if defined(GL_VERSION_4_1) || defined(GL_ES_VERSION_3_1)
|
||||
#if defined(BACKEND_OPENGL_LEVEL_GLES31)
|
||||
return GL_SHADER_STORAGE_BUFFER;
|
||||
#else
|
||||
utils::panic(__func__, __FILE__, __LINE__, "SHADER_STORAGE not supported");
|
||||
@@ -423,7 +423,7 @@ constexpr /* inline */ GLenum getInternalFormat(TextureFormat format) noexcept {
|
||||
case TextureFormat::RGBA32I: return GL_RGBA32I;
|
||||
|
||||
// compressed formats
|
||||
#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_4_3) || defined(GL_ARB_ES3_compatibility)
|
||||
#if defined(GL_ES_VERSION_3_0) || defined(BACKEND_OPENGL_VERSION_GL) || defined(GL_ARB_ES3_compatibility)
|
||||
case TextureFormat::EAC_R11: return GL_COMPRESSED_R11_EAC;
|
||||
case TextureFormat::EAC_R11_SIGNED: return GL_COMPRESSED_SIGNED_R11_EAC;
|
||||
case TextureFormat::EAC_RG11: return GL_COMPRESSED_RG11_EAC;
|
||||
|
||||
@@ -28,17 +28,17 @@ using namespace utils;
|
||||
namespace filament::backend {
|
||||
|
||||
bool OpenGLContext::queryOpenGLVersion(GLint* major, GLint* minor) noexcept {
|
||||
if constexpr (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GLES) {
|
||||
char const* version = (char const*)glGetString(GL_VERSION);
|
||||
// This works on all versions of GLES
|
||||
int const n = version ? sscanf(version, "OpenGL ES %d.%d", major, minor) : 0;
|
||||
return n == 2;
|
||||
} else if constexpr (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL) {
|
||||
// OpenGL version
|
||||
glGetIntegerv(GL_MAJOR_VERSION, major);
|
||||
glGetIntegerv(GL_MINOR_VERSION, minor);
|
||||
return (glGetError() == GL_NO_ERROR);
|
||||
}
|
||||
#ifdef BACKEND_OPENGL_VERSION_GLES
|
||||
char const* version = (char const*)glGetString(GL_VERSION);
|
||||
// This works on all versions of GLES
|
||||
int const n = version ? sscanf(version, "OpenGL ES %d.%d", major, minor) : 0;
|
||||
return n == 2;
|
||||
#else
|
||||
// OpenGL version
|
||||
glGetIntegerv(GL_MAJOR_VERSION, major);
|
||||
glGetIntegerv(GL_MINOR_VERSION, minor);
|
||||
return (glGetError() == GL_NO_ERROR);
|
||||
#endif
|
||||
}
|
||||
|
||||
OpenGLContext::OpenGLContext() noexcept {
|
||||
@@ -73,50 +73,48 @@ OpenGLContext::OpenGLContext() noexcept {
|
||||
constexpr GLint MAX_VERTEX_SAMPLER_COUNT = caps3.MAX_VERTEX_SAMPLER_COUNT;
|
||||
constexpr GLint MAX_FRAGMENT_SAMPLER_COUNT = caps3.MAX_FRAGMENT_SAMPLER_COUNT;
|
||||
|
||||
if constexpr (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GLES) {
|
||||
#if defined(GL_ES_VERSION_2_0)
|
||||
initExtensionsGLES();
|
||||
#endif
|
||||
if (state.major == 3) {
|
||||
assert_invariant(gets.max_texture_image_units >= 16);
|
||||
assert_invariant(gets.max_combined_texture_image_units >= 32);
|
||||
if (state.minor >= 1) {
|
||||
features.multisample_texture = true;
|
||||
// figure out our feature level
|
||||
if (ext.EXT_texture_cube_map_array) {
|
||||
mFeatureLevel = FeatureLevel::FEATURE_LEVEL_2;
|
||||
if (gets.max_texture_image_units >= MAX_FRAGMENT_SAMPLER_COUNT &&
|
||||
gets.max_combined_texture_image_units >=
|
||||
(MAX_FRAGMENT_SAMPLER_COUNT + MAX_VERTEX_SAMPLER_COUNT)) {
|
||||
mFeatureLevel = FeatureLevel::FEATURE_LEVEL_3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if constexpr (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL) {
|
||||
#if defined(GL_VERSION_4_1)
|
||||
initExtensionsGL();
|
||||
#endif
|
||||
if (state.major == 4) {
|
||||
assert_invariant(state.minor >= 1);
|
||||
mShaderModel = ShaderModel::DESKTOP;
|
||||
if (state.minor >= 3) {
|
||||
// cubemap arrays are available as of OpenGL 4.0
|
||||
#ifdef BACKEND_OPENGL_VERSION_GLES
|
||||
initExtensionsGLES();
|
||||
if (state.major == 3) {
|
||||
// Runtime OpenGL version is ES 3.x
|
||||
assert_invariant(gets.max_texture_image_units >= 16);
|
||||
assert_invariant(gets.max_combined_texture_image_units >= 32);
|
||||
if (state.minor >= 1) {
|
||||
features.multisample_texture = true;
|
||||
// figure out our feature level
|
||||
if (ext.EXT_texture_cube_map_array) {
|
||||
mFeatureLevel = FeatureLevel::FEATURE_LEVEL_2;
|
||||
// figure out our feature level
|
||||
if (gets.max_texture_image_units >= MAX_FRAGMENT_SAMPLER_COUNT &&
|
||||
gets.max_combined_texture_image_units >=
|
||||
(MAX_FRAGMENT_SAMPLER_COUNT + MAX_VERTEX_SAMPLER_COUNT)) {
|
||||
mFeatureLevel = FeatureLevel::FEATURE_LEVEL_3;
|
||||
}
|
||||
}
|
||||
features.multisample_texture = true;
|
||||
}
|
||||
// feedback loops are allowed on GL desktop as long as writes are disabled
|
||||
bugs.allow_read_only_ancillary_feedback_loop = true;
|
||||
assert_invariant(gets.max_texture_image_units >= 16);
|
||||
assert_invariant(gets.max_combined_texture_image_units >= 32);
|
||||
}
|
||||
#else
|
||||
initExtensionsGL();
|
||||
if (state.major == 4) {
|
||||
assert_invariant(state.minor >= 1);
|
||||
mShaderModel = ShaderModel::DESKTOP;
|
||||
if (state.minor >= 3) {
|
||||
// cubemap arrays are available as of OpenGL 4.0
|
||||
mFeatureLevel = FeatureLevel::FEATURE_LEVEL_2;
|
||||
// figure out our feature level
|
||||
if (gets.max_texture_image_units >= MAX_FRAGMENT_SAMPLER_COUNT &&
|
||||
gets.max_combined_texture_image_units >=
|
||||
(MAX_FRAGMENT_SAMPLER_COUNT + MAX_VERTEX_SAMPLER_COUNT)) {
|
||||
mFeatureLevel = FeatureLevel::FEATURE_LEVEL_3;
|
||||
}
|
||||
}
|
||||
features.multisample_texture = true;
|
||||
}
|
||||
// feedback loops are allowed on GL desktop as long as writes are disabled
|
||||
bugs.allow_read_only_ancillary_feedback_loop = true;
|
||||
assert_invariant(gets.max_texture_image_units >= 16);
|
||||
assert_invariant(gets.max_combined_texture_image_units >= 32);
|
||||
#endif
|
||||
|
||||
#ifdef GL_EXT_texture_filter_anisotropic
|
||||
if (ext.EXT_texture_filter_anisotropic) {
|
||||
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gets.max_anisotropy);
|
||||
@@ -337,7 +335,7 @@ void OpenGLContext::setDefaultState() noexcept {
|
||||
|
||||
// Point sprite size and seamless cubemap filtering are disabled by default in desktop GL.
|
||||
// In OpenGL ES, these flags do not exist because they are always on.
|
||||
#if BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL
|
||||
#ifdef BACKEND_OPENGL_VERSION_GL
|
||||
glEnable(GL_PROGRAM_POINT_SIZE);
|
||||
enable(GL_PROGRAM_POINT_SIZE);
|
||||
#endif
|
||||
@@ -351,14 +349,16 @@ void OpenGLContext::setDefaultState() noexcept {
|
||||
glHint(GL_FRAGMENT_SHADER_DERIVATIVE_HINT, GL_NICEST);
|
||||
#endif
|
||||
|
||||
#if defined(GL_EXT_clip_control) || defined(GL_ARB_clip_control) || defined(GL_VERSION_4_5)
|
||||
if (ext.EXT_clip_control) {
|
||||
#if defined(BACKEND_OPENGL_VERSION_GL)
|
||||
glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
|
||||
}
|
||||
#elif defined(GL_EXT_clip_control)
|
||||
glClipControlEXT(GL_LOWER_LEFT_EXT, GL_ZERO_TO_ONE_EXT);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(GL_ES_VERSION_2_0)
|
||||
#ifdef BACKEND_OPENGL_VERSION_GLES
|
||||
|
||||
void OpenGLContext::initExtensionsGLES() noexcept {
|
||||
const char * const extensions = (const char*)glGetString(GL_EXTENSIONS);
|
||||
@@ -394,7 +394,6 @@ void OpenGLContext::initExtensionsGLES() noexcept {
|
||||
ext.KHR_texture_compression_astc_hdr = exts.has("GL_KHR_texture_compression_astc_hdr"sv);
|
||||
ext.KHR_texture_compression_astc_ldr = exts.has("GL_KHR_texture_compression_astc_ldr"sv);
|
||||
ext.OES_EGL_image_external_essl3 = exts.has("GL_OES_EGL_image_external_essl3"sv);
|
||||
ext.QCOM_tiled_rendering = exts.has("GL_QCOM_tiled_rendering"sv);
|
||||
ext.WEBGL_compressed_texture_etc = exts.has("WEBGL_compressed_texture_etc"sv);
|
||||
ext.WEBGL_compressed_texture_s3tc = exts.has("WEBGL_compressed_texture_s3tc"sv);
|
||||
ext.WEBGL_compressed_texture_s3tc_srgb = exts.has("WEBGL_compressed_texture_s3tc_srgb"sv);
|
||||
@@ -404,9 +403,9 @@ void OpenGLContext::initExtensionsGLES() noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
#endif // defined(GL_ES_VERSION_2_0)
|
||||
#endif // BACKEND_OPENGL_VERSION_GLES
|
||||
|
||||
#if defined(GL_VERSION_4_1)
|
||||
#ifdef BACKEND_OPENGL_VERSION_GL
|
||||
|
||||
void OpenGLContext::initExtensionsGL() noexcept {
|
||||
GLUtils::unordered_string_set exts;
|
||||
@@ -427,7 +426,7 @@ void OpenGLContext::initExtensionsGL() noexcept {
|
||||
auto minor = state.minor;
|
||||
ext.APPLE_color_buffer_packed_float = true; // Assumes core profile.
|
||||
ext.ARB_shading_language_packing = exts.has("GL_ARB_shading_language_packing"sv) || (major == 4 && minor >= 2);
|
||||
ext.EXT_clip_control = exts.has("GL_ARB_clip_control"sv) || (major == 4 && minor >= 5);
|
||||
ext.EXT_clip_control = (major == 4 && minor >= 5);
|
||||
ext.EXT_color_buffer_float = true; // Assumes core profile.
|
||||
ext.EXT_color_buffer_half_float = true; // Assumes core profile.
|
||||
ext.EXT_debug_marker = exts.has("GL_EXT_debug_marker"sv);
|
||||
@@ -448,13 +447,12 @@ void OpenGLContext::initExtensionsGL() noexcept {
|
||||
ext.KHR_texture_compression_astc_hdr = exts.has("GL_KHR_texture_compression_astc_hdr"sv);
|
||||
ext.KHR_texture_compression_astc_ldr = exts.has("GL_KHR_texture_compression_astc_ldr"sv);
|
||||
ext.OES_EGL_image_external_essl3 = false;
|
||||
ext.QCOM_tiled_rendering = false;
|
||||
ext.WEBGL_compressed_texture_etc = false;
|
||||
ext.WEBGL_compressed_texture_s3tc = false;
|
||||
ext.WEBGL_compressed_texture_s3tc_srgb = false;
|
||||
}
|
||||
|
||||
#endif // defined(GL_VERSION_4_1)
|
||||
#endif // BACKEND_OPENGL_VERSION_GL
|
||||
|
||||
void OpenGLContext::bindBuffer(GLenum target, GLuint buffer) noexcept {
|
||||
if (target == GL_ELEMENT_ARRAY_BUFFER) {
|
||||
@@ -636,7 +634,7 @@ void OpenGLContext::resetState() noexcept {
|
||||
GLenum const bufferTargets[] = {
|
||||
GL_UNIFORM_BUFFER,
|
||||
GL_TRANSFORM_FEEDBACK_BUFFER,
|
||||
#if !defined(__EMSCRIPTEN__) && (defined(GL_VERSION_4_1) || defined(GL_ES_VERSION_3_1))
|
||||
#if defined(BACKEND_OPENGL_LEVEL_GLES31)
|
||||
GL_SHADER_STORAGE_BUFFER,
|
||||
#endif
|
||||
GL_ARRAY_BUFFER,
|
||||
@@ -667,14 +665,14 @@ void OpenGLContext::resetState() noexcept {
|
||||
{ GL_TEXTURE_2D_ARRAY, true },
|
||||
{ GL_TEXTURE_CUBE_MAP, true },
|
||||
{ GL_TEXTURE_3D, true },
|
||||
#if !defined(__EMSCRIPTEN__)
|
||||
#if defined(GL_VERSION_4_1) || defined(GL_ES_VERSION_3_1)
|
||||
#if defined(BACKEND_OPENGL_LEVEL_GLES31)
|
||||
{ GL_TEXTURE_2D_MULTISAMPLE, true },
|
||||
#endif
|
||||
#if !defined(__EMSCRIPTEN__)
|
||||
#if defined(GL_OES_EGL_image_external)
|
||||
{ GL_TEXTURE_EXTERNAL_OES, ext.OES_EGL_image_external_essl3 },
|
||||
#endif
|
||||
#if defined(GL_VERSION_4_1) || defined(GL_EXT_texture_cube_map_array)
|
||||
#if defined(BACKEND_OPENGL_VERSION_GL) || defined(GL_EXT_texture_cube_map_array)
|
||||
{ GL_TEXTURE_CUBE_MAP_ARRAY, ext.EXT_texture_cube_map_array },
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -69,6 +69,24 @@ public:
|
||||
|
||||
OpenGLContext() noexcept;
|
||||
|
||||
constexpr bool isAtLeastGL(int major, int minor) const noexcept {
|
||||
#ifdef BACKEND_OPENGL_VERSION_GL
|
||||
return state.major > major || (state.major == major && state.minor >= minor);
|
||||
#else
|
||||
(void)major, (void)minor;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr bool isAtLeastGLES(int major, int minor) const noexcept {
|
||||
#ifdef BACKEND_OPENGL_VERSION_GLES
|
||||
return state.major > major || (state.major == major && state.minor >= minor);
|
||||
#else
|
||||
(void)major, (void)minor;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr static inline size_t getIndexForTextureTarget(GLuint target) noexcept;
|
||||
constexpr inline size_t getIndexForCap(GLenum cap) noexcept;
|
||||
constexpr static inline size_t getIndexForBufferTarget(GLenum target) noexcept;
|
||||
@@ -184,7 +202,6 @@ public:
|
||||
bool KHR_texture_compression_astc_hdr;
|
||||
bool KHR_texture_compression_astc_ldr;
|
||||
bool OES_EGL_image_external_essl3;
|
||||
bool QCOM_tiled_rendering;
|
||||
bool WEBGL_compressed_texture_etc;
|
||||
bool WEBGL_compressed_texture_s3tc;
|
||||
bool WEBGL_compressed_texture_s3tc_srgb;
|
||||
@@ -413,10 +430,10 @@ private:
|
||||
RenderPrimitive mDefaultVAO;
|
||||
|
||||
// this is chosen to minimize code size
|
||||
#if defined(GL_ES_VERSION_2_0)
|
||||
#if defined(BACKEND_OPENGL_VERSION_GLES)
|
||||
void initExtensionsGLES() noexcept;
|
||||
#endif
|
||||
#if defined(GL_VERSION_4_1)
|
||||
#if defined(BACKEND_OPENGL_VERSION_GL)
|
||||
void initExtensionsGL() noexcept;
|
||||
#endif
|
||||
|
||||
@@ -443,7 +460,7 @@ constexpr size_t OpenGLContext::getIndexForTextureTarget(GLuint target) noexcept
|
||||
case GL_TEXTURE_2D: return 0;
|
||||
case GL_TEXTURE_2D_ARRAY: return 1;
|
||||
case GL_TEXTURE_CUBE_MAP: return 2;
|
||||
#if defined(GL_VERSION_4_1) || defined(GL_ES_VERSION_3_1)
|
||||
#if defined(BACKEND_OPENGL_LEVEL_GLES31)
|
||||
case GL_TEXTURE_2D_MULTISAMPLE: return 3;
|
||||
#endif
|
||||
case GL_TEXTURE_EXTERNAL_OES: return 4;
|
||||
@@ -469,7 +486,7 @@ constexpr size_t OpenGLContext::getIndexForCap(GLenum cap) noexcept { //NOLINT
|
||||
#ifdef GL_ARB_seamless_cube_map
|
||||
case GL_TEXTURE_CUBE_MAP_SEAMLESS: index = 9; break;
|
||||
#endif
|
||||
#if BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL
|
||||
#ifdef BACKEND_OPENGL_VERSION_GL
|
||||
case GL_PROGRAM_POINT_SIZE: index = 10; break;
|
||||
#endif
|
||||
default: break;
|
||||
@@ -484,7 +501,7 @@ constexpr size_t OpenGLContext::getIndexForBufferTarget(GLenum target) noexcept
|
||||
// The indexed buffers MUST be first in this list (those usable with bindBufferRange)
|
||||
case GL_UNIFORM_BUFFER: index = 0; break;
|
||||
case GL_TRANSFORM_FEEDBACK_BUFFER: index = 1; break;
|
||||
#if defined(GL_VERSION_4_1) || defined(GL_ES_VERSION_3_1)
|
||||
#if defined(BACKEND_OPENGL_LEVEL_GLES31)
|
||||
case GL_SHADER_STORAGE_BUFFER: index = 2; break;
|
||||
#endif
|
||||
case GL_ARRAY_BUFFER: index = 3; break;
|
||||
|
||||
@@ -131,18 +131,18 @@ Driver* OpenGLDriver::create(OpenGLPlatform* const platform,
|
||||
return {};
|
||||
}
|
||||
|
||||
if constexpr (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GLES) {
|
||||
if (UTILS_UNLIKELY(!(major >= 3 && minor >= 0))) {
|
||||
PANIC_LOG("OpenGL ES 3.0 minimum needed (current %d.%d)", major, minor);
|
||||
goto cleanup;
|
||||
}
|
||||
} else if constexpr (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL) {
|
||||
// we require GL 4.1 headers and minimum version
|
||||
if (UTILS_UNLIKELY(!((major == 4 && minor >= 1) || major > 4))) {
|
||||
PANIC_LOG("OpenGL 4.1 minimum needed (current %d.%d)", major, minor);
|
||||
goto cleanup;
|
||||
}
|
||||
#if defined(BACKEND_OPENGL_VERSION_GLES)
|
||||
if (UTILS_UNLIKELY(!(major >= 3 && minor >= 0))) {
|
||||
PANIC_LOG("OpenGL ES 3.0 minimum needed (current %d.%d)", major, minor);
|
||||
goto cleanup;
|
||||
}
|
||||
#else
|
||||
// we require GL 4.1 headers and minimum version
|
||||
if (UTILS_UNLIKELY(!((major == 4 && minor >= 1) || major > 4))) {
|
||||
PANIC_LOG("OpenGL 4.1 minimum needed (current %d.%d)", major, minor);
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t const defaultSize = FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
|
||||
Platform::DriverConfig const validConfig {
|
||||
@@ -182,9 +182,13 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfi
|
||||
// Timer queries are core in GL 3.3, otherwise we need EXT_disjoint_timer_query
|
||||
// iOS headers don't define GL_EXT_disjoint_timer_query, so make absolutely sure
|
||||
// we won't use it.
|
||||
#if defined(GL_VERSION_3_3) || defined(GL_EXT_disjoint_timer_query)
|
||||
if (mContext.ext.EXT_disjoint_timer_query ||
|
||||
BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL) {
|
||||
|
||||
#if defined(BACKEND_OPENGL_VERSION_GL)
|
||||
assert_invariant(mContext.ext.EXT_disjoint_timer_query);
|
||||
#endif
|
||||
|
||||
#if defined(BACKEND_OPENGL_VERSION_GL) || defined(GL_EXT_disjoint_timer_query)
|
||||
if (mContext.ext.EXT_disjoint_timer_query) {
|
||||
// timer queries are available
|
||||
if (mContext.bugs.dont_use_timer_query && mPlatform.canCreateFence()) {
|
||||
// however, they don't work well, revert to using fences if we can.
|
||||
@@ -545,25 +549,29 @@ void OpenGLDriver::textureStorage(OpenGLDriver::GLTexture* t,
|
||||
GLsizei(width), GLsizei(height), GLsizei(depth) * 6);
|
||||
break;
|
||||
}
|
||||
#if defined(GL_VERSION_4_1) || defined(GL_ES_VERSION_3_1)
|
||||
#ifdef BACKEND_OPENGL_LEVEL_GLES31
|
||||
case GL_TEXTURE_2D_MULTISAMPLE:
|
||||
if constexpr (TEXTURE_2D_MULTISAMPLE_SUPPORTED) {
|
||||
// NOTE: if there is a mix of texture and renderbuffers, "fixed_sample_locations" must be true
|
||||
// NOTE: what's the benefit of setting "fixed_sample_locations" to false?
|
||||
#if BACKEND_OPENGL_LEVEL >= BACKEND_OPENGL_LEVEL_GLES31
|
||||
// only supported from GL 4.3 and GLES 3.1 headers
|
||||
glTexStorage2DMultisample(t->gl.target, t->samples, t->gl.internalFormat,
|
||||
GLsizei(width), GLsizei(height), GL_TRUE);
|
||||
#elif defined(GL_VERSION_4_1)
|
||||
// only supported in GL (GL4.1 doesn't support glTexStorage2DMultisample)
|
||||
glTexImage2DMultisample(t->gl.target, t->samples, t->gl.internalFormat,
|
||||
GLsizei(width), GLsizei(height), GL_TRUE);
|
||||
|
||||
if (mContext.isAtLeastGL(4, 3) || mContext.isAtLeastGLES(3, 1)) {
|
||||
// only supported from GL 4.3 and GLES 3.1 headers
|
||||
glTexStorage2DMultisample(t->gl.target, t->samples, t->gl.internalFormat,
|
||||
GLsizei(width), GLsizei(height), GL_TRUE);
|
||||
}
|
||||
#ifdef BACKEND_OPENGL_VERSION_GL
|
||||
else {
|
||||
// only supported in GL (GL4.1 doesn't support glTexStorage2DMultisample)
|
||||
glTexImage2DMultisample(t->gl.target, t->samples, t->gl.internalFormat,
|
||||
GLsizei(width), GLsizei(height), GL_TRUE);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
PANIC_LOG("GL_TEXTURE_2D_MULTISAMPLE is not supported");
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#endif // BACKEND_OPENGL_LEVEL_GLES31
|
||||
default: // cannot happen
|
||||
break;
|
||||
}
|
||||
@@ -631,7 +639,7 @@ void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
|
||||
if (t->samples > 1) {
|
||||
// Note: we can't be here in practice because filament's user API doesn't
|
||||
// allow the creation of multi-sampled textures.
|
||||
#if defined(GL_VERSION_4_1) || defined(GL_ES_VERSION_3_1)
|
||||
#if defined(BACKEND_OPENGL_LEVEL_GLES31)
|
||||
if (gl.features.multisample_texture) {
|
||||
// multi-sample texture on GL 3.2 / GLES 3.1 and above
|
||||
t->gl.target = GL_TEXTURE_2D_MULTISAMPLE;
|
||||
@@ -733,7 +741,7 @@ void OpenGLDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
|
||||
if (t->samples > 1) {
|
||||
// Note: we can't be here in practice because filament's user API doesn't
|
||||
// allow the creation of multi-sampled textures.
|
||||
#if defined(GL_VERSION_4_1) || defined(GL_ES_VERSION_3_1)
|
||||
#if defined(BACKEND_OPENGL_LEVEL_GLES31)
|
||||
if (gl.features.multisample_texture) {
|
||||
// multi-sample texture on GL 3.2 / GLES 3.1 and above
|
||||
t->gl.target = GL_TEXTURE_2D_MULTISAMPLE;
|
||||
@@ -922,7 +930,7 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
||||
case GL_TEXTURE_2D:
|
||||
#if defined(GL_VERSION_4_1) || defined(GL_ES_VERSION_3_1)
|
||||
#if defined(BACKEND_OPENGL_LEVEL_GLES31)
|
||||
case GL_TEXTURE_2D_MULTISAMPLE:
|
||||
#endif
|
||||
if (any(t->usage & TextureUsage::SAMPLEABLE)) {
|
||||
@@ -1649,7 +1657,7 @@ bool OpenGLDriver::isRenderTargetFormatSupported(TextureFormat format) {
|
||||
|
||||
// Three-component SRGB is a color-renderable texture format in core OpenGL on desktop.
|
||||
case TextureFormat::SRGB8:
|
||||
return BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL;
|
||||
return mContext.isAtLeastGL(4, 5);
|
||||
|
||||
// Half-float formats, requires extension.
|
||||
case TextureFormat::R16F:
|
||||
@@ -1979,7 +1987,7 @@ void OpenGLDriver::generateMipmaps(Handle<HwTexture> th) {
|
||||
|
||||
auto& gl = mContext;
|
||||
GLTexture* t = handle_cast<GLTexture *>(th);
|
||||
#if defined(GL_VERSION_4_1) || defined(GL_ES_VERSION_3_1)
|
||||
#if defined(BACKEND_OPENGL_LEVEL_GLES31)
|
||||
assert_invariant(t->gl.target != GL_TEXTURE_2D_MULTISAMPLE);
|
||||
#endif
|
||||
// Note: glGenerateMimap can also fail if the internal format is not both
|
||||
@@ -2385,21 +2393,20 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
|
||||
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_FRAMEBUFFER)
|
||||
|
||||
// glInvalidateFramebuffer appeared on GLES 3.0 and GL4.3, for simplicity we just
|
||||
// ignore it on GL (rather than having to do a runtime check).
|
||||
if (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GLES &&
|
||||
BACKEND_OPENGL_LEVEL >= BACKEND_OPENGL_LEVEL_GLES30) {
|
||||
if (!gl.bugs.disable_invalidate_framebuffer) {
|
||||
AttachmentArray attachments; // NOLINT
|
||||
GLsizei const attachmentCount = getAttachments(attachments, rt, discardFlags);
|
||||
if (attachmentCount) {
|
||||
glInvalidateFramebuffer(GL_FRAMEBUFFER, attachmentCount, attachments.data());
|
||||
}
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
// glInvalidateFramebuffer appeared on GLES 3.0 and GL4.3
|
||||
#if defined(BACKEND_OPENGL_LEVEL_GLES30) || defined(BACKEND_OPENGL_VERSION_GL)
|
||||
if ((mContext.isAtLeastGLES(3, 0) || mContext.isAtLeastGL(4, 3))
|
||||
&& !gl.bugs.disable_invalidate_framebuffer) {
|
||||
AttachmentArray attachments; // NOLINT
|
||||
GLsizei const attachmentCount = getAttachments(attachments, rt, discardFlags);
|
||||
if (attachmentCount) {
|
||||
glInvalidateFramebuffer(GL_FRAMEBUFFER, attachmentCount, attachments.data());
|
||||
}
|
||||
} else {
|
||||
// on GL desktop we assume we don't have glInvalidateFramebuffer, but even if the GPU is
|
||||
// not a tiler, it's important to clear the framebuffer before drawing, as it resets
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
// It's important to clear the framebuffer before drawing, as it resets
|
||||
// the fb to a known state (resets fb compression and possibly other things).
|
||||
// So we use glClear instead of glInvalidateFramebuffer
|
||||
gl.disable(GL_SCISSOR_TEST);
|
||||
@@ -2471,8 +2478,8 @@ void OpenGLDriver::endRenderPass(int) {
|
||||
|
||||
// glInvalidateFramebuffer appeared on GLES 3.0 and GL4.3, for simplicity we just
|
||||
// ignore it on GL (rather than having to do a runtime check).
|
||||
if (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GLES &&
|
||||
BACKEND_OPENGL_LEVEL >= BACKEND_OPENGL_LEVEL_GLES30) {
|
||||
#if defined(BACKEND_OPENGL_LEVEL_GLES30) || defined(BACKEND_OPENGL_VERSION_GL)
|
||||
if (mContext.isAtLeastGLES(3, 0) || mContext.isAtLeastGL(4, 3)) {
|
||||
auto effectiveDiscardFlags = discardFlags;
|
||||
if (gl.bugs.invalidate_end_only_if_invalidate_start) {
|
||||
effectiveDiscardFlags &= mRenderPassParams.flags.discardStart;
|
||||
@@ -2488,6 +2495,7 @@ void OpenGLDriver::endRenderPass(int) {
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
// clear the discarded buffers in debug builds
|
||||
@@ -3232,7 +3240,7 @@ void OpenGLDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGr
|
||||
|
||||
useProgram(p);
|
||||
|
||||
#if defined(GL_ES_VERSION_3_1) || defined(GL_VERSION_4_3)
|
||||
#if defined(BACKEND_OPENGL_LEVEL_GLES31)
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
// on Android, GLES3.1 and above entry-points are defined in glext
|
||||
@@ -3241,7 +3249,7 @@ void OpenGLDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGr
|
||||
#endif
|
||||
|
||||
glDispatchCompute(workGroupCount.x, workGroupCount.y, workGroupCount.z);
|
||||
#endif
|
||||
#endif // BACKEND_OPENGL_LEVEL_GLES31
|
||||
|
||||
#ifdef FILAMENT_ENABLE_MATDBG
|
||||
CHECK_GL_ERROR_NON_FATAL(utils::slog.e)
|
||||
|
||||
@@ -130,7 +130,7 @@ void OpenGLProgram::compileShaders(OpenGLContext& context,
|
||||
glShaderType = GL_FRAGMENT_SHADER;
|
||||
break;
|
||||
case ShaderStage::COMPUTE:
|
||||
#if defined(GL_VERSION_4_1) || defined(GL_ES_VERSION_3_1)
|
||||
#if defined(BACKEND_OPENGL_LEVEL_GLES31)
|
||||
glShaderType = GL_COMPUTE_SHADER;
|
||||
#else
|
||||
continue;
|
||||
@@ -192,13 +192,12 @@ std::string_view OpenGLProgram::process_GOOGLE_cpp_style_line_directive(OpenGLCo
|
||||
return { source, len };
|
||||
}
|
||||
|
||||
// Tragically, OpenGL 4.1 doesn't support unpackHalf2x16 and
|
||||
// Tragically, OpenGL 4.1 doesn't support unpackHalf2x16 (appeared in 4.2) and
|
||||
// macOS doesn't support GL_ARB_shading_language_packing
|
||||
std::string_view OpenGLProgram::process_ARB_shading_language_packing(OpenGLContext& context) noexcept {
|
||||
using namespace std::literals;
|
||||
if constexpr (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL) {
|
||||
if (context.state.major == 4 && context.state.minor == 1 &&
|
||||
!context.ext.ARB_shading_language_packing) {
|
||||
#ifdef BACKEND_OPENGL_VERSION_GL
|
||||
if (!context.isAtLeastGL(4, 2) && !context.ext.ARB_shading_language_packing) {
|
||||
return R"(
|
||||
|
||||
// these don't handle denormals, NaNs or inf
|
||||
@@ -236,7 +235,7 @@ highp uint packHalf2x16(vec2 v) {
|
||||
}
|
||||
)"sv;
|
||||
}
|
||||
}
|
||||
#endif // BACKEND_OPENGL_VERSION_GL
|
||||
return ""sv;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ OpenGLTimerQueryInterface::~OpenGLTimerQueryInterface() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
#if defined(GL_VERSION_3_3) || defined(GL_EXT_disjoint_timer_query)
|
||||
#if defined(BACKEND_OPENGL_VERSION_GL) || defined(GL_EXT_disjoint_timer_query)
|
||||
|
||||
TimerQueryNative::TimerQueryNative(OpenGLContext&) {
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
virtual uint64_t queryResult(GLTimerQuery* query) = 0;
|
||||
};
|
||||
|
||||
#if defined(GL_VERSION_3_3) || defined(GL_EXT_disjoint_timer_query)
|
||||
#if defined(BACKEND_OPENGL_VERSION_GL) || defined(GL_EXT_disjoint_timer_query)
|
||||
|
||||
class TimerQueryNative : public OpenGLTimerQueryInterface {
|
||||
public:
|
||||
|
||||
@@ -28,10 +28,6 @@ static void getProcAddress(T& pfn, const char* name) noexcept {
|
||||
}
|
||||
|
||||
namespace glext {
|
||||
#ifdef GL_QCOM_tiled_rendering
|
||||
PFNGLSTARTTILINGQCOMPROC glStartTilingQCOM;
|
||||
PFNGLENDTILINGQCOMPROC glEndTilingQCOM;
|
||||
#endif
|
||||
#ifdef GL_OES_EGL_image
|
||||
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
|
||||
#endif
|
||||
@@ -52,7 +48,7 @@ PFNGLGETDEBUGMESSAGELOGKHRPROC glGetDebugMessageLogKHR;
|
||||
PFNGLGETQUERYOBJECTUI64VEXTPROC glGetQueryObjectui64v;
|
||||
#endif
|
||||
#ifdef GL_EXT_clip_control
|
||||
PFNGLCLIPCONTROLEXTPROC glClipControl;
|
||||
PFNGLCLIPCONTROLEXTPROC glClipControlEXT;
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
@@ -65,31 +61,27 @@ static std::once_flag sGlExtInitialized;
|
||||
|
||||
void importGLESExtensionsEntryPoints() {
|
||||
std::call_once(sGlExtInitialized, +[]() {
|
||||
#ifdef GL_QCOM_tiled_rendering
|
||||
getProcAddress(glStartTilingQCOM, "glStartTilingQCOM");
|
||||
getProcAddress(glEndTilingQCOM, "glEndTilingQCOM");
|
||||
#endif
|
||||
#ifdef GL_OES_EGL_image
|
||||
getProcAddress(glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES");
|
||||
getProcAddress(glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES");
|
||||
#endif
|
||||
#if GL_EXT_debug_marker
|
||||
getProcAddress(glInsertEventMarkerEXT, "glInsertEventMarkerEXT");
|
||||
getProcAddress(glPushGroupMarkerEXT, "glPushGroupMarkerEXT");
|
||||
getProcAddress(glPopGroupMarkerEXT, "glPopGroupMarkerEXT");
|
||||
getProcAddress(glInsertEventMarkerEXT, "glInsertEventMarkerEXT");
|
||||
getProcAddress(glPushGroupMarkerEXT, "glPushGroupMarkerEXT");
|
||||
getProcAddress(glPopGroupMarkerEXT, "glPopGroupMarkerEXT");
|
||||
#endif
|
||||
#if GL_EXT_multisampled_render_to_texture
|
||||
getProcAddress(glFramebufferTexture2DMultisampleEXT, "glFramebufferTexture2DMultisampleEXT");
|
||||
getProcAddress(glRenderbufferStorageMultisampleEXT, "glRenderbufferStorageMultisampleEXT");
|
||||
getProcAddress(glFramebufferTexture2DMultisampleEXT, "glFramebufferTexture2DMultisampleEXT");
|
||||
getProcAddress(glRenderbufferStorageMultisampleEXT, "glRenderbufferStorageMultisampleEXT");
|
||||
#endif
|
||||
#ifdef GL_KHR_debug
|
||||
getProcAddress(glDebugMessageCallbackKHR, "glDebugMessageCallbackKHR");
|
||||
getProcAddress(glGetDebugMessageLogKHR, "glGetDebugMessageLogKHR");
|
||||
getProcAddress(glDebugMessageCallbackKHR, "glDebugMessageCallbackKHR");
|
||||
getProcAddress(glGetDebugMessageLogKHR, "glGetDebugMessageLogKHR");
|
||||
#endif
|
||||
#ifdef GL_EXT_disjoint_timer_query
|
||||
getProcAddress(glGetQueryObjectui64v, "glGetQueryObjectui64vEXT");
|
||||
getProcAddress(glGetQueryObjectui64v, "glGetQueryObjectui64vEXT");
|
||||
#endif
|
||||
#ifdef GL_EXT_clip_control
|
||||
getProcAddress(glClipControl, "glClipControlEXT");
|
||||
getProcAddress(glClipControlEXT, "glClipControlEXT");
|
||||
#endif
|
||||
#if defined(__ANDROID__)
|
||||
getProcAddress(glDispatchCompute, "glDispatchCompute");
|
||||
|
||||
@@ -17,6 +17,26 @@
|
||||
#ifndef TNT_FILAMENT_BACKEND_OPENGL_GL_HEADERS_H
|
||||
#define TNT_FILAMENT_BACKEND_OPENGL_GL_HEADERS_H
|
||||
|
||||
/*
|
||||
* Configuration we aim to support:
|
||||
*
|
||||
* GL 4.5 headers
|
||||
* - GL 4.1 runtime (for macOS)
|
||||
* - GL 4.5 runtime
|
||||
*
|
||||
* GLES 2.0 headers
|
||||
* - GLES 2.0 runtime Android only
|
||||
*
|
||||
* GLES 3.0 headers
|
||||
* - GLES 3.0 runtime iOS and WebGL2 only
|
||||
*
|
||||
* GLES 3.1 headers
|
||||
* - GLES 2.0 runtime
|
||||
* - GLES 3.0 runtime
|
||||
* - GLES 3.1 runtime
|
||||
*/
|
||||
|
||||
|
||||
#if defined(__ANDROID__) || defined(FILAMENT_USE_EXTERNAL_GLES3) || defined(__EMSCRIPTEN__)
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
@@ -46,12 +66,22 @@
|
||||
|
||||
#endif
|
||||
|
||||
/* Validate the header configurations we aim to support */
|
||||
|
||||
#if (!defined(GL_ES_VERSION_2_0) && !defined(GL_VERSION_4_1))
|
||||
#error "Minimum header version must be OpenGL ES 2.0 or OpenGL 4.1"
|
||||
#if defined(GL_VERSION_4_5)
|
||||
#elif defined(GL_ES_VERSION_3_1)
|
||||
#elif defined(GL_ES_VERSION_3_0)
|
||||
# if !defined(IOS) && !defined(__EMSCRIPTEN__)
|
||||
# error "GLES 3.0 headers only supported on iOS and WebGL2"
|
||||
# endif
|
||||
#elif defined(GL_ES_VERSION_2_0)
|
||||
# if !defined(__ANDROID__)
|
||||
# error "GLES 2.0 headers only supported on Android"
|
||||
# endif
|
||||
#else
|
||||
# error "Minimum header version must be OpenGL ES 2.0 or OpenGL 4.5"
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* GLES extensions
|
||||
*/
|
||||
@@ -72,10 +102,6 @@ namespace glext {
|
||||
// it is currently called from PlatformEGL.
|
||||
void importGLESExtensionsEntryPoints();
|
||||
|
||||
#ifdef GL_QCOM_tiled_rendering
|
||||
extern PFNGLSTARTTILINGQCOMPROC glStartTilingQCOM;
|
||||
extern PFNGLENDTILINGQCOMPROC glEndTilingQCOM;
|
||||
#endif
|
||||
#ifdef GL_OES_EGL_image
|
||||
extern PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
|
||||
#endif
|
||||
@@ -93,7 +119,7 @@ extern PFNGLDEBUGMESSAGECALLBACKKHRPROC glDebugMessageCallbackKHR;
|
||||
extern PFNGLGETDEBUGMESSAGELOGKHRPROC glGetDebugMessageLogKHR;
|
||||
#endif
|
||||
#ifdef GL_EXT_clip_control
|
||||
extern PFNGLCLIPCONTROLEXTPROC glClipControl;
|
||||
extern PFNGLCLIPCONTROLEXTPROC glClipControlEXT;
|
||||
#endif
|
||||
#ifdef GL_EXT_disjoint_timer_query
|
||||
extern PFNGLGETQUERYOBJECTUI64VEXTPROC glGetQueryObjectui64v;
|
||||
@@ -157,29 +183,25 @@ void glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, void *d
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#define BACKEND_OPENGL_VERSION_GLES 0
|
||||
#define BACKEND_OPENGL_VERSION_GL 1
|
||||
#if defined(GL_ES_VERSION_2_0)
|
||||
# define BACKEND_OPENGL_VERSION BACKEND_OPENGL_VERSION_GLES
|
||||
#elif defined(GL_VERSION_4_1)
|
||||
# define BACKEND_OPENGL_VERSION BACKEND_OPENGL_VERSION_GL
|
||||
# define BACKEND_OPENGL_VERSION_GLES
|
||||
#elif defined(GL_VERSION_4_5)
|
||||
# define BACKEND_OPENGL_VERSION_GL
|
||||
#else
|
||||
# error "Unsupported header version"
|
||||
#endif
|
||||
|
||||
#define BACKEND_OPENGL_LEVEL_GLES20 0
|
||||
#define BACKEND_OPENGL_LEVEL_GLES30 1
|
||||
#define BACKEND_OPENGL_LEVEL_GLES31 2
|
||||
|
||||
#if defined(GL_VERSION_4_1)
|
||||
# define BACKEND_OPENGL_LEVEL BACKEND_OPENGL_LEVEL_GLES30
|
||||
#if defined(GL_VERSION_4_5) || defined(GL_ES_VERSION_3_1)
|
||||
# define BACKEND_OPENGL_LEVEL_GLES31
|
||||
# ifdef __EMSCRIPTEN__
|
||||
# error "__EMSCRIPTEN__ shouldn't be defined with GLES 3.1 headers"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(GL_ES_VERSION_3_1)
|
||||
# define BACKEND_OPENGL_LEVEL BACKEND_OPENGL_LEVEL_GLES31
|
||||
#elif defined(GL_ES_VERSION_3_0)
|
||||
# define BACKEND_OPENGL_LEVEL BACKEND_OPENGL_LEVEL_GLES30
|
||||
#elif defined(GL_ES_VERSION_2_0)
|
||||
# define BACKEND_OPENGL_LEVEL BACKEND_OPENGL_LEVEL_GLES20
|
||||
#if defined(GL_VERSION_4_5) || defined(GL_ES_VERSION_3_0)
|
||||
# define BACKEND_OPENGL_LEVEL_GLES30
|
||||
#endif
|
||||
#if defined(GL_VERSION_4_5) || defined(GL_ES_VERSION_2_0)
|
||||
# define BACKEND_OPENGL_LEVEL_GLES20
|
||||
#endif
|
||||
|
||||
#include "NullGLES.h"
|
||||
|
||||
@@ -75,6 +75,8 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform,
|
||||
mContext.commands->setObserver(&mPipelineCache);
|
||||
mPipelineCache.setDevice(mContext.device, mContext.allocator);
|
||||
mPipelineCache.setDummyTexture(mContext.emptyTexture->getPrimaryImageView());
|
||||
|
||||
mReadPixels.initialize(mContext.device);
|
||||
}
|
||||
|
||||
VulkanDriver::~VulkanDriver() noexcept = default;
|
||||
@@ -134,6 +136,9 @@ void VulkanDriver::terminate() {
|
||||
|
||||
void VulkanDriver::tick(int) {
|
||||
mContext.commands->updateFences();
|
||||
|
||||
// Handle any posted tasks
|
||||
runTaskHandler();
|
||||
}
|
||||
|
||||
// Garbage collection should not occur too frequently, only about once per frame. Internally, the
|
||||
@@ -1011,31 +1016,35 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
|
||||
rt->transformClientRectToPlatform(&renderPassInfo.renderArea);
|
||||
|
||||
VkClearValue clearValues[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT + MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT + 1] = {};
|
||||
VkClearValue clearValues[
|
||||
MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT + MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT +
|
||||
1] = {};
|
||||
if (params.flags.clear != TargetBufferFlags::NONE) {
|
||||
|
||||
// NOTE: clearValues must be populated in the same order as the attachments array in
|
||||
// VulkanFboCache::getFramebuffer. Values must be provided regardless of whether Vulkan is
|
||||
// actually clearing that particular target.
|
||||
for (int i = 0; i < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) {
|
||||
if (fbkey.color[i]) {
|
||||
VkClearValue& clearValue = clearValues[renderPassInfo.clearValueCount++];
|
||||
clearValue.color.float32[0] = params.clearColor.r;
|
||||
clearValue.color.float32[1] = params.clearColor.g;
|
||||
clearValue.color.float32[2] = params.clearColor.b;
|
||||
clearValue.color.float32[3] = params.clearColor.a;
|
||||
// NOTE: clearValues must be populated in the same order as the attachments array in
|
||||
// VulkanFboCache::getFramebuffer. Values must be provided regardless of whether Vulkan is
|
||||
// actually clearing that particular target.
|
||||
for (int i = 0; i < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) {
|
||||
if (fbkey.color[i]) {
|
||||
VkClearValue &clearValue = clearValues[renderPassInfo.clearValueCount++];
|
||||
clearValue.color.float32[0] = params.clearColor.r;
|
||||
clearValue.color.float32[1] = params.clearColor.g;
|
||||
clearValue.color.float32[2] = params.clearColor.b;
|
||||
clearValue.color.float32[3] = params.clearColor.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Resolve attachments are not cleared but still have entries in the list, so skip over them.
|
||||
for (int i = 0; i < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) {
|
||||
if (rpkey.needsResolveMask & (1u << i)) {
|
||||
renderPassInfo.clearValueCount++;
|
||||
// Resolve attachments are not cleared but still have entries in the list, so skip over them.
|
||||
for (int i = 0; i < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) {
|
||||
if (rpkey.needsResolveMask & (1u << i)) {
|
||||
renderPassInfo.clearValueCount++;
|
||||
}
|
||||
}
|
||||
if (fbkey.depth) {
|
||||
VkClearValue &clearValue = clearValues[renderPassInfo.clearValueCount++];
|
||||
clearValue.depthStencil = {(float) params.clearDepth, 0};
|
||||
}
|
||||
renderPassInfo.pClearValues = &clearValues[0];
|
||||
}
|
||||
if (fbkey.depth) {
|
||||
VkClearValue& clearValue = clearValues[renderPassInfo.clearValueCount++];
|
||||
clearValue.depthStencil = {(float) params.clearDepth, 0};
|
||||
}
|
||||
renderPassInfo.pClearValues = &clearValues[0];
|
||||
|
||||
vkCmdBeginRenderPass(cmdbuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
@@ -1321,152 +1330,18 @@ void VulkanDriver::stopCapture(int) {
|
||||
|
||||
}
|
||||
|
||||
void VulkanDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y,
|
||||
uint32_t width, uint32_t height, PixelBufferDescriptor&& pbd) {
|
||||
const VkDevice device = mContext.device;
|
||||
void VulkanDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y, uint32_t width,
|
||||
uint32_t height, PixelBufferDescriptor&& pbd) {
|
||||
VulkanRenderTarget* srcTarget = handle_cast<VulkanRenderTarget*>(src);
|
||||
VulkanTexture* srcTexture = srcTarget->getColor(0).texture;
|
||||
assert_invariant(srcTexture);
|
||||
const VkFormat srcFormat = srcTexture->getVkFormat();
|
||||
const bool swizzle = srcFormat == VK_FORMAT_B8G8R8A8_UNORM;
|
||||
|
||||
// Create a host visible, linearly tiled image as a staging area.
|
||||
|
||||
VkImageCreateInfo imageInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.imageType = VK_IMAGE_TYPE_2D,
|
||||
.format = srcFormat,
|
||||
.extent = { width, height, 1 },
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.tiling = VK_IMAGE_TILING_LINEAR,
|
||||
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
};
|
||||
|
||||
VkImage stagingImage;
|
||||
vkCreateImage(device, &imageInfo, VKALLOC, &stagingImage);
|
||||
|
||||
VkMemoryRequirements memReqs;
|
||||
VkDeviceMemory stagingMemory;
|
||||
vkGetImageMemoryRequirements(device, stagingImage, &memReqs);
|
||||
VkMemoryAllocateInfo allocInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = memReqs.size,
|
||||
.memoryTypeIndex = mContext.selectMemoryType(memReqs.memoryTypeBits,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_CACHED_BIT)
|
||||
};
|
||||
|
||||
vkAllocateMemory(device, &allocInfo, nullptr, &stagingMemory);
|
||||
vkBindImageMemory(device, stagingImage, stagingMemory, 0);
|
||||
|
||||
// TODO: don't flush/wait here, this should be asynchronous
|
||||
|
||||
mContext.commands->flush();
|
||||
mContext.commands->wait();
|
||||
|
||||
// Transition the staging image layout.
|
||||
|
||||
const VkCommandBuffer cmdbuffer = mContext.commands->get().cmdbuffer;
|
||||
|
||||
transitionImageLayout(cmdbuffer, {
|
||||
.image = stagingImage,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.subresources = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.srcStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||
.srcAccessMask = 0,
|
||||
.dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
});
|
||||
|
||||
const VulkanAttachment srcAttachment = srcTarget->getColor(0);
|
||||
|
||||
VkImageCopy imageCopyRegion = {
|
||||
.srcSubresource = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.mipLevel = srcAttachment.level,
|
||||
.baseArrayLayer = srcAttachment.layer,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.srcOffset = {
|
||||
.x = (int32_t) x,
|
||||
.y = (int32_t) (srcTarget->getExtent().height - (height + y)),
|
||||
},
|
||||
.dstSubresource = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.extent = {
|
||||
.width = width,
|
||||
.height = height,
|
||||
.depth = 1,
|
||||
},
|
||||
};
|
||||
|
||||
// Transition the source image layout (which might be the swap chain)
|
||||
|
||||
const VkImageSubresourceRange srcRange = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.baseMipLevel = srcAttachment.level,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = srcAttachment.layer,
|
||||
.layerCount = 1,
|
||||
};
|
||||
|
||||
srcTexture->transitionLayout(cmdbuffer, srcRange, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
|
||||
// Perform the copy into the staging area. At this point we know that the src layout is
|
||||
// TRANSFER_SRC_OPTIMAL and the staging area is GENERAL.
|
||||
|
||||
UTILS_UNUSED_IN_RELEASE VkExtent2D srcExtent = srcAttachment.getExtent2D();
|
||||
assert_invariant(imageCopyRegion.srcOffset.x + imageCopyRegion.extent.width <= srcExtent.width);
|
||||
assert_invariant(imageCopyRegion.srcOffset.y + imageCopyRegion.extent.height <= srcExtent.height);
|
||||
|
||||
vkCmdCopyImage(cmdbuffer, srcAttachment.getImage(),
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, stagingImage, VK_IMAGE_LAYOUT_GENERAL,
|
||||
1, &imageCopyRegion);
|
||||
|
||||
// Restore the source image layout. Between driver API calls, color images are always kept in
|
||||
// UNDEFINED layout or in their "usage default" layout (see comment for getDefaultImageLayout).
|
||||
|
||||
srcTexture->transitionLayout(cmdbuffer, srcRange,
|
||||
getDefaultImageLayout(TextureUsage::COLOR_ATTACHMENT));
|
||||
|
||||
// TODO: don't flush/wait here -- we should do this asynchronously
|
||||
|
||||
// Flush and wait.
|
||||
mContext.commands->flush();
|
||||
mContext.commands->wait();
|
||||
|
||||
VkImageSubresource subResource { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
VkSubresourceLayout subResourceLayout;
|
||||
vkGetImageSubresourceLayout(device, stagingImage, &subResource, &subResourceLayout);
|
||||
|
||||
// Map image memory so we can start copying from it.
|
||||
|
||||
const uint8_t* srcPixels;
|
||||
vkMapMemory(device, stagingMemory, 0, VK_WHOLE_SIZE, 0, (void**) &srcPixels);
|
||||
srcPixels += subResourceLayout.offset;
|
||||
|
||||
if (!DataReshaper::reshapeImage(&pbd, getComponentType(srcFormat), getComponentCount(srcFormat),
|
||||
srcPixels, subResourceLayout.rowPitch, width, height, swizzle)) {
|
||||
utils::slog.e << "Unsupported PixelDataFormat or PixelDataType" << utils::io::endl;
|
||||
}
|
||||
|
||||
vkUnmapMemory(device, stagingMemory);
|
||||
vkDestroyImage(device, stagingImage, nullptr);
|
||||
vkFreeMemory(device, stagingMemory, nullptr);
|
||||
|
||||
scheduleDestroy(std::move(pbd));
|
||||
mReadPixels.run(
|
||||
srcTarget, x, y, width, height, mContext.graphicsQueueFamilyIndex, std::move(pbd),
|
||||
getTaskHandler(),
|
||||
[&context = mContext](uint32_t reqs, VkFlags flags) {
|
||||
return context.selectMemoryType(reqs, flags);
|
||||
},
|
||||
[this](PixelBufferDescriptor&& pbd) {
|
||||
this->scheduleDestroy(std::move(pbd));
|
||||
});
|
||||
}
|
||||
|
||||
void VulkanDriver::readBufferSubData(backend::BufferObjectHandle boh,
|
||||
|
||||
@@ -23,8 +23,10 @@
|
||||
#include "VulkanConstants.h"
|
||||
#include "VulkanContext.h"
|
||||
#include "VulkanFboCache.h"
|
||||
#include "VulkanReadPixels.h"
|
||||
#include "VulkanSamplerCache.h"
|
||||
#include "VulkanStagePool.h"
|
||||
#include "VulkanTaskHandler.h"
|
||||
#include "VulkanUtility.h"
|
||||
|
||||
#include "private/backend/Driver.h"
|
||||
@@ -39,11 +41,14 @@ namespace filament::backend {
|
||||
class VulkanPlatform;
|
||||
struct VulkanSamplerGroup;
|
||||
|
||||
class VulkanDriver final : public DriverBase {
|
||||
class VulkanDriver final : public DriverBase, private VulkanTaskHandler::Host {
|
||||
public:
|
||||
static Driver* create(VulkanPlatform* platform,
|
||||
const char* const* ppEnabledExtensions, uint32_t enabledExtensionCount, const Platform::DriverConfig& driverConfig) noexcept;
|
||||
|
||||
VulkanDriver(VulkanDriver const&) = delete;
|
||||
VulkanDriver& operator = (VulkanDriver const&) = delete;
|
||||
|
||||
private:
|
||||
|
||||
void debugCommandBegin(CommandStream* cmds, bool synchronous, const char* methodName) noexcept override;
|
||||
@@ -73,9 +78,6 @@ private:
|
||||
|
||||
#include "private/backend/DriverAPI.inc"
|
||||
|
||||
VulkanDriver(VulkanDriver const&) = delete;
|
||||
VulkanDriver& operator = (VulkanDriver const&) = delete;
|
||||
|
||||
private:
|
||||
|
||||
HandleAllocatorVK mHandleAllocator;
|
||||
@@ -151,6 +153,7 @@ private:
|
||||
VulkanSamplerCache mSamplerCache;
|
||||
VulkanBlitter mBlitter;
|
||||
VulkanSamplerGroup* mSamplerBindings[VulkanPipelineCache::SAMPLER_BINDING_COUNT] = {};
|
||||
VulkanReadPixels mReadPixels;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "VulkanReadPixels.h"
|
||||
|
||||
#include "DataReshaper.h"
|
||||
#include "VulkanHandles.h"
|
||||
#include "VulkanTaskHandler.h"
|
||||
#include "VulkanTexture.h"
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
using namespace bluevk;
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
VulkanReadPixels::~VulkanReadPixels() noexcept {
|
||||
assert_invariant(mDevice != VK_NULL_HANDLE);
|
||||
if (mCommandPool == VK_NULL_HANDLE) {
|
||||
return;
|
||||
}
|
||||
vkDestroyCommandPool(mDevice, mCommandPool, VKALLOC);
|
||||
}
|
||||
|
||||
void VulkanReadPixels::initialize(VkDevice device) {
|
||||
mDevice = device;
|
||||
}
|
||||
|
||||
void VulkanReadPixels::run(VulkanRenderTarget const* srcTarget, uint32_t const x, uint32_t const y,
|
||||
uint32_t const width, uint32_t const height, uint32_t const graphicsQueueFamilyIndex,
|
||||
PixelBufferDescriptor&& pbd, VulkanTaskHandler& taskHandler,
|
||||
SelecteMemoryFunction const& selectMemoryFunc,
|
||||
OnReadCompleteFunction const& readCompleteFunc) {
|
||||
assert_invariant(mDevice != VK_NULL_HANDLE);
|
||||
|
||||
VkDevice device = mDevice;
|
||||
|
||||
if (mCommandPool == VK_NULL_HANDLE) {
|
||||
// Create a command pool if one has not been created.
|
||||
VkCommandPoolCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
|
||||
| VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
|
||||
.queueFamilyIndex = graphicsQueueFamilyIndex,
|
||||
};
|
||||
vkCreateCommandPool(device, &createInfo, VKALLOC, &mCommandPool);
|
||||
}
|
||||
VkCommandPool cmdpool = mCommandPool;
|
||||
|
||||
VulkanTexture* srcTexture = srcTarget->getColor(0).texture;
|
||||
assert_invariant(srcTexture);
|
||||
VkFormat const srcFormat = srcTexture->getVkFormat();
|
||||
bool const swizzle
|
||||
= srcFormat == VK_FORMAT_B8G8R8A8_UNORM || srcFormat == VK_FORMAT_B8G8R8A8_SRGB;
|
||||
|
||||
// Create a host visible, linearly tiled image as a staging area.
|
||||
VkImageCreateInfo const imageInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.imageType = VK_IMAGE_TYPE_2D,
|
||||
.format = srcFormat,
|
||||
.extent = {width, height, 1},
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.tiling = VK_IMAGE_TILING_LINEAR,
|
||||
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
};
|
||||
|
||||
VkImage stagingImage;
|
||||
vkCreateImage(device, &imageInfo, VKALLOC, &stagingImage);
|
||||
|
||||
VkMemoryRequirements memReqs;
|
||||
VkDeviceMemory stagingMemory;
|
||||
vkGetImageMemoryRequirements(device, stagingImage, &memReqs);
|
||||
VkMemoryAllocateInfo const allocInfo = {.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = memReqs.size,
|
||||
.memoryTypeIndex = selectMemoryFunc(memReqs.memoryTypeBits,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
| VK_MEMORY_PROPERTY_HOST_CACHED_BIT)};
|
||||
|
||||
vkAllocateMemory(device, &allocInfo, VKALLOC, &stagingMemory);
|
||||
vkBindImageMemory(device, stagingImage, stagingMemory, 0);
|
||||
|
||||
VkCommandBuffer cmdbuffer;
|
||||
VkCommandBufferAllocateInfo const allocateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.commandPool = cmdpool,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = 1,
|
||||
};
|
||||
vkAllocateCommandBuffers(device, &allocateInfo, &cmdbuffer);
|
||||
|
||||
VkCommandBufferBeginInfo const binfo{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
||||
};
|
||||
vkBeginCommandBuffer(cmdbuffer, &binfo);
|
||||
|
||||
transitionImageLayout(cmdbuffer, {
|
||||
.image = stagingImage,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.subresources = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.srcStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||
.srcAccessMask = 0,
|
||||
.dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
});
|
||||
|
||||
VulkanAttachment const srcAttachment = srcTarget->getColor(0);
|
||||
|
||||
VkImageCopy const imageCopyRegion = {
|
||||
.srcSubresource = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.mipLevel = srcAttachment.level,
|
||||
.baseArrayLayer = srcAttachment.layer,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.srcOffset = {
|
||||
.x = (int32_t) x,
|
||||
.y = (int32_t) (srcTarget->getExtent().height - (height + y)),
|
||||
},
|
||||
.dstSubresource = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.extent = {
|
||||
.width = width,
|
||||
.height = height,
|
||||
.depth = 1,
|
||||
},
|
||||
};
|
||||
|
||||
// Transition the source image layout (which might be the swap chain)
|
||||
VkImageSubresourceRange const srcRange = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.baseMipLevel = srcAttachment.level,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = srcAttachment.layer,
|
||||
.layerCount = 1,
|
||||
};
|
||||
|
||||
srcTexture->transitionLayout(cmdbuffer, srcRange, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
|
||||
// Perform the copy into the staging area. At this point we know that the src layout is
|
||||
// TRANSFER_SRC_OPTIMAL and the staging area is GENERAL.
|
||||
UTILS_UNUSED_IN_RELEASE VkExtent2D srcExtent = srcAttachment.getExtent2D();
|
||||
assert_invariant(imageCopyRegion.srcOffset.x + imageCopyRegion.extent.width <= srcExtent.width);
|
||||
assert_invariant(
|
||||
imageCopyRegion.srcOffset.y + imageCopyRegion.extent.height <= srcExtent.height);
|
||||
|
||||
vkCmdCopyImage(cmdbuffer, srcAttachment.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
stagingImage, VK_IMAGE_LAYOUT_GENERAL, 1, &imageCopyRegion);
|
||||
|
||||
// Restore the source image layout. Between driver API calls, color images are always kept in
|
||||
// UNDEFINED layout or in their "usage default" layout (see comment for getDefaultImageLayout).
|
||||
srcTexture->transitionLayout(cmdbuffer, srcRange,
|
||||
getDefaultImageLayout(TextureUsage::COLOR_ATTACHMENT));
|
||||
|
||||
vkEndCommandBuffer(cmdbuffer);
|
||||
|
||||
VkQueue queue;
|
||||
vkGetDeviceQueue(device, graphicsQueueFamilyIndex, 0, &queue);
|
||||
|
||||
VkSubmitInfo const submitInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.waitSemaphoreCount = 0,
|
||||
.pWaitSemaphores = VK_NULL_HANDLE,
|
||||
.pWaitDstStageMask = VK_NULL_HANDLE,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &cmdbuffer,
|
||||
.signalSemaphoreCount = 0,
|
||||
.pSignalSemaphores = VK_NULL_HANDLE,
|
||||
};
|
||||
VkFence fence;
|
||||
VkFenceCreateInfo const fenceCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||
};
|
||||
vkCreateFence(device, &fenceCreateInfo, VKALLOC, &fence);
|
||||
vkQueueSubmit(queue, 1, &submitInfo, fence);
|
||||
|
||||
auto* const pUserBuffer = new PixelBufferDescriptor(std::move(pbd));
|
||||
auto const waitTaskId = taskHandler.createTask(
|
||||
[device, width, height, swizzle, srcFormat, fence, stagingImage, stagingMemory, cmdpool,
|
||||
cmdbuffer, pUserBuffer, readCompleteFunc,
|
||||
&taskHandler](VulkanTaskHandler::TaskId taskId, void* data) mutable {
|
||||
PixelBufferDescriptor& p = *pUserBuffer;
|
||||
vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
|
||||
VkResult status = vkGetFenceStatus(device, fence);
|
||||
|
||||
// Fence hasn't been reached. Try waiting again.
|
||||
if (status == VK_NOT_READY) {
|
||||
taskHandler.post(taskId);
|
||||
return;
|
||||
}
|
||||
|
||||
// Need to abort the readPixels if the device is lost.
|
||||
if (status == VK_ERROR_DEVICE_LOST) {
|
||||
utils::slog.e << "Device lost while in VulkanReadPixels::run"
|
||||
<< utils::io::endl;
|
||||
taskHandler.completed(taskId);
|
||||
|
||||
// Try to free the pbd anyway
|
||||
readCompleteFunc(std::move(p));
|
||||
delete pUserBuffer;
|
||||
return;
|
||||
}
|
||||
|
||||
VkImageSubresource subResource{.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT};
|
||||
VkSubresourceLayout subResourceLayout;
|
||||
vkGetImageSubresourceLayout(device, stagingImage, &subResource, &subResourceLayout);
|
||||
|
||||
// Map image memory so that we can start copying from it.
|
||||
uint8_t const* srcPixels;
|
||||
vkMapMemory(device, stagingMemory, 0, VK_WHOLE_SIZE, 0, (void**) &srcPixels);
|
||||
srcPixels += subResourceLayout.offset;
|
||||
|
||||
if (!DataReshaper::reshapeImage(&p, getComponentType(srcFormat),
|
||||
getComponentCount(srcFormat), srcPixels,
|
||||
static_cast<int>(subResourceLayout.rowPitch), static_cast<int>(width),
|
||||
static_cast<int>(height), swizzle)) {
|
||||
utils::slog.e << "Unsupported PixelDataFormat or PixelDataType"
|
||||
<< utils::io::endl;
|
||||
}
|
||||
|
||||
vkUnmapMemory(device, stagingMemory);
|
||||
vkDestroyImage(device, stagingImage, VKALLOC);
|
||||
vkFreeMemory(device, stagingMemory, VKALLOC);
|
||||
vkDestroyFence(device, fence, VKALLOC);
|
||||
vkFreeCommandBuffers(device, cmdpool, 1, &cmdbuffer);
|
||||
readCompleteFunc(std::move(p));
|
||||
delete pUserBuffer;
|
||||
|
||||
taskHandler.completed(taskId);
|
||||
},
|
||||
nullptr);
|
||||
|
||||
taskHandler.post(waitTaskId);
|
||||
}
|
||||
|
||||
}// namespace filament::backend
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_FILAMENT_BACKEND_VULKANREADPIXELS_H
|
||||
#define TNT_FILAMENT_BACKEND_VULKANREADPIXELS_H
|
||||
|
||||
#include "VulkanTaskHandler.h"
|
||||
#include "private/backend/Driver.h"
|
||||
|
||||
#include <bluevk/BlueVK.h>
|
||||
#include <math/vec4.h>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
struct VulkanContext;
|
||||
struct VulkanRenderTarget;
|
||||
|
||||
class VulkanReadPixels {
|
||||
public:
|
||||
using OnReadCompleteFunction = std::function<void(PixelBufferDescriptor&&)>;
|
||||
using SelecteMemoryFunction = std::function<uint32_t(uint32_t, VkFlags)>;
|
||||
|
||||
~VulkanReadPixels() noexcept;
|
||||
|
||||
void initialize(VkDevice device);
|
||||
|
||||
void run(VulkanRenderTarget const* srcTarget, uint32_t x, uint32_t y, uint32_t width,
|
||||
uint32_t height, uint32_t graphicsQueueFamilyIndex, PixelBufferDescriptor&& pbd,
|
||||
VulkanTaskHandler& taskHandler, SelecteMemoryFunction const& selectMemoryFunc,
|
||||
OnReadCompleteFunction const& readCompleteFunc);
|
||||
|
||||
private:
|
||||
VkDevice mDevice = VK_NULL_HANDLE;
|
||||
VkCommandPool mCommandPool = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
}// namespace filament::backend
|
||||
|
||||
#endif//TNT_FILAMENT_BACKEND_VULKANREADPIXELS_H
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_FILAMENT_BACKEND_VULKANTASKHANDLER_H
|
||||
#define TNT_FILAMENT_BACKEND_VULKANTASKHANDLER_H
|
||||
|
||||
#include "utils/Panic.h"
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
class VulkanTaskHandler {
|
||||
public:
|
||||
// The Host class is meant to be called on the thread that processes the tasks. It has access to
|
||||
// the handle function.
|
||||
class Host {
|
||||
public:
|
||||
Host(Host const&) = delete;
|
||||
Host& operator=(Host const&) = delete;
|
||||
protected:
|
||||
Host()
|
||||
: mHandler(std::make_unique<VulkanTaskHandler>()) {}
|
||||
|
||||
void runTaskHandler() noexcept {
|
||||
mHandler->handle();
|
||||
}
|
||||
|
||||
VulkanTaskHandler& getTaskHandler() noexcept {
|
||||
return *mHandler;
|
||||
}
|
||||
private:
|
||||
std::unique_ptr<VulkanTaskHandler> mHandler;
|
||||
};
|
||||
|
||||
using TaskId = uint32_t;
|
||||
using TaskFunc = std::function<void(TaskId, void*)>;
|
||||
using Task = std::pair<TaskFunc, void*>;
|
||||
|
||||
TaskId createTask(TaskFunc const& func, void* data) noexcept {
|
||||
TaskId const id = mNextTaskId++;
|
||||
mTasks[id] = std::pair(func, data);
|
||||
return id;
|
||||
}
|
||||
|
||||
// Task that will never be put on the queue again should be marked as completed by calling this
|
||||
// function.
|
||||
void completed(TaskId taskId) noexcept {
|
||||
assert_invariant(mTasks.find(taskId) != mTasks.end());
|
||||
mTasks.erase(taskId);
|
||||
}
|
||||
|
||||
void post(TaskId taskId) noexcept {
|
||||
assert_invariant(mTasks.find(taskId) != mTasks.end());
|
||||
mTaskQueue.push(taskId);
|
||||
}
|
||||
|
||||
VulkanTaskHandler() = default;
|
||||
|
||||
VulkanTaskHandler(VulkanTaskHandler const&) = delete;
|
||||
VulkanTaskHandler& operator=(VulkanTaskHandler const&) = delete;
|
||||
|
||||
private:
|
||||
inline void handle() {
|
||||
while (!mTaskQueue.empty()) {
|
||||
auto taskId = mTaskQueue.front();
|
||||
mTaskQueue.pop();
|
||||
// It is possible for taskIds in the queue to refer to a task that has already been
|
||||
// completed. Just ignore.
|
||||
if (mTasks.find(taskId) == mTasks.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& [func, data] = mTasks[taskId];
|
||||
func(taskId, data);
|
||||
}
|
||||
}
|
||||
|
||||
std::queue<TaskId> mTaskQueue;
|
||||
std::map<TaskId, Task> mTasks;
|
||||
uint32_t mNextTaskId = 0;
|
||||
|
||||
friend class Host;
|
||||
};
|
||||
|
||||
}// namespace filament::backend
|
||||
|
||||
#endif// TNT_FILAMENT_BACKEND_VULKANTASKHANDLER_H
|
||||
@@ -171,6 +171,9 @@ public:
|
||||
//! Indicates whether this material is double-sided.
|
||||
bool isDoubleSided() const noexcept;
|
||||
|
||||
//! Indicates whether this material uses alpha to coverage.
|
||||
bool isAlphaToCoverageEnabled() const noexcept;
|
||||
|
||||
//! Returns the alpha mask threshold used when the blending mode is set to masked.
|
||||
float getMaskThreshold() const noexcept;
|
||||
|
||||
|
||||
@@ -72,6 +72,10 @@ bool Material::isDoubleSided() const noexcept {
|
||||
return downcast(this)->isDoubleSided();
|
||||
}
|
||||
|
||||
bool Material::isAlphaToCoverageEnabled() const noexcept {
|
||||
return downcast(this)->isAlphaToCoverageEnabled();
|
||||
}
|
||||
|
||||
float Material::getMaskThreshold() const noexcept {
|
||||
return downcast(this)->getMaskThreshold();
|
||||
}
|
||||
|
||||
@@ -246,6 +246,14 @@ bool MaterialParser::getMaskThreshold(float* value) const noexcept {
|
||||
return mImpl.getFromSimpleChunk(ChunkType::MaterialMaskThreshold, value);
|
||||
}
|
||||
|
||||
bool MaterialParser::getAlphaToCoverageSet(bool* value) const noexcept {
|
||||
return mImpl.getFromSimpleChunk(ChunkType::MaterialAlphaToCoverageSet, value);
|
||||
}
|
||||
|
||||
bool MaterialParser::getAlphaToCoverage(bool* value) const noexcept {
|
||||
return mImpl.getFromSimpleChunk(ChunkType::MaterialAlphaToCoverage, value);
|
||||
}
|
||||
|
||||
bool MaterialParser::hasShadowMultiplier(bool* value) const noexcept {
|
||||
return mImpl.getFromSimpleChunk(ChunkType::MaterialShadowMultiplier, value);
|
||||
}
|
||||
|
||||
@@ -88,6 +88,8 @@ public:
|
||||
bool getShading(Shading*) const noexcept;
|
||||
bool getBlendingMode(BlendingMode*) const noexcept;
|
||||
bool getMaskThreshold(float*) const noexcept;
|
||||
bool getAlphaToCoverageSet(bool*) const noexcept;
|
||||
bool getAlphaToCoverage(bool*) const noexcept;
|
||||
bool hasShadowMultiplier(bool*) const noexcept;
|
||||
bool getRequiredAttributes(AttributeBitset*) const noexcept;
|
||||
bool getRefractionMode(RefractionMode* value) const noexcept;
|
||||
|
||||
@@ -60,9 +60,8 @@ void PerShadowMapUniforms::prepareCamera(Transaction const& transaction,
|
||||
s.viewFromClipMatrix = viewFromClip; // 1/projection
|
||||
s.clipFromWorldMatrix = clipFromWorld; // projection * view
|
||||
s.worldFromClipMatrix = worldFromClip; // 1/(projection * view)
|
||||
s.userWorldFromWorldMatrix = mat4f(inverse(camera.worldOrigin));
|
||||
s.clipTransform = camera.clipTransfrom;
|
||||
s.cameraPosition = float3{ camera.getPosition() };
|
||||
s.worldOffset = camera.getWorldOffset();
|
||||
s.cameraFar = camera.zf;
|
||||
s.oneOverFarMinusNear = 1.0f / (camera.zf - camera.zn);
|
||||
s.nearOverFarMinusNear = camera.zn / (camera.zf - camera.zn);
|
||||
|
||||
@@ -76,9 +76,8 @@ void PerViewUniforms::prepareCamera(FEngine& engine, const CameraInfo& camera) n
|
||||
s.viewFromClipMatrix = viewFromClip; // 1/projection
|
||||
s.clipFromWorldMatrix = clipFromWorld; // projection * view
|
||||
s.worldFromClipMatrix = worldFromClip; // 1/(projection * view)
|
||||
s.userWorldFromWorldMatrix = mat4f(inverse(camera.worldOrigin));
|
||||
s.clipTransform = camera.clipTransfrom;
|
||||
s.cameraPosition = float3{ camera.getPosition() };
|
||||
s.worldOffset = camera.getWorldOffset();
|
||||
s.cameraFar = camera.zf;
|
||||
s.oneOverFarMinusNear = 1.0f / (camera.zf - camera.zn);
|
||||
s.nearOverFarMinusNear = camera.zn / (camera.zf - camera.zn);
|
||||
@@ -130,15 +129,10 @@ void PerViewUniforms::prepareTemporalNoise(FEngine& engine,
|
||||
}
|
||||
|
||||
void PerViewUniforms::prepareFog(float3 const& cameraPosition, FogOptions const& options) noexcept {
|
||||
// this can't be too high because we need density / heightFalloff to produce something
|
||||
// close to fogOptions.density in the fragment shader which use 16-bits floats.
|
||||
constexpr float epsilon = 0.001f;
|
||||
const float heightFalloff = std::max(epsilon, options.heightFalloff);
|
||||
const float heightFalloff = std::max(0.0f, options.heightFalloff);
|
||||
|
||||
// precalculate the constant part of density integral and correct for exp2() in the shader
|
||||
const float density = ((options.density / heightFalloff) *
|
||||
std::exp(-heightFalloff * (cameraPosition.y - options.height)))
|
||||
* float(1.0f / F_LN2);
|
||||
// precalculate the constant part of density integral
|
||||
const float density = -heightFalloff * (cameraPosition.y - options.height);
|
||||
|
||||
auto& s = mUniforms.edit();
|
||||
s.fogStart = options.distance;
|
||||
@@ -146,7 +140,7 @@ void PerViewUniforms::prepareFog(float3 const& cameraPosition, FogOptions const&
|
||||
s.fogHeight = options.height;
|
||||
s.fogHeightFalloff = heightFalloff;
|
||||
s.fogColor = options.color;
|
||||
s.fogDensity = density;
|
||||
s.fogDensity = { options.density, density, options.density * std::exp(density) };
|
||||
s.fogInscatteringStart = options.inScatteringStart;
|
||||
s.fogInscatteringSize = options.inScatteringSize;
|
||||
s.fogColorFromIbl = options.fogColorFromIbl ? 1.0f : 0.0f;
|
||||
|
||||
@@ -357,7 +357,7 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
||||
|
||||
if (params.options.stable) {
|
||||
// Use the world origin as reference point, fixed w.r.t. the camera
|
||||
snapLightFrustum(s, o, Mv, -camera.getWorldOffset(),
|
||||
snapLightFrustum(s, o, Mv, camera.worldOrigin[3].xyz,
|
||||
1.0f / float(shadowMapInfo.shadowDimension));
|
||||
}
|
||||
|
||||
|
||||
@@ -219,7 +219,6 @@ struct CameraInfo {
|
||||
float d{}; // focus distance [m]
|
||||
math::float3 const& getPosition() const noexcept { return model[3].xyz; }
|
||||
math::float3 getForwardVector() const noexcept { return normalize(-model[2].xyz); }
|
||||
math::float3 getWorldOffset() const noexcept { return -worldOrigin[3].xyz; }
|
||||
math::mat4 getUserViewMatrix() const noexcept { return view * worldOrigin; }
|
||||
};
|
||||
|
||||
|
||||
@@ -298,7 +298,16 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder)
|
||||
parser->getColorWrite(&colorWrite);
|
||||
mRasterState.colorWrite = colorWrite;
|
||||
mRasterState.depthFunc = depthTest ? DepthFunc::GE : DepthFunc::A;
|
||||
mRasterState.alphaToCoverage = mBlendingMode == BlendingMode::MASKED;
|
||||
|
||||
bool alphaToCoverageSet = false;
|
||||
parser->getAlphaToCoverageSet(&alphaToCoverageSet);
|
||||
if (alphaToCoverageSet) {
|
||||
bool alphaToCoverage = false;
|
||||
parser->getAlphaToCoverage(&alphaToCoverage);
|
||||
mRasterState.alphaToCoverage = alphaToCoverage;
|
||||
} else {
|
||||
mRasterState.alphaToCoverage = mBlendingMode == BlendingMode::MASKED;
|
||||
}
|
||||
|
||||
parser->hasSpecularAntiAliasing(&mSpecularAntiAliasing);
|
||||
if (mSpecularAntiAliasing) {
|
||||
|
||||
@@ -124,6 +124,7 @@ public:
|
||||
}
|
||||
bool isDoubleSided() const noexcept { return mDoubleSided; }
|
||||
bool hasDoubleSidedCapability() const noexcept { return mDoubleSidedCapability; }
|
||||
bool isAlphaToCoverageEnabled() const noexcept { return mRasterState.alphaToCoverage; }
|
||||
float getMaskThreshold() const noexcept { return mMaskThreshold; }
|
||||
bool hasShadowMultiplier() const noexcept { return mHasShadowMultiplier; }
|
||||
AttributeBitset getRequiredAttributes() const noexcept { return mRequiredAttributes; }
|
||||
|
||||
@@ -390,7 +390,7 @@ void FView::prepareLighting(FEngine& engine, FEngine::DriverApi& driver, ArenaSc
|
||||
* Directional light (always at index 0)
|
||||
*/
|
||||
|
||||
FLightManager::Instance directionalLight = lightData.elementAt<FScene::LIGHT_INSTANCE>(0);
|
||||
FLightManager::Instance const directionalLight = lightData.elementAt<FScene::LIGHT_INSTANCE>(0);
|
||||
const float3 sceneSpaceDirection = lightData.elementAt<FScene::DIRECTION>(0); // guaranteed normalized
|
||||
mPerViewUniforms.prepareDirectionalLight(engine, exposure, sceneSpaceDirection, directionalLight);
|
||||
mHasDirectionalLight = directionalLight.isValid();
|
||||
@@ -401,32 +401,31 @@ CameraInfo FView::computeCameraInfo(FEngine& engine) const noexcept {
|
||||
|
||||
/*
|
||||
* We apply a "world origin" to "everything" in order to implement the IBL rotation.
|
||||
* The "world origin" could also be useful for other things, like keeping the origin
|
||||
* close to the camera position to improve fp precision in the shader for large scenes.
|
||||
* The "world origin" is also be used to kee the origin close to the camera position to
|
||||
* improve fp precision in the shader for large scenes.
|
||||
*/
|
||||
mat4 worldOriginScene;
|
||||
FIndirectLight const* const ibl = scene->getIndirectLight();
|
||||
if (ibl) {
|
||||
// the IBL transformation must be a rigid transform
|
||||
mat3f rotation{ scene->getIndirectLight()->getRotation() };
|
||||
// for a rigid-body transform, the inverse is the transpose
|
||||
worldOriginScene = mat4{ transpose(rotation) };
|
||||
}
|
||||
mat4 translation;
|
||||
mat4 rotation;
|
||||
|
||||
/*
|
||||
* Calculate all camera parameters needed to render this View for this frame.
|
||||
*/
|
||||
FCamera const* const camera = mViewingCamera ? mViewingCamera : mCullingCamera;
|
||||
|
||||
if (engine.debug.view.camera_at_origin) {
|
||||
// this moves the camera to the origin, effectively doing all shader computations in
|
||||
// view-space, which improves floating point precision in the shader by staying around
|
||||
// zero, where fp precision is highest. This also ensures that when the camera is placed
|
||||
// very far from the origin, objects are still rendered and lit properly.
|
||||
worldOriginScene[3].xyz -= camera->getPosition();
|
||||
translation = mat4::translation( -camera->getPosition() );
|
||||
}
|
||||
|
||||
return { *camera, worldOriginScene };
|
||||
FIndirectLight const* const ibl = scene->getIndirectLight();
|
||||
if (ibl) {
|
||||
// the IBL transformation must be a rigid transform
|
||||
rotation = mat4{ transpose(scene->getIndirectLight()->getRotation()) };
|
||||
}
|
||||
|
||||
return { *camera, rotation * translation };
|
||||
}
|
||||
|
||||
void FView::prepare(FEngine& engine, DriverApi& driver, ArenaScope& arena,
|
||||
@@ -610,8 +609,10 @@ void FView::prepare(FEngine& engine, DriverApi& driver, ArenaScope& arena,
|
||||
* Update driver state
|
||||
*/
|
||||
|
||||
auto const userModelMatrix = inverse(cameraInfo.getUserViewMatrix());
|
||||
auto const userCameraPosition = userModelMatrix[3].xyz;
|
||||
mPerViewUniforms.prepareTime(engine, userTime);
|
||||
mPerViewUniforms.prepareFog(cameraInfo.getPosition(), mFogOptions);
|
||||
mPerViewUniforms.prepareFog(userCameraPosition, mFogOptions);
|
||||
mPerViewUniforms.prepareTemporalNoise(engine, mTemporalAntiAliasingOptions);
|
||||
mPerViewUniforms.prepareBlending(needsAlphaChannel);
|
||||
}
|
||||
|
||||
@@ -151,7 +151,12 @@ void RenderPassNode::resolve() noexcept {
|
||||
|
||||
rt.targetBufferFlags |= target;
|
||||
|
||||
if (!rt.outgoing[i] || !rt.outgoing[i]->hasActiveReaders()) {
|
||||
// Discard at the end only if we are writing to this attachment AND later reading
|
||||
// from it. (in particular, don't discard if we're not writing at all, because this
|
||||
// attachment might have other readers after us).
|
||||
// TODO: we could set the discard flag if we are the last reader, i.e.
|
||||
// if rt->incoming[i] last reader is us.
|
||||
if (rt.outgoing[i] && !rt.outgoing[i]->hasActiveReaders()) {
|
||||
rt.backend.params.flags.discardEnd |= target;
|
||||
}
|
||||
if (!rt.outgoing[i] || !rt.outgoing[i]->hasWriterPass()) {
|
||||
@@ -161,10 +166,10 @@ void RenderPassNode::resolve() noexcept {
|
||||
rt.backend.params.readOnlyDepthStencil |= RenderPassParams::READONLY_STENCIL;
|
||||
}
|
||||
}
|
||||
// Discard at the start if this attachment has no prior writer
|
||||
if (!rt.incoming[i] || !rt.incoming[i]->hasActiveWriters()) {
|
||||
rt.backend.params.flags.discardStart |= target;
|
||||
}
|
||||
|
||||
VirtualResource* pResource = mFrameGraph.getResource(rt.descriptor.attachments.array[i]);
|
||||
Resource<FrameGraphTexture>* pTextureResource = static_cast<Resource<FrameGraphTexture>*>(pResource);
|
||||
|
||||
|
||||
@@ -890,3 +890,55 @@ TEST_F(FrameGraphTest, SubResourcesWriteRead) {
|
||||
|
||||
fg.execute(driverApi);
|
||||
}
|
||||
|
||||
TEST_F(FrameGraphTest, WriteResourceReadAsAttachment) {
|
||||
|
||||
// this check s that using a resources as a read-only attachment doesn't set the
|
||||
// discard flag on that resource. i.e. that the mere fact of reading a resource as an
|
||||
// attachment doesn't make it invalid.
|
||||
// see: https://github.com/google/filament/issues/5005
|
||||
|
||||
struct PassData {
|
||||
FrameGraphId<FrameGraphTexture> input;
|
||||
};
|
||||
auto& writePass = fg.addPass<PassData>("Write Pass", [&](FrameGraph::Builder& builder, auto& data) {
|
||||
data.input = builder.create<FrameGraphTexture>("Output buffer", {.width=16, .height=32});
|
||||
data.input = builder.write(data.input, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
|
||||
builder.declareRenderPass("Output target", { .attachments = {
|
||||
.color = { data.input }
|
||||
}});
|
||||
builder.sideEffect();
|
||||
},
|
||||
[=](FrameGraphResources const& resources, auto const&, backend::DriverApi&) {
|
||||
auto rt = resources.getRenderPassInfo();
|
||||
EXPECT_EQ(rt.params.flags.discardStart, TargetBufferFlags::COLOR0);
|
||||
EXPECT_EQ(rt.params.flags.discardEnd, TargetBufferFlags::NONE);
|
||||
});
|
||||
|
||||
fg.addPass<PassData>("Read Pass", [&](FrameGraph::Builder& builder, auto& data) {
|
||||
data.input = builder.read(writePass->input, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
|
||||
builder.declareRenderPass("Input target", { .attachments = {
|
||||
.color = { data.input }
|
||||
}});
|
||||
builder.sideEffect();
|
||||
},
|
||||
[=](FrameGraphResources const& resources, auto const&, backend::DriverApi&) {
|
||||
auto rt = resources.getRenderPassInfo();
|
||||
EXPECT_EQ(rt.params.flags.discardStart, TargetBufferFlags::NONE);
|
||||
EXPECT_EQ(rt.params.flags.discardEnd, TargetBufferFlags::NONE);
|
||||
});
|
||||
|
||||
fg.addPass<PassData>("Sample Pass", [&](FrameGraph::Builder& builder, auto& data) {
|
||||
data.input = builder.sample(writePass->input);
|
||||
builder.sideEffect();
|
||||
},
|
||||
[=](FrameGraphResources const& resources, auto const&, backend::DriverApi&) {
|
||||
});
|
||||
|
||||
|
||||
EXPECT_TRUE(fg.isAcyclic());
|
||||
|
||||
fg.compile();
|
||||
|
||||
fg.execute(driverApi);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.31.7"
|
||||
spec.version = "1.32.0"
|
||||
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
||||
spec.homepage = "https://google.github.io/filament"
|
||||
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.platform = :ios, "11.0"
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.31.7/filament-v1.31.7-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.32.0/filament-v1.32.0-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -67,15 +67,17 @@ enum UTILS_PUBLIC ChunkType : uint64_t {
|
||||
MaterialReflectionMode = charTo64bitNum("MAT_REFL"),
|
||||
|
||||
MaterialRequiredAttributes = charTo64bitNum("MAT_REQA"),
|
||||
MaterialDepthWriteSet = charTo64bitNum("MAT_DEWS"),
|
||||
MaterialDoubleSidedSet = charTo64bitNum("MAT_DOSS"),
|
||||
MaterialDoubleSided = charTo64bitNum("MAT_DOSI"),
|
||||
|
||||
MaterialColorWrite = charTo64bitNum("MAT_CWRIT"),
|
||||
MaterialDepthWriteSet = charTo64bitNum("MAT_DEWS"),
|
||||
MaterialDepthWrite = charTo64bitNum("MAT_DWRIT"),
|
||||
MaterialDepthTest = charTo64bitNum("MAT_DTEST"),
|
||||
MaterialInstanced = charTo64bitNum("MAT_INSTA"),
|
||||
MaterialCullingMode = charTo64bitNum("MAT_CUMO"),
|
||||
MaterialAlphaToCoverageSet = charTo64bitNum("MAT_A2CS"),
|
||||
MaterialAlphaToCoverage = charTo64bitNum("MAT_A2CO"),
|
||||
|
||||
MaterialHasCustomDepthShader =charTo64bitNum("MAT_CSDP"),
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
namespace filament {
|
||||
|
||||
// update this when a new version of filament wouldn't work with older materials
|
||||
static constexpr size_t MATERIAL_VERSION = 31;
|
||||
static constexpr size_t MATERIAL_VERSION = 32;
|
||||
|
||||
/**
|
||||
* Supported shading models
|
||||
|
||||
@@ -43,16 +43,17 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
// Values that can be accessed in both surface and post-process materials
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
math::mat4f viewFromWorldMatrix;
|
||||
math::mat4f worldFromViewMatrix;
|
||||
math::mat4f clipFromViewMatrix;
|
||||
math::mat4f viewFromClipMatrix;
|
||||
math::mat4f clipFromWorldMatrix;
|
||||
math::mat4f worldFromClipMatrix;
|
||||
math::float4 clipTransform; // [sx, sy, tx, ty] only used by VERTEX_DOMAIN_DEVICE
|
||||
math::mat4f viewFromWorldMatrix; // clip view <- world : view matrix
|
||||
math::mat4f worldFromViewMatrix; // clip view -> world : model matrix
|
||||
math::mat4f clipFromViewMatrix; // clip <- view world : projection matrix
|
||||
math::mat4f viewFromClipMatrix; // clip -> view world : inverse projection matrix
|
||||
math::mat4f clipFromWorldMatrix; // clip <- view <- world
|
||||
math::mat4f worldFromClipMatrix; // clip -> view -> world
|
||||
math::mat4f userWorldFromWorldMatrix; // userWorld <- world
|
||||
math::float4 clipTransform; // [sx, sy, tx, ty] only used by VERTEX_DOMAIN_DEVICE
|
||||
|
||||
math::float2 clipControl; // clip control
|
||||
float time; // time in seconds, with a 1 second period
|
||||
float time; // time in seconds, with a 1-second period
|
||||
float temporalNoise; // noise [0,1] when TAA is used, 0 otherwise
|
||||
math::float4 userTime; // time(s), (double)time - (float)time, 0, 0
|
||||
|
||||
@@ -67,14 +68,9 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
|
||||
float lodBias; // load bias to apply to user materials
|
||||
float refractionLodOffset;
|
||||
float padding1;
|
||||
float padding2;
|
||||
|
||||
// camera position in view space (when camera_at_origin is enabled), i.e. it's (0,0,0).
|
||||
// Always add worldOffset in the shader to get the true world-space position of the camera.
|
||||
math::float3 cameraPosition;
|
||||
float oneOverFarMinusNear; // 1 / (f-n), always positive
|
||||
math::float3 worldOffset; // this is (0,0,0) when camera_at_origin is disabled
|
||||
float nearOverFarMinusNear; // n / (f-n), always positive
|
||||
float cameraFar; // camera *culling* far-plane distance, always positive (projection far is at +inf)
|
||||
float exposure;
|
||||
@@ -140,16 +136,18 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Fog [variant: FOG]
|
||||
// --------------------------------------------------------------------------------------------
|
||||
math::float3 fogDensity; // { density, -falloff * yc, density * exp(-fallof * yc) }
|
||||
float fogStart;
|
||||
float fogMaxOpacity;
|
||||
float fogHeight;
|
||||
float fogHeightFalloff; // falloff * 1.44269
|
||||
float fogHeightFalloff;
|
||||
float fogReserved0;
|
||||
math::float3 fogColor;
|
||||
float fogDensity; // (density/falloff)*exp(-falloff*(camera.y - fogHeight))
|
||||
float fogColorFromIbl;
|
||||
float fogInscatteringStart;
|
||||
float fogInscatteringSize;
|
||||
float fogColorFromIbl;
|
||||
float fogReserved0;
|
||||
float fogReserved1;
|
||||
float fogReserved2;
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Screen-space reflections [variant: SSR (i.e.: VSM | SRE)]
|
||||
@@ -162,7 +160,7 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
float ssrStride; // ssr texel stride, >= 1.0
|
||||
|
||||
// bring PerViewUib to 2 KiB
|
||||
math::float4 reserved[63];
|
||||
math::float4 reserved[60];
|
||||
};
|
||||
|
||||
// 2 KiB == 128 float4s
|
||||
|
||||
@@ -390,7 +390,10 @@ public:
|
||||
|
||||
MaterialBuilder& featureLevel(FeatureLevel featureLevel) noexcept;
|
||||
|
||||
//! Set the blending mode for this material.
|
||||
/**
|
||||
* Set the blending mode for this material. When set to MASKED, alpha to coverage is turned on.
|
||||
* You can override this behavior using alphaToCoverage(false).
|
||||
*/
|
||||
MaterialBuilder& blending(BlendingMode blending) noexcept;
|
||||
|
||||
/**
|
||||
@@ -436,6 +439,14 @@ public:
|
||||
*/
|
||||
MaterialBuilder& maskThreshold(float threshold) noexcept;
|
||||
|
||||
/**
|
||||
* Enables or disables alpha-to-coverage. When enabled, the coverage of a fragment is based
|
||||
* on its alpha value. This parameter is only useful when MSAA is in use. Alpha to coverage
|
||||
* is enabled automatically when the blend mode is set to MASKED; this behavior can be
|
||||
* overridden by calling alphaToCoverage(false).
|
||||
*/
|
||||
MaterialBuilder& alphaToCoverage(bool enable) noexcept;
|
||||
|
||||
//! The material output is multiplied by the shadowing factor (UNLIT model only).
|
||||
MaterialBuilder& shadowMultiplier(bool shadowMultiplier) noexcept;
|
||||
|
||||
@@ -791,6 +802,8 @@ private:
|
||||
bool mInstanced = false;
|
||||
bool mDepthWrite = true;
|
||||
bool mDepthWriteSet = false;
|
||||
bool mAlphaToCoverage = false;
|
||||
bool mAlphaToCoverageSet = false;
|
||||
|
||||
bool mSpecularAntiAliasing = false;
|
||||
bool mClearCoatIorChange = true;
|
||||
|
||||
@@ -336,6 +336,12 @@ MaterialBuilder& MaterialBuilder::maskThreshold(float threshold) noexcept {
|
||||
return *this;
|
||||
}
|
||||
|
||||
MaterialBuilder& MaterialBuilder::alphaToCoverage(bool enable) noexcept {
|
||||
mAlphaToCoverage = enable;
|
||||
mAlphaToCoverageSet = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
MaterialBuilder& MaterialBuilder::shadowMultiplier(bool shadowMultiplier) noexcept {
|
||||
mShadowMultiplier = shadowMultiplier;
|
||||
return *this;
|
||||
@@ -1226,11 +1232,13 @@ void MaterialBuilder::writeCommonChunks(ChunkContainer& container, MaterialInfo&
|
||||
container.addSimpleChild<uint8_t>(ChunkType::MaterialBlendingMode, static_cast<uint8_t>(mBlendingMode));
|
||||
container.addSimpleChild<uint8_t>(ChunkType::MaterialTransparencyMode, static_cast<uint8_t>(mTransparencyMode));
|
||||
container.addSimpleChild<uint8_t>(ChunkType::MaterialReflectionMode, static_cast<uint8_t>(mReflectionMode));
|
||||
container.addSimpleChild<bool>(ChunkType::MaterialDepthWriteSet, mDepthWriteSet);
|
||||
container.addSimpleChild<bool>(ChunkType::MaterialColorWrite, mColorWrite);
|
||||
container.addSimpleChild<bool>(ChunkType::MaterialDepthWriteSet, mDepthWriteSet);
|
||||
container.addSimpleChild<bool>(ChunkType::MaterialDepthWrite, mDepthWrite);
|
||||
container.addSimpleChild<bool>(ChunkType::MaterialDepthTest, mDepthTest);
|
||||
container.addSimpleChild<bool>(ChunkType::MaterialInstanced, mInstanced);
|
||||
container.addSimpleChild<bool>(ChunkType::MaterialAlphaToCoverageSet, mAlphaToCoverageSet);
|
||||
container.addSimpleChild<bool>(ChunkType::MaterialAlphaToCoverage, mAlphaToCoverage);
|
||||
container.addSimpleChild<uint8_t>(ChunkType::MaterialCullingMode, static_cast<uint8_t>(mCullingMode));
|
||||
|
||||
uint64_t properties = 0;
|
||||
|
||||
@@ -41,6 +41,7 @@ BufferInterfaceBlock const& UibGenerator::getPerViewUib() noexcept {
|
||||
{ "viewFromClipMatrix", 0, Type::MAT4, Precision::HIGH },
|
||||
{ "clipFromWorldMatrix", 0, Type::MAT4, Precision::HIGH },
|
||||
{ "worldFromClipMatrix", 0, Type::MAT4, Precision::HIGH },
|
||||
{ "userWorldFromWorldMatrix",0,Type::MAT4, Precision::HIGH },
|
||||
{ "clipTransform", 0, Type::FLOAT4, Precision::HIGH },
|
||||
|
||||
{ "clipControl", 0, Type::FLOAT2 },
|
||||
@@ -58,12 +59,8 @@ BufferInterfaceBlock const& UibGenerator::getPerViewUib() noexcept {
|
||||
|
||||
{ "lodBias", 0, Type::FLOAT },
|
||||
{ "refractionLodOffset", 0, Type::FLOAT },
|
||||
{ "padding1", 0, Type::FLOAT },
|
||||
{ "padding2", 0, Type::FLOAT },
|
||||
|
||||
{ "cameraPosition", 0, Type::FLOAT3, Precision::HIGH },
|
||||
{ "oneOverFarMinusNear", 0, Type::FLOAT, Precision::HIGH },
|
||||
{ "worldOffset", 0, Type::FLOAT3 },
|
||||
{ "nearOverFarMinusNear", 0, Type::FLOAT, Precision::HIGH },
|
||||
{ "cameraFar", 0, Type::FLOAT },
|
||||
{ "exposure", 0, Type::FLOAT, Precision::HIGH }, // high precision to work around #3602 (qualcom),
|
||||
@@ -120,16 +117,18 @@ BufferInterfaceBlock const& UibGenerator::getPerViewUib() noexcept {
|
||||
// ------------------------------------------------------------------------------------
|
||||
// Fog [variant: FOG]
|
||||
// ------------------------------------------------------------------------------------
|
||||
{ "fogStart", 0, Type::FLOAT },
|
||||
{ "fogDensity", 0, Type::FLOAT3,Precision::HIGH },
|
||||
{ "fogStart", 0, Type::FLOAT, Precision::HIGH },
|
||||
{ "fogMaxOpacity", 0, Type::FLOAT },
|
||||
{ "fogHeight", 0, Type::FLOAT },
|
||||
{ "fogHeight", 0, Type::FLOAT, Precision::HIGH },
|
||||
{ "fogHeightFalloff", 0, Type::FLOAT },
|
||||
{ "fogColor", 0, Type::FLOAT3 },
|
||||
{ "fogDensity", 0, Type::FLOAT },
|
||||
{ "fogInscatteringStart", 0, Type::FLOAT },
|
||||
{ "fogInscatteringSize", 0, Type::FLOAT },
|
||||
{ "fogColorFromIbl", 0, Type::FLOAT },
|
||||
{ "fogReserved0", 0, Type::FLOAT },
|
||||
{ "fogColor", 0, Type::FLOAT3 },
|
||||
{ "fogColorFromIbl", 0, Type::FLOAT },
|
||||
{ "fogInscatteringStart", 0, Type::FLOAT, Precision::HIGH },
|
||||
{ "fogInscatteringSize", 0, Type::FLOAT },
|
||||
{ "fogReserved1", 0, Type::FLOAT },
|
||||
{ "fogReserved2", 0, Type::FLOAT },
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
// Screen-space reflections [variant: SSR (i.e.: VSM | SRE)]
|
||||
|
||||
@@ -55,6 +55,7 @@ public:
|
||||
return mSkybox;
|
||||
}
|
||||
|
||||
bool hasSphericalHarmonics() const { return mHasSphericalHarmonics; }
|
||||
filament::math::float3 const* getSphericalHarmonics() const { return mBands; }
|
||||
|
||||
private:
|
||||
@@ -71,6 +72,7 @@ private:
|
||||
filament::Engine& mEngine;
|
||||
|
||||
filament::math::float3 mBands[9] = {};
|
||||
bool mHasSphericalHarmonics = false;
|
||||
|
||||
filament::Texture* mTexture = nullptr;
|
||||
filament::IndirectLight* mIndirectLight = nullptr;
|
||||
|
||||
@@ -139,6 +139,7 @@ bool IBL::loadFromKtx(const std::string& prefix) {
|
||||
if (!iblKtx->getSphericalHarmonics(mBands)) {
|
||||
return false;
|
||||
}
|
||||
mHasSphericalHarmonics = true;
|
||||
|
||||
mIndirectLight = IndirectLight::Builder()
|
||||
.reflections(mTexture)
|
||||
@@ -170,6 +171,7 @@ bool IBL::loadFromDirectory(const utils::Path& path) {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
mHasSphericalHarmonics = true;
|
||||
|
||||
// Read mip-mapped cubemap
|
||||
const std::string prefix = "m";
|
||||
|
||||
@@ -27,8 +27,7 @@ namespace geometry {
|
||||
struct TangentSpaceMeshInput;
|
||||
struct TangentSpaceMeshOutput;
|
||||
|
||||
/* WARNING: WORK-IN-PROGRESS, PLEASE DO NOT USE */
|
||||
/**
|
||||
/**
|
||||
* This class builds Filament-style TANGENTS buffers given an input mesh.
|
||||
*
|
||||
* This class enables the client to chose between several algorithms. The client can retrieve the
|
||||
@@ -139,8 +138,8 @@ public:
|
||||
*/
|
||||
Builder& operator=(Builder&& that) noexcept;
|
||||
|
||||
Builder(const Builder&) = delete;
|
||||
Builder& operator=(const Builder&) = delete;
|
||||
Builder(Builder const&) = delete;
|
||||
Builder& operator=(Builder const&) = delete;
|
||||
|
||||
/**
|
||||
* Client must provide this parameter
|
||||
@@ -154,7 +153,7 @@ public:
|
||||
* @param stride The stride for iterating through `normals`
|
||||
* @return Builder
|
||||
*/
|
||||
Builder& normals(const filament::math::float3* normals, size_t stride = 0) noexcept;
|
||||
Builder& normals(filament::math::float3 const* normals, size_t stride = 0) noexcept;
|
||||
|
||||
/**
|
||||
* @param tangents The input tangents. The `w` component is for use with
|
||||
@@ -162,25 +161,25 @@ public:
|
||||
* @param stride The stride for iterating through `tangents`
|
||||
* @return Builder
|
||||
*/
|
||||
Builder& tangents(const filament::math::float4* tangents, size_t stride = 0) noexcept;
|
||||
Builder& tangents(filament::math::float4 const* tangents, size_t stride = 0) noexcept;
|
||||
|
||||
/**
|
||||
* @param uvs The input uvs
|
||||
* @param stride The stride for iterating through `uvs`
|
||||
* @return Builder
|
||||
*/
|
||||
Builder& uvs(const filament::math::float2* uvs, size_t stride = 0) noexcept;
|
||||
Builder& uvs(filament::math::float2 const* uvs, size_t stride = 0) noexcept;
|
||||
|
||||
/**
|
||||
* @param positions The input positions
|
||||
* @param stride The stride for iterating through `positions`
|
||||
* @return Builder
|
||||
*/
|
||||
Builder& positions(const filament::math::float3* positions, size_t stride = 0) noexcept;
|
||||
Builder& positions(filament::math::float3 const* positions, size_t stride = 0) noexcept;
|
||||
|
||||
Builder& triangleCount(size_t triangleCount) noexcept;
|
||||
Builder& triangles(const filament::math::uint3* triangles) noexcept;
|
||||
Builder& triangles(const filament::math::ushort3* triangles) noexcept;
|
||||
Builder& triangles(filament::math::uint3 const* triangles) noexcept;
|
||||
Builder& triangles(filament::math::ushort3 const* triangles) noexcept;
|
||||
|
||||
Builder& algorithm(Algorithm algorithm) noexcept;
|
||||
|
||||
@@ -215,8 +214,8 @@ public:
|
||||
*/
|
||||
TangentSpaceMesh& operator=(TangentSpaceMesh&& that) noexcept;
|
||||
|
||||
TangentSpaceMesh(const TangentSpaceMesh&) = delete;
|
||||
TangentSpaceMesh& operator=(const TangentSpaceMesh&) = delete;
|
||||
TangentSpaceMesh(TangentSpaceMesh const&) = delete;
|
||||
TangentSpaceMesh& operator=(TangentSpaceMesh const&) = delete;
|
||||
|
||||
/**
|
||||
* Number of output vertices
|
||||
|
||||
@@ -40,7 +40,7 @@ int MikktspaceImpl::getNumVerticesOfFace(SMikkTSpaceContext const* context,
|
||||
}
|
||||
|
||||
void MikktspaceImpl::getPosition(SMikkTSpaceContext const* context, float fvPosOut[],
|
||||
const int iFace, const int iVert) noexcept {
|
||||
int const iFace, int const iVert) noexcept {
|
||||
auto const wrapper = MikktspaceImpl::getThis(context);
|
||||
float3 const pos = *pointerAdd(wrapper->mPositions, wrapper->getTriangle(iFace)[iVert],
|
||||
wrapper->mPositionStride);
|
||||
@@ -60,10 +60,10 @@ void MikktspaceImpl::getNormal(SMikkTSpaceContext const* context, float fvNormOu
|
||||
}
|
||||
|
||||
void MikktspaceImpl::getTexCoord(SMikkTSpaceContext const* context, float fvTexcOut[],
|
||||
const int iFace, const int iVert) noexcept {
|
||||
int const iFace, int const iVert) noexcept {
|
||||
auto const wrapper = MikktspaceImpl::getThis(context);
|
||||
float2 const texc =
|
||||
*pointerAdd(wrapper->mUVs, wrapper->getTriangle(iFace)[iVert], wrapper->mUVStride);
|
||||
float2 const texc
|
||||
= *pointerAdd(wrapper->mUVs, wrapper->getTriangle(iFace)[iVert], wrapper->mUVStride);
|
||||
fvTexcOut[0] = texc.x;
|
||||
fvTexcOut[1] = texc.y;
|
||||
}
|
||||
@@ -102,7 +102,7 @@ MikktspaceImpl* MikktspaceImpl::getThis(SMikkTSpaceContext const* context) noexc
|
||||
return (MikktspaceImpl*) context->m_pUserData;
|
||||
}
|
||||
|
||||
inline const uint3 MikktspaceImpl::getTriangle(int triangleIndex) const noexcept {
|
||||
inline const uint3 MikktspaceImpl::getTriangle(int const triangleIndex) const noexcept {
|
||||
const size_t tstride = mIsTriangle16 ? sizeof(ushort3) : sizeof(uint3);
|
||||
return mIsTriangle16 ? uint3(*(ushort3*) (pointerAdd(mTriangles, triangleIndex, tstride)))
|
||||
: *(uint3*) (pointerAdd(mTriangles, triangleIndex, tstride));
|
||||
@@ -115,7 +115,7 @@ void MikktspaceImpl::run(TangentSpaceMeshOutput* output) noexcept {
|
||||
.m_getPosition = MikktspaceImpl::getPosition,
|
||||
.m_getNormal = MikktspaceImpl::getNormal,
|
||||
.m_getTexCoord = MikktspaceImpl::getTexCoord,
|
||||
.m_setTSpaceBasic = MikktspaceImpl::setTSpaceBasic
|
||||
.m_setTSpaceBasic = MikktspaceImpl::setTSpaceBasic,
|
||||
};
|
||||
SMikkTSpaceContext context{.m_pInterface = &interface, .m_pUserData = this};
|
||||
genTangSpaceDefault(&context);
|
||||
@@ -128,12 +128,12 @@ void MikktspaceImpl::run(TangentSpaceMeshOutput* output) noexcept {
|
||||
meshopt_remapVertexBuffer((void*) newVertices.data(), mOutVertices.data(), mOutVertices.size(),
|
||||
sizeof(IOVertex), remap.data());
|
||||
|
||||
uint3* triangles32 = new uint3[mFaceCount];
|
||||
uint3* triangles32 = output->triangles32.allocate(mFaceCount);
|
||||
meshopt_remapIndexBuffer((uint32_t*) triangles32, NULL, mOutVertices.size(), remap.data());
|
||||
|
||||
float3* outPositions = new float3[vertexCount];
|
||||
float2* outUVs = new float2[vertexCount];
|
||||
quatf* outQuats = new quatf[vertexCount];
|
||||
float3* outPositions = output->positions.allocate(vertexCount);
|
||||
float2* outUVs = output->uvs.allocate(vertexCount);
|
||||
quatf* outQuats = output->tangentSpace.allocate(vertexCount);
|
||||
|
||||
for (size_t i = 0; i < vertexCount; ++i) {
|
||||
outPositions[i] = newVertices[i].position;
|
||||
@@ -142,10 +142,6 @@ void MikktspaceImpl::run(TangentSpaceMeshOutput* output) noexcept {
|
||||
}
|
||||
|
||||
output->vertexCount = vertexCount;
|
||||
output->positions = outPositions;
|
||||
output->uvs = outUVs;
|
||||
output->tangentSpace = outQuats;
|
||||
output->triangles32 = triangles32;
|
||||
output->triangleCount = mFaceCount;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,28 +39,28 @@ public:
|
||||
quatf tangentSpace;
|
||||
};
|
||||
|
||||
MikktspaceImpl(const TangentSpaceMeshInput* input) noexcept;
|
||||
MikktspaceImpl(TangentSpaceMeshInput const* input) noexcept;
|
||||
|
||||
MikktspaceImpl(const MikktspaceImpl&) = delete;
|
||||
MikktspaceImpl& operator=(const MikktspaceImpl&) = delete;
|
||||
MikktspaceImpl(MikktspaceImpl const&) = delete;
|
||||
MikktspaceImpl& operator=(MikktspaceImpl const&) = delete;
|
||||
|
||||
void run(TangentSpaceMeshOutput* output) noexcept;
|
||||
|
||||
private:
|
||||
static int getNumFaces(SMikkTSpaceContext const* context) noexcept;
|
||||
static int getNumVerticesOfFace(SMikkTSpaceContext const* context, int const iFace) noexcept;
|
||||
static void getPosition(SMikkTSpaceContext const* context, float fvPosOut[], const int iFace,
|
||||
const int iVert) noexcept;
|
||||
static void getPosition(SMikkTSpaceContext const* context, float fvPosOut[], int const iFace,
|
||||
int const iVert) noexcept;
|
||||
static void getNormal(SMikkTSpaceContext const* context, float fvNormOut[], int const iFace,
|
||||
int const iVert) noexcept;
|
||||
static void getTexCoord(SMikkTSpaceContext const* context, float fvTexcOut[], const int iFace,
|
||||
const int iVert) noexcept;
|
||||
static void getTexCoord(SMikkTSpaceContext const* context, float fvTexcOut[], int const iFace,
|
||||
int const iVert) noexcept;
|
||||
static void setTSpaceBasic(SMikkTSpaceContext const* context, float const fvTangent[],
|
||||
float const fSign, int const iFace, int const iVert) noexcept;
|
||||
|
||||
static MikktspaceImpl* getThis(SMikkTSpaceContext const* context) noexcept;
|
||||
|
||||
inline const uint3 getTriangle(int triangleIndex) const noexcept;
|
||||
inline const uint3 getTriangle(int const triangleIndex) const noexcept;
|
||||
|
||||
int const mFaceCount;
|
||||
float3 const* mPositions;
|
||||
|
||||
@@ -47,7 +47,7 @@ uint8_t const NORMALS = NORMALS_BIT;
|
||||
uint8_t const POSITIONS_INDICES = POSITIONS_BIT | INDICES_BIT;
|
||||
uint8_t const NORMALS_UVS_POSITIONS_INDICES = NORMALS_BIT | UVS_BIT | POSITIONS_BIT | INDICES_BIT;
|
||||
|
||||
std::string_view to_string(Algorithm algorithm) noexcept {
|
||||
std::string_view to_string(Algorithm const algorithm) noexcept {
|
||||
switch (algorithm) {
|
||||
case Algorithm::DEFAULT:
|
||||
return "DEFAULT";
|
||||
@@ -69,11 +69,11 @@ inline bool isInputType(uint8_t const inputType, uint8_t const checkType) noexce
|
||||
}
|
||||
|
||||
template <typename InputType>
|
||||
inline void takeStride(InputType*& out, size_t stride) noexcept {
|
||||
inline void takeStride(InputType*& out, size_t const stride) noexcept {
|
||||
out = pointerAdd(out, 1, stride);
|
||||
}
|
||||
|
||||
inline Algorithm selectBestDefaultAlgorithm(uint8_t inputType) {
|
||||
inline Algorithm selectBestDefaultAlgorithm(uint8_t const inputType) {
|
||||
Algorithm outAlgo;
|
||||
if (isInputType(inputType, NORMALS_UVS_POSITIONS_INDICES)) {
|
||||
outAlgo = Algorithm::MIKKTSPACE;
|
||||
@@ -170,7 +170,7 @@ inline std::pair<float3, float3> frisvadKernel(float3 const& n) {
|
||||
void frisvadMethod(TangentSpaceMeshInput const* input, TangentSpaceMeshOutput* output)
|
||||
noexcept {
|
||||
size_t const vertexCount = input->vertexCount;
|
||||
quatf* quats = new quatf[vertexCount];
|
||||
quatf* quats = output->tangentSpace.allocate(vertexCount);
|
||||
|
||||
float3 const* UTILS_RESTRICT normals = input->normals;
|
||||
size_t nstride = input->normalStride ? input->normalStride : sizeof(float3);
|
||||
@@ -181,19 +181,19 @@ void frisvadMethod(TangentSpaceMeshInput const* input, TangentSpaceMeshOutput* o
|
||||
quats[qindex] = mat3f::packTangentFrame({t, b, n}, sizeof(int32_t));
|
||||
normals = pointerAdd(normals, 1, nstride);
|
||||
}
|
||||
output->tangentSpace = quats;
|
||||
|
||||
output->vertexCount = input->vertexCount;
|
||||
output->triangleCount = input->triangleCount;
|
||||
output->uvs = input->uvs;
|
||||
output->positions = input->positions;
|
||||
output->triangles32 = input->triangles32;
|
||||
output->triangles16 = input->triangles16;
|
||||
output->uvs.borrow(input->uvs);
|
||||
output->positions.borrow(input->positions);
|
||||
output->triangles32.borrow(input->triangles32);
|
||||
output->triangles16.borrow(input->triangles16);
|
||||
}
|
||||
|
||||
void hughesMollerMethod(TangentSpaceMeshInput const* input, TangentSpaceMeshOutput* output)
|
||||
noexcept {
|
||||
size_t const vertexCount = input->vertexCount;
|
||||
quatf* quats = new quatf[vertexCount];
|
||||
quatf* quats = output->tangentSpace.allocate(vertexCount);
|
||||
|
||||
float3 const* UTILS_RESTRICT normals = input->normals;
|
||||
size_t nstride = input->normalStride ? input->normalStride : sizeof(float3);
|
||||
@@ -213,37 +213,36 @@ void hughesMollerMethod(TangentSpaceMeshInput const* input, TangentSpaceMeshOutp
|
||||
quats[qindex] = mat3f::packTangentFrame({t, b, n}, sizeof(int32_t));
|
||||
normals = pointerAdd(normals, 1, nstride);
|
||||
}
|
||||
output->tangentSpace = quats;
|
||||
output->vertexCount = input->vertexCount;
|
||||
output->triangleCount = input->triangleCount;
|
||||
output->uvs = input->uvs;
|
||||
output->positions = input->positions;
|
||||
output->triangles32 = input->triangles32;
|
||||
output->triangles16 = input->triangles16;
|
||||
output->uvs.borrow(input->uvs);
|
||||
output->positions.borrow(input->positions);
|
||||
output->triangles32.borrow(input->triangles32);
|
||||
output->triangles16.borrow(input->triangles16);
|
||||
}
|
||||
|
||||
void flatShadingMethod(TangentSpaceMeshInput const* input, TangentSpaceMeshOutput* output)
|
||||
noexcept {
|
||||
const float3* positions = input->positions;
|
||||
const size_t pstride = input->positionStride ? input->positionStride : sizeof(float3);
|
||||
float3 const* positions = input->positions;
|
||||
size_t const pstride = input->positionStride ? input->positionStride : sizeof(float3);
|
||||
|
||||
const float2* uvs = input->uvs;
|
||||
const size_t uvstride = input->uvStride ? input->uvStride : sizeof(float2);
|
||||
float2 const* uvs = input->uvs;
|
||||
size_t const uvstride = input->uvStride ? input->uvStride : sizeof(float2);
|
||||
|
||||
const bool isTriangle16 = input->triangles16 != nullptr;
|
||||
const uint8_t* triangles = isTriangle16 ? (const uint8_t*) input->triangles16 :
|
||||
(const uint8_t*) input->triangles32;
|
||||
bool const isTriangle16 = input->triangles16 != nullptr;
|
||||
uint8_t const* triangles = isTriangle16 ? (uint8_t const*) input->triangles16 :
|
||||
(uint8_t const*) input->triangles32;
|
||||
|
||||
const size_t triangleCount = input->triangleCount;
|
||||
const size_t tstride = isTriangle16 ? sizeof(ushort3) : sizeof(uint3);
|
||||
size_t const triangleCount = input->triangleCount;
|
||||
size_t const tstride = isTriangle16 ? sizeof(ushort3) : sizeof(uint3);
|
||||
|
||||
const size_t outVertexCount = triangleCount * 3;
|
||||
float3* outPositions = new float3[outVertexCount];
|
||||
float2* outUvs = uvs ? new float2[outVertexCount] : nullptr;
|
||||
quatf* quats = new quatf[outVertexCount];
|
||||
size_t const outVertexCount = triangleCount * 3;
|
||||
float3* outPositions = output->positions.allocate(outVertexCount);
|
||||
float2* outUvs = uvs ? output->uvs.allocate(outVertexCount) : nullptr;
|
||||
quatf* quats = output->tangentSpace.allocate(outVertexCount);
|
||||
|
||||
const size_t outTriangleCount = triangleCount;
|
||||
uint3* outTriangles = new uint3[outTriangleCount];
|
||||
size_t const outTriangleCount = triangleCount;
|
||||
uint3* outTriangles = output->triangles32.allocate(outTriangleCount);
|
||||
|
||||
size_t vindex = 0;
|
||||
for (size_t tindex = 0; tindex < triangleCount; ++tindex) {
|
||||
@@ -251,9 +250,9 @@ void flatShadingMethod(TangentSpaceMeshInput const* input, TangentSpaceMeshOutpu
|
||||
uint3(*(ushort3*)(pointerAdd(triangles, tindex, tstride))) :
|
||||
*(uint3*)(pointerAdd(triangles, tindex, tstride));
|
||||
|
||||
const float3 pa = *pointerAdd(positions, tri.x, pstride);
|
||||
const float3 pb = *pointerAdd(positions, tri.y, pstride);
|
||||
const float3 pc = *pointerAdd(positions, tri.z, pstride);
|
||||
float3 const pa = *pointerAdd(positions, tri.x, pstride);
|
||||
float3 const pb = *pointerAdd(positions, tri.y, pstride);
|
||||
float3 const pc = *pointerAdd(positions, tri.z, pstride);
|
||||
|
||||
uint32_t i0 = vindex++, i1 = vindex++, i2 = vindex++;
|
||||
outTriangles[tindex] = uint3{i0, i1, i2};
|
||||
@@ -262,10 +261,10 @@ void flatShadingMethod(TangentSpaceMeshInput const* input, TangentSpaceMeshOutpu
|
||||
outPositions[i1] = pb;
|
||||
outPositions[i2] = pc;
|
||||
|
||||
const float3 n = normalize(cross(pc - pb, pa - pb));
|
||||
float3 const n = normalize(cross(pc - pb, pa - pb));
|
||||
const auto [t, b] = frisvadKernel(n);
|
||||
|
||||
const quatf tspace = mat3f::packTangentFrame({t, b, n}, sizeof(int32_t));
|
||||
quatf const tspace = mat3f::packTangentFrame({t, b, n}, sizeof(int32_t));
|
||||
quats[i0] = tspace;
|
||||
quats[i1] = tspace;
|
||||
quats[i2] = tspace;
|
||||
@@ -277,11 +276,7 @@ void flatShadingMethod(TangentSpaceMeshInput const* input, TangentSpaceMeshOutpu
|
||||
}
|
||||
}
|
||||
|
||||
output->tangentSpace = quats;
|
||||
output->positions = outPositions;
|
||||
output->vertexCount = outVertexCount;
|
||||
output->uvs = outUvs;
|
||||
output->triangles32 = outTriangles;
|
||||
output->triangleCount = outTriangleCount;
|
||||
}
|
||||
|
||||
@@ -290,7 +285,7 @@ void mikktspaceMethod(TangentSpaceMeshInput const* input, TangentSpaceMeshOutput
|
||||
impl.run(output);
|
||||
}
|
||||
|
||||
inline float3 randomPerp(const float3& n) {
|
||||
inline float3 randomPerp(float3 const& n) {
|
||||
float3 perp = cross(n, float3{1, 0, 0});
|
||||
float sqrlen = dot(perp, perp);
|
||||
if (sqrlen <= std::numeric_limits<float>::epsilon()) {
|
||||
@@ -356,38 +351,30 @@ void lengyelMethod(TangentSpaceMeshInput const* input, TangentSpaceMeshOutput* o
|
||||
tan2[tri.z] += tdir;
|
||||
}
|
||||
|
||||
quatf* quats = new quatf[vertexCount];
|
||||
quatf* quats = output->tangentSpace.allocate(vertexCount);
|
||||
for (size_t a = 0; a < vertexCount; a++) {
|
||||
float3 const& n = normals[a];
|
||||
float3 const& t1 = tan1[a];
|
||||
float3 const& t2 = tan2[a];
|
||||
|
||||
// Gram-Schmidt orthogonalize
|
||||
float3 t = normalize(t1 - n * dot(n, t1));
|
||||
float3 const t = normalize(t1 - n * dot(n, t1));
|
||||
|
||||
// Calculate handedness
|
||||
float w = (dot(cross(n, t1), t2) < 0.0f) ? -1.0f : 1.0f;
|
||||
float const w = (dot(cross(n, t1), t2) < 0.0f) ? -1.0f : 1.0f;
|
||||
|
||||
float3 b = w < 0 ? cross(t, n) : cross(n, t);
|
||||
quats[a] = mat3f::packTangentFrame({t, b, n}, sizeof(int32_t));
|
||||
}
|
||||
|
||||
output->tangentSpace = quats;
|
||||
output->vertexCount = vertexCount;
|
||||
output->triangleCount = triangleCount;
|
||||
output->uvs = uvs;
|
||||
output->positions = positions;
|
||||
output->triangles32 = triangles32;
|
||||
output->triangles16 = triangles16;
|
||||
output->uvs.borrow(uvs);
|
||||
output->positions.borrow(positions);
|
||||
output->triangles32.borrow(triangles32);
|
||||
output->triangles16.borrow(triangles16);
|
||||
}
|
||||
|
||||
template<typename DataType, typename InputType>
|
||||
inline void cleanOutputPointer(DataType*& ptr, InputType inputPtr) noexcept {
|
||||
if (ptr && ptr != (const DataType*) inputPtr) {
|
||||
delete[] ptr;
|
||||
}
|
||||
ptr = nullptr;
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
Builder::Builder() noexcept
|
||||
@@ -411,19 +398,19 @@ Builder& Builder::vertexCount(size_t vertexCount) noexcept {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Builder& Builder::normals(const float3* normals, size_t stride) noexcept {
|
||||
Builder& Builder::normals(float3 const* normals, size_t stride) noexcept {
|
||||
mMesh->mInput->normals = normals;
|
||||
mMesh->mInput->normalStride = stride;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Builder& Builder::uvs(const float2* uvs, size_t stride) noexcept {
|
||||
Builder& Builder::uvs(float2 const* uvs, size_t stride) noexcept {
|
||||
mMesh->mInput->uvs = uvs;
|
||||
mMesh->mInput->uvStride = stride;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Builder& Builder::positions(const float3* positions, size_t stride) noexcept {
|
||||
Builder& Builder::positions(float3 const* positions, size_t stride) noexcept {
|
||||
mMesh->mInput->positions = positions;
|
||||
mMesh->mInput->positionStride = stride;
|
||||
return *this;
|
||||
@@ -434,12 +421,12 @@ Builder& Builder::triangleCount(size_t triangleCount) noexcept {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Builder& Builder::triangles(const uint3* triangle32) noexcept {
|
||||
Builder& Builder::triangles(uint3 const* triangle32) noexcept {
|
||||
mMesh->mInput->triangles32 = triangle32;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Builder& Builder::triangles(const ushort3* triangle16) noexcept {
|
||||
Builder& Builder::triangles(ushort3 const* triangle16) noexcept {
|
||||
mMesh->mInput->triangles16 = triangle16;
|
||||
return *this;
|
||||
}
|
||||
@@ -494,12 +481,6 @@ TangentSpaceMesh::TangentSpaceMesh() noexcept
|
||||
}
|
||||
|
||||
TangentSpaceMesh::~TangentSpaceMesh() noexcept {
|
||||
cleanOutputPointer(mOutput->tangentSpace, (quatf*) nullptr);
|
||||
cleanOutputPointer(mOutput->uvs, mInput->uvs);
|
||||
cleanOutputPointer(mOutput->positions, mInput->positions);
|
||||
cleanOutputPointer(mOutput->triangles16, mInput->triangles16);
|
||||
cleanOutputPointer(mOutput->triangles32, mInput->triangles32);
|
||||
|
||||
delete mOutput;
|
||||
delete mInput;
|
||||
}
|
||||
@@ -522,8 +503,9 @@ size_t TangentSpaceMesh::getVertexCount() const noexcept {
|
||||
void TangentSpaceMesh::getPositions(float3* positions, size_t stride) const {
|
||||
ASSERT_PRECONDITION(mInput->positions, "Must provide input positions");
|
||||
stride = stride ? stride : sizeof(decltype(*positions));
|
||||
auto outPositions = mOutput->positions.get();
|
||||
for (size_t i = 0; i < mOutput->vertexCount; ++i) {
|
||||
*positions = mOutput->positions[i];
|
||||
*positions = outPositions[i];
|
||||
takeStride(positions, stride);
|
||||
}
|
||||
}
|
||||
@@ -531,8 +513,9 @@ void TangentSpaceMesh::getPositions(float3* positions, size_t stride) const {
|
||||
void TangentSpaceMesh::getUVs(float2* uvs, size_t stride) const {
|
||||
ASSERT_PRECONDITION(mInput->uvs, "Must provide input UVs");
|
||||
stride = stride ? stride : sizeof(decltype(*uvs));
|
||||
auto outUvs = mOutput->uvs.get();
|
||||
for (size_t i = 0; i < mOutput->vertexCount; ++i) {
|
||||
*uvs = mOutput->uvs[i];
|
||||
*uvs = outUvs[i];
|
||||
takeStride(uvs, stride);
|
||||
}
|
||||
}
|
||||
@@ -544,10 +527,12 @@ size_t TangentSpaceMesh::getTriangleCount() const noexcept {
|
||||
void TangentSpaceMesh::getTriangles(uint3* out) const {
|
||||
ASSERT_PRECONDITION(mInput->triangles16 || mInput->triangles32, "Must provide input triangles");
|
||||
|
||||
const bool is16 = mOutput->triangles16 != nullptr;
|
||||
const size_t stride = sizeof(decltype(*out));
|
||||
bool const is16 = (bool) mOutput->triangles16;
|
||||
auto triangles16 = mOutput->triangles16.get();
|
||||
auto triangles32 = mOutput->triangles32.get();
|
||||
size_t const stride = sizeof(decltype(*out));
|
||||
for (size_t i = 0; i < mOutput->triangleCount; ++i) {
|
||||
*out = is16 ? uint3{mOutput->triangles16[i]} : mOutput->triangles32[i];
|
||||
*out = is16 ? uint3{triangles16[i]} : triangles32[i];
|
||||
takeStride(out, stride);
|
||||
}
|
||||
}
|
||||
@@ -555,13 +540,15 @@ void TangentSpaceMesh::getTriangles(uint3* out) const {
|
||||
void TangentSpaceMesh::getTriangles(ushort3* out) const {
|
||||
ASSERT_PRECONDITION(mInput->triangles16 || mInput->triangles32, "Must provide input triangles");
|
||||
|
||||
const bool is16 = mOutput->triangles16 != nullptr;
|
||||
const bool is16 = (bool) mOutput->triangles16;
|
||||
auto triangles16 = mOutput->triangles16.get();
|
||||
auto triangles32 = mOutput->triangles32.get();
|
||||
const size_t stride = sizeof(decltype(*out));
|
||||
for (size_t i = 0, c = mOutput->triangleCount; i < c; ++i) {
|
||||
if (is16) {
|
||||
*out = mOutput->triangles16[i];
|
||||
*out = triangles16[i];
|
||||
} else {
|
||||
const uint3 &tri = mOutput->triangles32[i];
|
||||
uint3 const& tri = triangles32[i];
|
||||
ASSERT_PRECONDITION(tri.x <= USHRT_MAX &&
|
||||
tri.y <= USHRT_MAX &&
|
||||
tri.z <= USHRT_MAX, "Overflow when casting uint3 to ushort3");
|
||||
@@ -575,8 +562,8 @@ void TangentSpaceMesh::getTriangles(ushort3* out) const {
|
||||
|
||||
void TangentSpaceMesh::getQuats(quatf* out, size_t stride) const noexcept {
|
||||
stride = stride ? stride : sizeof(decltype((*out)));
|
||||
const quatf* tangentSpace = mOutput->tangentSpace;
|
||||
const size_t vertexCount = mOutput->vertexCount;
|
||||
auto tangentSpace = mOutput->tangentSpace.get();
|
||||
size_t const vertexCount = mOutput->vertexCount;
|
||||
for (size_t i = 0; i < vertexCount; ++i) {
|
||||
*out = tangentSpace[i];
|
||||
takeStride(out, stride);
|
||||
@@ -585,8 +572,8 @@ void TangentSpaceMesh::getQuats(quatf* out, size_t stride) const noexcept {
|
||||
|
||||
void TangentSpaceMesh::getQuats(short4* out, size_t stride) const noexcept {
|
||||
stride = stride ? stride : sizeof(decltype((*out)));
|
||||
const quatf* tangentSpace = mOutput->tangentSpace;
|
||||
const size_t vertexCount = mOutput->vertexCount;
|
||||
auto tangentSpace = mOutput->tangentSpace.get();
|
||||
size_t const vertexCount = mOutput->vertexCount;
|
||||
for (size_t i = 0; i < vertexCount; ++i) {
|
||||
*out = packSnorm16(tangentSpace[i].xyzw);
|
||||
takeStride(out, stride);
|
||||
@@ -595,8 +582,8 @@ void TangentSpaceMesh::getQuats(short4* out, size_t stride) const noexcept {
|
||||
|
||||
void TangentSpaceMesh::getQuats(quath* out, size_t stride) const noexcept {
|
||||
stride = stride ? stride : sizeof(decltype((*out)));
|
||||
const quatf* tangentSpace = mOutput->tangentSpace;
|
||||
const size_t vertexCount = mOutput->vertexCount;
|
||||
auto tangentSpace = mOutput->tangentSpace.get();
|
||||
size_t const vertexCount = mOutput->vertexCount;
|
||||
for (size_t i = 0; i < vertexCount; ++i) {
|
||||
*out = quath(tangentSpace[i].xyzw);
|
||||
takeStride(out, stride);
|
||||
|
||||
@@ -22,11 +22,47 @@
|
||||
#include <math/mat3.h>
|
||||
#include <math/norm.h>
|
||||
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace filament::geometry {
|
||||
|
||||
using namespace filament::math;
|
||||
using Algorithm = TangentSpaceMesh::Algorithm;
|
||||
|
||||
template<typename T>
|
||||
class InternalArray {
|
||||
public:
|
||||
void borrow(T const* ptr) {
|
||||
assert_invariant(mAllocated.empty());
|
||||
mBorrowed = ptr;
|
||||
}
|
||||
|
||||
T* allocate(size_t size) {
|
||||
assert_invariant(!mBorrowed);
|
||||
mAllocated.resize(size);
|
||||
mAllocated.shrink_to_fit();
|
||||
return mAllocated.data();
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
return !mBorrowed && !mAllocated.empty();
|
||||
}
|
||||
|
||||
const T* get() {
|
||||
assert_invariant((bool) this);
|
||||
if (mBorrowed) {
|
||||
return mBorrowed;
|
||||
}
|
||||
return mAllocated.data();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<T> mAllocated;
|
||||
T const* mBorrowed = nullptr;
|
||||
};
|
||||
|
||||
struct TangentSpaceMeshInput {
|
||||
size_t vertexCount = 0;
|
||||
float3 const* normals = nullptr;
|
||||
@@ -49,11 +85,11 @@ struct TangentSpaceMeshOutput {
|
||||
size_t triangleCount = 0;
|
||||
size_t vertexCount = 0;
|
||||
|
||||
quatf const* tangentSpace = nullptr;
|
||||
float2 const* uvs = nullptr;
|
||||
float3 const* positions = nullptr;
|
||||
uint3 const* triangles32 = nullptr;
|
||||
ushort3 const* triangles16 = nullptr;
|
||||
InternalArray<quatf> tangentSpace;
|
||||
InternalArray<float2> uvs;
|
||||
InternalArray<float3> positions;
|
||||
InternalArray<uint3> triangles32;
|
||||
InternalArray<ushort3> triangles16;
|
||||
};
|
||||
|
||||
template<typename InputType>
|
||||
|
||||
@@ -54,6 +54,12 @@
|
||||
# define UTILS_NORETURN
|
||||
#endif
|
||||
|
||||
#if __has_attribute(fallthrough)
|
||||
# define UTILS_FALLTHROUGH [[fallthrough]]
|
||||
#else
|
||||
# define UTILS_FALLTHROUGH
|
||||
#endif
|
||||
|
||||
#if __has_attribute(visibility)
|
||||
# ifndef TNT_DEV
|
||||
# define UTILS_PRIVATE __attribute__((visibility("hidden")))
|
||||
|
||||
@@ -333,10 +333,16 @@ static void setup(Engine* engine, View*, Scene* scene) {
|
||||
if (ibl) {
|
||||
auto& params = g_params;
|
||||
IndirectLight* const pIndirectLight = ibl->getIndirectLight();
|
||||
params.lightDirection = IndirectLight::getDirectionEstimate(ibl->getSphericalHarmonics());
|
||||
float4 c = pIndirectLight->getColorEstimate(ibl->getSphericalHarmonics(), params.lightDirection);
|
||||
params.lightIntensity = c.w * pIndirectLight->getIntensity();
|
||||
params.lightColor = c.rgb;
|
||||
// If we loaded an equirectangular IBL, we don't have spherical harmonics. In that case,
|
||||
// simply skip the estimates.
|
||||
if (ibl->hasSphericalHarmonics()) {
|
||||
params.lightDirection =
|
||||
IndirectLight::getDirectionEstimate(ibl->getSphericalHarmonics());
|
||||
float4 c = pIndirectLight->getColorEstimate(
|
||||
ibl->getSphericalHarmonics(), params.lightDirection);
|
||||
params.lightIntensity = c.w * pIndirectLight->getIntensity();
|
||||
params.lightColor = c.rgb;
|
||||
}
|
||||
}
|
||||
|
||||
g_params.bloomOptions.dirt = FilamentApp::get().getDirtTexture();
|
||||
|
||||
@@ -32,6 +32,11 @@ highp mat4 getWorldFromClipMatrix() {
|
||||
return frameUniforms.worldFromClipMatrix;
|
||||
}
|
||||
|
||||
/** @public-api */
|
||||
highp mat4 getUserWorldFromWorldMatrix() {
|
||||
return frameUniforms.userWorldFromWorldMatrix;
|
||||
}
|
||||
|
||||
/** @public-api */
|
||||
float getTime() {
|
||||
return frameUniforms.time;
|
||||
@@ -81,12 +86,12 @@ highp vec4 getResolution() {
|
||||
|
||||
/** @public-api */
|
||||
highp vec3 getWorldCameraPosition() {
|
||||
return frameUniforms.cameraPosition;
|
||||
return frameUniforms.worldFromViewMatrix[3].xyz;
|
||||
}
|
||||
|
||||
/** @public-api */
|
||||
/** @public-api, @deprecated use getUserWorldPosition() or getUserWorldFromWorldMatrix() instead */
|
||||
highp vec3 getWorldOffset() {
|
||||
return frameUniforms.worldOffset;
|
||||
return getUserWorldFromWorldMatrix()[3].xyz;
|
||||
}
|
||||
|
||||
/** @public-api */
|
||||
|
||||
+57
-39
@@ -1,62 +1,80 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// Fog
|
||||
// see: Real-time Atmospheric Effects in Games (Carsten Wenzel)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
vec4 fog(vec4 color, vec3 view) {
|
||||
if (frameUniforms.fogDensity > 0.0) {
|
||||
float A = frameUniforms.fogDensity;
|
||||
float B = frameUniforms.fogHeightFalloff;
|
||||
vec4 fog(vec4 color, highp vec3 view) {
|
||||
// .x = density
|
||||
// .y = -fallof*(y-height)
|
||||
// .z = density * exp(-fallof*(y-height))
|
||||
highp vec3 density = frameUniforms.fogDensity;
|
||||
float falloff = frameUniforms.fogHeightFalloff;
|
||||
|
||||
float d = length(view);
|
||||
|
||||
float h = max(0.001, view.y);
|
||||
// Compute the integral of the fog density at a distance of 1m at a given height.
|
||||
highp float fogDensityIntegralAtOneMeter = density.z;
|
||||
highp float h = falloff * view.y;
|
||||
if (abs(h) > 0.01) {
|
||||
// The function below is continuous at h=0, so to avoid a divide-by-zero, we just clamp h
|
||||
float fogIntegralFunctionOfDistance = A * ((1.0 - exp(-B * h)) / h);
|
||||
float fogIntegral = fogIntegralFunctionOfDistance * max(d - frameUniforms.fogStart, 0.0);
|
||||
float fogOpacity = max(1.0 - exp2(-fogIntegral), 0.0);
|
||||
fogDensityIntegralAtOneMeter = (fogDensityIntegralAtOneMeter - density.x * exp(density.y - h)) / h;
|
||||
}
|
||||
|
||||
// don't go above requested max opacity
|
||||
fogOpacity = min(fogOpacity, frameUniforms.fogMaxOpacity);
|
||||
// Compute the integral of the fog density at a given height from fogStart to the fragment
|
||||
highp float d = length(view);
|
||||
highp float fogDensityIntegral =
|
||||
fogDensityIntegralAtOneMeter * max(d - frameUniforms.fogStart, 0.0);
|
||||
|
||||
// compute fog color
|
||||
vec3 fogColor = frameUniforms.fogColor;
|
||||
// Compute the transmittance using the Beer-Lambert Law
|
||||
float fogTransmittance = exp(-fogDensityIntegral);
|
||||
|
||||
if (frameUniforms.fogColorFromIbl > 0.0) {
|
||||
// get fog color from envmap
|
||||
float lod = frameUniforms.iblRoughnessOneLevel;
|
||||
fogColor *= textureLod(light_iblSpecular, view, lod).rgb * frameUniforms.iblLuminance;
|
||||
}
|
||||
// Compute the opacity from the transmittance
|
||||
float fogOpacity = min(1.0 - fogTransmittance, frameUniforms.fogMaxOpacity);
|
||||
|
||||
fogColor *= fogOpacity;
|
||||
if (frameUniforms.fogInscatteringSize > 0.0) {
|
||||
// compute a new line-integral for a different start distance
|
||||
float inscatteringIntegral = fogIntegralFunctionOfDistance *
|
||||
max(d - frameUniforms.fogInscatteringStart, 0.0);
|
||||
float inscatteringOpacity = max(1.0 - exp2(-inscatteringIntegral), 0.0);
|
||||
// compute fog color
|
||||
vec3 fogColor = frameUniforms.fogColor;
|
||||
|
||||
// Add sun colored fog when looking towards the sun
|
||||
vec3 sunColor = frameUniforms.lightColorIntensity.rgb * frameUniforms.lightColorIntensity.w;
|
||||
float sunAmount = max(dot(view, frameUniforms.lightDirection) / d, 0.0); // between 0 and 1
|
||||
float sunInscattering = pow(sunAmount, frameUniforms.fogInscatteringSize);
|
||||
if (frameUniforms.fogColorFromIbl > 0.0) {
|
||||
// get fog color from envmap
|
||||
float lod = frameUniforms.iblRoughnessOneLevel;
|
||||
fogColor *= textureLod(light_iblSpecular, view, lod).rgb * frameUniforms.iblLuminance;
|
||||
}
|
||||
|
||||
fogColor += sunColor * (sunInscattering * inscatteringOpacity);
|
||||
}
|
||||
fogColor *= fogOpacity;
|
||||
|
||||
if (frameUniforms.fogInscatteringSize > 0.0) {
|
||||
// compute a new line-integral for a different start distance
|
||||
highp float inscatteringDensityIntegral =
|
||||
fogDensityIntegralAtOneMeter * max(d - frameUniforms.fogInscatteringStart, 0.0);
|
||||
|
||||
// Compute the transmittance using the Beer-Lambert Law
|
||||
float inscatteringDensity = exp(-inscatteringDensityIntegral);
|
||||
|
||||
// Compute the opacity from the transmittance
|
||||
float inscatteringOpacity = 1.0 - inscatteringDensity;
|
||||
|
||||
// Add sun colored fog when looking towards the sun
|
||||
vec3 sunColor = frameUniforms.lightColorIntensity.rgb * frameUniforms.lightColorIntensity.w;
|
||||
|
||||
float sunAmount = max(dot(view, frameUniforms.lightDirection) / d, 0.0); // between 0 and 1
|
||||
float sunInscattering = pow(sunAmount, frameUniforms.fogInscatteringSize);
|
||||
|
||||
fogColor += sunColor * (sunInscattering * inscatteringOpacity);
|
||||
}
|
||||
|
||||
#if defined(BLEND_MODE_OPAQUE)
|
||||
// nothing to do here
|
||||
// nothing to do here
|
||||
#elif defined(BLEND_MODE_TRANSPARENT)
|
||||
fogColor *= color.a;
|
||||
fogColor *= color.a;
|
||||
#elif defined(BLEND_MODE_ADD)
|
||||
fogColor = vec3(0.0);
|
||||
fogColor = vec3(0.0);
|
||||
#elif defined(BLEND_MODE_MASKED)
|
||||
// nothing to do here
|
||||
// nothing to do here
|
||||
#elif defined(BLEND_MODE_MULTIPLY)
|
||||
// FIXME: unclear what to do here
|
||||
// FIXME: unclear what to do here
|
||||
#elif defined(BLEND_MODE_SCREEN)
|
||||
// FIXME: unclear what to do here
|
||||
// FIXME: unclear what to do here
|
||||
#endif
|
||||
|
||||
color.rgb = color.rgb * (1.0 - fogOpacity) + fogColor;
|
||||
}
|
||||
color.rgb = color.rgb * (1.0 - fogOpacity) + fogColor;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,11 @@ highp vec3 getWorldPosition() {
|
||||
return shading_position;
|
||||
}
|
||||
|
||||
/** @public-api */
|
||||
highp vec3 getUserWorldPosition() {
|
||||
return mulMat4x4Float3(getUserWorldFromWorldMatrix(), getWorldPosition()).xyz;
|
||||
}
|
||||
|
||||
/** @public-api */
|
||||
vec3 getWorldViewVector() {
|
||||
return shading_view;
|
||||
|
||||
@@ -36,10 +36,10 @@ void computeShadingParams() {
|
||||
|
||||
// With perspective camera, the view vector is cast from the fragment pos to the eye position,
|
||||
// With ortho camera, however, the view vector is the same for all fragments:
|
||||
shading_view = isPerspectiveProjection() ?
|
||||
(frameUniforms.cameraPosition - shading_position) :
|
||||
frameUniforms.worldFromViewMatrix[2].xyz; // ortho camera backward dir
|
||||
shading_view = normalize(shading_view);
|
||||
highp vec3 sv = isPerspectiveProjection() ?
|
||||
(frameUniforms.worldFromViewMatrix[3].xyz - shading_position) :
|
||||
frameUniforms.worldFromViewMatrix[2].xyz; // ortho camera backward dir
|
||||
shading_view = normalize(sv);
|
||||
|
||||
// we do this so we avoid doing (matrix multiply), but we burn 4 varyings:
|
||||
// p = clipFromWorldMatrix * shading_position;
|
||||
|
||||
Vendored
+18
-24
@@ -1,26 +1,20 @@
|
||||
Copyright (c) 1987, 1993, 1994, 1995
|
||||
The Regents of the University of California. All rights reserved.
|
||||
Copyright © 2005-2014 Rich Felker, et al.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the names of the copyright holders nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
+31
-62
@@ -1,62 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 1987, 1993, 1994, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
|
||||
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __GETOPT_H__
|
||||
#define __GETOPT_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int opterr; /* if error message should be printed */
|
||||
extern int optind; /* index into parent argv vector */
|
||||
extern int optopt; /* character checked for validity */
|
||||
extern int optreset; /* reset getopt */
|
||||
extern char *optarg; /* argument associated with option */
|
||||
|
||||
struct option {
|
||||
const char *name;
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
#define no_argument 0
|
||||
#define required_argument 1
|
||||
#define optional_argument 2
|
||||
|
||||
int getopt(int, char **, const char *);
|
||||
|
||||
int getopt_long(int, char **, const char *, const struct option *, int *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __GETOPT_H__ */
|
||||
#ifndef _GETOPT_H
|
||||
#define _GETOPT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int getopt(int, char * const [], const char *);
|
||||
extern char *optarg;
|
||||
extern int optind, opterr, optopt, optreset;
|
||||
|
||||
struct option
|
||||
{
|
||||
const char *name;
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
int getopt_long(int, char *const *, const char *, const struct option *, int *);
|
||||
int getopt_long_only(int, char *const *, const char *, const struct option *, int *);
|
||||
|
||||
#define no_argument 0
|
||||
#define required_argument 1
|
||||
#define optional_argument 2
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
+82
-139
@@ -1,139 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 1987, 1993, 1994, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
|
||||
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef __P
|
||||
#define __P(x) x
|
||||
#endif
|
||||
#define _DIAGASSERT(x) assert(x)
|
||||
|
||||
#ifdef __weak_alias
|
||||
__weak_alias(getopt, _getopt);
|
||||
#endif
|
||||
|
||||
int opterr = 1, /* if error message should be printed */
|
||||
optind = 1, /* index into parent argv vector */
|
||||
optopt, /* character checked for validity */
|
||||
optreset; /* reset getopt */
|
||||
char *optarg; /* argument associated with option */
|
||||
|
||||
static char *_progname __P((char *));
|
||||
|
||||
int getopt_internal __P((int, char *const *, const char *));
|
||||
|
||||
static char *_progname(nargv0)
|
||||
|
||||
char *nargv0;
|
||||
{
|
||||
char *tmp;
|
||||
|
||||
_DIAGASSERT(nargv0 != NULL);
|
||||
|
||||
tmp = strrchr(nargv0, '/');
|
||||
if (tmp)
|
||||
tmp++;
|
||||
else
|
||||
tmp = nargv0;
|
||||
return (tmp);
|
||||
}
|
||||
|
||||
#define BADCH (int)'?'
|
||||
#define BADARG (int)':'
|
||||
#define EMSG ""
|
||||
|
||||
/*
|
||||
* getopt --
|
||||
* Parse argc/argv argument vector.
|
||||
*/
|
||||
int getopt(nargc, nargv, ostr)
|
||||
|
||||
int nargc;
|
||||
char *const nargv[];
|
||||
const char *ostr;
|
||||
{
|
||||
static char *__progname = 0;
|
||||
static char *place = EMSG; /* option letter processing */
|
||||
char *oli; /* option letter list index */
|
||||
__progname = __progname ? __progname : _progname(*nargv);
|
||||
|
||||
_DIAGASSERT(nargv != NULL);
|
||||
_DIAGASSERT(ostr != NULL);
|
||||
|
||||
if (optreset || !*place) { /* update scanning pointer */
|
||||
optreset = 0;
|
||||
if (optind >= nargc || *(place = nargv[optind]) != '-') {
|
||||
place = EMSG;
|
||||
return (-1);
|
||||
}
|
||||
if (place[1] && *++place == '-' /* found "--" */
|
||||
&& place[1] == '\0') {
|
||||
++optind;
|
||||
place = EMSG;
|
||||
return (-1);
|
||||
}
|
||||
} /* option letter okay? */
|
||||
if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) {
|
||||
/*
|
||||
* if the user didn't specify '-' as an option,
|
||||
* assume it means -1.
|
||||
*/
|
||||
if (optopt == (int)'-')
|
||||
return (-1);
|
||||
if (!*place)
|
||||
++optind;
|
||||
if (opterr && *ostr != ':')
|
||||
(void)fprintf(stderr, "%s: illegal option -- %c\n", __progname, optopt);
|
||||
return (BADCH);
|
||||
}
|
||||
if (*++oli != ':') { /* don't need argument */
|
||||
optarg = NULL;
|
||||
if (!*place)
|
||||
++optind;
|
||||
} else { /* need an argument */
|
||||
if (*place) /* no white space */
|
||||
optarg = place;
|
||||
else if (nargc <= ++optind) { /* no arg */
|
||||
place = EMSG;
|
||||
if (*ostr == ':')
|
||||
return (BADARG);
|
||||
if (opterr)
|
||||
(void)fprintf(stderr, "%s: option requires an argument -- %c\n",
|
||||
__progname, optopt);
|
||||
return (BADCH);
|
||||
} else /* white space */
|
||||
optarg = nargv[optind];
|
||||
place = EMSG;
|
||||
++optind;
|
||||
}
|
||||
return (optopt); /* dump back option letter */
|
||||
}
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <wchar.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include "libc.h"
|
||||
|
||||
char *optarg;
|
||||
int optind=1, opterr=1, optopt, __optpos, __optreset=0;
|
||||
|
||||
#define optpos __optpos
|
||||
#ifndef _WIN32
|
||||
weak_alias(__optreset, optreset);
|
||||
#endif
|
||||
|
||||
int getopt(int argc, char * const argv[], const char *optstring)
|
||||
{
|
||||
int i;
|
||||
wchar_t c, d;
|
||||
int k, l;
|
||||
char *optchar;
|
||||
|
||||
if (!optind || __optreset) {
|
||||
__optreset = 0;
|
||||
__optpos = 0;
|
||||
optind = 1;
|
||||
}
|
||||
|
||||
if (optind >= argc || !argv[optind] || argv[optind][0] != '-' || !argv[optind][1])
|
||||
return -1;
|
||||
if (argv[optind][1] == '-' && !argv[optind][2])
|
||||
return optind++, -1;
|
||||
|
||||
if (!optpos) optpos++;
|
||||
if ((k = mbtowc(&c, argv[optind]+optpos, MB_LEN_MAX)) < 0) {
|
||||
k = 1;
|
||||
c = 0xfffd; /* replacement char */
|
||||
}
|
||||
optchar = argv[optind]+optpos;
|
||||
optopt = c;
|
||||
optpos += k;
|
||||
|
||||
if (!argv[optind][optpos]) {
|
||||
optind++;
|
||||
optpos = 0;
|
||||
}
|
||||
|
||||
for (i=0; (l = mbtowc(&d, optstring+i, MB_LEN_MAX)) && d!=c; i+=l>0?l:1);
|
||||
|
||||
if (d != c) {
|
||||
if (optstring[0] != ':' && opterr) {
|
||||
write(2, argv[0], strlen(argv[0]));
|
||||
write(2, ": illegal option: ", 18);
|
||||
write(2, optchar, k);
|
||||
write(2, "\n", 1);
|
||||
}
|
||||
return '?';
|
||||
}
|
||||
if (optstring[i+1] == ':') {
|
||||
if (optind >= argc) {
|
||||
if (optstring[0] == ':') return ':';
|
||||
if (opterr) {
|
||||
write(2, argv[0], strlen(argv[0]));
|
||||
write(2, ": option requires an argument: ", 31);
|
||||
write(2, optchar, k);
|
||||
write(2, "\n", 1);
|
||||
}
|
||||
return '?';
|
||||
}
|
||||
optarg = argv[optind++] + optpos;
|
||||
optpos = 0;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
weak_alias(getopt, __posix_getopt);
|
||||
#endif
|
||||
|
||||
+59
-231
@@ -1,231 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 1987, 1993, 1994, 1996
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
|
||||
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "getopt/getopt.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
extern int opterr; /* if error message should be printed */
|
||||
extern int optind; /* index into parent argv vector */
|
||||
extern int optopt; /* character checked for validity */
|
||||
extern int optreset; /* reset getopt */
|
||||
extern char *optarg; /* argument associated with option */
|
||||
|
||||
#ifndef __P
|
||||
#define __P(x) x
|
||||
#endif
|
||||
#define _DIAGASSERT(x) assert(x)
|
||||
|
||||
static char *__progname __P((char *));
|
||||
|
||||
int getopt_internal __P((int, char *const *, const char *));
|
||||
|
||||
static char *__progname(nargv0)
|
||||
|
||||
char *nargv0;
|
||||
{
|
||||
char *tmp;
|
||||
|
||||
_DIAGASSERT(nargv0 != NULL);
|
||||
|
||||
tmp = strrchr(nargv0, '/');
|
||||
if (tmp)
|
||||
tmp++;
|
||||
else
|
||||
tmp = nargv0;
|
||||
return (tmp);
|
||||
}
|
||||
|
||||
#define BADCH (int)'?'
|
||||
#define BADARG (int)':'
|
||||
#define EMSG ""
|
||||
|
||||
/*
|
||||
* getopt --
|
||||
* Parse argc/argv argument vector.
|
||||
*/
|
||||
int getopt_internal(nargc, nargv, ostr)
|
||||
|
||||
int nargc;
|
||||
char *const *nargv;
|
||||
const char *ostr;
|
||||
{
|
||||
static char *place = EMSG; /* option letter processing */
|
||||
char *oli; /* option letter list index */
|
||||
|
||||
_DIAGASSERT(nargv != NULL);
|
||||
_DIAGASSERT(ostr != NULL);
|
||||
|
||||
if (optreset || !*place) { /* update scanning pointer */
|
||||
optreset = 0;
|
||||
if (optind >= nargc || *(place = nargv[optind]) != '-') {
|
||||
place = EMSG;
|
||||
return (-1);
|
||||
}
|
||||
if (place[1] && *++place == '-') { /* found "--" */
|
||||
/* ++optind; */
|
||||
place = EMSG;
|
||||
return (-2);
|
||||
}
|
||||
} /* option letter okay? */
|
||||
if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) {
|
||||
/*
|
||||
* if the user didn't specify '-' as an option,
|
||||
* assume it means -1.
|
||||
*/
|
||||
if (optopt == (int)'-')
|
||||
return (-1);
|
||||
if (!*place)
|
||||
++optind;
|
||||
if (opterr && *ostr != ':')
|
||||
(void)fprintf(stderr, "%s: illegal option -- %c\n", __progname(nargv[0]),
|
||||
optopt);
|
||||
return (BADCH);
|
||||
}
|
||||
if (*++oli != ':') { /* don't need argument */
|
||||
optarg = NULL;
|
||||
if (!*place)
|
||||
++optind;
|
||||
} else { /* need an argument */
|
||||
if (*place) /* no white space */
|
||||
optarg = place;
|
||||
else if (nargc <= ++optind) { /* no arg */
|
||||
place = EMSG;
|
||||
if ((opterr) && (*ostr != ':'))
|
||||
(void)fprintf(stderr, "%s: option requires an argument -- %c\n",
|
||||
__progname(nargv[0]), optopt);
|
||||
return (BADARG);
|
||||
} else /* white space */
|
||||
optarg = nargv[optind];
|
||||
place = EMSG;
|
||||
++optind;
|
||||
}
|
||||
return (optopt); /* dump back option letter */
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* getopt --
|
||||
* Parse argc/argv argument vector.
|
||||
*/
|
||||
int
|
||||
getopt2(nargc, nargv, ostr)
|
||||
int nargc;
|
||||
char * const *nargv;
|
||||
const char *ostr;
|
||||
{
|
||||
int retval;
|
||||
if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) {
|
||||
retval = -1;
|
||||
++optind;
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* getopt_long --
|
||||
* Parse argc/argv argument vector.
|
||||
*/
|
||||
int getopt_long(nargc, nargv, options, long_options, index) int nargc;
|
||||
char **nargv;
|
||||
const char *options;
|
||||
const struct option *long_options;
|
||||
int *index;
|
||||
{
|
||||
int retval;
|
||||
|
||||
_DIAGASSERT(nargv != NULL);
|
||||
_DIAGASSERT(options != NULL);
|
||||
_DIAGASSERT(long_options != NULL);
|
||||
/* index may be NULL */
|
||||
|
||||
if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
|
||||
char *current_argv = nargv[optind++] + 2, *has_equal;
|
||||
int i, current_argv_len, match = -1;
|
||||
|
||||
if (*current_argv == '\0') {
|
||||
return (-1);
|
||||
}
|
||||
if ((has_equal = strchr(current_argv, '=')) != NULL) {
|
||||
current_argv_len = has_equal - current_argv;
|
||||
has_equal++;
|
||||
} else
|
||||
current_argv_len = strlen(current_argv);
|
||||
|
||||
for (i = 0; long_options[i].name; i++) {
|
||||
if (strncmp(current_argv, long_options[i].name, current_argv_len))
|
||||
continue;
|
||||
|
||||
if (strlen(long_options[i].name) == (unsigned)current_argv_len) {
|
||||
match = i;
|
||||
break;
|
||||
}
|
||||
if (match == -1)
|
||||
match = i;
|
||||
}
|
||||
if (match != -1) {
|
||||
if (long_options[match].has_arg == required_argument ||
|
||||
long_options[match].has_arg == optional_argument) {
|
||||
if (has_equal)
|
||||
optarg = has_equal;
|
||||
else
|
||||
optarg = nargv[optind++];
|
||||
}
|
||||
if ((long_options[match].has_arg == required_argument) &&
|
||||
(optarg == NULL)) {
|
||||
/*
|
||||
* Missing argument, leading :
|
||||
* indicates no error should be generated
|
||||
*/
|
||||
if ((opterr) && (*options != ':'))
|
||||
(void)fprintf(stderr, "%s: option requires an argument -- %s\n",
|
||||
__progname(nargv[0]), current_argv);
|
||||
return (BADARG);
|
||||
}
|
||||
} else { /* No matching argument */
|
||||
if ((opterr) && (*options != ':'))
|
||||
(void)fprintf(stderr, "%s: illegal option -- %s\n",
|
||||
__progname(nargv[0]), current_argv);
|
||||
return (BADCH);
|
||||
}
|
||||
if (long_options[match].flag) {
|
||||
*long_options[match].flag = long_options[match].val;
|
||||
retval = 0;
|
||||
} else
|
||||
retval = long_options[match].val;
|
||||
if (index)
|
||||
*index = match;
|
||||
}
|
||||
return (retval);
|
||||
}
|
||||
#define _GNU_SOURCE
|
||||
#include <stddef.h>
|
||||
#include <getopt/getopt.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern int __optpos, __optreset;
|
||||
|
||||
static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
|
||||
{
|
||||
if (!optind || __optreset) {
|
||||
__optreset = 0;
|
||||
__optpos = 0;
|
||||
optind = 1;
|
||||
}
|
||||
if (optind >= argc || !argv[optind] || argv[optind][0] != '-') return -1;
|
||||
if ((longonly && argv[optind][1]) ||
|
||||
(argv[optind][1] == '-' && argv[optind][2]))
|
||||
{
|
||||
int i;
|
||||
for (i=0; longopts[i].name; i++) {
|
||||
const char *name = longopts[i].name;
|
||||
char *opt = argv[optind]+1;
|
||||
if (*opt == '-') opt++;
|
||||
for (; *name && *name == *opt; name++, opt++);
|
||||
if (*name || (*opt && *opt != '=')) continue;
|
||||
if (*opt == '=') {
|
||||
if (!longopts[i].has_arg) continue;
|
||||
optarg = opt+1;
|
||||
} else {
|
||||
if (longopts[i].has_arg == required_argument) {
|
||||
if (!(optarg = argv[++optind]))
|
||||
return ':';
|
||||
} else optarg = NULL;
|
||||
}
|
||||
optind++;
|
||||
if (idx) *idx = i;
|
||||
if (longopts[i].flag) {
|
||||
*longopts[i].flag = longopts[i].val;
|
||||
return 0;
|
||||
}
|
||||
return longopts[i].val;
|
||||
}
|
||||
if (argv[optind][1] == '-') {
|
||||
optind++;
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
return getopt(argc, argv, optstring);
|
||||
}
|
||||
|
||||
int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
|
||||
{
|
||||
return __getopt_long(argc, argv, optstring, longopts, idx, 0);
|
||||
}
|
||||
|
||||
int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
|
||||
{
|
||||
return __getopt_long(argc, argv, optstring, longopts, idx, 1);
|
||||
}
|
||||
|
||||
Vendored
+74
@@ -0,0 +1,74 @@
|
||||
#ifndef LIBC_H
|
||||
#define LIBC_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
struct __libc {
|
||||
int has_thread_pointer;
|
||||
int can_do_threads;
|
||||
int threaded;
|
||||
int secure;
|
||||
size_t *auxv;
|
||||
volatile int threads_minus_1;
|
||||
FILE *ofl_head;
|
||||
int ofl_lock[2];
|
||||
size_t tls_size;
|
||||
size_t page_size;
|
||||
};
|
||||
|
||||
extern size_t __hwcap;
|
||||
|
||||
#ifndef PAGE_SIZE
|
||||
#define PAGE_SIZE libc.page_size
|
||||
#endif
|
||||
|
||||
#if !defined(__PIC__) || (100*__GNUC__+__GNUC_MINOR__ >= 303 && !defined(__PCC__))
|
||||
|
||||
#ifdef __PIC__
|
||||
#if __GNUC__ < 4
|
||||
#define BROKEN_VISIBILITY 1
|
||||
#endif
|
||||
#define ATTR_LIBC_VISIBILITY __attribute__((visibility("hidden")))
|
||||
#else
|
||||
#define ATTR_LIBC_VISIBILITY
|
||||
#endif
|
||||
|
||||
extern struct __libc __libc ATTR_LIBC_VISIBILITY;
|
||||
#define libc __libc
|
||||
|
||||
#else
|
||||
|
||||
#define USE_LIBC_ACCESSOR
|
||||
#define ATTR_LIBC_VISIBILITY
|
||||
extern struct __libc *__libc_loc(void) __attribute__((const));
|
||||
#define libc (*__libc_loc())
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Designed to avoid any overhead in non-threaded processes */
|
||||
void __lock(volatile int *) ATTR_LIBC_VISIBILITY;
|
||||
void __unlock(volatile int *) ATTR_LIBC_VISIBILITY;
|
||||
int __lockfile(FILE *) ATTR_LIBC_VISIBILITY;
|
||||
void __unlockfile(FILE *) ATTR_LIBC_VISIBILITY;
|
||||
#define LOCK(x) __lock(x)
|
||||
#define UNLOCK(x) __unlock(x)
|
||||
|
||||
void __synccall(void (*)(void *), void *);
|
||||
int __setxid(int, int, int, int);
|
||||
|
||||
extern char **__environ;
|
||||
|
||||
#undef weak_alias
|
||||
#define weak_alias(old, new) \
|
||||
extern __typeof(old) new __attribute__((weak))
|
||||
|
||||
#undef LFS64_2
|
||||
#define LFS64_2(x, y) weak_alias(x, y)
|
||||
|
||||
#undef LFS64
|
||||
#define LFS64(x) LFS64_2(x, x##64)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,4 @@
|
||||
Implementation from musl-1.1.0:
|
||||
https://musl.libc.org/
|
||||
https://musl.libc.org/releases.html
|
||||
|
||||
@@ -850,6 +850,11 @@ static bool processMaskThreshold(MaterialBuilder& builder, const JsonishValue& v
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool processAlphaToCoverage(MaterialBuilder& builder, const JsonishValue& value) {
|
||||
builder.alphaToCoverage(value.toJsonBool()->getBool());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool processShadowMultiplier(MaterialBuilder& builder, const JsonishValue& value) {
|
||||
builder.shadowMultiplier(value.toJsonBool()->getBool());
|
||||
return true;
|
||||
@@ -1070,6 +1075,7 @@ ParametersProcessor::ParametersProcessor() {
|
||||
mParameters["transparency"] = { &processTransparencyMode, Type::STRING };
|
||||
mParameters["reflections"] = { &processReflectionMode, Type::STRING };
|
||||
mParameters["maskThreshold"] = { &processMaskThreshold, Type::NUMBER };
|
||||
mParameters["alphaToCoverage"] = { &processAlphaToCoverage, Type::BOOL };
|
||||
mParameters["shadowMultiplier"] = { &processShadowMultiplier, Type::BOOL };
|
||||
mParameters["transparentShadow"] = { &processTransparentShadow, Type::BOOL };
|
||||
mParameters["shadingModel"] = { &processShading, Type::STRING };
|
||||
|
||||
@@ -523,12 +523,19 @@ if __name__ == "__main__":
|
||||
|
||||
copy_built_file('web/samples/suzanne.html')
|
||||
copy_built_file('web/samples/suzanne.filamesh')
|
||||
|
||||
copy_built_file('web/samples/metallic*.ktx')
|
||||
copy_built_file('web/samples/normal*.ktx')
|
||||
copy_built_file('web/samples/roughness*.ktx')
|
||||
copy_built_file('web/samples/ao*.ktx')
|
||||
copy_built_file('web/samples/albedo*.ktx')
|
||||
|
||||
copy_built_file('web/samples/metallic*.ktx2')
|
||||
copy_built_file('web/samples/normal*.ktx2')
|
||||
copy_built_file('web/samples/roughness*.ktx2')
|
||||
copy_built_file('web/samples/ao*.ktx2')
|
||||
copy_built_file('web/samples/albedo*.ktx2')
|
||||
|
||||
copy_built_file('web/samples/default_env/default_env*.ktx', 'default_env')
|
||||
|
||||
# TODO: We do not normally build the following env maps so we should update the tutorials.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.31.7",
|
||||
"version": "1.32.0",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
@@ -38,7 +38,7 @@ class App {
|
||||
const onDone = () => {
|
||||
loader.delete();
|
||||
scene.addEntities(asset.getEntities());
|
||||
this.animator = asset.getAnimator();
|
||||
this.animator = asset.getInstance().getAnimator();
|
||||
this.animationStartTime = Date.now();
|
||||
};
|
||||
asset.loadResources(onDone);
|
||||
|
||||
Reference in New Issue
Block a user