Compare commits

..
9 Commits
Author SHA1 Message Date
raviola 8e72e67bce Add fgdbg::Session.h, Pass.h, Resource.h dtos/models 2022-11-04 15:43:42 +11:00
raviola a0c486f608 pr feedback 2022-10-21 14:28:59 +11:00
raviola eb7447fd17 fgdbg client project structure + simple server connection 2022-10-20 13:48:48 +11:00
Fernando Raviola a870d01475 Add DebugServer for fgdbg with support for Websockets (#6169)
* Add dummy DebugServer for fgdbg with support for Websockets

* PR feedback
2022-10-20 11:00:13 +11:00
raviola 83e747b732 rename debug.server to debug.matdbg 2022-10-20 11:00:13 +11:00
raviola ca5cc32dc1 Use smart pointer 2022-10-20 11:00:13 +11:00
raviola 5c03e290c2 PR suggestions 2022-10-20 11:00:13 +11:00
Fernando RaviolaandMathias Agopian e4953ada3f Concat namespaces
Co-authored-by: Mathias Agopian <mathias@google.com>
2022-10-20 11:00:13 +11:00
Fernando Raviola 10022f983b Add FrameGraph debugger lib: package structure + CmakeLists.txt 2022-10-20 11:00:13 +11:00
229 changed files with 4255 additions and 8632 deletions
+32 -56
View File
@@ -45,23 +45,18 @@ jobs:
with:
ref: ${{ steps.git_ref.outputs.ref }}
- name: Run build script
env:
TAG: ${{ steps.git_ref.outputs.tag }}
run: |
WORKFLOW_OS=`echo \`uname\` | sed "s/Darwin/mac/" | tr [:upper:] [:lower:]`
cd build/$WORKFLOW_OS && printf "y" | ./build.sh release
cd ../..
- name: Upload release assets
run: |
xargs -L 1 sudo pip3 install < build/common/requirements.txt
if [ -f out/filament-release-darwin.tgz ]; then mv out/filament-release-darwin.tgz out/filament-${TAG}-mac.tgz; fi;
if [ -f out/filament-release-linux.tgz ]; then mv out/filament-release-linux.tgz out/filament-${TAG}-linux.tgz; fi;
- uses: actions/github-script@v6
python3 build/common/upload-assets.py ${TAG} out/*.tgz
env:
TAG: ${{ steps.git_ref.outputs.tag }}
with:
script: |
const upload = require('./build/common/upload-release-assets');
const { TAG } = process.env;
const globber = await glob.create('out/*.tgz');
await upload({ github, context }, await globber.glob(), TAG);
GITHUB_API_KEY: ${{ secrets.GITHUB_API_KEY }}
build-web:
name: build-web
@@ -80,21 +75,16 @@ jobs:
with:
ref: ${{ steps.git_ref.outputs.ref }}
- name: Run build script
env:
TAG: ${{ steps.git_ref.outputs.tag }}
run: |
cd build/web && printf "y" | ./build.sh release
cd ../..
- name: Upload release assets
run: |
xargs -L 1 sudo pip3 install < build/common/requirements.txt
mv out/filament-release-web.tgz out/filament-${TAG}-web.tgz
- uses: actions/github-script@v6
python3 build/common/upload-assets.py ${TAG} out/*.tgz
env:
TAG: ${{ steps.git_ref.outputs.tag }}
with:
script: |
const upload = require('./build/common/upload-release-assets');
const { TAG } = process.env;
const globber = await glob.create('out/*.tgz');
await upload({ github, context }, await globber.glob(), TAG);
GITHUB_API_KEY: ${{ secrets.GITHUB_API_KEY }}
build-android:
name: build-android
@@ -113,16 +103,8 @@ jobs:
with:
ref: ${{ steps.git_ref.outputs.ref }}
- name: Run build script
env:
TAG: ${{ steps.git_ref.outputs.tag }}
run: |
cd build/android && printf "y" | ./build.sh release
cd ../..
mv out/filament-android-release.aar out/filament-${TAG}-android.aar
mv out/filamat-android-release.aar out/filamat-${TAG}-android.aar
mv out/filamat-android-lite-release.aar out/filamat-${TAG}-lite-android.aar
mv out/gltfio-android-release.aar out/gltfio-${TAG}-android.aar
mv out/filament-utils-android-release.aar out/filament-utils-${TAG}-android.aar
- name: Sign sample-gltf-viewer
run: |
echo "${APK_KEYSTORE_BASE64}" > filament.jks.base64
@@ -137,15 +119,18 @@ jobs:
TAG: ${{ steps.git_ref.outputs.tag }}
APK_KEYSTORE_BASE64: ${{ secrets.APK_KEYSTORE_BASE64 }}
APK_KEYSTORE_PASS: ${{ secrets.APK_KEYSTORE_PASS }}
- uses: actions/github-script@v6
- name: Upload release assets
run: |
xargs -L 1 sudo pip3 install < build/common/requirements.txt
mv out/filament-android-release.aar out/filament-${TAG}-android.aar
mv out/filamat-android-release.aar out/filamat-${TAG}-android.aar
mv out/filamat-android-lite-release.aar out/filamat-${TAG}-lite-android.aar
mv out/gltfio-android-release.aar out/gltfio-${TAG}-android.aar
mv out/filament-utils-android-release.aar out/filament-utils-${TAG}-android.aar
python3 build/common/upload-assets.py ${TAG} out/*.aar out/*.apk
env:
TAG: ${{ steps.git_ref.outputs.tag }}
with:
script: |
const upload = require('./build/common/upload-release-assets');
const { TAG } = process.env;
const globber = await glob.create(['out/*.aar', 'out/*.apk'].join('\n'));
await upload({ github, context }, await globber.glob(), TAG);
GITHUB_API_KEY: ${{ secrets.GITHUB_API_KEY }}
build-ios:
name: build-ios
@@ -164,21 +149,16 @@ jobs:
with:
ref: ${{ steps.git_ref.outputs.ref }}
- name: Run build script
env:
TAG: ${{ steps.git_ref.outputs.tag }}
run: |
cd build/ios && printf "y" | ./build.sh release
cd ../..
- name: Upload release assets
run: |
xargs -L 1 sudo pip3 install < build/common/requirements.txt
mv out/filament-release-ios.tgz out/filament-${TAG}-ios.tgz
- uses: actions/github-script@v6
python3 build/common/upload-assets.py ${TAG} out/*.tgz
env:
TAG: ${{ steps.git_ref.outputs.tag }}
with:
script: |
const upload = require('./build/common/upload-release-assets');
const { TAG } = process.env;
const globber = await glob.create('out/*.tgz');
await upload({ github, context }, await globber.glob(), TAG);
GITHUB_API_KEY: ${{ secrets.GITHUB_API_KEY }}
build-windows:
name: build-windows
@@ -198,19 +178,15 @@ jobs:
with:
ref: ${{ steps.git_ref.outputs.ref }}
- name: Run build script
env:
TAG: ${{ steps.git_ref.outputs.tag }}
run: |
build\windows\build-github.bat release
cd ..\..
move out\filament-windows.tgz out\filament-%TAG%-windows.tgz
shell: cmd
- uses: actions/github-script@v6
- name: Upload release assets
run: |
pip3 install PyGithub
mv out/filament-windows.tgz out/filament-${TAG}-windows.tgz
python build/common/upload-assets.py ${TAG} out/*.tgz
shell: bash
env:
TAG: ${{ steps.git_ref.outputs.tag }}
with:
script: |
const upload = require('./build/common/upload-release-assets');
const { TAG } = process.env;
const globber = await glob.create('out/*.tgz');
await upload({ github, context }, await globber.glob(), TAG);
GITHUB_API_KEY: ${{ secrets.GITHUB_API_KEY }}
+25 -22
View File
@@ -74,18 +74,18 @@ if (CCACHE_PROGRAM)
configure_file(build/launch-cxx.in launch-cxx)
execute_process(COMMAND chmod a+rx
"${CMAKE_CURRENT_BINARY_DIR}/launch-c"
"${CMAKE_CURRENT_BINARY_DIR}/launch-cxx"
"${CMAKE_BINARY_DIR}/launch-c"
"${CMAKE_BINARY_DIR}/launch-cxx"
)
if (CMAKE_GENERATOR STREQUAL "Xcode")
set(CMAKE_XCODE_ATTRIBUTE_CC "${CMAKE_CURRENT_BINARY_DIR}/launch-c")
set(CMAKE_XCODE_ATTRIBUTE_CXX "${CMAKE_CURRENT_BINARY_DIR}/launch-cxx")
set(CMAKE_XCODE_ATTRIBUTE_LD "${CMAKE_CURRENT_BINARY_DIR}/launch-c")
set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS "${CMAKE_CURRENT_BINARY_DIR}/launch-cxx")
set(CMAKE_XCODE_ATTRIBUTE_CC "${CMAKE_BINARY_DIR}/launch-c")
set(CMAKE_XCODE_ATTRIBUTE_CXX "${CMAKE_BINARY_DIR}/launch-cxx")
set(CMAKE_XCODE_ATTRIBUTE_LD "${CMAKE_BINARY_DIR}/launch-c")
set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS "${CMAKE_BINARY_DIR}/launch-cxx")
else()
set(CMAKE_C_COMPILER_LAUNCHER "${CMAKE_CURRENT_BINARY_DIR}/launch-c")
set(CMAKE_CXX_COMPILER_LAUNCHER "${CMAKE_CURRENT_BINARY_DIR}/launch-cxx")
set(CMAKE_C_COMPILER_LAUNCHER "${CMAKE_BINARY_DIR}/launch-c")
set(CMAKE_CXX_COMPILER_LAUNCHER "${CMAKE_BINARY_DIR}/launch-cxx")
endif()
endif()
@@ -99,10 +99,6 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# ==================================================================================================
if (UNIX AND NOT APPLE AND NOT ANDROID AND NOT WEBGL)
set(LINUX TRUE)
else()
# since cmake 3.25 LINUX is automatically set based on CMAKE_SYSTEM_NAME, which the android
# cmake files are setting to "Linux".
set(LINUX FALSE)
endif()
if (LINUX)
@@ -341,23 +337,19 @@ endif()
# ==================================================================================================
# Release compiler flags
# ==================================================================================================
if (NOT MSVC AND NOT IOS)
# Omitting stack frame pointers prevents the generation of readable stack traces in crash reports on iOS
if (NOT MSVC)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fomit-frame-pointer")
# These aren't compatible with -fembed-bitcode (and seem to have no effect on Apple platforms anyway)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffunction-sections -fdata-sections")
if (NOT IOS)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffunction-sections -fdata-sections")
endif()
endif()
# On Android RELEASE builds, we disable exceptions and RTTI to save some space (about 75 KiB
# saved by -fno-exception and 10 KiB saved by -fno-rtti).
if (ANDROID OR IOS OR WEBGL)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-exceptions -fno-rtti")
if (ANDROID OR WEBGL)
# Omitting unwind info prevents the generation of readable stack traces in crash reports on iOS
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-unwind-tables -fno-asynchronous-unwind-tables")
endif()
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti")
endif()
# With WebGL, we disable RTTI even for debug builds because we pass emscripten::val back and forth
@@ -467,6 +459,13 @@ else()
option(FILAMENT_ENABLE_MATDBG "Enable the material debugger" OFF)
endif()
# By default, link in fgdbg for Desktop + Debug
if (CMAKE_BUILD_TYPE STREQUAL "Debug" AND IS_HOST_PLATFORM)
option(FILAMENT_ENABLE_FGDBG "Enable the framegraph debugger" ON)
else()
option(FILAMENT_ENABLE_FGDBG "Enable the framegraph debugger" OFF)
endif()
# Only optimize materials in Release mode (so error message lines match the source code)
if (CMAKE_BUILD_TYPE MATCHES Release)
option(FILAMENT_DISABLE_MATOPT "Disable material optimizations" OFF)
@@ -554,7 +553,7 @@ function(list_licenses OUTPUT MODULES)
endif()
endforeach()
configure_file(${FILAMENT}/build/licenses.inc.in ${OUTPUT})
endfunction()
endfunction(list_licenses)
set(COMBINE_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/build/linux/combine-static-libs.sh")
if (WIN32)
@@ -693,6 +692,10 @@ if (FILAMENT_BUILD_FILAMAT OR IS_HOST_PLATFORM)
if (FILAMENT_ENABLE_MATDBG OR IS_HOST_PLATFORM)
add_subdirectory(${LIBRARIES}/matdbg)
endif()
if (FILAMENT_ENABLE_FGDBG OR IS_HOST_PLATFORM)
add_subdirectory(${LIBRARIES}/fgdbg)
endif()
endif()
if (FILAMENT_SUPPORTS_VULKAN)
+5 -4
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.31.0'
implementation 'com.google.android.filament:filament-android:1.28.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.0'
pod 'Filament', '~> 1.28.0'
```
### Snapshots
@@ -117,9 +117,9 @@ steps:
- Image-based lighting
- Physically-based camera (shutter speed, sensitivity and aperture)
- Physical light units
- Point lights, spot lights, and directional light
- Point lights, spot lights and directional light
- Specular anti-aliasing
- Point, spot, and directional light shadows
- Spot and directional light shadows
- Cascaded shadows
- EVSM, PCSS, DPCF, or PCF shadows
- Transparent shadows
@@ -313,6 +313,7 @@ and tools.
- `bluegl`: OpenGL bindings for macOS, Linux and Windows
- `bluevk`: Vulkan bindings for macOS, Linux, Windows and Android
- `camutils`: Camera manipulation utilities
- `fgdbg`: Frame Graph inspector and debugger (debug builds only)
- `filabridge`: Library shared by the Filament engine and host tools
- `filaflat`: Serialization/deserialization library used for materials
- `filagui`: Helper library for [Dear ImGui](https://github.com/ocornut/imgui)
-35
View File
@@ -5,41 +5,6 @@ A new header is inserted each time a *tag* is created.
## main branch
## v1.31.0
- java: fix confusing typo in Camera documentation
- engine: the output color space can be set on `ColorGrading`. This API currently has limitations,
please refer to the documentation for more details
- Support for RGTC and BPTC texture compression
- engine: fix TransformManager high precision mode when using transactions
- web: added TypeScript definition for `Engine.destroy`
- materials: `getNormalizedViewportCoord()` now returns the logical (i.e. user) viewport
normalized position and keeps z reversed [⚠️ **Recompile Materials**]
- backend: workaround Adreno shader compiler bug (#6355) [⚠️ **Recompile Materials**]
- geometry: change computing tangent basis from normal vector to use Frisvad's method
## v1.30.0
- engine: optimize per-shadow UBO [⚠️ **Recompile Materials**]
- engine: fix potential memory corruption with larger scenes
- engine: VSM's MSAA setting is now per-view instead of per-light [⚠️ **API Change**]
## v1.29.0
- gltfio: calculate primitive's AABB correctly.
- gltfio: recompute bounding boxes with morph targets
- engine: add missing getters on `MaterialInstance`
- WebGL: add missing `ColorGrading` JS bindings
- engine: improvements/cleanup of Shadow mapping code [⚠️ **Recompile Materials**]
## v1.28.3
- backend: add support for GGP platform
- engine: primitives with `CullingMode::FRONT_AND_BACK` are now skipped.
## v1.28.2
- gltfio: support EXT_meshopt_compression
- release packaging: fixed location of default IBL file
@@ -79,7 +79,7 @@ Java_com_google_android_filament_LightManager_nBuilderShadowOptions(JNIEnv* env,
jfloat shadowFarHint, jboolean stable, jboolean lispsm,
jfloat polygonOffsetConstant, jfloat polygonOffsetSlope,
jboolean screenSpaceContactShadows, jint stepCount,
jfloat maxShadowDistance, jboolean elvsm, jfloat blurWidth, jfloat shadowBulbRadius) {
jfloat maxShadowDistance, jint vsmMsaaSamples, jboolean elvsm, jfloat blurWidth, jfloat shadowBulbRadius) {
LightManager::Builder *builder = (LightManager::Builder *) nativeBuilder;
LightManager::ShadowOptions shadowOptions {
.mapSize = (uint32_t)mapSize,
@@ -97,6 +97,7 @@ Java_com_google_android_filament_LightManager_nBuilderShadowOptions(JNIEnv* env,
.stepCount = uint8_t(stepCount),
.maxShadowDistance = maxShadowDistance,
.vsm = {
.msaaSamples = (uint8_t) vsmMsaaSamples,
.elvsm = (bool)elvsm,
.blurWidth = blurWidth
},
@@ -452,84 +452,3 @@ Java_com_google_android_filament_MaterialInstance_nDuplicate(JNIEnv* env, jclass
}
return (jlong)mi;
}
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();
}
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();
}
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();
}
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();
}
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();
}
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();
}
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();
}
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();
}
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();
}
@@ -365,7 +365,7 @@ public class Camera {
* By default, this is an identity matrix.
* </p>
*
* @param inScaling diagonal of the scaling matrix to be applied after the projection matrix.
* @param scaling diagonal of the scaling matrix to be applied after the projection matrix.
*
* @see Camera#setProjection
* @see Camera#setLensProjection
@@ -409,7 +409,7 @@ public class Camera {
*
* <pre>
* engine.getTransformManager().setTransform(
* engine.getTransformManager().getInstance(camera->getEntity()), modelMatrix);
* engine.getTransformManager().getInstance(camera->getEntity()), viewMatrix);
* </pre>
*
* @param modelMatrix The camera position and orientation provided as a <b>rigid transform</b> matrix.
@@ -349,6 +349,20 @@ public class LightManager {
* @see View#setShadowType
*/
/**
* The number of MSAA samples to use when rendering VSM shadow maps.
* Must be a power-of-two and greater than or equal to 1. A value of 1 effectively turns
* off MSAA.
* Higher values may not be available depending on the underlying hardware.
*
* <p>
* <strong>Warning: This API is still experimental and subject to change.</strong>
* </p>
*/
@IntRange(from = 1)
public int vsmMsaaSamples = 1;
/**
* When elvsm is set to true, "Exponential Layered VSM without Layers" are used. It is
* an improvement to the default EVSM which suffers important light leaks. Enabling
@@ -505,7 +519,7 @@ public class LightManager {
options.shadowFarHint, options.stable, options.lispsm,
options.polygonOffsetConstant, options.polygonOffsetSlope,
options.screenSpaceContactShadows,
options.stepCount, options.maxShadowDistance,
options.stepCount, options.maxShadowDistance, options.vsmMsaaSamples,
options.elvsm, options.blurWidth, options.shadowBulbRadius);
return this;
}
@@ -1004,6 +1018,8 @@ public class LightManager {
* lightbulbs.
*
* @param efficiency Efficiency in percent. This depends on the type of lightbulb used.
*
* @return This Builder, for chaining calls.
*/
public void setIntensity(@EntityInstance int i, float watts, float efficiency) {
nSetIntensity(mNativeObject, i , watts, efficiency);
@@ -1169,7 +1185,7 @@ public class LightManager {
boolean stable, boolean lispsm,
float polygonOffsetConstant, float polygonOffsetSlope,
boolean screenSpaceContactShadows, int stepCount, float maxShadowDistance,
boolean elvsm, float blurWidth, float shadowBulbRadius);
int vsmMsaaSamples, boolean elvsm, float blurWidth, float shadowBulbRadius);
private static native void nBuilderCastLight(long nativeBuilder, boolean enabled);
private static native void nBuilderPosition(long nativeBuilder, float x, float y, float z);
private static native void nBuilderDirection(long nativeBuilder, float x, float y, float z);
@@ -24,7 +24,6 @@ import com.google.android.filament.proguard.UsedByNative;
@UsedByNative("AssetLoader.cpp")
public class MaterialInstance {
private static final Material.CullingMode[] sCullingModeValues = Material.CullingMode.values();
private Material mMaterial;
private String mName;
private long mNativeObject;
@@ -474,14 +473,6 @@ public class MaterialInstance {
nSetMaskThreshold(getNativeObject(), threshold);
}
/**
* Gets the minimum alpha value a fragment must have to not be discarded when the blend
* mode is MASKED
*/
public float getMaskThreshold() {
return nGetMaskThreshold(getNativeObject());
}
/**
* Sets the screen space variance of the filter kernel used when applying specular
* anti-aliasing. The default value is set to 0.15. The specified value should be between
@@ -495,14 +486,6 @@ public class MaterialInstance {
nSetSpecularAntiAliasingVariance(getNativeObject(), variance);
}
/**
* Gets the screen space variance of the filter kernel used when applying specular
* anti-aliasing.
*/
public float getSpecularAntiAliasingVariance() {
return nGetSpecularAntiAliasingVariance(getNativeObject());
}
/**
* Sets the clamping threshold used to suppress estimation errors when applying specular
* anti-aliasing. The default value is set to 0.2. The specified value should be between 0
@@ -516,14 +499,6 @@ public class MaterialInstance {
nSetSpecularAntiAliasingThreshold(getNativeObject(), threshold);
}
/**
* Gets the clamping threshold used to suppress estimation errors when applying specular
* anti-aliasing.
*/
public float getSpecularAntiAliasingThreshold() {
return nGetSpecularAntiAliasingThreshold(getNativeObject());
}
/**
* Enables or disables double-sided lighting if the parent Material has double-sided capability,
* otherwise prints a warning. If double-sided lighting is enabled, backface culling is
@@ -537,14 +512,6 @@ public class MaterialInstance {
nSetDoubleSided(getNativeObject(), doubleSided);
}
/**
* Returns whether double-sided lighting is enabled when the parent Material has double-sided
* capability.
*/
public boolean isDoubleSided() {
return nIsDoubleSided(getNativeObject());
}
/**
* Overrides the default triangle culling state that was set on the material.
*
@@ -552,18 +519,10 @@ public class MaterialInstance {
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:culling">
* Rasterization: culling</a>
*/
public void setCullingMode(@NonNull Material.CullingMode mode) {
public void setCullingMode(Material.CullingMode mode) {
nSetCullingMode(getNativeObject(), mode.ordinal());
}
/**
* Returns the face culling mode.
*/
@NonNull
public Material.CullingMode getCullingMode() {
return sCullingModeValues[nGetCullingMode(getNativeObject())];
}
/**
* Overrides the default color-buffer write state that was set on the material.
*
@@ -575,13 +534,6 @@ public class MaterialInstance {
nSetColorWrite(getNativeObject(), enable);
}
/**
* Returns whether color write is enabled.
*/
public boolean isColorWriteEnabled() {
return nIsColorWriteEnabled(getNativeObject());
}
/**
* Overrides the default depth-buffer write state that was set on the material.
*
@@ -593,27 +545,10 @@ public class MaterialInstance {
nSetDepthWrite(getNativeObject(), enable);
}
/**
* Returns whether depth write is enabled.
*/
public boolean isDepthWriteEnabled() {
return nIsDepthWriteEnabled(getNativeObject());
}
/**
* Enables or Disable stencil writes
*/
public void setStencilWrite(boolean enable) {
nSetStencilWrite(getNativeObject(), enable);
}
/**
* Returns whether stencil write is enabled.
*/
public boolean isStencilWriteEnabled() {
return nIsStencilWriteEnabled(getNativeObject());
}
/**
* Overrides the default depth testing state that was set on the material.
*
@@ -625,13 +560,6 @@ public class MaterialInstance {
nSetDepthCulling(getNativeObject(), enable);
}
/**
* Returns whether depth culling is enabled.
*/
public boolean isDepthCullingEnabled() {
return nIsDepthCullingEnabled(getNativeObject());
}
/**
* Sets the stencil comparison function (default is {@link TextureSampler.CompareFunction#ALWAYS}).
*
@@ -928,15 +856,4 @@ public class MaterialInstance {
private static native long nGetMaterial(long nativeMaterialInstance);
private static native long nDuplicate(long otherNativeMaterialInstance, String name);
private static native float nGetMaskThreshold(long nativeMaterialInstance);
private static native float nGetSpecularAntiAliasingVariance(long nativeMaterialInstance);
private static native float nGetSpecularAntiAliasingThreshold(long nativeMaterialInstance);
private static native boolean nIsDoubleSided(long nativeMaterialInstance);
private static native int nGetCullingMode(long nativeMaterialInstance);
private static native boolean nIsColorWriteEnabled(long nativeMaterialInstance);
private static native boolean nIsDepthWriteEnabled(long nativeMaterialInstance);
private static native boolean nIsStencilWriteEnabled(long nativeMaterialInstance);
private static native boolean nIsDepthCullingEnabled(long nativeMaterialInstance);
}
@@ -124,24 +124,7 @@ public class Renderer {
*/
public static class ClearOptions {
/**
* Color (sRGB linear) to use to clear the RenderTarget (typically the SwapChain).
*
* The RenderTarget is cleared using this color, which won't be tone-mapped since
* tone-mapping is part of View rendering (this is not).
*
* When a View is rendered, there are 3 scenarios to consider:
* - Pixels rendered by the View replace the clear color (or blend with it in
* `BlendMode.TRANSLUCENT` mode).
*
* - With blending mode set to `BlendMode.TRANSLUCENT`, Pixels untouched by the View
* are considered fulling transparent and let the clear color show through.
*
* - With blending mode set to `BlendMode.OPAQUE`, Pixels untouched by the View
* are set to the clear color. However, because it is now used in the context of a View,
* it will go through the post-processing stage, which includes tone-mapping.
*
* For consistency, it is recommended to always use a Skybox to clear an opaque View's
* background, or to use black or fully-transparent (i.e. {0,0,0,0}) as the clear color.
* Color to use to clear the SwapChain
*/
@NonNull
public float[] clearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
@@ -250,19 +250,7 @@ public class Texture {
SRGB8_ALPHA8_ASTC_10x8,
SRGB8_ALPHA8_ASTC_10x10,
SRGB8_ALPHA8_ASTC_12x10,
SRGB8_ALPHA8_ASTC_12x12,
// RGTC formats available with a GLES extension
RED_RGTC1, // BC4 unsigned
SIGNED_RED_RGTC1, // BC4 signed
RED_GREEN_RGTC2, // BC5 unsigned
SIGNED_RED_GREEN_RGTC2, // BC5 signed
// BPTC formats available with a GLES extension
RGB_BPTC_SIGNED_FLOAT, // BC6H signed
RGB_BPTC_UNSIGNED_FLOAT,// BC6H unsigned
RGBA_BPTC_UNORM, // BC7
SRGB_ALPHA_BPTC_UNORM // BC7 sRGB
SRGB8_ALPHA8_ASTC_12x12
}
/**
@@ -308,19 +296,7 @@ public class Texture {
SRGB8_ALPHA8_ASTC_10x8,
SRGB8_ALPHA8_ASTC_10x10,
SRGB8_ALPHA8_ASTC_12x10,
SRGB8_ALPHA8_ASTC_12x12,
// RGTC formats available with a GLES extension
RED_RGTC1, // BC4 unsigned
SIGNED_RED_RGTC1, // BC4 signed
RED_GREEN_RGTC2, // BC5 unsigned
SIGNED_RED_GREEN_RGTC2, // BC5 signed
// BPTC formats available with a GLES extension
RGB_BPTC_SIGNED_FLOAT, // BC6H signed
RGB_BPTC_UNSIGNED_FLOAT,// BC6H unsigned
RGBA_BPTC_UNORM, // BC7
SRGB_ALPHA_BPTC_UNORM // BC7 sRGB
SRGB8_ALPHA8_ASTC_12x12
}
/**
@@ -1817,13 +1817,6 @@ public class View {
* Whether to generate mipmaps for all VSM shadow maps.
*/
public boolean mipmapping = false;
/**
* The number of MSAA samples to use when rendering VSM shadow maps.
* Must be a power-of-two and greater than or equal to 1. A value of 1 effectively turns
* off MSAA.
* Higher values may not be available depending on the underlying hardware.
*/
public int msaaSamples = 1;
/**
* Whether to use a 32-bits or 16-bits texture format for VSM shadow maps. 32-bits
* precision is rarely needed, but it does reduces light leaks as well as "fading"
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.31.0
VERSION_NAME=1.28.0
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
@@ -27,7 +27,6 @@ import android.view.animation.LinearInterpolator
import com.google.android.filament.*
import com.google.android.filament.RenderableManager.*
import com.google.android.filament.Renderer.ClearOptions
import com.google.android.filament.VertexBuffer.*
import com.google.android.filament.android.DisplayHelper
import com.google.android.filament.android.UiHelper
@@ -65,6 +64,7 @@ class MainActivity : Activity() {
private lateinit var view0: View
private lateinit var view1: View
private lateinit var view2: View
private lateinit var view3: View
private lateinit var view4: View
// We need skybox to set the background color
private lateinit var skybox: Skybox
@@ -119,19 +119,15 @@ class MainActivity : Activity() {
view0 = engine.createView()
view1 = engine.createView()
view2 = engine.createView()
view3 = engine.createView()
view4 = engine.createView()
view0.setName("view0");
view1.setName("view1");
view2.setName("view2");
view3.setName("view3");
view4.setName("view4");
// Useful for debugging issues
// view0.isPostProcessingEnabled = false
// view1.isPostProcessingEnabled = false
// view2.isPostProcessingEnabled = false
// view4.isPostProcessingEnabled = false
view4.blendMode = View.BlendMode.TRANSLUCENT;
skybox = Skybox.Builder().build(engine);
@@ -144,11 +140,13 @@ class MainActivity : Activity() {
view0.camera = camera
view1.camera = camera
view2.camera = camera
view3.camera = camera
view4.camera = camera
view0.scene = scene
view1.scene = scene
view2.scene = scene
view3.scene = scene
view4.scene = scene
}
@@ -381,6 +379,7 @@ class MainActivity : Activity() {
engine.destroyView(view0)
engine.destroyView(view1)
engine.destroyView(view2)
engine.destroyView(view3)
engine.destroyView(view4)
engine.destroySkybox(skybox)
engine.destroyScene(scene)
@@ -408,18 +407,19 @@ class MainActivity : Activity() {
// If beginFrame() returns false you should skip the frame
// This means you are sending frames too quickly to the GPU
if (renderer.beginFrame(swapChain!!, frameTimeNanos)) {
scene.skybox = skybox
skybox.setColor(0.35f, 0.35f, 0.35f, 1.0f);
skybox.setColor(0.035f, 0.035f, 0.035f, 1.0f);
renderer.render(view0)
skybox.setColor(1.0f, 1.0f, 0.0f, 1.0f);
skybox.setColor(1.0f, 0.0f, 0.0f, 1.0f);
renderer.render(view1)
scene.skybox = null
skybox.setColor(0.0f, 1.0f, 0.0f, 1.0f);
renderer.render(view2)
skybox.setColor(0.0f, 0.0f, 1.0f, 1.0f);
renderer.render(view3)
skybox.setColor(0.0f, 0.0f, 0.0f, 0.0f);
renderer.render(view4)
renderer.endFrame()
@@ -433,10 +433,6 @@ class MainActivity : Activity() {
swapChain?.let { engine.destroySwapChain(it) }
swapChain = engine.createSwapChain(surface)
renderer.setDisplayInfo(DisplayHelper.getDisplayInfo(surfaceView.display, Renderer.DisplayInfo()))
renderer.clearOptions = renderer.clearOptions.apply {
clear = true
clearColor = floatArrayOf( 0.0f, 0.0f, 1.0f, 0.0f )
}
}
override fun onDetachedFromSurface() {
@@ -457,6 +453,7 @@ class MainActivity : Activity() {
view0.viewport = Viewport(0, 0, width / 2, height / 2)
view1.viewport = Viewport(width / 2, 0, width / 2, height / 2)
view2.viewport = Viewport(0, height / 2, width / 2, height / 2)
view3.viewport = Viewport(width / 2, height / 2, width / 2, height / 2)
view4.viewport = Viewport(width / 4, height / 4, width / 2, height / 2)
}
}
+6
View File
@@ -162,6 +162,8 @@ EGL_ON_LINUX_OPTION="-DFILAMENT_SUPPORTS_EGL_ON_LINUX=OFF"
MATDBG_OPTION="-DFILAMENT_ENABLE_MATDBG=OFF"
MATDBG_GRADLE_OPTION=""
FGDBG_OPTION="-DFILAMENT_ENABLE_FGDBG=OFF"
IOS_BUILD_SIMULATOR=false
BUILD_UNIVERSAL_LIBRARIES=false
@@ -221,6 +223,7 @@ function build_desktop_target {
${SWIFTSHADER_OPTION} \
${EGL_ON_LINUX_OPTION} \
${MATDBG_OPTION} \
${FGDBG_OPTION} \
${deployment_target} \
${architectures} \
../..
@@ -347,6 +350,7 @@ function build_android_target {
-DCMAKE_INSTALL_PREFIX="../android-${lc_target}/filament" \
-DCMAKE_TOOLCHAIN_FILE="../../build/toolchain-${arch}-linux-android.cmake" \
${MATDBG_OPTION} \
${FGDBG_OPTION} \
${VULKAN_ANDROID_OPTION} \
../..
fi
@@ -576,6 +580,7 @@ function build_ios_target {
-DIOS=1 \
-DCMAKE_TOOLCHAIN_FILE=../../third_party/clang/iOS.cmake \
${MATDBG_OPTION} \
${FGDBG_OPTION} \
../..
fi
@@ -760,6 +765,7 @@ while getopts ":hacCfijmp:q:uvslwtedk:" opt; do
PRINT_MATDBG_HELP=true
MATDBG_OPTION="-DFILAMENT_ENABLE_MATDBG=ON, -DFILAMENT_DISABLE_MATOPT=ON, -DFILAMENT_BUILD_FILAMAT=ON"
MATDBG_GRADLE_OPTION="-Pcom.google.android.filament.matdbg"
FGDBG_OPTION="-DFILAMENT_ENABLE_FGDBG=ON"
;;
f)
ISSUE_CMAKE_ALWAYS=true
-99
View File
@@ -1,99 +0,0 @@
#!/usr/bin/env bash
set -e
function print_help {
local self_name=$(basename "$0")
echo "This tool verifies that every Metal shader in the given Filament material file(s) successfully compiles."
echo "Requires the matinfo tool and xcrun to be on the system PATH."
echo ""
echo "Usage:"
echo " $self_name [options] [<material> ...]"
echo ""
echo "Options:"
echo " -h"
echo " Print this help message."
echo " -w"
echo " Pass the -w flag to the Metal compiler, to disable warnings."
echo ""
}
COMP_FLAGS=""
while getopts ":hw" opt; do
case ${opt} in
h)
print_help
exit 1
;;
w)
COMP_FLAGS="${COMP_FLAGS} -w"
;;
esac
done
shift $((OPTIND - 1))
if [[ "$#" == "0" ]]; then
print_help
exit 1
fi
# Make sure matinfo and xcrun are available.
if [[ ! $(command -v matinfo) ]]; then
echo "Error: matinfo not on PATH."
exit 1
fi
if [[ ! $(command -v xcrun) ]]; then
echo "Error: xcrun not on PATH."
exit 1
fi
function check_material {
local material="$1"
tmpdir="$(mktemp -d /tmp/check_metal_shaders.XXXXX)"
# First check that the material is valid.
if [[ ! $(matinfo "${material}") ]]; then
echo "Invalid material file: ${material}"
exit 1
fi
echo "Checking that Metal shaders compile: ${material}"
set +e
local i=0
while true; do
# The file must have a .metal extension.
metalFile="${tmpdir}/${i}.metal"
# Extract shader i. matinfo will return a non-zero exit code if the shader doesn't exist,
# which means we're finished with this material.
matinfo --print-metal=${i} "${material}" > "${metalFile}" 2> /dev/null
if [[ "$?" -ne 0 ]]; then
break
fi
echo "Testing Metal shader ${i}"
# Attempt to compile the Metal shader.
xcrun -sdk macosx metal ${COMP_FLAGS} -c "${metalFile}" -o /dev/null
if [[ "$?" -ne 0 ]]; then
echo "Error compiling Metal shader: ${metalFile}"
exit 1
fi
((i++))
done
set -e
rm -r "${tmpdir}"
}
for material in "$@"
do
check_material "${material}"
done
+14
View File
@@ -0,0 +1,14 @@
setuptools==40.6.2
wheel==0.37.1
certifi==2021.10.8
cffi==1.15.0
charset-normalizer==2.0.12
Deprecated==1.2.13
idna==3.3
pycparser==2.21
PyGithub==1.55
PyJWT==2.4.0
PyNaCl==1.5.0
requests==2.27.1
urllib3==1.26.9
wrapt==1.14.0
+93
View File
@@ -0,0 +1,93 @@
# Copyright (C) 2019 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.
# requirements.txt created via:
#
# pip3 install virtualenv
# python3 -m venv env
# pip3 install PyGithub
# pip3 install wheel
# --all includes wheel and setuputils, which is needed for GitHub Actions
# pip3 freeze --all > requirements.txt
# Manually move 'setuptools' and 'wheel' lines to the beginning of the file.
# Manually remove the 'pip' line.
#
# Requirements are installed in GitHub Actions via:
# xargs -L 1 sudo pip3 install < build/common/requirements.txt
# xargs must be used because the ordering of the dependencies matters (namely, setuptools).
# sudo must be used to uninstall non-matching versions of packages.
# pip is removed to avoid conflicts with the pre-installed pip version on Actions.
# This technique does not work with Windows, unfortunately.
from github import Github
import os, sys
def print_usage():
print('Upload assets to a Filament GitHub release.')
print()
print('Usage:')
print(' upload-assets.py <tag> <asset>...')
print()
print('Notes:')
print(' The GitHub release must already be created prior to running this script. This is typically done')
print(' through the GitHub web UI.')
print()
print(' <tag> is the Git tag for the desired release to attach assets to, for example, "v1.4.2".')
print()
print(' <asset> is a path to the asset file to upload. The file name will be used as the name of the')
print(' asset.')
print()
print(' The GITHUB_API_KEY environment variable must be set to a valid authentication token for a')
print(' collaborator account of the Filament repository.')
# The first argument is the path to this script.
if len(sys.argv) < 3:
print_usage()
sys.exit(1)
tag = sys.argv[1]
assets = sys.argv[2:]
authentication_token = os.environ.get('GITHUB_API_KEY')
if not authentication_token:
sys.stderr.write('Error: the GITHUB_API_KEY is not set.\n')
sys.exit(1)
g = Github(authentication_token)
FILAMENT_REPO = "google/filament"
filament = g.get_repo(FILAMENT_REPO)
def find_release_from_tag(repo, tag):
""" Find a release in the repo for the given Git tag string. """
releases = repo.get_releases()
for r in releases:
if r.tag_name == tag:
return r
return None
release = find_release_from_tag(filament, tag)
if not release:
sys.stderr.write(f"Error: Could not find release with tag '{tag}'.\n")
sys.exit(1)
print(f"Found release with tag '{tag}'.")
for asset_path in assets:
sys.stdout.write(f'Uploding asset: {asset_path}... ')
asset_name = os.path.basename(asset_path)
asset = release.upload_asset(asset_path, name=asset_name)
if asset:
sys.stdout.write('Success!\n')
@@ -1,78 +0,0 @@
/*
* Copyright (C) 2022 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.
*/
const uploadReleaseAssets = async ({github, context}, assetPathsToUpload, releaseTag) => {
const fs = require('fs/promises');
const path = require('path');
const filesToUpload = assetPathsToUpload.map(assetPath => ({
buffer: fs.readFile(assetPath),
assetName: path.basename(assetPath)
}));
const findReleaseMatchingTag = async tag => {
const { data: releases } = await github.rest.repos.listReleases(context.repo);
const release = releases.find(release => release.tag_name === releaseTag);
if (!release) {
throw new Error(`Could not locate release with tag '${releaseTag}'`);
}
return release;
};
const release = await findReleaseMatchingTag(releaseTag);
console.log(`Found release named '${release.name}' matching tag '${release.tag_name}'.`);
const uploadPromises = [];
for (const file of filesToUpload) {
console.log(`Uploading asset ${file.assetName}.`);
const p = github.rest.repos.uploadReleaseAsset({
...context.repo,
release_id: release.id,
name: file.assetName,
data: await file.buffer
});
uploadPromises.push(p);
}
await Promise.all(uploadPromises);
console.log("Done!");
}
module.exports = uploadReleaseAssets;
////////////////////////////////////////////////////////////////////////////////////////////////////
// To test this script locally, uncomment the code below and run:
//
// npm install
// node index.js
// const { Octokit } = require("@octokit/rest");
// const glob = require("@actions/glob");
// (async () => {
// const github = new Octokit({
// auth: "" // <-- paste GitHub auth token here
// });
// const context = {
// repo: {
// owner: "bejado",
// repo: "filament",
// },
// };
// const globber = await glob.create('*.txt');
// await uploadReleaseAssets({ github, context }, await globber.glob(), 'vtest-28');
// })();
-546
View File
@@ -1,546 +0,0 @@
{
"name": "upload-release-assets",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"version": "1.0.0",
"license": "Apache-2.0",
"dependencies": {
"@actions/glob": "^0.3.0",
"@octokit/rest": "^19.0.5"
}
},
"node_modules/@actions/core": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz",
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
"dependencies": {
"@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
}
},
"node_modules/@actions/glob": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.3.0.tgz",
"integrity": "sha512-tJP1ZhF87fd6LBnaXWlahkyvdgvsLl7WnreW1EZaC8JWjpMXmzqWzQVe/IEYslrkT9ymibVrKyJN4UMD7uQM2w==",
"dependencies": {
"@actions/core": "^1.2.6",
"minimatch": "^3.0.4"
}
},
"node_modules/@actions/http-client": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"dependencies": {
"tunnel": "^0.0.6"
}
},
"node_modules/@octokit/auth-token": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.2.tgz",
"integrity": "sha512-pq7CwIMV1kmzkFTimdwjAINCXKTajZErLB4wMLYapR2nuB/Jpr66+05wOTZMSCBXP6n4DdDWT2W19Bm17vU69Q==",
"dependencies": {
"@octokit/types": "^8.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/core": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.1.0.tgz",
"integrity": "sha512-Czz/59VefU+kKDy+ZfDwtOIYIkFjExOKf+HA92aiTZJ6EfWpFzYQWw0l54ji8bVmyhc+mGaLUbSUmXazG7z5OQ==",
"dependencies": {
"@octokit/auth-token": "^3.0.0",
"@octokit/graphql": "^5.0.0",
"@octokit/request": "^6.0.0",
"@octokit/request-error": "^3.0.0",
"@octokit/types": "^8.0.0",
"before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/endpoint": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.3.tgz",
"integrity": "sha512-57gRlb28bwTsdNXq+O3JTQ7ERmBTuik9+LelgcLIVfYwf235VHbN9QNo4kXExtp/h8T423cR5iJThKtFYxC7Lw==",
"dependencies": {
"@octokit/types": "^8.0.0",
"is-plain-object": "^5.0.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/graphql": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.4.tgz",
"integrity": "sha512-amO1M5QUQgYQo09aStR/XO7KAl13xpigcy/kI8/N1PnZYSS69fgte+xA4+c2DISKqUZfsh0wwjc2FaCt99L41A==",
"dependencies": {
"@octokit/request": "^6.0.0",
"@octokit/types": "^8.0.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/openapi-types": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-14.0.0.tgz",
"integrity": "sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw=="
},
"node_modules/@octokit/plugin-paginate-rest": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-5.0.1.tgz",
"integrity": "sha512-7A+rEkS70pH36Z6JivSlR7Zqepz3KVucEFVDnSrgHXzG7WLAzYwcHZbKdfTXHwuTHbkT1vKvz7dHl1+HNf6Qyw==",
"dependencies": {
"@octokit/types": "^8.0.0"
},
"engines": {
"node": ">= 14"
},
"peerDependencies": {
"@octokit/core": ">=4"
}
},
"node_modules/@octokit/plugin-request-log": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
"integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==",
"peerDependencies": {
"@octokit/core": ">=3"
}
},
"node_modules/@octokit/plugin-rest-endpoint-methods": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.7.0.tgz",
"integrity": "sha512-orxQ0fAHA7IpYhG2flD2AygztPlGYNAdlzYz8yrD8NDgelPfOYoRPROfEyIe035PlxvbYrgkfUZIhSBKju/Cvw==",
"dependencies": {
"@octokit/types": "^8.0.0",
"deprecation": "^2.3.1"
},
"engines": {
"node": ">= 14"
},
"peerDependencies": {
"@octokit/core": ">=3"
}
},
"node_modules/@octokit/request": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.2.tgz",
"integrity": "sha512-6VDqgj0HMc2FUX2awIs+sM6OwLgwHvAi4KCK3mT2H2IKRt6oH9d0fej5LluF5mck1lRR/rFWN0YIDSYXYSylbw==",
"dependencies": {
"@octokit/endpoint": "^7.0.0",
"@octokit/request-error": "^3.0.0",
"@octokit/types": "^8.0.0",
"is-plain-object": "^5.0.0",
"node-fetch": "^2.6.7",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/request-error": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.2.tgz",
"integrity": "sha512-WMNOFYrSaX8zXWoJg9u/pKgWPo94JXilMLb2VManNOby9EZxrQaBe/QSC4a1TzpAlpxofg2X/jMnCyZgL6y7eg==",
"dependencies": {
"@octokit/types": "^8.0.0",
"deprecation": "^2.0.0",
"once": "^1.4.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/rest": {
"version": "19.0.5",
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.5.tgz",
"integrity": "sha512-+4qdrUFq2lk7Va+Qff3ofREQWGBeoTKNqlJO+FGjFP35ZahP+nBenhZiGdu8USSgmq4Ky3IJ/i4u0xbLqHaeow==",
"dependencies": {
"@octokit/core": "^4.1.0",
"@octokit/plugin-paginate-rest": "^5.0.0",
"@octokit/plugin-request-log": "^1.0.4",
"@octokit/plugin-rest-endpoint-methods": "^6.7.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/types": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-8.0.0.tgz",
"integrity": "sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg==",
"dependencies": {
"@octokit/openapi-types": "^14.0.0"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"node_modules/before-after-hook": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
},
"node_modules/deprecation": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
},
"node_modules/is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
"engines": {
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
}
},
"node_modules/universal-user-agent": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
}
},
"dependencies": {
"@actions/core": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz",
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
"requires": {
"@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
}
},
"@actions/glob": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.3.0.tgz",
"integrity": "sha512-tJP1ZhF87fd6LBnaXWlahkyvdgvsLl7WnreW1EZaC8JWjpMXmzqWzQVe/IEYslrkT9ymibVrKyJN4UMD7uQM2w==",
"requires": {
"@actions/core": "^1.2.6",
"minimatch": "^3.0.4"
}
},
"@actions/http-client": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"requires": {
"tunnel": "^0.0.6"
}
},
"@octokit/auth-token": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.2.tgz",
"integrity": "sha512-pq7CwIMV1kmzkFTimdwjAINCXKTajZErLB4wMLYapR2nuB/Jpr66+05wOTZMSCBXP6n4DdDWT2W19Bm17vU69Q==",
"requires": {
"@octokit/types": "^8.0.0"
}
},
"@octokit/core": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.1.0.tgz",
"integrity": "sha512-Czz/59VefU+kKDy+ZfDwtOIYIkFjExOKf+HA92aiTZJ6EfWpFzYQWw0l54ji8bVmyhc+mGaLUbSUmXazG7z5OQ==",
"requires": {
"@octokit/auth-token": "^3.0.0",
"@octokit/graphql": "^5.0.0",
"@octokit/request": "^6.0.0",
"@octokit/request-error": "^3.0.0",
"@octokit/types": "^8.0.0",
"before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/endpoint": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.3.tgz",
"integrity": "sha512-57gRlb28bwTsdNXq+O3JTQ7ERmBTuik9+LelgcLIVfYwf235VHbN9QNo4kXExtp/h8T423cR5iJThKtFYxC7Lw==",
"requires": {
"@octokit/types": "^8.0.0",
"is-plain-object": "^5.0.0",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/graphql": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.4.tgz",
"integrity": "sha512-amO1M5QUQgYQo09aStR/XO7KAl13xpigcy/kI8/N1PnZYSS69fgte+xA4+c2DISKqUZfsh0wwjc2FaCt99L41A==",
"requires": {
"@octokit/request": "^6.0.0",
"@octokit/types": "^8.0.0",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/openapi-types": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-14.0.0.tgz",
"integrity": "sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw=="
},
"@octokit/plugin-paginate-rest": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-5.0.1.tgz",
"integrity": "sha512-7A+rEkS70pH36Z6JivSlR7Zqepz3KVucEFVDnSrgHXzG7WLAzYwcHZbKdfTXHwuTHbkT1vKvz7dHl1+HNf6Qyw==",
"requires": {
"@octokit/types": "^8.0.0"
}
},
"@octokit/plugin-request-log": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
"integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==",
"requires": {}
},
"@octokit/plugin-rest-endpoint-methods": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.7.0.tgz",
"integrity": "sha512-orxQ0fAHA7IpYhG2flD2AygztPlGYNAdlzYz8yrD8NDgelPfOYoRPROfEyIe035PlxvbYrgkfUZIhSBKju/Cvw==",
"requires": {
"@octokit/types": "^8.0.0",
"deprecation": "^2.3.1"
}
},
"@octokit/request": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.2.tgz",
"integrity": "sha512-6VDqgj0HMc2FUX2awIs+sM6OwLgwHvAi4KCK3mT2H2IKRt6oH9d0fej5LluF5mck1lRR/rFWN0YIDSYXYSylbw==",
"requires": {
"@octokit/endpoint": "^7.0.0",
"@octokit/request-error": "^3.0.0",
"@octokit/types": "^8.0.0",
"is-plain-object": "^5.0.0",
"node-fetch": "^2.6.7",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/request-error": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.2.tgz",
"integrity": "sha512-WMNOFYrSaX8zXWoJg9u/pKgWPo94JXilMLb2VManNOby9EZxrQaBe/QSC4a1TzpAlpxofg2X/jMnCyZgL6y7eg==",
"requires": {
"@octokit/types": "^8.0.0",
"deprecation": "^2.0.0",
"once": "^1.4.0"
}
},
"@octokit/rest": {
"version": "19.0.5",
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.5.tgz",
"integrity": "sha512-+4qdrUFq2lk7Va+Qff3ofREQWGBeoTKNqlJO+FGjFP35ZahP+nBenhZiGdu8USSgmq4Ky3IJ/i4u0xbLqHaeow==",
"requires": {
"@octokit/core": "^4.1.0",
"@octokit/plugin-paginate-rest": "^5.0.0",
"@octokit/plugin-request-log": "^1.0.4",
"@octokit/plugin-rest-endpoint-methods": "^6.7.0"
}
},
"@octokit/types": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-8.0.0.tgz",
"integrity": "sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg==",
"requires": {
"@octokit/openapi-types": "^14.0.0"
}
},
"balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"before-after-hook": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
},
"deprecation": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
},
"is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
},
"minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"requires": {
"whatwg-url": "^5.0.0"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"requires": {
"wrappy": "1"
}
},
"tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
},
"universal-user-agent": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
},
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
},
"webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"requires": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
}
}
}
@@ -1,15 +0,0 @@
{
"name": "upload-release-assets",
"version": "1.0.0",
"description": "Upload Filament release assets",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Google",
"license": "Apache-2.0",
"dependencies": {
"@actions/glob": "^0.3.0",
"@octokit/rest": "^19.0.5"
}
}
+1 -1
View File
File diff suppressed because one or more lines are too long
+12 -11
View File
@@ -1432,13 +1432,12 @@ non-shader data.
</p><dl><table><tbody><tr valign="top"><td><dt>Type</dt></td><td><dd><p> <code>number</code>
</p></dd></td></tr><tr valign="top"><td><dt>Value</dt></td><td><dd><p> An integer value, either 1, 2 or 3. Defaults to 1.
</p></dd></td></tr><tr valign="top"><td><dt>Value</dt></td><td><dd><p> An integer value, either 1 or 2. Defaults to 1.
</p></dd></td></tr></tbody></table></dl><div class="table">
<table class="table"><tbody><tr><th style="text-align:left"> Feature Level </th><th style="text-align:left"> Guaranteed features </th></tr>
<tr><td style="text-align:left"> 1 </td><td style="text-align:left"> 9 textures per material </td></tr>
<tr><td style="text-align:left"> 2 </td><td style="text-align:left"> 9 textures per material, cubemap arrays, ESSL 3.10 </td></tr>
<tr><td style="text-align:left"> 3 </td><td style="text-align:left"> 12 textures per material, cubemap arrays, ESSL 3.10 </td></tr>
<tr><td style="text-align:left"> 2 </td><td style="text-align:left"> 12 textures per material, cubemap arrays, ESSL 3.10 </td></tr>
</tbody></table><center><div class="tablecaption"><a class="target" name="table_featurelevels">&nbsp;</a><b style="font-style:normal;">Table&nbsp;13:</b> Feature levels</div></center></div>
<p></p><p>
@@ -2037,21 +2036,23 @@ and sorting issues are minimized or eliminated</span></center></div></center>
</p></dd><dt>Value</dt><dd><p> <code>true</code> or <code>false</code>. Defaults to <code>false</code>.
</p></dd><dt>Description</dt><dd><p> Enables two-sided rendering and its capability to be toggled at run time. When set to <code>true</code>,
<code>culling</code> is automatically set to <code>none</code>; if the triangle is back-facing, the triangle's
normal is flipped to become front-facing. When explicitly set to <code>false</code>, this allows the
double-sidedness to be toggled at run time.
</p></dd><dt>Description</dt><dd><p> Only available in the <code>unlit</code> shading model. If this property is enabled, the final color
computed by the material is multiplied by the shadowing factor (or visibility). This allows to
create transparent shadow-receiving objects (for instance an invisible ground plane in AR).
This is only supported with shadows from directional lights.
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
<span class="line"> name : <span class="hljs-string">"Double sided material"</span>,</span>
<span class="line"> shadingModel : lit,</span>
<span class="line"> doubleSided : <span class="hljs-literal">true</span></span>
<span class="line"> name : <span class="hljs-string">"Invisible shadow plane"</span>,</span>
<span class="line"> shadingModel : unlit,</span>
<span class="line"> shadowMultiplier : <span class="hljs-literal">true</span>,</span>
<span class="line"> blending : transparent</span>
<span class="line">}</span>
<span class="line"></span>
<span class="line">fragment {</span>
<span class="line"> void material(inout MaterialInputs material) {</span>
<span class="line"> prepareMaterial(material);</span>
<span class="line"> material.baseColor = materialParams.albedo;</span>
<span class="line"> <span class="hljs-comment">// baseColor defines the color and opacity of the final shadow</span></span>
<span class="line"> material.baseColor = vec4(0.0, 0.0, 0.0, 0.7);</span>
<span class="line"> }</span>
<span class="line">}</span></code></pre>
<a class="target" name="lighting:reflections">&nbsp;</a><a class="target" name="materialdefinitions/materialblock/lighting:reflections">&nbsp;</a><a class="target" name="toc4.2.25">&nbsp;</a><h3>Lighting: reflections</h3>
+12 -10
View File
@@ -1582,22 +1582,24 @@ Value
: `true` or `false`. Defaults to `false`.
Description
: Enables two-sided rendering and its capability to be toggled at run time. When set to `true`,
`culling` is automatically set to `none`; if the triangle is back-facing, the triangle's
normal is flipped to become front-facing. When explicitly set to `false`, this allows the
double-sidedness to be toggled at run time.
: Only available in the `unlit` shading model. If this property is enabled, the final color
computed by the material is multiplied by the shadowing factor (or visibility). This allows to
create transparent shadow-receiving objects (for instance an invisible ground plane in AR).
This is only supported with shadows from directional lights.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
material {
name : "Double sided material",
shadingModel : lit,
doubleSided : true
name : "Invisible shadow plane",
shadingModel : unlit,
shadowMultiplier : true,
blending : transparent
}
fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
material.baseColor = materialParams.albedo;
// baseColor defines the color and opacity of the final shadow
material.baseColor = vec4(0.0, 0.0, 0.0, 0.7);
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2263,7 +2265,7 @@ 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.
**getResolution()** | float4 | Dimensions of the view's effective viewport in pixels: `width`, `height`, `1 / width`, `1 / height`. This might be different from `View::getViewport()` for instance because of added rendering guard-bands. This can be used in conjunction with `getNormalizedViewportCoord()` to generate pixel coordinates.
**getWorldCameraPosition()** | float3 | Position of the camera/eye in world space
**getWorldOffset()** | float3 | The shift required to obtain API-level world space
**getTime()** | float | Current time as a remainder of 1 second. Yields a value between 0 and 1
@@ -2301,7 +2303,7 @@ The following APIs are only available from the fragment block:
**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()`)
**getWorldReflectedVector()** | float3 | Reflection of the view vector about the normal (must be used after `prepareMaterial()`)
**getNormalizedViewportCoord()** | float3 | Normalized user viewport position (i.e. NDC coordinates normalized to [0, 1] for the position, [1, 0] for the depth), can be used before `prepareMaterial()`). Because the user viewport is smaller than the actual physical viewport, these coordinates can be negative or superior to 1 in the non-visible area of the physical viewport.
**getNormalizedViewportCoord()** | float3 | Normalized viewport position (i.e. NDC coordinates normalized to [0, 1], can be used before `prepareMaterial()`)
**getNdotV()** | float | The result of `dot(normal, view)`, always strictly greater than 0 (must be used after `prepareMaterial()`)
**getColor()** | float4 | Interpolated color of the fragment, if the color attribute is required
**getUV0()** | float2 | First interpolated set of UV coordinates, only available if the uv0 attribute is required
+157 -343
View File
File diff suppressed because one or more lines are too long
Binary file not shown.
+1 -1
View File
@@ -261,7 +261,7 @@ class App {
this.renderer.setClearOptions({clearColor: kBackgroundColor, clear: true});
this.render = this.render.bind(this);
this.simpleViewer = new Filament.ViewerGui(engine, scene, view, kInitialSidebarWidth);
this.simpleViewer = new Filament.SimpleViewer(engine, scene, view, kInitialSidebarWidth);
this.mouseX = -1;
this.mouseY = -1;
Binary file not shown.
Binary file not shown.
Binary file not shown.
+153 -330
View File
File diff suppressed because one or more lines are too long
Binary file not shown.
-1
View File
File diff suppressed because one or more lines are too long
+20 -21
View File
@@ -10,7 +10,7 @@ html, body { height: 100%; }
body { margin: 0; overflow: hidden; }
#container { position: relative; height: 100%; }
canvas { position: absolute; width: 100%; height: 100%; }
#messages { position: absolute; width: 100%; height: 100%; padding-left: 10px; color:blue; pointer-events: none; }
#messages { position: absolute; width: 100%; height: 100%; padding-left: 10px; color:white; }
</style>
</head>
<body>
@@ -20,7 +20,7 @@ canvas { position: absolute; width: 100%; height: 100%; }
</div>
<script src="filament.js"></script>
<script src="gl-matrix-min.js"></script>
<script src="gltumble.min.js"></script>
<script src="https://unpkg.com/gltumble"></script>
<script>
const env = 'default_env';
@@ -43,19 +43,7 @@ class App {
const scene = this.scene = engine.createScene();
this.trackball = new Trackball(canvas, {startSpin: 0.035});
const messages = document.getElementById('messages');
canvas.addEventListener('pointerdown', evt => {
const x = evt.clientX;
const y = this.canvas.getBoundingClientRect().height - 1 - evt.clientY;
const dpr = window.devicePixelRatio;
this.view.pick(x * dpr, y * dpr, (results) => {
const name = this.asset.getName(results.renderable);
messages.innerText = name ? ('Picked ' + name) : '';
});
});
const indirectLight = this.ibl = engine.createIblFromKtx1(ibl_url);
const indirectLight = this.ibl = engine.createIblFromKtx(ibl_url);
this.scene.setIndirectLight(indirectLight);
const iblDirection = IndirectLight.getDirectionEstimate(indirectLight.shfloats);
@@ -70,7 +58,7 @@ class App {
mat3.fromRotation(mat, radians, [0, 1, 0]);
indirectLight.setRotation(mat);
const skybox = engine.createSkyFromKtx1(sky_url);
const skybox = engine.createSkyFromKtx(sky_url);
this.scene.setSkybox(skybox);
const sunlight = Filament.EntityManager.get().create();
@@ -88,17 +76,28 @@ class App {
const loader = this.loader = engine.createAssetLoader();
this.allowRefresh = false;
const asset = this.asset = loader.createAsset(mesh_url);
const asset = this.asset = loader.createAssetFromJson(mesh_url);
this.assetRoot = this.asset.getRoot();
const messages = document.getElementById('messages');
// Crudely indicate progress by printing the URI of each resource as it is loaded.
const onFetched = (uri) => messages.innerText += `Downloaded ${uri}\n`;
const onDone = () => {
this.allowRefresh = true;
// Clear the progress indication messages.
messages.innerText = "";
// Enable shadows on every renderable.
const entities = asset.getEntities();
const rm = engine.getRenderableManager();
for (const entity of entities) {
const instance = rm.getInstance(entity);
rm.setCastShadows(instance, true);
instance.delete();
}
// Hide the HUD.
messages.remove();
};
asset.loadResources(onDone, onFetched);
@@ -138,7 +137,7 @@ class App {
this.allowRefresh = false;
this.scene.removeEntities(this.asset.getEntities());
this.loader.destroyAsset(this.asset);
this.asset = this.loader.createAsset(mesh_url);
this.asset = this.loader.createAssetFromJson(mesh_url);
const onDone = () => { this.allowRefresh = true; }
this.asset.loadResources(onDone);
}
@@ -150,7 +149,7 @@ class App {
tcm.setTransform(inst, this.trackball.getMatrix());
inst.delete();
// Gradually add renderables to the scene as their textures become ready.
// Add renderable entities to the scene as they become ready.
let entity;
const popRenderable = () => {
entity = this.asset.popRenderable();
Binary file not shown.
+2 -2
View File
@@ -54,14 +54,14 @@ class App {
.build(engine, sunlight);
this.scene.addEntity(sunlight);
const indirectLight = this.ibl = engine.createIblFromKtx1(iblfile);
const indirectLight = this.ibl = engine.createIblFromKtx(iblfile);
this.scene.setIndirectLight(indirectLight);
const radians = 1.0;
indirectLight.setRotation(mat3.fromRotation(mat3.create(), radians, [0, 1, 0]))
indirectLight.setIntensity(10000);
const skybox = engine.createSkyFromKtx1(skyfile);
const skybox = engine.createSkyFromKtx(skyfile);
this.scene.setSkybox(skybox);
const material = engine.createMaterial('parquet.filamat');
Binary file not shown.
+128 -137
View File
@@ -49,7 +49,7 @@
</tr>
<tr>
<td align="left"><a href="#EntityManager">EntityManager</a></td>
<td align="left">Singleton used for constructing entities in Filament&#x27;s ECS.</td>
<td align="left">Singleton used for constructing entities in Filament's ECS.</td>
</tr>
<tr>
<td align="left"><a href="#Frustum">Frustum</a></td>
@@ -69,7 +69,7 @@
</tr>
<tr>
<td align="left"><a href="#KtxInfo">KtxInfo</a></td>
<td align="left">Property accessor for KTX1 header.</td>
<td align="left">Property accessor for KTX header.</td>
</tr>
<tr>
<td align="left"><a href="#LightManager%24Instance">LightManager$Instance</a></td>
@@ -89,7 +89,7 @@
</tr>
<tr>
<td align="left"><a href="#Renderer">Renderer</a></td>
<td align="left">Represents the platform&#x27;s native window.</td>
<td align="left">Represents the platform's native window.</td>
</tr>
<tr>
<td align="left"><a href="#Scene">Scene</a></td>
@@ -97,7 +97,7 @@
</tr>
<tr>
<td align="left"><a href="#SwapChain">SwapChain</a></td>
<td align="left">Represents the platform&#x27;s native rendering surface.</td>
<td align="left">Represents the platform's native rendering surface.</td>
</tr>
<tr>
<td align="left"><a href="#Texture">Texture</a></td>
@@ -190,10 +190,6 @@
<td align="left"></td>
</tr>
<tr>
<td align="left"><a href="#ColorGrading%24LutFormat">ColorGrading$LutFormat</a></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"><a href="#ColorGrading%24QualityLevel">ColorGrading$QualityLevel</a></td>
<td align="left"></td>
</tr>
@@ -218,10 +214,6 @@
<td align="left"></td>
</tr>
<tr>
<td align="left"><a href="#FeatureLevel">FeatureLevel</a></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"><a href="#Frustum%24Plane">Frustum$Plane</a></td>
<td align="left"></td>
</tr>
@@ -230,14 +222,6 @@
<td align="left"></td>
</tr>
<tr>
<td align="left"><a href="#Ktx2Reader%24Result">Ktx2Reader$Result</a></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"><a href="#Ktx2Reader%24TransferFunction">Ktx2Reader$TransferFunction</a></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"><a href="#LightManager%24Type">LightManager$Type</a></td>
<td align="left"></td>
</tr>
@@ -274,14 +258,6 @@
<td align="left"></td>
</tr>
<tr>
<td align="left"><a href="#StencilFace">StencilFace</a></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"><a href="#StencilOperation">StencilOperation</a></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"><a href="#Texture%24CubemapFace">Texture$CubemapFace</a></td>
<td align="left"></td>
</tr>
@@ -298,10 +274,6 @@
<td align="left"></td>
</tr>
<tr>
<td align="left"><a href="#TransparencyMode">TransparencyMode</a></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"><a href="#VertexAttribute">VertexAttribute</a></td>
<td align="left"></td>
</tr>
@@ -314,6 +286,26 @@
<td align="left"></td>
</tr>
<tr>
<td align="left"><a href="#View%24AntiAliasing">View$AntiAliasing</a></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"><a href="#View%24BlendMode">View$BlendMode</a></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"><a href="#View%24BloomOptions%24BlendMode">View$BloomOptions$BlendMode</a></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"><a href="#View%24DepthOfFieldOptions%24Filter">View$DepthOfFieldOptions$Filter</a></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"><a href="#View%24QualityLevel">View$QualityLevel</a></td>
<td align="left"></td>
</tr>
<tr>
<td align="left"><a href="#WrapMode">WrapMode</a></td>
<td align="left"></td>
</tr>
@@ -379,7 +371,7 @@
<li><em>returns</em> an instance of <a href="#Camera">Camera</a></li>
</ul>
</li>
<li><strong>engine.createIblFromKtx1(buffer, options)</strong>
<li><strong>engine.createIblFromKtx(buffer, options)</strong>
<ul>
<li>Utility that creates an [IndirectLight] from a KTX file.</li>
<li><em>buffer</em> asset string, or Uint8Array, or <a href="#Buffer">Buffer</a> with KTX file contents</li>
@@ -403,7 +395,7 @@
<li><em>returns</em> an instance of <a href="#Scene">Scene</a></li>
</ul>
</li>
<li><strong>engine.createSkyFromKtx1(buffer, options)</strong>
<li><strong>engine.createSkyFromKtx(buffer, options)</strong>
<ul>
<li>Utility function that creates a [Skybox] from a KTX file.</li>
<li><em>buffer</em> asset string, or Uint8Array, or <a href="#Buffer">Buffer</a> with KTX file contents</li>
@@ -424,18 +416,10 @@
<li><em>returns</em> <a href="#Texture">Texture</a></li>
</ul>
</li>
<li><strong>engine.createTextureFromKtx1(buffer, options)</strong>
<li><strong>engine.createTextureFromKtx(buffer, options)</strong>
<ul>
<li>Utility function that creates a [Texture] from a KTX1 file.</li>
<li><em>buffer</em> asset string, or Uint8Array, or <a href="#Buffer">Buffer</a> with KTX1 file contents</li>
<li><em>options</em> Options dictionary.</li>
<li><em>returns</em> <a href="#Texture">Texture</a></li>
</ul>
</li>
<li><strong>engine.createTextureFromKtx2(buffer, options)</strong>
<ul>
<li>Utility function that creates a [Texture] from a KTX2 file.</li>
<li><em>buffer</em> asset string, or Uint8Array, or <a href="#Buffer">Buffer</a> with KTX2 file contents</li>
<li>Utility function that creates a [Texture] from a KTX file.</li>
<li><em>buffer</em> asset string, or Uint8Array, or <a href="#Buffer">Buffer</a> with KTX file contents</li>
<li><em>options</em> Options dictionary.</li>
<li><em>returns</em> <a href="#Texture">Texture</a></li>
</ul>
@@ -569,26 +553,57 @@
<li><em>entities</em> array of entities</li>
</ul>
</li>
<li><strong>engine.setAmbientOcclusionOptions()</strong></li>
<li><strong>engine.setBloomOptions()</strong></li>
<li><strong>engine.setAmbientOcclusionOptions(overrides)</strong>
<ul>
<li><em>overrides</em> Dictionary with one or more of the following properties: radius, power, bias, resolution, intensity, quality.</li>
</ul>
</li>
<li><strong>engine.setBloomOptions(overrides)</strong>
<ul>
<li><em>overrides</em> Dictionary with one or more of the following properties: enabled, strength, resolution, anomorphism, levels, blendMode, threshold, highlight.</li>
</ul>
</li>
<li><strong>engine.setClearOptions(overrides)</strong>
<ul>
<li><em>overrides</em> Dictionary with one or more of the following properties: clearColor, clear, discard.</li>
</ul>
</li>
<li><strong>engine.setDepthOfFieldOptions()</strong></li>
<li><strong>engine.setFogOptions()</strong></li>
<li><strong>engine.setGuardBandOptions()</strong></li>
<li><strong>engine.setMultiSampleAntiAliasingOptions()</strong></li>
<li><strong>engine.setScreenSpaceReflectionsOptions()</strong></li>
<li><strong>engine.setDepthOfFieldOptions(overrides)</strong>
<ul>
<li><em>overrides</em> Dictionary with one or more of the following properties: cocScale, maxApertureDiameter, enabled.</li>
</ul>
</li>
<li><strong>engine.setFogOptions(overrides)</strong>
<ul>
<li><em>overrides</em> Dictionary with one or more of the following properties: distance, maximumOpacity, height, heightFalloff, color, density, inScatteringStart,</li>
</ul>
</li>
<li><strong>engine.setMultiSampleAntiAliasingOptions(overrides)</strong>
<ul>
<li><em>overrides</em> Dictionary with one or more of the following properties: enabled, sampleCount, customResolve.</li>
</ul>
</li>
<li><strong>engine.setScreenSpaceReflectionsOptions(overrides)</strong>
<ul>
<li><em>overrides</em> Dictionary with one or more of the following properties: thickness, bias, maxDistance, stride, enabled.</li>
</ul>
</li>
<li><strong>engine.setShadowOptions(instance, overrides)</strong>
<ul>
<li><em>instance</em> Instance of a light component obtained from <code>getInstance</code>.</li>
<li><em>overrides</em> Dictionary with one or more of the following properties: mapSize, shadowCascades, constantBias, normalBias, shadowFar, shadowNearHint, shadowFarHint, stable, polygonOffsetConstant, polygonOffsetSlope, \</li>
</ul>
</li>
<li><strong>engine.setTemporalAntiAliasingOptions()</strong></li>
<li><strong>engine.setVignetteOptions()</strong></li>
<li><strong>engine.setTemporalAntiAliasingOptions(overrides)</strong>
<ul>
<li><em>overrides</em> Dictionary with one or more of the following properties: filterWidth, feedback, enabled.</li>
</ul>
</li>
<li><strong>engine.setVignetteOptions(overrides)</strong>
<ul>
<li><em>overrides</em> Dictionary with one or more of the following properties: midPoint, roundness, feather, color, enabled.</li>
</ul>
</li>
</ul>
</div>
<div class='classdoc'>
@@ -603,11 +618,11 @@
</ul>
<p>To create an entity with no components, use <a href="#EntityManager">EntityManager</a>.
TODO: It would be better to expose these as JS numbers rather than as JS objects.
This would also be more consistent with Filament&#x27;s Java bindings.</p>
This would also be more consistent with Filament's Java bindings.</p>
</div>
<div class='classdoc'>
<h2>class <a id='EntityManager' href='#EntityManager'>EntityManager</a></h2>
<p>Singleton used for constructing entities in Filament&#x27;s ECS.</p>
<p>Singleton used for constructing entities in Filament's ECS.</p>
<ul>
<li><strong>entityManager.create()</strong>
<ul>
@@ -712,9 +727,15 @@ wrapper rather than interacting with <code>Ktx1Bundle</code> directly.</p>
</div>
<div class='classdoc'>
<h2>class <a id='KtxInfo' href='#KtxInfo'>KtxInfo</a></h2>
<p>Property accessor for KTX1 header.</p>
<p>Property accessor for KTX header.</p>
<ul>
<li><strong>ktxInfo.createAsset(buffer)</strong>
<li><strong>ktxInfo.createAssetFromBinary(buffer)</strong>
<ul>
<li><em>buffer</em> asset string, or Uint8Array, or <a href="#Buffer">Buffer</a></li>
<li><em>returns</em> an instance of <a href="#FilamentAsset">FilamentAsset</a></li>
</ul>
</li>
<li><strong>ktxInfo.createAssetFromJson(buffer)</strong>
<ul>
<li><em>buffer</em> asset string, or Uint8Array, or <a href="#Buffer">Buffer</a></li>
<li><em>returns</em> an instance of <a href="#FilamentAsset">FilamentAsset</a></li>
@@ -741,7 +762,7 @@ properties.</p>
</ul>
</li>
</ul>
<p>Be sure to call the instance&#x27;s <code>delete</code> method when you&#x27;re done with it.</p>
<p>Be sure to call the instance's <code>delete</code> method when you're done with it.</p>
</div>
<div class='classdoc'>
<h2>class <a id='PixelBufferDescriptor' href='#PixelBufferDescriptor'>PixelBufferDescriptor</a></h2>
@@ -779,11 +800,11 @@ properties.</p>
</ul>
</li>
</ul>
<p>Be sure to call the instance&#x27;s <code>delete</code> method when you&#x27;re done with it.</p>
<p>Be sure to call the instance's <code>delete</code> method when you're done with it.</p>
</div>
<div class='classdoc'>
<h2>class <a id='Renderer' href='#Renderer'>Renderer</a></h2>
<p>Represents the platform&#x27;s native window.</p>
<p>Represents the platform's native window.</p>
<ul>
<li><strong>renderer.render(swapChain, view)</strong>
<ul>
@@ -802,7 +823,7 @@ properties.</p>
</div>
<div class='classdoc'>
<h2>class <a id='SwapChain' href='#SwapChain'>SwapChain</a></h2>
<p>Represents the platform&#x27;s native rendering surface.</p>
<p>Represents the platform's native rendering surface.</p>
<p>See also the <a href="#Engine">Engine</a> methods <code>createSwapChain</code> and <code>destroySwapChain</code>.</p>
</div>
<div class='classdoc'>
@@ -846,7 +867,7 @@ properties.</p>
</ul>
</li>
</ul>
<p>Be sure to call the instance&#x27;s <code>delete</code> method when you&#x27;re done with it.</p>
<p>Be sure to call the instance's <code>delete</code> method when you're done with it.</p>
</div>
<div class='classdoc'>
<h2>class <a id='VertexBuffer' href='#VertexBuffer'>VertexBuffer</a></h2>
@@ -943,7 +964,7 @@ See also the <a href="#Engine">Engine</a> methods <code>createView</code> and <c
<ul>
<li><strong>assets</strong>
<ul>
<li>Array of strings containing URL&#x27;s of required assets.</li>
<li>Array of strings containing URL's of required assets.</li>
</ul>
</li>
<li><strong>onDone</strong>
@@ -953,7 +974,7 @@ See also the <a href="#Engine">Engine</a> methods <code>createView</code> and <c
</li>
<li><strong>onFetched</strong>
<ul>
<li>optional callback that&#x27;s invoked after each asset is downloaded.</li>
<li>optional callback that's invoked after each asset is downloaded.</li>
</ul>
</li>
</ul>
@@ -1000,7 +1021,7 @@ useful for compressed textures. For example, some platforms accept ETC and other
<ul>
<li><strong>assets</strong>
<ul>
<li>Array of strings containing URL&#x27;s of required assets.</li>
<li>Array of strings containing URL's of required assets.</li>
</ul>
</li>
<li><strong>onready</strong>
@@ -1009,12 +1030,12 @@ useful for compressed textures. For example, some platforms accept ETC and other
</ul>
</li>
</ul>
<p>All JavaScript clients must call the init function, passing in a list of asset URL&#x27;s and a
<p>All JavaScript clients must call the init function, passing in a list of asset URL's and a
callback. This callback gets invoked only after all assets have been downloaded and the Filament
WebAssembly module has been loaded. Clients should only pass asset URL&#x27;s that absolutely must
WebAssembly module has been loaded. Clients should only pass asset URL's that absolutely must
be ready at initialization time.
When the callback is called, each downloaded asset is available in the <code>Filament.assets</code> global
object, which contains a mapping from URL&#x27;s to Uint8Array objects.</p>
object, which contains a mapping from URL's to Uint8Array objects.</p>
</div>
<div class='funcdoc'>
<h2>function <a id='loadMathExtensions' href='#loadMathExtensions'>loadMathExtensions</a>()</h2>
@@ -1064,13 +1085,6 @@ This defines the following functions:</p>
</ul>
</div>
<div class='enumdoc'>
<h2>enum <a id='ColorGrading$LutFormat' href='#ColorGrading$LutFormat'>ColorGrading$LutFormat</a></h2>
<ul>
<li>INTEGER</li>
<li>FLOAT</li>
</ul>
</div>
<div class='enumdoc'>
<h2>enum <a id='ColorGrading$QualityLevel' href='#ColorGrading$QualityLevel'>ColorGrading$QualityLevel</a></h2>
<ul>
<li>LOW</li>
@@ -1126,10 +1140,6 @@ This defines the following functions:</p>
<li>DXT1_RGBA</li>
<li>DXT3_RGBA</li>
<li>DXT5_RGBA</li>
<li>DXT1_SRGB</li>
<li>DXT1_SRGBA</li>
<li>DXT3_SRGBA</li>
<li>DXT5_SRGBA</li>
<li>RGBA_ASTC_4x4</li>
<li>RGBA_ASTC_5x4</li>
<li>RGBA_ASTC_5x5</li>
@@ -1170,13 +1180,6 @@ This defines the following functions:</p>
</ul>
</div>
<div class='enumdoc'>
<h2>enum <a id='FeatureLevel' href='#FeatureLevel'>FeatureLevel</a></h2>
<ul>
<li>FEATURE_LEVEL_1</li>
<li>FEATURE_LEVEL_2</li>
</ul>
</div>
<div class='enumdoc'>
<h2>enum <a id='Frustum$Plane' href='#Frustum$Plane'>Frustum$Plane</a></h2>
<ul>
<li>LEFT</li>
@@ -1195,23 +1198,6 @@ This defines the following functions:</p>
</ul>
</div>
<div class='enumdoc'>
<h2>enum <a id='Ktx2Reader$Result' href='#Ktx2Reader$Result'>Ktx2Reader$Result</a></h2>
<ul>
<li>SUCCESS</li>
<li>COMPRESSED_TRANSCODE_FAILURE</li>
<li>UNCOMPRESSED_TRANSCODE_FAILURE</li>
<li>FORMAT_UNSUPPORTED</li>
<li>FORMAT_ALREADY_REQUESTED</li>
</ul>
</div>
<div class='enumdoc'>
<h2>enum <a id='Ktx2Reader$TransferFunction' href='#Ktx2Reader$TransferFunction'>Ktx2Reader$TransferFunction</a></h2>
<ul>
<li>LINEAR</li>
<li>sRGB</li>
</ul>
</div>
<div class='enumdoc'>
<h2>enum <a id='LightManager$Type' href='#LightManager$Type'>LightManager$Type</a></h2>
<ul>
<li>SUN</li>
@@ -1289,6 +1275,7 @@ This defines the following functions:</p>
<li>LINE_STRIP</li>
<li>TRIANGLES</li>
<li>TRIANGLE_STRIP</li>
<li>NONE</li>
</ul>
</div>
<div class='enumdoc'>
@@ -1308,27 +1295,6 @@ This defines the following functions:</p>
</ul>
</div>
<div class='enumdoc'>
<h2>enum <a id='StencilFace' href='#StencilFace'>StencilFace</a></h2>
<ul>
<li>FRONT</li>
<li>BACK</li>
<li>FRONT_AND_BACK</li>
</ul>
</div>
<div class='enumdoc'>
<h2>enum <a id='StencilOperation' href='#StencilOperation'>StencilOperation</a></h2>
<ul>
<li>KEEP</li>
<li>ZERO</li>
<li>REPLACE</li>
<li>INCR_CLAMP</li>
<li>INCR_WRAP</li>
<li>DECR_CLAMP</li>
<li>DECR_WRAP</li>
<li>INVERT</li>
</ul>
</div>
<div class='enumdoc'>
<h2>enum <a id='Texture$CubemapFace' href='#Texture$CubemapFace'>Texture$CubemapFace</a></h2>
<ul>
<li>POSITIVE_X</li>
@@ -1411,10 +1377,6 @@ This defines the following functions:</p>
<li>DXT1_RGBA</li>
<li>DXT3_RGBA</li>
<li>DXT5_RGBA</li>
<li>DXT1_SRGB</li>
<li>DXT1_SRGBA</li>
<li>DXT3_SRGBA</li>
<li>DXT5_SRGBA</li>
<li>RGBA_ASTC_4x4</li>
<li>RGBA_ASTC_5x4</li>
<li>RGBA_ASTC_5x5</li>
@@ -1466,14 +1428,6 @@ This defines the following functions:</p>
</ul>
</div>
<div class='enumdoc'>
<h2>enum <a id='TransparencyMode' href='#TransparencyMode'>TransparencyMode</a></h2>
<ul>
<li>DEFAULT</li>
<li>TWO_PASSES_ONE_SIDE</li>
<li>TWO_PASSES_TWO_SIDES</li>
</ul>
</div>
<div class='enumdoc'>
<h2>enum <a id='VertexAttribute' href='#VertexAttribute'>VertexAttribute</a></h2>
<ul>
<li>POSITION</li>
@@ -1540,6 +1494,43 @@ This defines the following functions:</p>
</ul>
</div>
<div class='enumdoc'>
<h2>enum <a id='View$AntiAliasing' href='#View$AntiAliasing'>View$AntiAliasing</a></h2>
<ul>
<li>NONE</li>
<li>FXAA</li>
</ul>
</div>
<div class='enumdoc'>
<h2>enum <a id='View$BlendMode' href='#View$BlendMode'>View$BlendMode</a></h2>
<ul>
<li>OPAQUE</li>
<li>TRANSLUCENT</li>
</ul>
</div>
<div class='enumdoc'>
<h2>enum <a id='View$BloomOptions$BlendMode' href='#View$BloomOptions$BlendMode'>View$BloomOptions$BlendMode</a></h2>
<ul>
<li>ADD</li>
<li>INTERPOLATE</li>
</ul>
</div>
<div class='enumdoc'>
<h2>enum <a id='View$DepthOfFieldOptions$Filter' href='#View$DepthOfFieldOptions$Filter'>View$DepthOfFieldOptions$Filter</a></h2>
<ul>
<li>NONE</li>
<li>MEDIAN</li>
</ul>
</div>
<div class='enumdoc'>
<h2>enum <a id='View$QualityLevel' href='#View$QualityLevel'>View$QualityLevel</a></h2>
<ul>
<li>LOW</li>
<li>MEDIUM</li>
<li>HIGH</li>
<li>ULTRA</li>
</ul>
</div>
<div class='enumdoc'>
<h2>enum <a id='WrapMode' href='#WrapMode'>WrapMode</a></h2>
<ul>
<li>CLAMP_TO_EDGE</li>
Binary file not shown.
+20 -27
View File
@@ -16,14 +16,17 @@ canvas { touch-action: none; width: 100%; height: 100%; }
<script src="gl-matrix-min.js"></script>
<script>
const albedo_suffix = Filament.getSupportedFormatSuffix('astc s3tc_srgb');
const texture_suffix = Filament.getSupportedFormatSuffix('etc');
const env = 'default_env'
const ibl_url = `${env}/${env}_ibl.ktx`;
const sky_url = `${env}/${env}_skybox.ktx`;
const albedo_url = `albedo.ktx2`;
const ao_url = `ao.ktx2`;
const metallic_url = `metallic.ktx2`;
const normal_url = `normal.ktx2`;
const roughness_url = `roughness.ktx2`;
const albedo_url = `albedo${albedo_suffix}.ktx`;
const ao_url = `ao${texture_suffix}.ktx`;
const metallic_url = `metallic${texture_suffix}.ktx`;
const normal_url = `normal${texture_suffix}.ktx`;
const roughness_url = `roughness${texture_suffix}.ktx`;
const filamat_url = 'textured.filamat';
const filamesh_url = 'suzanne.filamesh';
@@ -38,13 +41,12 @@ Filament.init([
ibl_url,
sky_url
], () => {
window.AttributeType = Filament.VertexBuffer$AttributeType;
window.Format = Filament.Texture$InternalFormat;
window.Fov = Filament.Camera$Fov;
window.IndexType = Filament.IndexBuffer$IndexType;
window.LightType = Filament.LightManager$Type;
window.PrimitiveType = Filament.RenderableManager$PrimitiveType;
window.VertexAttribute = Filament.VertexAttribute;
window.AttributeType = Filament.VertexBuffer$AttributeType;
window.PrimitiveType = Filament.RenderableManager$PrimitiveType;
window.IndexType = Filament.IndexBuffer$IndexType;
window.Fov = Filament.Camera$Fov;
window.LightType = Filament.LightManager$Type;
window.app = new App(document.getElementsByTagName('canvas')[0]);
});
@@ -66,11 +68,11 @@ class App {
.build(engine, sunlight);
this.scene.addEntity(sunlight);
const indirectLight = this.ibl = engine.createIblFromKtx1(ibl_url);
const indirectLight = this.ibl = engine.createIblFromKtx(ibl_url);
this.scene.setIndirectLight(indirectLight);
indirectLight.setIntensity(80000);
const skybox = engine.createSkyFromKtx1(sky_url);
const skybox = engine.createSkyFromKtx(sky_url);
this.scene.setSkybox(skybox);
const material = engine.createMaterial(filamat_url);
@@ -81,20 +83,11 @@ class App {
Filament.MagFilter.LINEAR,
Filament.WrapMode.CLAMP_TO_EDGE);
// Filament requests support for the following extensions, but none are guaranteed.
// WEBGL_compressed_texture_s3tc, WEBGL_compressed_texture_s3tc_srgb
// WEBGL_compressed_texture_astc, WEBGL_compressed_texture_etc
const albedo = engine.createTextureFromKtx2(albedo_url, {
srgb: true,
formats: [ Format.DXT5_RGBA, Format.DXT5_SRGBA, Format.ETC2_EAC_SRGBA8 ]
});
console.assert(albedo, "Unable to create albedo texture.")
const roughness = engine.createTextureFromKtx2(roughness_url);
const metallic = engine.createTextureFromKtx2(metallic_url);
const ao = engine.createTextureFromKtx2(ao_url);
const normal = engine.createTextureFromKtx2(normal_url);
const albedo = engine.createTextureFromKtx(albedo_url, {srgb: true});
const roughness = engine.createTextureFromKtx(roughness_url);
const metallic = engine.createTextureFromKtx(metallic_url);
const normal = engine.createTextureFromKtx(normal_url);
const ao = engine.createTextureFromKtx(ao_url);
matinstance.setTextureParameter('albedo', albedo, sampler)
matinstance.setTextureParameter('roughness', roughness, sampler)
Binary file not shown.
Binary file not shown.
+155 -155
View File
@@ -10,7 +10,7 @@
textures.</p>
<p>For starters, create a text file called <code>redball.html</code> and copy over the HTML that we used in the
<a href="tutorial_triangle.html">previous tutorial</a>. Change the last script tag from <code>triangle.js</code> to <code>redball.js</code>.</p>
<p>Next you&#x27;ll need to get a couple command-line tools: <code>matc</code> and <code>cmgen</code>. You can find these in the
<p>Next you'll need to get a couple command-line tools: <code>matc</code> and <code>cmgen</code>. You can find these in the
appropriate <a href="//github.com/google/filament/releases">Filament release</a>. You should choose the
archive that corresponds to your development machine rather than the one for web, and the version
that matches the <code>unpkg.com/filament@x.x.x</code> url in the script tag of <code>redball.html</code> (you may check
@@ -19,7 +19,7 @@ out the last available release of <a href="https://www.npmjs.com/package/filamen
<p>The <code>matc</code> tool consumes a text file containing a high-level description of a PBR material, and
produces a binary material package that contains shader code and associated metadata. For more
information, see the official document describing the <a href="https://google.github.io/filament/Materials.md.html">Filament Material System</a>.</p>
<p>Let&#x27;s try out <code>matc</code>. Create the following file in your favorite text editor and call it
<p>Let's try out <code>matc</code>. Create the following file in your favorite text editor and call it
<code>plastic.mat</code>.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>material {
name : Lit,
@@ -47,10 +47,10 @@ fragment {
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>matc -a opengl -p mobile -o plastic.filamat plastic.mat
</pre></div>
<p>You should now have a material archive in your working directory, which we&#x27;ll use later in the
<p>You should now have a material archive in your working directory, which we'll use later in the
tutorial.</p>
<h2>Bake environment map</h2>
<p>Next we&#x27;ll use Filament&#x27;s <code>cmgen</code> tool to consume a HDR environment map in latlong format, and
<p>Next we'll use Filament's <code>cmgen</code> tool to consume a HDR environment map in latlong format, and
produce two cubemap files: a mipmapped IBL and a blurry skybox.</p>
<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
@@ -61,84 +61,84 @@ well as a text file with spherical harmonics coefficients. You can discard the t
IBL KTX contains these coefficients in its metadata.</p>
<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">&#39;pillars_2k&#39;</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">&#39;plastic.filamat&#39;</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> environ <span style="color: #666666">=</span> <span style="color: #BA2121">&#39;pillars_2k&#39;</span>;
<span style="color: #008000; font-weight: bold">const</span> ibl_url <span style="color: #666666">=</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> sky_url <span style="color: #666666">=</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> filamat_url <span style="color: #666666">=</span> <span style="color: #BA2121">&#39;plastic.filamat&#39;</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>=&gt;<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([ filamat_url, ibl_url, sky_url ], () =&gt; {
<span style="color: #3D7B7B; font-style: italic">// Create some global aliases to enums for convenience.</span>
<span style="color: #008000">window</span>.VertexAttribute <span style="color: #666666">=</span> Filament.VertexAttribute;
<span style="color: #008000">window</span>.AttributeType <span style="color: #666666">=</span> Filament.VertexBuffer$AttributeType;
<span style="color: #008000">window</span>.PrimitiveType <span style="color: #666666">=</span> Filament.RenderableManager$PrimitiveType;
<span style="color: #008000">window</span>.IndexType <span style="color: #666666">=</span> Filament.IndexBuffer$IndexType;
<span style="color: #008000">window</span>.Fov <span style="color: #666666">=</span> Filament.Camera$Fov;
<span style="color: #008000">window</span>.LightType <span style="color: #666666">=</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">&#39;canvas&#39;</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: #3D7B7B; font-style: italic">// Obtain the canvas DOM object and pass it to the App.</span>
<span style="color: #008000; font-weight: bold">const</span> canvas <span style="color: #666666">=</span> <span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">&#39;canvas&#39;</span>)[<span style="color: #666666">0</span>];
<span style="color: #008000">window</span>.app <span style="color: #666666">=</span> <span style="color: #AA22FF; font-weight: bold">new</span> App(canvas);
} );
<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> App {
<span style="color: #008000; font-weight: bold">constructor</span>(canvas) {
<span style="color: #008000; font-weight: bold">this</span>.canvas <span style="color: #666666">=</span> canvas;
<span style="color: #008000; font-weight: bold">const</span> engine <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine <span style="color: #666666">=</span> Filament.Engine.create(canvas);
<span style="color: #008000; font-weight: bold">const</span> scene <span style="color: #666666">=</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: #3D7B7B; font-style: italic">// TODO: create material</span>
<span style="color: #3D7B7B; font-style: italic">// TODO: create sphere</span>
<span style="color: #3D7B7B; font-style: italic">// TODO: create lights</span>
<span style="color: #3D7B7B; font-style: italic">// TODO: create IBL</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">&#39;resize&#39;</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: #008000; font-weight: bold">this</span>.swapChain <span style="color: #666666">=</span> engine.createSwapChain();
<span style="color: #008000; font-weight: bold">this</span>.renderer <span style="color: #666666">=</span> engine.createRenderer();
<span style="color: #008000; font-weight: bold">this</span>.camera <span style="color: #666666">=</span> engine.createCamera(Filament.EntityManager.get().create());
<span style="color: #008000; font-weight: bold">this</span>.view <span style="color: #666666">=</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(scene);
<span style="color: #008000; font-weight: bold">this</span>.resize();
<span style="color: #008000; font-weight: bold">this</span>.render <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);
<span style="color: #008000; font-weight: bold">this</span>.resize <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);
<span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">&#39;resize&#39;</span>, <span style="color: #008000; font-weight: bold">this</span>.resize);
<span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
}
<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>
render() {
<span style="color: #008000; font-weight: bold">const</span> eye <span style="color: #666666">=</span> [<span style="color: #666666">0</span>, <span style="color: #666666">0</span>, <span style="color: #666666">4</span>], center <span style="color: #666666">=</span> [<span style="color: #666666">0</span>, <span style="color: #666666">0</span>, <span style="color: #666666">0</span>], up <span style="color: #666666">=</span> [<span style="color: #666666">0</span>, <span style="color: #666666">1</span>, <span style="color: #666666">0</span>];
<span style="color: #008000; font-weight: bold">const</span> radians <span style="color: #666666">=</span> <span style="color: #008000">Date</span>.now() <span style="color: #666666">/</span> <span style="color: #666666">10000</span>;
vec3.rotateY(eye, eye, center, radians);
<span style="color: #008000; font-weight: bold">this</span>.camera.lookAt(eye, center, up);
<span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain, <span style="color: #008000; font-weight: bold">this</span>.view);
<span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
}
<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>
resize() {
<span style="color: #008000; font-weight: bold">const</span> dpr <span style="color: #666666">=</span> <span style="color: #008000">window</span>.devicePixelRatio;
<span style="color: #008000; font-weight: bold">const</span> width <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.canvas.width <span style="color: #666666">=</span> <span style="color: #008000">window</span>.innerWidth <span style="color: #666666">*</span> dpr;
<span style="color: #008000; font-weight: bold">const</span> height <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.canvas.height <span style="color: #666666">=</span> <span style="color: #008000">window</span>.innerHeight <span style="color: #666666">*</span> dpr;
<span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666666">0</span>, <span style="color: #666666">0</span>, width, height]);
<span style="color: #008000; font-weight: bold">this</span>.camera.setProjectionFov(<span style="color: #666666">45</span>, width <span style="color: #666666">/</span> height, <span style="color: #666666">1.0</span>, <span style="color: #666666">10.0</span>, Fov.VERTICAL);
}
}
</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&#x27;s create a material instance from the package that we built at the beginning the tutorial.
<p>Next let's create a material instance from the package that we built at the beginning the tutorial.
Replace the <strong>create material</strong> comment with the following snippet.</p>
<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> material <span style="color: #666666">=</span> engine.createMaterial(filamat_url);
<span style="color: #008000; font-weight: bold">const</span> matinstance <span style="color: #666666">=</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">&#39;baseColor&#39;</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">&#39;roughness&#39;</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.5</span>);<span style="color: #bbbbbb"></span>
matinstance.setFloatParameter(<span style="color: #BA2121">&#39;clearCoat&#39;</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1.0</span>);<span style="color: #bbbbbb"></span>
matinstance.setFloatParameter(<span style="color: #BA2121">&#39;clearCoatRoughness&#39;</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> red <span style="color: #666666">=</span> [<span style="color: #666666">0.8</span>, <span style="color: #666666">0.0</span>, <span style="color: #666666">0.0</span>];
matinstance.setColor3Parameter(<span style="color: #BA2121">&#39;baseColor&#39;</span>, Filament.RgbType.sRGB, red);
matinstance.setFloatParameter(<span style="color: #BA2121">&#39;roughness&#39;</span>, <span style="color: #666666">0.5</span>);
matinstance.setFloatParameter(<span style="color: #BA2121">&#39;clearCoat&#39;</span>, <span style="color: #666666">1.0</span>);
matinstance.setFloatParameter(<span style="color: #BA2121">&#39;clearCoatRoughness&#39;</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&#x27;ll use the <code>IcoSphere</code>
<p>The next step is to create a renderable for the sphere. To help with this, we'll use the <code>IcoSphere</code>
utility class, whose constructor takes a LOD. Its job is to subdivide an icosadedron, producing
three arrays:</p>
<ul>
@@ -147,137 +147,137 @@ three arrays:</p>
as quaternions.</li>
<li><code>icosphere.triangles</code> Uint16Array with triangle indices.</li>
</ul>
<p>Let&#x27;s go ahead use these arrays to build the vertex buffer and index buffer. Replace <strong>create
<p>Let's go ahead use these arrays to build the vertex buffer and index buffer. Replace <strong>create
sphere</strong> with the following snippet.</p>
<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> renderable <span style="color: #666666">=</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> icosphere <span style="color: #666666">=</span> <span style="color: #AA22FF; font-weight: bold">new</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> vb <span style="color: #666666">=</span> Filament.VertexBuffer.Builder()
.vertexCount(icosphere.vertices.length <span style="color: #666666">/</span> <span style="color: #666666">3</span>)
.bufferCount(<span style="color: #666666">2</span>)
.attribute(VertexAttribute.POSITION, <span style="color: #666666">0</span>, AttributeType.FLOAT3, <span style="color: #666666">0</span>, <span style="color: #666666">0</span>)
.attribute(VertexAttribute.TANGENTS, <span style="color: #666666">1</span>, AttributeType.SHORT4, <span style="color: #666666">0</span>, <span style="color: #666666">0</span>)
.normalized(VertexAttribute.TANGENTS)
.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> ib <span style="color: #666666">=</span> Filament.IndexBuffer.Builder()
.indexCount(icosphere.triangles.length)
.bufferType(IndexType.USHORT)
.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: #666666">0</span>, icosphere.vertices);
vb.setBufferAt(engine, <span style="color: #666666">1</span>, icosphere.tangents);
ib.setBuffer(engine, 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>)
.boundingBox({ center<span style="color: #666666">:</span> [<span style="color: #666666">-1</span>, <span style="color: #666666">-1</span>, <span style="color: #666666">-1</span>], halfExtent<span style="color: #666666">:</span> [<span style="color: #666666">1</span>, <span style="color: #666666">1</span>, <span style="color: #666666">1</span>] })
.material(<span style="color: #666666">0</span>, matinstance)
.geometry(<span style="color: #666666">0</span>, PrimitiveType.TRIANGLES, vb, ib)
.build(engine, renderable);
</pre></div>
<p>At this point, the app is rendering a sphere, but it is black so it doesn&#x27;t show up. To prove that
<p>At this point, the app is rendering a sphere, but it is black so it doesn't show up. To prove that
the sphere is there, you can try changing the background color to blue via <code>setClearColor</code>, like we
did in the first tutorial.</p>
<h2>Add lighting</h2>
<p>In this section we will create some directional light sources, as well as an image-based light (IBL)
defined by one of the KTX files we built at the start of the demo. First, replace the <strong>create
lights</strong> comment with the following snippet.</p>
<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> sunlight <span style="color: #666666">=</span> Filament.EntityManager.get().create();
scene.addEntity(sunlight);
Filament.LightManager.Builder(LightType.SUN)
.color([<span style="color: #666666">0.98</span>, <span style="color: #666666">0.92</span>, <span style="color: #666666">0.89</span>])
.intensity(<span style="color: #666666">110000.0</span>)
.direction([<span style="color: #666666">0.6</span>, <span style="color: #666666">-1.0</span>, <span style="color: #666666">-0.8</span>])
.sunAngularRadius(<span style="color: #666666">1.9</span>)
.sunHaloSize(<span style="color: #666666">10.0</span>)
.sunHaloFalloff(<span style="color: #666666">80.0</span>)
.build(engine, 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> backlight <span style="color: #666666">=</span> Filament.EntityManager.get().create();
scene.addEntity(backlight);
Filament.LightManager.Builder(LightType.DIRECTIONAL)
.direction([<span style="color: #666666">-1</span>, <span style="color: #666666">0</span>, <span style="color: #666666">1</span>])
.intensity(<span style="color: #666666">50000.0</span>)
.build(engine, 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&#x27;t type this out, there&#x27;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>
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> format <span style="color: #666666">=</span> Filament.PixelDataFormat.RGB;
<span style="color: #008000; font-weight: bold">const</span> datatype <span style="color: #666666">=</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> ibl_package <span style="color: #666666">=</span> Filament.Buffer(Filament.assets[ibl_url]);
<span style="color: #008000; font-weight: bold">const</span> iblktx <span style="color: #666666">=</span> <span style="color: #AA22FF; font-weight: bold">new</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> ibltex <span style="color: #666666">=</span> Filament.Texture.Builder()
.width(iblktx.info().pixelWidth)
.height(iblktx.info().pixelHeight)
.levels(iblktx.getNumMipLevels())
.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)
.format(Filament.Texture$InternalFormat.RGBA8)
.build(engine);
<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">&lt;</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: #008000; font-weight: bold">let</span> level <span style="color: #666666">=</span> <span style="color: #666666">0</span>; level <span style="color: #666666">&lt;</span> iblktx.getNumMipLevels(); <span style="color: #666666">++</span>level) {
<span style="color: #008000; font-weight: bold">const</span> uint8array <span style="color: #666666">=</span> iblktx.getCubeBlob(level).getBytes();
<span style="color: #008000; font-weight: bold">const</span> pixelbuffer <span style="color: #666666">=</span> Filament.PixelBuffer(uint8array, format, datatype);
ibltex.setImageCube(engine, level, 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">&#39;sh&#39;</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> shstring <span style="color: #666666">=</span> iblktx.getMetadata(<span style="color: #BA2121">&#39;sh&#39;</span>);
<span style="color: #008000; font-weight: bold">const</span> shfloats <span style="color: #666666">=</span> shstring.split(<span style="color: #A45A77">/\s/</span>, <span style="color: #666666">9</span> <span style="color: #666666">*</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> indirectLight <span style="color: #666666">=</span> Filament.IndirectLight.Builder()
.reflections(ibltex)
.irradianceSh(<span style="color: #666666">3</span>, shfloats)
.intensity(<span style="color: #666666">50000.0</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> indirectLight <span style="color: #666666">=</span> engine.createIblFromKtx(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&#x27;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>
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> sky_package <span style="color: #666666">=</span> Filament.Buffer(Filament.assets[sky_url]);
<span style="color: #008000; font-weight: bold">const</span> skyktx <span style="color: #666666">=</span> <span style="color: #AA22FF; font-weight: bold">new</span> Filament.Ktx1Bundle(sky_package);
<span style="color: #008000; font-weight: bold">const</span> skytex <span style="color: #666666">=</span> Filament.Texture.Builder()
.width(skyktx.info().pixelWidth)
.height(skyktx.info().pixelHeight)
.levels(<span style="color: #666666">1</span>)
.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)
.format(Filament.Texture$InternalFormat.RGBA8)
.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> uint8array <span style="color: #666666">=</span> skyktx.getCubeBlob(<span style="color: #666666">0</span>).getBytes();
<span style="color: #008000; font-weight: bold">const</span> pixelbuffer <span style="color: #666666">=</span> Filament.PixelBuffer(uint8array, format, datatype);
skytex.setImageCube(engine, <span style="color: #666666">0</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> skybox <span style="color: #666666">=</span> engine.createSkyFromKtx(sky_url);
scene.setSkybox(skybox);
</pre></div>
<p>That&#x27;s it, we now have a shiny red ball floating in an environment! The complete JavaScript file is
<p>That's it, we now have a shiny red ball floating in an environment! The complete JavaScript file is
available <a href="tutorial_redball.js">here</a>.</p>
<p>In the <a href="tutorial_suzanne.html">next tutorial</a>, we&#x27;ll take a closer look at textures and interaction.</p>
<p>In the <a href="tutorial_suzanne.html">next tutorial</a>, we'll take a closer look at textures and interaction.</p>
</body>
</html>
+2 -2
View File
@@ -70,10 +70,10 @@ class App {
.direction([-1, 0, 1])
.intensity(50000.0)
.build(engine, backlight);
const indirectLight = engine.createIblFromKtx1(ibl_url);
const indirectLight = engine.createIblFromKtx(ibl_url);
indirectLight.setIntensity(50000);
scene.setIndirectLight(indirectLight);
const skybox = engine.createSkyFromKtx1(sky_url);
const skybox = engine.createSkyFromKtx(sky_url);
scene.setSkybox(skybox);
this.swapChain = engine.createSwapChain();
this.renderer = engine.createRenderer();
+102 -102
View File
@@ -8,18 +8,18 @@
<div class="demo_frame"><iframe src="demo_suzanne.html"></iframe><a href="demo_suzanne.html">&#x1F517;</a></div>
<p>This tutorial will describe how to create the <strong>suzanne</strong> demo, introducing you to compressed
textures, mipmap generation, asynchronous texture loading, and trackball rotation.</p>
<p>Much like the <a href="tutorial_redball.html">previous tutorial</a>, you&#x27;ll need to use the command-line tools that can be found in
<p>Much like the <a href="tutorial_redball.html">previous tutorial</a>, you'll need to use the command-line tools that can be found in
the appropriate <a href="//github.com/google/filament/releases">Filament release</a> for your development machine. In addition to <code>matc</code> and <code>cmgen</code>,
we&#x27;ll also be using <code>filamesh</code> and <code>mipgen</code>.</p>
we'll also be using <code>filamesh</code> and <code>mipgen</code>.</p>
<h2>Create filamesh file</h2>
<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&#x27;s create a compressed filamesh file for suzanne by
called <code>filamesh</code> for simple use cases. Let's create a compressed filamesh file for suzanne by
converting <a href="https://github.com/google/filament/blob/main/assets/models/monkey/monkey.obj">this OBJ file</a>:</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>filamesh --compress monkey.obj suzanne.filamesh
</pre></div>
<h2>Create mipmapped textures</h2>
<p>Next, let&#x27;s create mipmapped KTX files using filament&#x27;s <code>mipgen</code> tool. We&#x27;ll create compressed and
<p>Next, let's create mipmapped KTX files using filament's <code>mipgen</code> tool. We'll create compressed and
non-compressed variants for each texture, since not all platforms support the same compression
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>
@@ -45,10 +45,10 @@ mipgen --grayscale ao.png ao.ktx
mipgen --grayscale --compression<span style="color: #666666">=</span>etc_r11_numeric_40 ao.png ao_etc.ktx
</pre></div>
<p>For more information on mipgen&#x27;s arguments and supported formats, do <code>mipgen --help</code>.</p>
<p>In a production setting, you&#x27;d want to invoke these commands with a script or build system.</p>
<p>For more information on mipgen's arguments and supported formats, do <code>mipgen --help</code>.</p>
<p>In a production setting, you'd want to invoke these commands with a script or build system.</p>
<h2>Bake environment map</h2>
<p>Much like the <a href="tutorial_redball.html">previous tutorial</a> we need to use Filament&#x27;s <code>cmgen</code> tool to produce cubemap files.</p>
<p>Much like the <a href="tutorial_redball.html">previous tutorial</a> we need to use Filament's <code>cmgen</code> tool to produce cubemap files.</p>
<p>Download <a href="//github.com/google/filament/blob/main/third_party/environments/venetian_crossroads_2k.hdr">venetian_crossroads_2k.hdr</a>, then invoke the following commands in your terminal.</p>
<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> -
@@ -60,7 +60,7 @@ cmgen -x . --format<span style="color: #666666">=</span>ktx --size<span style="c
<h2>Define textured material</h2>
<p>You might recall the <code>filamat</code> file we generated in the previous tutorial for red plastic. For this
demo, we&#x27;ll create a material that uses textures for several parameters.</p>
demo, we'll create a material that uses textures for several parameters.</p>
<p>Create the following text file and call it <code>textured.mat</code>. Note that our material definition now
requires a <code>uv0</code> attribute.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>material {
@@ -101,65 +101,65 @@ materials, consult the official document describing the <a href="https://google.
<p>Create a text file called <code>suzanne.html</code> and copy over the HTML that we used in the <a href="tutorial_redball.html">previous
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>=&gt;<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">&#39;canvas&#39;</span>)[<span style="color: #666666">0</span>]);<span style="color: #bbbbbb"></span>
});<span style="color: #bbbbbb"></span>
Filament.init([ filamat_url, filamesh_url, sky_small_url, ibl_url ], () =&gt; {
<span style="color: #008000">window</span>.app <span style="color: #666666">=</span> <span style="color: #AA22FF; font-weight: bold">new</span> App(<span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">&#39;canvas&#39;</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> App {
<span style="color: #008000; font-weight: bold">constructor</span>(canvas) {
<span style="color: #008000; font-weight: bold">this</span>.canvas <span style="color: #666666">=</span> canvas;
<span style="color: #008000; font-weight: bold">this</span>.engine <span style="color: #666666">=</span> Filament.Engine.create(canvas);
<span style="color: #008000; font-weight: bold">this</span>.scene <span style="color: #666666">=</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: #008000; font-weight: bold">const</span> material <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.createMaterial(filamat_url);
<span style="color: #008000; font-weight: bold">this</span>.matinstance <span style="color: #666666">=</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: #008000; font-weight: bold">const</span> filamesh <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.loadFilamesh(filamesh_url, <span style="color: #008000; font-weight: bold">this</span>.matinstance);
<span style="color: #008000; font-weight: bold">this</span>.suzanne <span style="color: #666666">=</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: #3D7B7B; font-style: italic">// TODO: create sky box and IBL</span>
<span style="color: #3D7B7B; font-style: italic">// TODO: initialize gltumble</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">&#39;resize&#39;</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">this</span>.swapChain <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.createSwapChain();
<span style="color: #008000; font-weight: bold">this</span>.renderer <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.createRenderer();
<span style="color: #008000; font-weight: bold">this</span>.camera <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.createCamera(Filament.EntityManager.get().create());
<span style="color: #008000; font-weight: bold">this</span>.view <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</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: #008000; font-weight: bold">this</span>.render <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);
<span style="color: #008000; font-weight: bold">this</span>.resize <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);
<span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">&#39;resize&#39;</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: #008000; font-weight: bold">const</span> eye <span style="color: #666666">=</span> [<span style="color: #666666">0</span>, <span style="color: #666666">0</span>, <span style="color: #666666">4</span>], center <span style="color: #666666">=</span> [<span style="color: #666666">0</span>, <span style="color: #666666">0</span>, <span style="color: #666666">0</span>], up <span style="color: #666666">=</span> [<span style="color: #666666">0</span>, <span style="color: #666666">1</span>, <span style="color: #666666">0</span>];
<span style="color: #008000; font-weight: bold">this</span>.camera.lookAt(eye, center, 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: #008000; font-weight: bold">this</span>.resize();
<span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
}
<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>
render() {
<span style="color: #3D7B7B; font-style: italic">// TODO: apply gltumble matrix</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: #008000; font-weight: bold">this</span>.view);
<span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
}
<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>
resize() {
<span style="color: #008000; font-weight: bold">const</span> dpr <span style="color: #666666">=</span> <span style="color: #008000">window</span>.devicePixelRatio;
<span style="color: #008000; font-weight: bold">const</span> width <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.canvas.width <span style="color: #666666">=</span> <span style="color: #008000">window</span>.innerWidth <span style="color: #666666">*</span> dpr;
<span style="color: #008000; font-weight: bold">const</span> height <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.canvas.height <span style="color: #666666">=</span> <span style="color: #008000">window</span>.innerHeight <span style="color: #666666">*</span> dpr;
<span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666666">0</span>, <span style="color: #666666">0</span>, width, 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">&lt;</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: #008000; font-weight: bold">const</span> aspect <span style="color: #666666">=</span> width <span style="color: #666666">/</span> height;
<span style="color: #008000; font-weight: bold">const</span> Fov <span style="color: #666666">=</span> Filament.Camera$Fov, fov <span style="color: #666666">=</span> aspect <span style="color: #666666">&lt;</span> <span style="color: #666666">1</span> <span style="color: #666666">?</span> Fov.HORIZONTAL <span style="color: #666666">:</span> Fov.VERTICAL;
<span style="color: #008000; font-weight: bold">this</span>.camera.setProjectionFov(<span style="color: #666666">45</span>, aspect, <span style="color: #666666">1.0</span>, <span style="color: #666666">10.0</span>, fov);
}
}
</pre></div>
<p>Our app will only require a subset of assets to be present for <code>App</code> construction. We&#x27;ll download
<p>Our app will only require a subset of assets to be present for <code>App</code> construction. We'll download
the other assets after construction. By using a progressive loading strategy, we can reduce the
perceived load time.</p>
<p>Next we need to supply the URLs for various assets. This is actually a bit tricky, because different
@@ -172,65 +172,65 @@ 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">&#39;astc s3tc_srgb&#39;</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">&#39;etc&#39;</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> albedo_suffix <span style="color: #666666">=</span> Filament.getSupportedFormatSuffix(<span style="color: #BA2121">&#39;astc s3tc_srgb&#39;</span>);
<span style="color: #008000; font-weight: bold">const</span> texture_suffix <span style="color: #666666">=</span> Filament.getSupportedFormatSuffix(<span style="color: #BA2121">&#39;etc&#39;</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">&#39;venetian_crossroads_2k&#39;</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">&#39;textured.filamat&#39;</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">&#39;suzanne.filamesh&#39;</span>;<span style="color: #bbbbbb"></span>
<span style="color: #008000; font-weight: bold">const</span> environ <span style="color: #666666">=</span> <span style="color: #BA2121">&#39;venetian_crossroads_2k&#39;</span>
<span style="color: #008000; font-weight: bold">const</span> ibl_url <span style="color: #666666">=</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> sky_small_url <span style="color: #666666">=</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> sky_large_url <span style="color: #666666">=</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> albedo_url <span style="color: #666666">=</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> ao_url <span style="color: #666666">=</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> metallic_url <span style="color: #666666">=</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> normal_url <span style="color: #666666">=</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> roughness_url <span style="color: #666666">=</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> filamat_url <span style="color: #666666">=</span> <span style="color: #BA2121">&#39;textured.filamat&#39;</span>;
<span style="color: #008000; font-weight: bold">const</span> filamesh_url <span style="color: #666666">=</span> <span style="color: #BA2121">&#39;suzanne.filamesh&#39;</span>;
</pre></div>
<h2>Create skybox and IBL</h2>
<p>Next, let&#x27;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>
<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: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.createSkyFromKtx(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: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.createIblFromKtx(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
loading in.</p>
<h2>Fetch assets asychronously</h2>
<p>Next we&#x27;ll invoke the <code>Filament.fetch</code> function from within the app constructor. This function is
<p>Next we'll invoke the <code>Filament.fetch</code> function from within the app constructor. This function is
very similar to <code>Filament.init</code>. It takes a list of asset URLs and a callback function that triggers
when the assets have finished downloading.</p>
<p>In our callback, we&#x27;ll make several <code>setTextureParameter</code> calls on the material instance, then we&#x27;ll
<p>In our callback, we'll make several <code>setTextureParameter</code> calls on the material instance, then we'll
recreate the skybox using a higher-resolution texture. As a last step we unhide the renderable that
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>=&gt;<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, albedo_url, roughness_url, metallic_url, normal_url, ao_url], () =&gt; {
<span style="color: #008000; font-weight: bold">const</span> albedo <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx(albedo_url, {srgb<span style="color: #666666">:</span> <span style="color: #008000; font-weight: bold">true</span>});
<span style="color: #008000; font-weight: bold">const</span> roughness <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx(roughness_url);
<span style="color: #008000; font-weight: bold">const</span> metallic <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx(metallic_url);
<span style="color: #008000; font-weight: bold">const</span> normal <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx(normal_url);
<span style="color: #008000; font-weight: bold">const</span> ao <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx(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: #008000; font-weight: bold">const</span> sampler <span style="color: #666666">=</span> <span style="color: #AA22FF; font-weight: bold">new</span> Filament.TextureSampler(
Filament.MinFilter.LINEAR_MIPMAP_LINEAR,
Filament.MagFilter.LINEAR,
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">&#39;albedo&#39;</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">&#39;roughness&#39;</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">&#39;metallic&#39;</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">&#39;normal&#39;</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">&#39;ao&#39;</span>,<span style="color: #bbbbbb"> </span>ao,<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">&#39;albedo&#39;</span>, albedo, sampler);
<span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">&#39;roughness&#39;</span>, roughness, sampler);
<span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">&#39;metallic&#39;</span>, metallic, sampler);
<span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">&#39;normal&#39;</span>, normal, sampler);
<span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">&#39;ao&#39;</span>, ao, 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: #3D7B7B; font-style: italic">// Replace low-res skybox with high-res skybox.</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: #008000; font-weight: bold">this</span>.skybox <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.createSkyFromKtx(sky_large_url);
<span style="color: #008000; font-weight: bold">this</span>.scene.setSkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox);
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.scene.addEntity(<span style="color: #008000; font-weight: bold">this</span>.suzanne);<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,16 +241,16 @@ 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: #666666">=</span> <span style="color: #AA22FF; font-weight: bold">new</span> Trackball(canvas, {startSpin<span style="color: #666666">:</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> tcm <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.getTransformManager();
<span style="color: #008000; font-weight: bold">const</span> inst <span style="color: #666666">=</span> tcm.getInstance(<span style="color: #008000; font-weight: bold">this</span>.suzanne);
tcm.setTransform(inst, <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&#x27;s it, we now have a fast-loading interactive demo. The complete JavaScript file is available
<p>That's it, we now have a fast-loading interactive demo. The complete JavaScript file is available
<a href="tutorial_suzanne.js">here</a>.</p>
</body>
+8 -8
View File
@@ -23,9 +23,9 @@ class App {
this.matinstance = material.createInstance();
const filamesh = this.engine.loadFilamesh(filamesh_url, this.matinstance);
this.suzanne = filamesh.renderable;
this.skybox = this.engine.createSkyFromKtx1(sky_small_url);
this.skybox = this.engine.createSkyFromKtx(sky_small_url);
this.scene.setSkybox(this.skybox);
this.indirectLight = this.engine.createIblFromKtx1(ibl_url);
this.indirectLight = this.engine.createIblFromKtx(ibl_url);
this.indirectLight.setIntensity(100000);
this.scene.setIndirectLight(this.indirectLight);
this.trackball = new Trackball(canvas, {
@@ -33,13 +33,13 @@ class App {
});
Filament.fetch([sky_large_url, albedo_url, roughness_url, metallic_url, normal_url, ao_url],
() => {
const albedo = this.engine.createTextureFromKtx1(albedo_url, {
const albedo = this.engine.createTextureFromKtx(albedo_url, {
srgb: true
});
const roughness = this.engine.createTextureFromKtx1(roughness_url);
const metallic = this.engine.createTextureFromKtx1(metallic_url);
const normal = this.engine.createTextureFromKtx1(normal_url);
const ao = this.engine.createTextureFromKtx1(ao_url);
const roughness = this.engine.createTextureFromKtx(roughness_url);
const metallic = this.engine.createTextureFromKtx(metallic_url);
const normal = this.engine.createTextureFromKtx(normal_url);
const ao = this.engine.createTextureFromKtx(ao_url);
const sampler = new Filament.TextureSampler(Filament.MinFilter.LINEAR_MIPMAP_LINEAR,
Filament.MagFilter.LINEAR, Filament.WrapMode.CLAMP_TO_EDGE);
this.matinstance.setTextureParameter('albedo', albedo, sampler);
@@ -49,7 +49,7 @@ class App {
this.matinstance.setTextureParameter('ao', ao, sampler);
// Replace low-res skybox with high-res skybox.
this.engine.destroySkybox(this.skybox);
this.skybox = this.engine.createSkyFromKtx1(sky_large_url);
this.skybox = this.engine.createSkyFromKtx(sky_large_url);
this.scene.setSkybox(this.skybox);
this.scene.addEntity(this.suzanne);
});
+97 -97
View File
@@ -8,9 +8,9 @@
<div class="demo_frame"><iframe src="demo_triangle.html"></iframe><a href="demo_triangle.html">&#x1F517;</a></div>
<h2>Literate programming</h2>
<p>The markdown source for this tutorial is not only used to generate this
web page, it&#x27;s also used to generate the JavaScript for the above demo.
web page, it's also used to generate the JavaScript for the above demo.
We use a small Python script for weaving (generating HTML) and tangling
(generating JS). In the code samples, you&#x27;ll often see
(generating JS). In the code samples, you'll often see
<code>// TODO: &lt;some task&gt;</code>. These are special markers that get replaced by
subsequent code blocks.</p>
<h2>Start your project</h2>
@@ -48,36 +48,36 @@ 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">&#39;resize&#39;</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> App {
<span style="color: #008000; font-weight: bold">constructor</span>() {
<span style="color: #3D7B7B; font-style: italic">// TODO: create entities</span>
<span style="color: #008000; font-weight: bold">this</span>.render <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);
<span style="color: #008000; font-weight: bold">this</span>.resize <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);
<span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">&#39;resize&#39;</span>, <span style="color: #008000; font-weight: bold">this</span>.resize);
<span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
}
render() {
<span style="color: #3D7B7B; font-style: italic">// TODO: render scene</span>
<span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
}
resize() {
<span style="color: #3D7B7B; font-style: italic">// TODO: adjust viewport and canvas</span>
}
}
Filament.init([<span style="color: #BA2121">&#39;triangle.filamat&#39;</span>],<span style="color: #bbbbbb"> </span>()<span style="color: #bbbbbb"> </span>=&gt;<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">&#39;triangle.filamat&#39;</span>], () =&gt; { <span style="color: #008000">window</span>.app <span style="color: #666666">=</span> <span style="color: #AA22FF; font-weight: bold">new</span> App() } );
</pre></div>
<p>The two calls to <code>bind()</code> allow us to pass instance methods as callbacks for animation and resize
events.</p>
<p><code>Filament.init()</code> consumes two things: a list of asset URLs and a callback.</p>
<p>The callback will be triggered only after all assets finish downloading and the Filament module has
become ready. In our callback, we simply instantiated the <code>App</code> object, since we&#x27;ll do most of the
become ready. In our callback, we simply instantiated the <code>App</code> object, since we'll do most of the
work in its constructor. We also set the app instance into a <code>Window</code> property to make it accessible
from the developer console.</p>
<p>Go ahead and download <a href="triangle.filamat">triangle.filamat</a> and place it in your project folder.
This is a <em>material package</em>, which is a binary file that contains shaders and other bits of data
that define a PBR material. We&#x27;ll learn more about material packages in the next tutorial.</p>
that define a PBR material. We'll learn more about material packages in the next tutorial.</p>
<h2>Spawn a local server</h2>
<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>
@@ -88,23 +88,23 @@ npx http-server -p <span style="color: #666666">8000</span> <span style="colo
<p>To see if this works, navigate to <a href="http://localhost:8000">http://localhost:8000</a> and check if you
can load the page without any errors appearing in the developer console.</p>
<p>Take care not to use Python&#x27;s simple server in production since it does not serve WebAssembly files
<p>Take care not to use Python's simple server in production since it does not serve WebAssembly files
with the correct MIME type.</p>
<h2>Create the Engine and Scene</h2>
<p>We now have a basic skeleton that can respond to paint and resize events. Let&#x27;s start adding
<p>We now have a basic skeleton that can respond to paint and resize events. Let's start adding
Filament objects to the app. Insert the following code into the top of the app constructor.</p>
<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">&#39;canvas&#39;</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: #666666">=</span> <span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">&#39;canvas&#39;</span>)[<span style="color: #666666">0</span>];
<span style="color: #008000; font-weight: bold">const</span> engine <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine <span style="color: #666666">=</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
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&#x27;s go ahead and create a scene, then add a blank entity called <code>triangle</code> into the
entities. Let's go ahead and create a scene, then add a blank entity called <code>triangle</code> into the
scene.</p>
<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: #666666">=</span> engine.createScene();
<span style="color: #008000; font-weight: bold">this</span>.triangle <span style="color: #666666">=</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>.
@@ -112,30 +112,30 @@ The triangle entity in the above snippet does not yet have an associated compone
tutorial we will make it into a <em>renderable</em>. Renderables are entities that have associated draw
calls.</p>
<h2>Construct typed arrays</h2>
<p>Next we&#x27;ll create two typed arrays: a positions array with XY coordinates for each vertex, and a
<p>Next we'll create two typed arrays: a positions array with XY coordinates for each vertex, and a
colors array with a 32-bit word for each vertex.</p>
<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> TRIANGLE_POSITIONS <span style="color: #666666">=</span> <span style="color: #AA22FF; font-weight: bold">new</span> <span style="color: #008000">Float32Array</span>([
<span style="color: #666666">1</span>, <span style="color: #666666">0</span>,
<span style="color: #008000">Math</span>.cos(<span style="color: #008000">Math</span>.PI <span style="color: #666666">*</span> <span style="color: #666666">2</span> <span style="color: #666666">/</span> <span style="color: #666666">3</span>), <span style="color: #008000">Math</span>.sin(<span style="color: #008000">Math</span>.PI <span style="color: #666666">*</span> <span style="color: #666666">2</span> <span style="color: #666666">/</span> <span style="color: #666666">3</span>),
<span style="color: #008000">Math</span>.cos(<span style="color: #008000">Math</span>.PI <span style="color: #666666">*</span> <span style="color: #666666">4</span> <span style="color: #666666">/</span> <span style="color: #666666">3</span>), <span style="color: #008000">Math</span>.sin(<span style="color: #008000">Math</span>.PI <span style="color: #666666">*</span> <span style="color: #666666">4</span> <span style="color: #666666">/</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> TRIANGLE_COLORS <span style="color: #666666">=</span> <span style="color: #AA22FF; font-weight: bold">new</span> <span style="color: #008000">Uint32Array</span>([<span style="color: #666666">0xffff0000</span>, <span style="color: #666666">0xff00ff00</span>, <span style="color: #666666">0xff0000ff</span>]);
</pre></div>
<p>Next we&#x27;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>
<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> VertexAttribute <span style="color: #666666">=</span> Filament.VertexAttribute;
<span style="color: #008000; font-weight: bold">const</span> AttributeType <span style="color: #666666">=</span> Filament.VertexBuffer$AttributeType;
<span style="color: #008000; font-weight: bold">this</span>.vb <span style="color: #666666">=</span> Filament.VertexBuffer.Builder()
.vertexCount(<span style="color: #666666">3</span>)
.bufferCount(<span style="color: #666666">2</span>)
.attribute(VertexAttribute.POSITION, <span style="color: #666666">0</span>, AttributeType.FLOAT2, <span style="color: #666666">0</span>, <span style="color: #666666">8</span>)
.attribute(VertexAttribute.COLOR, <span style="color: #666666">1</span>, AttributeType.UBYTE4, <span style="color: #666666">0</span>, <span style="color: #666666">4</span>)
.normalized(VertexAttribute.COLOR)
.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: #666666">0</span>, TRIANGLE_POSITIONS);
<span style="color: #008000; font-weight: bold">this</span>.vb.setBufferAt(engine, <span style="color: #666666">1</span>, TRIANGLE_COLORS);
</pre></div>
<p>The above snippet first creates aliases for two enum types, then constructs the vertex buffer using
@@ -147,74 +147,74 @@ self-documenting.</p>
<p>Our app sets up two buffer slots in the vertex buffer, and each slot is associated with a single
attribute. Alternatively, we could have interleaved or concatenated these attributes into a single
buffer slot.</p>
<p>Next we&#x27;ll construct an index buffer. The index buffer for our triangle is trivial: it simply holds
<p>Next we'll construct an index buffer. The index buffer for our triangle is trivial: it simply holds
the integers 0,1,2.</p>
<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: #666666">=</span> Filament.IndexBuffer.Builder()
.indexCount(<span style="color: #666666">3</span>)
.bufferType(Filament.IndexBuffer$IndexType.USHORT)
.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: #AA22FF; font-weight: bold">new</span> <span style="color: #008000">Uint16Array</span>([<span style="color: #666666">0</span>, <span style="color: #666666">1</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
one buffer slot, and it can only contain two types of data (USHORT or UINT).</p>
<h2>Finish up initialization</h2>
<p>Next let&#x27;s construct an actual <code>Material</code> from the material package that was downloaded (the
<p>Next let's construct an actual <code>Material</code> from the material package that was downloaded (the
material is an object; the package is just a binary blob), then extract the default
<code>MaterialInstance</code> from the material object. Material instances have concrete values for their
parameters, and they can be bound to renderables. We&#x27;ll learn more about material instances in the
parameters, and they can be bound to renderables. We'll learn more about material instances in the
next tutorial.</p>
<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">&#39;triangle.filamat&#39;</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> mat <span style="color: #666666">=</span> engine.createMaterial(<span style="color: #BA2121">&#39;triangle.filamat&#39;</span>);
<span style="color: #008000; font-weight: bold">const</span> matinst <span style="color: #666666">=</span> mat.getDefaultInstance();
Filament.RenderableManager.Builder(<span style="color: #666666">1</span>)
.boundingBox({ center<span style="color: #666666">:</span> [<span style="color: #666666">-1</span>, <span style="color: #666666">-1</span>, <span style="color: #666666">-1</span>], halfExtent<span style="color: #666666">:</span> [<span style="color: #666666">1</span>, <span style="color: #666666">1</span>, <span style="color: #666666">1</span>] })
.material(<span style="color: #666666">0</span>, matinst)
.geometry(<span style="color: #666666">0</span>, Filament.RenderableManager$PrimitiveType.TRIANGLES, <span style="color: #008000; font-weight: bold">this</span>.vb, <span style="color: #008000; font-weight: bold">this</span>.ib)
.build(engine, <span style="color: #008000; font-weight: bold">this</span>.triangle);
</pre></div>
<p>Next let&#x27;s wrap up the initialization routine by creating the swap chain, renderer, camera, and
<p>Next let's wrap up the initialization routine by creating the swap chain, renderer, camera, and
view.</p>
<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: #666666">=</span> engine.createSwapChain();
<span style="color: #008000; font-weight: bold">this</span>.renderer <span style="color: #666666">=</span> engine.createRenderer();
<span style="color: #008000; font-weight: bold">this</span>.camera <span style="color: #666666">=</span> engine.createCamera(Filament.EntityManager.get().create());
<span style="color: #008000; font-weight: bold">this</span>.view <span style="color: #666666">=</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: #666666">0.0</span>, <span style="color: #666666">0.1</span>, <span style="color: #666666">0.2</span>, <span style="color: #666666">1.0</span>], clear<span style="color: #666666">:</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&#x27;re done creating all Filament entities, and the code should run without errors.
<p>At this point, we're done creating all Filament entities, and the code should run without errors.
However the canvas is still blank!</p>
<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: #3D7B7B; font-style: italic">// TODO: render scene</span>
<span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
}
</pre></div>
<p>Let&#x27;s flesh this out by rotating the triangle and invoking the Filament renderer. Add the following
<p>Let's flesh this out by rotating the triangle and invoking the Filament renderer. Add the following
code to the top of the render method.</p>
<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> radians <span style="color: #666666">=</span> <span style="color: #008000">Date</span>.now() <span style="color: #666666">/</span> <span style="color: #666666">1000</span>;
<span style="color: #008000; font-weight: bold">const</span> transform <span style="color: #666666">=</span> mat4.fromRotation(mat4.create(), radians, [<span style="color: #666666">0</span>, <span style="color: #666666">0</span>, <span style="color: #666666">1</span>]);
<span style="color: #008000; font-weight: bold">const</span> tcm <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.getTransformManager();
<span style="color: #008000; font-weight: bold">const</span> inst <span style="color: #666666">=</span> tcm.getInstance(<span style="color: #008000; font-weight: bold">this</span>.triangle);
tcm.setTransform(inst, 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: #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,19 +225,19 @@ that it wants to skip a frame, hence the <code>if</code> statement.</p>
<p>One last step. Add the following code to the resize method. This adjusts the resolution of the
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> dpr <span style="color: #666666">=</span> <span style="color: #008000">window</span>.devicePixelRatio;
<span style="color: #008000; font-weight: bold">const</span> width <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.canvas.width <span style="color: #666666">=</span> <span style="color: #008000">window</span>.innerWidth <span style="color: #666666">*</span> dpr;
<span style="color: #008000; font-weight: bold">const</span> height <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.canvas.height <span style="color: #666666">=</span> <span style="color: #008000">window</span>.innerHeight <span style="color: #666666">*</span> dpr;
<span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666666">0</span>, <span style="color: #666666">0</span>, width, 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> aspect <span style="color: #666666">=</span> width <span style="color: #666666">/</span> height;
<span style="color: #008000; font-weight: bold">const</span> Projection <span style="color: #666666">=</span> Filament.Camera$Projection;
<span style="color: #008000; font-weight: bold">this</span>.camera.setProjection(Projection.ORTHO, <span style="color: #666666">-</span>aspect, aspect, <span style="color: #666666">-1</span>, <span style="color: #666666">1</span>, <span style="color: #666666">0</span>, <span style="color: #666666">1</span>);
</pre></div>
<p>You should now have a spinning triangle! The completed JavaScript is available
<a href="tutorial_triangle.js">here</a>.</p>
<p>In the <a href="tutorial_redball.html">next tutorial</a>, we&#x27;ll take a closer look at Filament materials and 3D rendering.</p>
<p>In the <a href="tutorial_redball.html">next tutorial</a>, we'll take a closer look at Filament materials and 3D rendering.</p>
</body>
</html>
+9 -6
View File
@@ -17,7 +17,6 @@ set(PUBLIC_HDRS
include/filament/Camera.h
include/filament/Color.h
include/filament/ColorGrading.h
include/filament/ColorSpace.h
include/filament/DebugRegistry.h
include/filament/Engine.h
include/filament/Exposure.h
@@ -49,12 +48,11 @@ set(PUBLIC_HDRS
)
set(SRCS
src/AtlasAllocator.cpp
src/Box.cpp
src/BufferObject.cpp
src/Camera.cpp
src/Color.cpp
src/ColorSpaceUtils.cpp
src/ColorSpace.cpp
src/Culler.cpp
src/DFG.cpp
src/DebugRegistry.cpp
@@ -74,7 +72,6 @@ set(SRCS
src/MaterialParser.cpp
src/MorphTargetBuffer.cpp
src/PerViewUniforms.cpp
src/PerShadowMapUniforms.cpp
src/PostProcessManager.cpp
src/RenderPass.cpp
src/RenderPrimitive.cpp
@@ -136,7 +133,7 @@ set(SRCS
set(PRIVATE_HDRS
src/Allocators.h
src/BufferPoolAllocator.h
src/ColorSpaceUtils.h
src/ColorSpace.h
src/Culler.h
src/DFG.h
src/FilamentAPI-impl.h
@@ -148,7 +145,6 @@ set(PRIVATE_HDRS
src/Intersections.h
src/MaterialParser.h
src/PerViewUniforms.h
src/PerShadowMapUniforms.h
src/PIDController.h
src/PostProcessManager.h
src/RendererUtils.h
@@ -541,6 +537,13 @@ target_link_libraries(${TARGET} PUBLIC filaflat)
target_link_libraries(${TARGET} PUBLIC filabridge)
target_link_libraries(${TARGET} PUBLIC ibl-lite)
if (FILAMENT_ENABLE_FGDBG)
target_link_libraries(${TARGET} PUBLIC fgdbg)
add_definitions(-DFILAMENT_ENABLE_FGDBG=1)
else()
add_definitions(-DFILAMENT_ENABLE_FGDBG=0)
endif()
if (FILAMENT_ENABLE_MATDBG)
target_link_libraries(${TARGET} PUBLIC matdbg)
add_definitions(-DFILAMENT_ENABLE_MATDBG=1)
-1
View File
@@ -405,7 +405,6 @@ if (APPLE)
backend
getopt
gtest
filamat
SPIRV
spirv-cross-glsl)
+4 -37
View File
@@ -220,7 +220,8 @@ enum class PrimitiveType : uint8_t {
LINES = 1, //!< lines
LINE_STRIP = 3, //!< line strip
TRIANGLES = 4, //!< triangles
TRIANGLE_STRIP = 5 //!< triangle strip
TRIANGLE_STRIP = 5, //!< triangle strip
NONE = 0xFF
};
/**
@@ -398,18 +399,6 @@ enum class CompressedPixelDataType : uint16_t {
SRGB8_ALPHA8_ASTC_10x10,
SRGB8_ALPHA8_ASTC_12x10,
SRGB8_ALPHA8_ASTC_12x12,
// RGTC formats available with a GLES extension
RED_RGTC1, // BC4 unsigned
SIGNED_RED_RGTC1, // BC4 signed
RED_GREEN_RGTC2, // BC5 unsigned
SIGNED_RED_GREEN_RGTC2, // BC5 signed
// BPTC formats available with a GLES extension
RGB_BPTC_SIGNED_FLOAT, // BC6H signed
RGB_BPTC_UNSIGNED_FLOAT,// BC6H unsigned
RGBA_BPTC_UNORM, // BC7
SRGB_ALPHA_BPTC_UNORM, // BC7 sRGB
};
/** Supported texel formats
@@ -564,18 +553,6 @@ enum class TextureFormat : uint16_t {
SRGB8_ALPHA8_ASTC_10x10,
SRGB8_ALPHA8_ASTC_12x10,
SRGB8_ALPHA8_ASTC_12x12,
// RGTC formats available with a GLES extension
RED_RGTC1, // BC4 unsigned
SIGNED_RED_RGTC1, // BC4 signed
RED_GREEN_RGTC2, // BC5 unsigned
SIGNED_RED_GREEN_RGTC2, // BC5 signed
// BPTC formats available with a GLES extension
RGB_BPTC_SIGNED_FLOAT, // BC6H signed
RGB_BPTC_UNSIGNED_FLOAT,// BC6H unsigned
RGBA_BPTC_UNORM, // BC7
SRGB_ALPHA_BPTC_UNORM, // BC7 sRGB
};
//! Bitmask describing the intended Texture Usage
@@ -656,7 +633,7 @@ static constexpr bool isSignedIntFormat(TextureFormat format) {
}
}
//! returns whether this format is a compressed format
//! returns whether this format a compressed format
static constexpr bool isCompressedFormat(TextureFormat format) noexcept {
return format >= TextureFormat::EAC_R11;
}
@@ -666,7 +643,7 @@ static constexpr bool isETC2Compression(TextureFormat format) noexcept {
return format >= TextureFormat::EAC_R11 && format <= TextureFormat::ETC2_EAC_SRGBA8;
}
//! returns whether this format is an S3TC compressed format
//! returns whether this format is an ETC3 compressed format
static constexpr bool isS3TCCompression(TextureFormat format) noexcept {
return format >= TextureFormat::DXT1_RGB && format <= TextureFormat::DXT5_SRGBA;
}
@@ -675,16 +652,6 @@ static constexpr bool isS3TCSRGBCompression(TextureFormat format) noexcept {
return format >= TextureFormat::DXT1_SRGB && format <= TextureFormat::DXT5_SRGBA;
}
//! returns whether this format is an RGTC compressed format
static constexpr bool isRGTCCompression(TextureFormat format) noexcept {
return format >= TextureFormat::RED_RGTC1 && format <= TextureFormat::SIGNED_RED_GREEN_RGTC2;
}
//! returns whether this format is an BPTC compressed format
static constexpr bool isBPTCCompression(TextureFormat format) noexcept {
return format >= TextureFormat::RGB_BPTC_SIGNED_FLOAT && format <= TextureFormat::SRGB_ALPHA_BPTC_UNORM;
}
static constexpr bool isASTCCompression(TextureFormat format) noexcept {
return format >= TextureFormat::RGBA_ASTC_4x4 && format <= TextureFormat::SRGB8_ALPHA8_ASTC_12x12;
}
+2 -37
View File
@@ -29,7 +29,7 @@ bool requestsGoogleLineDirectivesExtension(std::string_view source) noexcept {
}
void removeGoogleLineDirectives(char* shader, size_t length) noexcept {
std::string_view const s{ shader, length };
std::string_view s(shader, length);
size_t pos = 0;
while (true) {
@@ -173,20 +173,6 @@ size_t getFormatSize(TextureFormat format) noexcept {
case TextureFormat::DXT5_SRGBA:
return 16;
case TextureFormat::RED_RGTC1:
case TextureFormat::SIGNED_RED_RGTC1:
return 8;
case TextureFormat::RED_GREEN_RGTC2:
case TextureFormat::SIGNED_RED_GREEN_RGTC2:
return 16;
case TextureFormat::RGB_BPTC_SIGNED_FLOAT:
case TextureFormat::RGB_BPTC_UNSIGNED_FLOAT:
case TextureFormat::RGBA_BPTC_UNORM:
case TextureFormat::SRGB_ALPHA_BPTC_UNORM:
return 16;
// The block size for ASTC compression is always 16 bytes.
case TextureFormat::RGBA_ASTC_4x4:
case TextureFormat::RGBA_ASTC_5x4:
@@ -290,22 +276,16 @@ size_t getFormatComponentCount(TextureFormat format) noexcept {
// Compressed formats ---------------------------------------------------------------------
case TextureFormat::EAC_R11:
case TextureFormat::EAC_R11_SIGNED:
case TextureFormat::RED_RGTC1:
case TextureFormat::SIGNED_RED_RGTC1:
return 1;
case TextureFormat::EAC_RG11:
case TextureFormat::EAC_RG11_SIGNED:
case TextureFormat::RED_GREEN_RGTC2:
case TextureFormat::SIGNED_RED_GREEN_RGTC2:
return 2;
case TextureFormat::ETC2_RGB8:
case TextureFormat::ETC2_SRGB8:
case TextureFormat::DXT1_RGB:
case TextureFormat::DXT1_SRGB:
case TextureFormat::RGB_BPTC_SIGNED_FLOAT:
case TextureFormat::RGB_BPTC_UNSIGNED_FLOAT:
return 3;
case TextureFormat::ETC2_EAC_RGBA8:
@@ -318,8 +298,6 @@ size_t getFormatComponentCount(TextureFormat format) noexcept {
case TextureFormat::DXT3_SRGBA:
case TextureFormat::DXT5_RGBA:
case TextureFormat::DXT5_SRGBA:
case TextureFormat::RGBA_BPTC_UNORM:
case TextureFormat::SRGB_ALPHA_BPTC_UNORM:
case TextureFormat::RGBA_ASTC_4x4:
case TextureFormat::RGBA_ASTC_5x4:
case TextureFormat::RGBA_ASTC_5x5:
@@ -378,18 +356,6 @@ size_t getBlockWidth(TextureFormat format) noexcept {
case TextureFormat::DXT5_SRGBA:
return 4;
case TextureFormat::RED_RGTC1:
case TextureFormat::SIGNED_RED_RGTC1:
case TextureFormat::RED_GREEN_RGTC2:
case TextureFormat::SIGNED_RED_GREEN_RGTC2:
return 4;
case TextureFormat::RGB_BPTC_SIGNED_FLOAT:
case TextureFormat::RGB_BPTC_UNSIGNED_FLOAT:
case TextureFormat::RGBA_BPTC_UNORM:
case TextureFormat::SRGB_ALPHA_BPTC_UNORM:
return 4;
case TextureFormat::RGBA_ASTC_4x4:
case TextureFormat::SRGB8_ALPHA8_ASTC_4x4:
return 4;
@@ -489,8 +455,7 @@ bool reshape(const PixelBufferDescriptor& data, PixelBufferDescriptor& reshaped)
return false;
}
const auto freeFunc = [](void* buffer,
UTILS_UNUSED size_t size, UTILS_UNUSED void* user) { free(buffer); };
const auto freeFunc = [](void* buffer, size_t size, void* user) { free(buffer); };
const size_t reshapedSize = 4 * data.size / 3;
const PixelDataFormat reshapedFormat =
data.format == PixelDataFormat::RGB ? PixelDataFormat::RGBA : PixelDataFormat::RGBA_INTEGER;
+4 -2
View File
@@ -19,7 +19,8 @@
#include <utils/Panic.h>
#include <utils/debug.h>
namespace filament::backend {
namespace filament {
namespace backend {
PresentCallable::PresentCallable(PresentFn fn, void* user) noexcept
: mPresentFn(fn), mUser(user) {
@@ -34,4 +35,5 @@ void PresentCallable::operator()(bool presentFrame) noexcept {
mPresentFn = nullptr;
}
} // namespace filament::backend
} // namespace backend
} // namespace filament
+1 -1
View File
@@ -62,7 +62,7 @@ void* CircularBuffer::alloc(size_t size) noexcept {
void* vaddr = MAP_FAILED;
void* vaddr_shadow = MAP_FAILED;
void* vaddr_guard = MAP_FAILED;
int const fd = ashmem_create_region("filament::CircularBuffer", size + BLOCK_SIZE);
int fd = ashmem_create_region("filament::CircularBuffer", size + BLOCK_SIZE);
if (fd >= 0) {
// reserve/find enough address space
void* reserve_vaddr = mmap(nullptr, size * 2 + BLOCK_SIZE,
+8 -6
View File
@@ -26,7 +26,8 @@
using namespace utils;
namespace filament::backend {
namespace filament {
namespace backend {
CommandBufferQueue::CommandBufferQueue(size_t requiredSize, size_t bufferSize)
: mRequiredSize((requiredSize + CircularBuffer::BLOCK_MASK) & ~CircularBuffer::BLOCK_MASK),
@@ -40,13 +41,13 @@ CommandBufferQueue::~CommandBufferQueue() {
}
void CommandBufferQueue::requestExit() {
std::lock_guard<utils::Mutex> const lock(mLock);
std::lock_guard<utils::Mutex> lock(mLock);
mExitRequested = EXIT_REQUESTED;
mCondition.notify_one();
}
bool CommandBufferQueue::isExitRequested() const {
std::lock_guard<utils::Mutex> const lock(mLock);
std::lock_guard<utils::Mutex> lock(mLock);
ASSERT_PRECONDITION( mExitRequested == 0 || mExitRequested == EXIT_REQUESTED,
"mExitRequested is corrupted (value = 0x%08x)!", mExitRequested);
return (bool)mExitRequested;
@@ -72,7 +73,7 @@ void CommandBufferQueue::flush() noexcept {
void* const tail = circularBuffer.getTail();
// size of this slice
uint32_t const used = uint32_t(intptr_t(head) - intptr_t(tail));
uint32_t used = uint32_t(intptr_t(head) - intptr_t(tail));
circularBuffer.circularize();
@@ -124,9 +125,10 @@ std::vector<CommandBufferQueue::Slice> CommandBufferQueue::waitForCommands() con
}
void CommandBufferQueue::releaseBuffer(CommandBufferQueue::Slice const& buffer) {
std::lock_guard<utils::Mutex> const lock(mLock);
std::lock_guard<utils::Mutex> lock(mLock);
mFreeSpace += uintptr_t(buffer.end) - uintptr_t(buffer.begin);
mCondition.notify_one();
}
} // namespace filament::backend
} // namespace backend
} // namespace filament
+2 -5
View File
@@ -16,10 +16,7 @@
#include "private/backend/CommandStream.h"
#if DEBUG_COMMAND_STREAM
#include <utils/CallStack.h>
#endif
#include <utils/Log.h>
#include <utils/Profiler.h>
#include <utils/Systrace.h>
@@ -37,7 +34,7 @@ namespace filament::backend {
// ------------------------------------------------------------------------------------------------
// A few utility functions for debugging...
inline void printParameterPack(io::ostream&) { }
inline void printParameterPack(io::ostream& out) { }
template<typename LAST>
static void printParameterPack(io::ostream& out, const LAST& t) { out << t; }
@@ -98,7 +95,7 @@ void CommandStream::execute(void* buffer) {
if (UTILS_UNLIKELY(mUsePerformanceCounter)) {
// we want to remove all this when tracing is completely disabled
profiler.stop();
UTILS_UNUSED Profiler::Counters const counters = profiler.readCounters();
UTILS_UNUSED Profiler::Counters counters = profiler.readCounters();
SYSTRACE_VALUE32("GLThread (I)", counters.getInstructions());
SYSTRACE_VALUE32("GLThread (C)", counters.getCpuCycles());
SYSTRACE_VALUE32("GLThread (CPI x10)", counters.getCPI() * 10);
+2 -6
View File
@@ -42,9 +42,7 @@
#include "vulkan/PlatformVkCocoa.h"
#endif
#elif defined(__linux__)
#if defined(FILAMENT_SUPPORTS_GGP)
#include "vulkan/PlatformVkLinuxGGP.h"
#elif defined(FILAMENT_SUPPORTS_WAYLAND)
#if defined(FILAMENT_SUPPORTS_WAYLAND)
#if defined (FILAMENT_DRIVER_SUPPORTS_VULKAN)
#include "vulkan/PlatformVkLinuxWayland.h"
#endif
@@ -122,9 +120,7 @@ DefaultPlatform* DefaultPlatform::create(Backend* backend) noexcept {
#elif defined(IOS)
return new PlatformVkCocoaTouch();
#elif defined(__linux__)
#if defined(FILAMENT_SUPPORTS_GGP)
return new PlatformVkLinuxGGP();
#elif defined(FILAMENT_SUPPORTS_WAYLAND)
#if defined(FILAMENT_SUPPORTS_WAYLAND)
return new PlatformVkLinuxWayland();
#elif defined(FILAMENT_SUPPORTS_X11)
return new PlatformVkLinuxX11();
@@ -91,14 +91,12 @@ blitterFrag(VertexOut in [[stage_in]],
{
FragmentOut out = {};
#if defined(BLIT_COLOR) || defined(BLIT_DEPTH)
// These coordinates match the Vulkan vkCmdBlitImage spec:
// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkCmdBlitImage.html
float2 uvbase = in.position.xy; // unnormalized coordinates at center of texel: (1.5, 2.5, etc)
float2 uvoffset = uvbase - args->dstOffset;
float2 uvscaled = uvoffset * args->scale;
float2 uv = uvscaled + args->srcOffset;
#endif
#ifdef BLIT_COLOR
#ifdef MSAA_COLOR_SOURCE
@@ -64,7 +64,6 @@ struct MetalContext {
// Supported features.
bool supportsTextureSwizzling = false;
bool supportsAutoDepthResolve = false;
bool supportsMemorylessRenderTargets = false;
uint8_t maxColorRenderTargets = 4;
struct {
@@ -96,8 +95,6 @@ struct MetalContext {
SamplerStateCache samplerStateCache;
ArgumentEncoderCache argumentEncoderCache;
PolygonOffset currentPolygonOffset = {0.0f, 0.0f};
MetalSamplerGroup* samplerBindings[Program::SAMPLER_BINDING_COUNT] = {};
// Keeps track of sampler groups we've finalized for the current render pass.
+3 -17
View File
@@ -92,13 +92,6 @@ MetalDriver::MetalDriver(MetalPlatform* platform, const Platform::DriverConfig&
mContext->highestSupportedGpuFamily.mac >= 2; // newer macOS GPUs
}
// In order to support resolve store action on depth attachment, the GPU needs to support it.
// Note that support for depth resolve implies support for stencil resolve using .sample0 resolve filter.
// (Other resolve filters are supported starting .apple5 and .mac2 families).
mContext->supportsAutoDepthResolve =
mContext->highestSupportedGpuFamily.apple >= 3 ||
mContext->highestSupportedGpuFamily.mac >= 2;
// In order to support memoryless render targets, an Apple GPU is needed.
// Available starting macOS 11.0, the first version to run on Apple GPUs.
// On iOS, it's available on all OS versions.
@@ -703,7 +696,7 @@ bool MetalDriver::isFrameTimeSupported() {
}
bool MetalDriver::isAutoDepthResolveSupported() {
return mContext->supportsAutoDepthResolve;
return true;
}
bool MetalDriver::isWorkaroundNeeded(Workaround workaround) {
@@ -900,7 +893,7 @@ void MetalDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh, BufferDescripto
auto& encoderCache = mContext->argumentEncoderCache;
id<MTLArgumentEncoder> encoder =
encoderCache.getOrCreateState(ArgumentEncoderState(std::move(textureTypes)));
sb->reset(getPendingCommandBuffer(mContext), encoder, mContext->device);
sb->reset(getPendingCommandBuffer(mContext), encoder);
// In a perfect world, all the MTLTexture bindings would be known at updateSamplerGroup time.
// However, there are two special cases preventing this:
@@ -1005,7 +998,6 @@ void MetalDriver::beginRenderPass(Handle<HwRenderTarget> rth,
mContext->depthStencilState.invalidate();
mContext->cullModeState.invalidate();
mContext->windingState.invalidate();
mContext->currentPolygonOffset = {0.0f, 0.0f};
mContext->finalizedSamplerGroups.clear();
}
@@ -1184,12 +1176,8 @@ void MetalDriver::startCapture(int) {
if (@available(iOS 13, *)) {
MTLCaptureDescriptor* descriptor = [MTLCaptureDescriptor new];
descriptor.captureObject = mContext->device;
#if defined(IOS)
descriptor.destination = MTLCaptureDestinationDeveloperTools;
#else
descriptor.destination = MTLCaptureDestinationGPUTraceDocument;
descriptor.outputURL = [[NSURL alloc] initFileURLWithPath:@"filament.gputrace"];
#endif
NSError* error = nil;
[[MTLCaptureManager sharedCaptureManager] startCaptureWithDescriptor:descriptor
error:&error];
@@ -1591,12 +1579,10 @@ void MetalDriver::draw(PipelineState ps, Handle<HwRenderPrimitive> rph, uint32_t
[mContext->currentRenderPassEncoder setDepthStencilState:state];
}
if (ps.polygonOffset.constant != mContext->currentPolygonOffset.constant ||
ps.polygonOffset.slope != mContext->currentPolygonOffset.slope) {
if (ps.polygonOffset.constant != 0.0 || ps.polygonOffset.slope != 0.0) {
[mContext->currentRenderPassEncoder setDepthBias:ps.polygonOffset.constant
slopeScale:ps.polygonOffset.slope
clamp:0.0];
mContext->currentPolygonOffset = ps.polygonOffset;
}
// Set scissor-rectangle.
+2
View File
@@ -337,6 +337,8 @@ constexpr inline MTLPrimitiveType getMetalPrimitiveType(PrimitiveType type) noex
case PrimitiveType::LINE_STRIP: return MTLPrimitiveTypeLineStrip;
case PrimitiveType::TRIANGLES: return MTLPrimitiveTypeTriangle;
case PrimitiveType::TRIANGLE_STRIP: return MTLPrimitiveTypeTriangleStrip;
case PrimitiveType::NONE:
ASSERT_POSTCONDITION(false, "NONE is not a valid primitive type.");
}
}
-10
View File
@@ -198,16 +198,6 @@ MTLPixelFormat getMetalFormat(MetalContext* context, TextureFormat format) noexc
case TextureFormat::DXT1_RGB: return MTLPixelFormatInvalid;
case TextureFormat::DXT1_SRGB: return MTLPixelFormatInvalid;
case TextureFormat::RED_RGTC1: return MTLPixelFormatBC4_RUnorm;
case TextureFormat::SIGNED_RED_RGTC1: return MTLPixelFormatBC4_RSnorm;
case TextureFormat::RED_GREEN_RGTC2: return MTLPixelFormatBC5_RGUnorm;
case TextureFormat::SIGNED_RED_GREEN_RGTC2: return MTLPixelFormatBC5_RGSnorm;
case TextureFormat::RGB_BPTC_SIGNED_FLOAT: return MTLPixelFormatBC6H_RGBFloat;
case TextureFormat::RGB_BPTC_UNSIGNED_FLOAT: return MTLPixelFormatBC6H_RGBUfloat;
case TextureFormat::RGBA_BPTC_UNORM: return MTLPixelFormatBC7_RGBAUnorm;
case TextureFormat::SRGB_ALPHA_BPTC_UNORM: return MTLPixelFormatBC7_RGBAUnorm_sRGB;
default: break;
}
}
+1 -1
View File
@@ -305,7 +305,7 @@ public:
// the texture types have changed.
// Mutate re-encodes the current set of samplers/textures into the new argument
// buffer.
void reset(id<MTLCommandBuffer> cmdBuffer, id<MTLArgumentEncoder> e, id<MTLDevice> device);
void reset(id<MTLCommandBuffer> cmdBuffer, id<MTLArgumentEncoder> e);
void mutate(id<MTLCommandBuffer> cmdBuffer);
id<MTLBuffer> getArgumentBuffer() const {
+2 -8
View File
@@ -828,8 +828,7 @@ void MetalSamplerGroup::finalize() {
finalized = true;
}
void MetalSamplerGroup::reset(id<MTLCommandBuffer> cmdBuffer, id<MTLArgumentEncoder> e,
id<MTLDevice> device) {
void MetalSamplerGroup::reset(id<MTLCommandBuffer> cmdBuffer, id<MTLArgumentEncoder> e) {
encoder = e;
// The number of slots in the ring buffer we use to manage argument buffer allocations.
@@ -847,7 +846,7 @@ void MetalSamplerGroup::reset(id<MTLCommandBuffer> cmdBuffer, id<MTLArgumentEnco
// Chances are, even though the MTLArgumentEncoder might change, the required size and alignment
// probably won't. So we can re-use the previous ring buffer.
if (UTILS_UNLIKELY(!argBuffer || !argBuffer->canAccomodateLayout(argBufferLayout))) {
argBuffer = std::make_unique<MetalRingBuffer>(device, MTLResourceStorageModeShared,
argBuffer = std::make_unique<MetalRingBuffer>(encoder.device, MTLResourceStorageModeShared,
argBufferLayout, METAL_ARGUMENT_BUFFER_SLOTS);
} else {
argBuffer->createNewAllocation(cmdBuffer);
@@ -1054,7 +1053,6 @@ void MetalRenderTarget::setUpRenderPassAttachments(MTLRenderPassDescriptor* desc
descriptor.depthAttachment.slice = 0;
const bool discard = any(discardFlags & TargetBufferFlags::DEPTH);
if (!discard) {
assert_invariant(context->supportsAutoDepthResolve);
descriptor.depthAttachment.resolveTexture = depthAttachment.getTexture();
descriptor.depthAttachment.resolveLevel = depthAttachment.level;
descriptor.depthAttachment.resolveSlice = depthAttachment.layer;
@@ -1087,14 +1085,10 @@ void MetalRenderTarget::setUpRenderPassAttachments(MTLRenderPassDescriptor* desc
descriptor.stencilAttachment.slice = 0;
const bool discard = any(discardFlags & TargetBufferFlags::STENCIL);
if (!discard) {
assert_invariant(context->supportsAutoDepthResolve);
descriptor.stencilAttachment.resolveTexture = stencilAttachment.getTexture();
descriptor.stencilAttachment.resolveLevel = stencilAttachment.level;
descriptor.stencilAttachment.resolveSlice = stencilAttachment.layer;
descriptor.stencilAttachment.storeAction = MTLStoreActionMultisampleResolve;
if (@available(iOS 12.0, *)) {
descriptor.stencilAttachment.stencilResolveFilter = MTLMultisampleStencilResolveFilterSample0;
}
}
}
}
+4 -4
View File
@@ -57,7 +57,7 @@ const char* getGLError(GLenum error) noexcept {
UTILS_NOINLINE
GLenum checkGLError(io::ostream& out, const char* function, size_t line) noexcept {
GLenum const error = glGetError();
GLenum error = glGetError();
if (error != GL_NO_ERROR) {
const char* string = getGLError(error);
out << "OpenGL error " << io::hex << error << " (" << string << ") in \""
@@ -68,7 +68,7 @@ GLenum checkGLError(io::ostream& out, const char* function, size_t line) noexcep
UTILS_NOINLINE
void assertGLError(io::ostream& out, const char* function, size_t line) noexcept {
GLenum const err = checkGLError(out, function, line);
GLenum err = checkGLError(out, function, line);
if (err != GL_NO_ERROR) {
debug_trap();
}
@@ -104,7 +104,7 @@ const char* getFramebufferStatus(GLenum status) noexcept {
UTILS_NOINLINE
GLenum checkFramebufferStatus(io::ostream& out, GLenum target, const char* function, size_t line) noexcept {
GLenum const status = glCheckFramebufferStatus(target);
GLenum status = glCheckFramebufferStatus(target);
if (status != GL_FRAMEBUFFER_COMPLETE) {
const char* string = getFramebufferStatus(status);
out << "OpenGL framebuffer error " << io::hex << status << " (" << string << ") in \""
@@ -115,7 +115,7 @@ GLenum checkFramebufferStatus(io::ostream& out, GLenum target, const char* funct
UTILS_NOINLINE
void assertFramebufferStatus(io::ostream& out, GLenum target, const char* function, size_t line) noexcept {
GLenum const status = checkFramebufferStatus(out, target, function, line);
GLenum status = checkFramebufferStatus(out, target, function, line);
if (status != GL_FRAMEBUFFER_COMPLETE) {
debug_trap();
}
-28
View File
@@ -472,34 +472,6 @@ constexpr /* inline */ GLenum getInternalFormat(TextureFormat format) noexcept {
return 0;
#endif
#if defined(GL_EXT_texture_compression_rgtc)
case TextureFormat::RED_RGTC1: return GL_COMPRESSED_RED_RGTC1_EXT;
case TextureFormat::SIGNED_RED_RGTC1: return GL_COMPRESSED_SIGNED_RED_RGTC1_EXT;
case TextureFormat::RED_GREEN_RGTC2: return GL_COMPRESSED_RED_GREEN_RGTC2_EXT;
case TextureFormat::SIGNED_RED_GREEN_RGTC2: return GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT;
#else
case TextureFormat::RED_RGTC1:
case TextureFormat::SIGNED_RED_RGTC1:
case TextureFormat::RED_GREEN_RGTC2:
case TextureFormat::SIGNED_RED_GREEN_RGTC2:
// this should not happen
return 0;
#endif
#if defined(GL_EXT_texture_compression_bptc)
case TextureFormat::RGB_BPTC_SIGNED_FLOAT: return GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT;
case TextureFormat::RGB_BPTC_UNSIGNED_FLOAT: return GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT;
case TextureFormat::RGBA_BPTC_UNORM: return GL_COMPRESSED_RGBA_BPTC_UNORM_EXT;
case TextureFormat::SRGB_ALPHA_BPTC_UNORM: return GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT;
#else
case TextureFormat::RGB_BPTC_SIGNED_FLOAT:
case TextureFormat::RGB_BPTC_UNSIGNED_FLOAT:
case TextureFormat::RGBA_BPTC_UNORM:
case TextureFormat::SRGB_ALPHA_BPTC_UNORM:
// this should not happen
return 0;
#endif
#if defined(GL_KHR_texture_compression_astc_hdr)
case TextureFormat::RGBA_ASTC_4x4: return GL_COMPRESSED_RGBA_ASTC_4x4_KHR;
case TextureFormat::RGBA_ASTC_5x4: return GL_COMPRESSED_RGBA_ASTC_5x4_KHR;
+23 -21
View File
@@ -27,7 +27,7 @@ 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;
int 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
@@ -142,7 +142,7 @@ OpenGLContext::OpenGLContext() noexcept {
bugs.enable_initialize_non_used_uniform_array = true;
int maj, min, driverMajor, driverMinor;
int const c = sscanf(state.version, "OpenGL ES %d.%d V@%d.%d", // NOLINT(cert-err34-c)
int c = sscanf(state.version, "OpenGL ES %d.%d V@%d.%d", // NOLINT(cert-err34-c)
&maj, &min, &driverMajor, &driverMinor);
if (c == 4) {
// Workarounds based on version here.
@@ -176,7 +176,7 @@ OpenGLContext::OpenGLContext() noexcept {
bugs.dont_use_timer_query = true;
int maj, min, driverVersion, driverRevision, driverPatch;
int const c = sscanf(state.version, "OpenGL ES %d.%d v%d.r%dp%d", // NOLINT(cert-err34-c)
int c = sscanf(state.version, "OpenGL ES %d.%d v%d.r%dp%d", // NOLINT(cert-err34-c)
&maj, &min, &driverVersion, &driverRevision, &driverPatch);
if (c == 5) {
// Workarounds based on version here.
@@ -218,7 +218,7 @@ OpenGLContext::OpenGLContext() noexcept {
if (strstr(state.renderer, "Adreno")) {
// Qualcomm GPU
// early exit condition is flattened in EASU code
// (that should be regardless of ANGLE, but we should double-check)
// (that should be regardless of ANGLE, but we should double check)
bugs.split_easu = true;
}
// TODO: see if we could use `bugs.allow_read_only_ancillary_feedback_loop = true`
@@ -270,8 +270,8 @@ OpenGLContext::OpenGLContext() noexcept {
#if !defined(NDEBUG) && defined(GL_KHR_debug)
if (ext.KHR_debug) {
auto cb = +[](GLenum, GLenum type, GLuint, GLenum severity, GLsizei length,
const GLchar* message, const void *) {
auto cb = [](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
const GLchar* message, const void *userParam) {
io::ostream* stream = &slog.i;
switch (severity) {
case GL_DEBUG_SEVERITY_HIGH: stream = &slog.e; break;
@@ -292,7 +292,7 @@ OpenGLContext::OpenGLContext() noexcept {
case GL_DEBUG_TYPE_MARKER: level = "MARKER: "; break;
default: break;
}
out << "KHR_debug " << level << std::string_view{ message, size_t(length) } << io::endl;
out << "KHR_debug " << level << message << io::endl;
};
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
@@ -304,7 +304,7 @@ OpenGLContext::OpenGLContext() noexcept {
void OpenGLContext::setDefaultState() noexcept {
// We need to make sure our internal state matches the GL state when we start.
// (some of these calls may be unneeded as they might be the gl defaults)
GLenum const caps[] = {
GLenum caps[] = {
GL_BLEND,
GL_CULL_FACE,
GL_SCISSOR_TEST,
@@ -315,14 +315,16 @@ void OpenGLContext::setDefaultState() noexcept {
GL_SAMPLE_COVERAGE,
GL_POLYGON_OFFSET_FILL,
};
size_t capsCount = sizeof(caps) / sizeof(caps[0]);
UTILS_NOUNROLL
for (auto const capi : caps) {
size_t const capIndex = getIndexForCap(capi);
for (GLenum capi = 0; capi < capsCount; ++capi) {
size_t capIndex = getIndexForCap(caps[capi]);
GLenum cap = caps[capi];
if (state.enables.caps[capIndex]) {
glEnable(capi);
glEnable(cap);
} else {
glDisable(capi);
glDisable(cap);
}
}
@@ -351,7 +353,7 @@ void OpenGLContext::setDefaultState() noexcept {
void OpenGLContext::initExtensionsGLES() noexcept {
const char * const extensions = (const char*)glGetString(GL_EXTENSIONS);
GLUtils::unordered_string_set const exts = GLUtils::split(extensions);
GLUtils::unordered_string_set exts = GLUtils::split(extensions);
if constexpr (DEBUG_PRINT_EXTENSIONS) {
for (auto extension: exts) {
slog.d << "\"" << std::string_view(extension) << "\"\n";
@@ -375,8 +377,6 @@ void OpenGLContext::initExtensionsGLES() noexcept {
#endif
ext.EXT_texture_compression_s3tc = exts.has("GL_EXT_texture_compression_s3tc"sv);
ext.EXT_texture_compression_s3tc_srgb = exts.has("GL_EXT_texture_compression_s3tc_srgb"sv);
ext.EXT_texture_compression_rgtc = exts.has("GL_EXT_texture_compression_rgtc"sv);
ext.EXT_texture_compression_bptc = exts.has("GL_EXT_texture_compression_bptc"sv);
ext.EXT_texture_cube_map_array = exts.has("GL_EXT_texture_cube_map_array"sv) || exts.has("GL_OES_texture_cube_map_array"sv);
ext.GOOGLE_cpp_style_line_directive = exts.has("GL_GOOGLE_cpp_style_line_directive"sv);
ext.KHR_debug = exts.has("GL_KHR_debug"sv);
@@ -420,8 +420,6 @@ void OpenGLContext::initExtensionsGL() noexcept {
ext.EXT_texture_compression_etc2 = exts.has("GL_ARB_ES3_compatibility"sv);
ext.EXT_texture_compression_s3tc = exts.has("GL_EXT_texture_compression_s3tc"sv);
ext.EXT_texture_compression_s3tc_srgb = exts.has("GL_EXT_texture_compression_s3tc_srgb"sv);
ext.EXT_texture_compression_rgtc = exts.has("GL_EXT_texture_compression_rgtc"sv);
ext.EXT_texture_compression_bptc = exts.has("GL_EXT_texture_compression_bptc"sv);
ext.EXT_texture_filter_anisotropic = exts.has("GL_EXT_texture_filter_anisotropic"sv);
ext.EXT_texture_sRGB = exts.has("GL_EXT_texture_sRGB"sv);
ext.GOOGLE_cpp_style_line_directive = exts.has("GL_GOOGLE_cpp_style_line_directive"sv);
@@ -446,7 +444,7 @@ void OpenGLContext::bindBuffer(GLenum target, GLuint buffer) noexcept {
glBindBuffer(target, buffer);
}
} else {
size_t const targetIndex = getIndexForBufferTarget(target);
size_t targetIndex = getIndexForBufferTarget(target);
update_state(state.buffers.genericBinding[targetIndex], buffer, [&]() {
glBindBuffer(target, buffer);
});
@@ -613,7 +611,7 @@ void OpenGLContext::resetState() noexcept {
// Reset state.buffers to its default state to avoid the complexity and error-prone
// nature of resetting the GL state to its existing state
state.buffers = {};
GLenum const bufferTargets[] = {
GLenum bufferTargets[] = {
GL_UNIFORM_BUFFER,
GL_TRANSFORM_FEEDBACK_BUFFER,
#if !defined(__EMSCRIPTEN__)
@@ -626,7 +624,9 @@ void OpenGLContext::resetState() noexcept {
GL_PIXEL_PACK_BUFFER,
GL_PIXEL_UNPACK_BUFFER,
};
for (auto const target : bufferTargets) {
size_t bufferTargetCount = sizeof(bufferTargets) / sizeof(bufferTargets[0]);
for (size_t targetArrayIndex = 0; targetArrayIndex < bufferTargetCount; ++targetArrayIndex) {
GLenum target = bufferTargets[targetArrayIndex];
glBindBuffer(target, 0);
}
@@ -655,11 +655,13 @@ void OpenGLContext::resetState() noexcept {
GL_TEXTURE_CUBE_MAP_ARRAY,
#endif
};
const size_t textureTargetCount = sizeof(textureTargets) / sizeof(textureTargets[0]);
for (GLint unit = 0; unit < gets.max_combined_texture_image_units; ++unit) {
glActiveTexture(GL_TEXTURE0 + unit);
glBindSampler(unit, 0);
for (auto const target : textureTargets) {
for (size_t textureTargetArrayIndex = 0; textureTargetArrayIndex < textureTargetCount; ++textureTargetArrayIndex) {
GLuint target = textureTargets[textureTargetArrayIndex];
glBindTexture(target, 0);
}
}
+42 -44
View File
@@ -137,93 +137,91 @@ public:
// features supported by this version of GL or GLES
struct {
bool multisample_texture;
} features = {};
bool multisample_texture = false;
} features;
// supported extensions detected at runtime
struct {
bool APPLE_color_buffer_packed_float;
bool ARB_shading_language_packing;
bool EXT_clip_control;
bool EXT_color_buffer_float;
bool EXT_color_buffer_half_float;
bool EXT_debug_marker;
bool EXT_disjoint_timer_query;
bool EXT_multisampled_render_to_texture;
bool EXT_multisampled_render_to_texture2;
bool EXT_shader_framebuffer_fetch;
bool KHR_texture_compression_astc_hdr;
bool KHR_texture_compression_astc_ldr;
bool EXT_texture_compression_etc2;
bool EXT_texture_compression_s3tc;
bool EXT_texture_compression_s3tc_srgb;
bool EXT_texture_compression_rgtc;
bool EXT_texture_compression_bptc;
bool EXT_texture_cube_map_array;
bool EXT_texture_filter_anisotropic;
bool EXT_texture_sRGB;
bool GOOGLE_cpp_style_line_directive;
bool KHR_debug;
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;
} ext = {};
bool APPLE_color_buffer_packed_float = false;
bool ARB_shading_language_packing = false;
bool EXT_clip_control = false;
bool EXT_color_buffer_float = false;
bool EXT_color_buffer_half_float = false;
bool EXT_debug_marker = false;
bool EXT_disjoint_timer_query = false;
bool EXT_multisampled_render_to_texture = false;
bool EXT_multisampled_render_to_texture2 = false;
bool EXT_shader_framebuffer_fetch = false;
bool KHR_texture_compression_astc_hdr = false;
bool KHR_texture_compression_astc_ldr = false;
bool EXT_texture_compression_etc2 = false;
bool EXT_texture_compression_s3tc = false;
bool EXT_texture_compression_s3tc_srgb = false;
bool EXT_texture_cube_map_array = false;
bool EXT_texture_filter_anisotropic = false;
bool EXT_texture_sRGB = false;
bool GOOGLE_cpp_style_line_directive = false;
bool KHR_debug = false;
bool OES_EGL_image_external_essl3 = false;
bool QCOM_tiled_rendering = false;
bool WEBGL_compressed_texture_etc = false;
bool WEBGL_compressed_texture_s3tc = false;
bool WEBGL_compressed_texture_s3tc_srgb = false;
} ext;
struct {
// Some drivers have issues with UBOs in the fragment shader when
// glFlush() is called between draw calls.
bool disable_glFlush;
bool disable_glFlush = false;
// Some drivers seem to not store the GL_ELEMENT_ARRAY_BUFFER binding
// in the VAO state.
bool vao_doesnt_store_element_array_buffer_binding;
bool vao_doesnt_store_element_array_buffer_binding = false;
// Some drivers have gl state issues when drawing from shared contexts
bool disable_shared_context_draws;
bool disable_shared_context_draws = false;
// Some drivers require the GL_TEXTURE_EXTERNAL_OES target to be bound when
// the texture image changes, even if it's already bound to that texture
bool texture_external_needs_rebind;
bool texture_external_needs_rebind = false;
// Some web browsers seem to immediately clear the default framebuffer when calling
// glInvalidateFramebuffer with WebGL 2.0
bool disable_invalidate_framebuffer;
bool disable_invalidate_framebuffer = false;
// Some drivers declare GL_EXT_texture_filter_anisotropic but don't support
// calling glSamplerParameter() with GL_TEXTURE_MAX_ANISOTROPY_EXT
bool texture_filter_anisotropic_broken_on_sampler;
bool texture_filter_anisotropic_broken_on_sampler = false;
// Some drivers have issues when reading from a mip while writing to a different mip.
// In the OpenGL ES 3.0 specification this is covered in section 4.4.3,
// "Feedback Loops Between Textures and the Framebuffer".
bool disable_feedback_loops;
bool disable_feedback_loops = false;
// Some drivers don't implement timer queries correctly
bool dont_use_timer_query;
bool dont_use_timer_query = false;
// Some drivers can't blit from a sidecar renderbuffer into a layer of a texture array.
// This technique is used for VSM with MSAA turned on.
bool disable_sidecar_blit_into_texture_array;
bool disable_sidecar_blit_into_texture_array = false;
// Some drivers incorrectly flatten the early exit condition in the EASU code, in which
// case we need an alternative algorithm
bool split_easu;
bool split_easu = false;
// As of Android R some qualcomm drivers invalidate buffers for the whole render pass
// even if glInvalidateFramebuffer() is called at the end of it.
bool invalidate_end_only_if_invalidate_start;
bool invalidate_end_only_if_invalidate_start = false;
// GLES doesn't allow feedback loops even if writes are disabled. So take we the point of
// view that this is generally forbidden. However, this restriction is lifted on desktop
// GL and Vulkan and probably Metal.
bool allow_read_only_ancillary_feedback_loop;
bool allow_read_only_ancillary_feedback_loop = false;
// Some Adreno drivers crash in glDrawXXX() when there's an uninitialized uniform block,
// even when the shader doesn't access it.
bool enable_initialize_non_used_uniform_array;
} bugs = {};
bool enable_initialize_non_used_uniform_array = false;
} bugs;
// state getters -- as needed.
vec4gli const& getViewport() const { return state.window.viewport; }
+97 -109
View File
@@ -78,8 +78,8 @@ using namespace GLUtils;
// ------------------------------------------------------------------------------------------------
UTILS_NOINLINE
Driver* OpenGLDriver::create(OpenGLPlatform* const platform,
void* const sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
Driver* OpenGLDriver::create(
OpenGLPlatform* const platform, void* const sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
assert_invariant(platform);
OpenGLPlatform* const ec = platform;
@@ -120,7 +120,7 @@ Driver* OpenGLDriver::create(OpenGLPlatform* const platform,
// here we check we're on a supported version of GL before initializing the driver
GLint major = 0, minor = 0;
bool const success = OpenGLContext::queryOpenGLVersion(&major, &minor);
bool success = OpenGLContext::queryOpenGLVersion(&major, &minor);
if (UTILS_UNLIKELY(!success)) {
PANIC_LOG("Can't get OpenGL version");
@@ -142,9 +142,8 @@ Driver* OpenGLDriver::create(OpenGLPlatform* const platform,
}
}
size_t const defaultSize = FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
Platform::DriverConfig const validConfig {
.handleArenaSize = std::max(driverConfig.handleArenaSize, defaultSize) };
size_t defaultSize = FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
Platform::DriverConfig validConfig { .handleArenaSize = std::max(driverConfig.handleArenaSize, defaultSize) };
OpenGLDriver* const driver = new OpenGLDriver(ec, validConfig);
return driver;
}
@@ -170,8 +169,7 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfi
std::fill(mSamplerBindings.begin(), mSamplerBindings.end(), nullptr);
// set a reasonable default value for our stream array
mTexturesWithStreamsAttached.reserve(8);
mStreamsWithPendingAquiredImage.reserve(8);
mExternalStreams.reserve(8);
#ifndef NDEBUG
slog.i << "OS version: " << mPlatform.getOSVersion() << io::endl;
@@ -437,10 +435,10 @@ void OpenGLDriver::createIndexBufferR(
DEBUG_MARKER()
auto& gl = mContext;
uint8_t const elementSize = static_cast<uint8_t>(getElementTypeSize(elementType));
uint8_t elementSize = static_cast<uint8_t>(getElementTypeSize(elementType));
GLIndexBuffer* ib = construct<GLIndexBuffer>(ibh, elementSize, indexCount);
glGenBuffers(1, &ib->gl.buffer);
GLsizeiptr const size = elementSize * indexCount;
GLsizeiptr size = elementSize * indexCount;
gl.bindVertexArray(nullptr);
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib->gl.buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, nullptr, getBufferUsage(usage));
@@ -1040,8 +1038,7 @@ void OpenGLDriver::renderBufferStorage(GLuint rbo, GLenum internalformat, uint32
auto& gl = mContext;
if (gl.ext.EXT_multisampled_render_to_texture ||
gl.ext.EXT_multisampled_render_to_texture2) {
glext::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER,
samples, internalformat, width, height);
glext::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, internalformat, width, height);
} else
#endif
{
@@ -1208,11 +1205,11 @@ void OpenGLDriver::createSyncR(Handle<HwSync> fh, int) {
CHECK_GL_ERROR(utils::slog.e)
// check the status of the sync once a frame, since we must do this from our thread
std::weak_ptr<GLSync::State> const weak = f->result;
std::weak_ptr<GLSync::State> weak = f->result;
runEveryNowAndThen([sync = f->gl.sync, weak]() -> bool {
auto result = weak.lock();
if (result) {
GLenum const status = glClientWaitSync(sync, 0, 0u);
GLenum status = glClientWaitSync(sync, 0, 0u);
result->status.store(status, std::memory_order_relaxed);
return (status != GL_TIMEOUT_EXPIRED);
}
@@ -1373,23 +1370,15 @@ void OpenGLDriver::destroyStream(Handle<HwStream> sh) {
GLStream* s = handle_cast<GLStream*>(sh);
// if this stream is still attached to a texture, detach it first
auto& texturesWithStreamsAttached = mTexturesWithStreamsAttached;
auto pos = std::find_if(
texturesWithStreamsAttached.begin(), texturesWithStreamsAttached.end(),
[s](GLTexture const* t) {
return t->hwStream == s;
});
if (pos != texturesWithStreamsAttached.end()) {
auto& externalStreams = mExternalStreams;
auto pos = std::find_if(externalStreams.begin(), externalStreams.end(),
[s](GLTexture const* t) { return t->hwStream == s; });
if (pos != externalStreams.end()) {
detachStream(*pos);
}
// and then destroy the stream. Only NATIVE streams have Platform::Stream associated.
if (s->streamType == StreamType::NATIVE) {
mPlatform.destroyStream(s->stream);
}
// finally destroy the HwStream handle
destruct(sh, s);
}
}
@@ -1437,56 +1426,30 @@ Handle<HwStream> OpenGLDriver::createStreamAcquired() {
void OpenGLDriver::setAcquiredImage(Handle<HwStream> sh, void* hwbuffer,
CallbackHandler* handler, StreamCallback cb, void* userData) {
GLStream* glstream = handle_cast<GLStream*>(sh);
assert_invariant(glstream->streamType == StreamType::ACQUIRED);
if (UTILS_UNLIKELY(glstream->user_thread.pending.image)) {
if (glstream->user_thread.pending.image) {
scheduleRelease(glstream->user_thread.pending);
slog.w << "Acquired image is set more than once per frame." << io::endl;
}
glstream->user_thread.pending = mPlatform.transformAcquiredImage({
hwbuffer, cb, userData, handler });
if (glstream->user_thread.pending.image != nullptr) {
// If there's no pending image, do nothing. Note that GL_OES_EGL_image does not let you pass
// NULL to glEGLImageTargetTexture2DOES, and there is no concept of "detaching" an
// EGLimage from a texture.
mStreamsWithPendingAquiredImage.push_back(glstream);
}
}
// updateStreams() and setAcquiredImage() are both called from on the application's thread
// and therefore do not require synchronization. The former is always called immediately before
// beginFrame, the latter is called by the user from anywhere outside beginFrame / endFrame.
void OpenGLDriver::updateStreams(DriverApi* driver) {
if (UTILS_UNLIKELY(!mStreamsWithPendingAquiredImage.empty())) {
for (GLStream* s : mStreamsWithPendingAquiredImage) {
assert_invariant(s);
assert_invariant(s->streamType == StreamType::ACQUIRED);
if (UTILS_UNLIKELY(!mExternalStreams.empty())) {
for (GLTexture* t : mExternalStreams) {
assert_invariant(t);
AcquiredImage const previousImage = s->user_thread.acquired;
s->user_thread.acquired = s->user_thread.pending;
s->user_thread.pending = { nullptr };
GLStream* s = static_cast<GLStream*>(t->hwStream); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
if (UTILS_UNLIKELY(s == nullptr)) {
// this can happen because we're called synchronously and the setExternalStream()
// call may not have been processed yet.
continue;
}
// Bind the stashed EGLImage to its corresponding GL texture as soon as we start
// making the GL calls for the upcoming frame.
driver->queueCommand([this, s, image = s->user_thread.acquired.image, previousImage]() {
auto& streams = mTexturesWithStreamsAttached;
auto pos = std::find_if(streams.begin(), streams.end(),
[s](GLTexture const* t) {
return t->hwStream == s;
});
if (pos != streams.end()) {
setExternalTexture(*pos, image);
}
if (previousImage.image) {
scheduleRelease(AcquiredImage(previousImage));
}
});
if (s->streamType == StreamType::ACQUIRED) {
updateStreamAcquired(t, driver);
}
}
mStreamsWithPendingAquiredImage.clear();
}
}
@@ -1546,12 +1509,6 @@ bool OpenGLDriver::isTextureFormatSupported(TextureFormat format) {
return ext.EXT_texture_compression_s3tc || // this is ES specific
ext.WEBGL_compressed_texture_s3tc; // this is WEBGL specific
}
if (isRGTCCompression(format)) {
return ext.EXT_texture_compression_rgtc;
}
if (isBPTCCompression(format)) {
return ext.EXT_texture_compression_bptc;
}
if (isASTCCompression(format)) {
return ext.KHR_texture_compression_astc_hdr;
}
@@ -1852,7 +1809,7 @@ void OpenGLDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh,
DEBUG_MARKER()
#if defined(GL_EXT_texture_filter_anisotropic)
OpenGLContext const& context = getContext();
OpenGLContext& context = getContext();
const bool anisotropyWorkaround =
context.ext.EXT_texture_filter_anisotropic &&
context.bugs.texture_filter_anisotropic_broken_on_sampler;
@@ -1896,7 +1853,7 @@ void OpenGLDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh,
// Driver claims to support anisotropic filtering, but it fails when set on
// the sampler, we have to set it on the texture instead.
// The texture is already bound here.
GLfloat const anisotropy = float(1u << params.anisotropyLog2);
GLfloat anisotropy = float(1u << params.anisotropyLog2);
glTexParameterf(t->gl.target, GL_TEXTURE_MAX_ANISOTROPY_EXT,
std::min(context.gets.max_anisotropy, anisotropy));
}
@@ -1987,8 +1944,8 @@ void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level,
return;
}
GLenum const glFormat = getFormat(p.format);
GLenum const glType = getType(p.type);
GLenum glFormat = getFormat(p.format);
GLenum glType = getType(p.type);
gl.pixelStore(GL_UNPACK_ROW_LENGTH, GLint(p.stride));
gl.pixelStore(GL_UNPACK_ALIGNMENT, GLint(p.alignment));
@@ -1997,7 +1954,7 @@ void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level,
switch (t->target) {
case SamplerType::SAMPLER_EXTERNAL:
// if we get there, it's because the user is trying to use an external texture,
// if we get there, it's because the user is trying to use an external texture
// but it's not supported, so instead, we behave like a texture2d.
// fallthrough...
case SamplerType::SAMPLER_2D:
@@ -2041,7 +1998,7 @@ void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level,
assert_invariant(zoffset + depth <= 6);
UTILS_NOUNROLL
for (size_t face = 0; face < depth; face++) {
GLenum const target = getCubemapTarget(zoffset + face);
GLenum target = getCubemapTarget(zoffset + face);
glTexSubImage2D(target, GLint(level), GLint(xoffset), GLint(yoffset),
GLsizei(width), GLsizei(height), glFormat, glType,
static_cast<uint8_t const*>(p.buffer) + faceSize * face);
@@ -2085,13 +2042,13 @@ void OpenGLDriver::setCompressedTextureData(GLTexture* t, uint32_t level,
// TODO: maybe assert that the CompressedPixelDataType is the same as the internalFormat
GLsizei const imageSize = GLsizei(p.imageSize);
GLsizei imageSize = GLsizei(p.imageSize);
// TODO: maybe assert the size is right (b/c we can compute it ourselves)
switch (t->target) {
case SamplerType::SAMPLER_EXTERNAL:
// if we get there, it's because the user is trying to use an external texture,
// if we get there, it's because the user is trying to use an external texture
// but it's not supported, so instead, we behave like a texture2d.
// fallthrough...
case SamplerType::SAMPLER_2D:
@@ -2133,7 +2090,7 @@ void OpenGLDriver::setCompressedTextureData(GLTexture* t, uint32_t level,
UTILS_NOUNROLL
for (size_t face = 0; face < depth; face++) {
GLenum const target = getCubemapTarget(zoffset + face);
GLenum target = getCubemapTarget(zoffset + face);
glCompressedTexSubImage2D(target, GLint(level), GLint(xoffset), GLint(yoffset),
GLsizei(width), GLsizei(height), t->gl.internalFormat,
imageSize, static_cast<uint8_t const*>(p.buffer) + faceSize * face);
@@ -2220,7 +2177,7 @@ void OpenGLDriver::setExternalStream(Handle<HwTexture> th, Handle<HwStream> sh)
UTILS_NOINLINE
void OpenGLDriver::attachStream(GLTexture* t, GLStream* hwStream) noexcept {
mTexturesWithStreamsAttached.push_back(t);
mExternalStreams.push_back(t);
switch (hwStream->streamType) {
case StreamType::NATIVE:
@@ -2235,10 +2192,10 @@ void OpenGLDriver::attachStream(GLTexture* t, GLStream* hwStream) noexcept {
UTILS_NOINLINE
void OpenGLDriver::detachStream(GLTexture* t) noexcept {
auto& gl = mContext;
auto& texturesWithStreamsAttached = mTexturesWithStreamsAttached;
auto pos = std::find(texturesWithStreamsAttached.begin(), texturesWithStreamsAttached.end(), t);
if (pos != texturesWithStreamsAttached.end()) {
texturesWithStreamsAttached.erase(pos);
auto& streams = mExternalStreams;
auto pos = std::find(streams.begin(), streams.end(), t);
if (pos != streams.end()) {
streams.erase(pos);
}
GLStream* s = static_cast<GLStream*>(t->hwStream); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
@@ -2313,7 +2270,7 @@ void OpenGLDriver::endTimerQuery(Handle<HwTimerQuery> tqh) {
bool OpenGLDriver::getTimerQueryValue(Handle<HwTimerQuery> tqh, uint64_t* elapsedTime) {
GLTimerQuery* tq = handle_cast<GLTimerQuery*>(tqh);
uint64_t const d = tq->elapsed.load(std::memory_order_relaxed);
uint64_t d = tq->elapsed.load(std::memory_order_relaxed);
if (!d) {
return false;
}
@@ -2366,7 +2323,7 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
BACKEND_OPENGL_LEVEL >= BACKEND_OPENGL_LEVEL_GLES30) {
if (!gl.bugs.disable_invalidate_framebuffer) {
AttachmentArray attachments; // NOLINT
GLsizei const attachmentCount = getAttachments(attachments, rt, discardFlags);
GLsizei attachmentCount = getAttachments(attachments, rt, discardFlags);
if (attachmentCount) {
glInvalidateFramebuffer(GL_FRAMEBUFFER, attachmentCount, attachments.data());
}
@@ -2403,10 +2360,8 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
mRenderPassDepthWrite = any(clearFlags & TargetBufferFlags::DEPTH);
mRenderPassStencilWrite = any(clearFlags & TargetBufferFlags::STENCIL);
static_assert(sizeof(GLsizei) >= sizeof(uint32_t));
gl.viewport(params.viewport.left, params.viewport.bottom,
(GLsizei)std::min(uint32_t(std::numeric_limits<int32_t>::max()), params.viewport.width),
(GLsizei)std::min(uint32_t(std::numeric_limits<int32_t>::max()), params.viewport.height));
(GLsizei)params.viewport.width, (GLsizei)params.viewport.height);
gl.depthRange(params.depthRange.near, params.depthRange.far);
@@ -2456,7 +2411,7 @@ void OpenGLDriver::endRenderPass(int) {
// we wouldn't have to bind the framebuffer if we had glInvalidateNamedFramebuffer()
gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
AttachmentArray attachments; // NOLINT
GLsizei const attachmentCount = getAttachments(attachments, rt, effectiveDiscardFlags);
GLsizei attachmentCount = getAttachments(attachments, rt, effectiveDiscardFlags);
if (attachmentCount) {
glInvalidateFramebuffer(GL_FRAMEBUFFER, attachmentCount, attachments.data());
}
@@ -2484,7 +2439,7 @@ void OpenGLDriver::resolvePass(ResolveAction action, GLRenderTarget const* rt,
assert_invariant(rt->gl.fbo_read);
auto& gl = mContext;
const TargetBufferFlags resolve = rt->gl.resolve & ~discardFlags;
GLbitfield const mask = getAttachmentBitfield(resolve);
GLbitfield mask = getAttachmentBitfield(resolve);
if (UTILS_UNLIKELY(mask)) {
// we can only resolve COLOR0 at the moment
@@ -2575,6 +2530,40 @@ void OpenGLDriver::setScissor(Viewport const& scissor) noexcept {
gl.enable(GL_SCISSOR_TEST);
}
// Binds the external image stashed in the associated stream.
//
// updateStreamAcquired() and setAcquiredImage() are both called from on the application's thread
// and therefore do not require synchronization. The former is always called immediately before
// beginFrame, the latter is called by the user from anywhere outside beginFrame / endFrame.
void OpenGLDriver::updateStreamAcquired(GLTexture* gltexture, DriverApi* driver) noexcept {
SYSTRACE_CALL();
GLStream* glstream = static_cast<GLStream*>(gltexture->hwStream); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
assert_invariant(glstream);
assert_invariant(glstream->streamType == StreamType::ACQUIRED);
// If there's no pending image, do nothing. Note that GL_OES_EGL_image does not let you pass
// NULL to glEGLImageTargetTexture2DOES, and there is no concept of "detaching" an EGLimage from
// a texture.
if (glstream->user_thread.pending.image == nullptr) {
return;
}
AcquiredImage previousImage = glstream->user_thread.acquired;
glstream->user_thread.acquired = glstream->user_thread.pending;
glstream->user_thread.pending = { nullptr };
// Bind the stashed EGLImage to its corresponding GL texture as soon as we start making the GL
// calls for the upcoming frame.
void* image = glstream->user_thread.acquired.image;
driver->queueCommand([this, gltexture, image, previousImage]() {
setExternalTexture(gltexture, image);
if (previousImage.image) {
scheduleRelease(AcquiredImage(previousImage));
}
});
}
// ------------------------------------------------------------------------------------------------
// Setting rendering state
// ------------------------------------------------------------------------------------------------
@@ -2598,7 +2587,7 @@ void OpenGLDriver::bindBufferRange(BufferObjectBinding bindingType, uint32_t ind
GLBufferObject* ub = handle_cast<GLBufferObject *>(ubh);
GLenum const target = GLUtils::getBufferBindingType(bindingType);
GLenum target = GLUtils::getBufferBindingType(bindingType);
assert_invariant(bindingType == BufferObjectBinding::SHADER_STORAGE ||
ub->gl.binding == target);
@@ -2611,7 +2600,7 @@ void OpenGLDriver::bindBufferRange(BufferObjectBinding bindingType, uint32_t ind
void OpenGLDriver::unbindBuffer(BufferObjectBinding bindingType, uint32_t index) {
DEBUG_MARKER()
auto& gl = mContext;
GLenum const target = GLUtils::getBufferBindingType(bindingType);
GLenum target = GLUtils::getBufferBindingType(bindingType);
gl.bindBufferRange(target, GLuint(index), 0, 0, 0);
CHECK_GL_ERROR(utils::slog.e)
}
@@ -2642,7 +2631,7 @@ GLuint OpenGLDriver::getSamplerSlow(SamplerParams params) const noexcept {
auto& gl = mContext;
if (gl.ext.EXT_texture_filter_anisotropic &&
!gl.bugs.texture_filter_anisotropic_broken_on_sampler) {
GLfloat const anisotropy = float(1u << params.anisotropyLog2);
GLfloat anisotropy = float(1u << params.anisotropyLog2);
glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT,
std::min(gl.gets.max_anisotropy, anisotropy));
}
@@ -2703,8 +2692,8 @@ void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
DEBUG_MARKER()
auto& gl = mContext;
GLenum const glFormat = getFormat(p.format);
GLenum const glType = getType(p.type);
GLenum glFormat = getFormat(p.format);
GLenum glType = getType(p.type);
gl.pixelStore(GL_PACK_ROW_LENGTH, (GLint)p.stride);
gl.pixelStore(GL_PACK_ALIGNMENT, (GLint)p.alignment);
@@ -2755,8 +2744,9 @@ void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
auto& gl = mContext;
gl.bindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
void* vaddr = nullptr;
std::unique_ptr<uint8_t> clientBuffer;
#if defined(__EMSCRIPTEN__)
std::unique_ptr<uint8_t> clientBuffer = std::make_unique<uint8_t>(p.size);
clientBuffer.reset(new uint8_t(p.size));
glGetBufferSubData(GL_PIXEL_PACK_BUFFER, 0, p.size, clientBuffer.get());
vaddr = clientBuffer.get();
#else
@@ -2764,10 +2754,10 @@ void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
#endif
if (vaddr) {
// now we need to flip the buffer vertically to match our API
size_t const stride = p.stride ? p.stride : width;
size_t const bpp = PixelBufferDescriptor::computeDataSize(
size_t stride = p.stride ? p.stride : width;
size_t bpp = PixelBufferDescriptor::computeDataSize(
p.format, p.type, 1, 1, 1);
size_t const bpr = PixelBufferDescriptor::computeDataSize(
size_t bpr = PixelBufferDescriptor::computeDataSize(
p.format, p.type, stride, 1, p.alignment);
char const* head = (char const*)vaddr + p.left * bpp + bpr * p.top;
char* tail = (char*)p.buffer + p.left * bpp + bpr * (p.top + height - 1);
@@ -2854,7 +2844,7 @@ void OpenGLDriver::executeGpuCommandsCompleteOps() noexcept {
auto& v = mGpuCommandCompleteOps;
auto it = v.begin();
while (it != v.end()) {
GLenum const status = glClientWaitSync(it->first, 0, 0);
GLenum status = glClientWaitSync(it->first, 0, 0);
if (status == GL_ALREADY_SIGNALED || status == GL_CONDITION_SATISFIED) {
it->second();
glDeleteSync(it->first);
@@ -2911,15 +2901,13 @@ void OpenGLDriver::tick(int) {
executeEveryNowAndThenOps();
}
void OpenGLDriver::beginFrame(
UTILS_UNUSED int64_t monotonic_clock_ns,
UTILS_UNUSED uint32_t frameId) {
void OpenGLDriver::beginFrame(int64_t monotonic_clock_ns, uint32_t frameId) {
DEBUG_MARKER()
auto& gl = mContext;
insertEventMarker("beginFrame");
if (UTILS_UNLIKELY(!mTexturesWithStreamsAttached.empty())) {
if (UTILS_UNLIKELY(!mExternalStreams.empty())) {
OpenGLPlatform& platform = mPlatform;
for (GLTexture const* t : mTexturesWithStreamsAttached) {
for (GLTexture const* t : mExternalStreams) {
assert_invariant(t && t->hwStream);
if (t->hwStream->streamType == StreamType::NATIVE) {
assert_invariant(t->hwStream->stream);
@@ -2947,7 +2935,7 @@ void OpenGLDriver::setPresentationTime(int64_t monotonic_clock_ns) {
mPlatform.setPresentationTime(monotonic_clock_ns);
}
void OpenGLDriver::endFrame(UTILS_UNUSED uint32_t frameId) {
void OpenGLDriver::endFrame(uint32_t frameId) {
DEBUG_MARKER()
#if defined(__EMSCRIPTEN__)
// WebGL builds are single-threaded so users might manipulate various GL state after we're
@@ -3050,7 +3038,7 @@ void OpenGLDriver::blit(TargetBufferFlags buffers,
DEBUG_MARKER()
auto& gl = mContext;
GLbitfield const mask = getAttachmentBitfield(buffers);
GLbitfield mask = getAttachmentBitfield(buffers);
if (mask) {
GLenum glFilterMode = (filter == SamplerMagFilter::NEAREST) ? GL_NEAREST : GL_LINEAR;
if (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) {
+5 -6
View File
@@ -48,6 +48,7 @@ class PixelBufferDescriptor;
struct TargetBufferInfo;
class OpenGLProgram;
class OpenGLBlitter;
class OpenGLTimerQueryInterface;
class OpenGLDriver final : public DriverBase {
@@ -151,6 +152,8 @@ public:
struct GLStream : public HwStream {
using HwStream::HwStream;
struct Info {
// storage for the read/write textures below
Platform::ExternalTexture* ets = nullptr;
GLuint width = 0;
GLuint height = 0;
};
@@ -344,12 +347,7 @@ private:
std::array<GLSamplerGroup*, Program::SAMPLER_BINDING_COUNT> mSamplerBindings = {}; // 4 pointers
mutable tsl::robin_map<uint32_t, GLuint> mSamplerMap;
// this must be accessed from the driver thread only
std::vector<GLTexture*> mTexturesWithStreamsAttached;
// the must be accessed from the user thread only
std::vector<GLStream*> mStreamsWithPendingAquiredImage;
mutable std::vector<GLTexture*> mExternalStreams;
void attachStream(GLTexture* t, GLStream* stream) noexcept;
void detachStream(GLTexture* t) noexcept;
@@ -357,6 +355,7 @@ private:
OpenGLPlatform& mPlatform;
void updateStreamAcquired(GLTexture* t, DriverApi* driver) noexcept;
void updateTextureLodRange(GLTexture* texture, int8_t targetLevel) noexcept;
void setExternalTexture(GLTexture* t, void* image);
+27 -30
View File
@@ -81,7 +81,7 @@ OpenGLProgram::~OpenGLProgram() noexcept {
}
const GLuint program = gl.program;
UTILS_NOUNROLL
for (GLuint const shader: gl.shaders) {
for (GLuint shader: gl.shaders) {
if (shader) {
if (program) {
glDetachShader(program, shader);
@@ -103,18 +103,18 @@ void OpenGLProgram::compileShaders(OpenGLContext& context,
Program::ShaderSource shadersSource,
utils::FixedCapacityVector<Program::SpecializationConstant> const& specializationConstants,
GLuint shaderIds[Program::SHADER_TYPE_COUNT],
UTILS_UNUSED_IN_RELEASE std::array<CString, Program::SHADER_TYPE_COUNT>& outShaderSourceCode) noexcept {
std::array<CString, Program::SHADER_TYPE_COUNT>& outShaderSourceCode) noexcept {
std::string specializationConstantString;
std::string specificationConstantString;
for (auto const& sc : specializationConstants) {
specializationConstantString += "#define SPIRV_CROSS_CONSTANT_ID_" + std::to_string(sc.id) + ' ';
specializationConstantString += std::visit([](auto&& arg) {
specificationConstantString += "#define SPIRV_CROSS_CONSTANT_ID_" + std::to_string(sc.id) + ' ';
specificationConstantString += std::visit([](auto&& arg) {
return std::to_string(arg);
}, sc.value);
specializationConstantString += '\n';
specificationConstantString += '\n';
}
if (!specializationConstantString.empty()) {
specializationConstantString += '\n';
if (!specificationConstantString.empty()) {
specificationConstantString += '\n';
}
// build all shaders
@@ -132,7 +132,7 @@ void OpenGLProgram::compileShaders(OpenGLContext& context,
Program::ShaderBlob& shader = shadersSource[i];
// remove GOOGLE_cpp_style_line_directive
std::string_view const source = process_GOOGLE_cpp_style_line_directive(context,
std::string_view source = process_GOOGLE_cpp_style_line_directive(context,
reinterpret_cast<char*>(shader.data()), shader.size());
// add support for ARB_shading_language_packing if needed
@@ -143,19 +143,19 @@ void OpenGLProgram::compileShaders(OpenGLContext& context,
const std::array<const char*, 4> sources = {
prolog.data(),
specializationConstantString.c_str(),
specificationConstantString.c_str(),
packingFunctions.data(),
body.data()
};
const std::array<GLint, 4> lengths = {
(GLint)prolog.length(),
(GLint)specializationConstantString.length(),
(GLint)specificationConstantString.length(),
(GLint)packingFunctions.length(),
(GLint)body.length() - 1 // null terminated
};
GLuint const shaderId = glCreateShader(glShaderType);
GLuint shaderId = glCreateShader(glShaderType);
glShaderSource(shaderId, sources.size(), sources.data(), lengths.data());
glCompileShader(shaderId);
@@ -246,8 +246,8 @@ std::array<std::string_view, 2> OpenGLProgram::splitShaderSource(std::string_vie
auto eol = source.find('\n', pos) + 1;
assert_invariant(eol != std::string_view::npos);
std::string_view const version = source.substr(start, eol - start);
std::string_view const body = source.substr(version.length(), source.length() - version.length());
std::string_view version = source.substr(start, eol - start);
std::string_view body = source.substr(version.length(), source.length() - version.length());
return { version, body };
}
@@ -257,7 +257,7 @@ std::array<std::string_view, 2> OpenGLProgram::splitShaderSource(std::string_vie
* program itself is valid).
*/
GLuint OpenGLProgram::linkProgram(const GLuint shaderIds[Program::SHADER_TYPE_COUNT]) noexcept {
GLuint const program = glCreateProgram();
GLuint program = glCreateProgram();
for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
if (shaderIds[i]) {
glAttachShader(program, shaderIds[i]);
@@ -286,15 +286,13 @@ bool OpenGLProgram::checkProgramStatus(const char* name,
for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
const ShaderStage type = static_cast<ShaderStage>(i);
const GLuint shader = shaderIds[i];
if (shader) {
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE) {
logCompilationError(slog.e, type, name, shader, shaderSourceCode[i]);
}
glDetachShader(program, shader);
glDeleteShader(shader);
shaderIds[i] = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE) {
logCompilationError(slog.e, type, name, shader, shaderSourceCode[i]);
}
glDetachShader(program, shader);
glDeleteShader(shader);
shaderIds[i] = 0;
}
// log the link error as well
logProgramLinkError(slog.e, name, program);
@@ -342,9 +340,9 @@ void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint progra
for (GLuint binding = 0, n = lazyInitializationData.uniformBlockInfo.size(); binding < n; binding++) {
auto const& name = lazyInitializationData.uniformBlockInfo[binding];
if (!name.empty()) {
GLuint const index = glGetUniformBlockIndex(program, name.c_str());
if (index != GL_INVALID_INDEX) {
glUniformBlockBinding(program, index, binding);
GLint index = glGetUniformBlockIndex(program, name.c_str());
if (index >= 0) {
glUniformBlockBinding(program, GLuint(index), binding);
}
CHECK_GL_ERROR(utils::slog.e)
}
@@ -369,7 +367,7 @@ void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint progra
UTILS_NOUNROLL
for (const Program::Sampler& sampler: samplers) {
// find its location and associate a TMU to it
GLint const loc = glGetUniformLocation(program, sampler.name.c_str());
GLint loc = glGetUniformLocation(program, sampler.name.c_str());
if (loc >= 0) {
// this can fail if the program doesn't use this sampler
glUniform1i(loc, tmu);
@@ -404,7 +402,7 @@ void OpenGLProgram::updateSamplers(OpenGLDriver* gld) const noexcept {
assert_invariant(sb);
for (uint8_t j = 0, m = sb->textureUnitEntries.size(); j < m; ++j, ++tmu) { // "<=" on purpose here
const GLTexture* const t = sb->textureUnitEntries[j].texture;
GLuint const s = sb->textureUnitEntries[j].sampler;
GLuint s = sb->textureUnitEntries[j].sampler;
if (t) { // program may not use all samplers of sampler group
if (UTILS_UNLIKELY(t->gl.fence)) {
glWaitSync(t->gl.fence, 0, GL_TIMEOUT_IGNORED);
@@ -421,8 +419,7 @@ void OpenGLProgram::updateSamplers(OpenGLDriver* gld) const noexcept {
UTILS_NOINLINE
void logCompilationError(io::ostream& out, ShaderStage shaderType,
const char* name, GLuint shaderId,
UTILS_UNUSED_IN_RELEASE CString const& sourceCode) noexcept {
const char* name, GLuint shaderId, CString const& sourceCode) noexcept {
auto to_string = [](ShaderStage type) -> const char* {
switch (type) {
+2 -9
View File
@@ -54,6 +54,7 @@ io::ostream& operator<<(io::ostream& out, PrimitiveType type) {
CASE(PrimitiveType, LINES)
CASE(PrimitiveType, LINE_STRIP)
CASE(PrimitiveType, POINTS)
CASE(PrimitiveType, NONE)
}
return out;
}
@@ -252,14 +253,7 @@ io::ostream& operator<<(io::ostream& out, TextureFormat format) {
CASE(TextureFormat, DXT3_SRGBA)
CASE(TextureFormat, DXT5_RGBA)
CASE(TextureFormat, DXT5_SRGBA)
CASE(TextureFormat, RED_RGTC1)
CASE(TextureFormat, SIGNED_RED_RGTC1)
CASE(TextureFormat, RED_GREEN_RGTC2)
CASE(TextureFormat, SIGNED_RED_GREEN_RGTC2)
CASE(TextureFormat, RGB_BPTC_SIGNED_FLOAT)
CASE(TextureFormat, RGB_BPTC_UNSIGNED_FLOAT)
CASE(TextureFormat, RGBA_BPTC_UNORM)
CASE(TextureFormat, SRGB_ALPHA_BPTC_UNORM)
CASE(TextureFormat, UNUSED)
CASE(TextureFormat, RGBA_ASTC_4x4)
CASE(TextureFormat, RGBA_ASTC_5x4)
CASE(TextureFormat, RGBA_ASTC_5x5)
@@ -288,7 +282,6 @@ io::ostream& operator<<(io::ostream& out, TextureFormat format) {
CASE(TextureFormat, SRGB8_ALPHA8_ASTC_10x10)
CASE(TextureFormat, SRGB8_ALPHA8_ASTC_12x10)
CASE(TextureFormat, SRGB8_ALPHA8_ASTC_12x12)
CASE(TextureFormat, UNUSED)
}
return out;
}
@@ -1,74 +0,0 @@
/*
* Copyright (C) 2018 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 "vulkan/PlatformVkLinuxGGP.h"
#include <bluevk/BlueVK.h>
#if defined(FILAMENT_SUPPORTS_GGP)
#include <ggp_c/ggp.h>
#endif
#include <utils/Panic.h>
#include "VulkanDriverFactory.h"
using namespace bluevk;
namespace filament::backend {
Driver* PlatformVkLinuxGGP::createDriver(
void* const sharedContext,
const Platform::DriverConfig& driverConfig) noexcept {
#if defined(FILAMENT_SUPPORTS_GGP)
ASSERT_PRECONDITION(sharedContext == nullptr,
"Vulkan does not support shared contexts.");
const char* requiredInstanceExtensions[] = {
VK_GGP_STREAM_DESCRIPTOR_SURFACE_EXTENSION_NAME};
return VulkanDriverFactory::create(this, requiredInstanceExtensions,
sizeof(requiredInstanceExtensions) /
sizeof(requiredInstanceExtensions[0]),
driverConfig);
#else
PANIC_PRECONDITION("Filament does not support GGP.");
return nullptr;
#endif
}
void* PlatformVkLinuxGGP::createVkSurfaceKHR(void* nativeWindow, void* instance,
uint64_t flags) noexcept {
#if defined(FILAMENT_SUPPORTS_GGP)
VkStreamDescriptorSurfaceCreateInfoGGP surface_create_info = {
VK_STRUCTURE_TYPE_STREAM_DESCRIPTOR_SURFACE_CREATE_INFO_GGP};
surface_create_info.streamDescriptor = kGgpPrimaryStreamDescriptor;
PFN_vkCreateStreamDescriptorSurfaceGGP fpCreateStreamDescriptorSurfaceGGP =
reinterpret_cast<PFN_vkCreateStreamDescriptorSurfaceGGP>(
vkGetInstanceProcAddr(static_cast<VkInstance>(instance),
"vkCreateStreamDescriptorSurfaceGGP"));
ASSERT_PRECONDITION(fpCreateStreamDescriptorSurfaceGGP != nullptr,
"Error getting VkInstance "
"function vkCreateStreamDescriptorSurfaceGGP");
VkSurfaceKHR surface = nullptr;
VkResult res = fpCreateStreamDescriptorSurfaceGGP(
static_cast<VkInstance>(instance), &surface_create_info, nullptr,
&surface);
ASSERT_PRECONDITION(res == VK_SUCCESS, "Error in vulkan: %d", res);
return surface;
#else
PANIC_PRECONDITION("Filament does not support GGP.");
return nullptr;
#endif
}
} // namespace filament::backend
@@ -1,41 +0,0 @@
/*
* Copyright (C) 2018 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_VULKAN_PLATFORM_VK_LINUX_GGP_H
#define TNT_FILAMENT_BACKEND_VULKAN_PLATFORM_VK_LINUX_GGP_H
#include <backend/DriverEnums.h>
#include <stdint.h>
#include "VulkanPlatform.h"
namespace filament::backend {
class PlatformVkLinuxGGP final : public VulkanPlatform {
public:
Driver* createDriver(
void* const sharedContext,
const Platform::DriverConfig& driverConfig) noexcept override;
void* createVkSurfaceKHR(void* nativeWindow, void* instance,
uint64_t flags) noexcept override;
int getOSVersion() const noexcept override { return 0; }
};
} // namespace filament::backend
#endif // TNT_FILAMENT_BACKEND_VULKAN_PLATFORM_VK_LINUX_GGP_H
@@ -263,6 +263,7 @@ VulkanBufferObject::VulkanBufferObject(VulkanContext& context, VulkanStagePool&
void VulkanRenderPrimitive::setPrimitiveType(PrimitiveType pt) {
this->type = pt;
switch (pt) {
case PrimitiveType::NONE:
case PrimitiveType::POINTS:
primitiveTopology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
break;
@@ -184,16 +184,6 @@ VkFormat getVkFormat(TextureFormat format) {
case TextureFormat::DXT5_RGBA: return VK_FORMAT_BC3_UNORM_BLOCK;
case TextureFormat::DXT5_SRGBA: return VK_FORMAT_BC3_SRGB_BLOCK;
case TextureFormat::RED_RGTC1: return VK_FORMAT_BC4_UNORM_BLOCK;
case TextureFormat::SIGNED_RED_RGTC1: return VK_FORMAT_BC4_SNORM_BLOCK;
case TextureFormat::RED_GREEN_RGTC2: return VK_FORMAT_BC5_UNORM_BLOCK;
case TextureFormat::SIGNED_RED_GREEN_RGTC2: return VK_FORMAT_BC5_SNORM_BLOCK;
case TextureFormat::RGB_BPTC_SIGNED_FLOAT: return VK_FORMAT_BC6H_SFLOAT_BLOCK;
case TextureFormat::RGB_BPTC_UNSIGNED_FLOAT: return VK_FORMAT_BC6H_UFLOAT_BLOCK;
case TextureFormat::RGBA_BPTC_UNORM: return VK_FORMAT_BC7_UNORM_BLOCK;
case TextureFormat::SRGB_ALPHA_BPTC_UNORM: return VK_FORMAT_BC7_SRGB_BLOCK;
case TextureFormat::RGBA_ASTC_4x4: return VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
case TextureFormat::RGBA_ASTC_5x4: return VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
case TextureFormat::RGBA_ASTC_5x5: return VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
+37 -13
View File
@@ -22,12 +22,8 @@
#include <spirv_glsl.hpp>
#include <spirv_msl.hpp>
#include "../src/GLSLPostProcessor.h"
#include "builtinResource.h"
#include <utils/FixedCapacityVector.h>
#include <iostream>
#include <utility>
#include <vector>
@@ -63,6 +59,38 @@ void SpvToGlsl(const SpirvBlob* spirv, std::string* outGlsl) {
*outGlsl = glslCompiler.compile();
}
void SpvToMsl(const SpirvBlob* spirv, std::string* outMsl) {
CompilerMSL mslCompiler(*spirv);
mslCompiler.set_msl_options(CompilerMSL::Options {
.msl_version = CompilerMSL::Options::make_msl_version(1, 1)
});
auto executionModel = mslCompiler.get_execution_model();
auto duplicateResourceBinding = [executionModel, &mslCompiler](const auto& resource) {
auto set = mslCompiler.get_decoration(resource.id, spv::DecorationDescriptorSet);
auto binding = mslCompiler.get_decoration(resource.id, spv::DecorationBinding);
MSLResourceBinding newBinding;
newBinding.stage = executionModel;
newBinding.desc_set = set;
newBinding.binding = binding;
newBinding.msl_texture = binding;
newBinding.msl_sampler = binding;
newBinding.msl_buffer = binding;
mslCompiler.add_msl_resource_binding(newBinding);
};
auto resources = mslCompiler.get_shader_resources();
for (const auto& resource : resources.sampled_images) {
duplicateResourceBinding(resource);
}
for (const auto& resource : resources.uniform_buffers) {
duplicateResourceBinding(resource);
}
*outMsl = mslCompiler.compile();
}
} // anonymous namespace
void ShaderGenerator::init() {
@@ -74,16 +102,15 @@ void ShaderGenerator::shutdown() {
}
ShaderGenerator::ShaderGenerator(std::string vertex, std::string fragment,
Backend backend, bool isMobile, const filament::SamplerInterfaceBlock* sib) noexcept
Backend backend, bool isMobile) noexcept
: mBackend(backend),
mVertexBlob(transpileShader(ShaderStage::VERTEX, std::move(vertex), backend, isMobile, sib)),
mVertexBlob(transpileShader(ShaderStage::VERTEX, std::move(vertex), backend, isMobile)),
mFragmentBlob(transpileShader(ShaderStage::FRAGMENT, std::move(fragment), backend,
isMobile, sib)) {
isMobile)) {
}
ShaderGenerator::Blob ShaderGenerator::transpileShader(
ShaderStage stage, std::string shader, Backend backend, bool isMobile,
const filament::SamplerInterfaceBlock* sib) noexcept {
ShaderStage stage, std::string shader, Backend backend, bool isMobile) noexcept {
TProgram program;
const EShLanguage language = stage == ShaderStage::VERTEX ? EShLangVertex : EShLangFragment;
TShader tShader(language);
@@ -146,10 +173,7 @@ ShaderGenerator::Blob ShaderGenerator::transpileShader(
}
return { result.c_str(), result.c_str() + result.length() + 1 };
} else if (backend == Backend::METAL) {
const auto sm = isMobile ? ShaderModel::MOBILE : ShaderModel::DESKTOP;
filamat::SibVector sibs = filamat::SibVector::with_capacity(1);
if (sib) { sibs.emplace_back(0, sib); }
filamat::GLSLPostProcessor::spirvToMsl(&spirv, &result, sm, false, sibs, nullptr);
SpvToMsl(&spirv, &result);
return { result.c_str(), result.c_str() + result.length() + 1 };
} else if (backend == Backend::VULKAN) {
return { (uint8_t*)spirv.data(), (uint8_t*)(spirv.data() + spirv.size()) };
+2 -4
View File
@@ -19,7 +19,6 @@
#include "PlatformRunner.h"
#include "private/filament/SamplerInterfaceBlock.h"
#include "private/backend/DriverApi.h"
#include "backend/Program.h"
@@ -39,8 +38,7 @@ public:
* @param vertex The vertex shader, written in GLSL 450 core.
* @param fragment The fragment shader, written in GLSL 450 core.
*/
ShaderGenerator(std::string vertex, std::string fragment, Backend backend, bool isMobile,
const filament::SamplerInterfaceBlock* sib = nullptr) noexcept;
ShaderGenerator(std::string vertex, std::string fragment, Backend backend, bool isMobile) noexcept;
ShaderGenerator(const ShaderGenerator& rhs) = delete;
ShaderGenerator& operator=(const ShaderGenerator& rhs) = delete;
@@ -52,7 +50,7 @@ private:
using Blob = std::vector<char>;
static Blob transpileShader(ShaderStage stage, std::string shader, Backend backend,
bool isMobile, const filament::SamplerInterfaceBlock* sib = nullptr) noexcept;
bool isMobile) noexcept;
Backend mBackend;
+1 -6
View File
@@ -133,12 +133,7 @@ TEST_F(BackendTest, FeedbackLoops) {
// Create a program.
ProgramHandle program;
{
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
.name("backend_test_sib")
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
.add( {{"tex", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH }} )
.build();
ShaderGenerator shaderGen(fullscreenVs, fullscreenFs, sBackend, sIsMobilePlatform, &sib);
ShaderGenerator shaderGen(fullscreenVs, fullscreenFs, sBackend, sIsMobilePlatform);
Program prog = shaderGen.getProgram(api);
Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
+12 -31
View File
@@ -19,7 +19,6 @@
#include "ShaderGenerator.h"
#include "TrianglePrimitive.h"
#include "private/filament/SamplerInterfaceBlock.h"
#include "private/backend/SamplerGroup.h"
#include <math/half.h>
@@ -55,7 +54,7 @@ layout(location = 0) out vec4 fragColor;
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
// This parameter is ignored for other backends.
layout(location = 0, set = 1) uniform {samplerType} test_tex;
layout(location = 0, set = 1) uniform {samplerType} tex;
void main() {
vec2 fbsize = vec2(512);
@@ -63,7 +62,7 @@ void main() {
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT)
uv.y = 1.0 - uv.y;
#endif
fragColor = vec4(texture(test_tex, uv).rgb, 1.0f);
fragColor = vec4(texture(tex, uv).rgb, 1.0f);
}
)");
@@ -73,7 +72,8 @@ std::string fragmentUpdateImage3DTemplate (R"(#version 450 core
layout(location = 0) out vec4 fragColor;
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
layout(location = 0, set = 1) uniform {samplerType} test_tex;
// This parameter is ignored for other backends.
layout(location = 0, set = 1) uniform {samplerType} tex;
float getLayer(in sampler3D s) { return 2.5f / 4.0f; }
float getLayer(in sampler2DArray s) { return 2.0f; }
@@ -84,7 +84,7 @@ void main() {
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT)
uv.y = 1.0 - uv.y;
#endif
fragColor = vec4(texture(test_tex, vec3(uv, getLayer(test_tex))).rgb, 1.0f);
fragColor = vec4(texture(tex, vec3(uv, getLayer(tex))).rgb, 1.0f);
}
)");
@@ -94,7 +94,8 @@ std::string fragmentUpdateImageMip (R"(#version 450 core
layout(location = 0) out vec4 fragColor;
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
layout(location = 0, set = 1) uniform sampler2D test_tex;
// This parameter is ignored for other backends.
layout(location = 0, set = 1) uniform sampler2D tex;
void main() {
vec2 fbsize = vec2(512);
@@ -102,7 +103,7 @@ void main() {
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT)
uv.y = 1.0 - uv.y;
#endif
fragColor = vec4(textureLod(test_tex, uv, 1.0f).rgb, 1.0f);
fragColor = vec4(textureLod(tex, uv, 1.0f).rgb, 1.0f);
}
)");
@@ -344,15 +345,10 @@ TEST_F(BackendTest, UpdateImage2D) {
auto defaultRenderTarget = api.createDefaultRenderTarget(0);
// Create a program.
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
.name("Test")
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
.add( {{"tex", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH }} )
.build();
ProgramHandle program;
std::string fragment = stringReplace("{samplerType}",
getSamplerTypeName(t.textureFormat), fragmentTemplate);
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
Program prog = shaderGen.getProgram(api);
Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
@@ -429,14 +425,9 @@ TEST_F(BackendTest, UpdateImageSRGB) {
auto defaultRenderTarget = api.createDefaultRenderTarget(0);
// Create a program.
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
.name("Test")
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
.add( {{"tex", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH }} )
.build();
std::string fragment = stringReplace("{samplerType}",
getSamplerTypeName(textureFormat), fragmentTemplate);
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
Program prog = shaderGen.getProgram(api);
Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
@@ -520,14 +511,9 @@ TEST_F(BackendTest, UpdateImageMipLevel) {
auto defaultRenderTarget = api.createDefaultRenderTarget(0);
// Create a program.
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
.name("Test")
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
.add( {{"tex", SamplerType::SAMPLER_3D, SamplerFormat::FLOAT, Precision::HIGH }} )
.build();
std::string fragment = stringReplace("{samplerType}",
getSamplerTypeName(textureFormat), fragmentUpdateImageMip);
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
Program prog = shaderGen.getProgram(api);
Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
@@ -597,14 +583,9 @@ TEST_F(BackendTest, UpdateImage3D) {
auto defaultRenderTarget = api.createDefaultRenderTarget(0);
// Create a program.
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
.name("Test")
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
.add( {{"tex", SamplerType::SAMPLER_3D, SamplerFormat::FLOAT, Precision::HIGH }} )
.build();
std::string fragment = stringReplace("{samplerType}",
getSamplerTypeName(samplerType), fragmentUpdateImage3DTemplate);
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
Program prog = shaderGen.getProgram(api);
Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
@@ -45,7 +45,7 @@ std::string fragment (R"(#version 450 core
layout(location = 0) out vec4 fragColor;
layout(location = 0) in vec2 uv;
layout(location = 0, set = 1) uniform sampler2D tex;
layout(set = 1, binding = 6) uniform sampler2D tex;
void main() {
fragColor = texture(tex, uv);
@@ -65,16 +65,11 @@ TEST_F(BackendTest, RenderExternalImageWithoutSet) {
auto swapChain = createSwapChain();
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
.name("backend_test_sib")
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
.add( {{"tex", SamplerType::SAMPLER_EXTERNAL, SamplerFormat::FLOAT, Precision::HIGH }} )
.build();
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
// Create a program that samples a texture.
Program p = shaderGen.getProgram(getDriverApi());
Program::Sampler sampler { utils::CString("tex"), 0 };
Program::Sampler sampler { utils::CString("tex"), 6 };
p.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, &sampler, 1);
backend::Handle<HwProgram> program = getDriverApi().createProgram(std::move(p));
@@ -144,16 +139,11 @@ TEST_F(BackendTest, RenderExternalImage) {
auto swapChain = createSwapChain();
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
.name("backend_test_sib")
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
.add( {{"tex", SamplerType::SAMPLER_EXTERNAL, SamplerFormat::FLOAT, Precision::HIGH }} )
.build();
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
// Create a program that samples a texture.
Program p = shaderGen.getProgram(getDriverApi());
Program::Sampler sampler { utils::CString("tex"), 0 };
Program::Sampler sampler { utils::CString("tex"), 6 };
p.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, &sampler, 1);
auto program = getDriverApi().createProgram(std::move(p));
+9 -76
View File
@@ -11,7 +11,7 @@
</style>
**Vulkan Backend**
*Last updated: 26 October 2022*
*Last updated: 11 June 2021*
![](../../docs/images/filament_logo.png)
@@ -47,7 +47,7 @@ single `VkDevice` and `VkInstance`.
* | | | | *
* |------------------------------------------| |-----------------------------------------| *
* | | | | *
* | Helpers VulkanContext | | VulkanTexture VulkanTexture | *
* | Helpers VulkanContext | | SwapContext SwapContext | *
* | .--------------. .---------------. | | .----------------+----------------. | *
* | | PipelineCache| | VkDevice | | | | VkImage | VkImage | | *
* | +--------------+ | VkInstance | | | | VkImageView | VkImageView | | *
@@ -91,14 +91,13 @@ that are defined in `DriverBase.h`.
Most of the handle types do not contain much logic, but they often do more than mere wrapping of
Vk objects. Notably, `VulkanRenderTarget` does not have a straightforward mapping to any one Vk
object. See its class comment for details. Also, `VulkanTexture` and `VulkanSwapChain` have their
own cpps file because of complexity around layouts and subresources.
object. See its class comment for details.
VulkanProgram
: Descends from `HwProgram`, owns a pair of `VkShaderModule`.
VulkanRenderTarget
: Descends from `HwRenderTarget`, contains references to `VulkanTexture` objects.
: Descends from `HwRenderTarget`, contains references to `VkImage` objects.
VulkanSwapChain
: Descends from `HwSwapChain`, has a reference to `VkSurfaceKHR` and `VkSwapchainKHR`.
@@ -128,16 +127,14 @@ they do follow a common set of conventions. For example, most of them implement
that is called once per frame to free unused objects.
VulkanPipelineCache
: Cache of VkDescriptorSet, VkPipeline, and VkPipelineLayout.
: Cache of VkDescriptorSet and VkPipeline.
VulkanDisposer
: Holds reference counts to Vulkan objects in order to defer their destruction.
VulkanFboCache
: Cache of VkRenderPass and VkFramebuffer. Contains weak references to VkImage handles, but does not
own any pixel data. The cache key for render passes is quite complex because it needs to include
image layout information in a compact way. For details see the comments in the `RenderPassKey`
declaration.
own any pixel data.
VulkanStagePool
: Pool of VkBuffer objects that can be memory mapped (shared between host and device).
@@ -152,71 +149,6 @@ no subfolders. All backend-specific types and functions live directly in the `fi
namespace, and we simply prefix our names with "Vulkan" when necessary to avoid ambiguation with
OpenGL.
# Image Layout Strategy
Adhering to a coherent strategy for image layout transitions is crucial. Without this, validation
errors (and actual black screens with some GPU vendors) occur far too easily and can feel like
whack-a-mole.
Vulkan provides several mechanisms for transitioning layout (render passes, barriers) so the
strategy outlined below specifies which mechanism should be used in various scenarios.
The current image layouts are tracked at the subresource level in `VulkanTexture` using a
specialized STL-ish container that we designed for this purpose:
[RangeMap](https://github.com/google/filament/blob/main/libs/utils/include/utils/RangeMap.h).
In the past we tried to avoid tracking since it theoritically duplicates state that exists in the
GPU vendor's driver. However in practice this was impossible to manage, because complex logic was
required to deduce the current layout. Also, tracking lets us use `assert_invariant` in many places
to ensure that the behavior described in this document is implemented properly. It is much easier
to catch errors with asserts than with validation.
As of this writing, the current rules are:
(1) **Read-Only Color Textures**
These should be created in an UNDEFINED state and stay that way until data gets uploaded into them,
at which point the appropriate subresources are transitioned to TRANSFER_DST_OPTIMAL for the upload,
then to SHADER_READ_ONLY_OPTIMAL, both times using a barrier. Note that a subresource might be
updated several times; each time it undergoes these two transitions.
If a shader samples from a texture whose mipmaps are only partially loaded, we might see validation
warnings about how some subresources are in an UNDEFINED layout. However if we are properly using
the `setMinMaxLevels` driver API, then the Vulkan backend will not bind those particular
subresources, so validation should not complain.
(2) **Writeable Color Textures**
During construction of the HwTexture, these are transitioned to GENERAL using a barrier.
GENERAL layout is not recommended by AMD best practices but in our case we wish to avoid thrashing
the layout between COLOR_ATTACHMENT_OPTIMAL and SHADER_READ_ONLY_OPTIMAL for post-processing
effects. Moreover we do not have a priori knowledge about blitting and read pixels usage.
(3) **Depth Textures**
During construction of the HwTexture, these are transitioned to GENERAL using a barrier.
Note that some post-processing passes (e.g. SSAO) sample from the depth buffer while also enabling
depth testing. Using GENERAL makes this legal.
(4) **Swap Chain Textures**
During construction, these are transitioned to GENERAL using a barrier. They are then transitioned
to PRESENT at the end of the frame using a barrier, and transitioned back to GENERAL using the first
render pass of the frame.
Note that we transition to PRESENT using a barrier, but with some GPU vendors it might be preferable
to transition them using the last render pass. However we have no way of knowing ahead of time which
pass is last.
Note that Filament allows swap chains to be used as blit targets and blit sources (e.g. for
ReadPixels). Using GENERAL makes this easier to manage.
(5) **Headless Swap Chain Textures**
These follow the same rules as writeable color texture and depth textures.
# VulkanPipelineCache
Uniforms, samplers, and shaders are not directly bindable in Vulkan; instead they are bound through
@@ -229,6 +161,8 @@ public methods. See its header file for details.
The pipeline cache also manages the *layout objects*, which constrain the number of uniform buffers
and samplers that can be bound simultaneously (see `VkDescriptorSetLayout` and `VkPipelineLayout`).
Here we take advantage of Filament's opinionated shading model in order to keep things simple, which
allows us to create only one layout for the entire lifetime of the app.
# Memory Allocation
@@ -262,8 +196,7 @@ Here we list some of the most significant issues and to-be-done items for the Vu
- Improve the UBO strategy
- Currently we use staging buffers and perform lots of copies (host-to-host, then host-to-device)
- Consider an approach similar to MetalDriver, which effectively implements double-buffering
using a pool of shared mem buffers
- Consider an approach similar to MetalDriver, which effectively implements double-buffering using a pool of shared mem buffers
- Consider using subpasses for the depth prepass
- We lazily create pipeline objects
1. This is notoriously slow in Vulkan
+19 -23
View File
@@ -40,33 +40,33 @@ using sRGBColorA = math::float4;
//! types of RGB colors
enum class RgbType : uint8_t {
sRGB, //!< the color is defined in Rec.709-sRGB-D65 (sRGB) space
LINEAR, //!< the color is defined in Rec.709-Linear-D65 ("linear sRGB") space
sRGB, //!< the color is defined in sRGB space
LINEAR, //!< the color is defined in linear space
};
//! types of RGBA colors
enum class RgbaType : uint8_t {
/**
* the color is defined in Rec.709-sRGB-D65 (sRGB) space and the RGB values
* have not been pre-multiplied by the alpha (for instance, a 50%
* the color is defined in sRGB space and the RGB values
* have not been premultiplied by the alpha (for instance, a 50%
* transparent red is <1,0,0,0.5>)
*/
sRGB,
/**
* the color is defined in Rec.709-Linear-D65 ("linear sRGB") space and the
* RGB values have not been pre-multiplied by the alpha (for instance, a 50%
* the color is defined in linear space and the RGB values
* have not been premultiplied by the alpha (for instance, a 50%
* transparent red is <1,0,0,0.5>)
*/
LINEAR,
/**
* the color is defined in Rec.709-sRGB-D65 (sRGB) space and the RGB values
* have been pre-multiplied by the alpha (for instance, a 50%
* the color is defined in sRGB space and the RGB values
* have been premultiplied by the alpha (for instance, a 50%
* transparent red is <0.5,0,0,0.5>)
*/
PREMULTIPLIED_sRGB,
/**
* the color is defined in Rec.709-Linear-D65 ("linear sRGB") space and the
* RGB values have been pre-multiplied by the alpha (for instance, a 50%
* the color is defined in linear space and the RGB values
* have been premultiplied by the alpha (for instance, a 50%
* transparent red is <0.5,0,0,0.5>)
*/
PREMULTIPLIED_LINEAR
@@ -93,44 +93,40 @@ public:
template<ColorConversion = ACCURATE>
static LinearColor toLinear(sRGBColor const& color);
/**
* Converts an RGB color in Rec.709-Linear-D65 ("linear sRGB") space to an
* RGB color in Rec.709-sRGB-D65 (sRGB) space.
*/
//! converts an RGB color in linear space to an RGB color in sRGB space
template<ColorConversion = ACCURATE>
static sRGBColor toSRGB(LinearColor const& color);
/**
* Converts an RGBA color in Rec.709-sRGB-D65 (sRGB) space to an RGBA color in
* Rec.709-Linear-D65 ("linear sRGB") space the alpha component is left unmodified.
* converts an RGBA color in sRGB space to an RGBA color in linear space
* the alpha component is left unmodified
*/
template<ColorConversion = ACCURATE>
static LinearColorA toLinear(sRGBColorA const& color);
/**
* Converts an RGBA color in Rec.709-Linear-D65 ("linear sRGB") space to
* an RGBA color in Rec.709-sRGB-D65 (sRGB) space the alpha component is
* left unmodified.
* converts an RGBA color in linear space to an RGBA color in sRGB space
* the alpha component is left unmodified
*/
template<ColorConversion = ACCURATE>
static sRGBColorA toSRGB(LinearColorA const& color);
/**
* Converts a correlated color temperature to a linear RGB color in sRGB
* converts a correlated color temperature to a linear RGB color in sRGB
* space the temperature must be expressed in kelvin and must be in the
* range 1,000K to 15,000K.
* range 1,000K to 15,000K
*/
static LinearColor cct(float K);
/**
* Converts a CIE standard illuminant series D to a linear RGB color in
* converts a CIE standard illuminant series D to a linear RGB color in
* sRGB space the temperature must be expressed in kelvin and must be in
* the range 4,000K to 25,000K
*/
static LinearColor illuminantD(float K);
/**
* Computes the Beer-Lambert absorption coefficients from the specified
* computes the Beer-Lambert absorption coefficients from the specified
* transmittance color and distance. The computed absorption will guarantee
* the white light will become the specified color at the specified distance.
* The output of this function can be used as the absorption parameter of
-18
View File
@@ -31,10 +31,6 @@ namespace filament {
class Engine;
class FColorGrading;
namespace color {
class ColorSpace;
}
/**
* ColorGrading is used to transform (either to modify or correct) the colors of the HDR buffer
* rendered by Filament. Color grading transforms are applied after lighting, and after any lens
@@ -101,7 +97,6 @@ class ColorSpace;
* - Tone mapping: ACESLegacyToneMapper
* - Luminance scaling: false
* - Gamut mapping: false
* - Output color space: Rec709-sRGB-D65
*
* @see View
*/
@@ -452,19 +447,6 @@ public:
*/
Builder& curves(math::float3 shadowGamma, math::float3 midPoint, math::float3 highlightScale) noexcept;
/**
* Sets the output color space for this ColorGrading object. After all color grading steps
* have been applied, the final color will be converted in the desired color space.
*
* NOTE: Currently the output color space must be one of Rec709-sRGB-D65 or
* Rec709-Linear-D65. Only the transfer function is taken into account.
*
* @param colorSpace The output color space.
*
* @return This Builder, for chaining calls
*/
Builder& outputColorSpace(const color::ColorSpace& colorSpace) noexcept;
/**
* Creates the ColorGrading object and returns a pointer to it.
*
-256
View File
@@ -1,256 +0,0 @@
/*
* Copyright (C) 2015 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_COLOR_SPACE_H
#define TNT_FILAMENT_COLOR_SPACE_H
#include <math/vec2.h>
#include <math/vec3.h>
namespace filament {
namespace color {
using namespace math;
/**
* Holds the chromaticities of a color space's primaries as xy coordinates
* in xyY (Y is assumed to be 1).
*/
struct Primaries {
float2 r;
float2 g;
float2 b;
bool operator==(const Primaries& rhs) const noexcept {
return r == rhs.r && b == rhs.b && g == rhs.b;
}
};
//! Reference white for a color space, defined as the xy coordinates in the xyY space.
using WhitePoint = float2;
/**
* <p>Defines the parameters for the ICC parametric curve type 4, as
* defined in ICC.1:2004-10, section 10.15.</p>
*
* <p>The EOTF is of the form:</p>
*
* \(\begin{equation}
* Y = \begin{cases}c X + f & X \lt d \\\
* \left( a X + b \right) ^{g} + e & X \ge d \end{cases}
* \end{equation}\)
*
* <p>The corresponding OETF is simply the inverse function.</p>
*
* <p>The parameters defined by this class form a valid transfer
* function only if all the following conditions are met:</p>
* <ul>
* <li>No parameter is a NaN</li>
* <li>\(d\) is in the range \([0..1]\)</li>
* <li>The function is not constant</li>
* <li>The function is positive and increasing</li>
* </ul>
*/
struct TransferFunction {
/**
* <p>Defines the parameters for the ICC parametric curve type 3, as
* defined in ICC.1:2004-10, section 10.15.</p>
*
* <p>The EOTF is of the form:</p>
*
* \(\begin{equation}
* Y = \begin{cases}c X & X \lt d \\\
* \left( a X + b \right) ^{g} & X \ge d \end{cases}
* \end{equation}\)
*
* <p>This constructor is equivalent to setting \(e\) and \(f\) to 0.</p>
*
* @param a The value of \(a\) in the equation of the EOTF described above
* @param b The value of \(b\) in the equation of the EOTF described above
* @param c The value of \(c\) in the equation of the EOTF described above
* @param d The value of \(d\) in the equation of the EOTF described above
* @param g The value of \(g\) in the equation of the EOTF described above
*/
constexpr TransferFunction(
double a,
double b,
double c,
double d,
double e,
double f,
double g
) : a(a),
b(b),
c(c),
d(d),
e(e),
f(f),
g(g) {
}
constexpr TransferFunction(
double a,
double b,
double c,
double d,
double g
) : TransferFunction(a, b, c, d, 0.0, 0.0, g) {
}
bool operator==(const TransferFunction& rhs) const noexcept {
return
a == rhs.a &&
b == rhs.b &&
c == rhs.c &&
d == rhs.d &&
e == rhs.e &&
f == rhs.f &&
g == rhs.g;
}
double a;
double b;
double c;
double d;
double e;
double f;
double g;
};
/**
* <p>A color space in Filament is always an RGB color space. A specific RGB color space
* is defined by the following properties:</p>
* <ul>
* <li>Three chromaticities of the red, green and blue primaries, which
* define the gamut of the color space.</li>
* <li>A white point chromaticity that defines the stimulus to which
* color space values are normalized (also just called "white").</li>
* <li>An opto-electronic transfer function, also called opto-electronic
* conversion function or often, and approximately, gamma function.</li>
* <li>An electro-optical transfer function, also called electo-optical
* conversion function or often, and approximately, gamma function.</li>
* </ul>
*
* <h3>Primaries and white point chromaticities</h3>
* <p>In this implementation, the chromaticity of the primaries and the white
* point of an RGB color space is defined in the CIE xyY color space. This
* color space separates the chromaticity of a color, the x and y components,
* and its luminance, the Y component. Since the primaries and the white
* point have full brightness, the Y component is assumed to be 1 and only
* the x and y components are needed to encode them.</p>
*
* <h3>Transfer functions</h3>
* <p>A transfer function is a color component conversion function, defined as
* a single variable, monotonic mathematical function. It is applied to each
* individual component of a color. They are used to perform the mapping
* between linear tristimulus values and non-linear electronic signal value.</p>
* <p>The <em>opto-electronic transfer function</em> (OETF or OECF) encodes
* tristimulus values in a scene to a non-linear electronic signal value.</p>
*/
class ColorSpace {
public:
constexpr ColorSpace(
const Primaries primaries,
const TransferFunction transferFunction,
const WhitePoint whitePoint
) : mPrimaries(primaries),
mTransferFunction(transferFunction),
mWhitePoint(whitePoint) {
}
bool operator==(const ColorSpace& rhs) const noexcept {
return mPrimaries == rhs.mPrimaries &&
mTransferFunction == rhs.mTransferFunction &&
mWhitePoint == rhs.mWhitePoint;
}
constexpr const Primaries& getPrimaries() const { return mPrimaries; }
constexpr const TransferFunction& getTransferFunction() const { return mTransferFunction; }
constexpr const WhitePoint& getWhitePoint() const { return mWhitePoint; }
private:
Primaries mPrimaries;
TransferFunction mTransferFunction;
WhitePoint mWhitePoint;
};
/**
* Intermediate class used when building a color space using the "-" syntax:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* // Declares a "linear sRGB" color space.
* ColorSpace myColorSpace = Rec709-Linear-sRGB;
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
class PartialColorSpace {
public:
constexpr ColorSpace operator-(const WhitePoint whitePoint) const {
return ColorSpace(mPrimaries, mTransferFunction, whitePoint);
}
private:
constexpr PartialColorSpace(
const Primaries primaries,
const TransferFunction transferFunction
) : mPrimaries(primaries),
mTransferFunction(transferFunction) {
}
Primaries mPrimaries;
TransferFunction mTransferFunction;
friend class Gamut;
};
/**
* Defines the chromaticities of the primaries for a color space. The chromaticities
* are expressed as three pairs of xy coordinates (in xyY) for the red, green, and blue
* chromaticities.
*/
class Gamut {
public:
constexpr Gamut(const Primaries primaries) : mPrimaries(primaries) {
}
constexpr Gamut(float2 r, float2 g, float2 b) : Gamut(Primaries{r, g, b}) {
}
constexpr PartialColorSpace operator-(const TransferFunction transferFunction) const {
return PartialColorSpace(mPrimaries, transferFunction);
}
constexpr const Primaries& getPrimaries() const { return mPrimaries; }
private:
Primaries mPrimaries;
};
//! Rec.709 color gamut, used in the sRGB and DisplayP3 color spaces.
constexpr Gamut Rec709 = Gamut({0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f});
//! Linear transfer function.
constexpr TransferFunction Linear = TransferFunction(1.0, 0.0, 0.0, 0.0, 1.0);
//! sRGB transfer function.
constexpr TransferFunction sRGB =
TransferFunction(1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045, 2.4);
//! Standard CIE 1931 2° illuminant D65. This illuminant has a color temperature of 6504K.
constexpr WhitePoint D65 = WhitePoint({0.31271f, 0.32902f});
} // namespace color
} // namespace filament
#endif // TNT_FILAMENT_COLOR_SPACE_H
+8
View File
@@ -340,6 +340,14 @@ public:
* @see View::setShadowType
*/
struct Vsm {
/**
* The number of MSAA samples to use when rendering VSM shadow maps.
* Must be a power-of-two and greater than or equal to 1. A value of 1 effectively turns
* off MSAA.
* Higher values may not be available depending on the underlying hardware.
*/
uint8_t msaaSamples = 1;
/**
* When elvsm is set to true, "Exponential Layered VSM without Layers" are used. It is
* an improvement to the default EVSM which suffers important light leaks. Enabling
@@ -277,12 +277,6 @@ public:
*/
void setMaskThreshold(float threshold) noexcept;
/**
* Gets the minimum alpha value a fragment must have to not be discarded when the blend
* mode is MASKED
*/
float getMaskThreshold() const noexcept;
/**
* Sets the screen space variance of the filter kernel used when applying specular
* anti-aliasing. The default value is set to 0.15. The specified value should be between
@@ -290,12 +284,6 @@ public:
*/
void setSpecularAntiAliasingVariance(float variance) noexcept;
/**
* Gets the screen space variance of the filter kernel used when applying specular
* anti-aliasing.
*/
float getSpecularAntiAliasingVariance() const noexcept;
/**
* Sets the clamping threshold used to suppress estimation errors when applying specular
* anti-aliasing. The default value is set to 0.2. The specified value should be between 0
@@ -303,12 +291,6 @@ public:
*/
void setSpecularAntiAliasingThreshold(float threshold) noexcept;
/**
* Gets the clamping threshold used to suppress estimation errors when applying specular
* anti-aliasing.
*/
float getSpecularAntiAliasingThreshold() const noexcept;
/**
* Enables or disables double-sided lighting if the parent Material has double-sided capability,
* otherwise prints a warning. If double-sided lighting is enabled, backface culling is
@@ -316,72 +298,36 @@ public:
*/
void setDoubleSided(bool doubleSided) noexcept;
/**
* Returns whether double-sided lighting is enabled when the parent Material has double-sided
* capability.
*/
bool isDoubleSided() const noexcept;
/**
* Specifies how transparent objects should be rendered (default is DEFAULT).
*/
void setTransparencyMode(TransparencyMode mode) noexcept;
/**
* Returns the transparency mode.
*/
TransparencyMode getTransparencyMode() const noexcept;
/**
* Overrides the default triangle culling state that was set on the material.
*/
void setCullingMode(CullingMode culling) noexcept;
/**
* Returns the face culling mode.
*/
CullingMode getCullingMode() const noexcept;
/**
* Overrides the default color-buffer write state that was set on the material.
*/
void setColorWrite(bool enable) noexcept;
/**
* Returns whether color write is enabled.
*/
bool isColorWriteEnabled() const noexcept;
/**
* Overrides the default depth-buffer write state that was set on the material.
*/
void setDepthWrite(bool enable) noexcept;
/**
* Returns whether depth write is enabled.
*/
bool isDepthWriteEnabled() const noexcept;
/**
* Overrides the default depth testing state that was set on the material.
*/
void setDepthCulling(bool enable) noexcept;
/**
* Returns whether depth culling is enabled.
*/
bool isDepthCullingEnabled() const noexcept;
/**
* Overrides the default stencil-buffer write state that was set on the material.
*/
void setStencilWrite(bool enable) noexcept;
/**
* Returns whether stencil write is enabled.
*/
bool isStencilWriteEnabled() const noexcept;
/**
* Sets the stencil comparison function (default is StencilCompareFunc::A).
*
-8
View File
@@ -390,14 +390,6 @@ struct VsmShadowOptions {
*/
bool mipmapping = false;
/**
* The number of MSAA samples to use when rendering VSM shadow maps.
* Must be a power-of-two and greater than or equal to 1. A value of 1 effectively turns
* off MSAA.
* Higher values may not be available depending on the underlying hardware.
*/
uint8_t msaaSamples = 1;
/**
* Whether to use a 32-bits or 16-bits texture format for VSM shadow maps. 32-bits
* precision is rarely needed, but it does reduces light leaks as well as "fading"
+1 -23
View File
@@ -117,37 +117,15 @@ public:
* ClearOptions are used at the beginning of a frame to clear or retain the SwapChain content.
*/
struct ClearOptions {
/**
* Color (sRGB linear) to use to clear the RenderTarget (typically the SwapChain).
*
* The RenderTarget is cleared using this color, which won't be tone-mapped since
* tone-mapping is part of View rendering (this is not).
*
* When a View is rendered, there are 3 scenarios to consider:
* - Pixels rendered by the View replace the clear color (or blend with it in
* `BlendMode::TRANSLUCENT` mode).
*
* - With blending mode set to `BlendMode::TRANSLUCENT`, Pixels untouched by the View
* are considered fulling transparent and let the clear color show through.
*
* - With blending mode set to `BlendMode::OPAQUE`, Pixels untouched by the View
* are set to the clear color. However, because it is now used in the context of a View,
* it will go through the post-processing stage, which includes tone-mapping.
*
* For consistency, it is recommended to always use a Skybox to clear an opaque View's
* background, or to use black or fully-transparent (i.e. {0,0,0,0}) as the clear color.
*/
/** Color to use to clear the SwapChain */
math::float4 clearColor = {};
/** Value to clear the stencil buffer */
uint8_t clearStencil = 0u;
/**
* Whether the SwapChain should be cleared using the clearColor. Use this if translucent
* View will be drawn, for instance.
*/
bool clear = false;
/**
* Whether the SwapChain content should be discarded. clear implies discard. Set this
* to false (along with clear to false as well) if the SwapChain already has content that
+9 -11
View File
@@ -80,7 +80,14 @@ public:
*
* @return The associated Skybox, or nullptr if there is none.
*/
Skybox* getSkybox() const noexcept;
Skybox* getSkybox() noexcept;
/**
* Returns an immutable Skybox associated with the Scene.
*
* @return The associated Skybox, or nullptr if there is none.
*/
Skybox const* getSkybox() const noexcept;
/**
* Set the IndirectLight to use when rendering the Scene.
@@ -89,17 +96,8 @@ public:
* IndirectLight.
*
* @param ibl The IndirectLight to use when rendering the Scene or nullptr to unset.
* @see getIndirectLight
*/
void setIndirectLight(IndirectLight* ibl) noexcept;
/**
* Get the IndirectLight or nullptr if none is set.
*
* @return the the IndirectLight or nullptr if none is set
* @see setIndirectLight
*/
IndirectLight* getIndirectLight() const noexcept;
void setIndirectLight(IndirectLight const* ibl) noexcept;
/**
* Adds an Entity to the Scene.
-177
View File
@@ -1,177 +0,0 @@
/*
* Copyright (C) 2022 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 "AtlasAllocator.h"
#include <utils/debug.h>
namespace filament {
using namespace utils;
static inline constexpr std::pair<uint8_t, uint8_t> unmorton(uint16_t m) noexcept {
uint32_t r = (m | (uint32_t(m) << 15u)) & 0x55555555u;
r = (r | (r >> 1u)) & 0x33333333u;
r = (r | (r >> 2u)) & 0x0f0f0f0fu;
r = r | (r >> 4u);
return { uint8_t(r), uint8_t(r >> 16u) };
}
AtlasAllocator::AtlasAllocator(size_t maxTextureSize) noexcept {
// round to power-of-two immediately inferior or equal to the size specified.
mMaxTextureSizePot = (sizeof(maxTextureSize) * 8 - 1u) - utils::clz(maxTextureSize);
}
AtlasAllocator::Allocation AtlasAllocator::allocate(size_t textureSize) noexcept {
Allocation result{};
const size_t powerOfTwo = (sizeof(textureSize) * 8 - 1u) - utils::clz(textureSize);
// asked for a texture size too large
if (UTILS_UNLIKELY(powerOfTwo > mMaxTextureSizePot)) {
return result;
}
// asked for a texture size too small
if (UTILS_UNLIKELY(mMaxTextureSizePot - powerOfTwo >= QUAD_TREE_DEPTH)) {
return result;
}
const size_t layer = (mMaxTextureSizePot - powerOfTwo);
const NodeId loc = allocateInLayer(LAYERS_DEPTH + layer);
if (loc.l >= 0) {
assert_invariant(loc.l - LAYERS_DEPTH == int8_t(layer));
const size_t dimension = 1u << powerOfTwo;
// find the location of in the texture from the morton code (quadtree position)
const auto [x, y] = unmorton(loc.code);
// scale to our maximum allocation size
const uint32_t mask = (1u << layer) - 1u;
result.viewport.left = int32_t(x & mask) << powerOfTwo;
result.viewport.bottom = int32_t(y & mask) << powerOfTwo;
result.viewport.width = dimension;
result.viewport.height = dimension;
result.layer = loc.code >> (2 * layer);
}
return result;
}
void AtlasAllocator::clear(size_t maxTextureSize) noexcept {
std::fill(mQuadTree.begin(), mQuadTree.end(), Node{});
mMaxTextureSizePot = (sizeof(maxTextureSize) * 8 - 1u) - utils::clz(maxTextureSize);
}
AtlasAllocator::NodeId AtlasAllocator::allocateInLayer(size_t maxHeight) noexcept {
using namespace QuadTreeUtils;
NodeId candidate{ -1, 0 };
if (UTILS_UNLIKELY(maxHeight > QuadTree::height())) {
return candidate;
}
const int8_t n = int8_t(maxHeight);
QuadTree::traverse(0, 0, n,
[this, n, &candidate](NodeId const& curr) -> QuadTree::TraversalResult {
// we should never reach a level higher than n
assert_invariant(curr.l <= n);
// get the node being processed
const size_t i = index(curr.l, curr.code);
Node const& node = mQuadTree[i];
// if the node is allocated, the whole tree below it is unavailable
if (node.isAllocated()) {
// if a node is allocated it can't have children
assert_invariant(!node.hasChildren());
return QuadTree::TraversalResult::SKIP_CHILDREN;
}
// we're looking for the `deepest` unallocated node that has no children,
// up to the depth we're trying to allocate
if (curr.l > candidate.l && !node.hasChildren()) {
candidate = curr;
// Special case where we found a fitting node, just exit.
if (curr.l == n) {
return QuadTree::TraversalResult::EXIT;
}
}
// We only want to find a fitting node that already has siblings, in order
// to accomplish a "best fit" allocation. So if a parent (of what we're looking for)
// has no children, we skip the whole tree below it.
if (!node.hasChildren()) {
return QuadTree::TraversalResult::SKIP_CHILDREN;
}
// continue going down the tree
return QuadTree::TraversalResult::RECURSE;
});
if (candidate.l >= 0) {
const size_t i = index(candidate.l, candidate.code);
Node& allocation = mQuadTree[i];
assert_invariant(!allocation.isAllocated());
assert_invariant(!allocation.hasChildren());
if (candidate.l == n) {
allocation.allocated = true;
if (UTILS_LIKELY(n > 0)) {
// the root doesn't have a parent
const size_t p = parent(candidate.l, candidate.code);
Node& parent = mQuadTree[p];
assert_invariant(!parent.isAllocated());
assert_invariant(parent.hasChildren());
assert_invariant(!parent.hasAllChildren());
parent.children++;
#ifndef NDEBUG
// check that all the parents are not allocated and have at least 1 child.
NodeId ppp = candidate;
while (ppp.l > 0) {
const size_t pi = QuadTreeUtils::parent(ppp.l, ppp.code);
ppp = NodeId{ int8_t(ppp.l - 1), uint8_t(ppp.code >> 2) };
Node& node = mQuadTree[pi];
assert_invariant(!node.isAllocated());
assert_invariant(node.hasChildren());
}
#endif
}
} else if (candidate.l < int8_t(QuadTree::height())) {
// we need to create the hierarchy down to the level we need
NodeId found{ -1, 0 };
QuadTree::traverse(candidate.l, candidate.code,
[this, n, &found](NodeId const& curr) -> QuadTree::TraversalResult {
size_t i = index(curr.l, curr.code);
Node& node = mQuadTree[i];
if (curr.l == n) {
found = curr;
assert_invariant(!node.hasChildren());
node.allocated = true;
return QuadTree::TraversalResult::EXIT;
}
assert_invariant(!node.hasAllChildren());
node.children++;
return QuadTree::TraversalResult::RECURSE;
});
assert_invariant(found.l != -1);
candidate = found;
}
}
return candidate;
}
} // namespace filament
-111
View File
@@ -1,111 +0,0 @@
/*
* Copyright (C) 2022 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_ATLASALLOCATOR_H
#define TNT_FILAMENT_ATLASALLOCATOR_H
#include <utils/QuadTree.h>
#include <filament/Viewport.h>
#include <private/filament/EngineEnums.h>
class AtlasAllocator_AllocateFirstLevel_Test;
class AtlasAllocator_AllocateSecondLevel_Test;
class AtlasAllocator_AllocateMixed0_Test;
class AtlasAllocator_AllocateMixed1_Test;
class AtlasAllocator_AllocateMixed2_Test;
namespace filament {
/*
* A 2D allocator. Allocations must be square and have a power-of-two size.
* AtlasAllocator hard codes a depth of 4, that is only 4 allocation sizes are permitted.
* This doesn't actually allocate memory, just manages space within an abstract 2D image.
*/
class AtlasAllocator {
/*
* A quadtree is used to track the allocated regions. Each node of the quadtree stores a
* `Node` data structure below.
* The `Node` tracks if it is allocated as well as the number of children it has. It doesn't
* track which children though.
*/
struct Node {
// whether this node is allocated. Implies no children.
constexpr bool isAllocated() const noexcept { return allocated; }
// whether this node has children. Implies it's not allocated.
constexpr bool hasChildren() const noexcept { return children != 0; }
// whether this node has all four children. Implies hasChildren().
constexpr bool hasAllChildren() const noexcept { return children == 4; }
bool allocated : 1; // true / false
uint8_t children : 3; // 0, 1, 2, 3, 4
};
// this determines the number of layers we can use (3 layers == 64 quadtree entries)
static constexpr size_t LAYERS_DEPTH = 3u;
// this determines how many "sub-sizes" we can have from the base size.
// e.g. with a max texture size of 1024, we can allocate 1024, 512, 256 and 128 textures.
static constexpr size_t QUAD_TREE_DEPTH = 4u;
// LAYERS_DEPTH limits the number of layers
static_assert(CONFIG_MAX_SHADOW_LAYERS <= 1u << (LAYERS_DEPTH * 2u));
// QuadTreeArray is limited to a maximum depth of 7
using QuadTree = utils::QuadTreeArray<Node, LAYERS_DEPTH + QUAD_TREE_DEPTH>;
using NodeId = QuadTree::NodeId;
public:
/*
* Create allocator and specify the maximum texture size. Must be a power of two.
* Allocations size allowed are the four power-of-two smaller or equal to this size.
*/
explicit AtlasAllocator(size_t maxTextureSize) noexcept;
/*
* Allocates a square of size `textureSize`. Must be one of the power-of-two allowed
* (see above).
* Returns the location of the allocation within the maxTextureSize^2 square.
*/
struct Allocation {
int32_t layer = -1;
Viewport viewport;
};
Allocation allocate(size_t textureSize) noexcept;
/*
* Frees all allocations and reset the maximum texture size.
*/
void clear(size_t maxTextureSize = 1024) noexcept;
private:
friend AtlasAllocator_AllocateFirstLevel_Test;
friend AtlasAllocator_AllocateSecondLevel_Test;
friend AtlasAllocator_AllocateMixed0_Test;
friend AtlasAllocator_AllocateMixed1_Test;
friend AtlasAllocator_AllocateMixed2_Test;
QuadTree::NodeId allocateInLayer(size_t n) noexcept;
// quad-tree array to store the allocated list
QuadTree mQuadTree{};
uint8_t mMaxTextureSizePot = 0;
};
} // namespace filament
#endif // TNT_FILAMENT_ATLASALLOCATOR_H
+1
View File
@@ -92,6 +92,7 @@ private:
template<size_t POOL_SIZE, size_t ALIGNMENT, typename AllocatorPolicy, typename LockingPolicy>
BufferPoolAllocator<POOL_SIZE, ALIGNMENT, AllocatorPolicy, LockingPolicy>::~BufferPoolAllocator() noexcept {
assert_invariant(mOutstandingBuffers == mEntries.size());
clearInternal();
}
+1 -1
View File
@@ -16,7 +16,7 @@
#include <filament/Color.h>
#include "ColorSpaceUtils.h"
#include "ColorSpace.h"
#include <math/mat3.h>
#include <math/scalar.h>
@@ -14,7 +14,7 @@
* limitations under the License.
*/
#include "ColorSpaceUtils.h"
#include "ColorSpace.h"
namespace filament {
@@ -296,10 +296,6 @@ inline float3 linearAP1_to_ACEScct(float3 x) noexcept {
return x;
}
inline float3 OETF_Linear(float3 x) noexcept {
return x;
}
inline float3 OETF_sRGB(float3 x) noexcept {
constexpr float a = 0.055f;
constexpr float a1 = 1.055f;
-40
View File
@@ -292,44 +292,4 @@ MaterialInstance* MaterialInstance::duplicate(MaterialInstance const* other, con
}
float MaterialInstance::getMaskThreshold() const noexcept {
return downcast(this)->getMaskThreshold();
}
float MaterialInstance::getSpecularAntiAliasingVariance() const noexcept {
return downcast(this)->getSpecularAntiAliasingVariance();
}
float MaterialInstance::getSpecularAntiAliasingThreshold() const noexcept {
return downcast(this)->getSpecularAntiAliasingThreshold();
}
bool MaterialInstance::isDoubleSided() const noexcept {
return downcast(this)->isDoubleSided();
}
TransparencyMode MaterialInstance::getTransparencyMode() const noexcept {
return downcast(this)->getTransparencyMode();
}
CullingMode MaterialInstance::getCullingMode() const noexcept {
return downcast(this)->getCullingMode();
}
bool MaterialInstance::isColorWriteEnabled() const noexcept {
return downcast(this)->isColorWriteEnabled();
}
bool MaterialInstance::isDepthWriteEnabled() const noexcept {
return downcast(this)->isDepthWriteEnabled();
}
bool MaterialInstance::isStencilWriteEnabled() const noexcept {
return downcast(this)->isStencilWriteEnabled();
}
bool MaterialInstance::isDepthCullingEnabled() const noexcept {
return downcast(this)->isDepthCullingEnabled();
}
} // namespace filament
-128
View File
@@ -1,128 +0,0 @@
/*
* Copyright (C) 2022 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 "PerShadowMapUniforms.h"
#include "ShadowMapManager.h"
#include "details/Camera.h"
#include "details/Engine.h"
#include <private/filament/EngineEnums.h>
namespace filament {
using namespace backend;
using namespace math;
PerShadowMapUniforms::PerShadowMapUniforms(FEngine& engine) noexcept {
DriverApi& driver = engine.getDriverApi();
mUniformBufferHandle = driver.createBufferObject(sizeof(PerViewUib),
BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC);
}
void PerShadowMapUniforms::terminate(DriverApi& driver) {
driver.destroyBufferObject(mUniformBufferHandle);
}
PerViewUib& PerShadowMapUniforms::edit(Transaction const& transaction) noexcept {
assert_invariant(transaction.uniforms);
return *transaction.uniforms;
}
void PerShadowMapUniforms::prepareCamera(Transaction const& transaction,
FEngine& engine, const CameraInfo& camera) noexcept {
mat4f const& viewFromWorld = camera.view;
mat4f const& worldFromView = camera.model;
mat4f const& clipFromView = camera.projection;
const mat4f viewFromClip{ inverse((mat4)camera.projection) };
const mat4f clipFromWorld{ highPrecisionMultiply(clipFromView, viewFromWorld) };
const mat4f worldFromClip{ highPrecisionMultiply(worldFromView, viewFromClip) };
auto& s = edit(transaction);
s.viewFromWorldMatrix = viewFromWorld; // view
s.worldFromViewMatrix = worldFromView; // model
s.clipFromViewMatrix = clipFromView; // projection
s.viewFromClipMatrix = viewFromClip; // 1/projection
s.clipFromWorldMatrix = clipFromWorld; // projection * view
s.worldFromClipMatrix = worldFromClip; // 1/(projection * view)
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);
// with a clip-space of [-w, w] ==> z' = -z
// with a clip-space of [0, w] ==> z' = (w - z)/2
s.clipControl = engine.getDriverApi().getClipSpaceParams();
}
void PerShadowMapUniforms::prepareLodBias(Transaction const& transaction,
float bias) noexcept {
auto& s = edit(transaction);
s.lodBias = bias;
}
void PerShadowMapUniforms::prepareViewport(Transaction const& transaction,
backend::Viewport const& viewport) noexcept {
float2 const dimensions{ viewport.width, viewport.height };
auto& s = edit(transaction);
s.resolution = { dimensions, 1.0f / dimensions };
s.logicalViewportScale = 1.0f;
s.logicalViewportOffset = 0.0f;
}
void PerShadowMapUniforms::prepareTime(Transaction const& transaction,
FEngine& engine, math::float4 const& userTime) noexcept {
auto& s = edit(transaction);
const uint64_t oneSecondRemainder = engine.getEngineTime().count() % 1000000000;
const float fraction = float(double(oneSecondRemainder) / 1000000000.0);
s.time = fraction;
s.userTime = userTime;
}
void PerShadowMapUniforms::prepareShadowMapping(Transaction const& transaction,
bool highPrecision) noexcept {
auto& s = edit(transaction);
constexpr float low = 5.54f; // ~ std::log(std::numeric_limits<math::half>::max()) * 0.5f;
constexpr float high = 42.0f; // ~ std::log(std::numeric_limits<float>::max()) * 0.5f;
s.vsmExponent = highPrecision ? high : low;
}
PerShadowMapUniforms::Transaction PerShadowMapUniforms::open(backend::DriverApi& driver) noexcept {
Transaction transaction;
// TODO: use out-of-line buffer if too large
transaction.uniforms = (PerViewUib *)driver.allocate(sizeof(PerViewUib));
assert_invariant(transaction.uniforms);
return transaction;
}
void PerShadowMapUniforms::commit(Transaction& transaction,
backend::DriverApi& driver) noexcept {
driver.updateBufferObject(mUniformBufferHandle, {
transaction.uniforms, sizeof(PerViewUib) }, 0);
transaction.uniforms = nullptr;
}
void PerShadowMapUniforms::bind(backend::DriverApi& driver) noexcept {
driver.bindUniformBuffer(+UniformBindingPoints::PER_VIEW, mUniformBufferHandle);
}
} // namespace filament
-91
View File
@@ -1,91 +0,0 @@
/*
* Copyright (C) 2022 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_PERSHADOWMAPUNIFORMS_H
#define TNT_FILAMENT_PERSHADOWMAPUNIFORMS_H
#include <filament/Viewport.h>
#include <private/filament/UibStructs.h>
#include <private/backend/SamplerGroup.h>
#include "TypedUniformBuffer.h"
#include <backend/Handle.h>
#include <utils/EntityInstance.h>
#include <random>
namespace filament {
struct CameraInfo;
class FEngine;
class LightManager;
/*
* PerShadowMapUniforms manages the UBO needed to generate our shadow maps. Internally it just
* holds onto a `PerViewUniform` UBO handle, but doesn't keep any shadow copy of it, instead it
* writes the data directly into the commandstream, for this reason partial update of the data
* is not possible.
*/
class PerShadowMapUniforms {
using LightManagerInstance = utils::EntityInstance<LightManager>;
public:
class Transaction {
friend PerShadowMapUniforms;
PerViewUib* uniforms = nullptr;
Transaction() = default; // disallow creation by the caller
};
explicit PerShadowMapUniforms(FEngine& engine) noexcept;
void terminate(backend::DriverApi& driver);
static void prepareCamera(Transaction const& transaction,
FEngine& engine, const CameraInfo& camera) noexcept;
static void prepareLodBias(Transaction const& transaction,
float bias) noexcept;
static void prepareViewport(Transaction const& transaction,
backend::Viewport const& viewport) noexcept;
static void prepareTime(Transaction const& transaction,
FEngine& engine, math::float4 const& userTime) noexcept;
static void prepareShadowMapping(Transaction const& transaction,
bool highPrecision) noexcept;
static Transaction open(backend::DriverApi& driver) noexcept;
// update local data into GPU UBO
void commit(Transaction& transaction, backend::DriverApi& driver) noexcept;
// bind this UBO
void bind(backend::DriverApi& driver) noexcept;
private:
static PerViewUib& edit(Transaction const& transaction) noexcept;
backend::Handle<backend::HwBufferObject> mUniformBufferHandle;
};
} // namespace filament
#endif //TNT_FILAMENT_PERSHADOWMAPUNIFORMS_H
+35 -27
View File
@@ -34,13 +34,15 @@
#include <math/mat4.h>
namespace filament {
using namespace backend;
using namespace math;
PerViewUniforms::PerViewUniforms(FEngine& engine) noexcept
: mSamplers(PerViewSib::SAMPLER_COUNT) {
: mEngine(engine),
mSamplers(PerViewSib::SAMPLER_COUNT) {
DriverApi& driver = engine.getDriverApi();
mSamplerGroupHandle = driver.createSamplerGroup(mSamplers.getSize());
@@ -48,6 +50,10 @@ PerViewUniforms::PerViewUniforms(FEngine& engine) noexcept
mUniformBufferHandle = driver.createBufferObject(mUniforms.getSize(),
BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC);
// with a clip-space of [-w, w] ==> z' = -z
// with a clip-space of [0, w] ==> z' = (w - z)/2
mClipControl = driver.getClipSpaceParams();
if (engine.getDFG().isValid()) {
TextureSampler sampler(TextureSampler::MagFilter::LINEAR);
mSamplers.setSampler(PerViewSib::IBL_DFG_LUT,
@@ -60,7 +66,7 @@ void PerViewUniforms::terminate(DriverApi& driver) {
driver.destroySamplerGroup(mSamplerGroupHandle);
}
void PerViewUniforms::prepareCamera(FEngine& engine, const CameraInfo& camera) noexcept {
void PerViewUniforms::prepareCamera(const CameraInfo& camera) noexcept {
mat4f const& viewFromWorld = camera.view;
mat4f const& worldFromView = camera.model;
mat4f const& clipFromView = camera.projection;
@@ -82,15 +88,17 @@ void PerViewUniforms::prepareCamera(FEngine& engine, const CameraInfo& camera) n
s.cameraFar = camera.zf;
s.oneOverFarMinusNear = 1.0f / (camera.zf - camera.zn);
s.nearOverFarMinusNear = camera.zn / (camera.zf - camera.zn);
// with a clip-space of [-w, w] ==> z' = -z
// with a clip-space of [0, w] ==> z' = (w - z)/2
s.clipControl = engine.getDriverApi().getClipSpaceParams();
s.clipControl = mClipControl;
}
void PerViewUniforms::prepareLodBias(float bias) noexcept {
void PerViewUniforms::prepareUpscaler(math::float2 scale,
DynamicResolutionOptions const& options) noexcept {
auto& s = mUniforms.edit();
s.lodBias = bias;
if (options.quality >= QualityLevel::HIGH) {
s.lodBias = std::log2(std::min(scale.x, scale.y));
} else {
s.lodBias = 0.0f;
}
}
void PerViewUniforms::prepareExposure(float ev100) noexcept {
@@ -100,32 +108,27 @@ void PerViewUniforms::prepareExposure(float ev100) noexcept {
s.ev100 = ev100;
}
void PerViewUniforms::prepareViewport(
const filament::Viewport& physicalViewport,
const filament::Viewport& logicalViewport) noexcept {
float4 const physical{ physicalViewport.left, physicalViewport.bottom,
physicalViewport.width, physicalViewport.height };
float4 const logical{ logicalViewport.left, logicalViewport.bottom,
logicalViewport.width, logicalViewport.height };
void PerViewUniforms::prepareViewport(const filament::Viewport& viewport,
uint32_t xoffset, uint32_t yoffset) noexcept {
const float w = float(viewport.width);
const float h = float(viewport.height);
auto& s = mUniforms.edit();
s.resolution = { physical.zw, 1.0f / physical.zw };
s.logicalViewportScale = physical.zw / logical.zw;
s.logicalViewportOffset = -logical.xy / logical.zw;
s.resolution = float4{ w, h, 1.0f / w, 1.0f / h };
s.origin = float2{ viewport.left, viewport.bottom };
s.offset = float2{ xoffset, yoffset };
}
void PerViewUniforms::prepareTime(FEngine& engine, math::float4 const& userTime) noexcept {
void PerViewUniforms::prepareTime(math::float4 const& userTime) noexcept {
auto& s = mUniforms.edit();
const uint64_t oneSecondRemainder = engine.getEngineTime().count() % 1000000000;
const uint64_t oneSecondRemainder = mEngine.getEngineTime().count() % 1000000000;
const float fraction = float(double(oneSecondRemainder) / 1000000000.0);
s.time = fraction;
s.userTime = userTime;
}
void PerViewUniforms::prepareTemporalNoise(FEngine& engine,
TemporalAntiAliasingOptions const& options) noexcept {
std::uniform_real_distribution<float> uniformDistribution{ 0.0f, 1.0f };
void PerViewUniforms::prepareTemporalNoise(TemporalAntiAliasingOptions const& options) noexcept {
auto& s = mUniforms.edit();
const float temporalNoise = uniformDistribution(engine.getRandomEngine());
const float temporalNoise = mUniformDistribution(mEngine.getRandomEngine());
s.temporalNoise = options.enabled ? temporalNoise : 0.0f;
}
@@ -214,11 +217,11 @@ void PerViewUniforms::prepareStructure(Handle<HwTexture> structure) noexcept {
mSamplers.setSampler(PerViewSib::STRUCTURE, { structure, {}});
}
void PerViewUniforms::prepareDirectionalLight(FEngine& engine,
void PerViewUniforms::prepareDirectionalLight(
float exposure,
float3 const& sceneSpaceDirection,
PerViewUniforms::LightManagerInstance directionalLight) noexcept {
FLightManager& lcm = engine.getLightManager();
FLightManager& lcm = mEngine.getLightManager();
auto& s = mUniforms.edit();
const float3 l = -sceneSpaceDirection; // guaranteed normalized
@@ -252,8 +255,9 @@ void PerViewUniforms::prepareDirectionalLight(FEngine& engine,
}
}
void PerViewUniforms::prepareAmbientLight(FEngine& engine, FIndirectLight const& ibl,
void PerViewUniforms::prepareAmbientLight(FIndirectLight const& ibl,
float intensity, float exposure) noexcept {
auto& engine = mEngine;
auto& s = mUniforms.edit();
// Set up uniforms and sampler for the IBL, guaranteed to be non-null at this point.
@@ -293,10 +297,14 @@ void PerViewUniforms::prepareShadowMapping(bool highPrecision) noexcept {
void PerViewUniforms::prepareShadowSampling(PerViewUib& uniforms,
ShadowMappingUniforms const& shadowMappingUniforms) noexcept {
uniforms.lightFromWorldMatrix = shadowMappingUniforms.lightFromWorldMatrix;
uniforms.cascadeSplits = shadowMappingUniforms.cascadeSplits;
uniforms.shadowBulbRadiusLs = shadowMappingUniforms.shadowBulbRadiusLs;
uniforms.shadowBias = shadowMappingUniforms.shadowBias;
uniforms.ssContactShadowDistance = shadowMappingUniforms.ssContactShadowDistance;
uniforms.directionalShadows = shadowMappingUniforms.directionalShadows;
uniforms.cascades = shadowMappingUniforms.cascades;
uniforms.cascades |= uint32_t(shadowMappingUniforms.elvsm) << 31u;
}
void PerViewUniforms::prepareShadowVSM(Handle<HwTexture> texture,
+10 -15
View File
@@ -48,11 +48,6 @@ class FIndirectLight;
class Froxelizer;
class LightManager;
/*
* PerViewUniforms manages the UBO and samplers needed to render the color passes. Internally it
* holds onto handles for the PER_VIEW UBO and SamplerGroup. This class maintains a shadow copy
* of the UBO/sampler data, so it is possible to partially update it between commits.
*/
class PerViewUniforms {
using LightManagerInstance = utils::EntityInstance<LightManager>;
@@ -68,8 +63,8 @@ public:
void terminate(backend::DriverApi& driver);
void prepareCamera(FEngine& engine, const CameraInfo& camera) noexcept;
void prepareLodBias(float bias) noexcept;
void prepareCamera(const CameraInfo& camera) noexcept;
void prepareUpscaler(math::float2 scale, DynamicResolutionOptions const& options) noexcept;
/*
* @param viewport viewport (should be same as RenderPassParams::viewport)
@@ -78,12 +73,10 @@ public:
* @param yoffset vertical rendering offset *within* the viewport.
* Non-zero when we have guard bands.
*/
void prepareViewport(
const filament::Viewport& physicalViewport,
const filament::Viewport& logicalViewport) noexcept;
void prepareViewport(const filament::Viewport& viewport, uint32_t xoffset, uint32_t yoffset) noexcept;
void prepareTime(FEngine& engine, math::float4 const& userTime) noexcept;
void prepareTemporalNoise(FEngine& engine, TemporalAntiAliasingOptions const& options) noexcept;
void prepareTime(math::float4 const& userTime) noexcept;
void prepareTemporalNoise(TemporalAntiAliasingOptions const& options) noexcept;
void prepareExposure(float ev100) noexcept;
void prepareFog(math::float3 const& cameraPosition, FogOptions const& options) noexcept;
void prepareStructure(TextureHandle structure) noexcept;
@@ -102,11 +95,10 @@ public:
void prepareShadowMapping(bool highPrecision) noexcept;
void prepareDirectionalLight(FEngine& engine, float exposure,
void prepareDirectionalLight(float exposure,
math::float3 const& sceneSpaceDirection, LightManagerInstance instance) noexcept;
void prepareAmbientLight(FEngine& engine,
FIndirectLight const& ibl, float intensity, float exposure) noexcept;
void prepareAmbientLight(FIndirectLight const& ibl, float intensity, float exposure) noexcept;
void prepareDynamicLights(Froxelizer& froxelizer) noexcept;
@@ -134,10 +126,13 @@ public:
void unbindSamplers() noexcept;
private:
FEngine& mEngine;
math::float2 mClipControl{};
TypedUniformBuffer<PerViewUib> mUniforms;
backend::SamplerGroup mSamplers;
backend::Handle<backend::HwBufferObject> mUniformBufferHandle;
backend::Handle<backend::HwSamplerGroup> mSamplerGroupHandle;
std::uniform_real_distribution<float> mUniformDistribution{ 0.0f, 1.0f };
static void prepareShadowSampling(PerViewUib& uniforms,
ShadowMappingUniforms const& shadowMappingUniforms) noexcept;
};

Some files were not shown because too many files have changed in this diff Show More