Compare commits

..
59 changed files with 559 additions and 1204 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 }}
+8 -12
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)
+4 -4
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.30.0'
implementation 'com.google.android.filament:filament-android:1.28.2'
}
```
@@ -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.30.0'
pod 'Filament', '~> 1.28.2'
```
### 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
-8
View File
@@ -5,14 +5,6 @@ A new header is inserted each time a *tag* is created.
## main branch
## 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`
@@ -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
},
@@ -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;
}
@@ -1171,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);
@@ -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.30.0
VERSION_NAME=1.28.2
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
+14
View File
@@ -0,0 +1,14 @@
setuptools==58.0.4
wheel==0.37.1
certifi==2022.9.24
cffi==1.15.1
charset-normalizer==2.1.1
Deprecated==1.2.13
idna==3.4
pycparser==2.21
PyGithub==1.56
PyJWT==2.6.0
PyNaCl==1.5.0
requests==2.28.1
urllib3==1.26.12
wrapt==1.14.1
+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 -3
View File
@@ -2360,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);
+14 -16
View File
@@ -105,16 +105,16 @@ void OpenGLProgram::compileShaders(OpenGLContext& context,
GLuint shaderIds[Program::SHADER_TYPE_COUNT],
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
@@ -143,14 +143,14 @@ 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
};
@@ -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);
+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
-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"
+19 -35
View File
@@ -35,8 +35,8 @@ AtlasAllocator::AtlasAllocator(size_t maxTextureSize) noexcept {
mMaxTextureSizePot = (sizeof(maxTextureSize) * 8 - 1u) - utils::clz(maxTextureSize);
}
AtlasAllocator::Allocation AtlasAllocator::allocate(size_t textureSize) noexcept {
Allocation result{};
Viewport AtlasAllocator::allocate(size_t textureSize) noexcept {
Viewport result{};
const size_t powerOfTwo = (sizeof(textureSize) * 8 - 1u) - utils::clz(textureSize);
// asked for a texture size too large
@@ -45,24 +45,22 @@ AtlasAllocator::Allocation AtlasAllocator::allocate(size_t textureSize) noexcept
}
// asked for a texture size too small
if (UTILS_UNLIKELY(mMaxTextureSizePot - powerOfTwo >= QUAD_TREE_DEPTH)) {
if (UTILS_UNLIKELY(mMaxTextureSizePot - powerOfTwo >= QuadTree::height())) {
return result;
}
const size_t layer = (mMaxTextureSizePot - powerOfTwo);
const NodeId loc = allocateInLayer(LAYERS_DEPTH + layer);
const size_t layer = mMaxTextureSizePot - powerOfTwo;
const NodeId loc = allocateInLayer(layer);
if (loc.l >= 0) {
assert_invariant(loc.l - LAYERS_DEPTH == int8_t(layer));
const size_t dimension = 1u << powerOfTwo;
assert_invariant(loc.l == int8_t(layer));
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);
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);
result.left = int32_t(x) << powerOfTwo;
result.bottom = int32_t(y) << powerOfTwo;
result.width = dimension;
result.height = dimension;
}
return result;
}
@@ -110,9 +108,9 @@ AtlasAllocator::NodeId AtlasAllocator::allocateInLayer(size_t maxHeight) noexcep
}
// 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()) {
// to accomplish a "best fit" allocation. So if we're a parent of a 'fitting'
// node and don't have children, we skip the children recursion.
if (curr.l == n - 1 && !node.hasChildren()) {
return QuadTree::TraversalResult::SKIP_CHILDREN;
}
@@ -123,8 +121,6 @@ AtlasAllocator::NodeId AtlasAllocator::allocateInLayer(size_t maxHeight) noexcep
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;
@@ -136,38 +132,26 @@ AtlasAllocator::NodeId AtlasAllocator::allocateInLayer(size_t maxHeight) noexcep
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 };
assert_invariant(!allocation.isAllocated());
assert_invariant(!allocation.hasChildren());
NodeId found{};
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;
}
}
+3 -19
View File
@@ -21,8 +21,6 @@
#include <filament/Viewport.h>
#include <private/filament/EngineEnums.h>
class AtlasAllocator_AllocateFirstLevel_Test;
class AtlasAllocator_AllocateSecondLevel_Test;
class AtlasAllocator_AllocateMixed0_Test;
@@ -55,18 +53,8 @@ class AtlasAllocator {
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 QuadTree = utils::QuadTreeArray<Node, QUAD_TREE_DEPTH>;
using NodeId = QuadTree::NodeId;
public:
@@ -74,18 +62,14 @@ 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;
explicit AtlasAllocator(size_t maxTextureSize = 1024) 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;
Viewport allocate(size_t textureSize) noexcept;
/*
* Frees all allocations and reset the maximum texture size.
+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
@@ -79,7 +79,7 @@ void PerShadowMapUniforms::prepareLodBias(Transaction const& transaction,
}
void PerShadowMapUniforms::prepareViewport(Transaction const& transaction,
backend::Viewport const& viewport,
const filament::Viewport& viewport,
uint32_t xoffset, uint32_t yoffset) noexcept {
const float w = float(viewport.width);
const float h = float(viewport.height);
+1 -1
View File
@@ -65,7 +65,7 @@ public:
float bias) noexcept;
static void prepareViewport(Transaction const& transaction,
backend::Viewport const& viewport, uint32_t xoffset, uint32_t yoffset) noexcept;
const filament::Viewport& viewport, uint32_t xoffset, uint32_t yoffset) noexcept;
static void prepareTime(Transaction const& transaction,
FEngine& engine, math::float4 const& userTime) noexcept;
-10
View File
@@ -707,11 +707,6 @@ void RenderPass::Executor::overrideScissor(backend::Viewport const* scissor) noe
}
}
void RenderPass::Executor::overrideScissor(backend::Viewport const& scissor) noexcept {
mScissorOverride = true;
mScissor = scissor;
}
void RenderPass::Executor::execute(FEngine& engine, const char* name) const noexcept {
execute(engine.getDriverApi(), mCommands.begin(), mCommands.end());
}
@@ -755,11 +750,6 @@ void RenderPass::Executor::execute(backend::DriverApi& driver,
continue;
}
// primitiveHandle may be invalid if no geometry was set on the renderable.
if (UTILS_UNLIKELY(!first->primitive.primitiveHandle)) {
continue;
}
// per-renderable uniform
const PrimitiveInfo info = first->primitive;
pipeline.rasterState = info.rasterState;
-1
View File
@@ -349,7 +349,6 @@ public:
// if non-null, overrides the material's scissor
void overrideScissor(backend::Viewport const* scissor) noexcept;
void overrideScissor(backend::Viewport const& scissor) noexcept;
void execute(FEngine& engine, const char* name) const noexcept;
};
+127 -97
View File
@@ -368,9 +368,8 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
// Computes St the transform to use in the shader to access the shadow map texture
// i.e. it transforms a world-space vertex to a texture coordinate in the shadowmap
const backend::Viewport viewport = getViewport();
const auto [Mt, Mn] = ShadowMap::getTextureCoordsMapping(shadowMapInfo, viewport);
const mat4f St = math::highPrecisionMultiply(Mt, S);
const mat4 MbMt = getTextureCoordsMapping(shadowMapInfo);
const mat4f St = mat4f(MbMt * S);
ShadowMap::ShaderParameters shaderParameters;
@@ -378,7 +377,7 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
// L * Mp * Mv is a rigid transform for directional lights, and doesn't matter.
// if Wp[3][1] is 0, then LISPSM was cancelled.
if (useLispsm && Wp[3][1] != 0.0f) {
shaderParameters.texelSizeAtOneMeterWs = texelSizeWorldSpace(Wp, mat4f(Mt * F),
shaderParameters.texelSizeAtOneMeterWs = texelSizeWorldSpace(Wp, mat4f(MbMt * F),
shadowMapInfo.shadowDimension);
} else {
// We know we're using an ortho projection
@@ -391,8 +390,6 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
shaderParameters.lightSpace = computeVsmLightSpaceMatrix(St, Mv, znear, zfar);
}
shaderParameters.scissorNormalized = getViewportNormalized(shadowMapInfo);
// We apply the constant bias in world space (as opposed to light-space) to account
// for perspective and lispsm shadow maps. This also allows us to do this at zero-cost
// by baking it in the shadow-map itself.
@@ -407,8 +404,8 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
// The model matrix below is in fact inverted to get the view matrix and passed to the
// shader as 'viewFromWorldMatrix', and is used in the VSM case to compute the depth metric.
// (see depth_main.fs). Note that in the case of VSM, 'b' below is identity.
mCamera->setModelMatrix(FCamera::rigidTransformInverse(math::highPrecisionMultiplyd(Mv, b)));
mCamera->setCustomProjection(mat4(Mn * F * W * L * Mp), znear, zfar);
mCamera->setModelMatrix(mat4{ FCamera::rigidTransformInverse(Mv * b) });
mCamera->setCustomProjection(mat4(F * W * L * Mp), znear, zfar);
// for the debug camera, we need to undo the world origin
mDebugCamera->setCustomProjection(mat4(S * b * camera.worldOrigin), znear, zfar);
@@ -416,18 +413,48 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
return shaderParameters;
}
ShadowMap::ShaderParameters ShadowMap::updatePunctual(
mat4f const& Mv, float outerConeAngle, float nearPlane, float farPlane,
const ShadowMapInfo& shadowMapInfo, const FLightManager::ShadowParams& params) noexcept {
const mat4f Mp = mat4f::perspective(outerConeAngle * f::RAD_TO_DEG * 2.0f, 1.0f, nearPlane, farPlane);
ShadowMap::ShaderParameters ShadowMap::updateSpot(FEngine& engine,
const FScene::LightSoa& lightData, size_t index,
filament::CameraInfo const& camera,
const ShadowMapInfo& shadowMapInfo,
FScene const& scene, SceneInfo sceneInfo) noexcept {
assert_invariant(shadowMapInfo.textureDimension == mOptions->mapSize);
ShaderParameters shaderParameters;
auto& lcm = engine.getLightManager();
auto li = lightData.elementAt<FScene::LIGHT_INSTANCE>(index);
auto position = lightData.elementAt<FScene::POSITION_RADIUS>(index).xyz;
auto direction = lightData.elementAt<FScene::DIRECTION>(index);
auto radius = lightData.elementAt<FScene::POSITION_RADIUS>(index).w;
auto outerConeAngle = lcm.getSpotLightOuterCone(li);
const FLightManager::ShadowParams& params = lcm.getShadowParams(li);
/*
* Compute the light model matrix.
*/
// Choose a reasonable value for the near plane.
const mat4f Mv = getDirectionalLightViewMatrix(direction, position);
// find decent near/far
ShadowMap::updateSceneInfoSpot(Mv, scene, sceneInfo);
// if the scene was empty, near > far
mHasVisibleShadows = -sceneInfo.lsNearFar[0] < -sceneInfo.lsNearFar[1];
// FIXME: we need a configuration for minimum near plane (for now hardcoded to 1cm)
float nearPlane = std::max(0.01f, -sceneInfo.lsNearFar[0]);
float farPlane = std::min(radius, -sceneInfo.lsNearFar[1]);
float outerConeAngleDegrees = outerConeAngle * f::RAD_TO_DEG;
const mat4f Mp = mat4f::perspective(outerConeAngleDegrees * 2.0f, 1.0f, nearPlane, farPlane);
const mat4f MpMv(math::highPrecisionMultiply(Mp, Mv));
// Final shadow transform
const backend::Viewport viewport = getViewport();
const mat4f S = math::highPrecisionMultiply(Mp, Mv);
const auto [Mt, Mn] = ShadowMap::getTextureCoordsMapping(shadowMapInfo, viewport);
const mat4f St = math::highPrecisionMultiply(Mt, S);
const mat4f S = MpMv;
const mat4 MbMt = getTextureCoordsMapping(shadowMapInfo);
const mat4f St = mat4f(MbMt * S);
// TODO: focus projection
// 1) focus on the casters
@@ -442,9 +469,7 @@ ShadowMap::ShaderParameters ShadowMap::updatePunctual(
// = zInLightSpace * texelSizeAtOneMeter
// = zInLightSpace * (2*tan(halfConeAngle)/dimension)
// Note: this would not work with LISPSM, which warps the texture space.
ShaderParameters shaderParameters;
shaderParameters.texelSizeAtOneMeterWs =
(2.0f * std::tan(outerConeAngle) / float(shadowMapInfo.shadowDimension));
shaderParameters.texelSizeAtOneMeterWs = (2.0f * std::tan(outerConeAngle) / float(shadowMapInfo.shadowDimension));
shaderParameters.lightFromWorldZ = -transpose(Mv)[2]; // negate because camera looks in -Z
if (!shadowMapInfo.vsm) {
@@ -453,11 +478,9 @@ ShadowMap::ShaderParameters ShadowMap::updatePunctual(
shaderParameters.lightSpace = computeVsmLightSpaceMatrix(St, Mv, nearPlane, farPlane);
}
shaderParameters.scissorNormalized = getViewportNormalized(shadowMapInfo);
const float3 direction = -transpose(Mv)[2].xyz;
const float constantBias = shadowMapInfo.vsm ? 0.0f : params.options.constantBias;
const mat4f b = mat4f::translation(direction * constantBias);
const mat4f Sb = S * b;
// It's important to set the light camera's model matrix separately from its projection, so that
// the cameraPosition uniform gets set correctly.
@@ -467,47 +490,22 @@ ShadowMap::ShaderParameters ShadowMap::updatePunctual(
// The model matrix below is in fact inverted to get the view matrix and passed to the
// shader as 'viewFromWorldMatrix', and is used in the VSM case to compute the depth metric.
// (see depth_main.fs). Note that in the case of VSM, 'b' below is identity.
mCamera->setModelMatrix(FCamera::rigidTransformInverse(math::highPrecisionMultiplyd(Mv, b)));
mCamera->setCustomProjection(math::highPrecisionMultiplyd(Mn, Mp), nearPlane, farPlane);
mCamera->setModelMatrix(mat4{ FCamera::rigidTransformInverse(Mv * b) });
mCamera->setCustomProjection(mat4(Mp), nearPlane, farPlane);
// for the debug camera, we need to undo the world origin
mDebugCamera->setCustomProjection(mat4(Sb * camera.worldOrigin), nearPlane, radius);
return shaderParameters;
}
ShadowMap::ShaderParameters ShadowMap::updateSpot(FEngine& engine,
const FScene::LightSoa& lightData, size_t index,
filament::CameraInfo const& camera,
const ShadowMapInfo& shadowMapInfo,
FScene const& scene, SceneInfo sceneInfo) noexcept {
auto& lcm = engine.getLightManager();
auto position = lightData.elementAt<FScene::POSITION_RADIUS>(index).xyz;
auto direction = lightData.elementAt<FScene::DIRECTION>(index);
auto radius = lightData.elementAt<FScene::POSITION_RADIUS>(index).w;
auto li = lightData.elementAt<FScene::LIGHT_INSTANCE>(index);
const FLightManager::ShadowParams& params = lcm.getShadowParams(li);
const mat4f Mv = getDirectionalLightViewMatrix(direction, position);
// find decent near/far
ShadowMap::updateSceneInfoSpot(Mv, scene, sceneInfo);
// if the scene was empty, near > far
mHasVisibleShadows = -sceneInfo.lsNearFar[0] < -sceneInfo.lsNearFar[1];
if (!mHasVisibleShadows) {
return {};
}
// FIXME: we need a configuration for minimum near plane (for now hardcoded to 1cm)
float nearPlane = std::max(0.01f, -sceneInfo.lsNearFar[0]);
float farPlane = std::min(radius, -sceneInfo.lsNearFar[1]);
auto outerConeAngle = lcm.getSpotLightOuterCone(li);
return updatePunctual(Mv, outerConeAngle, nearPlane, farPlane, shadowMapInfo, params);
}
ShadowMap::ShaderParameters ShadowMap::updatePoint(FEngine& engine,
const FScene::LightSoa& lightData, size_t index,
filament::CameraInfo const& camera, const ShadowMapInfo& shadowMapInfo, FScene const& scene,
SceneInfo, uint8_t face) noexcept {
ShaderParameters shaderParameters;
// check if this shadow map has anything to render
mHasVisibleShadows = false;
FScene::RenderableSoa const& UTILS_RESTRICT soa = scene.getRenderableData();
@@ -520,16 +518,53 @@ ShadowMap::ShaderParameters ShadowMap::updatePoint(FEngine& engine,
}
}
if (!mHasVisibleShadows) {
return {};
return shaderParameters;
}
auto& lcm = engine.getLightManager();
auto li = lightData.elementAt<FScene::LIGHT_INSTANCE>(index);
auto position = lightData.elementAt<FScene::POSITION_RADIUS>(index).xyz;
auto radius = lightData.elementAt<FScene::POSITION_RADIUS>(index).w;
auto li = lightData.elementAt<FScene::LIGHT_INSTANCE>(index);
const FLightManager::ShadowParams& params = lcm.getShadowParams(li);
/*
* Compute the light model matrix.
*/
const mat4f Mv = getPointLightViewMatrix(TextureCubemapFace(face), position);
return updatePunctual(Mv, 45.0f * f::DEG_TO_RAD, 0.01f, radius, shadowMapInfo, params);
const float3 direction = -transpose(Mv)[2].xyz;
// TODO: don't hardcode near plane
// Choose a reasonable value for the near plane.
float nearPlane = 0.01f;
float farPlane = radius;
const mat4f Mp = mat4f::perspective(90.0f, 1.0f, nearPlane, farPlane);
// For calculating the point light normal bias, we need the texel size in world space at the
// sample location. Using Thales's theorem, we find:
// texelSize(zInLightSpace) = zInLightSpace * texelSizeOnTheNearPlane / near
// = zInLightSpace * texelSizeAtOneMeter
// = zInLightSpace * (2*tan(halfConeAngle)/dimension)
// Note: this would not work with LISPSM, which warps the texture space.
shaderParameters.texelSizeAtOneMeterWs =
(2.0f * std::tan(f::PI_4) / float(shadowMapInfo.shadowDimension));
const float constantBias = shadowMapInfo.vsm ? 0.0f : params.options.constantBias;
const mat4f b = mat4f::translation(direction * constantBias);
// It's important to set the light camera's model matrix separately from its projection, so that
// the cameraPosition uniform gets set correctly.
// mLightSpace is used in the shader to access the shadow map texture, and has the model matrix
// baked in.
// The model matrix below is in fact inverted to get the view matrix and passed to the
// shader as 'viewFromWorldMatrix', and is used in the VSM case to compute the depth metric.
// (see depth_main.fs). Note that in the case of VSM, 'b' below is identity.
mCamera->setModelMatrix(mat4{ FCamera::rigidTransformInverse(Mv * b) });
mCamera->setCustomProjection(mat4(Mp), nearPlane, farPlane);
return shaderParameters;
}
mat4f ShadowMap::applyLISPSM(mat4f& Wp,
@@ -611,8 +646,7 @@ mat4f ShadowMap::applyLISPSM(mat4f& Wp,
// Apply these remapping in double to maintain a high precision for the depth axis
ShadowMap::TextureCoordsMapping ShadowMap::getTextureCoordsMapping(ShadowMapInfo const& info,
backend::Viewport const& viewport) noexcept {
mat4 ShadowMap::getTextureCoordsMapping(ShadowMapInfo const& info) noexcept {
// remapping from NDC to texture coordinates (i.e. [-1,1] -> [0, 1])
// ([1, 0] for depth mapping)
const mat4f Mt(info.clipSpaceFlipped ? mat4f::row_major_init{
@@ -627,12 +661,22 @@ ShadowMap::TextureCoordsMapping ShadowMap::getTextureCoordsMapping(ShadowMapInfo
0.0f, 0.0f, 0.0f, 1.0f
});
// apply the viewport transform
const float2 o = float2{ viewport.left, viewport.bottom } / float(info.atlasDimension);
const float2 s = float2{ viewport.width, viewport.height } / float(info.atlasDimension);
// the shadow map texture might be larger than the shadow map dimension, so we add a scaling
// factor
const float v = float(info.textureDimension) / float(info.atlasDimension);
const mat4f Mv(mat4f::row_major_init{
s.x, 0.0f, 0.0f, o.x,
0.0f, s.y, 0.0f, o.y,
v, 0.0f, 0.0f, 0.0f,
0.0f, v, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
});
// apply the 1-texel border viewport transform
const float o = 1.0f / float(info.atlasDimension);
const float s = 1.0f - 2.0f * (1.0f / float(info.textureDimension));
const mat4f Mb(mat4f::row_major_init{
s, 0.0f, 0.0f, o,
0.0f, s, 0.0f, o,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
});
@@ -644,8 +688,8 @@ ShadowMap::TextureCoordsMapping ShadowMap::getTextureCoordsMapping(ShadowMapInfo
0.0f, 0.0f, 0.0f, 1.0f
}) : mat4f();
// Compute shadow-map texture access and viewport transform
return { Mf * (Mv * Mt), inverse(Mt) * (Mv * Mt) };
// Compute shadow-map texture access transform
return mat4(Mf * Mb * Mv * Mt);
}
mat4f ShadowMap::computeVsmLightSpaceMatrix(const mat4f& lightSpacePcf,
@@ -1201,40 +1245,26 @@ void ShadowMap::updateSceneInfoSpot(mat4f const& Mv, FScene const& scene,
);
}
backend::Viewport ShadowMap::getViewport() const noexcept {
filament::Viewport ShadowMap::getViewport() const noexcept {
// We set a viewport with a 1-texel border for when we index outside the
// texture. This can only happen for the directional light when "focus shadow casters is used".
// texture.
// DON'T CHANGE this unless ShadowMap::getTextureCoordsMapping() is updated too.
// see: ShadowMap::getTextureCoordsMapping()
//
// For floating-point depth textures, the 1-texel border could be set to
// FLOAT_MAX to avoid clamping in the shadow shader (see sampleDepth inside
// shadowing.fs). Unfortunately, the APIs don't seem let us clear depth
// attachments to anything greater than 1.0, so we'd need a way to do this other
// than clearing.
const uint32_t dim = mOptions->mapSize;
const uint16_t border = 1u;
return { border, border, dim - 2u * border, dim - 2u * border };
}
backend::Viewport ShadowMap::getScissor() const noexcept {
// We set a viewport with a 1-texel border for when we index outside the
// texture. This can only happen for the directional light when "focus shadow casters is used".
const uint32_t dim = mOptions->mapSize;
const uint16_t border = 1u;
switch (mShadowType) {
case ShadowType::DIRECTIONAL:
return { border, border, dim - 2u * border, dim - 2u * border };
case ShadowType::SPOT:
case ShadowType::POINT:
default:
return { 0, 0, dim, dim };
if (isPointShadow()) {
// for point-light we don't have a border
return { 0, 0, dim, dim };
} else {
return { 1, 1, dim - 2, dim - 2 };
}
}
math::float4 ShadowMap::getViewportNormalized(ShadowMapInfo const& shadowMapInfo) const noexcept {
const auto [l, b, w, h] = getViewport();
const float texel = 1.0f / float(shadowMapInfo.atlasDimension);
const float4 v = float4{ l, b, l + w, b + h } * texel;
if (shadowMapInfo.textureSpaceFlipped) {
return { v.x, 1.0f - v.w, v.z, 1.0f - v.y };
}
return v;
}
// ------------------------------------------------------------------------------------------------
void ShadowMap::prepareCamera(Transaction const& transaction,
@@ -1244,7 +1274,7 @@ void ShadowMap::prepareCamera(Transaction const& transaction,
}
void ShadowMap::prepareViewport(Transaction const& transaction,
backend::Viewport const& viewport) noexcept {
const filament::Viewport& viewport) noexcept {
PerShadowMapUniforms::prepareViewport(transaction, viewport, 0, 0);
}
+5 -19
View File
@@ -24,7 +24,7 @@
#include "details/Camera.h"
#include "details/Scene.h"
#include <backend/DriverApiForward.h>
#include "private/backend/DriverApi.h"
#include <filament/Viewport.h>
@@ -130,7 +130,6 @@ public:
struct ShaderParameters {
math::mat4f lightSpace{};
math::float4 lightFromWorldZ{};
math::float4 scissorNormalized{};
float texelSizeAtOneMeterWs{};
};
@@ -175,14 +174,13 @@ public:
static void updateSceneInfoSpot(const math::mat4f& Mv, FScene const& scene,
SceneInfo& sceneInfo);
filament::Viewport getViewport() const noexcept;
LightManager::ShadowOptions const* getShadowOptions() const noexcept { return mOptions; }
size_t getLightIndex() const { return mLightIndex; }
uint16_t getShadowIndex() const { return mShadowIndex; }
void setLayer(uint8_t layer) noexcept { mLayer = layer; }
uint8_t getLayer() const noexcept { return mLayer; }
backend::Viewport getViewport() const noexcept;
backend::Viewport getScissor() const noexcept;
bool isDirectionalShadow() const noexcept { return mShadowType == ShadowType::DIRECTIONAL; }
bool isSpotShadow() const noexcept { return mShadowType == ShadowType::SPOT; }
bool isPointShadow() const noexcept { return mShadowType == ShadowType::POINT; }
@@ -194,7 +192,7 @@ public:
static void prepareCamera(Transaction const& transaction,
FEngine& engine, const CameraInfo& cameraInfo) noexcept;
static void prepareViewport(Transaction const& transaction,
backend::Viewport const& viewport) noexcept;
const filament::Viewport& viewport) noexcept;
static void prepareTime(Transaction const& transaction,
FEngine& engine, math::float4 const& userTime) noexcept;
static void prepareShadowMapping(Transaction const& transaction,
@@ -216,11 +214,6 @@ private:
// 8 corners, 12 segments w/ 2 intersection max -- all of this twice (8 + 12 * 2) * 2 (768 bytes)
using FrustumBoxIntersection = std::array<math::float3, 64>;
ShaderParameters updatePunctual(
math::mat4f const& Mv, float outerConeAngle, float nearPlane, float farPlane,
const ShadowMapInfo& shadowMapInfo,
const FLightManager::ShadowParams& params) noexcept;
static math::mat4f applyLISPSM(math::mat4f& Wp,
filament::CameraInfo const& camera, FLightManager::ShadowParams const& params,
const math::mat4f& LMpMv,
@@ -280,18 +273,11 @@ private:
static math::mat4f directionalLightFrustum(float n, float f) noexcept;
struct TextureCoordsMapping {
math::mat4f clipToTexture;
math::mat4f clipToNdc;
};
static TextureCoordsMapping getTextureCoordsMapping(ShadowMapInfo const& info,
backend::Viewport const& viewport) noexcept;
static math::mat4 getTextureCoordsMapping(ShadowMapInfo const& info) noexcept;
static math::mat4f computeVsmLightSpaceMatrix(const math::mat4f& lightSpacePcf,
const math::mat4f& Mv, float znear, float zfar) noexcept;
math::float4 getViewportNormalized(ShadowMapInfo const& shadowMapInfo) const noexcept;
float texelSizeWorldSpace(const math::mat3f& worldToShadowTexture,
uint16_t shadowDimension) const noexcept;
+25 -23
View File
@@ -99,7 +99,7 @@ void ShadowMapManager::setDirectionalShadowMap(size_t lightIndex,
for (size_t c = 0; c < options->shadowCascades; c++) {
const size_t i = c;
assert_invariant(i < CONFIG_MAX_SHADOW_CASCADES);
auto* pShadowMap = getShadowMap(i);
auto* pShadowMap = getCascadeShadowMap(i);
pShadowMap->initialize(lightIndex, ShadowType::DIRECTIONAL, i, 0, options);
mCascadeShadowMaps.push_back(pShadowMap);
}
@@ -111,7 +111,7 @@ void ShadowMapManager::addShadowMap(size_t lightIndex, bool spotlight,
const size_t c = mSpotShadowMaps.size();
const size_t i = c + CONFIG_MAX_SHADOW_CASCADES;
assert_invariant(i < CONFIG_MAX_SHADOWMAPS);
auto* pShadowMap = getShadowMap(i);
auto* pShadowMap = getPointOrSpotShadowMap(i);
pShadowMap->initialize(lightIndex, ShadowType::SPOT, i, 0, options);
mSpotShadowMaps.push_back(pShadowMap);
} else {
@@ -120,7 +120,7 @@ void ShadowMapManager::addShadowMap(size_t lightIndex, bool spotlight,
const size_t c = mSpotShadowMaps.size();
const size_t i = c + CONFIG_MAX_SHADOW_CASCADES;
assert_invariant(i < CONFIG_MAX_SHADOWMAPS);
auto* pShadowMap = getShadowMap(i);
auto* pShadowMap = getPointOrSpotShadowMap(i);
pShadowMap->initialize(lightIndex, ShadowType::POINT, i, face, options);
mSpotShadowMaps.push_back(pShadowMap);
}
@@ -159,8 +159,6 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
utils::FixedCapacityVector<ShadowPass> passList;
};
VsmShadowOptions const& vsmShadowOptions = view.getVsmShadowOptions();
auto& prepareShadowPass = fg.addPass<PrepareShadowPassData>("Prepare Shadow Pass",
[&](FrameGraph::Builder& builder, auto& data) {
data.passList.reserve(CONFIG_MAX_SHADOWMAPS);
@@ -205,8 +203,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
// "read" from one of its resource (only writes), so the FrameGraph culls it.
builder.sideEffect();
},
[this, &engine, &view, vsmShadowOptions,
scene, mainCameraInfo, userTime, passTemplate = pass](
[this, &engine, &view, scene, mainCameraInfo, userTime, passTemplate = pass](
FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
// Note: we could almost parallel_for the loop below, the problem currently is
@@ -254,7 +251,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
ShadowMap::prepareViewport(transaction, shadowMap.getViewport());
ShadowMap::prepareTime(transaction, engine, userTime);
ShadowMap::prepareShadowMapping(transaction,
vsmShadowOptions.highPrecision);
view.getVsmShadowOptions().highPrecision);
shadowMap.commit(transaction, driver);
// updatePrimitivesLod must be run before RenderPass::appendCommands.
@@ -280,6 +277,11 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
};
entry.executor.overridePolygonOffset(&polygonOffset);
}
constexpr const backend::Viewport disabledScissor{ 0, 0,
(uint32_t)std::numeric_limits<int32_t>::max(),
(uint32_t)std::numeric_limits<int32_t>::max() };
entry.executor.overrideScissor(&disabledScissor);
}
}
@@ -308,7 +310,6 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
const uint8_t layer = entry.shadowMap->getLayer();
const auto* options = entry.shadowMap->getShadowOptions();
const auto msaaSamples = textureRequirements.msaaSamples;
auto& shadowPass = fg.addPass<ShadowPassData>("Shadow Pass",
[&](FrameGraph::Builder& builder, auto& data) {
@@ -327,7 +328,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
// We specify the sample count here because we don't need automatic resolve.
auto depth = builder.createTexture("Temporary VSM Depth Texture", {
.width = textureRequirements.size, .height = textureRequirements.size,
.samples = msaaSamples,
.samples = options->vsm.msaaSamples,
.format = TextureFormat::DEPTH16,
});
@@ -350,7 +351,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH;
// we need to clear the shadow map with the max EVSM moments
renderTargetDesc.clearColor = vsmClearColor;
renderTargetDesc.samples = msaaSamples;
renderTargetDesc.samples = options->vsm.msaaSamples;
if (blur) {
data.tempBlurSrc = builder.write(data.tempBlurSrc,
@@ -361,7 +362,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
.color = { data.tempBlurSrc },
.depth = depth },
.clearColor = vsmClearColor,
.samples = msaaSamples,
.samples = options->vsm.msaaSamples,
.clearFlags = TargetBufferFlags::COLOR
| TargetBufferFlags::DEPTH
});
@@ -392,11 +393,11 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
// initialized, as this happens in an `execute` block.
auto rt = resources.getRenderPassInfo(data.rt);
rt.params.viewport = entry.shadowMap->getViewport();
engine.flush();
driver.beginRenderPass(rt.target, rt.params);
entry.shadowMap->bind(driver);
entry.executor.overrideScissor(entry.shadowMap->getScissor());
entry.executor.execute(engine, "Shadow Pass");
driver.endRenderPass();
});
@@ -546,7 +547,6 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
auto& s = mShadowUb.edit();
s.shadows[shadowIndex].layer = shadowMap.getLayer();
s.shadows[shadowIndex].lightFromWorldMatrix = shaderParameters.lightSpace;
s.shadows[shadowIndex].scissorNormalized = shaderParameters.scissorNormalized;
s.shadows[shadowIndex].normalBias = normalBias * wsTexelSize;
s.shadows[shadowIndex].texelSizeAtOneMeter = wsTexelSize;
s.shadows[shadowIndex].elvsm = options.vsm.elvsm;
@@ -632,7 +632,7 @@ void ShadowMapManager::prepareSpotShadowMap(ShadowMap& shadowMap,
// compute shadow map frustum for culling
const mat4f Mv = ShadowMap::getDirectionalLightViewMatrix(direction, position);
const mat4f Mp = mat4f::perspective(outerConeAngle * f::RAD_TO_DEG * 2.0f, 1.0f, 0.01f, radius);
const mat4f MpMv = math::highPrecisionMultiply(Mp, Mv);
const mat4f MpMv(math::highPrecisionMultiply(Mp, Mv));
const Frustum frustum(MpMv);
// Cull shadow casters
@@ -682,7 +682,7 @@ void ShadowMapManager::prepareSpotShadowMap(ShadowMap& shadowMap,
const double f = shadowMap.getCamera().getCullingFar();
s.shadows[shadowIndex].layer = shadowMap.getLayer();
s.shadows[shadowIndex].lightFromWorldMatrix = shaderParameters.lightSpace;
s.shadows[shadowIndex].scissorNormalized = shaderParameters.scissorNormalized;
s.shadows[shadowIndex].direction = direction;
s.shadows[shadowIndex].normalBias = normalBias * wsTexelSizeAtOneMeter;
s.shadows[shadowIndex].lightFromWorldZ = shaderParameters.lightFromWorldZ;
s.shadows[shadowIndex].texelSizeAtOneMeter = wsTexelSizeAtOneMeter;
@@ -690,7 +690,7 @@ void ShadowMapManager::prepareSpotShadowMap(ShadowMap& shadowMap,
s.shadows[shadowIndex].elvsm = options->vsm.elvsm;
s.shadows[shadowIndex].bulbRadiusLs =
mSoftShadowOptions.penumbraScale * options->shadowBulbRadius
/ wsTexelSizeAtOneMeter;
/ wsTexelSizeAtOneMeter;
}
}
@@ -763,10 +763,15 @@ void ShadowMapManager::preparePointShadowMap(ShadowMap& shadowMap,
const double n = shadowMap.getCamera().getNear();
const double f = shadowMap.getCamera().getCullingFar();
s.shadows[shadowIndex].layer = shadowMap.getLayer();
s.shadows[shadowIndex].lightFromWorldMatrix = shaderParameters.lightSpace;
s.shadows[shadowIndex].scissorNormalized = shaderParameters.scissorNormalized;
s.shadows[shadowIndex].lightFromWorldMatrix = {}; // no texture matrix for point lights
s.shadows[shadowIndex].direction = {}; // no direction of point lights
s.shadows[shadowIndex].normalBias = normalBias * wsTexelSizeAtOneMeter;
s.shadows[shadowIndex].lightFromWorldZ = shaderParameters.lightFromWorldZ;
s.shadows[shadowIndex].lightFromWorldZ = {
-((n + f) / (f - n)) * 0.5f + 0.5f,
(f * n) / (f - n),
-n / (f - n),
1.0f / (f - n),
};
s.shadows[shadowIndex].texelSizeAtOneMeter = wsTexelSizeAtOneMeter;
s.shadows[shadowIndex].nearOverFarMinusNear = float(n / (f - n));
s.shadows[shadowIndex].elvsm = options->vsm.elvsm;
@@ -842,8 +847,6 @@ void ShadowMapManager::calculateTextureRequirements(FEngine& engine, FView& view
const bool useMipmapping = view.hasVSM() &&
((vsmShadowOptions.anisotropy > 0) || vsmShadowOptions.mipmapping);
const uint8_t msaaSamples = vsmShadowOptions.msaaSamples;
TextureFormat format = TextureFormat::DEPTH16;
if (view.hasVSM()) {
if (vsmShadowOptions.highPrecision) {
@@ -875,7 +878,6 @@ void ShadowMapManager::calculateTextureRequirements(FEngine& engine, FView& view
(uint16_t)maxDimension,
layersNeeded,
mipLevels,
msaaSamples,
format
};
}
+15 -6
View File
@@ -89,13 +89,23 @@ public:
FrameGraphId<FrameGraphTexture> render(FEngine& engine, FrameGraph& fg, RenderPass const& pass,
FView& view, CameraInfo const& mainCameraInfo, math::float4 const& userTime) noexcept;
ShadowMap* getShadowMap(size_t index) noexcept {
assert_invariant(index < CONFIG_MAX_SHADOWMAPS);
return std::launder(reinterpret_cast<ShadowMap*>(&mShadowMapCache[index]));
ShadowMap* getCascadeShadowMap(size_t cascade) noexcept {
assert_invariant(cascade < CONFIG_MAX_SHADOW_CASCADES);
return std::launder(reinterpret_cast<ShadowMap*>(&mShadowMapCache[cascade]));
}
ShadowMap const* getShadowMap(size_t index) const noexcept {
return const_cast<ShadowMapManager*>(this)->getShadowMap(index);
ShadowMap const* getCascadeShadowMap(size_t cascade) const noexcept {
return const_cast<ShadowMapManager*>(this)->getCascadeShadowMap(cascade);
}
ShadowMap* getPointOrSpotShadowMap(size_t index) noexcept {
assert_invariant(index < CONFIG_MAX_SHADOWMAPS);
return std::launder(reinterpret_cast<ShadowMap*>(
&mShadowMapCache[index]));
}
ShadowMap const* getPointOrSpotShadowMap(size_t spot) const noexcept {
return const_cast<ShadowMapManager*>(this)->getPointOrSpotShadowMap(spot);
}
// valid after calling update() above
@@ -180,7 +190,6 @@ private:
uint16_t size = 0;
uint8_t layers = 0;
uint8_t levels = 0;
uint8_t msaaSamples = 1;
backend::TextureFormat format = backend::TextureFormat::DEPTH16;
} mTextureAtlasRequirements;
+1
View File
@@ -240,6 +240,7 @@ void FLightManager::setShadowOptions(Instance i, ShadowOptions const& options) n
params.options.shadowFar = std::max(options.shadowFar, 0.0f);
params.options.shadowNearHint = std::max(options.shadowNearHint, 0.0f);
params.options.shadowFarHint = std::max(options.shadowFarHint, 0.0f);
params.options.vsm.msaaSamples = std::max(uint8_t(0), options.vsm.msaaSamples);
params.options.vsm.blurWidth = std::max(0.0f, options.vsm.blurWidth);
}
+5 -14
View File
@@ -43,7 +43,7 @@ namespace filament {
// ------------------------------------------------------------------------------------------------
FScene::FScene(FEngine& engine) :
mEngine(engine), mSharedState(std::make_shared<SharedState>()) {
mEngine(engine) {
}
FScene::~FScene() noexcept = default;
@@ -268,8 +268,7 @@ void FScene::updateUBOs(
PerRenderableData* buffer = [&]{
if (count >= MAX_STREAM_ALLOCATION_COUNT) {
// use the heap allocator
auto& bufferPoolAllocator = mSharedState->mBufferPoolAllocator;
return (PerRenderableData*)bufferPoolAllocator.get(count * sizeof(PerRenderableData));
return (PerRenderableData*)mBufferPoolAllocator.get(count * sizeof(PerRenderableData));
} else {
// allocate space into the command stream directly
return driver.allocatePod<PerRenderableData>(count);
@@ -282,24 +281,16 @@ void FScene::updateUBOs(
buffer[i] = uboData[i];
}
// We capture state shared between Scene and the update buffer callback, because the Scene could
// be destroyed before the callback executes.
std::weak_ptr<SharedState>* const weakShared = new std::weak_ptr<SharedState>(mSharedState);
// update the UBO
driver.resetBufferObject(renderableUbh);
driver.updateBufferObjectUnsynchronized(renderableUbh, {
buffer, count * sizeof(PerRenderableData),
+[](void* p, size_t s, void* user) {
std::weak_ptr<SharedState>* const weakShared =
static_cast<std::weak_ptr<SharedState>*>(user);
if (s >= MAX_STREAM_ALLOCATION_COUNT * sizeof(PerRenderableData)) {
if (auto state = weakShared->lock()) {
state->mBufferPoolAllocator.put(p);
}
FScene* const that = static_cast<FScene*>(user);
that->mBufferPoolAllocator.put(p);
}
delete weakShared;
}, weakShared
}, this
}, 0);
// update skybox
+1 -8
View File
@@ -42,8 +42,6 @@
#include <tsl/robin_set.h>
#include <memory>
namespace filament {
struct CameraInfo;
@@ -223,12 +221,7 @@ private:
LightSoa mLightData;
backend::Handle<backend::HwBufferObject> mRenderableViewUbh; // This is actually owned by the view.
bool mHasContactShadows = false;
// State shared between Scene and driver callbacks.
struct SharedState {
BufferPoolAllocator<3> mBufferPoolAllocator = {};
};
std::shared_ptr<SharedState> mSharedState;
BufferPoolAllocator<3> mBufferPoolAllocator;
};
FILAMENT_DOWNCAST(Scene)
+8 -12
View File
@@ -294,7 +294,7 @@ void FView::prepareShadowing(FEngine& engine, DriverApi& driver,
}
// Find all shadow-casting spotlights.
size_t shadowMapCount = CONFIG_MAX_SHADOW_CASCADES;
size_t shadowMapCount = 0;
// We allow a max of CONFIG_MAX_SHADOWMAPS point/spotlight shadows. Any additional
// shadow-casting spotlights are ignored.
@@ -314,16 +314,16 @@ void FView::prepareShadowing(FEngine& engine, DriverApi& driver,
continue; // doesn't cast shadows
}
const bool spotLight = lcm.isSpotLight(li);
const auto& shadowOptions = lcm.getShadowOptions(li);
mShadowMapManager.addShadowMap(l, lcm.isSpotLight(li), &shadowOptions);
const size_t shadowMapCountNeeded = spotLight ? 1 : 6;
if (shadowMapCount + shadowMapCountNeeded <= CONFIG_MAX_SHADOWMAPS) {
shadowMapCount += shadowMapCountNeeded;
const auto& shadowOptions = lcm.getShadowOptions(li);
mShadowMapManager.addShadowMap(l, spotLight, &shadowOptions);
if (lcm.isSpotLight(li)) {
shadowMapCount += 6;
} else {
shadowMapCount += 1;
}
if (shadowMapCount >= CONFIG_MAX_SHADOWMAPS) {
if (shadowMapCount > CONFIG_MAX_SHADOWMAPS - 1) {
break; // we ran out of spotlight shadow casting
}
}
@@ -994,10 +994,6 @@ void FView::setAmbientOcclusionOptions(AmbientOcclusionOptions options) noexcept
options.ssct.rayCount = math::clamp((unsigned)options.ssct.rayCount, 1u, 255u);
mAmbientOcclusionOptions = options;
}
void FView::setVsmShadowOptions(VsmShadowOptions options) noexcept {
options.msaaSamples = std::max(uint8_t(0), options.msaaSamples);
mVsmShadowOptions = options;
}
void FView::setSoftShadowOptions(SoftShadowOptions options) noexcept {
options.penumbraScale = std::max(0.0f, options.penumbraScale);
+4 -2
View File
@@ -187,7 +187,7 @@ public:
bool isStencilBufferEnabled() const noexcept { return mStencilBufferEnabled; }
FCamera const* getDirectionalLightCamera() const noexcept {
return &mShadowMapManager.getShadowMap(0)->getDebugCamera();
return &mShadowMapManager.getCascadeShadowMap(0)->getDebugCamera();
}
void setRenderTarget(FRenderTarget* renderTarget) noexcept {
@@ -305,7 +305,9 @@ public:
mShadowType = shadow;
}
void setVsmShadowOptions(VsmShadowOptions options) noexcept;
void setVsmShadowOptions(VsmShadowOptions const& options) noexcept {
mVsmShadowOptions = options;
}
VsmShadowOptions getVsmShadowOptions() const noexcept {
return mVsmShadowOptions;
+11 -37
View File
@@ -22,7 +22,7 @@ using namespace filament;
TEST(AtlasAllocator, AllocateFirstLevel) {
AtlasAllocator allocator(1024);
AtlasAllocator allocator;
auto a = allocator.allocateInLayer(0);
EXPECT_TRUE(a.l == 0 && a.code == 0);
@@ -39,7 +39,7 @@ TEST(AtlasAllocator, AllocateFirstLevel) {
TEST(AtlasAllocator, AllocateSecondLevel) {
AtlasAllocator allocator(1024);
AtlasAllocator allocator;
auto d0 = allocator.allocateInLayer(1);
EXPECT_TRUE(d0.l == 1 && d0.code == 0);
@@ -55,7 +55,7 @@ TEST(AtlasAllocator, AllocateSecondLevel) {
}
TEST(AtlasAllocator, AllocateMixed0) {
AtlasAllocator allocator(1024);
AtlasAllocator allocator;
auto e0 = allocator.allocateInLayer(1);
EXPECT_TRUE(e0.l == 1 && e0.code == 0);
@@ -74,7 +74,7 @@ TEST(AtlasAllocator, AllocateMixed0) {
}
TEST(AtlasAllocator, AllocateMixed1) {
AtlasAllocator allocator(1024);
AtlasAllocator allocator;
auto e0 = allocator.allocateInLayer(1);
EXPECT_TRUE(e0.l == 1 && e0.code == 0);
@@ -90,7 +90,7 @@ TEST(AtlasAllocator, AllocateMixed1) {
}
TEST(AtlasAllocator, AllocateMixed2) {
AtlasAllocator allocator(1024);
AtlasAllocator allocator;
auto e0 = allocator.allocateInLayer(1);
EXPECT_TRUE(e0.l == 1 && e0.code == 0);
@@ -122,11 +122,10 @@ TEST(AtlasAllocator, AllocateBySize) {
Viewport vp(0,0,256,256);
auto vp0 = allocator.allocate(256);
EXPECT_EQ(vp0.viewport, vp);
EXPECT_EQ(vp0.layer, 0);
EXPECT_EQ(vp0, vp);
auto vp1 = allocator.allocate(128);
EXPECT_EQ(vp1.layer, 1);
EXPECT_TRUE(vp1.empty());
}
TEST(AtlasAllocator, AllocateBySizeOneOfEach) {
@@ -141,35 +140,10 @@ TEST(AtlasAllocator, AllocateBySizeOneOfEach) {
auto vp2 = allocator.allocate(32);
auto vp3 = allocator.allocate(16);
EXPECT_EQ(vp0.layer, 0);
EXPECT_EQ(vp1.layer, 0);
EXPECT_EQ(vp2.layer, 0);
EXPECT_EQ(vp0.viewport, r0);
EXPECT_EQ(vp1.viewport, r1);
EXPECT_EQ(vp2.viewport, r2);
EXPECT_TRUE(vp3.viewport.empty());
EXPECT_EQ(vp0, r0);
EXPECT_EQ(vp1, r1);
EXPECT_EQ(vp2, r2);
EXPECT_TRUE(vp3.empty());
}
TEST(AtlasAllocator, AllocateBySizeFullLayers) {
AtlasAllocator allocator(512);
Viewport r(0,0,512,512);
auto vp0 = allocator.allocate(512);
auto vp1 = allocator.allocate(512);
auto vp2 = allocator.allocate(512);
auto vp3 = allocator.allocate(512);
EXPECT_EQ(vp0.layer, 0);
EXPECT_EQ(vp1.layer, 1);
EXPECT_EQ(vp2.layer, 2);
EXPECT_EQ(vp3.layer, 3);
EXPECT_EQ(vp0.viewport, r);
EXPECT_EQ(vp1.viewport, r);
EXPECT_EQ(vp2.viewport, r);
EXPECT_EQ(vp3.viewport, r);
}
+2 -2
View File
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.30.0"
spec.version = "1.28.2"
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
spec.homepage = "https://google.github.io/filament"
spec.authors = "Google LLC."
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
spec.platform = :ios, "11.0"
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.30.0/filament-v1.30.0-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.28.2/filament-v1.28.2-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {
@@ -27,7 +27,7 @@
namespace filament {
// update this when a new version of filament wouldn't work with older materials
static constexpr size_t MATERIAL_VERSION = 30;
static constexpr size_t MATERIAL_VERSION = 29;
/**
* Supported shading models
@@ -247,15 +247,18 @@ static_assert(sizeof(LightsUib) == 64,
struct ShadowUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
static constexpr std::string_view _name{ "ShadowUniforms" };
struct alignas(16) ShadowData {
math::mat4f lightFromWorldMatrix; // 64
math::float4 lightFromWorldZ; // 16
math::float4 scissorNormalized; // 16
math::mat4f lightFromWorldMatrix; // 64 - unused for point lights
math::float3 direction; // 12 - unused for point lights
float normalBias; // 4 - unused for point lights
math::float4 lightFromWorldZ; // 16 - point lights { depth reconstruction values }
float texelSizeAtOneMeter; // 4
float bulbRadiusLs; // 4
float nearOverFarMinusNear; // 4
float normalBias; // 4
bool elvsm; // 4
uint32_t layer; // 4
uint32_t reserved0; // 4
uint32_t reserved1; // 4
uint32_t reserved2; // 4
};
+2 -5
View File
@@ -35,11 +35,6 @@ Variant Variant::filterUserVariant(
if (filterMask & (uint32_t)UserVariantFilterBit::FOG) {
variant.key &= ~(filterMask & FOG);
}
} else {
// depth variants can have their VSM bit filtered
if (filterMask & (uint32_t)UserVariantFilterBit::VSM) {
variant.key &= ~(filterMask & VSM);
}
}
if (!isSSRVariant(variant)) {
// SSR variant needs to be handled separately
@@ -58,6 +53,8 @@ Variant Variant::filterUserVariant(
return variant;
}
namespace details {
// compile time sanity-check tests
+3 -3
View File
@@ -121,8 +121,8 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade
// specification constants
out << '\n';
generateSpecializationConstant(out, "BACKEND_FEATURE_LEVEL", 0, 1);
generateSpecializationConstant(out, "CONFIG_MAX_INSTANCES", 1, (int)CONFIG_MAX_INSTANCES);
generateSpecificationConstant(out, "BACKEND_FEATURE_LEVEL", 0, 1);
generateSpecificationConstant(out, "CONFIG_MAX_INSTANCES", 1, (int)CONFIG_MAX_INSTANCES);
out << '\n';
out << SHADERS_COMMON_DEFINES_GLSL_DATA;
@@ -597,7 +597,7 @@ io::sstream& CodeGenerator::generateIndexedDefine(io::sstream& out, const char*
return out;
}
utils::io::sstream& CodeGenerator::generateSpecializationConstant(utils::io::sstream& out,
utils::io::sstream& CodeGenerator::generateSpecificationConstant(utils::io::sstream& out,
const char* name, uint32_t id, std::variant<int, float, bool> value) const {
static const char* types[] = { "int", "float", "bool" };
if (mTargetLanguage == MaterialBuilderBase::TargetLanguage::SPIRV) {
+1 -1
View File
@@ -150,7 +150,7 @@ public:
static utils::io::sstream& generateIndexedDefine(utils::io::sstream& out, const char* name,
uint32_t index, uint32_t value);
utils::io::sstream& generateSpecializationConstant(utils::io::sstream& out,
utils::io::sstream& generateSpecificationConstant(utils::io::sstream& out,
const char* name, uint32_t id, std::variant<int, float, bool> value) const;
static utils::io::sstream& generatePostProcessGetters(utils::io::sstream& out, ShaderStage type);
+4 -3
View File
@@ -145,10 +145,11 @@ void FFilamentInstance::recomputeBoundingBoxes() {
}
const cgltf_accessor* targetAccessor = targetAttribute.data;
const cgltf_size targetCount = targetAccessor->count;
const cgltf_size targetDim = cgltf_num_components(targetAccessor->type);
assert_invariant(targetAccessor);
assert_invariant(targetAccessor->count == accessor->count);
assert_invariant(cgltf_num_components(targetAccessor->type) == dim);
assert_invariant(targetCount == accessor->count);
assert_invariant(targetDim == dim);
cgltf_accessor_unpack_floats(targetAccessor, unpacked.data(), unpacked.size());
-20
View File
@@ -588,26 +588,6 @@ constexpr mat4f highPrecisionMultiply(mat4f const& lhs, mat4f const& rhs) noexce
};
}
// mat4 * float4, with double precision intermediates
constexpr double4 highPrecisionMultiplyd(mat4f const& lhs, float4 const& rhs) noexcept {
double4 result{};
result += lhs[0] * rhs[0];
result += lhs[1] * rhs[1];
result += lhs[2] * rhs[2];
result += lhs[3] * rhs[3];
return result;
}
// mat4 * mat4, with double precision intermediates
constexpr mat4 highPrecisionMultiplyd(mat4f const& lhs, mat4f const& rhs) noexcept {
return {
highPrecisionMultiplyd(lhs, rhs[0]),
highPrecisionMultiplyd(lhs, rhs[1]),
highPrecisionMultiplyd(lhs, rhs[2]),
highPrecisionMultiplyd(lhs, rhs[3])
};
}
// ----------------------------------------------------------------------------------------
} // namespace math
} // namespace filament
+2 -2
View File
@@ -87,11 +87,11 @@ static_assert(size(4) == 85);
/**
* A Quad-tree encoded as an array.
* @tparam T Type of the quad-tree nodes
* @tparam HEIGHT Height of the quad-tree
* @tparam HEIGHT Height of the quad-tree, muse be <= 4
*/
template<typename T, size_t HEIGHT>
class QuadTreeArray : public std::array<T, QuadTreeUtils::size(HEIGHT)> {
static_assert(HEIGHT <= 7, "QuadTreeArray height must be <= 7 (16-bits morton)");
static_assert(HEIGHT <= 4, "QuadTreeArray height must be <= 4");
// Simple fixed capacity stack
template<typename TYPE, size_t CAPACITY,
+4 -1
View File
@@ -320,7 +320,9 @@ static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk,
for (int j = 0; j < size; ++j) {
const jsmntok_t tok = tokens[i];
CHECK_KEY(tok);
if (compare(tok, jsonChunk, "elvsm") == 0) {
if (compare(tok, jsonChunk, "msaaSamples") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->msaaSamples);
} else if (compare(tok, jsonChunk, "elvsm") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->elvsm);
} else if (compare(tok, jsonChunk, "blurWidth") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->blurWidth);
@@ -676,6 +678,7 @@ static std::ostream& operator<<(std::ostream& out, const LightManager::ShadowOpt
math::float3 splitsVector = { splits[0], splits[1], splits[2] };
return out << "{\n"
<< "\"vsm\": {\n"
<< "\"msaaSamples\": " << int(in.vsm.msaaSamples) << ",\n"
<< "\"elvsm\": " << to_string(in.vsm.elvsm) << ",\n"
<< "\"blurWidth\": " << in.vsm.blurWidth << "\n"
<< "},\n"
-3
View File
@@ -800,8 +800,6 @@ int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, VsmShadowOption
i = parse(tokens, i + 1, jsonChunk, &out->anisotropy);
} else if (compare(tok, jsonChunk, "mipmapping") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->mipmapping);
} else if (compare(tok, jsonChunk, "msaaSamples") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->msaaSamples);
} else if (compare(tok, jsonChunk, "highPrecision") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->highPrecision);
} else if (compare(tok, jsonChunk, "minVarianceScale") == 0) {
@@ -824,7 +822,6 @@ std::ostream& operator<<(std::ostream& out, const VsmShadowOptions& in) {
return out << "{\n"
<< "\"anisotropy\": " << int(in.anisotropy) << ",\n"
<< "\"mipmapping\": " << to_string(in.mipmapping) << ",\n"
<< "\"msaaSamples\": " << int(in.msaaSamples) << ",\n"
<< "\"highPrecision\": " << to_string(in.highPrecision) << ",\n"
<< "\"minVarianceScale\": " << (in.minVarianceScale) << ",\n"
<< "\"lightBleedReduction\": " << (in.lightBleedReduction) << "\n"
+1 -1
View File
@@ -846,7 +846,7 @@ void ViewerGui::updateUserInterface() {
char label[32];
snprintf(label, 32, "%d", 1 << mVsmMsaaSamplesLog2);
ImGui::SliderInt("VSM MSAA samples", &mVsmMsaaSamplesLog2, 0, 3, label);
mSettings.view.vsmShadowOptions.msaaSamples =
light.shadowOptions.vsm.msaaSamples =
static_cast<uint8_t>(1u << mVsmMsaaSamplesLog2);
int vsmAnisotropy = mSettings.view.vsmShadowOptions.anisotropy;
+1 -2
View File
@@ -2,9 +2,8 @@ struct Light {
vec4 colorIntensity; // rgb, pre-exposed intensity
vec3 l;
float attenuation;
highp vec3 worldPosition;
vec3 worldPosition;
float NoL;
highp vec3 direction;
float zLight;
bool castsShadows;
bool contactShadows;
+3 -3
View File
@@ -12,11 +12,11 @@
*/
highp vec4 computeLightSpacePosition(highp vec3 p, const highp vec3 n,
const highp vec3 dir, const float b, const highp mat4 lightFromWorldMatrix) {
const highp vec3 l, const float b, const highp mat4 lightFromWorldMatrix) {
#if !defined(VARIANT_HAS_VSM)
highp float cosTheta = saturate(dot(n, dir));
highp float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
highp float NoL = saturate(dot(n, l));
highp float sinTheta = sqrt(1.0 - NoL * NoL);
p += n * (sinTheta * b);
#endif
+9 -8
View File
@@ -2,16 +2,17 @@
// UBOs, which is is the case here.
struct ShadowData {
highp mat4 lightFromWorldMatrix;
highp vec3 direction;
float normalBias;
highp vec4 lightFromWorldZ;
highp vec4 scissorNormalized;
mediump float texelSizeAtOneMeter;
mediump float bulbRadiusLs;
mediump float nearOverFarMinusNear;
mediump float normalBias;
float texelSizeAtOneMeter;
float bulbRadiusLs;
float nearOverFarMinusNear;
bool elvsm;
mediump uint layer;
mediump uint reserved1;
mediump uint reserved2;
uint layer;
uint reserved0;
uint reserved1;
uint reserved2;
};
struct BoneData {
+2 -1
View File
@@ -94,8 +94,9 @@ highp vec3 getNormalizedViewportCoord2() {
}
#if defined(VARIANT_HAS_SHADOWING) && defined(VARIANT_HAS_DYNAMIC_LIGHTING)
highp vec4 getSpotLightSpacePosition(uint index, highp vec3 dir, highp float zLight) {
highp vec4 getSpotLightSpacePosition(uint index, highp float zLight) {
highp mat4 lightFromWorldMatrix = shadowUniforms.shadows[index].lightFromWorldMatrix;
highp vec3 dir = shadowUniforms.shadows[index].direction;
// for spotlights, the bias depends on z
float bias = shadowUniforms.shadows[index].normalBias * zLight;
+1 -1
View File
@@ -56,7 +56,7 @@ void evaluateDirectionalLight(const MaterialInputs material,
bool cascadeHasVisibleShadows = bool(frameUniforms.cascades & ((1u << cascade) << 8u));
bool hasDirectionalShadows = bool(frameUniforms.directionalShadows & 1u);
if (hasDirectionalShadows && cascadeHasVisibleShadows) {
highp vec4 shadowPosition = getShadowPosition(cascade);
highp vec4 shadowPosition = getShadowPosition(true, 0u, cascade, 0.0f);
visibility = shadow(true, light_shadowMap, cascade, shadowPosition, 0.0f);
}
if ((frameUniforms.directionalShadows & 0x2u) != 0u && visibility > 0.0) {
+7 -5
View File
@@ -150,7 +150,6 @@ Light getLight(const uint lightIndex) {
light.colorIntensity.w = computePreExposedIntensity(intensity, frameUniforms.exposure);
light.l = normalize(posToLight);
light.attenuation = getDistanceAttenuation(posToLight, positionFalloff.w);
light.direction = direction;
light.NoL = saturate(dot(shading_normal, light.l));
light.worldPosition = positionFalloff.xyz;
light.channels = channels;
@@ -212,15 +211,18 @@ void evaluatePunctualLights(const MaterialInputs material,
if (light.NoL > 0.0) {
if (light.castsShadows) {
uint shadowIndex = light.shadowIndex;
highp vec4 shadowPosition;
if (light.type == LIGHT_TYPE_POINT) {
// point-light shadows are sampled from a direction
highp vec3 r = getWorldPosition() - light.worldPosition;
uint face = getPointLightFace(r);
highp uint face = 0u;
// getShadowPosition returns zLight which is needed for PCSS/DPCF
shadowPosition = getShadowPosition(r, shadowIndex, light.zLight, face);
shadowIndex += face;
light.zLight = dot(shadowUniforms.shadows[shadowIndex].lightFromWorldZ,
vec4(getWorldPosition(), 1.0));
} else {
// getShadowPosition needs zLight for applying the normal bias
shadowPosition = getShadowPosition(false, shadowIndex, 0u, light.zLight);
}
highp vec4 shadowPosition = getShadowPosition(shadowIndex, light.direction, light.zLight);
visibility = shadow(false, light_shadowMap, shadowIndex,
shadowPosition, light.zLight);
}
+1 -1
View File
@@ -50,7 +50,7 @@ vec4 evaluateMaterial(const MaterialInputs material) {
bool cascadeHasVisibleShadows = bool(frameUniforms.cascades & ((1u << cascade) << 8u));
bool hasDirectionalShadows = bool(frameUniforms.directionalShadows & 1u);
if (hasDirectionalShadows && cascadeHasVisibleShadows) {
highp vec4 shadowPosition = getShadowPosition(cascade);
highp vec4 shadowPosition = getShadowPosition(true, 0u, cascade, 0.0f);
visibility = shadow(true, light_shadowMap, cascade, shadowPosition, 0.0f);
}
if ((frameUniforms.directionalShadows & 0x2u) != 0u && visibility > 0.0) {
+81 -79
View File
@@ -17,33 +17,27 @@
// PCF Shadow Sampling
//------------------------------------------------------------------------------
float sampleDepth(const mediump sampler2DArrayShadow map,
const highp vec4 scissorNormalized,
const uint layer, highp vec2 uv, float depth) {
// clamp needed for directional lights and/or large kernels
uv = clamp(uv, scissorNormalized.xy, scissorNormalized.zw);
// depth must be clamped to support floating-point depth formats which are always in
// the range [0, 1].
float sampleDepth(const mediump sampler2DArrayShadow map, const uint layer,
const highp vec2 uv, float depth) {
// depth must be clamped to support floating-point depth formats. This is to avoid comparing a
// value from the depth texture (which is never greater than 1.0) with a greater-than-one
// comparison value (which is possible with floating-point formats).
return texture(map, vec4(uv, layer, saturate(depth)));
}
#if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HARD
// use hardware assisted PCF
float ShadowSample_PCF_Hard(const mediump sampler2DArrayShadow map,
const highp vec4 scissorNormalized,
const uint layer, const highp vec4 shadowPosition) {
highp vec3 position = shadowPosition.xyz * (1.0 / shadowPosition.w);
// note: shadowPosition.z is in the [1, 0] range (reversed Z)
return sampleDepth(map, scissorNormalized, layer, position.xy, position.z);
return sampleDepth(map, layer, position.xy, position.z);
}
#endif
#if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_LOW
// use hardware assisted PCF + 3x3 gaussian filter
float ShadowSample_PCF_Low(const mediump sampler2DArrayShadow map,
const highp vec4 scissorNormalized,
const uint layer, const highp vec4 shadowPosition) {
highp vec3 position = shadowPosition.xyz * (1.0 / shadowPosition.w);
// note: shadowPosition.z is in the [1, 0] range (reversed Z)
@@ -71,35 +65,31 @@ float ShadowSample_PCF_Low(const mediump sampler2DArrayShadow map,
v *= texelSize.y;
float sum = 0.0;
sum += uw.x * vw.x * sampleDepth(map, scissorNormalized, layer, base + vec2(u.x, v.x), depth);
sum += uw.y * vw.x * sampleDepth(map, scissorNormalized, layer, base + vec2(u.y, v.x), depth);
sum += uw.x * vw.y * sampleDepth(map, scissorNormalized, layer, base + vec2(u.x, v.y), depth);
sum += uw.y * vw.y * sampleDepth(map, scissorNormalized, layer, base + vec2(u.y, v.y), depth);
sum += uw.x * vw.x * sampleDepth(map, layer, base + vec2(u.x, v.x), depth);
sum += uw.y * vw.x * sampleDepth(map, layer, base + vec2(u.y, v.x), depth);
sum += uw.x * vw.y * sampleDepth(map, layer, base + vec2(u.x, v.y), depth);
sum += uw.y * vw.y * sampleDepth(map, layer, base + vec2(u.y, v.y), depth);
return sum * (1.0 / 16.0);
}
#endif
// use manual PCF
float ShadowSample_PCF(const mediump sampler2DArray map,
const highp vec4 scissorNormalized,
const uint layer, const highp vec4 shadowPosition) {
highp vec3 position = shadowPosition.xyz * (1.0 / shadowPosition.w);
// note: shadowPosition.z is in the [1, 0] range (reversed Z)
highp vec2 size = vec2(textureSize(map, 0));
highp vec2 tc = clamp(position.xy, scissorNormalized.xy, scissorNormalized.zw);
highp vec2 st = tc.xy * size - 0.5;
highp vec2 st = position.xy * size - 0.5;
vec4 d;
#if defined(FILAMENT_HAS_FEATURE_TEXTURE_GATHER)
d = textureGather(map, vec3(tc, layer), 0); // 01, 11, 10, 00
d = textureGather(map, vec3(position.xy, layer), 0); // 01, 11, 10, 00
#else
// we must use texelFetchOffset before texelLodOffset filters
d[0] = texelFetchOffset(map, ivec3(st, layer), 0, ivec2(0, 1)).r;
d[1] = texelFetchOffset(map, ivec3(st, layer), 0, ivec2(1, 1)).r;
d[2] = texelFetchOffset(map, ivec3(st, layer), 0, ivec2(1, 0)).r;
d[3] = texelFetchOffset(map, ivec3(st, layer), 0, ivec2(0, 0)).r;
highp ivec3 tc = ivec3(st, layer);
d[0] = texelFetchOffset(map, tc, 0, ivec2(0, 1)).r;
d[1] = texelFetchOffset(map, tc, 0, ivec2(1, 1)).r;
d[2] = texelFetchOffset(map, tc, 0, ivec2(1, 0)).r;
d[3] = texelFetchOffset(map, tc, 0, ivec2(0, 0)).r;
#endif
vec4 pcf = step(0.0, position.zzzz - d);
highp vec2 grad = fract(st);
return mix(mix(pcf.w, pcf.z, grad.x), mix(pcf.x, pcf.y, grad.x), grad.y);
@@ -202,17 +192,14 @@ float getPenumbraRatio(const bool DIRECTIONAL, const uint index,
}
void blockerSearchAndFilter(out float occludedCount, out float z_occSum,
const mediump sampler2DArray map, const highp vec4 scissorNormalized, const highp vec2 uv,
const float z_rec, const uint layer,
const mediump sampler2DArray map, const highp vec2 uv, const float z_rec, const uint layer,
const highp vec2 filterRadii, const mat2 R, const highp vec2 dz_duv,
const uint tapCount) {
occludedCount = 0.0;
z_occSum = 0.0;
for (uint i = 0u; i < tapCount; i++) {
highp vec2 duv = R * (poissonDisk[i] * filterRadii);
highp vec2 tc = clamp(uv + duv, scissorNormalized.xy, scissorNormalized.zw);
float z_occ = textureLod(map, vec3(tc, layer), 0.0).r;
float z_occ = textureLod(map, vec3(uv + duv, layer), 0.0).r;
// note: z_occ and z_rec are not necessarily linear here, comparing them is always okay for
// the regular PCF, but the "distance" is meaningless unless they are actually linear
@@ -230,9 +217,7 @@ void blockerSearchAndFilter(out float occludedCount, out float z_occSum,
}
}
float filterPCSS(const mediump sampler2DArray map,
const highp vec4 scissorNormalized,
const highp vec2 size,
float filterPCSS(const mediump sampler2DArray map, const highp vec2 size,
const highp vec2 uv, const float z_rec, const uint layer,
const highp vec2 filterRadii, const mat2 R, const highp vec2 dz_duv,
const uint tapCount) {
@@ -243,14 +228,11 @@ float filterPCSS(const mediump sampler2DArray map,
// sample the shadow map with a 2x2 PCF, this helps a lot in low resolution areas
vec4 d;
highp vec2 tc = clamp(uv + duv, scissorNormalized.xy, scissorNormalized.zw);
highp vec2 st = tc.xy * size - 0.5;
highp vec2 st = (uv + duv) * size - 0.5;
highp vec2 grad = fract(st);
#if defined(FILAMENT_HAS_FEATURE_TEXTURE_GATHER)
d = textureGather(map, vec3(tc, layer), 0); // 01, 11, 10, 00
d = textureGather(map, vec3(uv + duv, layer), 0); // 01, 11, 10, 00
#else
// we must use texelFetchOffset before texelLodOffset filters
d[0] = texelFetchOffset(map, ivec3(st, layer), 0, ivec2(0, 1)).r;
d[1] = texelFetchOffset(map, ivec3(st, layer), 0, ivec2(1, 1)).r;
d[2] = texelFetchOffset(map, ivec3(st, layer), 0, ivec2(1, 0)).r;
@@ -271,9 +253,7 @@ float filterPCSS(const mediump sampler2DArray map,
* see "Shadow of Cold War", A scalable approach to shadowing -- by Kevin Myers
*/
float ShadowSample_DPCF(const bool DIRECTIONAL,
const mediump sampler2DArray map,
const highp vec4 scissorNormalized,
const uint layer, const uint index,
const mediump sampler2DArray map, const uint layer, const uint index,
const highp vec4 shadowPosition, const highp float zLight) {
highp vec3 position = shadowPosition.xyz * (1.0 / shadowPosition.w);
highp vec2 texelSize = vec2(1.0) / vec2(textureSize(map, 0));
@@ -291,7 +271,7 @@ float ShadowSample_DPCF(const bool DIRECTIONAL,
float z_occSum = 0.0;
blockerSearchAndFilter(occludedCount, z_occSum,
map, scissorNormalized, position.xy, position.z, layer, texelSize * penumbra, R, dz_duv,
map, position.xy, position.z, layer, texelSize * penumbra, R, dz_duv,
DPCF_SHADOW_TAP_COUNT);
// early exit if there is no occluders at all, also avoids a divide-by-zero below.
@@ -318,9 +298,7 @@ float ShadowSample_DPCF(const bool DIRECTIONAL,
}
float ShadowSample_PCSS(const bool DIRECTIONAL,
const mediump sampler2DArray map,
const highp vec4 scissorNormalized,
const uint layer, const uint index,
const mediump sampler2DArray map, const uint layer, const uint index,
const highp vec4 shadowPosition, const highp float zLight) {
highp vec2 size = vec2(textureSize(map, 0));
highp vec2 texelSize = vec2(1.0) / size;
@@ -339,7 +317,7 @@ float ShadowSample_PCSS(const bool DIRECTIONAL,
float z_occSum = 0.0;
blockerSearchAndFilter(occludedCount, z_occSum,
map, scissorNormalized, position.xy, position.z, layer, texelSize * penumbra, R, dz_duv,
map, position.xy, position.z, layer, texelSize * penumbra, R, dz_duv,
PCSS_SHADOW_BLOCKER_SEARCH_TAP_COUNT);
// early exit if there is no occluders at all, also avoids a divide-by-zero below.
@@ -349,8 +327,7 @@ float ShadowSample_PCSS(const bool DIRECTIONAL,
float penumbraRatio = getPenumbraRatio(DIRECTIONAL, index, position.z, z_occSum / occludedCount);
float percentageOccluded = filterPCSS(map, scissorNormalized, size,
position.xy, position.z, layer,
float percentageOccluded = filterPCSS(map, size, position.xy, position.z, layer,
texelSize * (penumbra * penumbraRatio),
R, dz_duv, PCSS_SHADOW_FILTER_TAP_COUNT);
@@ -467,7 +444,6 @@ float evaluateShadowVSM(const highp vec2 moments, const highp float depth) {
}
float ShadowSample_VSM(const bool ELVSM, const mediump sampler2DArray shadowMap,
const highp vec4 scissorNormalized,
const uint layer, const highp vec4 shadowPosition) {
// note: shadowPosition.z is in linear light-space normalized to [0, 1]
@@ -475,10 +451,6 @@ float ShadowSample_VSM(const bool ELVSM, const mediump sampler2DArray shadowMap,
// see: computeLightSpacePosition() in common_shadowing.fs
highp vec3 position = vec3(shadowPosition.xy * (1.0 / shadowPosition.w), shadowPosition.z);
// Note: we don't need to clamp to `scissorNormalized` in the VSM case because this is only
// needed when the shadow casters and receivers are different, which is never the case with VSM
// (see ShadowMap.cpp).
// Read the shadow map with all available filtering
highp vec4 moments = texture(shadowMap, vec3(position.xy, layer));
highp float depth = position.z;
@@ -506,43 +478,78 @@ float ShadowSample_VSM(const bool ELVSM, const mediump sampler2DArray shadowMap,
*/
// get texture coordinate for directional and spot shadow maps
highp vec4 getShadowPosition(const bool DIRECTIONAL,
const uint index, const uint cascade, const highp float zLight) {
highp vec4 p;
// This conditional is resolved at compile time
if (DIRECTIONAL) {
#if defined(VARIANT_HAS_DIRECTIONAL_LIGHTING)
highp vec4 getShadowPosition(const uint cascade) {
return getCascadeLightSpacePosition(cascade);
}
p = getCascadeLightSpacePosition(cascade);
#endif
} else {
#if defined(VARIANT_HAS_DYNAMIC_LIGHTING)
highp vec4 getShadowPosition(const uint index, const highp vec3 dir, const highp float zLight) {
return getSpotLightSpacePosition(index, dir, zLight);
}
p = getSpotLightSpacePosition(index, zLight);
#endif
}
return p;
}
uint getPointLightFace(const highp vec3 r) {
// get {texture coordinate, layer} for point shadow maps
highp vec4 getShadowPosition(const highp vec3 r, const highp uint shadowIndex,
out highp float d, out highp uint face) {
highp vec4 tc;
highp float rx = abs(r.x);
highp float ry = abs(r.y);
highp float rz = abs(r.z);
highp float d = max(rx, max(ry, rz));
d = max(rx, max(ry, rz));
highp float ma = 1.0 / d;
if (d == rx) {
return (r.x >= 0.0 ? 0u : 1u);
tc.x = r.x >= 0.0 ? r.z : -r.z;
tc.y = r.y;
face = (r.x >= 0.0 ? 0u : 1u);
} else if (d == ry) {
return (r.y >= 0.0 ? 2u : 3u);
tc.x = r.y >= 0.0 ? r.x : -r.x;
tc.y = r.z;
face = (r.y >= 0.0 ? 2u : 3u);
} else {
return (r.z >= 0.0 ? 4u : 5u);
tc.x = r.z >= 0.0 ? -r.x : r.x;
tc.y = r.y;
face = (r.z >= 0.0 ? 4u : 5u);
}
// ma is guaranteed to be >= sc and tc
tc.xy = (tc.xy * ma + vec2(1.0)) * 0.5;
highp vec4 nf = shadowUniforms.shadows[shadowIndex + face].lightFromWorldZ;
// z coordinate of the normalized fragment position in light-space
// i.e.: remap [near, far] to [0,1] : d = (d - n) / (f - n)
d = nf[2] + nf[3] * d;
if (frameUniforms.shadowSamplingType == SHADOW_SAMPLING_RUNTIME_EVSM) {
// for VSM, the depth metric is linear normalized in light-space
tc.z = d;
} else {
// for other types of shadows it's clip-space depth. Below is an optimized version of
// (lightProjection * position).z
tc.z = nf[0] + nf[1] * ma;
}
// FIXME: the normal bias is not applied
tc.w = 1.0;
return tc;
}
// PCF sampling
float shadow(const bool DIRECTIONAL,
const mediump sampler2DArrayShadow shadowMap,
const uint index, highp vec4 shadowPosition, highp float zLight) {
highp vec4 scissorNormalized = shadowUniforms.shadows[index].scissorNormalized;
uint layer = shadowUniforms.shadows[index].layer;
#if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HARD
return ShadowSample_PCF_Hard(shadowMap, scissorNormalized, layer, shadowPosition);
return ShadowSample_PCF_Hard(shadowMap, layer, shadowPosition);
#elif SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_LOW
return ShadowSample_PCF_Low(shadowMap, scissorNormalized, layer, shadowPosition);
return ShadowSample_PCF_Low(shadowMap, layer, shadowPosition);
#endif
}
@@ -550,31 +557,26 @@ float shadow(const bool DIRECTIONAL,
float shadow(const bool DIRECTIONAL,
const mediump sampler2DArray shadowMap,
const uint index, highp vec4 shadowPosition, highp float zLight) {
highp vec4 scissorNormalized = shadowUniforms.shadows[index].scissorNormalized;
uint layer = shadowUniforms.shadows[index].layer;
// This conditional is resolved at compile time
if (frameUniforms.shadowSamplingType == SHADOW_SAMPLING_RUNTIME_EVSM) {
bool elvsm = shadowUniforms.shadows[index].elvsm;
return ShadowSample_VSM(elvsm, shadowMap, scissorNormalized, layer,
shadowPosition);
return ShadowSample_VSM(elvsm, shadowMap, layer, shadowPosition);
}
if (frameUniforms.shadowSamplingType == SHADOW_SAMPLING_RUNTIME_DPCF) {
return ShadowSample_DPCF(DIRECTIONAL, shadowMap, scissorNormalized, layer, index,
shadowPosition, zLight);
return ShadowSample_DPCF(DIRECTIONAL, shadowMap, layer, index, shadowPosition, zLight);
}
if (frameUniforms.shadowSamplingType == SHADOW_SAMPLING_RUNTIME_PCSS) {
return ShadowSample_PCSS(DIRECTIONAL, shadowMap, scissorNormalized, layer, index,
shadowPosition, zLight);
return ShadowSample_PCSS(DIRECTIONAL, shadowMap, layer, index, shadowPosition, zLight);
}
if (frameUniforms.shadowSamplingType == SHADOW_SAMPLING_RUNTIME_PCF) {
// This is here mostly for debugging at this point.
// Note: In this codepath, the normal bias is not applied because we're in the VSM variant.
// (see: get{Cascade|Spot}LightSpacePosition)
return ShadowSample_PCF(shadowMap, scissorNormalized,
layer, shadowPosition);
return ShadowSample_PCF(shadowMap, layer, shadowPosition);
}
// should not happen
+6 -6
View File
@@ -33,6 +33,12 @@
#include "SDL_video.h"
#include "SDL_version.h"
#include "begin_code.h"
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \file SDL_syswm.h
*
@@ -104,12 +110,6 @@ typedef void *EGLSurface;
#include "SDL_egl.h"
#endif
#include "begin_code.h"
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
/**
* These are the various supported windowing subsystems
*/
-1
View File
@@ -164,7 +164,6 @@ Filament.loadGeneratedExtensions = function() {
const options = {
anisotropy: 0,
mipmapping: false,
msaaSamples: 1,
highPrecision: false,
minVarianceScale: 0.5,
lightBleedReduction: 0.15,
-7
View File
@@ -1678,13 +1678,6 @@ export interface View$VsmShadowOptions {
* Whether to generate mipmaps for all VSM shadow maps.
*/
mipmapping?: boolean;
/**
* 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.
*/
msaaSamples?: number;
/**
* 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
View File
@@ -135,7 +135,6 @@ value_object<View::GuardBandOptions>("View$GuardBandOptions")
value_object<View::VsmShadowOptions>("View$VsmShadowOptions")
.field("anisotropy", &View::VsmShadowOptions::anisotropy)
.field("mipmapping", &View::VsmShadowOptions::mipmapping)
.field("msaaSamples", &View::VsmShadowOptions::msaaSamples)
.field("highPrecision", &View::VsmShadowOptions::highPrecision)
.field("minVarianceScale", &View::VsmShadowOptions::minVarianceScale)
.field("lightBleedReduction", &View::VsmShadowOptions::lightBleedReduction)
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "filament",
"version": "1.30.0",
"version": "1.28.2",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",