Compare commits
26 Commits
ebridgewat
...
ebridgewat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d59459f90 | ||
|
|
4249ff6cfb | ||
|
|
1076433fc0 | ||
|
|
3bd0039ee9 | ||
|
|
67b9c72442 | ||
|
|
c1a8d73384 | ||
|
|
2d98ac878e | ||
|
|
35ab5f768d | ||
|
|
705b3c39f4 | ||
|
|
56231db326 | ||
|
|
e97f7ef628 | ||
|
|
4570c2e710 | ||
|
|
4759237e66 | ||
|
|
543b93939a | ||
|
|
9b356926b8 | ||
|
|
7179ab5b9d | ||
|
|
0a6bbdb35c | ||
|
|
29919e64cd | ||
|
|
a7660e40f8 | ||
|
|
22e1f9b930 | ||
|
|
e205611128 | ||
|
|
8a3bf04eef | ||
|
|
44840a481e | ||
|
|
8070643ba5 | ||
|
|
0c33f9f2a3 | ||
|
|
db72bd024b |
7
.github/actions/dep-versions/action.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
name: 'Set up dependency versions'
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Set up dependency versions
|
||||
shell: bash
|
||||
run: cat ./build/common/versions >> $GITHUB_ENV
|
||||
38
.github/actions/linux-prereq/action.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: 'Linux Preqrequisites'
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: ./.github/actions/dep-versions
|
||||
- name: Install Linux Prerequisites
|
||||
shell: bash
|
||||
run: |
|
||||
set -xe
|
||||
# See https://askubuntu.com/questions/272248/processing-triggers-for-man-db/1476024#1476024
|
||||
echo "set man-db/auto-update false" | sudo debconf-communicate
|
||||
sudo dpkg-reconfigure man-db
|
||||
|
||||
# Install ninja
|
||||
source ./build/common/get-ninja.sh
|
||||
|
||||
# Install CMake
|
||||
mkdir -p cmake
|
||||
cd cmake
|
||||
|
||||
sudo wget https://github.com/Kitware/CMake/releases/download/v$GITHUB_CMAKE_VERSION/cmake-$GITHUB_CMAKE_VERSION-Linux-x86_64.sh
|
||||
sudo chmod +x ./cmake-$GITHUB_CMAKE_VERSION-Linux-x86_64.sh
|
||||
sudo ./cmake-$GITHUB_CMAKE_VERSION-Linux-x86_64.sh --skip-license > /dev/null
|
||||
sudo update-alternatives --install /usr/bin/cmake cmake $(pwd)/bin/cmake 1000 --force
|
||||
|
||||
cd ..
|
||||
|
||||
sudo wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo apt-get update
|
||||
sudo apt-get install clang-$GITHUB_CLANG_VERSION libc++-$GITHUB_CLANG_VERSION-dev libc++abi-$GITHUB_CLANG_VERSION-dev
|
||||
sudo apt-get install mesa-common-dev libxi-dev libxxf86vm-dev
|
||||
|
||||
# For dawn
|
||||
sudo apt-get install libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libx11-xcb-dev
|
||||
|
||||
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${GITHUB_CLANG_VERSION} 100
|
||||
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${GITHUB_CLANG_VERSION} 100
|
||||
set +xe
|
||||
23
.github/actions/mac-prereq/action.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: 'Mac Preqrequisites'
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: ./.github/actions/dep-versions
|
||||
- name: Set up Homebrew
|
||||
id: set-up-homebrew
|
||||
uses: Homebrew/actions/setup-homebrew@master
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Cache Brew
|
||||
id: brew-cache
|
||||
uses: actions/cache@v4 # Use a specific version
|
||||
with:
|
||||
path: $HOME/Library/Caches/Homebrew
|
||||
key: ${{ runner.os }}-brew-20250424
|
||||
- name: Install Mac Prerequisites
|
||||
shell: bash
|
||||
run: |
|
||||
# Install ninja
|
||||
source ./build/common/get-ninja.sh
|
||||
3
.github/workflows/android-continuous.yml
vendored
@@ -16,6 +16,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- name: Run Android Continuous
|
||||
uses: ./.github/actions/android-continuous
|
||||
with:
|
||||
|
||||
3
.github/workflows/ios-continuous.yml
vendored
@@ -14,6 +14,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/ios && printf "y" | ./build.sh continuous
|
||||
|
||||
3
.github/workflows/linux-continuous.yml
vendored
@@ -14,6 +14,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/linux && printf "y" | ./build.sh continuous
|
||||
|
||||
3
.github/workflows/mac-continuous.yml
vendored
@@ -14,6 +14,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/mac && printf "y" | ./build.sh continuous
|
||||
|
||||
82
.github/workflows/presubmit.yml
vendored
@@ -9,22 +9,32 @@ on:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build-desktop:
|
||||
name: build-desktop
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-14-xlarge, ubuntu-22.04-16core]
|
||||
|
||||
build-desktop-mac:
|
||||
name: build-mac
|
||||
runs-on: macos-14-xlarge
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
WORKFLOW_OS=`echo \`uname\` | sed "s/Darwin/mac/" | tr [:upper:] [:lower:]`
|
||||
cd build/$WORKFLOW_OS && printf "y" | ./build.sh presubmit
|
||||
cd build/mac && printf "y" | ./build.sh presubmit
|
||||
- name: Test material parser
|
||||
run: |
|
||||
out/cmake-release/filament/test/test_material_parser
|
||||
|
||||
build-desktop-linux:
|
||||
name: build-linux
|
||||
runs-on: ubuntu-22.04-16core
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/linux && printf "y" | ./build.sh presubmit
|
||||
- name: Test material parser
|
||||
run: |
|
||||
out/cmake-release/filament/test/test_material_parser
|
||||
@@ -35,6 +45,8 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Run build script
|
||||
run: |
|
||||
build\windows\build-github.bat presubmit
|
||||
@@ -48,6 +60,7 @@ jobs:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
@@ -66,6 +79,7 @@ jobs:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/ios && printf "y" | ./build.sh presubmit
|
||||
@@ -79,6 +93,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/web && printf "y" | ./build.sh presubmit
|
||||
@@ -101,30 +118,20 @@ jobs:
|
||||
runs-on: macos-14-xlarge
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Set up Homebrew
|
||||
id: set-up-homebrew
|
||||
uses: Homebrew/actions/setup-homebrew@master
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Cache Mesa and deps
|
||||
id: mesa-cache
|
||||
uses: actions/cache@v4 # Use a specific version
|
||||
with:
|
||||
path: |
|
||||
$HOME/Library/Caches/Homebrew
|
||||
mesa
|
||||
key: ${{ runner.os }}-mesa-deps-${{ vars.MESA_VERSION }}
|
||||
path: mesa
|
||||
key: ${{ runner.os }}-mesa-deps-2-${{ vars.MESA_VERSION }}
|
||||
- name: Get Mesa
|
||||
id: mesa-prereq
|
||||
env:
|
||||
MESA_VERSION: ${{ vars.MESA_VERSION }}
|
||||
run: |
|
||||
bash test/utils/get_mesa.sh
|
||||
run: bash test/utils/get_mesa.sh
|
||||
- name: Run Test
|
||||
run: |
|
||||
bash test/renderdiff/test.sh
|
||||
run: bash test/renderdiff/test.sh
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: presubmit-renderdiff-result
|
||||
@@ -133,11 +140,13 @@ jobs:
|
||||
validate-wgsl-webgpu:
|
||||
name: validate-wgsl-webgpu
|
||||
runs-on: 'ubuntu-24.04-8core'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- name: Run build script
|
||||
run: source ./build/linux/ci-common.sh && ./build.sh -W debug test_filamat filament
|
||||
run: ./build.sh -W debug test_filamat filament
|
||||
- name: Run test
|
||||
run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl*
|
||||
|
||||
@@ -148,23 +157,16 @@ jobs:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up Homebrew
|
||||
id: set-up-homebrew
|
||||
uses: Homebrew/actions/setup-homebrew@master
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install prerequisites
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Install clang-tidy and deps
|
||||
run: |
|
||||
pip install pyyaml
|
||||
brew install llvm
|
||||
sudo ln -s "$(brew --prefix llvm)/bin/clang-tidy" "/usr/local/bin/clang-tidy"
|
||||
brew install llvm@${GITHUB_LLVM_VERSION}
|
||||
sudo ln -s "$(brew --prefix llvm)@${GITHUB_LLVM_VERSION}/bin/clang-tidy" "/usr/local/bin/clang-tidy"
|
||||
- name: Run build script
|
||||
# We need to build before clang-tidy can run analysis
|
||||
run: |
|
||||
# This will build for all three desktop backends on mac
|
||||
./build.sh -p desktop debug gltf_viewer
|
||||
- name: Run test
|
||||
run: |
|
||||
bash test/code-correctness/test.sh
|
||||
run: bash test/code-correctness/test.sh
|
||||
|
||||
48
.github/workflows/release.yml
vendored
@@ -29,8 +29,42 @@ on:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
build-desktop:
|
||||
name: build-desktop
|
||||
build-linux:
|
||||
name: build-linux
|
||||
runs-on: ubuntu-22.04-32core
|
||||
if: github.event_name == 'release' || github.event.inputs.platform == 'desktop'
|
||||
|
||||
steps:
|
||||
- name: Decide Git ref
|
||||
id: git_ref
|
||||
run: |
|
||||
REF=${RELEASE_TAG:-${GITHUB_REF}}
|
||||
TAG=${REF##*/}
|
||||
echo "ref=${REF}" >> $GITHUB_OUTPUT
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- name: Run build script
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
run: |
|
||||
cd build/linux && printf "y" | ./build.sh release
|
||||
cd ../..
|
||||
mv out/filament-release-linux.tgz out/filament-${TAG}-linux.tgz
|
||||
- uses: actions/github-script@v6
|
||||
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);
|
||||
|
||||
build-mac:
|
||||
name: build-mac
|
||||
runs-on: ${{ matrix.os }}
|
||||
if: github.event_name == 'release' || github.event.inputs.platform == 'desktop'
|
||||
|
||||
@@ -49,15 +83,14 @@ jobs:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- 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 build/mac && printf "y" | ./build.sh release
|
||||
cd ../..
|
||||
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;
|
||||
mv out/filament-release-darwin.tgz out/filament-${TAG}-mac.tgz
|
||||
- uses: actions/github-script@v6
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
@@ -84,6 +117,7 @@ jobs:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- name: Run build script
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
@@ -121,6 +155,7 @@ jobs:
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- name: Run build script
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
@@ -171,6 +206,7 @@ jobs:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Run build script
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
|
||||
3
.github/workflows/web-continuous.yml
vendored
@@ -14,6 +14,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/web && printf "y" | ./build.sh continuous
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.59.3'
|
||||
implementation 'com.google.android.filament:filament-android:1.59.4'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
||||
iOS projects can use CocoaPods to install the latest release:
|
||||
|
||||
```shell
|
||||
pod 'Filament', '~> 1.59.3'
|
||||
pod 'Filament', '~> 1.59.4'
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -7,6 +7,9 @@ A new header is inserted each time a *tag* is created.
|
||||
Instead, if you are authoring a PR for the main branch, add your release note to
|
||||
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
||||
|
||||
## v1.59.5
|
||||
|
||||
|
||||
## v1.59.4
|
||||
|
||||
|
||||
|
||||
@@ -1980,7 +1980,7 @@ public class View {
|
||||
}
|
||||
|
||||
/**
|
||||
* reconstruction filter width typically between 0.2 (sharper, aliased) and 1.5 (smoother)
|
||||
* reconstruction filter width typically between 1 (sharper) and 2 (smoother)
|
||||
*/
|
||||
public float filterWidth = 1.0f;
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.59.3
|
||||
VERSION_NAME=1.59.4
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -14,12 +14,12 @@ echo "Please refer to BUILDING.md for more information."
|
||||
read -r -p "Do you wish to proceed (y/n)? " choice
|
||||
case "${choice}" in
|
||||
y|Y)
|
||||
echo "Build will proceed..."
|
||||
;;
|
||||
echo "Build will proceed..."
|
||||
;;
|
||||
n|N)
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
@@ -30,30 +30,27 @@ set -x
|
||||
UNAME=`echo $(uname)`
|
||||
LC_UNAME=`echo $UNAME | tr '[:upper:]' '[:lower:]'`
|
||||
|
||||
FILAMENT_ANDROID_CI_BUILD=true
|
||||
|
||||
# build-common.sh will generate the following variables:
|
||||
# $GENERATE_ARCHIVES
|
||||
# $BUILD_DEBUG
|
||||
# $BUILD_RELEASE
|
||||
source `dirname $0`/../common/ci-common.sh
|
||||
if [[ "$LC_UNAME" == "linux" ]]; then
|
||||
source `dirname $0`/../linux/ci-common.sh
|
||||
elif [[ "$LC_UNAME" == "darwin" ]]; then
|
||||
source `dirname $0`/../mac/ci-common.sh
|
||||
fi
|
||||
source `dirname $0`/../common/build-common.sh
|
||||
|
||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||
java_version=$(java -version 2>&1 | head -1 | cut -d'"' -f2 | sed '/^1\./s///' | cut -d'.' -f1)
|
||||
if [[ "$java_version" < 17 ]]; then
|
||||
echo "Android builds require Java 17, found version ${java_version} instead"
|
||||
exit 0
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Unless explicitly specified, NDK version will be set to match exactly the required one
|
||||
FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/ndk.version)}
|
||||
FILAMENT_NDK_VERSION=${GITHUB_NDK_VERSION:-27.0.11718014}
|
||||
|
||||
(! grep "${FILAMENT_NDK_VERSION}" `dirname $0`/../../android/build.gradle > /dev/null) &&
|
||||
echo "Mismatch of NDK versions: want ${FILAMENT_NDK_VERSION} and not found in android/build.gradle" &&
|
||||
exit 1
|
||||
|
||||
# Install the required NDK version specifically (if not present)
|
||||
if [[ ! -d "${ANDROID_HOME}/ndk/$FILAMENT_NDK_VERSION" ]]; then
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
27.0.11718014
|
||||
@@ -2,5 +2,4 @@
|
||||
|
||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||
echo "Running workflow $GITHUB_WORKFLOW (event: $GITHUB_EVENT_NAME, action: $GITHUB_ACTION)"
|
||||
CONTINUOUS_INTEGRATION=true
|
||||
fi
|
||||
|
||||
18
build/common/get-ninja.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||
OS_NAME=$(uname -s)
|
||||
NINJA_DL_DIR=/tmp/ninja-dl
|
||||
NINJA_PLATFORM=
|
||||
if [[ "$OS_NAME" == "Linux" ]]; then
|
||||
NINJA_PLATFORM=linux
|
||||
elif [[ "$OS_NAME" == "Darwin" ]]; then
|
||||
NINJA_PLATFORM=mac
|
||||
fi
|
||||
curl -L -o /tmp/ninja-dl.zip https://github.com/ninja-build/ninja/releases/download/v${GITHUB_NINJA_VERSION}/ninja-${NINJA_PLATFORM}.zip
|
||||
mkdir -p $NINJA_DL_DIR
|
||||
unzip -q /tmp/ninja-dl.zip -d $NINJA_DL_DIR
|
||||
chmod +x ${NINJA_DL_DIR}/ninja
|
||||
# Install ninja globally for AGP
|
||||
sudo cp ${NINJA_DL_DIR}/ninja /usr/local/bin/
|
||||
fi
|
||||
6
build/common/versions
Normal file
@@ -0,0 +1,6 @@
|
||||
GITHUB_CLANG_VERSION=14
|
||||
GITHUB_CMAKE_VERSION=3.19.5
|
||||
GITHUB_NINJA_VERSION=1.10.2
|
||||
GITHUB_MESA_VERSION=24.2.1
|
||||
GITHUB_LLVM_VERSION=16
|
||||
GITHUB_NDK_VERSION=27.0.11718014
|
||||
@@ -28,7 +28,6 @@ set -e
|
||||
set -x
|
||||
|
||||
source `dirname $0`/../common/ci-common.sh
|
||||
source `dirname $0`/ci-common.sh
|
||||
source `dirname $0`/../common/build-common.sh
|
||||
|
||||
pushd `dirname $0`/../.. > /dev/null
|
||||
@@ -41,4 +40,3 @@ if [[ "${GENERATE_ARCHIVES}" ]]; then
|
||||
fi
|
||||
|
||||
./build.sh -i -p ios -c $BUILD_SIMULATOR $GENERATE_ARCHIVES $BUILD_DEBUG $BUILD_RELEASE
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
curl -OL https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-mac.zip
|
||||
unzip -q ninja-mac.zip
|
||||
chmod +x ninja
|
||||
export PATH="$PWD:$PATH"
|
||||
@@ -32,7 +32,6 @@ set -x
|
||||
# $BUILD_DEBUG
|
||||
# $BUILD_RELEASE
|
||||
source `dirname $0`/../common/ci-common.sh
|
||||
source `dirname $0`/ci-common.sh
|
||||
source `dirname $0`/../common/build-common.sh
|
||||
|
||||
pushd `dirname $0`/../.. > /dev/null
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# version of clang we want to use
|
||||
export GITHUB_CLANG_VERSION=14
|
||||
# version of CMake to use instead of the default one
|
||||
export GITHUB_CMAKE_VERSION=3.19.5
|
||||
# version of ninja to use
|
||||
export GITHUB_NINJA_VERSION=1.10.2
|
||||
|
||||
# Steps for GitHub Workflows
|
||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||
# Install ninja
|
||||
wget -q https://github.com/ninja-build/ninja/releases/download/v$GITHUB_NINJA_VERSION/ninja-linux.zip
|
||||
unzip -q ninja-linux.zip
|
||||
export PATH="$PWD:$PATH"
|
||||
|
||||
# Install CMake
|
||||
mkdir -p cmake
|
||||
cd cmake
|
||||
|
||||
sudo wget https://github.com/Kitware/CMake/releases/download/v$GITHUB_CMAKE_VERSION/cmake-$GITHUB_CMAKE_VERSION-Linux-x86_64.sh
|
||||
sudo chmod +x ./cmake-$GITHUB_CMAKE_VERSION-Linux-x86_64.sh
|
||||
sudo ./cmake-$GITHUB_CMAKE_VERSION-Linux-x86_64.sh --skip-license > /dev/null
|
||||
sudo update-alternatives --install /usr/bin/cmake cmake $(pwd)/bin/cmake 1000 --force
|
||||
|
||||
cd ..
|
||||
|
||||
sudo wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo apt-get update
|
||||
sudo apt-get install clang-$GITHUB_CLANG_VERSION libc++-$GITHUB_CLANG_VERSION-dev libc++abi-$GITHUB_CLANG_VERSION-dev
|
||||
sudo apt-get install mesa-common-dev libxi-dev libxxf86vm-dev
|
||||
|
||||
# For dawn
|
||||
sudo apt-get install libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libx11-xcb-dev
|
||||
|
||||
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${GITHUB_CLANG_VERSION} 100
|
||||
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${GITHUB_CLANG_VERSION} 100
|
||||
fi
|
||||
@@ -28,7 +28,6 @@ set -e
|
||||
set -x
|
||||
|
||||
source `dirname $0`/../common/ci-common.sh
|
||||
source `dirname $0`/ci-common.sh
|
||||
source `dirname $0`/../common/build-common.sh
|
||||
|
||||
pushd `dirname $0`/../.. > /dev/null
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
curl -OL https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-mac.zip
|
||||
unzip -q ninja-mac.zip
|
||||
chmod +x ninja
|
||||
# Install ninja globally for AGP
|
||||
cp ninja /usr/local/bin
|
||||
export PATH="$PWD:$PATH"
|
||||
@@ -31,10 +31,16 @@ set(DIST_ARCH arm64-v8a)
|
||||
string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} HOST_NAME_L)
|
||||
file(TO_CMAKE_PATH $ENV{ANDROID_HOME} ANDROID_HOME_UNIX)
|
||||
|
||||
message(STATUS "Try using NDK \'${FILAMENT_NDK_VERSION}\'")
|
||||
if (NOT FILAMENT_NDK_VERSION)
|
||||
file(READ "${CMAKE_CURRENT_LIST_DIR}/android/ndk.version" FILAMENT_NDK_VERSION)
|
||||
string(REGEX MATCH "^\\d+" FILAMENT_NDK_VERSION ${FILAMENT_NDK_VERSION})
|
||||
file(READ "${CMAKE_CURRENT_LIST_DIR}/common/versions" VERSIONS_STR)
|
||||
string(REGEX MATCH "GITHUB_NDK_VERSION=(\\d+)" _UNUSED ${VERSIONS_STR})
|
||||
if(CMAKE_MATCH_1)
|
||||
set(FILAMENT_NDK_VERSION "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "Using NDK \'${FILAMENT_NDK_VERSION}\'")
|
||||
|
||||
file(GLOB NDK_VERSIONS LIST_DIRECTORIES true ${ANDROID_HOME_UNIX}/ndk/${FILAMENT_NDK_VERSION}*)
|
||||
list(SORT NDK_VERSIONS)
|
||||
list(GET NDK_VERSIONS -1 NDK_VERSION)
|
||||
|
||||
@@ -32,10 +32,16 @@ set(DIST_ARCH armeabi-v7a)
|
||||
string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} HOST_NAME_L)
|
||||
file(TO_CMAKE_PATH $ENV{ANDROID_HOME} ANDROID_HOME_UNIX)
|
||||
|
||||
message(STATUS "Try using NDK \'${FILAMENT_NDK_VERSION}\'")
|
||||
if (NOT FILAMENT_NDK_VERSION)
|
||||
file(READ "${CMAKE_CURRENT_LIST_DIR}/android/ndk.version" FILAMENT_NDK_VERSION)
|
||||
string(REGEX MATCH "^\\d+" FILAMENT_NDK_VERSION ${FILAMENT_NDK_VERSION})
|
||||
file(READ "${CMAKE_CURRENT_LIST_DIR}/common/versions" VERSIONS_STR)
|
||||
string(REGEX MATCH "GITHUB_NDK_VERSION=(\\d+)" _UNUSED ${VERSIONS_STR})
|
||||
if(CMAKE_MATCH_1)
|
||||
set(FILAMENT_NDK_VERSION "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "Using NDK \'${FILAMENT_NDK_VERSION}\'")
|
||||
|
||||
file(GLOB NDK_VERSIONS LIST_DIRECTORIES true ${ANDROID_HOME_UNIX}/ndk/${FILAMENT_NDK_VERSION}*)
|
||||
list(SORT NDK_VERSIONS)
|
||||
list(GET NDK_VERSIONS -1 NDK_VERSION)
|
||||
|
||||
@@ -31,10 +31,16 @@ set(DIST_ARCH x86)
|
||||
string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} HOST_NAME_L)
|
||||
file(TO_CMAKE_PATH $ENV{ANDROID_HOME} ANDROID_HOME_UNIX)
|
||||
|
||||
message(STATUS "Try using NDK \'${FILAMENT_NDK_VERSION}\'")
|
||||
if (NOT FILAMENT_NDK_VERSION)
|
||||
file(READ "${CMAKE_CURRENT_LIST_DIR}/android/ndk.version" FILAMENT_NDK_VERSION)
|
||||
string(REGEX MATCH "^\\d+" FILAMENT_NDK_VERSION ${FILAMENT_NDK_VERSION})
|
||||
file(READ "${CMAKE_CURRENT_LIST_DIR}/common/versions" VERSIONS_STR)
|
||||
string(REGEX MATCH "GITHUB_NDK_VERSION=(\\d+)" _UNUSED ${VERSIONS_STR})
|
||||
if(CMAKE_MATCH_1)
|
||||
set(FILAMENT_NDK_VERSION "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "Using NDK \'${FILAMENT_NDK_VERSION}\'")
|
||||
|
||||
file(GLOB NDK_VERSIONS LIST_DIRECTORIES true ${ANDROID_HOME_UNIX}/ndk/${FILAMENT_NDK_VERSION}*)
|
||||
list(SORT NDK_VERSIONS)
|
||||
list(GET NDK_VERSIONS -1 NDK_VERSION)
|
||||
|
||||
@@ -31,10 +31,16 @@ set(DIST_ARCH x86_64)
|
||||
string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} HOST_NAME_L)
|
||||
file(TO_CMAKE_PATH $ENV{ANDROID_HOME} ANDROID_HOME_UNIX)
|
||||
|
||||
message(STATUS "Try using NDK \'${FILAMENT_NDK_VERSION}\'")
|
||||
if (NOT FILAMENT_NDK_VERSION)
|
||||
file(READ "${CMAKE_CURRENT_LIST_DIR}/android/ndk.version" FILAMENT_NDK_VERSION)
|
||||
string(REGEX MATCH "^\\d+" FILAMENT_NDK_VERSION ${FILAMENT_NDK_VERSION})
|
||||
file(READ "${CMAKE_CURRENT_LIST_DIR}/common/versions" VERSIONS_STR)
|
||||
string(REGEX MATCH "GITHUB_NDK_VERSION=(\\d+)" _UNUSED ${VERSIONS_STR})
|
||||
if(CMAKE_MATCH_1)
|
||||
set(FILAMENT_NDK_VERSION "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "Using NDK \'${FILAMENT_NDK_VERSION}\'")
|
||||
|
||||
file(GLOB NDK_VERSIONS LIST_DIRECTORIES true ${ANDROID_HOME_UNIX}/ndk/${FILAMENT_NDK_VERSION}*)
|
||||
list(SORT NDK_VERSIONS)
|
||||
list(GET NDK_VERSIONS -1 NDK_VERSION)
|
||||
|
||||
@@ -1,16 +1,4 @@
|
||||
#!/bin/bash
|
||||
if [ `uname` == "Linux" ];then
|
||||
source `dirname $0`/../linux/ci-common.sh
|
||||
elif [ `uname` == "Darwin" ];then
|
||||
curl -OL https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-mac.zip
|
||||
unzip -q ninja-mac.zip
|
||||
else
|
||||
echo "Unsupported OS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
chmod +x ninja
|
||||
export PATH="$PWD:$PATH"
|
||||
|
||||
# Install emscripten.
|
||||
curl -L https://github.com/emscripten-core/emsdk/archive/refs/tags/3.1.60.zip > emsdk.zip
|
||||
|
||||
@@ -166,7 +166,7 @@ This document is part of the <a href="https://github.com/google/filament">Filame
|
||||
</p><ul>
|
||||
<li class="minus"><a href="https://github.com/romainguy">Romain Guy</a>, <a href="https://twitter.com/romainguy">@romainguy</a>
|
||||
</li>
|
||||
<li class="minus"><a href="https://github.com/pixelflinger">Mathias Agopian</a>, <a href="https://twitter.com/darthmoosious">@darthmoosious</a></li></ul>
|
||||
<li class="minus"><a href="https://github.com/pixelflinger">Mathias Agopian</a>, <a href="https://bsky.app/profile/pixelflinger.bsky.social">@pixelflinger</a></li></ul>
|
||||
|
||||
<p></p>
|
||||
<a class="target" name="overview"> </a><a class="target" name="overview"> </a><a class="target" name="toc2"> </a><h1>Overview</h1>
|
||||
@@ -259,26 +259,27 @@ in <a href="#table_standardproperties">table 1</a>.
|
||||
</p><div class="table">
|
||||
<table class="table"><tbody><tr><th style="text-align:right"> Property </th><th style="text-align:left"> Definition </th></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">baseColor</strong> </td><td style="text-align:left"> Diffuse albedo for non-metallic surfaces, and specular color for metallic surfaces </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">metallic</strong> </td><td style="text-align:left"> Whether a surface appears to be dielectric (0.0) or conductor (1.0). Often used as a binary value (0 or 1) </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">roughness</strong> </td><td style="text-align:left"> Perceived smoothness (1.0) or roughness (0.0) of a surface. Smooth surfaces exhibit sharp reflections </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">metallic</strong> </td><td style="text-align:left"> Whether a surface appears to be dielectric (0.0) or conductor (1.0). Often used as a binary value (0 or 1) </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">reflectance</strong> </td><td style="text-align:left"> Fresnel reflectance at normal incidence for dielectric surfaces. This directly controls the strength of the reflections </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">sheenColor</strong> </td><td style="text-align:left"> Strength of the sheen layer </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">sheenRoughness</strong> </td><td style="text-align:left"> Perceived smoothness or roughness of the sheen layer </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">ambientOcclusion</strong> </td><td style="text-align:left"> Defines how much of the ambient light is accessible to a surface point. It is a per-pixel shadowing factor between 0.0 and 1.0 </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">clearCoat</strong> </td><td style="text-align:left"> Strength of the clear coat layer </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">clearCoatRoughness</strong> </td><td style="text-align:left"> Perceived smoothness or roughness of the clear coat layer </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">clearCoatNormal</strong> </td><td style="text-align:left"> A detail normal used to perturb the clear coat layer using <em class="underscore">bump mapping</em> (<em class="underscore">normal mapping</em>) </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">anisotropy</strong> </td><td style="text-align:left"> Amount of anisotropy in either the tangent or bitangent direction </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">anisotropyDirection</strong> </td><td style="text-align:left"> Local surface direction in tangent space </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">ambientOcclusion</strong> </td><td style="text-align:left"> Defines how much of the ambient light is accessible to a surface point. It is a per-pixel shadowing factor between 0.0 and 1.0 </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">normal</strong> </td><td style="text-align:left"> A detail normal used to perturb the surface using <em class="underscore">bump mapping</em> (<em class="underscore">normal mapping</em>) </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">bentNormal</strong> </td><td style="text-align:left"> A normal pointing in the average unoccluded direction. Can be used to improve indirect lighting quality </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">clearCoatNormal</strong> </td><td style="text-align:left"> A detail normal used to perturb the clear coat layer using <em class="underscore">bump mapping</em> (<em class="underscore">normal mapping</em>) </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">emissive</strong> </td><td style="text-align:left"> Additional diffuse albedo to simulate emissive surfaces (such as neons, etc.) This property is mostly useful in an HDR pipeline with a bloom pass </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">postLightingColor</strong> </td><td style="text-align:left"> Additional color that can be blended with the result of the lighting computations. See <code>postLightingBlending</code> </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">ior</strong> </td><td style="text-align:left"> Index of refraction, either for refractive objects or as an alternative to reflectance </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">transmission</strong> </td><td style="text-align:left"> Defines how much of the diffuse light of a dielectric is transmitted through the object, in other words this defines how transparent an object is </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">absorption</strong> </td><td style="text-align:left"> Absorption factor for refractive objects </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">microThickness</strong> </td><td style="text-align:left"> Thickness of the thin layer of refractive objects </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">thickness</strong> </td><td style="text-align:left"> Thickness of the solid volume of refractive objects </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">sheenColor</strong> </td><td style="text-align:left"> Strength of the sheen layer </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">sheenRoughness</strong> </td><td style="text-align:left"> Perceived smoothness or roughness of the sheen layer </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">emissive</strong> </td><td style="text-align:left"> Additional diffuse albedo to simulate emissive surfaces (such as neons, etc.) This property is mostly useful in an HDR pipeline with a bloom pass </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">normal</strong> </td><td style="text-align:left"> A detail normal used to perturb the surface using <em class="underscore">bump mapping</em> (<em class="underscore">normal mapping</em>) </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">postLightingColor</strong> </td><td style="text-align:left"> Additional color that can be blended with the result of the lighting computations. See <code>postLightingBlending</code> </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">absorption</strong> </td><td style="text-align:left"> Absorption factor for refractive objects </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">transmission</strong> </td><td style="text-align:left"> Defines how much of the diffuse light of a dielectric is transmitted through the object, in other words this defines how transparent an object is </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">ior</strong> </td><td style="text-align:left"> Index of refraction, either for refractive objects or as an alternative to reflectance </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">microThickness</strong> </td><td style="text-align:left"> Thickness of the thin layer of refractive objects </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">bentNormal</strong> </td><td style="text-align:left"> A normal pointing in the average unoccluded direction. Can be used to improve indirect lighting quality </td></tr>
|
||||
<tr><td style="text-align:right"> <strong class="asterisk">shadowStrength</strong> </td><td style="text-align:left"> Strength factor between 0 and 1 for all shadows received by this material </td></tr>
|
||||
</tbody></table><center><div class="tablecaption"><a class="target" name="table_standardproperties"> </a><b style="font-style:normal;">Table 1:</b> Properties of the standard model</div></center></div>
|
||||
|
||||
<p></p><p>
|
||||
@@ -1486,10 +1487,13 @@ non-shader data.
|
||||
</p><dl><dt>Type</dt><dd><p> array of parameter objects
|
||||
|
||||
</p></dd><dt>Value</dt><dd><p> Each entry is an object with the properties <code>name</code> and <code>type</code>, both of <code>string</code> type. The
|
||||
name must be a valid GLSL identifier. Entries also have an optional <code>precision</code>, which can be
|
||||
name must be a valid GLSL identifier. Entries have an optional <code>precision</code>, which can be
|
||||
one of <code>default</code> (best precision for the platform, typically <code>high</code> on desktop, <code>medium</code> on
|
||||
mobile), <code>low</code>, <code>medium</code>, <code>high</code>. The type must be one of the types described in
|
||||
<a href="#table_materialparamstypes">table 14</a>.
|
||||
<a href="#table_materialparamstypes">table 14</a>. For Android external textures, entries also have an optional
|
||||
transformName parameter to specify the name of the material parameter that will be
|
||||
used to expose the transform matrix associated with the external sampler. In iOS and Vulkan,
|
||||
this will always be identity.
|
||||
|
||||
</p></dd></dl><div class="table">
|
||||
<table class="table"><tbody><tr><th style="text-align:left"> Type </th><th style="text-align:left"> Description </th></tr>
|
||||
@@ -1752,7 +1756,13 @@ non-shader data.
|
||||
when selecting any shading model that is not <code>unlit</code>. See the shader sections of this document
|
||||
for more information on how to access these attributes from the shaders.
|
||||
|
||||
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
</p></dd></dl><div class="admonition note"><div class="admonition-title"> Interaction with custom variables</div>
|
||||
|
||||
<p></p><p>
|
||||
|
||||
When the <code>color</code> attribute is specified, only four custom variables are available instead of five.</p></div>
|
||||
|
||||
<p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> parameters : [</span>
|
||||
<span class="line"> {</span>
|
||||
<span class="line"> type : sampler2d,</span>
|
||||
@@ -1779,7 +1789,7 @@ non-shader data.
|
||||
|
||||
</p><dl><dt>Type</dt><dd><p> array of <code>string</code>
|
||||
|
||||
</p></dd><dt>Value</dt><dd><p> Up to 4 strings, each must be a valid GLSL identifier.
|
||||
</p></dd><dt>Value</dt><dd><p> Up to 5 strings, each must be a valid GLSL identifier.
|
||||
|
||||
</p></dd><dt>Description</dt><dd><p> Defines custom interpolants (or variables) that are output by the material's vertex shader.
|
||||
Each entry of the array defines the name of an interpolant. The full name in the fragment
|
||||
@@ -1794,7 +1804,14 @@ non-shader data.
|
||||
particular if <code>default</code> is specified the default precision is used is the fragment shader
|
||||
(<code>mediump</code>) and in the vertex shader (<code>highp</code>).
|
||||
|
||||
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
</p></dd></dl><div class="admonition warning"><div class="admonition-title"> Interaction with required attributes</div>
|
||||
|
||||
<p></p><p>
|
||||
|
||||
If the <code>color</code> attribute is specified in the <code>required</code> list, then only four variables can be used
|
||||
instead of five.</p></div>
|
||||
|
||||
<p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> name : Skybox,</span>
|
||||
<span class="line"> parameters : [</span>
|
||||
<span class="line"> {</span>
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="#EntityManager">EntityManager</a></td>
|
||||
<td align="left">Singleton used for constructing entities in Filament's ECS.</td>
|
||||
<td align="left">Singleton used for constructing entities in Filament's ECS.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="#Frustum">Frustum</a></td>
|
||||
@@ -89,7 +89,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="#Renderer">Renderer</a></td>
|
||||
<td align="left">Represents the platform's native window.</td>
|
||||
<td align="left">Represents the platform's native window.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="#Scene">Scene</a></td>
|
||||
@@ -97,7 +97,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="#SwapChain">SwapChain</a></td>
|
||||
<td align="left">Represents the platform's native rendering surface.</td>
|
||||
<td align="left">Represents the platform's native rendering surface.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left"><a href="#Texture">Texture</a></td>
|
||||
@@ -604,11 +604,11 @@
|
||||
</ul>
|
||||
<p>To create an entity with no components, use <a href="#EntityManager">EntityManager</a>.
|
||||
TODO: It would be better to expose these as JS numbers rather than as JS objects.
|
||||
This would also be more consistent with Filament's Java bindings.</p>
|
||||
This would also be more consistent with Filament's Java bindings.</p>
|
||||
</div>
|
||||
<div class='classdoc'>
|
||||
<h2>class <a id='EntityManager' href='#EntityManager'>EntityManager</a></h2>
|
||||
<p>Singleton used for constructing entities in Filament's ECS.</p>
|
||||
<p>Singleton used for constructing entities in Filament's ECS.</p>
|
||||
<ul>
|
||||
<li><strong>entityManager.create()</strong>
|
||||
<ul>
|
||||
@@ -742,7 +742,7 @@ properties.</p>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Be sure to call the instance's <code>delete</code> method when you're done with it.</p>
|
||||
<p>Be sure to call the instance's <code>delete</code> method when you're done with it.</p>
|
||||
</div>
|
||||
<div class='classdoc'>
|
||||
<h2>class <a id='PixelBufferDescriptor' href='#PixelBufferDescriptor'>PixelBufferDescriptor</a></h2>
|
||||
@@ -780,11 +780,11 @@ properties.</p>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Be sure to call the instance's <code>delete</code> method when you're done with it.</p>
|
||||
<p>Be sure to call the instance's <code>delete</code> method when you're done with it.</p>
|
||||
</div>
|
||||
<div class='classdoc'>
|
||||
<h2>class <a id='Renderer' href='#Renderer'>Renderer</a></h2>
|
||||
<p>Represents the platform's native window.</p>
|
||||
<p>Represents the platform's native window.</p>
|
||||
<ul>
|
||||
<li><strong>renderer.render(swapChain, view)</strong>
|
||||
<ul>
|
||||
@@ -803,7 +803,7 @@ properties.</p>
|
||||
</div>
|
||||
<div class='classdoc'>
|
||||
<h2>class <a id='SwapChain' href='#SwapChain'>SwapChain</a></h2>
|
||||
<p>Represents the platform's native rendering surface.</p>
|
||||
<p>Represents the platform's native rendering surface.</p>
|
||||
<p>See also the <a href="#Engine">Engine</a> methods <code>createSwapChain</code> and <code>destroySwapChain</code>.</p>
|
||||
</div>
|
||||
<div class='classdoc'>
|
||||
@@ -847,7 +847,7 @@ properties.</p>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Be sure to call the instance's <code>delete</code> method when you're done with it.</p>
|
||||
<p>Be sure to call the instance's <code>delete</code> method when you're done with it.</p>
|
||||
</div>
|
||||
<div class='classdoc'>
|
||||
<h2>class <a id='VertexBuffer' href='#VertexBuffer'>VertexBuffer</a></h2>
|
||||
@@ -944,7 +944,7 @@ See also the <a href="#Engine">Engine</a> methods <code>createView</code> and <c
|
||||
<ul>
|
||||
<li><strong>assets</strong>
|
||||
<ul>
|
||||
<li>Array of strings containing URL's of required assets.</li>
|
||||
<li>Array of strings containing URL's of required assets.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>onDone</strong>
|
||||
@@ -954,7 +954,7 @@ See also the <a href="#Engine">Engine</a> methods <code>createView</code> and <c
|
||||
</li>
|
||||
<li><strong>onFetched</strong>
|
||||
<ul>
|
||||
<li>optional callback that's invoked after each asset is downloaded.</li>
|
||||
<li>optional callback that's invoked after each asset is downloaded.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -1001,7 +1001,7 @@ useful for compressed textures. For example, some platforms accept ETC and other
|
||||
<ul>
|
||||
<li><strong>assets</strong>
|
||||
<ul>
|
||||
<li>Array of strings containing URL's of required assets.</li>
|
||||
<li>Array of strings containing URL's of required assets.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>onready</strong>
|
||||
@@ -1010,12 +1010,12 @@ useful for compressed textures. For example, some platforms accept ETC and other
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>All JavaScript clients must call the init function, passing in a list of asset URL's and a
|
||||
<p>All JavaScript clients must call the init function, passing in a list of asset URL's and a
|
||||
callback. This callback gets invoked only after all assets have been downloaded and the Filament
|
||||
WebAssembly module has been loaded. Clients should only pass asset URL's that absolutely must
|
||||
WebAssembly module has been loaded. Clients should only pass asset URL's that absolutely must
|
||||
be ready at initialization time.
|
||||
When the callback is called, each downloaded asset is available in the <code>Filament.assets</code> global
|
||||
object, which contains a mapping from URL's to Uint8Array objects.</p>
|
||||
object, which contains a mapping from URL's to Uint8Array objects.</p>
|
||||
</div>
|
||||
<div class='funcdoc'>
|
||||
<h2>function <a id='loadMathExtensions' href='#loadMathExtensions'>loadMathExtensions</a>()</h2>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
textures.</p>
|
||||
<p>For starters, create a text file called <code>redball.html</code> and copy over the HTML that we used in the
|
||||
<a href="tutorial_triangle.html">previous tutorial</a>. Change the last script tag from <code>triangle.js</code> to <code>redball.js</code>.</p>
|
||||
<p>Next you'll need to get a couple command-line tools: <code>matc</code> and <code>cmgen</code>. You can find these in the
|
||||
<p>Next you'll need to get a couple command-line tools: <code>matc</code> and <code>cmgen</code>. You can find these in the
|
||||
appropriate <a href="//github.com/google/filament/releases">Filament release</a>. You should choose the
|
||||
archive that corresponds to your development machine rather than the one for web, and the version
|
||||
that matches the <code>unpkg.com/filament@x.x.x</code> url in the script tag of <code>redball.html</code> (you may check
|
||||
@@ -19,7 +19,7 @@ out the last available release of <a href="https://www.npmjs.com/package/filamen
|
||||
<p>The <code>matc</code> tool consumes a text file containing a high-level description of a PBR material, and
|
||||
produces a binary material package that contains shader code and associated metadata. For more
|
||||
information, see the official document describing the <a href="https://google.github.io/filament/Materials.md.html">Filament Material System</a>.</p>
|
||||
<p>Let's try out <code>matc</code>. Create the following file in your favorite text editor and call it
|
||||
<p>Let's try out <code>matc</code>. Create the following file in your favorite text editor and call it
|
||||
<code>plastic.mat</code>.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>material {
|
||||
name : Lit,
|
||||
@@ -44,16 +44,16 @@ fragment {
|
||||
</pre></div>
|
||||
|
||||
<p>Next, invoke <code>matc</code> as follows.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>matc -a opengl -p mobile -o plastic.filamat plastic.mat
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>matc<span style="color: #BBB"> </span>-a<span style="color: #BBB"> </span>opengl<span style="color: #BBB"> </span>-p<span style="color: #BBB"> </span>mobile<span style="color: #BBB"> </span>-o<span style="color: #BBB"> </span>plastic.filamat<span style="color: #BBB"> </span>plastic.mat
|
||||
</pre></div>
|
||||
|
||||
<p>You should now have a material archive in your working directory, which we'll use later in the
|
||||
<p>You should now have a material archive in your working directory, which we'll use later in the
|
||||
tutorial.</p>
|
||||
<h2>Bake environment map</h2>
|
||||
<p>Next we'll use Filament's <code>cmgen</code> tool to consume a HDR environment map in latlong format, and
|
||||
<p>Next we'll use Filament's <code>cmgen</code> tool to consume a HDR environment map in latlong format, and
|
||||
produce two cubemap files: a mipmapped IBL and a blurry skybox.</p>
|
||||
<p>Download <a href="//github.com/google/filament/blob/main/third_party/environments/pillars_2k.hdr">pillars_2k.hdr</a>, then invoke the following command in your terminal.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>cmgen -x pillars_2k --format<span style="color: #666666">=</span>ktx --size<span style="color: #666666">=256</span> --extract-blur<span style="color: #666666">=0</span>.1 pillars_2k.hdr
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>cmgen<span style="color: #BBB"> </span>-x<span style="color: #BBB"> </span>pillars_2k<span style="color: #BBB"> </span>--format<span style="color: #666">=</span>ktx<span style="color: #BBB"> </span>--size<span style="color: #666">=256</span><span style="color: #BBB"> </span>--extract-blur<span style="color: #666">=0</span>.1<span style="color: #BBB"> </span>pillars_2k.hdr
|
||||
</pre></div>
|
||||
|
||||
<p>You should now have a <code>pillars_2k</code> folder containing a couple KTX files for the IBL and skybox, as
|
||||
@@ -61,84 +61,84 @@ well as a text file with spherical harmonics coefficients. You can discard the t
|
||||
IBL KTX contains these coefficients in its metadata.</p>
|
||||
<h2>Create JavaScript</h2>
|
||||
<p>Next, create <code>redball.js</code> with the following content.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>environ<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">'pillars_2k'</span>;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ibl_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_ibl.ktx`</span>;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sky_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox.ktx`</span>;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>filamat_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">'plastic.filamat'</span><span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>environ<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">'pillars_2k'</span>;
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ibl_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_ibl.ktx`</span>;
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>sky_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox.ktx`</span>;
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>filamat_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">'plastic.filamat'</span>
|
||||
|
||||
Filament.init([<span style="color: #bbbbbb"> </span>filamat_url,<span style="color: #bbbbbb"> </span>ibl_url,<span style="color: #bbbbbb"> </span>sky_url<span style="color: #bbbbbb"> </span>],<span style="color: #bbbbbb"> </span>()<span style="color: #bbbbbb"> </span>=><span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// Create some global aliases to enums for convenience.</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.VertexAttribute<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.VertexAttribute;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.AttributeType<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.VertexBuffer$AttributeType;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.PrimitiveType<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.RenderableManager$PrimitiveType;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.IndexType<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.IndexBuffer$IndexType;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.Fov<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Camera$Fov;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.LightType<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.LightManager$Type;<span style="color: #bbbbbb"></span>
|
||||
Filament.init([<span style="color: #BBB"> </span>filamat_url,<span style="color: #BBB"> </span>ibl_url,<span style="color: #BBB"> </span>sky_url<span style="color: #BBB"> </span>],<span style="color: #BBB"> </span>()<span style="color: #BBB"> </span>=><span style="color: #BBB"> </span>{
|
||||
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// Create some global aliases to enums for convenience.</span>
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.VertexAttribute<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.VertexAttribute;
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.AttributeType<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.VertexBuffer$AttributeType;
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.PrimitiveType<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.RenderableManager$PrimitiveType;
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.IndexType<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.IndexBuffer$IndexType;
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.Fov<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Camera$Fov;
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.LightType<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.LightManager$Type;
|
||||
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// Obtain the canvas DOM object and pass it to the App.</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>canvas<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">'canvas'</span>)[<span style="color: #666666">0</span>];<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.app<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>App(canvas);<span style="color: #bbbbbb"></span>
|
||||
}<span style="color: #bbbbbb"> </span>);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// Obtain the canvas DOM object and pass it to the App.</span>
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>canvas<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">'canvas'</span>)[<span style="color: #666">0</span>];
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.app<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>App(canvas);
|
||||
}<span style="color: #BBB"> </span>);
|
||||
|
||||
<span style="color: #008000; font-weight: bold">class</span><span style="color: #bbbbbb"> </span>App<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">constructor</span>(canvas)<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>canvas;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>engine<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Engine.create(canvas);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>scene<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createScene();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">class</span><span style="color: #BBB"> </span>App<span style="color: #BBB"> </span>{
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">constructor</span>(canvas)<span style="color: #BBB"> </span>{
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>canvas;
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>engine<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Engine.create(canvas);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>scene<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createScene();
|
||||
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create material</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create sphere</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create lights</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create IBL</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create skybox</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create material</span>
|
||||
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create sphere</span>
|
||||
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create lights</span>
|
||||
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create IBL</span>
|
||||
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create skybox</span>
|
||||
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.swapChain<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createSwapChain();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createRenderer();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.camera<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createCamera(Filament.EntityManager.get().create());<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createView();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setScene(scene);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.render<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">'resize'</span>,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.swapChain<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createSwapChain();
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createRenderer();
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.camera<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createCamera(Filament.EntityManager.get().create());
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createView();
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setScene(scene);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize();
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.render<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">'resize'</span>,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||
<span style="color: #BBB"> </span>}
|
||||
|
||||
<span style="color: #bbbbbb"> </span>render()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>eye<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">4</span>],<span style="color: #bbbbbb"> </span>center<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>],<span style="color: #bbbbbb"> </span>up<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>];<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>radians<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">Date</span>.now()<span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">10000</span>;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>vec3.rotateY(eye,<span style="color: #bbbbbb"> </span>eye,<span style="color: #bbbbbb"> </span>center,<span style="color: #bbbbbb"> </span>radians);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.lookAt(eye,<span style="color: #bbbbbb"> </span>center,<span style="color: #bbbbbb"> </span>up);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #BBB"> </span>render()<span style="color: #BBB"> </span>{
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>eye<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">4</span>],<span style="color: #BBB"> </span>center<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>],<span style="color: #BBB"> </span>up<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>];
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>radians<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">Date</span>.now()<span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">10000</span>;
|
||||
<span style="color: #BBB"> </span>vec3.rotateY(eye,<span style="color: #BBB"> </span>eye,<span style="color: #BBB"> </span>center,<span style="color: #BBB"> </span>radians);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.lookAt(eye,<span style="color: #BBB"> </span>center,<span style="color: #BBB"> </span>up);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||
<span style="color: #BBB"> </span>}
|
||||
|
||||
<span style="color: #bbbbbb"> </span>resize()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>dpr<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.devicePixelRatio;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>width<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.width<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.innerWidth<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span>dpr;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>height<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.height<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.innerHeight<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span>dpr;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>width,<span style="color: #bbbbbb"> </span>height]);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.setProjectionFov(<span style="color: #666666">45</span>,<span style="color: #bbbbbb"> </span>width<span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span>height,<span style="color: #bbbbbb"> </span><span style="color: #666666">1.0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">10.0</span>,<span style="color: #bbbbbb"> </span>Fov.VERTICAL);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
||||
}<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #BBB"> </span>resize()<span style="color: #BBB"> </span>{
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>dpr<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.devicePixelRatio;
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>width<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.width<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.innerWidth<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span>dpr;
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>height<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.height<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.innerHeight<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span>dpr;
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>width,<span style="color: #BBB"> </span>height]);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.setProjectionFov(<span style="color: #666">45</span>,<span style="color: #BBB"> </span>width<span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span>height,<span style="color: #BBB"> </span><span style="color: #666">1.0</span>,<span style="color: #BBB"> </span><span style="color: #666">10.0</span>,<span style="color: #BBB"> </span>Fov.VERTICAL);
|
||||
<span style="color: #BBB"> </span>}
|
||||
}
|
||||
</pre></div>
|
||||
|
||||
<p>The above boilerplate should be familiar to you from the previous tutorial, although it loads in a
|
||||
new set of assets. We also added some animation to the camera.</p>
|
||||
<p>Next let's create a material instance from the package that we built at the beginning the tutorial.
|
||||
<p>Next let's create a material instance from the package that we built at the beginning the tutorial.
|
||||
Replace the <strong>create material</strong> comment with the following snippet.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>material<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createMaterial(filamat_url);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>matinstance<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>material.createInstance();<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>material<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createMaterial(filamat_url);
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>matinstance<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>material.createInstance();
|
||||
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>red<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0.8</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.0</span>];<span style="color: #bbbbbb"></span>
|
||||
matinstance.setColor3Parameter(<span style="color: #BA2121">'baseColor'</span>,<span style="color: #bbbbbb"> </span>Filament.RgbType.sRGB,<span style="color: #bbbbbb"> </span>red);<span style="color: #bbbbbb"></span>
|
||||
matinstance.setFloatParameter(<span style="color: #BA2121">'roughness'</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.5</span>);<span style="color: #bbbbbb"></span>
|
||||
matinstance.setFloatParameter(<span style="color: #BA2121">'clearCoat'</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1.0</span>);<span style="color: #bbbbbb"></span>
|
||||
matinstance.setFloatParameter(<span style="color: #BA2121">'clearCoatRoughness'</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.3</span>);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>red<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0.8</span>,<span style="color: #BBB"> </span><span style="color: #666">0.0</span>,<span style="color: #BBB"> </span><span style="color: #666">0.0</span>];
|
||||
matinstance.setColor3Parameter(<span style="color: #BA2121">'baseColor'</span>,<span style="color: #BBB"> </span>Filament.RgbType.sRGB,<span style="color: #BBB"> </span>red);
|
||||
matinstance.setFloatParameter(<span style="color: #BA2121">'roughness'</span>,<span style="color: #BBB"> </span><span style="color: #666">0.5</span>);
|
||||
matinstance.setFloatParameter(<span style="color: #BA2121">'clearCoat'</span>,<span style="color: #BBB"> </span><span style="color: #666">1.0</span>);
|
||||
matinstance.setFloatParameter(<span style="color: #BA2121">'clearCoatRoughness'</span>,<span style="color: #BBB"> </span><span style="color: #666">0.3</span>);
|
||||
</pre></div>
|
||||
|
||||
<p>The next step is to create a renderable for the sphere. To help with this, we'll use the <code>IcoSphere</code>
|
||||
<p>The next step is to create a renderable for the sphere. To help with this, we'll use the <code>IcoSphere</code>
|
||||
utility class, whose constructor takes a LOD. Its job is to subdivide an icosadedron, producing
|
||||
three arrays:</p>
|
||||
<ul>
|
||||
@@ -147,137 +147,137 @@ three arrays:</p>
|
||||
as quaternions.</li>
|
||||
<li><code>icosphere.triangles</code> Uint16Array with triangle indices.</li>
|
||||
</ul>
|
||||
<p>Let's go ahead use these arrays to build the vertex buffer and index buffer. Replace <strong>create
|
||||
<p>Let's go ahead use these arrays to build the vertex buffer and index buffer. Replace <strong>create
|
||||
sphere</strong> with the following snippet.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>renderable<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.EntityManager.get().create();<span style="color: #bbbbbb"></span>
|
||||
scene.addEntity(renderable);<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>renderable<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.EntityManager.get().create();
|
||||
scene.addEntity(renderable);
|
||||
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>icosphere<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>Filament.IcoSphere(<span style="color: #666666">5</span>);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>icosphere<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>Filament.IcoSphere(<span style="color: #666">5</span>);
|
||||
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>vb<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.VertexBuffer.Builder()<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.vertexCount(icosphere.vertices.length<span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">3</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.bufferCount(<span style="color: #666666">2</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.attribute(VertexAttribute.POSITION,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>AttributeType.FLOAT3,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.attribute(VertexAttribute.TANGENTS,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span>AttributeType.SHORT4,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.normalized(VertexAttribute.TANGENTS)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>vb<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.VertexBuffer.Builder()
|
||||
<span style="color: #BBB"> </span>.vertexCount(icosphere.vertices.length<span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">3</span>)
|
||||
<span style="color: #BBB"> </span>.bufferCount(<span style="color: #666">2</span>)
|
||||
<span style="color: #BBB"> </span>.attribute(VertexAttribute.POSITION,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>AttributeType.FLOAT3,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>)
|
||||
<span style="color: #BBB"> </span>.attribute(VertexAttribute.TANGENTS,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span>AttributeType.SHORT4,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>)
|
||||
<span style="color: #BBB"> </span>.normalized(VertexAttribute.TANGENTS)
|
||||
<span style="color: #BBB"> </span>.build(engine);
|
||||
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ib<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.IndexBuffer.Builder()<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.indexCount(icosphere.triangles.length)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.bufferType(IndexType.USHORT)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ib<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.IndexBuffer.Builder()
|
||||
<span style="color: #BBB"> </span>.indexCount(icosphere.triangles.length)
|
||||
<span style="color: #BBB"> </span>.bufferType(IndexType.USHORT)
|
||||
<span style="color: #BBB"> </span>.build(engine);
|
||||
|
||||
vb.setBufferAt(engine,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>icosphere.vertices);<span style="color: #bbbbbb"></span>
|
||||
vb.setBufferAt(engine,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span>icosphere.tangents);<span style="color: #bbbbbb"></span>
|
||||
ib.setBuffer(engine,<span style="color: #bbbbbb"> </span>icosphere.triangles);<span style="color: #bbbbbb"></span>
|
||||
vb.setBufferAt(engine,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>icosphere.vertices);
|
||||
vb.setBufferAt(engine,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span>icosphere.tangents);
|
||||
ib.setBuffer(engine,<span style="color: #BBB"> </span>icosphere.triangles);
|
||||
|
||||
Filament.RenderableManager.Builder(<span style="color: #666666">1</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.boundingBox({<span style="color: #bbbbbb"> </span>center<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">-1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">-1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">-1</span>],<span style="color: #bbbbbb"> </span>halfExtent<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>]<span style="color: #bbbbbb"> </span>})<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.material(<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>matinstance)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.geometry(<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>PrimitiveType.TRIANGLES,<span style="color: #bbbbbb"> </span>vb,<span style="color: #bbbbbb"> </span>ib)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine,<span style="color: #bbbbbb"> </span>renderable);<span style="color: #bbbbbb"></span>
|
||||
Filament.RenderableManager.Builder(<span style="color: #666">1</span>)
|
||||
<span style="color: #BBB"> </span>.boundingBox({<span style="color: #BBB"> </span>center<span style="color: #666">:</span><span style="color: #BBB"> </span>[<span style="color: #666">-1</span>,<span style="color: #BBB"> </span><span style="color: #666">-1</span>,<span style="color: #BBB"> </span><span style="color: #666">-1</span>],<span style="color: #BBB"> </span>halfExtent<span style="color: #666">:</span><span style="color: #BBB"> </span>[<span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>]<span style="color: #BBB"> </span>})
|
||||
<span style="color: #BBB"> </span>.material(<span style="color: #666">0</span>,<span style="color: #BBB"> </span>matinstance)
|
||||
<span style="color: #BBB"> </span>.geometry(<span style="color: #666">0</span>,<span style="color: #BBB"> </span>PrimitiveType.TRIANGLES,<span style="color: #BBB"> </span>vb,<span style="color: #BBB"> </span>ib)
|
||||
<span style="color: #BBB"> </span>.build(engine,<span style="color: #BBB"> </span>renderable);
|
||||
</pre></div>
|
||||
|
||||
<p>At this point, the app is rendering a sphere, but it is black so it doesn't show up. To prove that
|
||||
<p>At this point, the app is rendering a sphere, but it is black so it doesn't show up. To prove that
|
||||
the sphere is there, you can try changing the background color to blue via <code>setClearColor</code>, like we
|
||||
did in the first tutorial.</p>
|
||||
<h2>Add lighting</h2>
|
||||
<p>In this section we will create some directional light sources, as well as an image-based light (IBL)
|
||||
defined by one of the KTX files we built at the start of the demo. First, replace the <strong>create
|
||||
lights</strong> comment with the following snippet.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sunlight<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.EntityManager.get().create();<span style="color: #bbbbbb"></span>
|
||||
scene.addEntity(sunlight);<span style="color: #bbbbbb"></span>
|
||||
Filament.LightManager.Builder(LightType.SUN)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.color([<span style="color: #666666">0.98</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.92</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.89</span>])<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.intensity(<span style="color: #666666">110000.0</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.direction([<span style="color: #666666">0.6</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">-1.0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">-0.8</span>])<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.sunAngularRadius(<span style="color: #666666">1.9</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.sunHaloSize(<span style="color: #666666">10.0</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.sunHaloFalloff(<span style="color: #666666">80.0</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine,<span style="color: #bbbbbb"> </span>sunlight);<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>sunlight<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.EntityManager.get().create();
|
||||
scene.addEntity(sunlight);
|
||||
Filament.LightManager.Builder(LightType.SUN)
|
||||
<span style="color: #BBB"> </span>.color([<span style="color: #666">0.98</span>,<span style="color: #BBB"> </span><span style="color: #666">0.92</span>,<span style="color: #BBB"> </span><span style="color: #666">0.89</span>])
|
||||
<span style="color: #BBB"> </span>.intensity(<span style="color: #666">110000.0</span>)
|
||||
<span style="color: #BBB"> </span>.direction([<span style="color: #666">0.6</span>,<span style="color: #BBB"> </span><span style="color: #666">-1.0</span>,<span style="color: #BBB"> </span><span style="color: #666">-0.8</span>])
|
||||
<span style="color: #BBB"> </span>.sunAngularRadius(<span style="color: #666">1.9</span>)
|
||||
<span style="color: #BBB"> </span>.sunHaloSize(<span style="color: #666">10.0</span>)
|
||||
<span style="color: #BBB"> </span>.sunHaloFalloff(<span style="color: #666">80.0</span>)
|
||||
<span style="color: #BBB"> </span>.build(engine,<span style="color: #BBB"> </span>sunlight);
|
||||
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>backlight<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.EntityManager.get().create();<span style="color: #bbbbbb"></span>
|
||||
scene.addEntity(backlight);<span style="color: #bbbbbb"></span>
|
||||
Filament.LightManager.Builder(LightType.DIRECTIONAL)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.direction([<span style="color: #666666">-1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>])<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.intensity(<span style="color: #666666">50000.0</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine,<span style="color: #bbbbbb"> </span>backlight);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>backlight<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.EntityManager.get().create();
|
||||
scene.addEntity(backlight);
|
||||
Filament.LightManager.Builder(LightType.DIRECTIONAL)
|
||||
<span style="color: #BBB"> </span>.direction([<span style="color: #666">-1</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>])
|
||||
<span style="color: #BBB"> </span>.intensity(<span style="color: #666">50000.0</span>)
|
||||
<span style="color: #BBB"> </span>.build(engine,<span style="color: #BBB"> </span>backlight);
|
||||
</pre></div>
|
||||
|
||||
<p>The <code>SUN</code> light source is similar to the <code>DIRECTIONAL</code> light source, but has some extra
|
||||
parameters because Filament will automatically draw a disk into the skybox.</p>
|
||||
<p>Next we need to create an <code>IndirectLight</code> object from the KTX IBL. One way of doing this is the
|
||||
following (don't type this out, there's an easier way).</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>format<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.PixelDataFormat.RGB;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>datatype<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.PixelDataType.UINT_10F_11F_11F_REV;<span style="color: #bbbbbb"></span>
|
||||
following (don't type this out, there's an easier way).</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>format<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.PixelDataFormat.RGB;
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>datatype<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.PixelDataType.UINT_10F_11F_11F_REV;
|
||||
|
||||
<span style="color: #3D7B7B; font-style: italic">// Create a Texture object for the mipmapped cubemap.</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ibl_package<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Buffer(Filament.assets[ibl_url]);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>iblktx<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>Filament.Ktx1Bundle(ibl_package);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #3D7B7B; font-style: italic">// Create a Texture object for the mipmapped cubemap.</span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ibl_package<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Buffer(Filament.assets[ibl_url]);
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>iblktx<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>Filament.Ktx1Bundle(ibl_package);
|
||||
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ibltex<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Texture.Builder()<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.width(iblktx.info().pixelWidth)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.height(iblktx.info().pixelHeight)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.levels(iblktx.getNumMipLevels())<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.format(Filament.Texture$InternalFormat.RGBA8)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ibltex<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Texture.Builder()
|
||||
<span style="color: #BBB"> </span>.width(iblktx.info().pixelWidth)
|
||||
<span style="color: #BBB"> </span>.height(iblktx.info().pixelHeight)
|
||||
<span style="color: #BBB"> </span>.levels(iblktx.getNumMipLevels())
|
||||
<span style="color: #BBB"> </span>.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)
|
||||
<span style="color: #BBB"> </span>.format(Filament.Texture$InternalFormat.RGBA8)
|
||||
<span style="color: #BBB"> </span>.build(engine);
|
||||
|
||||
<span style="color: #008000; font-weight: bold">for</span><span style="color: #bbbbbb"> </span>(<span style="color: #008000; font-weight: bold">let</span><span style="color: #bbbbbb"> </span>level<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>;<span style="color: #bbbbbb"> </span>level<span style="color: #bbbbbb"> </span><span style="color: #666666"><</span><span style="color: #bbbbbb"> </span>iblktx.getNumMipLevels();<span style="color: #bbbbbb"> </span><span style="color: #666666">++</span>level)<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>uint8array<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>iblktx.getCubeBlob(level).getBytes();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>pixelbuffer<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.PixelBuffer(uint8array,<span style="color: #bbbbbb"> </span>format,<span style="color: #bbbbbb"> </span>datatype);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>ibltex.setImageCube(engine,<span style="color: #bbbbbb"> </span>level,<span style="color: #bbbbbb"> </span>pixelbuffer);<span style="color: #bbbbbb"></span>
|
||||
}<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">for</span><span style="color: #BBB"> </span>(<span style="color: #008000; font-weight: bold">let</span><span style="color: #BBB"> </span>level<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #666">0</span>;<span style="color: #BBB"> </span>level<span style="color: #BBB"> </span><span style="color: #666"><</span><span style="color: #BBB"> </span>iblktx.getNumMipLevels();<span style="color: #BBB"> </span><span style="color: #666">++</span>level)<span style="color: #BBB"> </span>{
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>uint8array<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>iblktx.getCubeBlob(level).getBytes();
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>pixelbuffer<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.PixelBuffer(uint8array,<span style="color: #BBB"> </span>format,<span style="color: #BBB"> </span>datatype);
|
||||
<span style="color: #BBB"> </span>ibltex.setImageCube(engine,<span style="color: #BBB"> </span>level,<span style="color: #BBB"> </span>pixelbuffer);
|
||||
}
|
||||
|
||||
<span style="color: #3D7B7B; font-style: italic">// Parse the spherical harmonics metadata.</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>shstring<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>iblktx.getMetadata(<span style="color: #BA2121">'sh'</span>);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>shfloats<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>shstring.split(<span style="color: #A45A77">/\s/</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">9</span><span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span><span style="color: #666666">3</span>).map(<span style="color: #008000">parseFloat</span>);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #3D7B7B; font-style: italic">// Parse the spherical harmonics metadata.</span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>shstring<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>iblktx.getMetadata(<span style="color: #BA2121">'sh'</span>);
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>shfloats<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>shstring.split(<span style="color: #A45A77">/\s/</span>,<span style="color: #BBB"> </span><span style="color: #666">9</span><span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span><span style="color: #666">3</span>).map(<span style="color: #008000">parseFloat</span>);
|
||||
|
||||
<span style="color: #3D7B7B; font-style: italic">// Build the IBL object and insert it into the scene.</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>indirectLight<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.IndirectLight.Builder()<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.reflections(ibltex)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.irradianceSh(<span style="color: #666666">3</span>,<span style="color: #bbbbbb"> </span>shfloats)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.intensity(<span style="color: #666666">50000.0</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #3D7B7B; font-style: italic">// Build the IBL object and insert it into the scene.</span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>indirectLight<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.IndirectLight.Builder()
|
||||
<span style="color: #BBB"> </span>.reflections(ibltex)
|
||||
<span style="color: #BBB"> </span>.irradianceSh(<span style="color: #666">3</span>,<span style="color: #BBB"> </span>shfloats)
|
||||
<span style="color: #BBB"> </span>.intensity(<span style="color: #666">50000.0</span>)
|
||||
<span style="color: #BBB"> </span>.build(engine);
|
||||
|
||||
scene.setIndirectLight(indirectLight);<span style="color: #bbbbbb"></span>
|
||||
scene.setIndirectLight(indirectLight);
|
||||
</pre></div>
|
||||
|
||||
<p>Filament provides a JavaScript utility to make this simpler,
|
||||
simply replace the <strong>create IBL</strong> comment with the following snippet.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>indirectLight<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createIblFromKtx1(ibl_url);<span style="color: #bbbbbb"></span>
|
||||
indirectLight.setIntensity(<span style="color: #666666">50000</span>);<span style="color: #bbbbbb"></span>
|
||||
scene.setIndirectLight(indirectLight);<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>indirectLight<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createIblFromKtx1(ibl_url);
|
||||
indirectLight.setIntensity(<span style="color: #666">50000</span>);
|
||||
scene.setIndirectLight(indirectLight);
|
||||
</pre></div>
|
||||
|
||||
<h2>Add background</h2>
|
||||
<p>At this point you can run the demo and you should see a red plastic ball against a black background.
|
||||
Without a skybox, the reflections on the ball are not representative of its surroundings.
|
||||
Here's one way to create a texture for the skybox:</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sky_package<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Buffer(Filament.assets[sky_url]);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>skyktx<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>Filament.Ktx1Bundle(sky_package);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>skytex<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Texture.Builder()<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.width(skyktx.info().pixelWidth)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.height(skyktx.info().pixelHeight)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.levels(<span style="color: #666666">1</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.format(Filament.Texture$InternalFormat.RGBA8)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
|
||||
Here's one way to create a texture for the skybox:</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>sky_package<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Buffer(Filament.assets[sky_url]);
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>skyktx<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>Filament.Ktx1Bundle(sky_package);
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>skytex<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Texture.Builder()
|
||||
<span style="color: #BBB"> </span>.width(skyktx.info().pixelWidth)
|
||||
<span style="color: #BBB"> </span>.height(skyktx.info().pixelHeight)
|
||||
<span style="color: #BBB"> </span>.levels(<span style="color: #666">1</span>)
|
||||
<span style="color: #BBB"> </span>.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)
|
||||
<span style="color: #BBB"> </span>.format(Filament.Texture$InternalFormat.RGBA8)
|
||||
<span style="color: #BBB"> </span>.build(engine);
|
||||
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>uint8array<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>skyktx.getCubeBlob(<span style="color: #666666">0</span>).getBytes();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>pixelbuffer<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.PixelBuffer(uint8array,<span style="color: #bbbbbb"> </span>format,<span style="color: #bbbbbb"> </span>datatype);<span style="color: #bbbbbb"></span>
|
||||
skytex.setImageCube(engine,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>pixelbuffer);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>uint8array<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>skyktx.getCubeBlob(<span style="color: #666">0</span>).getBytes();
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>pixelbuffer<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.PixelBuffer(uint8array,<span style="color: #BBB"> </span>format,<span style="color: #BBB"> </span>datatype);
|
||||
skytex.setImageCube(engine,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>pixelbuffer);
|
||||
</pre></div>
|
||||
|
||||
<p>Filament provides a Javascript utility to make this easier.
|
||||
Replace <strong>create skybox</strong> with the following.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>skybox<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createSkyFromKtx1(sky_url);<span style="color: #bbbbbb"></span>
|
||||
scene.setSkybox(skybox);<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>skybox<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createSkyFromKtx1(sky_url);
|
||||
scene.setSkybox(skybox);
|
||||
</pre></div>
|
||||
|
||||
<p>That's it, we now have a shiny red ball floating in an environment! The complete JavaScript file is
|
||||
<p>That's it, we now have a shiny red ball floating in an environment! The complete JavaScript file is
|
||||
available <a href="tutorial_redball.js">here</a>.</p>
|
||||
<p>In the <a href="tutorial_suzanne.html">next tutorial</a>, we'll take a closer look at textures and interaction.</p>
|
||||
<p>In the <a href="tutorial_suzanne.html">next tutorial</a>, we'll take a closer look at textures and interaction.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -8,58 +8,58 @@
|
||||
<div class="demo_frame"><iframe src="demo_suzanne.html"></iframe><a href="demo_suzanne.html">🔗</a></div>
|
||||
<p>This tutorial will describe how to create the <strong>suzanne</strong> demo, introducing you to compressed
|
||||
textures, mipmap generation, asynchronous texture loading, and trackball rotation.</p>
|
||||
<p>Much like the <a href="tutorial_redball.html">previous tutorial</a>, you'll need to use the command-line tools that can be found in
|
||||
<p>Much like the <a href="tutorial_redball.html">previous tutorial</a>, you'll need to use the command-line tools that can be found in
|
||||
the appropriate <a href="//github.com/google/filament/releases">Filament release</a> for your development machine. In addition to <code>matc</code> and <code>cmgen</code>,
|
||||
we'll also be using <code>filamesh</code> and <code>mipgen</code>.</p>
|
||||
we'll also be using <code>filamesh</code> and <code>mipgen</code>.</p>
|
||||
<h2>Create filamesh file</h2>
|
||||
<p>Filament does not have an asset loading system, but it does provide a binary mesh format
|
||||
called <code>filamesh</code> for simple use cases. Let's create a compressed filamesh file for suzanne by
|
||||
called <code>filamesh</code> for simple use cases. Let's create a compressed filamesh file for suzanne by
|
||||
converting <a href="https://github.com/google/filament/blob/main/assets/models/monkey/monkey.obj">this OBJ file</a>:</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>filamesh --compress monkey.obj suzanne.filamesh
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>filamesh<span style="color: #BBB"> </span>--compress<span style="color: #BBB"> </span>monkey.obj<span style="color: #BBB"> </span>suzanne.filamesh
|
||||
</pre></div>
|
||||
|
||||
<h2>Create mipmapped textures</h2>
|
||||
<p>Next, let's create mipmapped KTX files using filament's <code>mipgen</code> tool. We'll create compressed and
|
||||
<p>Next, let's create mipmapped KTX files using filament's <code>mipgen</code> tool. We'll create compressed and
|
||||
non-compressed variants for each texture, since not all platforms support the same compression
|
||||
formats. First copy over the PNG files from the <a href="https://github.com/google/filament/blob/main/assets/models/monkey">monkey folder</a>, then do:</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic"># Create mipmaps for base color</span>
|
||||
mipgen albedo.png albedo.ktx2
|
||||
mipgen --compression<span style="color: #666666">=</span>uastc albedo.png albedo.ktx2
|
||||
mipgen<span style="color: #BBB"> </span>albedo.png<span style="color: #BBB"> </span>albedo.ktx2
|
||||
mipgen<span style="color: #BBB"> </span>--compression<span style="color: #666">=</span>uastc<span style="color: #BBB"> </span>albedo.png<span style="color: #BBB"> </span>albedo.ktx2
|
||||
|
||||
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the normal map and a compressed variant.</span>
|
||||
mipgen --strip-alpha --kernel<span style="color: #666666">=</span>NORMALS --linear normal.png normal.ktx
|
||||
mipgen --strip-alpha --kernel<span style="color: #666666">=</span>NORMALS --linear --compression<span style="color: #666666">=</span>uastc_normals <span style="color: #AA5D1F; font-weight: bold">\</span>
|
||||
normal.png normal.ktx2
|
||||
mipgen<span style="color: #BBB"> </span>--strip-alpha<span style="color: #BBB"> </span>--kernel<span style="color: #666">=</span>NORMALS<span style="color: #BBB"> </span>--linear<span style="color: #BBB"> </span>normal.png<span style="color: #BBB"> </span>normal.ktx
|
||||
mipgen<span style="color: #BBB"> </span>--strip-alpha<span style="color: #BBB"> </span>--kernel<span style="color: #666">=</span>NORMALS<span style="color: #BBB"> </span>--linear<span style="color: #BBB"> </span>--compression<span style="color: #666">=</span>uastc_normals<span style="color: #BBB"> </span><span style="color: #AA5D1F; font-weight: bold">\</span>
|
||||
<span style="color: #BBB"> </span>normal.png<span style="color: #BBB"> </span>normal.ktx2
|
||||
|
||||
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component roughness map and a compressed variant.</span>
|
||||
mipgen --grayscale roughness.png roughness.ktx
|
||||
mipgen --grayscale --compression<span style="color: #666666">=</span>uastc roughness.png roughness.ktx2
|
||||
mipgen<span style="color: #BBB"> </span>--grayscale<span style="color: #BBB"> </span>roughness.png<span style="color: #BBB"> </span>roughness.ktx
|
||||
mipgen<span style="color: #BBB"> </span>--grayscale<span style="color: #BBB"> </span>--compression<span style="color: #666">=</span>uastc<span style="color: #BBB"> </span>roughness.png<span style="color: #BBB"> </span>roughness.ktx2
|
||||
|
||||
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component metallic map and a compressed variant.</span>
|
||||
mipgen --grayscale metallic.png metallic.ktx
|
||||
mipgen --grayscale --compression<span style="color: #666666">=</span>uastc metallic.png metallic.ktx2
|
||||
mipgen<span style="color: #BBB"> </span>--grayscale<span style="color: #BBB"> </span>metallic.png<span style="color: #BBB"> </span>metallic.ktx
|
||||
mipgen<span style="color: #BBB"> </span>--grayscale<span style="color: #BBB"> </span>--compression<span style="color: #666">=</span>uastc<span style="color: #BBB"> </span>metallic.png<span style="color: #BBB"> </span>metallic.ktx2
|
||||
|
||||
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component occlusion map and a compressed variant.</span>
|
||||
mipgen --grayscale ao.png ao.ktx
|
||||
mipgen --grayscale --compression<span style="color: #666666">=</span>uastc ao.png ao.ktx2
|
||||
mipgen<span style="color: #BBB"> </span>--grayscale<span style="color: #BBB"> </span>ao.png<span style="color: #BBB"> </span>ao.ktx
|
||||
mipgen<span style="color: #BBB"> </span>--grayscale<span style="color: #BBB"> </span>--compression<span style="color: #666">=</span>uastc<span style="color: #BBB"> </span>ao.png<span style="color: #BBB"> </span>ao.ktx2
|
||||
</pre></div>
|
||||
|
||||
<p>For more information on mipgen's arguments and supported formats, do <code>mipgen --help</code>.</p>
|
||||
<p>In a production setting, you'd want to invoke these commands with a script or build system.</p>
|
||||
<p>For more information on mipgen's arguments and supported formats, do <code>mipgen --help</code>.</p>
|
||||
<p>In a production setting, you'd want to invoke these commands with a script or build system.</p>
|
||||
<h2>Bake environment map</h2>
|
||||
<p>Much like the <a href="tutorial_redball.html">previous tutorial</a> we need to use Filament's <code>cmgen</code> tool to produce cubemap files.</p>
|
||||
<p>Much like the <a href="tutorial_redball.html">previous tutorial</a> we need to use Filament's <code>cmgen</code> tool to produce cubemap files.</p>
|
||||
<p>Download <a href="//github.com/google/filament/blob/main/third_party/environments/venetian_crossroads_2k.hdr">venetian_crossroads_2k.hdr</a>, then invoke the following commands in your terminal.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>cmgen -x . --format<span style="color: #666666">=</span>ktx --size<span style="color: #666666">=64</span> --extract-blur<span style="color: #666666">=0</span>.1 venetian_crossroads_2k.hdr
|
||||
<span style="color: #008000">cd</span> venetian* ; mv venetian*_ibl.ktx venetian_crossroads_2k_skybox_tiny.ktx ; <span style="color: #008000">cd</span> -
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>cmgen<span style="color: #BBB"> </span>-x<span style="color: #BBB"> </span>.<span style="color: #BBB"> </span>--format<span style="color: #666">=</span>ktx<span style="color: #BBB"> </span>--size<span style="color: #666">=64</span><span style="color: #BBB"> </span>--extract-blur<span style="color: #666">=0</span>.1<span style="color: #BBB"> </span>venetian_crossroads_2k.hdr
|
||||
<span style="color: #008000">cd</span><span style="color: #BBB"> </span>venetian*<span style="color: #BBB"> </span>;<span style="color: #BBB"> </span>mv<span style="color: #BBB"> </span>venetian*_ibl.ktx<span style="color: #BBB"> </span>venetian_crossroads_2k_skybox_tiny.ktx<span style="color: #BBB"> </span>;<span style="color: #BBB"> </span><span style="color: #008000">cd</span><span style="color: #BBB"> </span>-
|
||||
|
||||
cmgen -x . --format<span style="color: #666666">=</span>ktx --size<span style="color: #666666">=256</span> --extract-blur<span style="color: #666666">=0</span>.1 venetian_crossroads_2k.hdr
|
||||
cmgen -x . --format<span style="color: #666666">=</span>ktx --size<span style="color: #666666">=256</span> --extract-blur<span style="color: #666666">=0</span>.1 venetian_crossroads_2k.hdr
|
||||
cmgen -x . --format<span style="color: #666666">=</span>ktx --size<span style="color: #666666">=256</span> --extract-blur<span style="color: #666666">=0</span>.1 venetian_crossroads_2k.hdr
|
||||
cmgen<span style="color: #BBB"> </span>-x<span style="color: #BBB"> </span>.<span style="color: #BBB"> </span>--format<span style="color: #666">=</span>ktx<span style="color: #BBB"> </span>--size<span style="color: #666">=256</span><span style="color: #BBB"> </span>--extract-blur<span style="color: #666">=0</span>.1<span style="color: #BBB"> </span>venetian_crossroads_2k.hdr
|
||||
cmgen<span style="color: #BBB"> </span>-x<span style="color: #BBB"> </span>.<span style="color: #BBB"> </span>--format<span style="color: #666">=</span>ktx<span style="color: #BBB"> </span>--size<span style="color: #666">=256</span><span style="color: #BBB"> </span>--extract-blur<span style="color: #666">=0</span>.1<span style="color: #BBB"> </span>venetian_crossroads_2k.hdr
|
||||
cmgen<span style="color: #BBB"> </span>-x<span style="color: #BBB"> </span>.<span style="color: #BBB"> </span>--format<span style="color: #666">=</span>ktx<span style="color: #BBB"> </span>--size<span style="color: #666">=256</span><span style="color: #BBB"> </span>--extract-blur<span style="color: #666">=0</span>.1<span style="color: #BBB"> </span>venetian_crossroads_2k.hdr
|
||||
</pre></div>
|
||||
|
||||
<h2>Define textured material</h2>
|
||||
<p>You might recall the <code>filamat</code> file we generated in the previous tutorial for red plastic. For this
|
||||
demo, we'll create a material that uses textures for several parameters.</p>
|
||||
demo, we'll create a material that uses textures for several parameters.</p>
|
||||
<p>Create the following text file and call it <code>textured.mat</code>. Note that our material definition now
|
||||
requires a <code>uv0</code> attribute.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>material {
|
||||
@@ -90,7 +90,7 @@ fragment {
|
||||
</pre></div>
|
||||
|
||||
<p>Next, invoke <code>matc</code> as follows.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>matc -a opengl -p mobile -o textured.filamat textured.mat
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>matc<span style="color: #BBB"> </span>-a<span style="color: #BBB"> </span>opengl<span style="color: #BBB"> </span>-p<span style="color: #BBB"> </span>mobile<span style="color: #BBB"> </span>-o<span style="color: #BBB"> </span>textured.filamat<span style="color: #BBB"> </span>textured.mat
|
||||
</pre></div>
|
||||
|
||||
<p>You should now have a material archive in your working directory. For the suzanne asset, the normal
|
||||
@@ -100,65 +100,65 @@ materials, consult the official document describing the <a href="https://google.
|
||||
<p>Create a text file called <code>suzanne.html</code> and copy over the HTML that we used in the <a href="tutorial_redball.html">previous
|
||||
tutorial</a>. Change the last script tag from <code>redball.js</code> to <code>suzanne.js</code>. Next, create <code>suzanne.js</code>
|
||||
with the following content.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic">// TODO: declare asset URLs</span><span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic">// TODO: declare asset URLs</span>
|
||||
|
||||
Filament.init([<span style="color: #bbbbbb"> </span>filamat_url,<span style="color: #bbbbbb"> </span>filamesh_url,<span style="color: #bbbbbb"> </span>sky_small_url,<span style="color: #bbbbbb"> </span>ibl_url<span style="color: #bbbbbb"> </span>],<span style="color: #bbbbbb"> </span>()<span style="color: #bbbbbb"> </span>=><span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.app<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>App(<span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">'canvas'</span>)[<span style="color: #666666">0</span>]);<span style="color: #bbbbbb"></span>
|
||||
});<span style="color: #bbbbbb"></span>
|
||||
Filament.init([<span style="color: #BBB"> </span>filamat_url,<span style="color: #BBB"> </span>filamesh_url,<span style="color: #BBB"> </span>sky_small_url,<span style="color: #BBB"> </span>ibl_url<span style="color: #BBB"> </span>],<span style="color: #BBB"> </span>()<span style="color: #BBB"> </span>=><span style="color: #BBB"> </span>{
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.app<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>App(<span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">'canvas'</span>)[<span style="color: #666">0</span>]);
|
||||
});
|
||||
|
||||
<span style="color: #008000; font-weight: bold">class</span><span style="color: #bbbbbb"> </span>App<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">constructor</span>(canvas)<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>canvas;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Engine.create(canvas);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.scene<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createScene();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">class</span><span style="color: #BBB"> </span>App<span style="color: #BBB"> </span>{
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">constructor</span>(canvas)<span style="color: #BBB"> </span>{
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>canvas;
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Engine.create(canvas);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.scene<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createScene();
|
||||
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>material<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createMaterial(filamat_url);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>material.createInstance();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>material<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createMaterial(filamat_url);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>material.createInstance();
|
||||
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>filamesh<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.loadFilamesh(filamesh_url,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.suzanne<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>filamesh.renderable;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>filamesh<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.loadFilamesh(filamesh_url,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.suzanne<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>filamesh.renderable;
|
||||
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create sky box and IBL</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: initialize gltumble</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: fetch larger assets</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create sky box and IBL</span>
|
||||
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: initialize gltumble</span>
|
||||
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: fetch larger assets</span>
|
||||
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.swapChain<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createSwapChain();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createRenderer();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.camera<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createCamera(Filament.EntityManager.get().create());<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createView();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setScene(<span style="color: #008000; font-weight: bold">this</span>.scene);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.render<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">'resize'</span>,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.swapChain<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createSwapChain();
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createRenderer();
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.camera<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createCamera(Filament.EntityManager.get().create());
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createView();
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setScene(<span style="color: #008000; font-weight: bold">this</span>.scene);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.render<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">'resize'</span>,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize);
|
||||
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>eye<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">4</span>],<span style="color: #bbbbbb"> </span>center<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>],<span style="color: #bbbbbb"> </span>up<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>];<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.lookAt(eye,<span style="color: #bbbbbb"> </span>center,<span style="color: #bbbbbb"> </span>up);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>eye<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">4</span>],<span style="color: #BBB"> </span>center<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>],<span style="color: #BBB"> </span>up<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>];
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.lookAt(eye,<span style="color: #BBB"> </span>center,<span style="color: #BBB"> </span>up);
|
||||
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize();
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||
<span style="color: #BBB"> </span>}
|
||||
|
||||
<span style="color: #bbbbbb"> </span>render()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: apply gltumble matrix</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #BBB"> </span>render()<span style="color: #BBB"> </span>{
|
||||
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: apply gltumble matrix</span>
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||
<span style="color: #BBB"> </span>}
|
||||
|
||||
<span style="color: #bbbbbb"> </span>resize()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>dpr<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.devicePixelRatio;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>width<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.width<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.innerWidth<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span>dpr;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>height<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.height<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.innerHeight<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span>dpr;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>width,<span style="color: #bbbbbb"> </span>height]);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #BBB"> </span>resize()<span style="color: #BBB"> </span>{
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>dpr<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.devicePixelRatio;
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>width<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.width<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.innerWidth<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span>dpr;
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>height<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.height<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.innerHeight<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span>dpr;
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>width,<span style="color: #BBB"> </span>height]);
|
||||
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>aspect<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>width<span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span>height;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>Fov<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Camera$Fov,<span style="color: #bbbbbb"> </span>fov<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>aspect<span style="color: #bbbbbb"> </span><span style="color: #666666"><</span><span style="color: #bbbbbb"> </span><span style="color: #666666">1</span><span style="color: #bbbbbb"> </span><span style="color: #666666">?</span><span style="color: #bbbbbb"> </span>Fov.HORIZONTAL<span style="color: #bbbbbb"> </span><span style="color: #666666">:</span><span style="color: #bbbbbb"> </span>Fov.VERTICAL;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.setProjectionFov(<span style="color: #666666">45</span>,<span style="color: #bbbbbb"> </span>aspect,<span style="color: #bbbbbb"> </span><span style="color: #666666">1.0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">10.0</span>,<span style="color: #bbbbbb"> </span>fov);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
||||
}<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>aspect<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>width<span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span>height;
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>Fov<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Camera$Fov,<span style="color: #BBB"> </span>fov<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>aspect<span style="color: #BBB"> </span><span style="color: #666"><</span><span style="color: #BBB"> </span><span style="color: #666">1</span><span style="color: #BBB"> </span><span style="color: #666">?</span><span style="color: #BBB"> </span>Fov.HORIZONTAL<span style="color: #BBB"> </span><span style="color: #666">:</span><span style="color: #BBB"> </span>Fov.VERTICAL;
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.camera.setProjectionFov(<span style="color: #666">45</span>,<span style="color: #BBB"> </span>aspect,<span style="color: #BBB"> </span><span style="color: #666">1.0</span>,<span style="color: #BBB"> </span><span style="color: #666">10.0</span>,<span style="color: #BBB"> </span>fov);
|
||||
<span style="color: #BBB"> </span>}
|
||||
}
|
||||
</pre></div>
|
||||
|
||||
<p>Our app will only require a subset of assets to be present for <code>App</code> construction. We'll download
|
||||
<p>Our app will only require a subset of assets to be present for <code>App</code> construction. We'll download
|
||||
the other assets after construction. By using a progressive loading strategy, we can reduce the
|
||||
perceived load time.</p>
|
||||
<p>Next we need to supply the URLs for various assets. This is actually a bit tricky, because different
|
||||
@@ -171,85 +171,85 @@ string -- which might be empty.</p>
|
||||
<p>In our case, we know that our web server will have <code>astc</code> and <code>s3tc</code> variants for albedo, and <code>etc</code>
|
||||
variants for the other textures. The uncompressed variants (empty string) are always available as a
|
||||
last resort. Go ahead and replace the <strong>declare asset URLs</strong> comment with the following snippet.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>albedo_suffix<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.getSupportedFormatSuffix(<span style="color: #BA2121">'astc s3tc_srgb'</span>);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>texture_suffix<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.getSupportedFormatSuffix(<span style="color: #BA2121">'etc'</span>);<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>albedo_suffix<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.getSupportedFormatSuffix(<span style="color: #BA2121">'astc s3tc_srgb'</span>);
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>texture_suffix<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.getSupportedFormatSuffix(<span style="color: #BA2121">'etc'</span>);
|
||||
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>environ<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">'venetian_crossroads_2k'</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ibl_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_ibl.ktx`</span>;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sky_small_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox_tiny.ktx`</span>;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sky_large_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox.ktx`</span>;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>albedo_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`albedo</span><span style="color: #A45A77; font-weight: bold">${</span>albedo_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ao_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`ao</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>metallic_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`metallic</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>normal_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`normal</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>roughness_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">`roughness</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>filamat_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">'textured.filamat'</span>;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>filamesh_url<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #BA2121">'suzanne.filamesh'</span>;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>environ<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">'venetian_crossroads_2k'</span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ibl_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_ibl.ktx`</span>;
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>sky_small_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox_tiny.ktx`</span>;
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>sky_large_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox.ktx`</span>;
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>albedo_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`albedo</span><span style="color: #A45A77; font-weight: bold">${</span>albedo_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ao_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`ao</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>metallic_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`metallic</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>normal_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`normal</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>roughness_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">`roughness</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>filamat_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">'textured.filamat'</span>;
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>filamesh_url<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #BA2121">'suzanne.filamesh'</span>;
|
||||
</pre></div>
|
||||
|
||||
<h2>Create skybox and IBL</h2>
|
||||
<p>Next, let's create the low-resolution skybox and IBL in the <code>App</code> constructor.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.skybox<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createSkyFromKtx1(sky_small_url);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.scene.setSkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.indirectLight<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createIblFromKtx1(ibl_url);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.indirectLight.setIntensity(<span style="color: #666666">100000</span>);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.scene.setIndirectLight(<span style="color: #008000; font-weight: bold">this</span>.indirectLight);<span style="color: #bbbbbb"></span>
|
||||
<p>Next, let's create the low-resolution skybox and IBL in the <code>App</code> constructor.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.skybox<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createSkyFromKtx1(sky_small_url);
|
||||
<span style="color: #008000; font-weight: bold">this</span>.scene.setSkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox);
|
||||
<span style="color: #008000; font-weight: bold">this</span>.indirectLight<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createIblFromKtx1(ibl_url);
|
||||
<span style="color: #008000; font-weight: bold">this</span>.indirectLight.setIntensity(<span style="color: #666">100000</span>);
|
||||
<span style="color: #008000; font-weight: bold">this</span>.scene.setIndirectLight(<span style="color: #008000; font-weight: bold">this</span>.indirectLight);
|
||||
</pre></div>
|
||||
|
||||
<p>This allows users to see a reasonable background fairly quickly, before larger assets have finished
|
||||
loading in.</p>
|
||||
<h2>Fetch assets asychronously</h2>
|
||||
<p>Next we'll invoke the <code>Filament.fetch</code> function from within the app constructor. This function is
|
||||
<p>Next we'll invoke the <code>Filament.fetch</code> function from within the app constructor. This function is
|
||||
very similar to <code>Filament.init</code>. It takes a list of asset URLs and a callback function that triggers
|
||||
when the assets have finished downloading.</p>
|
||||
<p>In our callback, we'll make several <code>setTextureParameter</code> calls on the material instance, then we'll
|
||||
<p>In our callback, we'll make several <code>setTextureParameter</code> calls on the material instance, then we'll
|
||||
recreate the skybox using a higher-resolution texture. As a last step we unhide the renderable that
|
||||
was created in the app constructor.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>Filament.fetch([sky_large_url,<span style="color: #bbbbbb"> </span>albedo_url,<span style="color: #bbbbbb"> </span>roughness_url,<span style="color: #bbbbbb"> </span>metallic_url,<span style="color: #bbbbbb"> </span>normal_url,<span style="color: #bbbbbb"> </span>ao_url],<span style="color: #bbbbbb"> </span>()<span style="color: #bbbbbb"> </span>=><span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>albedo<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(albedo_url,<span style="color: #bbbbbb"> </span>{srgb<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">true</span>});<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>roughness<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(roughness_url);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>metallic<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(metallic_url);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>normal<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(normal_url);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>ao<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(ao_url);<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>Filament.fetch([sky_large_url,<span style="color: #BBB"> </span>albedo_url,<span style="color: #BBB"> </span>roughness_url,<span style="color: #BBB"> </span>metallic_url,<span style="color: #BBB"> </span>normal_url,<span style="color: #BBB"> </span>ao_url],<span style="color: #BBB"> </span>()<span style="color: #BBB"> </span>=><span style="color: #BBB"> </span>{
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>albedo<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(albedo_url,<span style="color: #BBB"> </span>{srgb<span style="color: #666">:</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">true</span>});
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>roughness<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(roughness_url);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>metallic<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(metallic_url);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>normal<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(normal_url);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>ao<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createTextureFromKtx2(ao_url);
|
||||
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>sampler<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>Filament.TextureSampler(<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>Filament.MinFilter.LINEAR_MIPMAP_LINEAR,<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>Filament.MagFilter.LINEAR,<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>Filament.WrapMode.CLAMP_TO_EDGE);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>sampler<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>Filament.TextureSampler(
|
||||
<span style="color: #BBB"> </span>Filament.MinFilter.LINEAR_MIPMAP_LINEAR,
|
||||
<span style="color: #BBB"> </span>Filament.MagFilter.LINEAR,
|
||||
<span style="color: #BBB"> </span>Filament.WrapMode.CLAMP_TO_EDGE);
|
||||
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'albedo'</span>,<span style="color: #bbbbbb"> </span>albedo,<span style="color: #bbbbbb"> </span>sampler);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'roughness'</span>,<span style="color: #bbbbbb"> </span>roughness,<span style="color: #bbbbbb"> </span>sampler);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'metallic'</span>,<span style="color: #bbbbbb"> </span>metallic,<span style="color: #bbbbbb"> </span>sampler);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'normal'</span>,<span style="color: #bbbbbb"> </span>normal,<span style="color: #bbbbbb"> </span>sampler);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'ao'</span>,<span style="color: #bbbbbb"> </span>ao,<span style="color: #bbbbbb"> </span>sampler);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'albedo'</span>,<span style="color: #BBB"> </span>albedo,<span style="color: #BBB"> </span>sampler);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'roughness'</span>,<span style="color: #BBB"> </span>roughness,<span style="color: #BBB"> </span>sampler);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'metallic'</span>,<span style="color: #BBB"> </span>metallic,<span style="color: #BBB"> </span>sampler);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'normal'</span>,<span style="color: #BBB"> </span>normal,<span style="color: #BBB"> </span>sampler);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">'ao'</span>,<span style="color: #BBB"> </span>ao,<span style="color: #BBB"> </span>sampler);
|
||||
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// Replace low-res skybox with high-res skybox.</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.destroySkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.skybox<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createSkyFromKtx1(sky_large_url);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.scene.setSkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// Replace low-res skybox with high-res skybox.</span>
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.destroySkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.skybox<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.createSkyFromKtx1(sky_large_url);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.scene.setSkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox);
|
||||
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.scene.addEntity(<span style="color: #008000; font-weight: bold">this</span>.suzanne);<span style="color: #bbbbbb"></span>
|
||||
});<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.scene.addEntity(<span style="color: #008000; font-weight: bold">this</span>.suzanne);
|
||||
});
|
||||
</pre></div>
|
||||
|
||||
<h2>Introduce trackball rotation</h2>
|
||||
<p>Add the following script tag to your HTML file. This imports a small third-party library that
|
||||
listens for drag events and computes a rotation matrix.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666666">=</span><span style="color: #BA2121">"//unpkg.com/gltumble"</span>></<span style="color: #008000; font-weight: bold">script</span>>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666">=</span><span style="color: #BA2121">"//unpkg.com/gltumble"</span>></<span style="color: #008000; font-weight: bold">script</span>>
|
||||
</pre></div>
|
||||
|
||||
<p>Next, replace the <strong>initialize gltumble</strong> and <strong>apply gltumble matrix</strong> comments with the following
|
||||
two code snippets.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.trackball<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>Trackball(canvas,<span style="color: #bbbbbb"> </span>{startSpin<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span><span style="color: #666666">0.035</span>});<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.trackball<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>Trackball(canvas,<span style="color: #BBB"> </span>{startSpin<span style="color: #666">:</span><span style="color: #BBB"> </span><span style="color: #666">0.035</span>});
|
||||
</pre></div>
|
||||
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>tcm<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.getTransformManager();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>inst<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>tcm.getInstance(<span style="color: #008000; font-weight: bold">this</span>.suzanne);<span style="color: #bbbbbb"></span>
|
||||
tcm.setTransform(inst,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.trackball.getMatrix());<span style="color: #bbbbbb"></span>
|
||||
inst.<span style="color: #AA22FF; font-weight: bold">delete</span>();<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>tcm<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.getTransformManager();
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>inst<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>tcm.getInstance(<span style="color: #008000; font-weight: bold">this</span>.suzanne);
|
||||
tcm.setTransform(inst,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.trackball.getMatrix());
|
||||
inst.<span style="color: #A2F; font-weight: bold">delete</span>();
|
||||
</pre></div>
|
||||
|
||||
<p>That's it, we now have a fast-loading interactive demo. The complete JavaScript file is available
|
||||
<p>That's it, we now have a fast-loading interactive demo. The complete JavaScript file is available
|
||||
<a href="tutorial_suzanne.js">here</a>.</p>
|
||||
|
||||
</body>
|
||||
|
||||
@@ -8,30 +8,30 @@
|
||||
<div class="demo_frame"><iframe src="demo_triangle.html"></iframe><a href="demo_triangle.html">🔗</a></div>
|
||||
<h2>Literate programming</h2>
|
||||
<p>The markdown source for this tutorial is not only used to generate this
|
||||
web page, it's also used to generate the JavaScript for the above demo.
|
||||
web page, it's also used to generate the JavaScript for the above demo.
|
||||
We use a small Python script for weaving (generating HTML) and tangling
|
||||
(generating JS). In the code samples, you'll often see
|
||||
(generating JS). In the code samples, you'll often see
|
||||
<code>// TODO: <some task></code>. These are special markers that get replaced by
|
||||
subsequent code blocks.</p>
|
||||
<h2>Start your project</h2>
|
||||
<p>First, create a text file called <code>triangle.html</code> and fill it with the following HTML. This creates
|
||||
a mobile-friendly page with a full-screen canvas.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #9C6500"><!DOCTYPE html></span>
|
||||
<<span style="color: #008000; font-weight: bold">html</span> <span style="color: #687822">lang</span><span style="color: #666666">=</span><span style="color: #BA2121">"en"</span>>
|
||||
<<span style="color: #008000; font-weight: bold">html</span> <span style="color: #687822">lang</span><span style="color: #666">=</span><span style="color: #BA2121">"en"</span>>
|
||||
<<span style="color: #008000; font-weight: bold">head</span>>
|
||||
<<span style="color: #008000; font-weight: bold">title</span>>Filament Tutorial</<span style="color: #008000; font-weight: bold">title</span>>
|
||||
<<span style="color: #008000; font-weight: bold">meta</span> <span style="color: #687822">charset</span><span style="color: #666666">=</span><span style="color: #BA2121">"utf-8"</span>>
|
||||
<<span style="color: #008000; font-weight: bold">meta</span> <span style="color: #687822">name</span><span style="color: #666666">=</span><span style="color: #BA2121">"viewport"</span> <span style="color: #687822">content</span><span style="color: #666666">=</span><span style="color: #BA2121">"width=device-width,user-scalable=no,initial-scale=1"</span>>
|
||||
<<span style="color: #008000; font-weight: bold">style</span>><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">body</span><span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">margin</span>:<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>;<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">overflow</span>:<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">hidden</span>;<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">canvas</span><span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"> </span>touch-action:<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">none</span>;<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">width</span>:<span style="color: #bbbbbb"> </span><span style="color: #666666">100</span><span style="color: #B00040">%</span>;<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">height</span>:<span style="color: #bbbbbb"> </span><span style="color: #666666">100</span><span style="color: #B00040">%</span>;<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span></<span style="color: #008000; font-weight: bold">style</span>>
|
||||
<<span style="color: #008000; font-weight: bold">meta</span> <span style="color: #687822">charset</span><span style="color: #666">=</span><span style="color: #BA2121">"utf-8"</span>>
|
||||
<<span style="color: #008000; font-weight: bold">meta</span> <span style="color: #687822">name</span><span style="color: #666">=</span><span style="color: #BA2121">"viewport"</span> <span style="color: #687822">content</span><span style="color: #666">=</span><span style="color: #BA2121">"width=device-width,user-scalable=no,initial-scale=1"</span>>
|
||||
<<span style="color: #008000; font-weight: bold">style</span>>
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">body</span><span style="color: #BBB"> </span>{<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">margin</span>:<span style="color: #BBB"> </span><span style="color: #666">0</span>;<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">overflow</span>:<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">hidden</span>;<span style="color: #BBB"> </span>}
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">canvas</span><span style="color: #BBB"> </span>{<span style="color: #BBB"> </span>touch-action:<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">none</span>;<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">width</span>:<span style="color: #BBB"> </span><span style="color: #666">100</span><span style="color: #B00040">%</span>;<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">height</span>:<span style="color: #BBB"> </span><span style="color: #666">100</span><span style="color: #B00040">%</span>;<span style="color: #BBB"> </span>}
|
||||
<span style="color: #BBB"> </span></<span style="color: #008000; font-weight: bold">style</span>>
|
||||
</<span style="color: #008000; font-weight: bold">head</span>>
|
||||
<<span style="color: #008000; font-weight: bold">body</span>>
|
||||
<<span style="color: #008000; font-weight: bold">canvas</span>></<span style="color: #008000; font-weight: bold">canvas</span>>
|
||||
<<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666666">=</span><span style="color: #BA2121">"filament.js"</span>></<span style="color: #008000; font-weight: bold">script</span>>
|
||||
<<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666666">=</span><span style="color: #BA2121">"//unpkg.com/gl-matrix@2.8.1"</span>></<span style="color: #008000; font-weight: bold">script</span>>
|
||||
<<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666666">=</span><span style="color: #BA2121">"triangle.js"</span>></<span style="color: #008000; font-weight: bold">script</span>>
|
||||
<<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666">=</span><span style="color: #BA2121">"filament.js"</span>></<span style="color: #008000; font-weight: bold">script</span>>
|
||||
<<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666">=</span><span style="color: #BA2121">"//unpkg.com/gl-matrix@2.8.1"</span>></<span style="color: #008000; font-weight: bold">script</span>>
|
||||
<<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666">=</span><span style="color: #BA2121">"triangle.js"</span>></<span style="color: #008000; font-weight: bold">script</span>>
|
||||
</<span style="color: #008000; font-weight: bold">body</span>>
|
||||
</<span style="color: #008000; font-weight: bold">html</span>>
|
||||
</pre></div>
|
||||
@@ -48,63 +48,63 @@ a mobile-friendly page with a full-screen canvas.</p>
|
||||
<li><code>triangle.js</code> will contain your application code.</li>
|
||||
</ul>
|
||||
<p>Go ahead and create <code>triangle.js</code> with the following content.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">class</span><span style="color: #bbbbbb"> </span>App<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">constructor</span>()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create entities</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.render<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">'resize'</span>,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.resize);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>render()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: render scene</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>resize()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: adjust viewport and canvas</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
|
||||
}<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">class</span><span style="color: #BBB"> </span>App<span style="color: #BBB"> </span>{
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">constructor</span>()<span style="color: #BBB"> </span>{
|
||||
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: create entities</span>
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.render<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">'resize'</span>,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.resize);
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||
<span style="color: #BBB"> </span>}
|
||||
<span style="color: #BBB"> </span>render()<span style="color: #BBB"> </span>{
|
||||
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: render scene</span>
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||
<span style="color: #BBB"> </span>}
|
||||
<span style="color: #BBB"> </span>resize()<span style="color: #BBB"> </span>{
|
||||
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: adjust viewport and canvas</span>
|
||||
<span style="color: #BBB"> </span>}
|
||||
}
|
||||
|
||||
Filament.init([<span style="color: #BA2121">'triangle.filamat'</span>],<span style="color: #bbbbbb"> </span>()<span style="color: #bbbbbb"> </span>=><span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.app<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span>App()<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"> </span>);<span style="color: #bbbbbb"></span>
|
||||
Filament.init([<span style="color: #BA2121">'triangle.filamat'</span>],<span style="color: #BBB"> </span>()<span style="color: #BBB"> </span>=><span style="color: #BBB"> </span>{<span style="color: #BBB"> </span><span style="color: #008000">window</span>.app<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span>App()<span style="color: #BBB"> </span>}<span style="color: #BBB"> </span>);
|
||||
</pre></div>
|
||||
|
||||
<p>The two calls to <code>bind()</code> allow us to pass instance methods as callbacks for animation and resize
|
||||
events.</p>
|
||||
<p><code>Filament.init()</code> consumes two things: a list of asset URLs and a callback.</p>
|
||||
<p>The callback will be triggered only after all assets finish downloading and the Filament module has
|
||||
become ready. In our callback, we simply instantiated the <code>App</code> object, since we'll do most of the
|
||||
become ready. In our callback, we simply instantiated the <code>App</code> object, since we'll do most of the
|
||||
work in its constructor. We also set the app instance into a <code>Window</code> property to make it accessible
|
||||
from the developer console.</p>
|
||||
<p>Go ahead and download <a href="triangle.filamat">triangle.filamat</a> and place it in your project folder.
|
||||
This is a <em>material package</em>, which is a binary file that contains shaders and other bits of data
|
||||
that define a PBR material. We'll learn more about material packages in the next tutorial.</p>
|
||||
that define a PBR material. We'll learn more about material packages in the next tutorial.</p>
|
||||
<h2>Spawn a local server</h2>
|
||||
<p>Because of CORS restrictions, your web app cannot fetch the material package directly from the
|
||||
file system. One way around this is to create a temporary server using Python or node:</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>python3 -m http.server <span style="color: #3D7B7B; font-style: italic"># Python 3</span>
|
||||
python -m SimpleHTTPServer <span style="color: #3D7B7B; font-style: italic"># Python 2.7</span>
|
||||
npx http-server -p <span style="color: #666666">8000</span> <span style="color: #3D7B7B; font-style: italic"># nodejs</span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>python3<span style="color: #BBB"> </span>-m<span style="color: #BBB"> </span>http.server<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic"># Python 3</span>
|
||||
python<span style="color: #BBB"> </span>-m<span style="color: #BBB"> </span>SimpleHTTPServer<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic"># Python 2.7</span>
|
||||
npx<span style="color: #BBB"> </span>http-server<span style="color: #BBB"> </span>-p<span style="color: #BBB"> </span><span style="color: #666">8000</span><span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic"># nodejs</span>
|
||||
</pre></div>
|
||||
|
||||
<p>To see if this works, navigate to <a href="http://localhost:8000">http://localhost:8000</a> and check if you
|
||||
can load the page without any errors appearing in the developer console.</p>
|
||||
<p>Take care not to use Python's simple server in production since it does not serve WebAssembly files
|
||||
<p>Take care not to use Python's simple server in production since it does not serve WebAssembly files
|
||||
with the correct MIME type.</p>
|
||||
<h2>Create the Engine and Scene</h2>
|
||||
<p>We now have a basic skeleton that can respond to paint and resize events. Let's start adding
|
||||
<p>We now have a basic skeleton that can respond to paint and resize events. Let's start adding
|
||||
Filament objects to the app. Insert the following code into the top of the app constructor.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.canvas<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">'canvas'</span>)[<span style="color: #666666">0</span>];<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>engine<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Engine.create(<span style="color: #008000; font-weight: bold">this</span>.canvas);<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.canvas<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">'canvas'</span>)[<span style="color: #666">0</span>];
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>engine<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Engine.create(<span style="color: #008000; font-weight: bold">this</span>.canvas);
|
||||
</pre></div>
|
||||
|
||||
<p>The above snippet creates the <code>Engine</code> by passing it a canvas DOM object. The engine needs the
|
||||
canvas in order to create a WebGL 2.0 context in its contructor.</p>
|
||||
<p>The engine is a factory for many Filament entities, including <code>Scene</code>, which is a flat container of
|
||||
entities. Let's go ahead and create a scene, then add a blank entity called <code>triangle</code> into the
|
||||
entities. Let's go ahead and create a scene, then add a blank entity called <code>triangle</code> into the
|
||||
scene.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.scene<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createScene();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.triangle<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.EntityManager.get().create();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.scene.addEntity(<span style="color: #008000; font-weight: bold">this</span>.triangle);<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.scene<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createScene();
|
||||
<span style="color: #008000; font-weight: bold">this</span>.triangle<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.EntityManager.get().create();
|
||||
<span style="color: #008000; font-weight: bold">this</span>.scene.addEntity(<span style="color: #008000; font-weight: bold">this</span>.triangle);
|
||||
</pre></div>
|
||||
|
||||
<p>Filament uses an <a href="//en.wikipedia.org/wiki/Entity-component-system">Entity-Component System</a>.
|
||||
@@ -112,30 +112,30 @@ The triangle entity in the above snippet does not yet have an associated compone
|
||||
tutorial we will make it into a <em>renderable</em>. Renderables are entities that have associated draw
|
||||
calls.</p>
|
||||
<h2>Construct typed arrays</h2>
|
||||
<p>Next we'll create two typed arrays: a positions array with XY coordinates for each vertex, and a
|
||||
<p>Next we'll create two typed arrays: a positions array with XY coordinates for each vertex, and a
|
||||
colors array with a 32-bit word for each vertex.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>TRIANGLE_POSITIONS<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span><span style="color: #008000">Float32Array</span>([<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">Math</span>.cos(<span style="color: #008000">Math</span>.PI<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span><span style="color: #666666">2</span><span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">3</span>),<span style="color: #bbbbbb"> </span><span style="color: #008000">Math</span>.sin(<span style="color: #008000">Math</span>.PI<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span><span style="color: #666666">2</span><span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">3</span>),<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">Math</span>.cos(<span style="color: #008000">Math</span>.PI<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span><span style="color: #666666">4</span><span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">3</span>),<span style="color: #bbbbbb"> </span><span style="color: #008000">Math</span>.sin(<span style="color: #008000">Math</span>.PI<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span><span style="color: #666666">4</span><span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">3</span>),<span style="color: #bbbbbb"></span>
|
||||
]);<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>TRIANGLE_POSITIONS<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span><span style="color: #008000">Float32Array</span>([
|
||||
<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">Math</span>.cos(<span style="color: #008000">Math</span>.PI<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span><span style="color: #666">2</span><span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">3</span>),<span style="color: #BBB"> </span><span style="color: #008000">Math</span>.sin(<span style="color: #008000">Math</span>.PI<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span><span style="color: #666">2</span><span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">3</span>),
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">Math</span>.cos(<span style="color: #008000">Math</span>.PI<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span><span style="color: #666">4</span><span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">3</span>),<span style="color: #BBB"> </span><span style="color: #008000">Math</span>.sin(<span style="color: #008000">Math</span>.PI<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span><span style="color: #666">4</span><span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">3</span>),
|
||||
]);
|
||||
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>TRIANGLE_COLORS<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span><span style="color: #008000">Uint32Array</span>([<span style="color: #666666">0xffff0000</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0xff00ff00</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0xff0000ff</span>]);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>TRIANGLE_COLORS<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span><span style="color: #008000">Uint32Array</span>([<span style="color: #666">0xffff0000</span>,<span style="color: #BBB"> </span><span style="color: #666">0xff00ff00</span>,<span style="color: #BBB"> </span><span style="color: #666">0xff0000ff</span>]);
|
||||
</pre></div>
|
||||
|
||||
<p>Next we'll use the positions and colors buffers to create a single <code>VertexBuffer</code> object.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>VertexAttribute<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.VertexAttribute;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>AttributeType<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.VertexBuffer$AttributeType;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.vb<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.VertexBuffer.Builder()<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.vertexCount(<span style="color: #666666">3</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.bufferCount(<span style="color: #666666">2</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.attribute(VertexAttribute.POSITION,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>AttributeType.FLOAT2,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">8</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.attribute(VertexAttribute.COLOR,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span>AttributeType.UBYTE4,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">4</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.normalized(VertexAttribute.COLOR)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
|
||||
<p>Next we'll use the positions and colors buffers to create a single <code>VertexBuffer</code> object.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>VertexAttribute<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.VertexAttribute;
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>AttributeType<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.VertexBuffer$AttributeType;
|
||||
<span style="color: #008000; font-weight: bold">this</span>.vb<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.VertexBuffer.Builder()
|
||||
<span style="color: #BBB"> </span>.vertexCount(<span style="color: #666">3</span>)
|
||||
<span style="color: #BBB"> </span>.bufferCount(<span style="color: #666">2</span>)
|
||||
<span style="color: #BBB"> </span>.attribute(VertexAttribute.POSITION,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>AttributeType.FLOAT2,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">8</span>)
|
||||
<span style="color: #BBB"> </span>.attribute(VertexAttribute.COLOR,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span>AttributeType.UBYTE4,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">4</span>)
|
||||
<span style="color: #BBB"> </span>.normalized(VertexAttribute.COLOR)
|
||||
<span style="color: #BBB"> </span>.build(engine);
|
||||
|
||||
<span style="color: #008000; font-weight: bold">this</span>.vb.setBufferAt(engine,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>TRIANGLE_POSITIONS);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.vb.setBufferAt(engine,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span>TRIANGLE_COLORS);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.vb.setBufferAt(engine,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>TRIANGLE_POSITIONS);
|
||||
<span style="color: #008000; font-weight: bold">this</span>.vb.setBufferAt(engine,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span>TRIANGLE_COLORS);
|
||||
</pre></div>
|
||||
|
||||
<p>The above snippet first creates aliases for two enum types, then constructs the vertex buffer using
|
||||
@@ -147,74 +147,74 @@ self-documenting.</p>
|
||||
<p>Our app sets up two buffer slots in the vertex buffer, and each slot is associated with a single
|
||||
attribute. Alternatively, we could have interleaved or concatenated these attributes into a single
|
||||
buffer slot.</p>
|
||||
<p>Next we'll construct an index buffer. The index buffer for our triangle is trivial: it simply holds
|
||||
<p>Next we'll construct an index buffer. The index buffer for our triangle is trivial: it simply holds
|
||||
the integers 0,1,2.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.ib<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.IndexBuffer.Builder()<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.indexCount(<span style="color: #666666">3</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.bufferType(Filament.IndexBuffer$IndexType.USHORT)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine);<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.ib<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.IndexBuffer.Builder()
|
||||
<span style="color: #BBB"> </span>.indexCount(<span style="color: #666">3</span>)
|
||||
<span style="color: #BBB"> </span>.bufferType(Filament.IndexBuffer$IndexType.USHORT)
|
||||
<span style="color: #BBB"> </span>.build(engine);
|
||||
|
||||
<span style="color: #008000; font-weight: bold">this</span>.ib.setBuffer(engine,<span style="color: #bbbbbb"> </span><span style="color: #AA22FF; font-weight: bold">new</span><span style="color: #bbbbbb"> </span><span style="color: #008000">Uint16Array</span>([<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">2</span>]));<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.ib.setBuffer(engine,<span style="color: #BBB"> </span><span style="color: #A2F; font-weight: bold">new</span><span style="color: #BBB"> </span><span style="color: #008000">Uint16Array</span>([<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">2</span>]));
|
||||
</pre></div>
|
||||
|
||||
<p>Note that constructing an index buffer is similar to constructing a vertex buffer, but it only has
|
||||
one buffer slot, and it can only contain two types of data (USHORT or UINT).</p>
|
||||
<h2>Finish up initialization</h2>
|
||||
<p>Next let's construct an actual <code>Material</code> from the material package that was downloaded (the
|
||||
<p>Next let's construct an actual <code>Material</code> from the material package that was downloaded (the
|
||||
material is an object; the package is just a binary blob), then extract the default
|
||||
<code>MaterialInstance</code> from the material object. Material instances have concrete values for their
|
||||
parameters, and they can be bound to renderables. We'll learn more about material instances in the
|
||||
parameters, and they can be bound to renderables. We'll learn more about material instances in the
|
||||
next tutorial.</p>
|
||||
<p>After extracting the material instance, we can finally create a renderable component for the
|
||||
triangle by setting up a bounding box and passing in the vertex and index buffers.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>mat<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createMaterial(<span style="color: #BA2121">'triangle.filamat'</span>);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>matinst<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>mat.getDefaultInstance();<span style="color: #bbbbbb"></span>
|
||||
Filament.RenderableManager.Builder(<span style="color: #666666">1</span>)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.boundingBox({<span style="color: #bbbbbb"> </span>center<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">-1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">-1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">-1</span>],<span style="color: #bbbbbb"> </span>halfExtent<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>]<span style="color: #bbbbbb"> </span>})<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.material(<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>matinst)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.geometry(<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>Filament.RenderableManager$PrimitiveType.TRIANGLES,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.vb,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.ib)<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span>.build(engine,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.triangle);<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>mat<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createMaterial(<span style="color: #BA2121">'triangle.filamat'</span>);
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>matinst<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>mat.getDefaultInstance();
|
||||
Filament.RenderableManager.Builder(<span style="color: #666">1</span>)
|
||||
<span style="color: #BBB"> </span>.boundingBox({<span style="color: #BBB"> </span>center<span style="color: #666">:</span><span style="color: #BBB"> </span>[<span style="color: #666">-1</span>,<span style="color: #BBB"> </span><span style="color: #666">-1</span>,<span style="color: #BBB"> </span><span style="color: #666">-1</span>],<span style="color: #BBB"> </span>halfExtent<span style="color: #666">:</span><span style="color: #BBB"> </span>[<span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>]<span style="color: #BBB"> </span>})
|
||||
<span style="color: #BBB"> </span>.material(<span style="color: #666">0</span>,<span style="color: #BBB"> </span>matinst)
|
||||
<span style="color: #BBB"> </span>.geometry(<span style="color: #666">0</span>,<span style="color: #BBB"> </span>Filament.RenderableManager$PrimitiveType.TRIANGLES,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.vb,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.ib)
|
||||
<span style="color: #BBB"> </span>.build(engine,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.triangle);
|
||||
</pre></div>
|
||||
|
||||
<p>Next let's wrap up the initialization routine by creating the swap chain, renderer, camera, and
|
||||
<p>Next let's wrap up the initialization routine by creating the swap chain, renderer, camera, and
|
||||
view.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.swapChain<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createSwapChain();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.renderer<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createRenderer();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.camera<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createCamera(Filament.EntityManager.get().create());<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.view<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>engine.createView();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.view.setScene(<span style="color: #008000; font-weight: bold">this</span>.scene);<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">this</span>.swapChain<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createSwapChain();
|
||||
<span style="color: #008000; font-weight: bold">this</span>.renderer<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createRenderer();
|
||||
<span style="color: #008000; font-weight: bold">this</span>.camera<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createCamera(Filament.EntityManager.get().create());
|
||||
<span style="color: #008000; font-weight: bold">this</span>.view<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>engine.createView();
|
||||
<span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera);
|
||||
<span style="color: #008000; font-weight: bold">this</span>.view.setScene(<span style="color: #008000; font-weight: bold">this</span>.scene);
|
||||
|
||||
<span style="color: #3D7B7B; font-style: italic">// Set up a blue-green background:</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.renderer.setClearOptions({clearColor<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span>[<span style="color: #666666">0.0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0.2</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1.0</span>],<span style="color: #bbbbbb"> </span>clear<span style="color: #666666">:</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">true</span>});<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #3D7B7B; font-style: italic">// Set up a blue-green background:</span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.renderer.setClearOptions({clearColor<span style="color: #666">:</span><span style="color: #BBB"> </span>[<span style="color: #666">0.0</span>,<span style="color: #BBB"> </span><span style="color: #666">0.1</span>,<span style="color: #BBB"> </span><span style="color: #666">0.2</span>,<span style="color: #BBB"> </span><span style="color: #666">1.0</span>],<span style="color: #BBB"> </span>clear<span style="color: #666">:</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">true</span>});
|
||||
|
||||
<span style="color: #3D7B7B; font-style: italic">// Adjust the initial viewport:</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.resize();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #3D7B7B; font-style: italic">// Adjust the initial viewport:</span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.resize();
|
||||
</pre></div>
|
||||
|
||||
<p>At this point, we're done creating all Filament entities, and the code should run without errors.
|
||||
<p>At this point, we're done creating all Filament entities, and the code should run without errors.
|
||||
However the canvas is still blank!</p>
|
||||
<h2>Render and resize handlers</h2>
|
||||
<p>Recall that our App class has a skeletal render method, which the browser calls every time it needs
|
||||
to repaint. Often this is 60 times a second.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>render()<span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: render scene</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);<span style="color: #bbbbbb"></span>
|
||||
}<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>render()<span style="color: #BBB"> </span>{
|
||||
<span style="color: #BBB"> </span><span style="color: #3D7B7B; font-style: italic">// TODO: render scene</span>
|
||||
<span style="color: #BBB"> </span><span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
|
||||
}
|
||||
</pre></div>
|
||||
|
||||
<p>Let's flesh this out by rotating the triangle and invoking the Filament renderer. Add the following
|
||||
<p>Let's flesh this out by rotating the triangle and invoking the Filament renderer. Add the following
|
||||
code to the top of the render method.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic">// Rotate the triangle.</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>radians<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">Date</span>.now()<span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span><span style="color: #666666">1000</span>;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>transform<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>mat4.fromRotation(mat4.create(),<span style="color: #bbbbbb"> </span>radians,<span style="color: #bbbbbb"> </span>[<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>]);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>tcm<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.getTransformManager();<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>inst<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>tcm.getInstance(<span style="color: #008000; font-weight: bold">this</span>.triangle);<span style="color: #bbbbbb"></span>
|
||||
tcm.setTransform(inst,<span style="color: #bbbbbb"> </span>transform);<span style="color: #bbbbbb"></span>
|
||||
inst.<span style="color: #AA22FF; font-weight: bold">delete</span>();<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic">// Rotate the triangle.</span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>radians<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">Date</span>.now()<span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span><span style="color: #666">1000</span>;
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>transform<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>mat4.fromRotation(mat4.create(),<span style="color: #BBB"> </span>radians,<span style="color: #BBB"> </span>[<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>]);
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>tcm<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.engine.getTransformManager();
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>inst<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>tcm.getInstance(<span style="color: #008000; font-weight: bold">this</span>.triangle);
|
||||
tcm.setTransform(inst,<span style="color: #BBB"> </span>transform);
|
||||
inst.<span style="color: #A2F; font-weight: bold">delete</span>();
|
||||
|
||||
<span style="color: #3D7B7B; font-style: italic">// Render the frame.</span><span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain,<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.view);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #3D7B7B; font-style: italic">// Render the frame.</span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain,<span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.view);
|
||||
</pre></div>
|
||||
|
||||
<p>The first half of our render method obtains the transform component of the triangle entity and uses
|
||||
@@ -225,19 +225,19 @@ that it wants to skip a frame, hence the <code>if</code> statement.</p>
|
||||
<p>One last step. Add the following code to the resize method. This adjusts the resolution of the
|
||||
rendering surface when the window size changes, taking <code>devicePixelRatio</code> into account for high-DPI
|
||||
displays. It also adjusts the camera frustum accordingly.</p>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>dpr<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.devicePixelRatio;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>width<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.width<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.innerWidth<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span>dpr;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>height<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.height<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span><span style="color: #008000">window</span>.innerHeight<span style="color: #bbbbbb"> </span><span style="color: #666666">*</span><span style="color: #bbbbbb"> </span>dpr;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span>width,<span style="color: #bbbbbb"> </span>height]);<span style="color: #bbbbbb"></span>
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>dpr<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.devicePixelRatio;
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>width<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.width<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.innerWidth<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span>dpr;
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>height<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000; font-weight: bold">this</span>.canvas.height<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span><span style="color: #008000">window</span>.innerHeight<span style="color: #BBB"> </span><span style="color: #666">*</span><span style="color: #BBB"> </span>dpr;
|
||||
<span style="color: #008000; font-weight: bold">this</span>.view.setViewport([<span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span>width,<span style="color: #BBB"> </span>height]);
|
||||
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>aspect<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>width<span style="color: #bbbbbb"> </span><span style="color: #666666">/</span><span style="color: #bbbbbb"> </span>height;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #bbbbbb"> </span>Projection<span style="color: #bbbbbb"> </span><span style="color: #666666">=</span><span style="color: #bbbbbb"> </span>Filament.Camera$Projection;<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.camera.setProjection(Projection.ORTHO,<span style="color: #bbbbbb"> </span><span style="color: #666666">-</span>aspect,<span style="color: #bbbbbb"> </span>aspect,<span style="color: #bbbbbb"> </span><span style="color: #666666">-1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>,<span style="color: #bbbbbb"> </span><span style="color: #666666">1</span>);<span style="color: #bbbbbb"></span>
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>aspect<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>width<span style="color: #BBB"> </span><span style="color: #666">/</span><span style="color: #BBB"> </span>height;
|
||||
<span style="color: #008000; font-weight: bold">const</span><span style="color: #BBB"> </span>Projection<span style="color: #BBB"> </span><span style="color: #666">=</span><span style="color: #BBB"> </span>Filament.Camera$Projection;
|
||||
<span style="color: #008000; font-weight: bold">this</span>.camera.setProjection(Projection.ORTHO,<span style="color: #BBB"> </span><span style="color: #666">-</span>aspect,<span style="color: #BBB"> </span>aspect,<span style="color: #BBB"> </span><span style="color: #666">-1</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>,<span style="color: #BBB"> </span><span style="color: #666">0</span>,<span style="color: #BBB"> </span><span style="color: #666">1</span>);
|
||||
</pre></div>
|
||||
|
||||
<p>You should now have a spinning triangle! The completed JavaScript is available
|
||||
<a href="tutorial_triangle.js">here</a>.</p>
|
||||
<p>In the <a href="tutorial_redball.html">next tutorial</a>, we'll take a closer look at Filament materials and 3D rendering.</p>
|
||||
<p>In the <a href="tutorial_redball.html">next tutorial</a>, we'll take a closer look at Filament materials and 3D rendering.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -5,6 +5,18 @@ set(TARGET backend)
|
||||
set(PUBLIC_HDR_DIR include)
|
||||
set(GENERATION_ROOT ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# ==================================================================================================
|
||||
# Compilation options
|
||||
# ==================================================================================================
|
||||
#
|
||||
set(BACKEND_SANITIZATION "" CACHE STRING "Sanitization option")
|
||||
set_property(CACHE BACKEND_SANITIZATION PROPERTY STRINGS ";ASAN")
|
||||
|
||||
set(BACKEND_SANITIZERS)
|
||||
if (BACKEND_SANITIZATION STREQUAL "ASAN")
|
||||
set(BACKEND_SANITIZERS -fsanitize=address)
|
||||
endif()
|
||||
|
||||
# ==================================================================================================
|
||||
# Sources and headers
|
||||
# ==================================================================================================
|
||||
@@ -259,6 +271,8 @@ if (FILAMENT_SUPPORTS_WEBGPU)
|
||||
src/webgpu/WebGPUDriver.h
|
||||
src/webgpu/WebGPUHandles.cpp
|
||||
src/webgpu/WebGPUHandles.h
|
||||
src/webgpu/WebGPUPipelineCreation.cpp
|
||||
src/webgpu/WebGPUPipelineCreation.h
|
||||
src/webgpu/WebGPUSwapChain.cpp
|
||||
src/webgpu/WebGPUSwapChain.h
|
||||
src/webgpu/WGPUProgram.cpp
|
||||
@@ -470,6 +484,7 @@ target_compile_options(${TARGET} PRIVATE
|
||||
${OSMESA_COMPILE_FLAGS}
|
||||
$<$<CONFIG:Release>:${OPTIMIZATION_FLAGS}>
|
||||
$<$<AND:$<PLATFORM_ID:Darwin>,$<CONFIG:Release>>:${DARWIN_OPTIMIZATION_FLAGS}>
|
||||
${BACKEND_SANITIZERS}
|
||||
)
|
||||
|
||||
if (FILAMENT_SUPPORTS_METAL)
|
||||
@@ -480,6 +495,8 @@ if (FILAMENT_SUPPORTS_WEBGPU)
|
||||
target_compile_definitions(${TARGET} PRIVATE $<$<BOOL:${FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING}>:FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING>)
|
||||
endif()
|
||||
|
||||
target_link_options(${TARGET} PRIVATE ${BACKEND_SANITIZERS})
|
||||
|
||||
target_link_libraries(${TARGET} PRIVATE
|
||||
${OSMESA_LINKER_FLAGS}
|
||||
$<$<AND:$<PLATFORM_ID:Linux>,$<CONFIG:Release>>:${LINUX_LINKER_OPTIMIZATION_FLAGS}>
|
||||
@@ -549,6 +566,8 @@ if (APPLE AND NOT IOS)
|
||||
test/test_RenderExternalImage.cpp)
|
||||
add_library(backend_test STATIC ${BACKEND_TEST_SRC})
|
||||
target_link_libraries(backend_test PUBLIC ${BACKEND_TEST_LIBS})
|
||||
target_compile_options(backend_test PRIVATE ${BACKEND_SANITIZERS})
|
||||
target_link_options(backend_test PRIVATE ${BACKEND_SANITIZERS})
|
||||
|
||||
set(BACKEND_TEST_DEPS
|
||||
OSDependent
|
||||
@@ -587,6 +606,7 @@ if (APPLE AND NOT IOS)
|
||||
# linker from removing "unused" symbols.
|
||||
target_link_libraries(backend_test_mac PRIVATE -force_load backend_test)
|
||||
set_target_properties(backend_test_mac PROPERTIES FOLDER Tests)
|
||||
target_link_options(backend_test_mac PRIVATE ${BACKEND_SANITIZERS})
|
||||
|
||||
# This is needed after XCode 15.3
|
||||
set_target_properties(backend_test_mac PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
@@ -596,6 +616,8 @@ endif()
|
||||
|
||||
if (LINUX)
|
||||
add_executable(backend_test_linux test/linux_runner.cpp ${BACKEND_TEST_SRC})
|
||||
target_compile_options(backend_test_linux PRIVATE ${BACKEND_SANITIZERS})
|
||||
target_link_options(backend_test_linux PRIVATE ${BACKEND_SANITIZERS})
|
||||
target_link_libraries(backend_test_linux PRIVATE ${BACKEND_TEST_LIBS})
|
||||
set_target_properties(backend_test_linux PROPERTIES FOLDER Tests)
|
||||
endif()
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <utils/StaticString.h>
|
||||
|
||||
/**
|
||||
* Types and enums used by filament's driver.
|
||||
@@ -1139,6 +1140,7 @@ struct ExternalSamplerDatum {
|
||||
static_assert(sizeof(ExternalSamplerDatum) == 12);
|
||||
|
||||
struct DescriptorSetLayout {
|
||||
std::variant<utils::StaticString, utils::CString, std::monostate> label;
|
||||
utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings;
|
||||
|
||||
// TODO: uncomment when needed
|
||||
@@ -1455,6 +1457,11 @@ enum class Workaround : uint16_t {
|
||||
DISABLE_BLIT_INTO_TEXTURE_ARRAY,
|
||||
// Multiple workarounds needed for PowerVR GPUs
|
||||
POWER_VR_SHADER_WORKAROUNDS,
|
||||
// Some browsers, such as Firefox on Mac, struggle with slow shader compile/link times when
|
||||
// creating programs for the default material, leading to startup stutters. This workaround
|
||||
// prevents these stutters by not precaching depth variants of the default material for those
|
||||
// particular browsers.
|
||||
DISABLE_DEPTH_PRECACHE_FOR_DEFAULT_MATERIAL,
|
||||
};
|
||||
|
||||
using StereoscopicType = backend::Platform::StereoscopicType;
|
||||
|
||||
@@ -340,7 +340,7 @@ void OpenGLContext::setDefaultState() noexcept {
|
||||
GL_DITHER,
|
||||
GL_SAMPLE_ALPHA_TO_COVERAGE,
|
||||
GL_SAMPLE_COVERAGE,
|
||||
GL_POLYGON_OFFSET_FILL,
|
||||
GL_POLYGON_OFFSET_FILL,
|
||||
};
|
||||
|
||||
UTILS_NOUNROLL
|
||||
@@ -600,6 +600,12 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
|
||||
// For Mozilla, the issue appears to be observed regardless of whether the renderer is
|
||||
// ANGLE or not. (b/376125497)
|
||||
bugs->rebind_buffer_after_deletion = true;
|
||||
|
||||
// We disable depth precache for the default material on Mozilla FireFox. It struggles with
|
||||
// slow shader compile/link times if the shader contains large arrays of uniform. Some depth
|
||||
// program variants have skinning-related data, which incurs this slowness and end up
|
||||
// causing an initial startup stalls. (b/392917621)
|
||||
bugs->disable_depth_precache_for_default_material = true;
|
||||
}
|
||||
|
||||
#ifdef BACKEND_OPENGL_VERSION_GLES
|
||||
@@ -1069,41 +1075,41 @@ void OpenGLContext::resetState() noexcept {
|
||||
glCullFace(state.raster.cullFace);
|
||||
glBlendEquationSeparate(state.raster.blendEquationRGB, state.raster.blendEquationA);
|
||||
glBlendFuncSeparate(
|
||||
state.raster.blendFunctionSrcRGB,
|
||||
state.raster.blendFunctionSrcRGB,
|
||||
state.raster.blendFunctionDstRGB,
|
||||
state.raster.blendFunctionSrcA,
|
||||
state.raster.blendFunctionDstA
|
||||
);
|
||||
glColorMask(
|
||||
state.raster.colorMask,
|
||||
state.raster.colorMask,
|
||||
state.raster.colorMask,
|
||||
state.raster.colorMask,
|
||||
state.raster.colorMask,
|
||||
state.raster.colorMask,
|
||||
state.raster.colorMask
|
||||
);
|
||||
glDepthMask(state.raster.depthMask);
|
||||
glDepthFunc(state.raster.depthFunc);
|
||||
|
||||
|
||||
// state.stencil
|
||||
glStencilFuncSeparate(
|
||||
GL_FRONT,
|
||||
state.stencil.front.func.func,
|
||||
state.stencil.front.func.ref,
|
||||
GL_FRONT,
|
||||
state.stencil.front.func.func,
|
||||
state.stencil.front.func.ref,
|
||||
state.stencil.front.func.mask
|
||||
);
|
||||
glStencilFuncSeparate(
|
||||
GL_BACK,
|
||||
state.stencil.back.func.func,
|
||||
state.stencil.back.func.ref,
|
||||
GL_BACK,
|
||||
state.stencil.back.func.func,
|
||||
state.stencil.back.func.ref,
|
||||
state.stencil.back.func.mask
|
||||
);
|
||||
glStencilOpSeparate(
|
||||
GL_FRONT,
|
||||
GL_FRONT,
|
||||
state.stencil.front.op.sfail,
|
||||
state.stencil.front.op.dpfail,
|
||||
state.stencil.front.op.dppass
|
||||
);
|
||||
glStencilOpSeparate(
|
||||
GL_BACK,
|
||||
GL_BACK,
|
||||
state.stencil.back.op.sfail,
|
||||
state.stencil.back.op.dpfail,
|
||||
state.stencil.back.op.dppass
|
||||
@@ -1206,9 +1212,9 @@ void OpenGLContext::resetState() noexcept {
|
||||
|
||||
// state.window
|
||||
glScissor(
|
||||
state.window.scissor.x,
|
||||
state.window.scissor.y,
|
||||
state.window.scissor.z,
|
||||
state.window.scissor.x,
|
||||
state.window.scissor.y,
|
||||
state.window.scissor.z,
|
||||
state.window.scissor.w
|
||||
);
|
||||
glViewport(
|
||||
|
||||
@@ -328,6 +328,11 @@ public:
|
||||
// bugs or performance issues.
|
||||
bool force_feature_level0;
|
||||
|
||||
// Some browsers, such as Firefox on Mac, struggle with slow shader compile/link times when
|
||||
// creating programs for the default material, leading to startup stutters. This workaround
|
||||
// prevents these stutters by not precaching depth variants of the default material for
|
||||
// those particular browsers.
|
||||
bool disable_depth_precache_for_default_material;
|
||||
|
||||
} bugs = {};
|
||||
|
||||
@@ -569,6 +574,9 @@ private:
|
||||
{ bugs.force_feature_level0,
|
||||
"force_feature_level0",
|
||||
""},
|
||||
{ bugs.disable_depth_precache_for_default_material,
|
||||
"disable_depth_precache_for_default_material",
|
||||
""},
|
||||
}};
|
||||
|
||||
// this is chosen to minimize code size
|
||||
|
||||
@@ -2435,6 +2435,8 @@ bool OpenGLDriver::isWorkaroundNeeded(Workaround workaround) {
|
||||
return mContext.bugs.disable_blit_into_texture_array;
|
||||
case Workaround::POWER_VR_SHADER_WORKAROUNDS:
|
||||
return mContext.bugs.powervr_shader_workarounds;
|
||||
case Workaround::DISABLE_DEPTH_PRECACHE_FOR_DEFAULT_MATERIAL:
|
||||
return mContext.bugs.disable_depth_precache_for_default_material;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
@@ -66,71 +67,123 @@ namespace {
|
||||
};
|
||||
wgpu::ShaderModule module = device.CreateShaderModule(&descriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(module != nullptr) << "Failed to create " << descriptor.label;
|
||||
module.GetCompilationInfo(wgpu::CallbackMode::AllowSpontaneous,
|
||||
[&descriptor](auto const& status, wgpu::CompilationInfo const* info) {
|
||||
switch (status) {
|
||||
case wgpu::CompilationInfoRequestStatus::CallbackCancelled:
|
||||
FWGPU_LOGW << "Shader compilation info callback cancelled for "
|
||||
<< descriptor.label << "?" << utils::io::endl;
|
||||
return;
|
||||
case wgpu::CompilationInfoRequestStatus::Success:
|
||||
break;
|
||||
}
|
||||
if (info != nullptr) {
|
||||
std::stringstream errorStream;
|
||||
int errorCount = 0;
|
||||
for (size_t msgIndex = 0; msgIndex < info->messageCount; msgIndex++) {
|
||||
wgpu::CompilationMessage const& message = info->messages[msgIndex];
|
||||
switch (message.type) {
|
||||
case wgpu::CompilationMessageType::Info:
|
||||
FWGPU_LOGI << descriptor.label << ": " << message.message
|
||||
<< " line#:" << message.lineNum
|
||||
<< " linePos:" << message.linePos
|
||||
<< " offset:" << message.offset
|
||||
<< " length:" << message.length << utils::io::endl;
|
||||
break;
|
||||
case wgpu::CompilationMessageType::Warning:
|
||||
FWGPU_LOGW << "Warning compiling " << descriptor.label << ": "
|
||||
<< message.message << " line#:" << message.lineNum
|
||||
<< " linePos:" << message.linePos
|
||||
<< " offset:" << message.offset
|
||||
<< " length:" << message.length << utils::io::endl;
|
||||
break;
|
||||
case wgpu::CompilationMessageType::Error:
|
||||
errorCount++;
|
||||
errorStream << "Error " << errorCount << " : "
|
||||
<< std::string_view(message.message)
|
||||
<< " line#:" << message.lineNum
|
||||
<< " linePos:" << message.linePos
|
||||
<< " offset:" << message.offset
|
||||
<< " length:" << message.length << "\n";
|
||||
|
||||
wgpu::Instance instance = device.GetAdapter().GetInstance();
|
||||
instance.WaitAny(
|
||||
module.GetCompilationInfo(wgpu::CallbackMode::WaitAnyOnly,
|
||||
[&descriptor](auto const& status,
|
||||
wgpu::CompilationInfo const* info) {
|
||||
switch (status) {
|
||||
case wgpu::CompilationInfoRequestStatus::CallbackCancelled:
|
||||
FWGPU_LOGW << "Shader compilation info callback cancelled for "
|
||||
<< descriptor.label << "?" << utils::io::endl;
|
||||
return;
|
||||
case wgpu::CompilationInfoRequestStatus::Success:
|
||||
break;
|
||||
}
|
||||
}
|
||||
FILAMENT_CHECK_POSTCONDITION(errorCount < 1)
|
||||
<< errorCount << " error(s) compiling " << descriptor.label << ":\n"
|
||||
<< errorStream.str();
|
||||
}
|
||||
FWGPU_LOGD << descriptor.label << " compiled successfully" << utils::io::endl;
|
||||
});
|
||||
if (info != nullptr) {
|
||||
std::stringstream errorStream;
|
||||
int errorCount = 0;
|
||||
for (size_t msgIndex = 0; msgIndex < info->messageCount; msgIndex++) {
|
||||
wgpu::CompilationMessage const& message = info->messages[msgIndex];
|
||||
switch (message.type) {
|
||||
case wgpu::CompilationMessageType::Info:
|
||||
FWGPU_LOGI << descriptor.label << ": " << message.message
|
||||
<< " line#:" << message.lineNum
|
||||
<< " linePos:" << message.linePos
|
||||
<< " offset:" << message.offset
|
||||
<< " length:" << message.length
|
||||
<< utils::io::endl;
|
||||
break;
|
||||
case wgpu::CompilationMessageType::Warning:
|
||||
FWGPU_LOGW
|
||||
<< "Warning compiling " << descriptor.label << ": "
|
||||
<< message.message << " line#:" << message.lineNum
|
||||
<< " linePos:" << message.linePos
|
||||
<< " offset:" << message.offset
|
||||
<< " length:" << message.length << utils::io::endl;
|
||||
break;
|
||||
case wgpu::CompilationMessageType::Error:
|
||||
errorCount++;
|
||||
errorStream << "Error " << errorCount << " : "
|
||||
<< std::string_view(message.message)
|
||||
<< " line#:" << message.lineNum
|
||||
<< " linePos:" << message.linePos
|
||||
<< " offset:" << message.offset
|
||||
<< " length:" << message.length << "\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
FILAMENT_CHECK_POSTCONDITION(errorCount < 1)
|
||||
<< errorCount << " error(s) compiling " << descriptor.label
|
||||
<< ":\n"
|
||||
<< errorStream.str();
|
||||
}
|
||||
FWGPU_LOGD << descriptor.label << " compiled successfully"
|
||||
<< utils::io::endl;
|
||||
}),
|
||||
UINT16_MAX);
|
||||
return module;
|
||||
}
|
||||
|
||||
// This is a 1 to 1 mapping of the ReservedSpecializationConstants enum in EngineEnums.h
|
||||
// The _hack is a workaround until https://issues.chromium.org/issues/42250586 is resolved
|
||||
// This workaround is the same one being used on the generateSpecializationConstant() function
|
||||
wgpu::StringView getSpecConstantStringId(uint32_t id) {
|
||||
switch (id) {
|
||||
case 0:
|
||||
return "0";// BACKEND_FEATURE_LEVEL_hack
|
||||
case 1:
|
||||
return "1";// CONFIG_MAX_INSTANCES_hack
|
||||
case 2:
|
||||
return "2";// ONFIG_STATIC_TEXTURE_TARGET_WORKAROUND_hack
|
||||
case 3:
|
||||
return "3";// CONFIG_SRGB_SWAPCHAIN_EMULATION_hack
|
||||
case 4:
|
||||
return "4";// CONFIG_FROXEL_BUFFER_HEIGHT_hack
|
||||
case 5:
|
||||
return "5";// CONFIG_POWER_VR_SHADER_WORKAROUNDS_hack
|
||||
case 6:
|
||||
return "6";// CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP_hack
|
||||
case 7:
|
||||
return "7";// CONFIG_DEBUG_FROXEL_VISUALIZATION_hack
|
||||
case 8:
|
||||
return "8";// CONFIG_STEREO_EYE_COUNT_hack
|
||||
case 9:
|
||||
return "9";// CONFIG_SH_BANDS_COUNT_hack
|
||||
case 10:
|
||||
return "10";// CONFIG_SHADOW_SAMPLING_METHOD_hack
|
||||
default:
|
||||
PANIC_POSTCONDITION("Unknown/unhandled spec constant key/id: %d", id);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<wgpu::ConstantEntry> convertConstants(
|
||||
utils::FixedCapacityVector<filament::backend::Program::SpecializationConstant> const&
|
||||
constantsInfo) {
|
||||
std::vector<wgpu::ConstantEntry> constants(constantsInfo.size());
|
||||
for (size_t i = 0; i < constantsInfo.size(); i++) {
|
||||
filament::backend::Program::SpecializationConstant const& specConstant = constantsInfo[i];
|
||||
wgpu::ConstantEntry& constantEntry = constants[i];
|
||||
constantEntry.key = wgpu::StringView(std::to_string(specConstant.id));
|
||||
if (auto* v = std::get_if<int32_t>(&specConstant.value)) {
|
||||
constantEntry.value = static_cast<double>(*v);
|
||||
} else if (auto* f = std::get_if<float>(&specConstant.value)) {
|
||||
constantEntry.value = static_cast<double>(*f);
|
||||
} else if (auto* b = std::get_if<bool>(&specConstant.value)) {
|
||||
constantEntry.value = *b ? 0.0 : 1.0;
|
||||
std::vector<wgpu::ConstantEntry> constants;
|
||||
constants.reserve(constantsInfo.size());
|
||||
for (filament::backend::Program::SpecializationConstant const& constant: constantsInfo) {
|
||||
// CONFIG_MAX_INSTANCES (1) and CONFIG_FROXEL_BUFFER_HEIGHT (4) will not be present
|
||||
// as constant overrides in the generated WGSL, because WGSL doesn't support specialization
|
||||
// constants as an array length
|
||||
// More information at https://github.com/gpuweb/gpuweb/issues/572#issuecomment-649760005
|
||||
// CONFIG_SRGB_SWAPCHAIN_EMULATION (3) is being skipped all together since it's only
|
||||
// included for the case of mFeatureLevel == FeatureLevel::FEATURE_LEVEL_0, which should
|
||||
// not be possible for WebGPU
|
||||
if (constant.id == 1 || constant.id == 3 || constant.id == 4) {
|
||||
continue;
|
||||
}
|
||||
double value = 0.0;
|
||||
if (auto* v = std::get_if<int32_t>(&constant.value)) {
|
||||
value = static_cast<double>(*v);
|
||||
} else if (auto* f = std::get_if<float>(&constant.value)) {
|
||||
value = static_cast<double>(*f);
|
||||
} else if (auto* b = std::get_if<bool>(&constant.value)) {
|
||||
value = *b ? 0.0 : 1.0;
|
||||
}
|
||||
constants.push_back(
|
||||
wgpu::ConstantEntry{ .key = getSpecConstantStringId(constant.id), .value = value });
|
||||
}
|
||||
return constants;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "webgpu/WebGPUDriver.h"
|
||||
|
||||
#include "WebGPUPipelineCreation.h"
|
||||
#include "WebGPUSwapChain.h"
|
||||
#include <backend/platforms/WebGPUPlatform.h>
|
||||
|
||||
@@ -24,18 +25,20 @@
|
||||
#include "private/backend/Dispatcher.h"
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/Handle.h>
|
||||
#include <backend/TargetBufferInfo.h>
|
||||
|
||||
#include <math/mat3.h>
|
||||
#include <utils/CString.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#include <dawn/webgpu_cpp_print.h>
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
@@ -289,7 +292,22 @@ void WebGPUDriver::endFrame(uint32_t frameId) {
|
||||
void WebGPUDriver::flush(int) {
|
||||
}
|
||||
|
||||
void WebGPUDriver::finish(int) {
|
||||
void WebGPUDriver::finish(int /* dummy */) {
|
||||
if (mCommandEncoder != nullptr) {
|
||||
// submit the command buffer thus far...
|
||||
assert_invariant(mRenderPassEncoder == nullptr);
|
||||
wgpu::CommandBufferDescriptor commandBufferDescriptor{
|
||||
.label = "command_buffer",
|
||||
};
|
||||
mCommandBuffer = mCommandEncoder.Finish(&commandBufferDescriptor);
|
||||
assert_invariant(mCommandBuffer);
|
||||
mQueue.Submit(1, &mCommandBuffer);
|
||||
mCommandBuffer = nullptr;
|
||||
// create a new command buffer encoder to continue recording the next command for frame...
|
||||
wgpu::CommandEncoderDescriptor commandEncoderDescriptor = { .label = "command_encoder" };
|
||||
mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
|
||||
assert_invariant(mCommandEncoder);
|
||||
}
|
||||
}
|
||||
|
||||
void WebGPUDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
||||
@@ -371,9 +389,7 @@ Handle<HwTexture> WebGPUDriver::createTextureS() noexcept {
|
||||
return allocHandle<WGPUTexture>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> WebGPUDriver::importTextureS() noexcept {
|
||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
||||
}
|
||||
Handle<HwTexture> WebGPUDriver::importTextureS() noexcept { return allocHandle<WGPUTexture>(); }
|
||||
|
||||
Handle<HwProgram> WebGPUDriver::createProgramS() noexcept {
|
||||
return allocHandle<WGPUProgram>();
|
||||
@@ -392,7 +408,7 @@ Handle<HwIndexBuffer> WebGPUDriver::createIndexBufferS() noexcept {
|
||||
}
|
||||
|
||||
Handle<HwTexture> WebGPUDriver::createTextureViewS() noexcept {
|
||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
||||
return allocHandle<WGPUTexture>();
|
||||
}
|
||||
|
||||
Handle<HwBufferObject> WebGPUDriver::createBufferObjectS() noexcept {
|
||||
@@ -420,7 +436,7 @@ Handle<HwVertexBufferInfo> WebGPUDriver::createVertexBufferInfoS() noexcept {
|
||||
}
|
||||
|
||||
Handle<HwTexture> WebGPUDriver::createTextureViewSwizzleS() noexcept {
|
||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
||||
return allocHandle<WGPUTexture>();
|
||||
}
|
||||
|
||||
Handle<HwRenderTarget> WebGPUDriver::createDefaultRenderTargetS() noexcept {
|
||||
@@ -432,15 +448,15 @@ Handle<HwDescriptorSetLayout> WebGPUDriver::createDescriptorSetLayoutS() noexcep
|
||||
}
|
||||
|
||||
Handle<HwTexture> WebGPUDriver::createTextureExternalImageS() noexcept {
|
||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
||||
return allocHandle<WGPUTexture>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> WebGPUDriver::createTextureExternalImage2S() noexcept {
|
||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
||||
return allocHandle<WGPUTexture>();
|
||||
}
|
||||
|
||||
Handle<HwTexture> WebGPUDriver::createTextureExternalImagePlaneS() noexcept {
|
||||
return Handle<HwTexture>((Handle<HwTexture>::HandleId) mNextFakeHandle++);
|
||||
return allocHandle<WGPUTexture>();
|
||||
}
|
||||
|
||||
void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
|
||||
@@ -452,6 +468,8 @@ void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
|
||||
mSwapChain = constructHandle<WebGPUSwapChain>(sch, std::move(surface), surfaceSize, mAdapter,
|
||||
mDevice, flags);
|
||||
assert_invariant(mSwapChain);
|
||||
WebGPUDescriptorSet::initializeDummyResourcesIfNotAlready(mDevice,
|
||||
mSwapChain->getColorFormat());
|
||||
FWGPU_LOGW << "WebGPU support is still essentially a no-op at this point in development (only "
|
||||
"background components have been instantiated/selected, such as surface/screen, "
|
||||
"graphics device/GPU, etc.), thus nothing is being drawn to the screen."
|
||||
@@ -494,30 +512,46 @@ void WebGPUDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byte
|
||||
|
||||
void WebGPUDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
||||
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
|
||||
TextureUsage usage) {}
|
||||
TextureUsage usage) {
|
||||
constructHandle<WGPUTexture>(th, target, levels, format, samples, w, h, depth, usage, mDevice);
|
||||
}
|
||||
|
||||
void WebGPUDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||
uint8_t baseLevel, uint8_t levelCount) {}
|
||||
uint8_t baseLevel, uint8_t levelCount) {
|
||||
auto source = handleCast<WGPUTexture>(srch);
|
||||
|
||||
constructHandle<WGPUTexture>(th, source, baseLevel, levelCount);
|
||||
}
|
||||
|
||||
void WebGPUDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
|
||||
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
|
||||
backend::TextureSwizzle a) {}
|
||||
backend::TextureSwizzle a) {
|
||||
PANIC_POSTCONDITION("Swizzle WebGPU Texture is not supported");
|
||||
}
|
||||
|
||||
void WebGPUDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::SamplerType target,
|
||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
Platform::ExternalImageHandleRef externalImage) {}
|
||||
Platform::ExternalImageHandleRef externalImage) {
|
||||
PANIC_POSTCONDITION("External WebGPU Texture is not supported");
|
||||
}
|
||||
|
||||
void WebGPUDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
|
||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
void* externalImage) {}
|
||||
void* externalImage) {
|
||||
PANIC_POSTCONDITION("External WebGPU Texture is not supported");
|
||||
}
|
||||
|
||||
void WebGPUDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
||||
void* image, uint32_t plane) {}
|
||||
void* image, uint32_t plane) {
|
||||
PANIC_POSTCONDITION("External WebGPU Texture is not supported");
|
||||
}
|
||||
|
||||
void WebGPUDriver::importTextureR(Handle<HwTexture> th, intptr_t id, SamplerType target,
|
||||
uint8_t levels, TextureFormat format, uint8_t samples, uint32_t w, uint32_t h,
|
||||
uint32_t depth, TextureUsage usage) {}
|
||||
uint32_t depth, TextureUsage usage) {
|
||||
PANIC_POSTCONDITION("Import WebGPU Texture is not supported");
|
||||
}
|
||||
|
||||
void WebGPUDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph, Handle<HwVertexBuffer> vbh,
|
||||
Handle<HwIndexBuffer> ibh, PrimitiveType pt) {
|
||||
@@ -557,7 +591,7 @@ void WebGPUDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh
|
||||
void WebGPUDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
|
||||
Handle<HwDescriptorSetLayout> dslh) {
|
||||
auto layout = handleCast<WebGPUDescriptorSetLayout>(dslh);
|
||||
constructHandle<WebGPUDescriptorSet>(dsh, layout->getLayout(), layout->getLayoutSize());
|
||||
constructHandle<WebGPUDescriptorSet>(dsh, layout->getLayout(), layout->getBindGroupEntries());
|
||||
}
|
||||
|
||||
Handle<HwStream> WebGPUDriver::createStreamNative(void* nativeStream) {
|
||||
@@ -594,7 +628,7 @@ FenceStatus WebGPUDriver::getFenceStatus(Handle<HwFence> fh) {
|
||||
// We create all textures using VK_IMAGE_TILING_OPTIMAL, so our definition of "supported" is that
|
||||
// the GPU supports the given texture format with non-zero optimal tiling features.
|
||||
bool WebGPUDriver::isTextureFormatSupported(TextureFormat format) {
|
||||
return true;
|
||||
return WGPUTexture::fToWGPUTextureFormat(format) != wgpu::TextureFormat::Undefined;
|
||||
}
|
||||
|
||||
bool WebGPUDriver::isTextureSwizzleSupported() {
|
||||
@@ -742,13 +776,31 @@ void WebGPUDriver::compilePrograms(CompilerPriorityQueue priority,
|
||||
}
|
||||
}
|
||||
|
||||
void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassParams& params) {
|
||||
wgpu::CommandEncoderDescriptor commandEncoderDescriptor = {
|
||||
.label = "command_encoder"
|
||||
};
|
||||
mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
|
||||
void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> rth, RenderPassParams const& params) {
|
||||
assert_invariant(mCommandEncoder);
|
||||
|
||||
auto* renderTarget = handleCast<WGPURenderTarget>(rth);
|
||||
// if (renderTarget == mDefaultRenderTarget) {
|
||||
// FWGPU_LOGW << "Default render target"
|
||||
// << utils::io::endl;
|
||||
// } else {
|
||||
// FWGPU_LOGW << "Non Default render target"
|
||||
// << utils::io::endl;
|
||||
// }
|
||||
wgpu::RenderPassDescriptor renderPassDescriptor2;
|
||||
wgpu::RenderPassDepthStencilAttachment depthStencilAttachment{
|
||||
.view = mSwapChain->getDepthTextureView(),
|
||||
.depthLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::DEPTH),
|
||||
.depthStoreOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::DEPTH),
|
||||
.depthClearValue = static_cast<float>(params.clearDepth),
|
||||
.depthReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH) > 0,
|
||||
.stencilLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::STENCIL),
|
||||
.stencilStoreOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::STENCIL),
|
||||
.stencilClearValue = params.clearStencil,
|
||||
.stencilReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_STENCIL) > 0
|
||||
};
|
||||
renderTarget->setUpRenderPassAttachments(renderPassDescriptor2, mTextureView, params);
|
||||
renderPassDescriptor2.depthStencilAttachment = &depthStencilAttachment;
|
||||
// TODO: Remove this code once WebGPU pipeline is implemented
|
||||
static float red = 1.0f;
|
||||
if (red - 0.01 > 0) {
|
||||
@@ -773,19 +825,14 @@ void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
.timestampWrites = nullptr,
|
||||
};
|
||||
|
||||
mRenderPassEncoder = mCommandEncoder.BeginRenderPass(&renderPassDescriptor);
|
||||
mRenderPassEncoder = mCommandEncoder.BeginRenderPass(&renderPassDescriptor2);
|
||||
mRenderPassEncoder.SetViewport(params.viewport.left, params.viewport.bottom,
|
||||
params.viewport.width, params.viewport.height, params.depthRange.near, params.depthRange.far);
|
||||
}
|
||||
|
||||
void WebGPUDriver::endRenderPass(int) {
|
||||
void WebGPUDriver::endRenderPass(int /* dummy */) {
|
||||
mRenderPassEncoder.End();
|
||||
mRenderPassEncoder = nullptr;
|
||||
wgpu::CommandBufferDescriptor commandBufferDescriptor {
|
||||
.label = "command_buffer",
|
||||
};
|
||||
mCommandBuffer = mCommandEncoder.Finish(&commandBufferDescriptor);
|
||||
assert_invariant(mCommandBuffer);
|
||||
}
|
||||
|
||||
void WebGPUDriver::nextSubpass(int) {
|
||||
@@ -800,9 +847,19 @@ void WebGPUDriver::makeCurrent(Handle<HwSwapChain> drawSch, Handle<HwSwapChain>
|
||||
wgpu::Extent2D surfaceSize = mPlatform.getSurfaceExtent(mNativeWindow);
|
||||
mTextureView = mSwapChain->getCurrentSurfaceTextureView(surfaceSize);
|
||||
assert_invariant(mTextureView);
|
||||
wgpu::CommandEncoderDescriptor commandEncoderDescriptor = {
|
||||
.label = "command_encoder"
|
||||
};
|
||||
mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
|
||||
assert_invariant(mCommandEncoder);
|
||||
}
|
||||
|
||||
void WebGPUDriver::commit(Handle<HwSwapChain> sch) {
|
||||
wgpu::CommandBufferDescriptor commandBufferDescriptor{
|
||||
.label = "command_buffer",
|
||||
};
|
||||
mCommandBuffer = mCommandEncoder.Finish(&commandBufferDescriptor);
|
||||
assert_invariant(mCommandBuffer);
|
||||
mCommandEncoder = nullptr;
|
||||
mQueue.Submit(1, &mCommandBuffer);
|
||||
mCommandBuffer = nullptr;
|
||||
@@ -859,6 +916,44 @@ void WebGPUDriver::blit(
|
||||
}
|
||||
|
||||
void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
|
||||
const auto* program = handleCast<WGPUProgram>(pipelineState.program);
|
||||
assert_invariant(program);
|
||||
assert_invariant(program->computeShaderModule == nullptr &&
|
||||
"WebGPU backend does not (yet) support compute pipelines.");
|
||||
FILAMENT_CHECK_POSTCONDITION(program->vertexShaderModule)
|
||||
<< "WebGPU backend requires a vertex shader module for a render pipeline";
|
||||
std::array<wgpu::BindGroupLayout, MAX_DESCRIPTOR_SET_COUNT> bindGroupLayouts{};
|
||||
assert_invariant(bindGroupLayouts.size() >= pipelineState.pipelineLayout.setLayout.size());
|
||||
size_t bindGroupLayoutCount = 0;
|
||||
for (size_t i = 0; i < bindGroupLayouts.size(); i++) {
|
||||
const auto handle = pipelineState.pipelineLayout.setLayout[bindGroupLayoutCount];
|
||||
if (handle.getId() == HandleBase::nullid) {
|
||||
continue;
|
||||
}
|
||||
bindGroupLayouts[bindGroupLayoutCount++] =
|
||||
handleCast<WebGPUDescriptorSetLayout>(handle)->getLayout();
|
||||
}
|
||||
std::stringstream layoutLabelStream;
|
||||
layoutLabelStream << program->name.c_str() << " layout";
|
||||
const auto layoutLabel = layoutLabelStream.str();
|
||||
const wgpu::PipelineLayoutDescriptor layoutDescriptor{
|
||||
.label = wgpu::StringView(layoutLabel),
|
||||
.bindGroupLayoutCount = bindGroupLayoutCount,
|
||||
.bindGroupLayouts = bindGroupLayouts.data()
|
||||
// TODO investigate immediateDataRangeByteSize
|
||||
};
|
||||
const wgpu::PipelineLayout layout = mDevice.CreatePipelineLayout(&layoutDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(layout)
|
||||
<< "Failed to create wgpu::PipelineLayout for render pipeline for "
|
||||
<< layoutDescriptor.label;
|
||||
auto const* vertexBufferInfo = handleCast<WGPUVertexBufferInfo>(pipelineState.vertexBufferInfo);
|
||||
assert_invariant(vertexBufferInfo);
|
||||
const wgpu::RenderPipeline pipeline = createWebGPURenderPipeline(mDevice, *program,
|
||||
*vertexBufferInfo, layout, pipelineState.rasterState, pipelineState.stencilState,
|
||||
pipelineState.polygonOffset, pipelineState.primitiveType, mSwapChain->getColorFormat(),
|
||||
mSwapChain->getDepthFormat());
|
||||
// TODO: uncomment once we have a valid pipeline to set
|
||||
mRenderPassEncoder.SetPipeline(pipeline);
|
||||
}
|
||||
|
||||
void WebGPUDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
||||
@@ -878,10 +973,18 @@ void WebGPUDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
||||
}
|
||||
|
||||
void WebGPUDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
|
||||
// Calling DrawIndexed with "firstInstance = 0" results in a NON spinning triangle
|
||||
// mRenderPassEncoder.DrawIndexed(indexCount, instanceCount, indexOffset, 0, 0);
|
||||
// Calling DrawIndexed with "firstInstance = 1" results in a spinning triangle
|
||||
mRenderPassEncoder.DrawIndexed(indexCount, instanceCount, indexOffset, 0, 1);
|
||||
// Calling Draw with "firstInstance = 0" results in a NON spinning triangle
|
||||
// Calling Draw with "firstInstance = 1" results in a spinning triangle
|
||||
// mRenderPassEncoder.Draw(indexCount, instanceCount, 0, 1);
|
||||
}
|
||||
|
||||
void WebGPUDriver::draw(PipelineState pipelineState, Handle<HwRenderPrimitive> rph,
|
||||
uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
|
||||
void WebGPUDriver::draw(PipelineState, Handle<HwRenderPrimitive>, uint32_t indexOffset,
|
||||
uint32_t indexCount, uint32_t instanceCount) {
|
||||
draw2(indexOffset, indexCount, instanceCount);
|
||||
}
|
||||
|
||||
void WebGPUDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGroupCount) {
|
||||
@@ -917,34 +1020,156 @@ void WebGPUDriver::updateDescriptorSetBuffer(Handle<HwDescriptorSet> dsh,
|
||||
|
||||
void WebGPUDriver::updateDescriptorSetTexture(Handle<HwDescriptorSet> dsh,
|
||||
backend::descriptor_binding_t binding, Handle<HwTexture> th, SamplerParams params) {
|
||||
/*
|
||||
auto bindGroup = handleCast<WebGPUDescriptorSet>(dsh);
|
||||
auto texture = handleCast<WGPUTexture>(th);
|
||||
|
||||
// TODO very high odds badd assumptions are in here about handling HwTexture. Revisit with more
|
||||
// understanding. Right now assuming there is a wgpu::TextureView filled in
|
||||
if (!bindGroup->getIsLocked()) {
|
||||
// Dawn will cache duplicate samplers, so we don't strictly need to maintain a cache.
|
||||
// Making a cache might save us minor perf by reducing param translation
|
||||
auto sampler = makeSampler(params);
|
||||
// TODO making assumptions that size and offset mean the same thing here.
|
||||
wgpu::BindGroupEntry tEntry{ .binding = static_cast<uint32_t>(binding * 2),
|
||||
.textureView = texture->texView };
|
||||
.textureView = texture->getTexView() };
|
||||
bindGroup->addEntry(tEntry.binding, std::move(tEntry));
|
||||
|
||||
wgpu::BindGroupEntry sEntry{ .binding = static_cast<uint32_t>(binding * 2 + 1),
|
||||
.sampler = texture->sampler };
|
||||
.sampler = sampler };
|
||||
bindGroup->addEntry(sEntry.binding, std::move(sEntry));
|
||||
}
|
||||
//TODO Just the setup, this function stilll needs the rest of logic implemented
|
||||
*/
|
||||
}
|
||||
|
||||
void WebGPUDriver::bindDescriptorSet(Handle<HwDescriptorSet> dsh, backend::descriptor_set_t set,
|
||||
backend::DescriptorSetOffsetArray&& offsets) {
|
||||
auto bindGroup = handleCast<WebGPUDescriptorSet>(dsh);
|
||||
// TODO: presume we need this, use it. Probably Encoder::SetBindGroup
|
||||
auto wbg = bindGroup->lockAndReturn(mDevice);
|
||||
void WebGPUDriver::bindDescriptorSet(Handle<HwDescriptorSet> dsh,
|
||||
backend::descriptor_set_t setIndex, backend::DescriptorSetOffsetArray&& offsets) {
|
||||
const auto bindGroup = handleCast<WebGPUDescriptorSet>(dsh);
|
||||
const auto wbg = bindGroup->lockAndReturn(mDevice);
|
||||
assert_invariant(mRenderPassEncoder);
|
||||
// TODO is this how we should be getting the dynamic offsets?
|
||||
// should we add offsets for unused entries or is the input already have them?
|
||||
// this implementation assumes unused entries are not provided, and adds dummy values.
|
||||
// The count also includes unused entities, as not doing so produces errors
|
||||
const size_t dynamicOffsetCount = bindGroup->countEntitiesWithDynamicOffsets();
|
||||
uint32_t const* const dynamicOffsetsWithUnused = bindGroup->setDynamicOffsets(offsets.data());
|
||||
mRenderPassEncoder.SetBindGroup(setIndex, wbg, dynamicOffsetCount, dynamicOffsetsWithUnused);
|
||||
}
|
||||
|
||||
void WebGPUDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
|
||||
}
|
||||
wgpu::Sampler WebGPUDriver::makeSampler(SamplerParams const& params) {
|
||||
wgpu::SamplerDescriptor desc;
|
||||
|
||||
desc.label = "TODO";
|
||||
desc.addressModeU = fWrapModeToWAddressMode(params.wrapS);
|
||||
desc.addressModeV = fWrapModeToWAddressMode(params.wrapR);
|
||||
desc.addressModeW = fWrapModeToWAddressMode(params.wrapT);
|
||||
switch (params.filterMag) {
|
||||
case SamplerMagFilter::NEAREST: {
|
||||
desc.magFilter = wgpu::FilterMode::Nearest;
|
||||
break;
|
||||
}
|
||||
case SamplerMagFilter::LINEAR: {
|
||||
desc.magFilter = wgpu::FilterMode::Linear;
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (params.filterMin) {
|
||||
case SamplerMinFilter::NEAREST: {
|
||||
desc.minFilter = wgpu::FilterMode::Nearest;
|
||||
// Metal Driver uses an explicit not-mipmapped value webgpu lacks. Nearest should
|
||||
// suffice
|
||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
||||
break;
|
||||
}
|
||||
case SamplerMinFilter::LINEAR: {
|
||||
desc.minFilter = wgpu::FilterMode::Linear;
|
||||
// Metal Driver uses an explicit not-mipmapped value webgpu lacks. Nearest should
|
||||
// suffice
|
||||
|
||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
||||
break;
|
||||
}
|
||||
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST: {
|
||||
desc.minFilter = wgpu::FilterMode::Nearest;
|
||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
||||
break;
|
||||
}
|
||||
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST: {
|
||||
desc.minFilter = wgpu::FilterMode::Linear;
|
||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
||||
|
||||
break;
|
||||
}
|
||||
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR: {
|
||||
desc.minFilter = wgpu::FilterMode::Nearest;
|
||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Linear;
|
||||
|
||||
break;
|
||||
}
|
||||
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR: {
|
||||
desc.minFilter = wgpu::FilterMode::Linear;
|
||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Linear;
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (params.compareFunc) {
|
||||
case SamplerCompareFunc::LE: {
|
||||
desc.compare = wgpu::CompareFunction::LessEqual;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::GE: {
|
||||
desc.compare = wgpu::CompareFunction::GreaterEqual;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::L: {
|
||||
desc.compare = wgpu::CompareFunction::Less;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::G: {
|
||||
desc.compare = wgpu::CompareFunction::Greater;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::E: {
|
||||
desc.compare = wgpu::CompareFunction::Equal;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::NE: {
|
||||
desc.compare = wgpu::CompareFunction::NotEqual;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::A: {
|
||||
desc.compare = wgpu::CompareFunction::Always;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::N: {
|
||||
desc.compare = wgpu::CompareFunction::Never;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
desc.maxAnisotropy = 1u << params.anisotropyLog2;
|
||||
|
||||
|
||||
// Unused: Filament's compareMode, WGPU lodMinClamp/lodMaxClamp
|
||||
|
||||
//TODO Once we can properly map to descriptorsetlayout use the sampler.
|
||||
return mDevice.CreateSampler(/*&desc*/);
|
||||
}
|
||||
wgpu::AddressMode WebGPUDriver::fWrapModeToWAddressMode(const SamplerWrapMode& fWrapMode) {
|
||||
switch (fWrapMode) {
|
||||
case SamplerWrapMode::CLAMP_TO_EDGE: {
|
||||
return wgpu::AddressMode::ClampToEdge;
|
||||
break;
|
||||
}
|
||||
case SamplerWrapMode::REPEAT: {
|
||||
return wgpu::AddressMode::Repeat;
|
||||
break;
|
||||
}
|
||||
case SamplerWrapMode::MIRRORED_REPEAT: {
|
||||
return wgpu::AddressMode::MirrorRepeat;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return wgpu::AddressMode::Undefined;
|
||||
}
|
||||
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -56,7 +56,8 @@ private:
|
||||
explicit WebGPUDriver(WebGPUPlatform& platform, const Platform::DriverConfig& driverConfig) noexcept;
|
||||
[[nodiscard]] ShaderModel getShaderModel() const noexcept final;
|
||||
[[nodiscard]] ShaderLanguage getShaderLanguage() const noexcept final;
|
||||
|
||||
[[nodiscard]] wgpu::Sampler makeSampler(SamplerParams const& params);
|
||||
[[nodiscard]] static wgpu::AddressMode fWrapModeToWAddressMode(const filament::backend::SamplerWrapMode& fUsage);
|
||||
template<typename GPUBufferObject>
|
||||
void updateGPUBuffer(GPUBufferObject* gpuBufferObject, BufferDescriptor&& bufferDescriptor,
|
||||
uint32_t byteOffset) {
|
||||
|
||||
@@ -16,7 +16,16 @@
|
||||
|
||||
#include "WebGPUHandles.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <utils/BitmaskEnum.h>
|
||||
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
constexpr wgpu::BufferUsage getBufferObjectUsage(
|
||||
@@ -110,6 +119,44 @@ wgpu::VertexFormat getVertexFormat(filament::backend::ElementType type, bool nor
|
||||
}
|
||||
}
|
||||
|
||||
wgpu::StringView getUserTextureLabel(filament::backend::SamplerType target) {
|
||||
// TODO will be helpful to get more useful info than this
|
||||
using filament::backend::SamplerType;
|
||||
switch (target) {
|
||||
case SamplerType::SAMPLER_2D:
|
||||
return "a_2D_user_texture";
|
||||
case SamplerType::SAMPLER_2D_ARRAY:
|
||||
return "a_2D_array_user_texture";
|
||||
case SamplerType::SAMPLER_CUBEMAP:
|
||||
return "a_cube_map_user_texture";
|
||||
case SamplerType::SAMPLER_EXTERNAL:
|
||||
return "an_external_user_texture";
|
||||
case SamplerType::SAMPLER_3D:
|
||||
return "a_3D_user_texture";
|
||||
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||
return "a_cube_mape_array_user_texture";
|
||||
}
|
||||
}
|
||||
|
||||
wgpu::StringView getUserTextureViewLabel(filament::backend::SamplerType target) {
|
||||
// TODO will be helpful to get more useful info than this
|
||||
using filament::backend::SamplerType;
|
||||
switch (target) {
|
||||
case SamplerType::SAMPLER_2D:
|
||||
return "a_2D_user_texture_view";
|
||||
case SamplerType::SAMPLER_2D_ARRAY:
|
||||
return "a_2D_array_user_texture_view";
|
||||
case SamplerType::SAMPLER_CUBEMAP:
|
||||
return "a_cube_map_user_texture_view";
|
||||
case SamplerType::SAMPLER_EXTERNAL:
|
||||
return "an_external_user_texture_view";
|
||||
case SamplerType::SAMPLER_3D:
|
||||
return "a_3D_user_texture_view";
|
||||
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||
return "a_cube_mape_array_user_texture_view";
|
||||
}
|
||||
}
|
||||
|
||||
}// namespace
|
||||
|
||||
namespace filament::backend {
|
||||
@@ -137,7 +184,7 @@ WGPUVertexBufferInfo::WGPUVertexBufferInfo(uint8_t bufferCount, uint8_t attribut
|
||||
mAttributes[attrib.buffer].push_back({
|
||||
.format = vertexFormat,
|
||||
.offset = attrib.offset,
|
||||
.shaderLocation = static_cast<uint32_t>(mAttributes[attrib.buffer].size()),
|
||||
.shaderLocation = attribIndex,
|
||||
});
|
||||
|
||||
mVertexBufferLayout[attrib.buffer].stepMode = wgpu::VertexStepMode::Vertex;
|
||||
@@ -192,11 +239,20 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
|
||||
wgpu::Device const& device) {
|
||||
assert_invariant(device);
|
||||
|
||||
std::string baseLabel;
|
||||
if (std::holds_alternative<utils::StaticString>(layout.label)) {
|
||||
const auto& temp = std::get_if<utils::StaticString>(&layout.label);
|
||||
baseLabel = temp->c_str();
|
||||
} else if (std::holds_alternative<utils::CString>(layout.label)) {
|
||||
const auto& temp = std::get_if<utils::CString>(&layout.label);
|
||||
baseLabel = temp->c_str();
|
||||
}
|
||||
|
||||
// TODO: layoutDescriptor has a "Label". Ideally we can get info on what this layout is for
|
||||
// debugging. For now, hack an incrementing value.
|
||||
static int layoutNum = 0;
|
||||
|
||||
uint samplerCount =
|
||||
unsigned int samplerCount =
|
||||
std::count_if(layout.bindings.begin(), layout.bindings.end(), [](auto& fEntry) {
|
||||
return fEntry.type == DescriptorType::SAMPLER ||
|
||||
fEntry.type == DescriptorType::SAMPLER_EXTERNAL;
|
||||
@@ -205,86 +261,204 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
|
||||
|
||||
std::vector<wgpu::BindGroupLayoutEntry> wEntries;
|
||||
wEntries.reserve(layout.bindings.size() + samplerCount);
|
||||
mBindGroupEntries.reserve(wEntries.capacity());
|
||||
|
||||
for (auto fEntry: layout.bindings) {
|
||||
auto& wEntry = wEntries.emplace_back();
|
||||
auto& entryInfo = mBindGroupEntries.emplace_back();
|
||||
wEntry.visibility = filamentStageToWGPUStage(fEntry.stageFlags);
|
||||
wEntry.binding = fEntry.binding * 2;
|
||||
entryInfo.binding = wEntry.binding;
|
||||
|
||||
switch (fEntry.type) {
|
||||
// TODO Metal treats these the same. Is this fine?
|
||||
case DescriptorType::SAMPLER_EXTERNAL:
|
||||
case DescriptorType::SAMPLER: {
|
||||
// Sampler binding is 2n+1 due to split.
|
||||
auto& samplerEntry = wEntries.emplace_back();
|
||||
auto& samplerEntryInfo = mBindGroupEntries.emplace_back();
|
||||
samplerEntry.binding = fEntry.binding * 2 + 1;
|
||||
samplerEntryInfo.binding = samplerEntry.binding;
|
||||
samplerEntryInfo.type = WebGPUDescriptorSetLayout::BindGroupEntryType::SAMPLER;
|
||||
samplerEntry.visibility = wEntry.visibility;
|
||||
// We are simply hoping that undefined and defaults suffices here.
|
||||
samplerEntry.sampler.type = wgpu::SamplerBindingType::Undefined;
|
||||
wEntry.texture.sampleType = wgpu::TextureSampleType::Undefined;
|
||||
samplerEntry.sampler.type = wgpu::SamplerBindingType::NonFiltering; // Example default
|
||||
wEntry.texture.sampleType = wgpu::TextureSampleType::Float; // Example default
|
||||
// TODO: FIX! THIS IS HACK FOR HELLO-TRIANGLE!
|
||||
if (baseLabel.find("Skybox") != std::string::npos ||
|
||||
(baseLabel == "Filament Default Material_perView" && wEntry.binding == 22)) {
|
||||
wEntry.texture.viewDimension = wgpu::TextureViewDimension::Cube;
|
||||
} else {
|
||||
wEntry.texture.viewDimension =
|
||||
wgpu::TextureViewDimension::e2D;// Example default
|
||||
}
|
||||
entryInfo.type = WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW;
|
||||
break;
|
||||
}
|
||||
case DescriptorType::UNIFORM_BUFFER: {
|
||||
wEntry.buffer.hasDynamicOffset =
|
||||
any(fEntry.flags & DescriptorFlags::DYNAMIC_OFFSET);
|
||||
entryInfo.hasDynamicOffset = wEntry.buffer.hasDynamicOffset;
|
||||
wEntry.buffer.type = wgpu::BufferBindingType::Uniform;
|
||||
// TODO: Ideally we fill minBindingSize
|
||||
break;
|
||||
}
|
||||
|
||||
case DescriptorType::INPUT_ATTACHMENT: {
|
||||
// TODO: support INPUT_ATTACHMENT. Metal does not currently.
|
||||
PANIC_POSTCONDITION("Input Attachment is not supported");
|
||||
break;
|
||||
}
|
||||
|
||||
case DescriptorType::SHADER_STORAGE_BUFFER: {
|
||||
// TODO: Vulkan does not support this, can we?
|
||||
PANIC_POSTCONDITION("Shader storage is not supported");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Currently flags are only used to specify dynamic offset.
|
||||
|
||||
// UNUSED
|
||||
// fEntry.count
|
||||
// fEntry.count is unused currently
|
||||
}
|
||||
|
||||
std::string label = "layout_" + baseLabel + std::to_string(++layoutNum) ;
|
||||
wgpu::BindGroupLayoutDescriptor layoutDescriptor{
|
||||
// TODO: layoutDescriptor has a "Label". Ideally we can get info on what this layout is for
|
||||
// debugging. For now, hack an incrementing value.
|
||||
.label{ "layout_" + std::to_string(++layoutNum) },
|
||||
.label{label.c_str()}, // Use .c_str() if label needs to be const char*
|
||||
.entryCount = wEntries.size(),
|
||||
.entries = wEntries.data()
|
||||
};
|
||||
// TODO Do we need to defer this until we have more info on textures and samplers??
|
||||
mLayoutSize = wEntries.size();
|
||||
mLayout = device.CreateBindGroupLayout(&layoutDescriptor);
|
||||
}
|
||||
|
||||
WebGPUDescriptorSetLayout::~WebGPUDescriptorSetLayout() {}
|
||||
|
||||
WebGPUDescriptorSet::WebGPUDescriptorSet(const wgpu::BindGroupLayout& layout, uint layoutSize)
|
||||
: mLayout(layout),
|
||||
entries(layoutSize, wgpu::BindGroupEntry{}) {
|
||||
// Establish the size of entries based on the layout. This should be reliable and efficient.
|
||||
wgpu::Buffer WebGPUDescriptorSet::sDummyUniformBuffer = nullptr;
|
||||
wgpu::Texture WebGPUDescriptorSet::sDummyTexture = nullptr;
|
||||
wgpu::TextureView WebGPUDescriptorSet::sDummyTextureView = nullptr;
|
||||
wgpu::Sampler WebGPUDescriptorSet::sDummySampler = nullptr;
|
||||
|
||||
void WebGPUDescriptorSet::initializeDummyResourcesIfNotAlready(wgpu::Device const& device,
|
||||
wgpu::TextureFormat aColorFormat) {
|
||||
if (!sDummyUniformBuffer) {
|
||||
wgpu::BufferDescriptor bufferDescriptor{
|
||||
.label = "dummy_uniform_not_to_be_used",
|
||||
.usage = wgpu::BufferUsage::Uniform,
|
||||
.size = 4
|
||||
};
|
||||
sDummyUniformBuffer = device.CreateBuffer(&bufferDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer)
|
||||
<< "Failed to create dummy uniform buffer?";
|
||||
}
|
||||
if (!sDummyTexture || !sDummyTextureView) {
|
||||
wgpu::TextureDescriptor textureDescriptor{
|
||||
.label = "dummy_texture_not_to_be_used",
|
||||
.usage = wgpu::TextureUsage::TextureBinding,
|
||||
.dimension = wgpu::TextureDimension::e2D,
|
||||
.size = wgpu::Extent3D{ .width = 4, .height = 4, .depthOrArrayLayers = 1 },
|
||||
.format = aColorFormat,
|
||||
};
|
||||
if (!sDummyTexture) {
|
||||
sDummyTexture = device.CreateTexture(&textureDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer) << "Failed to create dummy texture?";
|
||||
}
|
||||
if (!sDummyTextureView) {
|
||||
wgpu::TextureViewDescriptor textureViewDescriptor{
|
||||
.label = "dummy_texture_view_not_to_be_used"
|
||||
};
|
||||
sDummyTextureView = sDummyTexture.CreateView(&textureViewDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer)
|
||||
<< "Failed to create dummy texture view?";
|
||||
}
|
||||
}
|
||||
if (!sDummySampler) {
|
||||
wgpu::SamplerDescriptor samplerDescriptor{
|
||||
.label = "dummy_sampler_not_to_be_used"
|
||||
};
|
||||
sDummySampler = device.CreateSampler(&samplerDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer) << "Failed to create dummy sampler?";
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<wgpu::BindGroupEntry> WebGPUDescriptorSet::createDummyEntriesSortedByBinding(
|
||||
std::vector<filament::backend::WebGPUDescriptorSetLayout::BindGroupEntryInfo> const&
|
||||
bindGroupEntries) {
|
||||
assert_invariant(WebGPUDescriptorSet::sDummyUniformBuffer &&
|
||||
"Dummy uniform buffer must have been created before "
|
||||
"creating dummy bind group entries.");
|
||||
assert_invariant(
|
||||
WebGPUDescriptorSet::sDummyTexture &&
|
||||
"Dummy texture must have been created before creating dummy bind group entries.");
|
||||
assert_invariant(
|
||||
WebGPUDescriptorSet::sDummyTextureView &&
|
||||
"Dummy texture view must have been created before creating dummy bind group entries.");
|
||||
assert_invariant(
|
||||
WebGPUDescriptorSet::sDummySampler &&
|
||||
"Dummy sampler must have been created before creating dummy bind group entries.");
|
||||
using filament::backend::WebGPUDescriptorSetLayout;
|
||||
std::vector<wgpu::BindGroupEntry> entries;
|
||||
entries.reserve(bindGroupEntries.size());
|
||||
for (auto const& entryInfo: bindGroupEntries) {
|
||||
auto& entry = entries.emplace_back();
|
||||
entry.binding = entryInfo.binding;
|
||||
switch (entryInfo.type) {
|
||||
case WebGPUDescriptorSetLayout::BindGroupEntryType::UNIFORM_BUFFER:
|
||||
entry.buffer = WebGPUDescriptorSet::sDummyUniformBuffer;
|
||||
break;
|
||||
case WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW:
|
||||
entry.textureView = WebGPUDescriptorSet::sDummyTextureView;
|
||||
break;
|
||||
case WebGPUDescriptorSetLayout::BindGroupEntryType::SAMPLER:
|
||||
entry.sampler = WebGPUDescriptorSet::sDummySampler;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::sort(entries.begin(), entries.end(),
|
||||
[](wgpu::BindGroupEntry const& a, wgpu::BindGroupEntry const& b) {
|
||||
return a.binding < b.binding;
|
||||
});
|
||||
return entries;
|
||||
}
|
||||
|
||||
WebGPUDescriptorSet::WebGPUDescriptorSet(wgpu::BindGroupLayout const& layout,
|
||||
std::vector<WebGPUDescriptorSetLayout::BindGroupEntryInfo> const& bindGroupEntries)
|
||||
: mLayout(layout),
|
||||
mEntriesSortedByBinding(createDummyEntriesSortedByBinding(bindGroupEntries)) {
|
||||
// Establish the size of entries based on the layout. This should be reliable and efficient.
|
||||
assert_invariant(INVALID_INDEX > mEntryIndexByBinding.size());
|
||||
for (size_t i = 0; i < mEntryIndexByBinding.size(); i++) {
|
||||
mEntryIndexByBinding[i] = INVALID_INDEX;
|
||||
}
|
||||
for (size_t index = 0; index < mEntriesSortedByBinding.size(); index++) {
|
||||
wgpu::BindGroupEntry const& entry = mEntriesSortedByBinding[index];
|
||||
assert_invariant(entry.binding < mEntryIndexByBinding.size());
|
||||
mEntryIndexByBinding[entry.binding] = static_cast<uint8_t>(index);
|
||||
}
|
||||
for (auto const& entry : bindGroupEntries) {
|
||||
if (entry.hasDynamicOffset) {
|
||||
assert_invariant(entry.binding < mEntriesByBindingWithDynamicOffsets.size());
|
||||
mEntriesByBindingWithDynamicOffsets[entry.binding] = true;
|
||||
}
|
||||
}
|
||||
mDynamicOffsets.reserve(mEntriesSortedByBinding.size());
|
||||
}
|
||||
|
||||
WebGPUDescriptorSet::~WebGPUDescriptorSet() {
|
||||
mBindGroup = nullptr;
|
||||
mLayout = nullptr;
|
||||
}
|
||||
WebGPUDescriptorSet::~WebGPUDescriptorSet() {}
|
||||
|
||||
wgpu::BindGroup WebGPUDescriptorSet::lockAndReturn(const wgpu::Device& device) {
|
||||
if (mBindGroup) {
|
||||
return mBindGroup;
|
||||
}
|
||||
// TODO label? Should we just copy layout label?
|
||||
wgpu::BindGroupDescriptor desc{ .layout = mLayout,
|
||||
.entryCount = entries.size(),
|
||||
.entries = entries.data() };
|
||||
wgpu::BindGroupDescriptor desc{
|
||||
.layout = mLayout,
|
||||
.entryCount = mEntriesSortedByBinding.size(),
|
||||
.entries = mEntriesSortedByBinding.data()
|
||||
};
|
||||
mBindGroup = device.CreateBindGroup(&desc);
|
||||
FILAMENT_CHECK_POSTCONDITION(mBindGroup) << "Failed to create bind group?";
|
||||
// once we have created the bind group itself we should no longer need any other state
|
||||
mLayout = nullptr;
|
||||
mEntriesSortedByBinding.clear();
|
||||
mEntriesSortedByBinding.shrink_to_fit();
|
||||
return mBindGroup;
|
||||
}
|
||||
|
||||
void WebGPUDescriptorSet::addEntry(uint index, wgpu::BindGroupEntry&& entry) {
|
||||
void WebGPUDescriptorSet::addEntry(unsigned int index, wgpu::BindGroupEntry&& entry) {
|
||||
if (mBindGroup) {
|
||||
// We will keep getting hits from future updates, but shouldn't do anything
|
||||
// Filament guarantees this won't change after things have locked.
|
||||
@@ -292,6 +466,490 @@ void WebGPUDescriptorSet::addEntry(uint index, wgpu::BindGroupEntry&& entry) {
|
||||
}
|
||||
// TODO: Putting some level of trust that Filament is not going to reuse indexes or go past the
|
||||
// layout index for efficiency. Add guards if wrong.
|
||||
entries[index] = std::move(entry);
|
||||
FILAMENT_CHECK_POSTCONDITION(index < mEntryIndexByBinding.size())
|
||||
<< "impossible/invalid index for a descriptor/binding (our of range or >= "
|
||||
"MAX_DESCRIPTOR_COUNT) "
|
||||
<< index;
|
||||
uint8_t entryIndex = mEntryIndexByBinding[index];
|
||||
FILAMENT_CHECK_POSTCONDITION(
|
||||
entryIndex != INVALID_INDEX && entryIndex < mEntriesSortedByBinding.size())
|
||||
<< "Invalid binding " << index;
|
||||
entry.binding = index;
|
||||
mEntriesSortedByBinding[entryIndex] = std::move(entry);
|
||||
mEntriesByBindingAdded[index] = true;
|
||||
}
|
||||
|
||||
uint32_t const* WebGPUDescriptorSet::setDynamicOffsets(uint32_t const* offsets) {
|
||||
// mDynamicOffsets already reserves enough memory for the number of entries in the set
|
||||
mDynamicOffsets.clear();
|
||||
// this implementation copies the offsets to mDynamicOffsets, but also adds values for
|
||||
// unused entries TODO: is this necessary?
|
||||
size_t inputIndex = 0;
|
||||
size_t outputIndex = 0;
|
||||
for (auto const& entry : mEntriesSortedByBinding) {
|
||||
if (mEntriesByBindingWithDynamicOffsets[entry.binding]) {
|
||||
if (mEntriesByBindingAdded[entry.binding]) {
|
||||
mDynamicOffsets[outputIndex++] = offsets[inputIndex++];
|
||||
} else {
|
||||
mDynamicOffsets[outputIndex++] = 0; // dummy offset, as it was never added
|
||||
}
|
||||
}
|
||||
}
|
||||
return mDynamicOffsets.data();
|
||||
}
|
||||
|
||||
size_t WebGPUDescriptorSet::countEntitiesWithDynamicOffsets() const {
|
||||
return mEntriesByBindingWithDynamicOffsets.count();
|
||||
}
|
||||
|
||||
// From createTextureR
|
||||
WGPUTexture::WGPUTexture(SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
||||
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage,
|
||||
wgpu::Device const& device) noexcept {
|
||||
assert_invariant(
|
||||
samples == 1 ||
|
||||
samples == 4 &&
|
||||
"An invalid number of samples were requested, as WGPU requires the sample "
|
||||
"count to either be 1 (no multisampling) or 4, at least as of April 2025 of "
|
||||
"the spec. See https://www.w3.org/TR/webgpu/#texture-creation or "
|
||||
"https://gpuweb.github.io/gpuweb/#multisample-state");
|
||||
// First, the texture aspect, starting with the defaults/basic configuration
|
||||
mUsage = fToWGPUTextureUsage(usage);
|
||||
mFormat = fToWGPUTextureFormat(format);
|
||||
wgpu::TextureDescriptor textureDescriptor{
|
||||
.label = getUserTextureLabel(target),
|
||||
.usage = mUsage,
|
||||
.dimension = target == SamplerType::SAMPLER_3D ? wgpu::TextureDimension::e3D
|
||||
: wgpu::TextureDimension::e2D,
|
||||
.size = { .width = width, .height = height, .depthOrArrayLayers = depth },
|
||||
.format = mFormat,
|
||||
.mipLevelCount = levels,
|
||||
.sampleCount = samples,
|
||||
// TODO Is this fine? Could do all-the-things, a naive mapping or get something from
|
||||
// Filament
|
||||
.viewFormatCount = 0,
|
||||
.viewFormats = nullptr,
|
||||
};
|
||||
// adjust for specific cases
|
||||
switch (target) {
|
||||
case SamplerType::SAMPLER_2D:
|
||||
mArrayLayerCount = 1;
|
||||
break;
|
||||
case SamplerType::SAMPLER_2D_ARRAY:
|
||||
mArrayLayerCount = textureDescriptor.size.depthOrArrayLayers;
|
||||
break;
|
||||
case SamplerType::SAMPLER_CUBEMAP:
|
||||
textureDescriptor.size.depthOrArrayLayers = 6;
|
||||
mArrayLayerCount = textureDescriptor.size.depthOrArrayLayers;
|
||||
break;
|
||||
case SamplerType::SAMPLER_EXTERNAL:
|
||||
case SamplerType::SAMPLER_3D:
|
||||
mArrayLayerCount = 1;
|
||||
break;
|
||||
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||
textureDescriptor.size.depthOrArrayLayers = depth * 6;
|
||||
mArrayLayerCount = textureDescriptor.size.depthOrArrayLayers;
|
||||
break;
|
||||
}
|
||||
assert_invariant(textureDescriptor.format != wgpu::TextureFormat::Undefined &&
|
||||
"Could not find appropriate WebGPU format");
|
||||
mTexture = device.CreateTexture(&textureDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(mTexture)
|
||||
<< "Failed to create texture for " << textureDescriptor.label;
|
||||
// Second, the texture view aspect
|
||||
mTexView = makeTextureView(0, levels, target);
|
||||
}
|
||||
|
||||
// From createTextureViewR
|
||||
WGPUTexture::WGPUTexture(WGPUTexture* src, uint8_t baseLevel, uint8_t levelCount) noexcept {
|
||||
mTexture = src->mTexture;
|
||||
mTexView = makeTextureView(baseLevel, levelCount, target);
|
||||
}
|
||||
|
||||
wgpu::TextureUsage WGPUTexture::fToWGPUTextureUsage(const TextureUsage& fUsage) {
|
||||
wgpu::TextureUsage retUsage = wgpu::TextureUsage::None;
|
||||
|
||||
// Basing this mapping off of VulkanTexture.cpp's getUsage func and suggestions from Gemini
|
||||
// TODO Validate assumptions, revisit if issues.
|
||||
if (any(TextureUsage::BLIT_SRC & fUsage)) {
|
||||
retUsage |= wgpu::TextureUsage::CopySrc;
|
||||
}
|
||||
if (any((TextureUsage::BLIT_DST | TextureUsage::UPLOADABLE) & fUsage)) {
|
||||
retUsage |= wgpu::TextureUsage::CopyDst;
|
||||
}
|
||||
if (any(TextureUsage::SAMPLEABLE & fUsage)) {
|
||||
retUsage |= wgpu::TextureUsage::TextureBinding;
|
||||
}
|
||||
// WGPU Render attachment covers either color or stencil situation dependant
|
||||
// NOTE: Depth attachment isn't used this way in Vulkan but logically maps to WGPU docs. If
|
||||
// issues, investigate here.
|
||||
if (any((TextureUsage::COLOR_ATTACHMENT | TextureUsage::STENCIL_ATTACHMENT |
|
||||
TextureUsage::DEPTH_ATTACHMENT) &
|
||||
fUsage)) {
|
||||
retUsage |= wgpu::TextureUsage::RenderAttachment;
|
||||
}
|
||||
|
||||
// This is from Vulkan logic- if there are any issues try disabling this first, allows perf
|
||||
// benefit though
|
||||
const bool useTransientAttachment =
|
||||
// Usage consists of attachment flags only.
|
||||
none(fUsage & ~TextureUsage::ALL_ATTACHMENTS) &&
|
||||
// Usage contains at least one attachment flag.
|
||||
any(fUsage & TextureUsage::ALL_ATTACHMENTS) &&
|
||||
// Depth resolve cannot use transient attachment because it uses a custom shader.
|
||||
// TODO: see VulkanDriver::isDepthStencilResolveSupported() to know when to remove this
|
||||
// restriction.
|
||||
// Note that the custom shader does not resolve stencil. We do need to move to vk 1.2
|
||||
// and above to be able to support stencil resolve (along with depth).
|
||||
!(any(fUsage & TextureUsage::DEPTH_ATTACHMENT) && samples > 1);
|
||||
if (useTransientAttachment) {
|
||||
retUsage |= wgpu::TextureUsage::TransientAttachment;
|
||||
}
|
||||
// NOTE: Unused wgpu flags:
|
||||
// StorageBinding
|
||||
// StorageAttachment
|
||||
|
||||
// NOTE: Unused Filament flags:
|
||||
// SUBPASS_INPUT VK goes to input attachment which we don't support right now
|
||||
// PROTECTED
|
||||
return retUsage;
|
||||
}
|
||||
wgpu::TextureFormat WGPUTexture::fToWGPUTextureFormat(const TextureFormat& fUsage) {
|
||||
switch (fUsage) {
|
||||
case filament::backend::TextureFormat::R8:
|
||||
return wgpu::TextureFormat::R8Unorm;
|
||||
case filament::backend::TextureFormat::R8_SNORM:
|
||||
return wgpu::TextureFormat::R8Snorm;
|
||||
case filament::backend::TextureFormat::R8UI:
|
||||
return wgpu::TextureFormat::R8Uint;
|
||||
case filament::backend::TextureFormat::R8I:
|
||||
return wgpu::TextureFormat::R8Sint;
|
||||
case filament::backend::TextureFormat::STENCIL8:
|
||||
return wgpu::TextureFormat::Stencil8;
|
||||
case filament::backend::TextureFormat::R16F:
|
||||
return wgpu::TextureFormat::R16Float;
|
||||
case filament::backend::TextureFormat::R16UI:
|
||||
return wgpu::TextureFormat::R16Uint;
|
||||
case filament::backend::TextureFormat::R16I:
|
||||
return wgpu::TextureFormat::R16Sint;
|
||||
case filament::backend::TextureFormat::RG8:
|
||||
return wgpu::TextureFormat::RG8Unorm;
|
||||
case filament::backend::TextureFormat::RG8_SNORM:
|
||||
return wgpu::TextureFormat::RG8Snorm;
|
||||
case filament::backend::TextureFormat::RG8UI:
|
||||
return wgpu::TextureFormat::RG8Uint;
|
||||
case filament::backend::TextureFormat::RG8I:
|
||||
return wgpu::TextureFormat::RG8Sint;
|
||||
case filament::backend::TextureFormat::R32F:
|
||||
return wgpu::TextureFormat::R32Float;
|
||||
case filament::backend::TextureFormat::R32UI:
|
||||
return wgpu::TextureFormat::R32Uint;
|
||||
case filament::backend::TextureFormat::R32I:
|
||||
return wgpu::TextureFormat::R32Sint;
|
||||
case filament::backend::TextureFormat::RG16F:
|
||||
return wgpu::TextureFormat::RG16Float;
|
||||
case filament::backend::TextureFormat::RG16UI:
|
||||
return wgpu::TextureFormat::RG16Uint;
|
||||
case filament::backend::TextureFormat::RG16I:
|
||||
return wgpu::TextureFormat::RG16Sint;
|
||||
case filament::backend::TextureFormat::RGBA8:
|
||||
return wgpu::TextureFormat::RGBA8Unorm;
|
||||
case filament::backend::TextureFormat::SRGB8_A8:
|
||||
return wgpu::TextureFormat::RGBA8UnormSrgb;
|
||||
case filament::backend::TextureFormat::RGBA8_SNORM:
|
||||
return wgpu::TextureFormat::RGBA8Snorm;
|
||||
case filament::backend::TextureFormat::RGBA8UI:
|
||||
return wgpu::TextureFormat::RGBA8Uint;
|
||||
case filament::backend::TextureFormat::RGBA8I:
|
||||
return wgpu::TextureFormat::RGBA8Sint;
|
||||
case filament::backend::TextureFormat::DEPTH16:
|
||||
return wgpu::TextureFormat::Depth16Unorm;
|
||||
case filament::backend::TextureFormat::DEPTH24:
|
||||
return wgpu::TextureFormat::Depth24Plus;
|
||||
case filament::backend::TextureFormat::DEPTH32F:
|
||||
return wgpu::TextureFormat::Depth32Float;
|
||||
case filament::backend::TextureFormat::DEPTH24_STENCIL8:
|
||||
return wgpu::TextureFormat::Depth24PlusStencil8;
|
||||
case filament::backend::TextureFormat::DEPTH32F_STENCIL8:
|
||||
return wgpu::TextureFormat::Depth32FloatStencil8;
|
||||
case filament::backend::TextureFormat::RG32F:
|
||||
return wgpu::TextureFormat::RG32Float;
|
||||
case filament::backend::TextureFormat::RG32UI:
|
||||
return wgpu::TextureFormat::RG32Uint;
|
||||
case filament::backend::TextureFormat::RG32I:
|
||||
return wgpu::TextureFormat::RG32Sint;
|
||||
case filament::backend::TextureFormat::RGBA16F:
|
||||
return wgpu::TextureFormat::RGBA16Float;
|
||||
case filament::backend::TextureFormat::RGBA16UI:
|
||||
return wgpu::TextureFormat::RGBA16Uint;
|
||||
case filament::backend::TextureFormat::RGBA16I:
|
||||
return wgpu::TextureFormat::RGBA16Sint;
|
||||
case filament::backend::TextureFormat::RGBA32F:
|
||||
return wgpu::TextureFormat::RGBA32Float;
|
||||
case filament::backend::TextureFormat::RGBA32UI:
|
||||
return wgpu::TextureFormat::RGBA32Uint;
|
||||
case filament::backend::TextureFormat::RGBA32I:
|
||||
return wgpu::TextureFormat::RGBA32Sint;
|
||||
case filament::backend::TextureFormat::EAC_R11:
|
||||
return wgpu::TextureFormat::EACR11Unorm;
|
||||
case filament::backend::TextureFormat::EAC_R11_SIGNED:
|
||||
return wgpu::TextureFormat::EACR11Snorm;
|
||||
case filament::backend::TextureFormat::EAC_RG11:
|
||||
return wgpu::TextureFormat::EACRG11Unorm;
|
||||
case filament::backend::TextureFormat::EAC_RG11_SIGNED:
|
||||
return wgpu::TextureFormat::EACRG11Snorm;
|
||||
case filament::backend::TextureFormat::ETC2_RGB8:
|
||||
return wgpu::TextureFormat::ETC2RGB8Unorm;
|
||||
case filament::backend::TextureFormat::ETC2_SRGB8:
|
||||
return wgpu::TextureFormat::ETC2RGB8UnormSrgb;
|
||||
case filament::backend::TextureFormat::ETC2_RGB8_A1:
|
||||
return wgpu::TextureFormat::ETC2RGB8A1Unorm;
|
||||
case filament::backend::TextureFormat::ETC2_SRGB8_A1:
|
||||
return wgpu::TextureFormat::ETC2RGB8A1UnormSrgb;
|
||||
case filament::backend::TextureFormat::ETC2_EAC_RGBA8:
|
||||
return wgpu::TextureFormat::ETC2RGBA8Unorm;
|
||||
case filament::backend::TextureFormat::ETC2_EAC_SRGBA8:
|
||||
return wgpu::TextureFormat::ETC2RGBA8UnormSrgb;
|
||||
case filament::backend::TextureFormat::RGBA_ASTC_4x4:
|
||||
return wgpu::TextureFormat::ASTC4x4Unorm;
|
||||
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_4x4:
|
||||
return wgpu::TextureFormat::ASTC4x4UnormSrgb;
|
||||
case filament::backend::TextureFormat::RGBA_ASTC_5x4:
|
||||
return wgpu::TextureFormat::ASTC5x4Unorm;
|
||||
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_5x4:
|
||||
return wgpu::TextureFormat::ASTC5x4UnormSrgb;
|
||||
case filament::backend::TextureFormat::RGBA_ASTC_5x5:
|
||||
return wgpu::TextureFormat::ASTC5x5Unorm;
|
||||
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_5x5:
|
||||
return wgpu::TextureFormat::ASTC5x5UnormSrgb;
|
||||
case filament::backend::TextureFormat::RGBA_ASTC_6x5:
|
||||
return wgpu::TextureFormat::ASTC6x5Unorm;
|
||||
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_6x5:
|
||||
return wgpu::TextureFormat::ASTC6x5UnormSrgb;
|
||||
case filament::backend::TextureFormat::RGBA_ASTC_6x6:
|
||||
return wgpu::TextureFormat::ASTC6x6Unorm;
|
||||
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_6x6:
|
||||
return wgpu::TextureFormat::ASTC6x6UnormSrgb;
|
||||
case filament::backend::TextureFormat::RGBA_ASTC_8x5:
|
||||
return wgpu::TextureFormat::ASTC8x5Unorm;
|
||||
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_8x5:
|
||||
return wgpu::TextureFormat::ASTC8x5UnormSrgb;
|
||||
case filament::backend::TextureFormat::RGBA_ASTC_8x6:
|
||||
return wgpu::TextureFormat::ASTC8x6Unorm;
|
||||
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_8x6:
|
||||
return wgpu::TextureFormat::ASTC8x6UnormSrgb;
|
||||
case filament::backend::TextureFormat::RGBA_ASTC_8x8:
|
||||
return wgpu::TextureFormat::ASTC8x8Unorm;
|
||||
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_8x8:
|
||||
return wgpu::TextureFormat::ASTC8x8UnormSrgb;
|
||||
case filament::backend::TextureFormat::RGBA_ASTC_10x5:
|
||||
return wgpu::TextureFormat::ASTC10x5Unorm;
|
||||
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_10x5:
|
||||
return wgpu::TextureFormat::ASTC10x5UnormSrgb;
|
||||
case filament::backend::TextureFormat::RGBA_ASTC_10x6:
|
||||
return wgpu::TextureFormat::ASTC10x6Unorm;
|
||||
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_10x6:
|
||||
return wgpu::TextureFormat::ASTC10x6UnormSrgb;
|
||||
case filament::backend::TextureFormat::RGBA_ASTC_10x8:
|
||||
return wgpu::TextureFormat::ASTC10x8Unorm;
|
||||
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_10x8:
|
||||
return wgpu::TextureFormat::ASTC10x8UnormSrgb;
|
||||
case filament::backend::TextureFormat::RGBA_ASTC_10x10:
|
||||
return wgpu::TextureFormat::ASTC10x10Unorm;
|
||||
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_10x10:
|
||||
return wgpu::TextureFormat::ASTC10x10UnormSrgb;
|
||||
case filament::backend::TextureFormat::RGBA_ASTC_12x10:
|
||||
return wgpu::TextureFormat::ASTC12x10Unorm;
|
||||
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_12x10:
|
||||
return wgpu::TextureFormat::ASTC12x10UnormSrgb;
|
||||
case filament::backend::TextureFormat::RGBA_ASTC_12x12:
|
||||
return wgpu::TextureFormat::ASTC12x12Unorm;
|
||||
case filament::backend::TextureFormat::SRGB8_ALPHA8_ASTC_12x12:
|
||||
return wgpu::TextureFormat::ASTC12x12UnormSrgb;
|
||||
case filament::backend::TextureFormat::RED_RGTC1:
|
||||
return wgpu::TextureFormat::BC4RUnorm;
|
||||
case filament::backend::TextureFormat::SIGNED_RED_RGTC1:
|
||||
return wgpu::TextureFormat::BC4RSnorm;
|
||||
case filament::backend::TextureFormat::RED_GREEN_RGTC2:
|
||||
return wgpu::TextureFormat::BC5RGUnorm;
|
||||
case filament::backend::TextureFormat::SIGNED_RED_GREEN_RGTC2:
|
||||
return wgpu::TextureFormat::BC5RGSnorm;
|
||||
case filament::backend::TextureFormat::RGB_BPTC_UNSIGNED_FLOAT:
|
||||
return wgpu::TextureFormat::BC6HRGBUfloat;
|
||||
case filament::backend::TextureFormat::RGB_BPTC_SIGNED_FLOAT:
|
||||
return wgpu::TextureFormat::BC6HRGBFloat;
|
||||
case filament::backend::TextureFormat::RGBA_BPTC_UNORM:
|
||||
return wgpu::TextureFormat::BC7RGBAUnorm;
|
||||
case filament::backend::TextureFormat::SRGB_ALPHA_BPTC_UNORM:
|
||||
return wgpu::TextureFormat::BC7RGBAUnormSrgb;
|
||||
case filament::backend::TextureFormat::RGB565:
|
||||
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
|
||||
// and discard the alpha and lower precision.
|
||||
return wgpu::TextureFormat::Undefined;
|
||||
case filament::backend::TextureFormat::RGB9_E5:
|
||||
return wgpu::TextureFormat::RGB9E5Ufloat;
|
||||
case filament::backend::TextureFormat::RGB5_A1:
|
||||
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
|
||||
// and handle the packing/unpacking in shaders.
|
||||
return wgpu::TextureFormat::Undefined;
|
||||
case filament::backend::TextureFormat::RGBA4:
|
||||
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
|
||||
// and handle the packing/unpacking in shaders.
|
||||
return wgpu::TextureFormat::Undefined;
|
||||
case filament::backend::TextureFormat::RGB8:
|
||||
// No direct sRGB equivalent in wgpu without alpha.
|
||||
return wgpu::TextureFormat::RGBA8Unorm;
|
||||
case filament::backend::TextureFormat::SRGB8:
|
||||
// No direct sRGB equivalent in wgpu without alpha.
|
||||
return wgpu::TextureFormat::RGBA8UnormSrgb;
|
||||
case filament::backend::TextureFormat::RGB8_SNORM:
|
||||
// No direct mapping in wgpu without alpha.
|
||||
return wgpu::TextureFormat::RGBA8Snorm;
|
||||
case filament::backend::TextureFormat::RGB8UI:
|
||||
// No direct mapping in wgpu without alpha.
|
||||
return wgpu::TextureFormat::RGBA8Uint;
|
||||
case filament::backend::TextureFormat::RGB8I:
|
||||
// No direct mapping in wgpu without alpha.
|
||||
return wgpu::TextureFormat::RGBA8Sint;
|
||||
case filament::backend::TextureFormat::R11F_G11F_B10F:
|
||||
return wgpu::TextureFormat::RG11B10Ufloat;
|
||||
case filament::backend::TextureFormat::UNUSED:
|
||||
return wgpu::TextureFormat::Undefined;
|
||||
case filament::backend::TextureFormat::RGB10_A2:
|
||||
return wgpu::TextureFormat::RGB10A2Unorm;
|
||||
case filament::backend::TextureFormat::RGB16F:
|
||||
// No direct mapping in wgpu without alpha.
|
||||
return wgpu::TextureFormat::RGBA16Float;
|
||||
case filament::backend::TextureFormat::RGB16UI:
|
||||
// No direct mapping in wgpu without alpha.
|
||||
return wgpu::TextureFormat::RGBA16Uint;
|
||||
case filament::backend::TextureFormat::RGB16I:
|
||||
// No direct mapping in wgpu without alpha.
|
||||
return wgpu::TextureFormat::RGBA16Sint;
|
||||
case filament::backend::TextureFormat::RGB32F:
|
||||
// No direct mapping in wgpu without alpha.
|
||||
return wgpu::TextureFormat::RGBA32Float;
|
||||
case filament::backend::TextureFormat::RGB32UI:
|
||||
// No direct mapping in wgpu without alpha.
|
||||
return wgpu::TextureFormat::RGBA32Uint;
|
||||
case filament::backend::TextureFormat::RGB32I:
|
||||
// No direct mapping in wgpu without alpha.
|
||||
return wgpu::TextureFormat::RGBA32Sint;
|
||||
case filament::backend::TextureFormat::DXT1_RGB:
|
||||
return wgpu::TextureFormat::BC1RGBAUnorm;
|
||||
case filament::backend::TextureFormat::DXT1_RGBA:
|
||||
return wgpu::TextureFormat::BC1RGBAUnorm;
|
||||
case filament::backend::TextureFormat::DXT3_RGBA:
|
||||
return wgpu::TextureFormat::BC2RGBAUnorm;
|
||||
case filament::backend::TextureFormat::DXT5_RGBA:
|
||||
return wgpu::TextureFormat::BC3RGBAUnorm;
|
||||
case filament::backend::TextureFormat::DXT1_SRGB:
|
||||
return wgpu::TextureFormat::BC1RGBAUnormSrgb;
|
||||
case filament::backend::TextureFormat::DXT1_SRGBA:
|
||||
return wgpu::TextureFormat::BC1RGBAUnormSrgb;
|
||||
case filament::backend::TextureFormat::DXT3_SRGBA:
|
||||
return wgpu::TextureFormat::BC2RGBAUnormSrgb;
|
||||
case filament::backend::TextureFormat::DXT5_SRGBA:
|
||||
return wgpu::TextureFormat::BC3RGBAUnormSrgb;
|
||||
}
|
||||
}
|
||||
|
||||
wgpu::TextureView WGPUTexture::makeTextureView(const uint8_t& baseLevel, const uint8_t& levelCount,
|
||||
SamplerType target) {
|
||||
// starting with the defaults/basic configuration
|
||||
wgpu::TextureViewDescriptor textureViewDescriptor{
|
||||
.label = getUserTextureViewLabel(target),
|
||||
.format = mFormat,
|
||||
// dimension depends on target and is set below
|
||||
.baseMipLevel = baseLevel,
|
||||
.mipLevelCount = levelCount,
|
||||
// baseArrayLayer is required, making a guess
|
||||
.baseArrayLayer = 0,
|
||||
.arrayLayerCount = mArrayLayerCount,
|
||||
// Have not found an analog to aspect in other drivers, but ALL should be unrestrictive.
|
||||
// TODO Can we make this better?
|
||||
.aspect = wgpu::TextureAspect::All,
|
||||
.usage = mUsage
|
||||
};
|
||||
// adjust for specific cases
|
||||
switch (target) {
|
||||
case SamplerType::SAMPLER_2D:
|
||||
textureViewDescriptor.dimension = wgpu::TextureViewDimension::e2D;
|
||||
break;
|
||||
case SamplerType::SAMPLER_2D_ARRAY:
|
||||
textureViewDescriptor.dimension = wgpu::TextureViewDimension::e2DArray;
|
||||
break;
|
||||
case SamplerType::SAMPLER_CUBEMAP:
|
||||
textureViewDescriptor.dimension = wgpu::TextureViewDimension::Cube;
|
||||
break;
|
||||
case SamplerType::SAMPLER_EXTERNAL:
|
||||
textureViewDescriptor.dimension = wgpu::TextureViewDimension::e2D;
|
||||
break;
|
||||
case SamplerType::SAMPLER_3D:
|
||||
textureViewDescriptor.dimension = wgpu::TextureViewDimension::e3D;
|
||||
break;
|
||||
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||
textureViewDescriptor.dimension = wgpu::TextureViewDimension::CubeArray;
|
||||
break;
|
||||
}
|
||||
wgpu::TextureView textureView = mTexture.CreateView(&textureViewDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(textureView)
|
||||
<< "Failed to create texture view " << textureViewDescriptor.label;
|
||||
return textureView;
|
||||
}
|
||||
|
||||
WGPURenderTarget::Attachment WGPURenderTarget::getDrawColorAttachment(size_t index) {
|
||||
assert_invariant( index < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT);
|
||||
auto result = color[index];
|
||||
if (index == 0 && defaultRenderTarget) {
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
wgpu::LoadOp WGPURenderTarget::getLoadOperation(RenderPassParams const& params,
|
||||
TargetBufferFlags buffer) {
|
||||
auto clearFlags = params.flags.clear;
|
||||
auto discardStartFlags = params.flags.discardStart;
|
||||
if (any(clearFlags & buffer)) {
|
||||
return wgpu::LoadOp::Clear;
|
||||
} else if (any(discardStartFlags & buffer)) {
|
||||
return wgpu::LoadOp::Clear;
|
||||
}
|
||||
return wgpu::LoadOp::Load;
|
||||
}
|
||||
|
||||
wgpu::StoreOp WGPURenderTarget::getStoreOperation(RenderPassParams const& params,
|
||||
TargetBufferFlags buffer) {
|
||||
const auto discardEndFlags = params.flags.discardEnd;
|
||||
if (any(discardEndFlags & buffer)) {
|
||||
return wgpu::StoreOp::Discard;
|
||||
}
|
||||
return wgpu::StoreOp::Store;
|
||||
}
|
||||
void WGPURenderTarget::setUpRenderPassAttachments(wgpu::RenderPassDescriptor& descriptor,
|
||||
wgpu::TextureView const& textureView, RenderPassParams const& params) {
|
||||
// auto discardFlags = params.flags.discardEnd;
|
||||
// (void) discardFlags;
|
||||
// std::vector<wgpu::RenderPassColorAttachment> colorAttachments;
|
||||
colorAttachments.clear();
|
||||
for (size_t i = 0; i < 1/*MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT*/; i++) {
|
||||
// auto attachment = getDrawColorAttachment(i);
|
||||
// if (attachment) {
|
||||
wgpu::RenderPassColorAttachment colorAttachment;
|
||||
colorAttachment.view = textureView;
|
||||
colorAttachment.loadOp = getLoadOperation(params, getTargetBufferFlagsAt(i));
|
||||
colorAttachment.storeOp = getStoreOperation(params, getTargetBufferFlagsAt(i));
|
||||
colorAttachment.clearValue = { params.clearColor.r, params.clearColor.g, params.clearColor.b, params.clearColor.a };
|
||||
colorAttachments.emplace_back(colorAttachment);
|
||||
// }
|
||||
}
|
||||
descriptor.colorAttachments = colorAttachments.data();
|
||||
descriptor.colorAttachmentCount = colorAttachments.size();
|
||||
descriptor.depthStencilAttachment = nullptr;
|
||||
descriptor.timestampWrites = nullptr;
|
||||
}
|
||||
|
||||
|
||||
}// namespace filament::backend
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
@@ -98,80 +100,124 @@ struct WGPUBufferObject : HwBufferObject {
|
||||
wgpu::Buffer buffer = nullptr;
|
||||
const BufferObjectBinding bufferObjectBinding;
|
||||
};
|
||||
|
||||
class WebGPUDescriptorSetLayout final : public HwDescriptorSetLayout {
|
||||
public:
|
||||
|
||||
enum class BindGroupEntryType : uint8_t {
|
||||
UNIFORM_BUFFER,
|
||||
TEXTURE_VIEW,
|
||||
SAMPLER
|
||||
};
|
||||
|
||||
struct BindGroupEntryInfo final {
|
||||
uint8_t binding = 0;
|
||||
BindGroupEntryType type = BindGroupEntryType::UNIFORM_BUFFER;
|
||||
bool hasDynamicOffset = false;
|
||||
};
|
||||
|
||||
WebGPUDescriptorSetLayout(DescriptorSetLayout const& layout, wgpu::Device const& device);
|
||||
~WebGPUDescriptorSetLayout();
|
||||
[[nodiscard]] const wgpu::BindGroupLayout& getLayout() const { return mLayout; }
|
||||
[[nodiscard]] uint getLayoutSize() const { return mLayoutSize; }
|
||||
[[nodiscard]] std::vector<BindGroupEntryInfo> const& getBindGroupEntries() const {
|
||||
return mBindGroupEntries;
|
||||
}
|
||||
|
||||
private:
|
||||
// TODO: If this is useful elsewhere, remove it from this class
|
||||
// Convert Filament Shader Stage Flags bitmask to webgpu equivilant
|
||||
static wgpu::ShaderStage filamentStageToWGPUStage(ShaderStageFlags fFlags);
|
||||
uint mLayoutSize;
|
||||
std::vector<BindGroupEntryInfo> mBindGroupEntries;
|
||||
wgpu::BindGroupLayout mLayout;
|
||||
};
|
||||
|
||||
class WebGPUDescriptorSet final : public HwDescriptorSet {
|
||||
public:
|
||||
WebGPUDescriptorSet(const wgpu::BindGroupLayout& layout, uint layoutSize);
|
||||
static void initializeDummyResourcesIfNotAlready(wgpu::Device const&,
|
||||
wgpu::TextureFormat aColorFormat);
|
||||
|
||||
WebGPUDescriptorSet(wgpu::BindGroupLayout const& layout,
|
||||
std::vector<WebGPUDescriptorSetLayout::BindGroupEntryInfo> const& bindGroupEntries);
|
||||
~WebGPUDescriptorSet();
|
||||
|
||||
wgpu::BindGroup lockAndReturn(wgpu::Device const& device);
|
||||
void addEntry(uint index, wgpu::BindGroupEntry&& entry);
|
||||
wgpu::BindGroup lockAndReturn(wgpu::Device const&);
|
||||
void addEntry(unsigned int index, wgpu::BindGroupEntry&& entry);
|
||||
[[nodiscard]] uint32_t const* setDynamicOffsets(uint32_t const* offsets);
|
||||
[[nodiscard]] bool getIsLocked() const { return mBindGroup != nullptr; }
|
||||
|
||||
[[nodiscard]] size_t countEntitiesWithDynamicOffsets() const;
|
||||
private:
|
||||
|
||||
static wgpu::Buffer sDummyUniformBuffer;
|
||||
static wgpu::Texture sDummyTexture;
|
||||
static wgpu::TextureView sDummyTextureView;
|
||||
static wgpu::Sampler sDummySampler;
|
||||
|
||||
static std::vector<wgpu::BindGroupEntry> createDummyEntriesSortedByBinding(
|
||||
std::vector<filament::backend::WebGPUDescriptorSetLayout::BindGroupEntryInfo> const&);
|
||||
|
||||
// TODO: Consider storing what we used to make the layout. However we need to essentially
|
||||
// Recreate some of the info (Sampler in slot X with the actual sampler) so letting Dawn confirm
|
||||
// there isn't a mismatch may be easiest.
|
||||
// Also storing the wgpu ObjectBase takes care of ownership challenges in theory
|
||||
wgpu::BindGroupLayout mLayout;
|
||||
std::vector<wgpu::BindGroupEntry> entries;
|
||||
wgpu::BindGroup mBindGroup;
|
||||
wgpu::BindGroupLayout mLayout = nullptr;
|
||||
static constexpr uint8_t INVALID_INDEX = MAX_DESCRIPTOR_COUNT + 1;
|
||||
std::array<uint8_t, MAX_DESCRIPTOR_COUNT> mEntryIndexByBinding {};
|
||||
std::vector<wgpu::BindGroupEntry> mEntriesSortedByBinding;
|
||||
std::bitset<MAX_DESCRIPTOR_COUNT> mEntriesByBindingWithDynamicOffsets {};
|
||||
std::bitset<MAX_DESCRIPTOR_COUNT> mEntriesByBindingAdded {};
|
||||
std::vector<uint32_t> mDynamicOffsets;
|
||||
wgpu::BindGroup mBindGroup = nullptr;
|
||||
};
|
||||
|
||||
// TODO: Currently WGPUTexture is not used by WebGPU for useful task.
|
||||
// Update the struct when used by WebGPU driver.
|
||||
struct WGPUTexture : public HwTexture {
|
||||
class WGPUTexture : public HwTexture {
|
||||
public:
|
||||
WGPUTexture(SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
||||
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage) noexcept;
|
||||
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage,
|
||||
wgpu::Device const& device) noexcept;
|
||||
|
||||
// constructors for creating texture views
|
||||
WGPUTexture(WGPUTexture const* src, uint8_t baseLevel, uint8_t levelCount) noexcept;
|
||||
WGPUTexture(WGPUTexture* src, uint8_t baseLevel, uint8_t levelCount) noexcept;
|
||||
|
||||
wgpu::Texture texture = nullptr;
|
||||
// TODO: Adding this but not yet setting it up. Filament "Textures" are combined image samplers,
|
||||
// rep both.
|
||||
wgpu::Sampler sampler = nullptr;
|
||||
//TODO: Not sure all the ways HwTexture is used. Overloading like this might be entirely wrong.
|
||||
wgpu::TextureView texView = nullptr;
|
||||
const wgpu::Texture& getTexture() const { return mTexture; }
|
||||
const wgpu::TextureView& getTexView() const { return mTexView; }
|
||||
|
||||
// Public to allow checking for support of a texture format
|
||||
static wgpu::TextureFormat fToWGPUTextureFormat(const filament::backend::TextureFormat& fUsage);
|
||||
|
||||
private:
|
||||
wgpu::TextureView makeTextureView(const uint8_t& baseLevel, const uint8_t& levelCount,
|
||||
SamplerType target);
|
||||
// CreateTextureR has info for a texture and sampler. Texture Views are needed for binding,
|
||||
// along with a sampler Current plan: Inherit the sampler and Texture to always exist (It is a
|
||||
// ref counted pointer) when making views. View is optional
|
||||
wgpu::Texture mTexture = nullptr;
|
||||
wgpu::TextureUsage mUsage = wgpu::TextureUsage::None;
|
||||
wgpu::TextureFormat mFormat = wgpu::TextureFormat::Undefined;
|
||||
uint32_t mArrayLayerCount = 1;
|
||||
wgpu::TextureView mTexView = nullptr;
|
||||
wgpu::TextureUsage fToWGPUTextureUsage(const filament::backend::TextureUsage& fUsage);
|
||||
};
|
||||
|
||||
struct WGPURenderPrimitive : public HwRenderPrimitive {
|
||||
WGPURenderPrimitive() {}
|
||||
|
||||
void setBuffers(WGPUVertexBufferInfo const* const vbi,
|
||||
WGPUVertexBuffer* vertexBuffer, WGPUIndexBuffer* indexBuffer);
|
||||
|
||||
WGPUVertexBuffer* vertexBuffer = nullptr;
|
||||
WGPUIndexBuffer* indexBuffer = nullptr;
|
||||
};
|
||||
|
||||
// TODO: Currently WGPURenderTarget is not used by WebGPU for useful task.
|
||||
// Update the struct when used by WebGPU driver.
|
||||
struct WGPURenderTarget : public HwRenderTarget {
|
||||
class WGPURenderTarget : public HwRenderTarget {
|
||||
public:
|
||||
class Attachment {
|
||||
public:
|
||||
friend struct WGPURenderTarget;
|
||||
friend class WGPURenderTarget;
|
||||
|
||||
Attachment() = default;
|
||||
Attachment(WGPUTexture* gpuTexture, uint8_t level = 0, uint16_t layer = 0)
|
||||
: level(level),
|
||||
layer(layer),
|
||||
texture(gpuTexture->texture),
|
||||
texture(gpuTexture->getTexture()),
|
||||
mWGPUTexture(gpuTexture) {}
|
||||
operator bool() const {
|
||||
return mWGPUTexture != nullptr;
|
||||
}
|
||||
|
||||
uint8_t level = 0;
|
||||
uint16_t layer = 0;
|
||||
@@ -187,8 +233,8 @@ struct WGPURenderTarget : public HwRenderTarget {
|
||||
: HwRenderTarget(0, 0),
|
||||
defaultRenderTarget(true) {}
|
||||
|
||||
void setUpRenderPassAttachments(wgpu::RenderPassDescriptor* descriptor,
|
||||
const RenderPassParams& params);
|
||||
void setUpRenderPassAttachments(wgpu::RenderPassDescriptor& descriptor,
|
||||
wgpu::TextureView const& textureView, RenderPassParams const& params);
|
||||
|
||||
math::uint2 getAttachmentSize() noexcept;
|
||||
|
||||
@@ -198,15 +244,15 @@ struct WGPURenderTarget : public HwRenderTarget {
|
||||
Attachment getDrawColorAttachment(size_t index);
|
||||
Attachment getReadColorAttachment(size_t index);
|
||||
|
||||
static wgpu::LoadOp getLoadOperation(const RenderPassParams& params, TargetBufferFlags buffer);
|
||||
static wgpu::StoreOp getStoreOperation(const RenderPassParams& params, TargetBufferFlags buffer);
|
||||
private:
|
||||
static wgpu::LoadOp getLoadAction(const RenderPassParams& params, TargetBufferFlags buffer);
|
||||
static wgpu::LoadOp getStoreAction(const RenderPassParams& params, TargetBufferFlags buffer);
|
||||
|
||||
bool defaultRenderTarget = false;
|
||||
uint8_t samples = 1;
|
||||
|
||||
Attachment color[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
|
||||
math::uint2 attachmentSize = {};
|
||||
std::vector<wgpu::RenderPassColorAttachment> colorAttachments {};
|
||||
};
|
||||
|
||||
}// namespace filament::backend
|
||||
|
||||
255
filament/backend/src/webgpu/WebGPUPipelineCreation.cpp
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "WebGPUPipelineCreation.h"
|
||||
|
||||
#include "WebGPUHandles.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/TargetBufferInfo.h>
|
||||
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr wgpu::PrimitiveTopology toWebGPU(PrimitiveType primitiveType) {
|
||||
switch (primitiveType) {
|
||||
case PrimitiveType::POINTS:
|
||||
return wgpu::PrimitiveTopology::PointList;
|
||||
case PrimitiveType::LINES:
|
||||
return wgpu::PrimitiveTopology::LineList;
|
||||
case PrimitiveType::LINE_STRIP:
|
||||
return wgpu::PrimitiveTopology::LineStrip;
|
||||
case PrimitiveType::TRIANGLES:
|
||||
return wgpu::PrimitiveTopology::TriangleList;
|
||||
case PrimitiveType::TRIANGLE_STRIP:
|
||||
return wgpu::PrimitiveTopology::TriangleStrip;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr wgpu::CullMode toWebGPU(CullingMode cullMode) {
|
||||
switch (cullMode) {
|
||||
case CullingMode::NONE:
|
||||
return wgpu::CullMode::None;
|
||||
case CullingMode::FRONT:
|
||||
return wgpu::CullMode::Front;
|
||||
case CullingMode::BACK:
|
||||
return wgpu::CullMode::Back;
|
||||
case CullingMode::FRONT_AND_BACK:
|
||||
// no WegGPU equivalent of front and back
|
||||
FILAMENT_CHECK_POSTCONDITION(false)
|
||||
<< "WebGPU does not support CullingMode::FRONT_AND_BACK";
|
||||
return wgpu::CullMode::Undefined;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr wgpu::CompareFunction toWebGPU(SamplerCompareFunc compareFunction) {
|
||||
switch (compareFunction) {
|
||||
case SamplerCompareFunc::LE:
|
||||
return wgpu::CompareFunction::LessEqual;
|
||||
case SamplerCompareFunc::GE:
|
||||
return wgpu::CompareFunction::GreaterEqual;
|
||||
case SamplerCompareFunc::L:
|
||||
return wgpu::CompareFunction::Less;
|
||||
case SamplerCompareFunc::G:
|
||||
return wgpu::CompareFunction::Greater;
|
||||
case SamplerCompareFunc::E:
|
||||
return wgpu::CompareFunction::Equal;
|
||||
case SamplerCompareFunc::NE:
|
||||
return wgpu::CompareFunction::NotEqual;
|
||||
case SamplerCompareFunc::A:
|
||||
return wgpu::CompareFunction::Always;
|
||||
case SamplerCompareFunc::N:
|
||||
return wgpu::CompareFunction::Never;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr wgpu::StencilOperation toWebGPU(StencilOperation stencilOp) {
|
||||
switch (stencilOp) {
|
||||
case StencilOperation::KEEP:
|
||||
return wgpu::StencilOperation::Keep;
|
||||
case StencilOperation::ZERO:
|
||||
return wgpu::StencilOperation::Zero;
|
||||
case StencilOperation::REPLACE:
|
||||
return wgpu::StencilOperation::Replace;
|
||||
case StencilOperation::INCR:
|
||||
return wgpu::StencilOperation::IncrementClamp;
|
||||
case StencilOperation::INCR_WRAP:
|
||||
return wgpu::StencilOperation::IncrementWrap;
|
||||
case StencilOperation::DECR:
|
||||
return wgpu::StencilOperation::DecrementClamp;
|
||||
case StencilOperation::DECR_WRAP:
|
||||
return wgpu::StencilOperation::DecrementWrap;
|
||||
case StencilOperation::INVERT:
|
||||
return wgpu::StencilOperation::Invert;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr wgpu::BlendOperation toWebGPU(BlendEquation blendOp) {
|
||||
switch (blendOp) {
|
||||
case BlendEquation::ADD:
|
||||
return wgpu::BlendOperation::Add;
|
||||
case BlendEquation::SUBTRACT:
|
||||
return wgpu::BlendOperation::Subtract;
|
||||
case BlendEquation::REVERSE_SUBTRACT:
|
||||
return wgpu::BlendOperation::ReverseSubtract;
|
||||
case BlendEquation::MIN:
|
||||
return wgpu::BlendOperation::Min;
|
||||
case BlendEquation::MAX:
|
||||
return wgpu::BlendOperation::Max;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr wgpu::BlendFactor toWebGPU(BlendFunction blendFunction) {
|
||||
switch (blendFunction) {
|
||||
case BlendFunction::ZERO:
|
||||
return wgpu::BlendFactor::Zero;
|
||||
case BlendFunction::ONE:
|
||||
return wgpu::BlendFactor::One;
|
||||
case BlendFunction::SRC_COLOR:
|
||||
return wgpu::BlendFactor::Src;
|
||||
case BlendFunction::ONE_MINUS_SRC_COLOR:
|
||||
return wgpu::BlendFactor::OneMinusSrc;
|
||||
case BlendFunction::DST_COLOR:
|
||||
return wgpu::BlendFactor::Dst;
|
||||
case BlendFunction::ONE_MINUS_DST_COLOR:
|
||||
return wgpu::BlendFactor::OneMinusDst;
|
||||
case BlendFunction::SRC_ALPHA:
|
||||
return wgpu::BlendFactor::SrcAlpha;
|
||||
case BlendFunction::ONE_MINUS_SRC_ALPHA:
|
||||
return wgpu::BlendFactor::OneMinusSrcAlpha;
|
||||
case BlendFunction::DST_ALPHA:
|
||||
return wgpu::BlendFactor::DstAlpha;
|
||||
case BlendFunction::ONE_MINUS_DST_ALPHA:
|
||||
return wgpu::BlendFactor::OneMinusDstAlpha;
|
||||
case BlendFunction::SRC_ALPHA_SATURATE:
|
||||
return wgpu::BlendFactor::SrcAlphaSaturated;
|
||||
}
|
||||
}
|
||||
|
||||
}// namespace
|
||||
|
||||
wgpu::RenderPipeline createWebGPURenderPipeline(wgpu::Device const& device,
|
||||
WGPUProgram const& program, WGPUVertexBufferInfo const& vertexBufferInfo,
|
||||
wgpu::PipelineLayout const& layout, RasterState const& rasterState,
|
||||
StencilState const& stencilState, PolygonOffset const& polygonOffset,
|
||||
PrimitiveType primitiveType, wgpu::TextureFormat colorFormat,
|
||||
wgpu::TextureFormat depthFormat) {
|
||||
assert_invariant(program.vertexShaderModule);
|
||||
const wgpu::DepthStencilState depthStencilState {
|
||||
.format = depthFormat,
|
||||
.depthWriteEnabled = rasterState.depthWrite,
|
||||
.depthCompare = toWebGPU(rasterState.depthFunc),
|
||||
.stencilFront = {
|
||||
.compare = toWebGPU(stencilState.front.stencilFunc),
|
||||
.failOp = toWebGPU(stencilState.front.stencilOpStencilFail),
|
||||
.depthFailOp = toWebGPU(stencilState.front.stencilOpDepthFail),
|
||||
.passOp = toWebGPU(stencilState.front.stencilOpDepthStencilPass),
|
||||
},
|
||||
.stencilBack = {
|
||||
.compare = toWebGPU(stencilState.back.stencilFunc),
|
||||
.failOp = toWebGPU(stencilState.back.stencilOpStencilFail),
|
||||
.depthFailOp = toWebGPU(stencilState.back.stencilOpDepthFail),
|
||||
.passOp = toWebGPU(stencilState.back.stencilOpDepthStencilPass),
|
||||
},
|
||||
.stencilReadMask = 0,
|
||||
.stencilWriteMask = stencilState.stencilWrite ? 0xFFFFFFFF : 0,
|
||||
.depthBias = static_cast<int32_t>(polygonOffset.constant),
|
||||
.depthBiasSlopeScale = polygonOffset.slope,
|
||||
.depthBiasClamp = 0.0f
|
||||
};
|
||||
std::stringstream pipelineLabelStream;
|
||||
pipelineLabelStream << program.name.c_str() << " pipeline";
|
||||
const auto pipelineLabel = pipelineLabelStream.str();
|
||||
wgpu::RenderPipelineDescriptor pipelineDescriptor{
|
||||
.label = wgpu::StringView(pipelineLabel),
|
||||
.layout = layout,
|
||||
.vertex = {
|
||||
.module = program.vertexShaderModule,
|
||||
.entryPoint = "main",
|
||||
.constantCount = program.constants.size(),
|
||||
.constants = program.constants.data(),
|
||||
.bufferCount = vertexBufferInfo.getVertexBufferLayoutSize(),
|
||||
.buffers = vertexBufferInfo.getVertexBufferLayout()
|
||||
},
|
||||
.primitive = {
|
||||
.topology = toWebGPU(primitiveType),
|
||||
// TODO should we assume some constant format here or is there a way to get
|
||||
// this from PipelineState somehow or elsewhere?
|
||||
// Perhaps, cache/assert format from index buffers as they are requested?
|
||||
.stripIndexFormat = wgpu::IndexFormat::Undefined,
|
||||
.frontFace = rasterState.inverseFrontFaces ? wgpu::FrontFace::CW : wgpu::FrontFace::CCW,
|
||||
.cullMode = toWebGPU(rasterState.culling),
|
||||
// TODO no depth clamp in WebGPU supported directly. unclippedDepth is close, so we are
|
||||
// starting there
|
||||
.unclippedDepth = !rasterState.depthClamp &&
|
||||
device.HasFeature(wgpu::FeatureName::DepthClipControl)
|
||||
},
|
||||
.depthStencil = &depthStencilState,
|
||||
.multisample = {
|
||||
.count = 1, // TODO need to get this from the render target
|
||||
.mask = 0xFFFFFFFF,
|
||||
.alphaToCoverageEnabled = rasterState.alphaToCoverage
|
||||
},
|
||||
.fragment = nullptr // will add below if fragment module is included
|
||||
};
|
||||
wgpu::FragmentState fragmentState = {};
|
||||
std::array<wgpu::ColorTargetState, MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT> colorTargets {};
|
||||
const wgpu::BlendState blendState {
|
||||
.color = {
|
||||
.operation = toWebGPU(rasterState.blendEquationRGB),
|
||||
.srcFactor = toWebGPU(rasterState.blendFunctionSrcRGB),
|
||||
.dstFactor = toWebGPU(rasterState.blendFunctionDstRGB)
|
||||
},
|
||||
.alpha = {
|
||||
.operation = toWebGPU(rasterState.blendEquationAlpha),
|
||||
.srcFactor = toWebGPU(rasterState.blendFunctionSrcAlpha),
|
||||
.dstFactor = toWebGPU(rasterState.blendFunctionDstAlpha)
|
||||
}
|
||||
};
|
||||
if (program.fragmentShaderModule != nullptr) {
|
||||
fragmentState.module = program.fragmentShaderModule;
|
||||
fragmentState.entryPoint = "main";
|
||||
fragmentState.constantCount = program.constants.size(),
|
||||
fragmentState.constants = program.constants.data(),
|
||||
fragmentState.targetCount = 1; // TODO need to get this from the render target
|
||||
fragmentState.targets = colorTargets.data();
|
||||
assert_invariant(fragmentState.targetCount <= MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT);
|
||||
for (size_t targetIndex = 0; targetIndex < fragmentState.targetCount; targetIndex++) {
|
||||
auto& colorTarget = colorTargets[targetIndex];
|
||||
colorTarget.format = colorFormat;
|
||||
colorTarget.blend = rasterState.hasBlending() ? &blendState : nullptr;
|
||||
colorTarget.writeMask =
|
||||
rasterState.colorWrite ? wgpu::ColorWriteMask::All : wgpu::ColorWriteMask::None;
|
||||
}
|
||||
pipelineDescriptor.fragment = &fragmentState;
|
||||
}
|
||||
const wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(pipeline)
|
||||
<< "Failed to create render pipeline for " << pipelineDescriptor.label;
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
}// namespace filament::backend
|
||||
46
filament/backend/src/webgpu/WebGPUPipelineCreation.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_FILAMENT_BACKEND_WEBGPUPIPELINECREATION_H
|
||||
#define TNT_FILAMENT_BACKEND_WEBGPUPIPELINECREATION_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace wgpu {
|
||||
class Device;
|
||||
class PipelineLayout;
|
||||
class RenderPipeline;
|
||||
enum class TextureFormat : uint32_t;
|
||||
}// namespace wgpu
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
struct PolygonOffset;
|
||||
enum class PrimitiveType : uint8_t;
|
||||
struct RasterState;
|
||||
struct StencilState;
|
||||
|
||||
class WGPUVertexBufferInfo;
|
||||
class WGPUProgram;
|
||||
|
||||
[[nodiscard]] wgpu::RenderPipeline createWebGPURenderPipeline(wgpu::Device const&,
|
||||
WGPUProgram const&, WGPUVertexBufferInfo const&, wgpu::PipelineLayout const&,
|
||||
RasterState const&, StencilState const&, PolygonOffset const&, PrimitiveType,
|
||||
wgpu::TextureFormat colorFormat, wgpu::TextureFormat depthFormat);
|
||||
|
||||
}// namespace filament::backend
|
||||
|
||||
#endif// TNT_FILAMENT_BACKEND_WEBGPUPIPELINECREATION_H
|
||||
@@ -73,7 +73,8 @@ void printSurfaceCapabilitiesDetails(wgpu::SurfaceCapabilities const& capabiliti
|
||||
#endif
|
||||
|
||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||
void printSurfaceConfiguration(wgpu::SurfaceConfiguration const& config) {
|
||||
void printSurfaceConfiguration(wgpu::SurfaceConfiguration const& config,
|
||||
wgpu::TextureFormat depthFormat) {
|
||||
std::stringstream formatStream{};
|
||||
formatStream << config.format;
|
||||
std::stringstream usageStream{};
|
||||
@@ -82,6 +83,8 @@ void printSurfaceConfiguration(wgpu::SurfaceConfiguration const& config) {
|
||||
alphaModeStream << config.alphaMode;
|
||||
std::stringstream presentModeStream{};
|
||||
presentModeStream << config.presentMode;
|
||||
std::stringstream depthFormatStream;
|
||||
depthFormatStream << depthFormat;
|
||||
FWGPU_LOGI << "WebGPU surface configuration:" << utils::io::endl;
|
||||
FWGPU_LOGI << " surface format: " << formatStream.str() << utils::io::endl;
|
||||
FWGPU_LOGI << " surface usage: " << usageStream.str() << utils::io::endl;
|
||||
@@ -98,10 +101,11 @@ void printSurfaceConfiguration(wgpu::SurfaceConfiguration const& config) {
|
||||
FWGPU_LOGI << " surface width: " << config.width << utils::io::endl;
|
||||
FWGPU_LOGI << " surface height: " << config.height << utils::io::endl;
|
||||
FWGPU_LOGI << " surface present mode: " << presentModeStream.str() << utils::io::endl;
|
||||
FWGPU_LOGI << "WebGPU selected depth format: " << depthFormatStream.str() << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
wgpu::TextureFormat selectColorFormat(size_t availableFormatsCount,
|
||||
[[nodiscard]] constexpr wgpu::TextureFormat selectColorFormat(size_t availableFormatsCount,
|
||||
wgpu::TextureFormat const* availableFormats, bool useSRGBColorSpace) {
|
||||
const std::array expectedColorFormats =
|
||||
useSRGBColorSpace ?
|
||||
@@ -119,7 +123,21 @@ wgpu::TextureFormat selectColorFormat(size_t availableFormatsCount,
|
||||
return *firstFoundColorFormat;
|
||||
}
|
||||
|
||||
wgpu::PresentMode selectPresentMode(size_t availablePresentModesCount,
|
||||
[[nodiscard]] constexpr wgpu::TextureFormat selectDepthFormat(bool depth32FloatStencil8Enabled,
|
||||
bool needStencil) {
|
||||
if (needStencil) {
|
||||
if (depth32FloatStencil8Enabled) {
|
||||
return wgpu::TextureFormat::Depth32FloatStencil8;
|
||||
} else {
|
||||
return wgpu::TextureFormat::Depth24PlusStencil8;
|
||||
}
|
||||
} else {
|
||||
// other options: Depth16Unorm or Depth24Plus
|
||||
return wgpu::TextureFormat::Depth32Float;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr wgpu::PresentMode selectPresentMode(size_t availablePresentModesCount,
|
||||
wgpu::PresentMode const* availablePresentModes) {
|
||||
// Verify that our chosen present mode is supported. In practice all devices support the FIFO
|
||||
// mode, but we check for it anyway for completeness. (and to avoid validation warnings)
|
||||
@@ -133,7 +151,7 @@ wgpu::PresentMode selectPresentMode(size_t availablePresentModesCount,
|
||||
return desiredPresentMode;
|
||||
}
|
||||
|
||||
wgpu::CompositeAlphaMode selectAlphaMode(size_t availableAlphaModesCount,
|
||||
[[nodiscard]] constexpr wgpu::CompositeAlphaMode selectAlphaMode(size_t availableAlphaModesCount,
|
||||
wgpu::CompositeAlphaMode const* availableAlphaModes) {
|
||||
bool autoAvailable = false;
|
||||
bool inheritAvailable = false;
|
||||
@@ -204,13 +222,58 @@ void initConfig(wgpu::SurfaceConfiguration& config, wgpu::Device const& device,
|
||||
config.alphaMode = selectAlphaMode(capabilities.alphaModeCount, capabilities.alphaModes);
|
||||
}
|
||||
|
||||
[[nodiscard]] wgpu::Texture createDepthTexture(wgpu::Device const& device,
|
||||
wgpu::Extent2D const& extent, wgpu::TextureFormat depthFormat) {
|
||||
wgpu::TextureDescriptor descriptor{ .label = "depth_texture",
|
||||
.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment,
|
||||
.dimension = wgpu::TextureDimension::e2D,
|
||||
.size = { .width = extent.width, .height = extent.height, .depthOrArrayLayers = 1 },
|
||||
.format = depthFormat,
|
||||
.mipLevelCount = 1,
|
||||
.sampleCount = 1,
|
||||
.viewFormatCount = 1,
|
||||
.viewFormats = &depthFormat
|
||||
};
|
||||
wgpu::Texture depthTexture = device.CreateTexture(&descriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(depthTexture) << "Failed to create depth texture with width "
|
||||
<< extent.width << " and height " << extent.height;
|
||||
return depthTexture;
|
||||
}
|
||||
|
||||
[[nodiscard]] wgpu::TextureView createDepthTextureView(wgpu::Texture const& depthTexture,
|
||||
wgpu::TextureFormat depthFormat, bool needStencil) {
|
||||
wgpu::TextureViewDescriptor descriptor{
|
||||
.label = "depth_texture_view",
|
||||
.format = depthFormat,
|
||||
.dimension = wgpu::TextureViewDimension::e2D,
|
||||
.baseMipLevel = 0,
|
||||
.mipLevelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.arrayLayerCount = 1,
|
||||
.aspect = wgpu::TextureAspect::DepthOnly,
|
||||
.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment
|
||||
};
|
||||
if (needStencil) {
|
||||
descriptor.aspect = wgpu::TextureAspect::All;
|
||||
}
|
||||
wgpu::TextureView depthTextureView = depthTexture.CreateView(&descriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(depthTextureView) << "Failed to create depth texture view";
|
||||
return depthTextureView;
|
||||
}
|
||||
|
||||
}// namespace
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
WebGPUSwapChain::WebGPUSwapChain(wgpu::Surface&& surface, wgpu::Extent2D const& surfaceSize,
|
||||
wgpu::Adapter& adapter, wgpu::Device& device, uint64_t flags)
|
||||
: mSurface(surface) {
|
||||
wgpu::Adapter const& adapter, wgpu::Device const& device, uint64_t flags)
|
||||
: mDevice(device),
|
||||
mSurface(surface),
|
||||
mNeedStencil((flags & SWAP_CHAIN_HAS_STENCIL_BUFFER) != 0),
|
||||
mDepthFormat(selectDepthFormat(device.HasFeature(wgpu::FeatureName::Depth32FloatStencil8),
|
||||
mNeedStencil)),
|
||||
mDepthTexture(createDepthTexture(device, surfaceSize, mDepthFormat)),
|
||||
mDepthTextureView(createDepthTextureView(mDepthTexture, mDepthFormat, mNeedStencil)) {
|
||||
wgpu::SurfaceCapabilities capabilities = {};
|
||||
if (!mSurface.GetCapabilities(adapter, &capabilities)) {
|
||||
FWGPU_LOGW << "Failed to get WebGPU surface capabilities" << utils::io::endl;
|
||||
@@ -221,12 +284,13 @@ WebGPUSwapChain::WebGPUSwapChain(wgpu::Surface&& surface, wgpu::Extent2D const&
|
||||
}
|
||||
const bool useSRGBColorSpace = (flags & SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) != 0;
|
||||
initConfig(mConfig, device, capabilities, surfaceSize, useSRGBColorSpace);
|
||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||
printSurfaceConfiguration(mConfig, mDepthFormat);
|
||||
#endif
|
||||
mSurface.Configure(&mConfig);
|
||||
}
|
||||
|
||||
WebGPUSwapChain::~WebGPUSwapChain() {
|
||||
mSurface.Unconfigure();
|
||||
}
|
||||
WebGPUSwapChain::~WebGPUSwapChain() { mSurface.Unconfigure(); }
|
||||
|
||||
void WebGPUSwapChain::setExtent(wgpu::Extent2D const& currentSurfaceSize) {
|
||||
FILAMENT_CHECK_POSTCONDITION(currentSurfaceSize.width > 0 || currentSurfaceSize.height > 0)
|
||||
@@ -235,14 +299,16 @@ void WebGPUSwapChain::setExtent(wgpu::Extent2D const& currentSurfaceSize) {
|
||||
if (mConfig.width != currentSurfaceSize.width || mConfig.height != currentSurfaceSize.height) {
|
||||
mConfig.width = currentSurfaceSize.width;
|
||||
mConfig.height = currentSurfaceSize.height;
|
||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||
printSurfaceConfiguration(mConfig);
|
||||
#endif
|
||||
FWGPU_LOGD << "Resizing to width " << mConfig.width << " height " << mConfig.height
|
||||
<< utils::io::endl;
|
||||
// TODO we may need to ensure no surface texture is flight when we do this. some
|
||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||
printSurfaceConfiguration(mConfig, mDepthFormat);
|
||||
#endif
|
||||
// TODO we may need to ensure no surface texture is in flight when we do this. some
|
||||
// synchronization may be necessary
|
||||
mSurface.Configure(&mConfig);
|
||||
mDepthTexture = createDepthTexture(mDevice, currentSurfaceSize, mDepthFormat);
|
||||
mDepthTextureView = createDepthTextureView(mDepthTexture, mDepthFormat, mNeedStencil);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,7 +323,7 @@ wgpu::TextureView WebGPUSwapChain::getCurrentSurfaceTextureView(
|
||||
// Create a view for this surface texture
|
||||
// TODO: review these initiliazations as webgpu pipeline gets mature
|
||||
wgpu::TextureViewDescriptor textureViewDescriptor = {
|
||||
.label = "texture_view",
|
||||
.label = "surface_texture_view",
|
||||
.format = surfaceTexture.texture.GetFormat(),
|
||||
.dimension = wgpu::TextureViewDimension::e2D,
|
||||
.baseMipLevel = 0,
|
||||
|
||||
@@ -29,18 +29,29 @@ namespace filament::backend {
|
||||
class WebGPUSwapChain final : public Platform::SwapChain, HwSwapChain {
|
||||
public:
|
||||
WebGPUSwapChain(wgpu::Surface&& surface, wgpu::Extent2D const& surfaceSize,
|
||||
wgpu::Adapter& adapter, wgpu::Device& device, uint64_t flags);
|
||||
wgpu::Adapter const& adapter, wgpu::Device const& device, uint64_t flags);
|
||||
~WebGPUSwapChain();
|
||||
|
||||
wgpu::TextureView getCurrentSurfaceTextureView(wgpu::Extent2D const&);
|
||||
[[nodiscard]] wgpu::TextureFormat getColorFormat() const { return mConfig.format; }
|
||||
|
||||
[[nodiscard]] wgpu::TextureFormat getDepthFormat() const { return mDepthFormat; }
|
||||
|
||||
[[nodiscard]] wgpu::TextureView getCurrentSurfaceTextureView(wgpu::Extent2D const&);
|
||||
|
||||
[[nodiscard]] wgpu::TextureView getDepthTextureView() const { return mDepthTextureView; }
|
||||
|
||||
void present();
|
||||
|
||||
private:
|
||||
void setExtent(wgpu::Extent2D const&);
|
||||
|
||||
wgpu::Device mDevice = nullptr;
|
||||
wgpu::Surface mSurface = {};
|
||||
wgpu::SurfaceConfiguration mConfig = {};
|
||||
bool mNeedStencil = false;
|
||||
wgpu::TextureFormat mDepthFormat = wgpu::TextureFormat::Undefined;
|
||||
wgpu::Texture mDepthTexture = nullptr;
|
||||
wgpu::TextureView mDepthTextureView = nullptr;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -98,10 +98,46 @@ wgpu::Adapter WebGPUPlatform::requestAdapter(wgpu::Surface const& surface) {
|
||||
}
|
||||
|
||||
wgpu::Device WebGPUPlatform::requestDevice(wgpu::Adapter const& adapter) {
|
||||
// TODO consider passing required features and/or limits
|
||||
// TODO consider passing limits
|
||||
constexpr std::array optionalFeatures = { wgpu::FeatureName::DepthClipControl,
|
||||
wgpu::FeatureName::Depth32FloatStencil8, wgpu::FeatureName::CoreFeaturesAndLimits };
|
||||
|
||||
constexpr std::array requiredFeatures = { wgpu::FeatureName::TransientAttachments };
|
||||
|
||||
wgpu::SupportedFeatures supportedFeatures;
|
||||
adapter.GetFeatures(&supportedFeatures);
|
||||
|
||||
std::vector<wgpu::FeatureName> enabledFeatures;
|
||||
enabledFeatures.reserve(requiredFeatures.size() + optionalFeatures.size());
|
||||
|
||||
std::set_intersection(supportedFeatures.features,
|
||||
supportedFeatures.features + supportedFeatures.featureCount, requiredFeatures.begin(),
|
||||
requiredFeatures.end(), std::back_inserter(enabledFeatures));
|
||||
|
||||
if (enabledFeatures.size() != requiredFeatures.size()) {
|
||||
std::vector<wgpu::FeatureName> missingFeatures;
|
||||
std::set_difference(requiredFeatures.begin(), requiredFeatures.end(),
|
||||
supportedFeatures.features,
|
||||
supportedFeatures.features + supportedFeatures.featureCount,
|
||||
std::back_inserter(missingFeatures));
|
||||
|
||||
std::stringstream missingFeaturesStream{};
|
||||
for (const auto& entry: missingFeatures) {
|
||||
missingFeaturesStream << std::to_string(static_cast<uint32_t>(entry)) << " ";
|
||||
}
|
||||
PANIC_POSTCONDITION("Some required features are not available %s/n",
|
||||
missingFeaturesStream.str().c_str());
|
||||
}
|
||||
|
||||
std::set_intersection(supportedFeatures.features,
|
||||
supportedFeatures.features + supportedFeatures.featureCount, optionalFeatures.begin(),
|
||||
optionalFeatures.end(), std::back_inserter(enabledFeatures));
|
||||
|
||||
wgpu::DeviceDescriptor deviceDescriptor{};
|
||||
deviceDescriptor.label = "graphics_device";
|
||||
deviceDescriptor.defaultQueue.label = "default_queue";
|
||||
deviceDescriptor.requiredFeatureCount = enabledFeatures.size();
|
||||
deviceDescriptor.requiredFeatures = enabledFeatures.data();
|
||||
deviceDescriptor.SetDeviceLostCallback(wgpu::CallbackMode::AllowSpontaneous,
|
||||
[](wgpu::Device const&, wgpu::DeviceLostReason const& reason,
|
||||
wgpu::StringView message) {
|
||||
|
||||
@@ -33,9 +33,10 @@
|
||||
#endif
|
||||
|
||||
ScreenshotParams::ScreenshotParams(int width, int height, std::string fileName,
|
||||
uint32_t expectedHash)
|
||||
uint32_t expectedHash, bool isSrgb)
|
||||
: mWidth(width),
|
||||
mHeight(height),
|
||||
mIsSrgb(isSrgb),
|
||||
mExpectedPixelHash(expectedHash),
|
||||
mFileName(std::move(fileName)) {}
|
||||
|
||||
@@ -47,6 +48,10 @@ int ScreenshotParams::height() const {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
bool ScreenshotParams::isSrgb() const {
|
||||
return mIsSrgb;
|
||||
}
|
||||
|
||||
uint32_t ScreenshotParams::expectedHash() const {
|
||||
return mExpectedPixelHash;
|
||||
}
|
||||
@@ -147,13 +152,25 @@ RenderTargetDump::RenderTargetDump(filament::backend::DriverApi& api,
|
||||
auto* internal = static_cast<RenderTargetDump::Internal*>(user);
|
||||
internal->bytesFilled = true;
|
||||
#ifndef FILAMENT_IOS
|
||||
image::LinearImage image(internal->params.width(), internal->params.width(), 4);
|
||||
image = image::toLinearWithAlpha<uint8_t>(internal->params.width(),
|
||||
internal->params.height(),
|
||||
internal->params.width() * 4, (uint8_t*)buffer);
|
||||
image::LinearImage image;
|
||||
if (internal->params.isSrgb()) {
|
||||
image = image::toLinearWithAlpha<uint8_t>(internal->params.width(),
|
||||
internal->params.height(),
|
||||
internal->params.width() * 4, (uint8_t*)buffer);
|
||||
} else {
|
||||
// The image data is already linear, so pass in transforms that simply go from uint8_t
|
||||
// to float. toLinearWithAlpha divides the float values by uint8_t max so there's no
|
||||
// need to scale it to [0, 1]
|
||||
image = image::toLinearWithAlpha<uint8_t>(
|
||||
internal->params.width(), internal->params.height(),
|
||||
internal->params.width() * 4, (uint8_t*) buffer,
|
||||
[](uint8_t value) -> float { return value; },
|
||||
[](filament::math::float4 rgba) -> filament::math::float4 { return rgba; });
|
||||
}
|
||||
std::string filePath = internal->params.actualFilePath();
|
||||
std::ofstream pngStream(filePath, std::ios::binary | std::ios::trunc);
|
||||
image::ImageEncoder::encode(pngStream, image::ImageEncoder::Format::PNG, image, "",
|
||||
// To avoid going from linear -> sRGB -> linear save the PNG as linear.
|
||||
image::ImageEncoder::encode(pngStream, image::ImageEncoder::Format::PNG_LINEAR, image, "",
|
||||
filePath);
|
||||
#endif
|
||||
};
|
||||
@@ -175,8 +192,12 @@ RenderTargetDump::~RenderTargetDump() {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t RenderTargetDump::Internal::hash() const {
|
||||
return utils::hash::murmur3((uint32_t*)bytes.data(), bytes.size() / 4, 0);
|
||||
}
|
||||
|
||||
uint32_t RenderTargetDump::hash() const {
|
||||
return utils::hash::murmur3((uint32_t*)mInternal->bytes.data(), mInternal->bytes.size() / 4, 0);
|
||||
return mInternal->hash();
|
||||
}
|
||||
|
||||
bool RenderTargetDump::bytesFilled() const {
|
||||
@@ -204,9 +225,15 @@ LoadedPng::LoadedPng(std::string filePath) : mFilePath(std::move(filePath)) {
|
||||
|
||||
uint32_t LoadedPng::hash() const {
|
||||
EXPECT_THAT(mBytes, testing::Not(testing::IsEmpty()))
|
||||
<< "Failed to load expected test result: " << mFilePath;
|
||||
<< "Failed to load expected test result: " << mFilePath << ".\n"
|
||||
<< "Did you forget to sync CMake after updating the expected image in the source "
|
||||
"directory?";
|
||||
if (mBytes.empty()) {
|
||||
return 0;
|
||||
}
|
||||
return utils::hash::murmur3((uint32_t*)mBytes.data(), mBytes.size() / 4, 0);
|
||||
}
|
||||
|
||||
const std::vector<unsigned char>& LoadedPng::bytes() const {
|
||||
return mBytes;
|
||||
}
|
||||
|
||||
@@ -40,10 +40,12 @@ do { \
|
||||
*/
|
||||
class ScreenshotParams {
|
||||
public:
|
||||
ScreenshotParams(int width, int height, std::string fileName, uint32_t expectedPixelHash);
|
||||
ScreenshotParams(int width, int height, std::string fileName, uint32_t expectedPixelHash,
|
||||
bool isSrgb = false);
|
||||
|
||||
int width() const;
|
||||
int height() const;
|
||||
bool isSrgb() const;
|
||||
uint32_t expectedHash() const;
|
||||
|
||||
static std::string actualDirectoryPath();
|
||||
@@ -56,6 +58,7 @@ public:
|
||||
private:
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
bool mIsSrgb;
|
||||
uint32_t mExpectedPixelHash;
|
||||
std::string mFileName;
|
||||
};
|
||||
@@ -92,6 +95,8 @@ private:
|
||||
ScreenshotParams params;
|
||||
std::atomic<bool> bytesFilled = false;
|
||||
std::vector<unsigned char> bytes;
|
||||
|
||||
uint32_t hash() const;
|
||||
};
|
||||
|
||||
// We need a memory location that won't be invalidated to pass to GPU callbacks as they can't
|
||||
@@ -105,6 +110,8 @@ public:
|
||||
|
||||
uint32_t hash() const;
|
||||
|
||||
const std::vector<unsigned char>& bytes() const;
|
||||
|
||||
private:
|
||||
std::string mFilePath;
|
||||
std::vector<unsigned char> mBytes;
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
#include "backend/Handle.h"
|
||||
#include "backend/DriverApiForward.h"
|
||||
#include "BackendTest.h"
|
||||
@@ -71,6 +74,7 @@ private:
|
||||
|
||||
template <typename HandleType>
|
||||
filament::backend::Handle<HandleType> Cleanup::add(filament::backend::Handle<HandleType> handle) {
|
||||
EXPECT_THAT(handle, ::testing::IsTrue()) << "Added a null handle to clean up.";
|
||||
addInternal(handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ Shader::Shader(DriverApi& api, Cleanup& cleanup, ShaderConfig config) : mCleanup
|
||||
// This assumes that the uniforms will all be in a single descriptor set at index 1.
|
||||
// If there are shaders with uniforms in other sets then ShaderConfig will need to be expanded
|
||||
// to accommodate that.
|
||||
size_t kDescriptorSetIndex = 1;
|
||||
size_t kDescriptorSetIndex = 0;
|
||||
filamat::DescriptorSets descriptors;
|
||||
descriptors[kDescriptorSetIndex] = filamat::DescriptorSetInfo(config.uniforms.size());
|
||||
for (unsigned char i = 0; i < config.uniforms.size(); ++i) {
|
||||
@@ -52,11 +52,13 @@ Shader::Shader(DriverApi& api, Cleanup& cleanup, ShaderConfig config) : mCleanup
|
||||
config.uniforms[i].name,
|
||||
config.uniforms[i].type.value_or(DescriptorType::UNIFORM_BUFFER), i };
|
||||
}
|
||||
prog.descriptorBindings(1, bindingsInfo);
|
||||
prog.descriptorBindings(0, bindingsInfo);
|
||||
mProgram = cleanup.add(api.createProgram(std::move(prog)));
|
||||
|
||||
mDescriptorSetLayout = cleanup.add(
|
||||
api.createDescriptorSetLayout(DescriptorSetLayout{ kLayouts }));
|
||||
if (!kLayouts.empty()) {
|
||||
mDescriptorSetLayout =
|
||||
cleanup.add(api.createDescriptorSetLayout(DescriptorSetLayout{ kLayouts }));
|
||||
}
|
||||
}
|
||||
|
||||
filament::backend::DescriptorSetHandle Shader::createDescriptorSet(DriverApi& api) const {
|
||||
@@ -64,10 +66,15 @@ filament::backend::DescriptorSetHandle Shader::createDescriptorSet(DriverApi& ap
|
||||
}
|
||||
|
||||
filament::backend::ProgramHandle Shader::getProgram() const {
|
||||
assert(mProgram);
|
||||
EXPECT_THAT(mProgram, ::testing::IsTrue())
|
||||
<< "Shader program accessed despite being null.";
|
||||
return mProgram;
|
||||
}
|
||||
|
||||
filament::backend::DescriptorSetLayoutHandle Shader::getDescriptorSetLayout() const {
|
||||
EXPECT_THAT(mDescriptorSetLayout, ::testing::IsTrue())
|
||||
<< "Shader descriptor set layout accessed despite being null.";
|
||||
return mDescriptorSetLayout;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ public:
|
||||
protected:
|
||||
Cleanup& mCleanup;
|
||||
filament::backend::ProgramHandle mProgram;
|
||||
// This will be a null handle if there are no uniforms.
|
||||
filament::backend::DescriptorSetLayoutHandle mDescriptorSetLayout;
|
||||
};
|
||||
|
||||
@@ -106,7 +107,7 @@ ResolvedUniformBindingConfig UniformBindingConfig::resolve() {
|
||||
.dataSize = resolvedDataSize,
|
||||
.bufferSize = bufferSize.value_or(resolvedDataSize),
|
||||
.byteOffset = byteOffset.value_or(0),
|
||||
.set = set.value_or(1),
|
||||
.set = set.value_or(0),
|
||||
.binding = binding.value_or(0),
|
||||
.descriptorSet = descriptorSet
|
||||
};
|
||||
|
||||
@@ -138,7 +138,7 @@ std::optional<std::string> GetGlslUniform(ShaderUniformType type) {
|
||||
}
|
||||
case ShaderUniformType::Simple: {
|
||||
return R"(
|
||||
layout(binding = 0, set = 1) uniform Params {
|
||||
layout(binding = 0, set = 0) uniform Params {
|
||||
highp vec4 color;
|
||||
// Use scaleMinusOne instead of scale so that a 0 initialized value is a good default
|
||||
highp vec4 scaleMinusOne;
|
||||
@@ -148,7 +148,7 @@ layout(binding = 0, set = 1) uniform Params {
|
||||
}
|
||||
case ShaderUniformType::SimpleWithPadding: {
|
||||
return R"(
|
||||
layout(binding = 0, set = 1) uniform Params {
|
||||
layout(binding = 0, set = 0) uniform Params {
|
||||
highp vec4 padding[4]; // offset of 64 bytes
|
||||
|
||||
highp vec4 color;
|
||||
@@ -160,7 +160,7 @@ layout(binding = 0, set = 1) uniform Params {
|
||||
}
|
||||
case ShaderUniformType::Sampler: {
|
||||
return R"(
|
||||
layout(location = 0, set = 1) uniform sampler2D test_tex;
|
||||
layout(location = 0, set = 0) uniform sampler2D test_tex;
|
||||
)";
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -20,13 +20,27 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "BackendTest.h"
|
||||
|
||||
// skipEnvironment must be a test::SkipEnvironment
|
||||
#define SKIP_IF(skipEnvironment) \
|
||||
do { \
|
||||
SkipEnvironment skip(skipEnvironment); \
|
||||
if (skip.matches()) { \
|
||||
GTEST_SKIP() << "Skipping test as the " << skip.describe(); \
|
||||
} \
|
||||
// skipEnvironment must be a test::SkipEnvironment or something that can be passed to the type's
|
||||
// constructor
|
||||
// rationale must be a string
|
||||
#define SKIP_IF(skipEnvironment, rationale) \
|
||||
do { \
|
||||
SkipEnvironment skip(skipEnvironment); \
|
||||
if (skip.matches()) { \
|
||||
GTEST_SKIP() << "Skipping test as the " << skip.describe() << "\n" \
|
||||
<< " This test can't run there because " << rationale; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define FAIL_IF(skipEnvironment, rationale) \
|
||||
do { \
|
||||
SkipEnvironment skip(skipEnvironment); \
|
||||
if (skip.matches()) { \
|
||||
GTEST_FAIL() \
|
||||
<< "Failing test as the " << skip.describe() << "\n" \
|
||||
<< " This test should be able to succeed but it needs to fail early because" \
|
||||
<< rationale; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
namespace test {
|
||||
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 982 B After Width: | Height: | Size: 915 B |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.6 KiB |
BIN
filament/backend/test/expected_images/pushConstants.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
62
filament/backend/test/move_actual_images_to_expected.py
Normal file
@@ -0,0 +1,62 @@
|
||||
import os, shutil, argparse, typing
|
||||
|
||||
def match_sufffix(file_name: str, suffix: str, accepted_prefixes: typing.List[str]) -> str:
|
||||
"""
|
||||
Check if the file name is one of the searched for ones with the given suffix and if so return it.
|
||||
:param accepted_prefixes: If None accepts any prefix
|
||||
:return: file_name with the suffix removed or "" if it doesn't match. This does mean a string that
|
||||
is just the suffix is considered to not match as it will return the empty string.
|
||||
"""
|
||||
if file_name.endswith(suffix):
|
||||
prefix = file_name.removesuffix(suffix)
|
||||
if accepted_prefixes is None or prefix in accepted_prefixes:
|
||||
return prefix
|
||||
return ""
|
||||
|
||||
|
||||
def replace_file_names(path: str, removed: str, replacement: str = "", output_path: str = "",
|
||||
prefixes: typing.List[str] = None):
|
||||
if not output_path:
|
||||
output_path = path
|
||||
for file_name in os.listdir(path=path):
|
||||
prefix = match_sufffix(file_name, removed, prefixes)
|
||||
if prefix:
|
||||
# Remove the prefix from the list so that prefixes is the list of intended but not yet found
|
||||
# files.
|
||||
if prefixes is not None:
|
||||
prefixes.remove(prefix)
|
||||
new_file_name = prefix + replacement
|
||||
new_file_path = os.path.join(output_path, new_file_name)
|
||||
old_file_path = os.path.join(path, file_name)
|
||||
print(f'{old_file_path} to {new_file_path}')
|
||||
shutil.move(old_file_path, new_file_path)
|
||||
if prefixes is not None:
|
||||
for unfound_prefix in prefixes:
|
||||
print(f'Failed to find {unfound_prefix}_actual.png')
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(prog='Backend Test File Renamer',
|
||||
description='Moves actual generated test images to the expected '
|
||||
'images directory, to update the test requirements. '
|
||||
'test_cases accepts multiple arguments that should '
|
||||
'be the name of the expected image file without the '
|
||||
'.png suffix. Also --all can be passed to copy all '
|
||||
'images.\n'
|
||||
'Remember to sync CMake after running this to move '
|
||||
'the new expected images to the binary directory.')
|
||||
parser.add_argument('-i', '--input_path')
|
||||
parser.add_argument('-o', '--output_path', default="./expected_images")
|
||||
parser.add_argument('-t', '--test_cases', action='extend', nargs='*')
|
||||
parser.add_argument('-a', '--all', action='store_true')
|
||||
|
||||
args = parser.parse_args()
|
||||
input_path = "."
|
||||
if args.input_path:
|
||||
input_path = args.input_path
|
||||
|
||||
prefixes = args.test_cases
|
||||
if args.all:
|
||||
prefixes = None
|
||||
|
||||
replace_file_names(path=input_path, output_path=args.output_path, removed="_actual.png",
|
||||
replacement=".png", prefixes=prefixes)
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "Lifetimes.h"
|
||||
#include "Shader.h"
|
||||
#include "SharedShaders.h"
|
||||
#include "Skip.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
|
||||
#include <utils/Hash.h>
|
||||
@@ -309,7 +310,7 @@ TEST_F(BlitTest, ColorResolve) {
|
||||
|
||||
PipelineState state = {};
|
||||
state.program = shader.getProgram();
|
||||
state.pipelineLayout.setLayout[1] = { shader.getDescriptorSetLayout() };
|
||||
state.pipelineLayout.setLayout[0] = { shader.getDescriptorSetLayout() };
|
||||
state.rasterState.colorWrite = true;
|
||||
state.rasterState.depthWrite = false;
|
||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
@@ -489,6 +490,7 @@ TEST_F(BlitTest, BlitRegion) {
|
||||
}
|
||||
|
||||
TEST_F(BlitTest, BlitRegionToSwapChain) {
|
||||
FAIL_IF(Backend::VULKAN, "Crashes due to not finding color attachment");
|
||||
auto& api = getDriverApi();
|
||||
mCleanup.addPostCall([&]() { executeCommands(); });
|
||||
|
||||
|
||||