Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
794420ebdf |
@@ -1,7 +0,0 @@
|
||||
name: 'Set up dependency versions'
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Set up dependency versions
|
||||
shell: bash
|
||||
run: cat ./build/common/versions >> $GITHUB_ENV
|
||||
@@ -1,38 +0,0 @@
|
||||
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
|
||||
@@ -1,23 +0,0 @@
|
||||
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
|
||||
@@ -1,16 +0,0 @@
|
||||
name: 'Web Preqrequisites'
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: ./.github/actions/dep-versions
|
||||
- name: Cache EMSDK
|
||||
id: emsdk-cache
|
||||
uses: actions/cache@v4 # Use a specific version
|
||||
with:
|
||||
path: emsdk
|
||||
key: ${{ runner.os }}-emsdk-${{ env.GITHUB_EMSDK_VERSION }}
|
||||
- name: Install Web Prerequisites
|
||||
shell: bash
|
||||
run: |
|
||||
bash ./build/common/get-emscripten.sh
|
||||
echo "EMSDK=$PWD/emsdk" >> $GITHUB_ENV
|
||||
@@ -12,13 +12,10 @@ jobs:
|
||||
name: build-android
|
||||
# We intentially use a larger runner here to enable larger disk space
|
||||
# (standard linux runner will fail on disk space and faster build time).
|
||||
runs-on: 'ubuntu-24.04-32core'
|
||||
runs-on: ubuntu-22.04-32core
|
||||
|
||||
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:
|
||||
|
||||
@@ -14,9 +14,6 @@ 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
|
||||
|
||||
@@ -10,13 +10,10 @@ on:
|
||||
jobs:
|
||||
build-linux:
|
||||
name: build-linux
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
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 continuous
|
||||
|
||||
@@ -14,9 +14,6 @@ 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
|
||||
@@ -26,4 +23,4 @@ jobs:
|
||||
path: out/filament-release-darwin.tgz
|
||||
- name: Check public headers
|
||||
run: |
|
||||
test/check-headers/test.sh out/release/filament/include
|
||||
build/common/check-headers.sh out/release/filament/include
|
||||
|
||||
@@ -9,32 +9,20 @@ on:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
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: |
|
||||
cd build/mac && printf "y" | ./build.sh presubmit
|
||||
- name: Test material parser
|
||||
run: |
|
||||
out/cmake-release/filament/test/test_material_parser
|
||||
build-desktop:
|
||||
name: build-desktop
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-14-xlarge, ubuntu-22.04-16core]
|
||||
|
||||
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
|
||||
WORKFLOW_OS=`echo \`uname\` | sed "s/Darwin/mac/" | tr [:upper:] [:lower:]`
|
||||
cd build/$WORKFLOW_OS && printf "y" | ./build.sh presubmit
|
||||
- name: Test material parser
|
||||
run: |
|
||||
out/cmake-release/filament/test/test_material_parser
|
||||
@@ -45,8 +33,6 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Run build script
|
||||
run: |
|
||||
build\windows\build-github.bat presubmit
|
||||
@@ -54,13 +40,10 @@ jobs:
|
||||
|
||||
build-android:
|
||||
name: build-android
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
runs-on: ubuntu-22.04-16core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
@@ -77,9 +60,6 @@ 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 presubmit
|
||||
@@ -89,21 +69,17 @@ jobs:
|
||||
|
||||
build-web:
|
||||
name: build-web
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
runs-on: ubuntu-22.04-16core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- uses: ./.github/actions/web-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/web && printf "y" | ./build.sh presubmit
|
||||
|
||||
validate-docs:
|
||||
name: validate-docs
|
||||
runs-on: 'ubuntu-24.04-4core'
|
||||
runs-on: ubuntu-22.04-4core
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
@@ -119,22 +95,18 @@ 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:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Cache Mesa and deps
|
||||
id: mesa-cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: mesa
|
||||
key: ${{ runner.os }}-mesa-deps-2-${{ vars.MESA_VERSION }}
|
||||
- name: Prerequisites
|
||||
id: prereqs
|
||||
python-version: '3.x'
|
||||
- name: Install python prereqs
|
||||
run: pip install mako setuptools pyyaml
|
||||
- name: Run script
|
||||
run: |
|
||||
bash build/common/get-mesa.sh
|
||||
pip install tifffile numpy
|
||||
- name: Run Test
|
||||
run: bash test/renderdiff/test.sh
|
||||
bash test/renderdiff/test.sh
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: presubmit-renderdiff-result
|
||||
@@ -142,34 +114,11 @@ jobs:
|
||||
|
||||
validate-wgsl-webgpu:
|
||||
name: validate-wgsl-webgpu
|
||||
runs-on: 'ubuntu-24.04-8core'
|
||||
runs-on: ubuntu-22.04-8core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- name: Run build script
|
||||
run: ./build.sh -W debug test_filamat filament
|
||||
run: source ./build/linux/ci-common.sh && ./build.sh -W debug test_filamat filament
|
||||
- name: Run test
|
||||
run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl*
|
||||
|
||||
test-code-correctness:
|
||||
name: test-code-correctness
|
||||
runs-on: 'macos-14-xlarge'
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Install clang-tidy and deps
|
||||
run: |
|
||||
pip install pyyaml
|
||||
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
|
||||
|
||||
@@ -29,11 +29,15 @@ on:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
build-linux:
|
||||
name: build-linux
|
||||
runs-on: ubuntu-22.04-32core
|
||||
build-desktop:
|
||||
name: build-desktop
|
||||
runs-on: ${{ matrix.os }}
|
||||
if: github.event_name == 'release' || github.event.inputs.platform == 'desktop'
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-14-xlarge, ubuntu-22.04-32core]
|
||||
|
||||
steps:
|
||||
- name: Decide Git ref
|
||||
id: git_ref
|
||||
@@ -45,48 +49,15 @@ 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 }}
|
||||
run: |
|
||||
cd build/linux && printf "y" | ./build.sh release
|
||||
WORKFLOW_OS=`echo \`uname\` | sed "s/Darwin/mac/" | tr [:upper:] [:lower:]`
|
||||
cd build/$WORKFLOW_OS && 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: macos-14-xlarge
|
||||
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/mac-prereq
|
||||
- name: Run build script
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
run: |
|
||||
cd build/mac && printf "y" | ./build.sh release
|
||||
cd ../..
|
||||
mv out/filament-release-darwin.tgz out/filament-${TAG}-mac.tgz
|
||||
if [ -f out/filament-release-darwin.tgz ]; then mv out/filament-release-darwin.tgz out/filament-${TAG}-mac.tgz; fi;
|
||||
if [ -f out/filament-release-linux.tgz ]; then mv out/filament-release-linux.tgz out/filament-${TAG}-linux.tgz; fi;
|
||||
- uses: actions/github-script@v6
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
@@ -99,7 +70,7 @@ jobs:
|
||||
|
||||
build-web:
|
||||
name: build-web
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
runs-on: ubuntu-22.04-16core
|
||||
if: github.event_name == 'release' || github.event.inputs.platform == 'web'
|
||||
|
||||
steps:
|
||||
@@ -113,8 +84,6 @@ jobs:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- uses: ./.github/actions/web-prereq
|
||||
- name: Run build script
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
@@ -134,7 +103,7 @@ jobs:
|
||||
|
||||
build-android:
|
||||
name: build-android
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
runs-on: ubuntu-22.04-16core
|
||||
if: github.event_name == 'release' || github.event.inputs.platform == 'android'
|
||||
|
||||
steps:
|
||||
@@ -152,7 +121,6 @@ jobs:
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- name: Run build script
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
@@ -163,9 +131,6 @@ jobs:
|
||||
mv out/filamat-android-release.aar out/filamat-${TAG}-android.aar
|
||||
mv out/gltfio-android-release.aar out/gltfio-${TAG}-android.aar
|
||||
mv out/filament-utils-android-release.aar out/filament-utils-${TAG}-android.aar
|
||||
cd out/android-release/filament
|
||||
tar -czf ../../filament-${TAG}-android-native.tgz .
|
||||
cd ../../..
|
||||
- name: Sign sample-gltf-viewer
|
||||
run: |
|
||||
echo "${APK_KEYSTORE_BASE64}" > filament.jks.base64
|
||||
@@ -187,7 +152,7 @@ jobs:
|
||||
script: |
|
||||
const upload = require('./build/common/upload-release-assets');
|
||||
const { TAG } = process.env;
|
||||
const globber = await glob.create(['out/*.aar', 'out/*.apk', 'out/*.tgz'].join('\n'));
|
||||
const globber = await glob.create(['out/*.aar', 'out/*.apk'].join('\n'));
|
||||
await upload({ github, context }, await globber.glob(), TAG);
|
||||
|
||||
build-ios:
|
||||
@@ -206,7 +171,6 @@ 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 }}
|
||||
|
||||
@@ -10,14 +10,10 @@ on:
|
||||
jobs:
|
||||
build-web:
|
||||
name: build-web
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
runs-on: ubuntu-22.04-16core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- uses: ./.github/actions/web-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/web && printf "y" | ./build.sh continuous
|
||||
|
||||
@@ -363,8 +363,6 @@ python ./emsdk.py activate latest
|
||||
source ./emsdk_env.sh
|
||||
```
|
||||
|
||||
Alternatively, you can try running the script `build/common/get-emscripten.sh`.
|
||||
|
||||
After this you can invoke the [easy build](#easy-build) script as follows:
|
||||
|
||||
```shell
|
||||
|
||||
@@ -334,9 +334,6 @@ if (MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_STANDARD} /W0 /Zc:__cplusplus")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_STANDARD} -fstrict-aliasing -Wno-unknown-pragmas -Wno-unused-function -Wno-deprecated-declarations")
|
||||
if (APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-nullability-extension")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (FILAMENT_USE_EXTERNAL_GLES3)
|
||||
@@ -801,7 +798,6 @@ add_subdirectory(${EXTERNAL}/draco/tnt)
|
||||
add_subdirectory(${EXTERNAL}/jsmn/tnt)
|
||||
add_subdirectory(${EXTERNAL}/stb/tnt)
|
||||
add_subdirectory(${EXTERNAL}/getopt)
|
||||
add_subdirectory(${EXTERNAL}/perfetto/tnt)
|
||||
|
||||
# Note that this has to be placed after mikktspace in order for combine_static_libs to work.
|
||||
add_subdirectory(${LIBRARIES}/geometry)
|
||||
|
||||
@@ -7,3 +7,6 @@ for next branch cut* header.
|
||||
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
||||
|
||||
## Release notes for next branch cut
|
||||
|
||||
- materials: five custom variables (varyings) are now available on the condition that the `color` attribute is not requested (b/404930099). [⚠️ **New Material Version**]
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.60.1'
|
||||
implementation 'com.google.android.filament:filament-android:1.58.1'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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.60.1'
|
||||
pod 'Filament', '~> 1.58.1'
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -7,42 +7,6 @@ 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.61.0
|
||||
|
||||
- materials: sampler now export their type in the material binary [⚠️ **New Material Version**]
|
||||
- samples/texturedquad.cpp now has CLI to select backend api
|
||||
- samples/hellopbr.cpp CLI now allows for selecting webgpu
|
||||
|
||||
## v1.60.1
|
||||
|
||||
|
||||
## v1.60.0
|
||||
|
||||
- materials: remove dependence on per-view descset layout from filamat. [⚠️ **New Material Version**]
|
||||
- matc non-functional change: Update GLSL postprocessor to
|
||||
isolate calls to SPVRemap from calls to SPIRV-Cross.
|
||||
|
||||
|
||||
## v1.59.5
|
||||
|
||||
|
||||
## v1.59.4
|
||||
|
||||
|
||||
## v1.59.3
|
||||
|
||||
|
||||
## v1.59.2
|
||||
|
||||
- Fix build/compile errors when upgrading to MacOS 15.4
|
||||
|
||||
## v1.59.1
|
||||
|
||||
|
||||
## v1.59.0
|
||||
|
||||
- materials: five custom variables (varyings) are now available on the condition that the `color` attribute is not requested (b/404930099). [⚠️ **New Material Version**]
|
||||
|
||||
## v1.58.2
|
||||
|
||||
- engine: Generate 1D instead of 3D LUTs for color grading whenever possible.
|
||||
|
||||
@@ -94,7 +94,7 @@ buildscript {
|
||||
|
||||
ext.versions = [
|
||||
'jdk': 17,
|
||||
'minSdk': 21,
|
||||
'minSdk': 26,
|
||||
'targetSdk': 34,
|
||||
'compileSdk': 34,
|
||||
'kotlin': '2.0.21',
|
||||
@@ -125,7 +125,7 @@ buildscript {
|
||||
ext.cmakeArgs = [
|
||||
"--no-warn-unused-cli",
|
||||
"-DANDROID_PIE=ON",
|
||||
"-DANDROID_PLATFORM=21",
|
||||
"-DANDROID_PLATFORM=26",
|
||||
"-DANDROID_STL=c++_static",
|
||||
"-DFILAMENT_DIST_DIR=${filamentPath}".toString(),
|
||||
"-DFILAMENT_SUPPORTS_VULKAN=${excludeVulkan ? 'OFF' : 'ON'}".toString(),
|
||||
@@ -200,7 +200,7 @@ subprojects {
|
||||
ndkVersion versions.ndk
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion versions.minSdk
|
||||
minSdkVersion 26
|
||||
targetSdkVersion versions.targetSdk
|
||||
|
||||
externalNativeBuild {
|
||||
|
||||
@@ -142,12 +142,6 @@ abstract class MaterialCompiler extends TaskWithBinary {
|
||||
if (!exclude_vulkan) {
|
||||
matcArgs += ['-a', 'vulkan']
|
||||
}
|
||||
def include_webgpu = providers
|
||||
.gradleProperty("com.google.android.filament.include-webgpu")
|
||||
.forUseAtConfigurationTime().present
|
||||
if (include_webgpu) {
|
||||
matcArgs += ['-a', 'webgpu', '--variant-filter=skinning,stereo']
|
||||
}
|
||||
|
||||
def mat_no_opt = providers
|
||||
.gradleProperty("com.google.android.filament.matnopt")
|
||||
|
||||
@@ -26,10 +26,6 @@ add_library(utils STATIC IMPORTED)
|
||||
set_target_properties(utils PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libutils.a)
|
||||
|
||||
add_library(perfetto STATIC IMPORTED)
|
||||
set_target_properties(perfetto PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libperfetto.a)
|
||||
|
||||
add_library(filabridge STATIC IMPORTED)
|
||||
set_target_properties(filabridge PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilabridge.a)
|
||||
@@ -44,7 +40,6 @@ set_target_properties(shaders PROPERTIES IMPORTED_LOCATION
|
||||
|
||||
set(FILAMAT_INCLUDE_DIRS
|
||||
../../libs/utils/include
|
||||
../../third_party/perfetto
|
||||
)
|
||||
|
||||
include_directories(${FILAMENT_DIR}/include)
|
||||
@@ -60,7 +55,6 @@ target_link_libraries(filamat-jni
|
||||
filabridge
|
||||
shaders
|
||||
utils
|
||||
perfetto
|
||||
log
|
||||
smol-v
|
||||
$<$<STREQUAL:${FILAMENT_SUPPORTS_WEBGPU},ON>:tint>
|
||||
|
||||
@@ -21,10 +21,6 @@ add_library(utils STATIC IMPORTED)
|
||||
set_target_properties(utils PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libutils.a)
|
||||
|
||||
add_library(perfetto STATIC IMPORTED)
|
||||
set_target_properties(perfetto PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libperfetto.a)
|
||||
|
||||
add_library(ibl-lite STATIC IMPORTED)
|
||||
set_target_properties(ibl-lite PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libibl-lite.a)
|
||||
@@ -127,7 +123,6 @@ target_link_libraries(filament-jni
|
||||
PRIVATE android
|
||||
PRIVATE jnigraphics
|
||||
PRIVATE utils
|
||||
PRIVATE perfetto
|
||||
|
||||
# libgeometry is PUBLIC because gltfio uses it.
|
||||
PUBLIC geometry
|
||||
@@ -146,7 +141,6 @@ target_include_directories(filament-jni PRIVATE
|
||||
${FILAMENT_DIR}/include
|
||||
../../filament/backend/include
|
||||
../../third_party/robin-map
|
||||
../../third_party/perfetto
|
||||
../../libs/utils/include)
|
||||
|
||||
# Force a relink when the version script is changed:
|
||||
|
||||
@@ -1801,22 +1801,6 @@ public class View {
|
||||
* @see setAmbientOcclusionOptions()
|
||||
*/
|
||||
public static class AmbientOcclusionOptions {
|
||||
public enum AmbientOcclusionType {
|
||||
/**
|
||||
* use Scalable Ambient Occlusion
|
||||
*/
|
||||
SAO,
|
||||
/**
|
||||
* use Ground Truth-Based Ambient Occlusion
|
||||
*/
|
||||
GTAO,
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of ambient occlusion algorithm.
|
||||
*/
|
||||
@NonNull
|
||||
public AmbientOcclusionOptions.AmbientOcclusionType aoType = AmbientOcclusionOptions.AmbientOcclusionType.SAO;
|
||||
/**
|
||||
* Ambient Occlusion radius in meters, between 0 and ~10.
|
||||
*/
|
||||
@@ -1826,8 +1810,7 @@ public class View {
|
||||
*/
|
||||
public float power = 1.0f;
|
||||
/**
|
||||
* Self-occlusion bias in meters. Use to avoid self-occlusion.
|
||||
* Between 0 and a few mm. No effect when aoType set to GTAO
|
||||
* Self-occlusion bias in meters. Use to avoid self-occlusion. Between 0 and a few mm.
|
||||
*/
|
||||
public float bias = 0.0005f;
|
||||
/**
|
||||
@@ -1843,12 +1826,12 @@ public class View {
|
||||
*/
|
||||
public float bilateralThreshold = 0.05f;
|
||||
/**
|
||||
* affects # of samples used for AO and params for filtering
|
||||
* affects # of samples used for AO.
|
||||
*/
|
||||
@NonNull
|
||||
public QualityLevel quality = QualityLevel.LOW;
|
||||
/**
|
||||
* affects AO smoothness. Recommend setting to HIGH when aoType set to GTAO.
|
||||
* affects AO smoothness
|
||||
*/
|
||||
@NonNull
|
||||
public QualityLevel lowPassFilter = QualityLevel.MEDIUM;
|
||||
@@ -1866,7 +1849,7 @@ public class View {
|
||||
*/
|
||||
public boolean bentNormals = false;
|
||||
/**
|
||||
* min angle in radian to consider. No effect when aoType set to GTAO.
|
||||
* min angle in radian to consider
|
||||
*/
|
||||
public float minHorizonAngleRad = 0.0f;
|
||||
/**
|
||||
@@ -1921,19 +1904,6 @@ public class View {
|
||||
*/
|
||||
public boolean ssctEnabled = false;
|
||||
|
||||
/**
|
||||
* Ground Truth-base Ambient Occlusion (GTAO) options
|
||||
*/
|
||||
public int gtaoSampleSliceCount = 4;
|
||||
/**
|
||||
* Ground Truth-base Ambient Occlusion (GTAO) options
|
||||
*/
|
||||
public int gtaoSampleStepsPerSlice = 3;
|
||||
/**
|
||||
* Ground Truth-base Ambient Occlusion (GTAO) options
|
||||
*/
|
||||
public float gtaoThicknessHeuristic = 0.004f;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2010,7 +1980,7 @@ public class View {
|
||||
}
|
||||
|
||||
/**
|
||||
* reconstruction filter width typically between 1 (sharper) and 2 (smoother)
|
||||
* reconstruction filter width typically between 0.2 (sharper, aliased) and 1.5 (smoother)
|
||||
*/
|
||||
public float filterWidth = 1.0f;
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,8 @@ project(filament-utils-android)
|
||||
set(FILAMENT_DIR ${FILAMENT_DIST_DIR})
|
||||
set(IMAGEIO_DIR ../../libs/imageio)
|
||||
|
||||
set(CMAKE_SYSTEM_VERSION 26)
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../gltfio-android ${CMAKE_CURRENT_BINARY_DIR}/gltfio-android)
|
||||
|
||||
add_library(camutils STATIC IMPORTED)
|
||||
@@ -30,6 +32,10 @@ add_library(iblprefilter STATIC IMPORTED)
|
||||
set_target_properties(iblprefilter PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilament-iblprefilter.a)
|
||||
|
||||
add_library(bluevk STATIC IMPORTED)
|
||||
set_target_properties(bluevk PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libbluevk.a)
|
||||
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libfilament-utils-jni.map")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384")
|
||||
|
||||
@@ -57,7 +63,8 @@ target_include_directories(filament-utils-jni PRIVATE
|
||||
..
|
||||
../../filament/backend/include
|
||||
${IMAGEIO_DIR}/include
|
||||
../../libs/utils/include)
|
||||
../../libs/utils/include
|
||||
../../libs/bluevk/include)
|
||||
|
||||
set_target_properties(filament-utils-jni PROPERTIES LINK_DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libfilament-utils-jni.symbols)
|
||||
@@ -71,4 +78,6 @@ target_link_libraries(filament-utils-jni
|
||||
image
|
||||
ktxreader
|
||||
viewer
|
||||
bluevk
|
||||
android
|
||||
)
|
||||
|
||||
@@ -12,6 +12,10 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 26
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
// No need to package up the following shared libs, which arise as a side effect of our
|
||||
// externalNativeBuild dependencies. When clients pick and choose from project-level gradle
|
||||
|
||||
@@ -14,12 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include <android/hardware_buffer.h>
|
||||
#include <android/hardware_buffer_jni.h>
|
||||
#include <jni.h>
|
||||
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/IndirectLight.h>
|
||||
#include <filament/Skybox.h>
|
||||
|
||||
#include <backend/Platform.h>
|
||||
#include <backend/platforms/PlatformEGLAndroid.h>
|
||||
#include <backend/platforms/VulkanPlatformAndroid.h>
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <ktxreader/Ktx1Reader.h>
|
||||
|
||||
#include "common/NioUtils.h"
|
||||
@@ -29,6 +38,8 @@ using namespace filament::math;
|
||||
using namespace image;
|
||||
using namespace ktxreader;
|
||||
|
||||
using namespace filament::backend;
|
||||
|
||||
jlong nCreateHDRTexture(JNIEnv* env, jclass,
|
||||
jlong nativeEngine, jobject javaBuffer, jint remaining, jint internalFormat);
|
||||
|
||||
@@ -79,6 +90,37 @@ static jboolean nGetSphericalHarmonics(JNIEnv* env, jclass, jobject javaBuffer,
|
||||
return success ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
static jlong nSetExternalImageOnTexture(JNIEnv* env, jclass, jlong nativeEngine, jlong nativeTexture,
|
||||
jobject hardwareBuffer, jboolean srgb) {
|
||||
utils::slog.e <<"--------- jni nSetExternalImageOnTexture" << utils::io::endl;
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
Texture* texture = (Texture*) nativeTexture;
|
||||
|
||||
Platform* platform = engine->getPlatform();
|
||||
AHardwareBuffer* nativeBuffer = nullptr;
|
||||
if (__builtin_available(android 26, *)) {
|
||||
nativeBuffer = AHardwareBuffer_fromHardwareBuffer(env, hardwareBuffer);
|
||||
}
|
||||
|
||||
utils::slog.e <<"--------- jni nSetExternalImageOnTexture buf=" << nativeBuffer << utils::io::endl;
|
||||
|
||||
if (!nativeBuffer) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (engine->getBackend() == Backend::OPENGL) {
|
||||
PlatformEGLAndroid* eglPlatform = (PlatformEGLAndroid*) platform;
|
||||
auto ref = eglPlatform->createExternalImage(nativeBuffer, srgb == JNI_TRUE);
|
||||
texture->setExternalImage(*engine, ref);
|
||||
} else if (engine->getBackend() == Backend::VULKAN) {
|
||||
VulkanPlatformAndroid* vulkanPlatform = (VulkanPlatformAndroid*) platform;
|
||||
auto ref = vulkanPlatform->createExternalImage(nativeBuffer, srgb == JNI_TRUE);
|
||||
texture->setExternalImage(*engine, ref);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
|
||||
JNIEnv* env;
|
||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
||||
@@ -108,5 +150,14 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
|
||||
rc = env->RegisterNatives(hdrloaderClass, hdrMethods, sizeof(hdrMethods) / sizeof(JNINativeMethod));
|
||||
if (rc != JNI_OK) return rc;
|
||||
|
||||
jclass loaderClass = env->FindClass("com/google/android/filament/utils/ExternalImage");
|
||||
if (loaderClass == nullptr) return JNI_ERR;
|
||||
static const JNINativeMethod methods[] = {
|
||||
{ (char*) "nSetExternalImageOnTexture", (char*) "(JJLandroid/hardware/HardwareBuffer;Z)J",
|
||||
reinterpret_cast<void*>(nSetExternalImageOnTexture) },
|
||||
};
|
||||
rc = env->RegisterNatives(loaderClass, methods, sizeof(methods) / sizeof(JNINativeMethod));
|
||||
if (rc != JNI_OK) return rc;
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Romain Guy
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.google.android.filament.utils
|
||||
|
||||
import android.hardware.HardwareBuffer
|
||||
import com.google.android.filament.Engine
|
||||
import com.google.android.filament.Texture
|
||||
|
||||
object ExternalImage {
|
||||
fun setOnTexture(
|
||||
engine: Engine,
|
||||
texture: Texture,
|
||||
buffer: HardwareBuffer,
|
||||
srgb: Boolean,
|
||||
) {
|
||||
val nativeEngine = engine.nativeObject
|
||||
val nativeTexture = texture.nativeObject
|
||||
val l = nSetExternalImageOnTexture(nativeEngine, nativeTexture, buffer, srgb)
|
||||
}
|
||||
|
||||
private external fun nSetExternalImageOnTexture(
|
||||
nativeEngine: Long,
|
||||
nativeTexture: Long,
|
||||
buffer: HardwareBuffer,
|
||||
srgb: Boolean,
|
||||
): Long
|
||||
}
|
||||
@@ -35,10 +35,6 @@ add_library(utils STATIC IMPORTED)
|
||||
set_target_properties(utils PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libutils.a)
|
||||
|
||||
add_library(perfetto STATIC IMPORTED)
|
||||
set_target_properties(perfetto PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libperfetto.a)
|
||||
|
||||
add_library(uberzlib STATIC IMPORTED)
|
||||
set_target_properties(uberzlib PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libuberzlib.a)
|
||||
@@ -125,7 +121,6 @@ set(GLTFIO_INCLUDE_DIRS
|
||||
../../third_party/meshoptimizer/src
|
||||
../../third_party/robin-map
|
||||
../../third_party/stb
|
||||
../../third_party/perfetto
|
||||
../../libs/utils/include
|
||||
../../libs/ktxreader/include
|
||||
)
|
||||
@@ -134,7 +129,7 @@ add_library(gltfio-jni SHARED ${GLTFIO_SRCS})
|
||||
target_include_directories(gltfio-jni PRIVATE ${GLTFIO_INCLUDE_DIRS})
|
||||
set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.symbols)
|
||||
set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libgltfio-jni.map)
|
||||
target_link_libraries(gltfio-jni filament-jni utils perfetto uberzlib log stb ktxreader basis_transcoder zstd uberarchive)
|
||||
target_link_libraries(gltfio-jni filament-jni utils uberzlib log stb ktxreader basis_transcoder zstd uberarchive)
|
||||
target_link_libraries(gltfio-jni dracodec meshoptimizer)
|
||||
target_compile_definitions(gltfio-jni PUBLIC GLTFIO_DRACO_SUPPORTED=1)
|
||||
target_include_directories(gltfio-jni PRIVATE ${DRACO_DIR}/src)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.60.1
|
||||
VERSION_NAME=1.58.1
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
/.idea/caches
|
||||
/.idea/gradle.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
/src/main/assets
|
||||
.externalNativeBuild
|
||||
@@ -0,0 +1,55 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'filament-tools-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(versions.jdk)
|
||||
}
|
||||
|
||||
filamentTools {
|
||||
materialInputDir = project.layout.projectDirectory.dir("src/main/materials")
|
||||
materialOutputDir = project.layout.projectDirectory.dir("src/main/assets/materials")
|
||||
}
|
||||
|
||||
clean.doFirst {
|
||||
delete "src/main/assets"
|
||||
}
|
||||
|
||||
android {
|
||||
namespace 'com.google.android.filament.externalimg'
|
||||
|
||||
compileSdkVersion versions.compileSdk
|
||||
defaultConfig {
|
||||
applicationId "com.google.android.filament.externalimg"
|
||||
minSdkVersion 26
|
||||
targetSdkVersion versions.targetSdk
|
||||
}
|
||||
|
||||
// NOTE: This is a workaround required because the AGP task collectReleaseDependencies
|
||||
// is not configuration-cache friendly yet; this is only useful for Play publication
|
||||
dependenciesInfo {
|
||||
includeInApk = false
|
||||
}
|
||||
|
||||
// We use the .filamat extension for materials compiled with matc
|
||||
// Telling aapt to not compress them allows to load them efficiently
|
||||
aaptOptions {
|
||||
noCompress 'filamat', 'ktx'
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility versions.jdk
|
||||
targetCompatibility versions.jdk
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation deps.kotlin
|
||||
implementation deps.androidx.core
|
||||
implementation project(':filament-android')
|
||||
implementation project(':filament-utils-android')
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (C) 2019 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<uses-feature android:name="android.hardware.camera" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity
|
||||
android:exported="true"
|
||||
android:name=".MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.filament.externalimg
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.SurfaceTexture
|
||||
import android.hardware.camera2.*
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.util.Log
|
||||
import android.util.Size
|
||||
import android.view.Surface
|
||||
import androidx.core.content.ContextCompat
|
||||
|
||||
import android.Manifest
|
||||
import android.graphics.ImageFormat
|
||||
import android.hardware.HardwareBuffer
|
||||
import android.media.ImageReader
|
||||
import android.opengl.Matrix
|
||||
import android.os.Build
|
||||
import android.os.Looper
|
||||
import androidx.annotation.RequiresApi
|
||||
|
||||
import com.google.android.filament.*
|
||||
|
||||
import java.util.concurrent.Semaphore
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Toy class that handles all interaction with the Android camera2 API.
|
||||
* Sets the "textureTransform" and "videoTexture" parameters on the given Filament material.
|
||||
*/
|
||||
class CameraHelper(val activity: Activity, private val filamentEngine: Engine, private val filamentMaterial: MaterialInstance) {
|
||||
private lateinit var cameraId: String
|
||||
private lateinit var captureRequest: CaptureRequest
|
||||
|
||||
private val cameraOpenCloseLock = Semaphore(1)
|
||||
private var backgroundHandler: Handler? = null
|
||||
private var backgroundThread: HandlerThread? = null
|
||||
private var cameraDevice: CameraDevice? = null
|
||||
private var captureSession: CameraCaptureSession? = null
|
||||
private var resolution = Size(640, 480)
|
||||
private var filamentTexture: Texture? = null
|
||||
private var filamentStream: Stream? = null
|
||||
private val imageReader = ImageReader.newInstance(
|
||||
resolution.width,
|
||||
resolution.height,
|
||||
ImageFormat.PRIVATE,
|
||||
kImageReaderMaxImages,
|
||||
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE)
|
||||
|
||||
@Suppress("deprecation")
|
||||
private val display = if (Build.VERSION.SDK_INT >= 30) {
|
||||
Api30Impl.getDisplay(activity)
|
||||
} else {
|
||||
activity.windowManager.defaultDisplay!!
|
||||
}
|
||||
|
||||
@RequiresApi(30)
|
||||
class Api30Impl {
|
||||
companion object {
|
||||
fun getDisplay(context: Context) = context.display!!
|
||||
}
|
||||
}
|
||||
|
||||
private val cameraCallback = object : CameraDevice.StateCallback() {
|
||||
override fun onOpened(cameraDevice: CameraDevice) {
|
||||
cameraOpenCloseLock.release()
|
||||
this@CameraHelper.cameraDevice = cameraDevice
|
||||
createCaptureSession()
|
||||
}
|
||||
override fun onDisconnected(cameraDevice: CameraDevice) {
|
||||
cameraOpenCloseLock.release()
|
||||
cameraDevice.close()
|
||||
this@CameraHelper.cameraDevice = null
|
||||
}
|
||||
override fun onError(cameraDevice: CameraDevice, error: Int) {
|
||||
onDisconnected(cameraDevice)
|
||||
this@CameraHelper.activity.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the latest image (if any) from ImageReader and passes its HardwareBuffer to Filament.
|
||||
*/
|
||||
fun pushExternalImageToFilament() {
|
||||
val stream = filamentStream
|
||||
if (stream != null) {
|
||||
imageReader.acquireLatestImage()?.also {
|
||||
stream.setAcquiredImage(it.hardwareBuffer, Handler(Looper.getMainLooper())) {
|
||||
it.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the front-facing Android camera, requests permission, and sets up a listener that will
|
||||
* start a capture session as soon as the camera is ready.
|
||||
*/
|
||||
fun openCamera() {
|
||||
val manager = activity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
||||
try {
|
||||
for (cameraId in manager.cameraIdList) {
|
||||
val characteristics = manager.getCameraCharacteristics(cameraId)
|
||||
val cameraDirection = characteristics.get(CameraCharacteristics.LENS_FACING)
|
||||
if (cameraDirection != null && cameraDirection == CameraCharacteristics.LENS_FACING_FRONT) {
|
||||
continue
|
||||
}
|
||||
|
||||
this.cameraId = cameraId
|
||||
Log.i(kLogTag, "Selected camera $cameraId.")
|
||||
|
||||
val map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) ?: continue
|
||||
resolution = map.getOutputSizes(SurfaceTexture::class.java)[0]
|
||||
Log.i(kLogTag, "Highest resolution is $resolution.")
|
||||
}
|
||||
} catch (e: CameraAccessException) {
|
||||
Log.e(kLogTag, e.toString())
|
||||
} catch (e: NullPointerException) {
|
||||
Log.e(kLogTag, "Camera2 API is not supported on this device.")
|
||||
}
|
||||
|
||||
val permission = ContextCompat.checkSelfPermission(this.activity, Manifest.permission.CAMERA)
|
||||
if (permission != PackageManager.PERMISSION_GRANTED) {
|
||||
activity.requestPermissions(arrayOf(Manifest.permission.CAMERA), kRequestCameraPermission)
|
||||
return
|
||||
}
|
||||
if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
|
||||
throw RuntimeException("Time out waiting to lock camera opening.")
|
||||
}
|
||||
manager.openCamera(cameraId, cameraCallback, backgroundHandler)
|
||||
}
|
||||
|
||||
fun onResume() {
|
||||
backgroundThread = HandlerThread("CameraBackground").also { it.start() }
|
||||
backgroundHandler = Handler(backgroundThread?.looper!!)
|
||||
}
|
||||
|
||||
fun onPause() {
|
||||
backgroundThread?.quitSafely()
|
||||
try {
|
||||
backgroundThread?.join()
|
||||
backgroundThread = null
|
||||
backgroundHandler = null
|
||||
} catch (e: InterruptedException) {
|
||||
Log.e(kLogTag, e.toString())
|
||||
}
|
||||
}
|
||||
|
||||
fun onRequestPermissionsResult(requestCode: Int, grantResults: IntArray): Boolean {
|
||||
if (requestCode == kRequestCameraPermission) {
|
||||
if (grantResults.size != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
||||
Log.e(kLogTag, "Unable to obtain camera position.")
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun createCaptureSession() {
|
||||
filamentStream?.apply { filamentEngine.destroyStream(this) }
|
||||
|
||||
// [Re]create the Filament Stream object that gets bound to the Texture.
|
||||
filamentStream = Stream.Builder().build(filamentEngine)
|
||||
|
||||
// Create the Filament Texture object if we haven't done so already.
|
||||
if (filamentTexture == null) {
|
||||
filamentTexture = Texture.Builder()
|
||||
.sampler(Texture.Sampler.SAMPLER_EXTERNAL)
|
||||
.format(Texture.InternalFormat.RGB8)
|
||||
.build(filamentEngine)
|
||||
}
|
||||
|
||||
// We are texturing a front-facing square shape so we need to generate a matrix that transforms (u, v, 0, 1)
|
||||
// into a new UV coordinate according to the screen rotation and the aspect ratio of the camera image.
|
||||
val aspectRatio = resolution.width.toFloat() / resolution.height.toFloat()
|
||||
val textureTransform = FloatArray(16)
|
||||
Matrix.setIdentityM(textureTransform, 0)
|
||||
when (display.rotation) {
|
||||
Surface.ROTATION_0 -> {
|
||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
||||
Matrix.rotateM(textureTransform, 0, 90.0f, 0.0f, 0.0f, 1.0f)
|
||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
||||
Matrix.scaleM(textureTransform, 0, -1.0f, 1.0f / aspectRatio, 1.0f)
|
||||
}
|
||||
Surface.ROTATION_90 -> {
|
||||
Matrix.translateM(textureTransform, 0, 1.0f, 1.0f, 0.0f)
|
||||
Matrix.rotateM(textureTransform, 0, 180.0f, 0.0f, 0.0f, 1.0f)
|
||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
||||
Matrix.scaleM(textureTransform, 0, -1.0f / aspectRatio, 1.0f, 1.0f)
|
||||
}
|
||||
Surface.ROTATION_270 -> {
|
||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
||||
Matrix.scaleM(textureTransform, 0, -1.0f / aspectRatio, 1.0f, 1.0f)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect the Stream to the Texture and the Texture to the MaterialInstance.
|
||||
val sampler = TextureSampler(TextureSampler.MinFilter.LINEAR, TextureSampler.MagFilter.LINEAR, TextureSampler.WrapMode.CLAMP_TO_EDGE)
|
||||
filamentTexture!!.setExternalStream(filamentEngine, filamentStream!!)
|
||||
filamentMaterial.setParameter("videoTexture", filamentTexture!!, sampler)
|
||||
filamentMaterial.setParameter("textureTransform", MaterialInstance.FloatElement.MAT4, textureTransform, 0, 1)
|
||||
|
||||
// Start the capture session. You could also use TEMPLATE_PREVIEW here.
|
||||
val captureRequestBuilder = cameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_RECORD)
|
||||
captureRequestBuilder.addTarget(imageReader.surface)
|
||||
|
||||
cameraDevice?.createCaptureSession(listOf(imageReader.surface),
|
||||
object : CameraCaptureSession.StateCallback() {
|
||||
override fun onConfigured(cameraCaptureSession: CameraCaptureSession) {
|
||||
if (cameraDevice == null) return
|
||||
captureSession = cameraCaptureSession
|
||||
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
|
||||
captureRequest = captureRequestBuilder.build()
|
||||
captureSession!!.setRepeatingRequest(captureRequest, null, backgroundHandler)
|
||||
Log.i(kLogTag, "Created CaptureRequest.")
|
||||
}
|
||||
override fun onConfigureFailed(session: CameraCaptureSession) {
|
||||
Log.e(kLogTag, "onConfigureFailed")
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val kLogTag = "CameraHelper"
|
||||
private const val kRequestCameraPermission = 1
|
||||
private const val kImageReaderMaxImages = 7
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.filament.externalimg
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.SurfaceTexture
|
||||
import android.hardware.camera2.*
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.util.Log
|
||||
import android.util.Size
|
||||
import android.view.Surface
|
||||
import androidx.core.content.ContextCompat
|
||||
|
||||
import android.Manifest
|
||||
import android.graphics.ImageFormat
|
||||
import android.hardware.HardwareBuffer
|
||||
import android.media.ImageReader
|
||||
import android.opengl.Matrix
|
||||
import android.os.Build
|
||||
import android.os.Looper
|
||||
import androidx.annotation.RequiresApi
|
||||
|
||||
import com.google.android.filament.*
|
||||
|
||||
import java.util.concurrent.Semaphore
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Toy class that handles all interaction with the Android camera2 API.
|
||||
* Sets the "textureTransform" and "videoTexture" parameters on the given Filament material.
|
||||
*/
|
||||
class CameraHelper(val activity: Activity, private val filamentEngine: Engine, private val filamentMaterial: MaterialInstance) {
|
||||
private lateinit var cameraId: String
|
||||
private lateinit var captureRequest: CaptureRequest
|
||||
|
||||
private val cameraOpenCloseLock = Semaphore(1)
|
||||
private var backgroundHandler: Handler? = null
|
||||
private var backgroundThread: HandlerThread? = null
|
||||
private var cameraDevice: CameraDevice? = null
|
||||
private var captureSession: CameraCaptureSession? = null
|
||||
private var resolution = Size(640, 480)
|
||||
private var filamentTexture: Texture? = null
|
||||
private var filamentStream: Stream? = null
|
||||
private val imageReader = ImageReader.newInstance(
|
||||
resolution.width,
|
||||
resolution.height,
|
||||
ImageFormat.PRIVATE,
|
||||
kImageReaderMaxImages,
|
||||
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE)
|
||||
|
||||
@Suppress("deprecation")
|
||||
private val display = if (Build.VERSION.SDK_INT >= 30) {
|
||||
Api30Impl.getDisplay(activity)
|
||||
} else {
|
||||
activity.windowManager.defaultDisplay!!
|
||||
}
|
||||
|
||||
@RequiresApi(30)
|
||||
class Api30Impl {
|
||||
companion object {
|
||||
fun getDisplay(context: Context) = context.display!!
|
||||
}
|
||||
}
|
||||
|
||||
private val cameraCallback = object : CameraDevice.StateCallback() {
|
||||
override fun onOpened(cameraDevice: CameraDevice) {
|
||||
cameraOpenCloseLock.release()
|
||||
this@CameraHelper.cameraDevice = cameraDevice
|
||||
createCaptureSession()
|
||||
}
|
||||
override fun onDisconnected(cameraDevice: CameraDevice) {
|
||||
cameraOpenCloseLock.release()
|
||||
cameraDevice.close()
|
||||
this@CameraHelper.cameraDevice = null
|
||||
}
|
||||
override fun onError(cameraDevice: CameraDevice, error: Int) {
|
||||
onDisconnected(cameraDevice)
|
||||
this@CameraHelper.activity.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the latest image (if any) from ImageReader and passes its HardwareBuffer to Filament.
|
||||
*/
|
||||
fun pushExternalImageToFilament() {
|
||||
val stream = filamentStream
|
||||
if (stream != null) {
|
||||
imageReader.acquireLatestImage()?.also {
|
||||
stream.setAcquiredImage(it.hardwareBuffer, Handler(Looper.getMainLooper())) {
|
||||
it.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the front-facing Android camera, requests permission, and sets up a listener that will
|
||||
* start a capture session as soon as the camera is ready.
|
||||
*/
|
||||
fun openCamera() {
|
||||
val manager = activity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
||||
try {
|
||||
for (cameraId in manager.cameraIdList) {
|
||||
val characteristics = manager.getCameraCharacteristics(cameraId)
|
||||
val cameraDirection = characteristics.get(CameraCharacteristics.LENS_FACING)
|
||||
if (cameraDirection != null && cameraDirection == CameraCharacteristics.LENS_FACING_FRONT) {
|
||||
continue
|
||||
}
|
||||
|
||||
this.cameraId = cameraId
|
||||
Log.i(kLogTag, "Selected camera $cameraId.")
|
||||
|
||||
val map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) ?: continue
|
||||
resolution = map.getOutputSizes(SurfaceTexture::class.java)[0]
|
||||
Log.i(kLogTag, "Highest resolution is $resolution.")
|
||||
}
|
||||
} catch (e: CameraAccessException) {
|
||||
Log.e(kLogTag, e.toString())
|
||||
} catch (e: NullPointerException) {
|
||||
Log.e(kLogTag, "Camera2 API is not supported on this device.")
|
||||
}
|
||||
|
||||
val permission = ContextCompat.checkSelfPermission(this.activity, Manifest.permission.CAMERA)
|
||||
if (permission != PackageManager.PERMISSION_GRANTED) {
|
||||
activity.requestPermissions(arrayOf(Manifest.permission.CAMERA), kRequestCameraPermission)
|
||||
return
|
||||
}
|
||||
if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
|
||||
throw RuntimeException("Time out waiting to lock camera opening.")
|
||||
}
|
||||
manager.openCamera(cameraId, cameraCallback, backgroundHandler)
|
||||
}
|
||||
|
||||
fun onResume() {
|
||||
backgroundThread = HandlerThread("CameraBackground").also { it.start() }
|
||||
backgroundHandler = Handler(backgroundThread?.looper!!)
|
||||
}
|
||||
|
||||
fun onPause() {
|
||||
backgroundThread?.quitSafely()
|
||||
try {
|
||||
backgroundThread?.join()
|
||||
backgroundThread = null
|
||||
backgroundHandler = null
|
||||
} catch (e: InterruptedException) {
|
||||
Log.e(kLogTag, e.toString())
|
||||
}
|
||||
}
|
||||
|
||||
fun onRequestPermissionsResult(requestCode: Int, grantResults: IntArray): Boolean {
|
||||
if (requestCode == kRequestCameraPermission) {
|
||||
if (grantResults.size != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
||||
Log.e(kLogTag, "Unable to obtain camera position.")
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun createCaptureSession() {
|
||||
filamentStream?.apply { filamentEngine.destroyStream(this) }
|
||||
|
||||
// [Re]create the Filament Stream object that gets bound to the Texture.
|
||||
filamentStream = Stream.Builder().build(filamentEngine)
|
||||
|
||||
// Create the Filament Texture object if we haven't done so already.
|
||||
if (filamentTexture == null) {
|
||||
filamentTexture = Texture.Builder()
|
||||
.sampler(Texture.Sampler.SAMPLER_EXTERNAL)
|
||||
.format(Texture.InternalFormat.RGB8)
|
||||
.build(filamentEngine)
|
||||
}
|
||||
|
||||
// We are texturing a front-facing square shape so we need to generate a matrix that transforms (u, v, 0, 1)
|
||||
// into a new UV coordinate according to the screen rotation and the aspect ratio of the camera image.
|
||||
val aspectRatio = resolution.width.toFloat() / resolution.height.toFloat()
|
||||
val textureTransform = FloatArray(16)
|
||||
Matrix.setIdentityM(textureTransform, 0)
|
||||
when (display.rotation) {
|
||||
Surface.ROTATION_0 -> {
|
||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
||||
Matrix.rotateM(textureTransform, 0, 90.0f, 0.0f, 0.0f, 1.0f)
|
||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
||||
Matrix.scaleM(textureTransform, 0, -1.0f, 1.0f / aspectRatio, 1.0f)
|
||||
}
|
||||
Surface.ROTATION_90 -> {
|
||||
Matrix.translateM(textureTransform, 0, 1.0f, 1.0f, 0.0f)
|
||||
Matrix.rotateM(textureTransform, 0, 180.0f, 0.0f, 0.0f, 1.0f)
|
||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
||||
Matrix.scaleM(textureTransform, 0, -1.0f / aspectRatio, 1.0f, 1.0f)
|
||||
}
|
||||
Surface.ROTATION_270 -> {
|
||||
Matrix.translateM(textureTransform, 0, 1.0f, 0.0f, 0.0f)
|
||||
Matrix.scaleM(textureTransform, 0, -1.0f / aspectRatio, 1.0f, 1.0f)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect the Stream to the Texture and the Texture to the MaterialInstance.
|
||||
val sampler = TextureSampler(TextureSampler.MinFilter.LINEAR, TextureSampler.MagFilter.LINEAR, TextureSampler.WrapMode.CLAMP_TO_EDGE)
|
||||
filamentTexture!!.setExternalStream(filamentEngine, filamentStream!!)
|
||||
filamentMaterial.setParameter("videoTexture", filamentTexture!!, sampler)
|
||||
filamentMaterial.setParameter("textureTransform", MaterialInstance.FloatElement.MAT4, textureTransform, 0, 1)
|
||||
|
||||
// Start the capture session. You could also use TEMPLATE_PREVIEW here.
|
||||
val captureRequestBuilder = cameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_RECORD)
|
||||
captureRequestBuilder.addTarget(imageReader.surface)
|
||||
|
||||
cameraDevice?.createCaptureSession(listOf(imageReader.surface),
|
||||
object : CameraCaptureSession.StateCallback() {
|
||||
override fun onConfigured(cameraCaptureSession: CameraCaptureSession) {
|
||||
if (cameraDevice == null) return
|
||||
captureSession = cameraCaptureSession
|
||||
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
|
||||
captureRequest = captureRequestBuilder.build()
|
||||
captureSession!!.setRepeatingRequest(captureRequest, null, backgroundHandler)
|
||||
Log.i(kLogTag, "Created CaptureRequest.")
|
||||
}
|
||||
override fun onConfigureFailed(session: CameraCaptureSession) {
|
||||
Log.e(kLogTag, "onConfigureFailed")
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val kLogTag = "CameraHelper"
|
||||
private const val kRequestCameraPermission = 1
|
||||
private const val kImageReaderMaxImages = 7
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
import android.graphics.*
|
||||
import android.hardware.HardwareBuffer
|
||||
import android.media.Image
|
||||
import android.media.ImageReader
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.util.Log
|
||||
import android.view.Surface
|
||||
import androidx.annotation.RequiresApi
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.TimeoutException
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
object CanvasToHardwareBufferUtil {
|
||||
private const val TAG = "CanvasToHardwareBufferKt"
|
||||
private const val IMAGE_READER_TIMEOUT_MS = 3000L // Timeout for waiting buffer
|
||||
|
||||
fun drawToHardwareBuffer(
|
||||
width: Int,
|
||||
height: Int,
|
||||
): HardwareBuffer? {
|
||||
if (width <= 0 || height <= 0) {
|
||||
Log.e(TAG, "Invalid dimensions: width=$width, height=$height")
|
||||
return null
|
||||
}
|
||||
|
||||
var handlerThread: HandlerThread? = null
|
||||
var imageReader: ImageReader? = null
|
||||
var surface: Surface? = null // Keep track for logging/debugging if needed
|
||||
// Use var as it's assigned within the try block after future completion
|
||||
var receivedHardwareBuffer: HardwareBuffer? = null
|
||||
|
||||
try {
|
||||
// 1. Setup HandlerThread for ImageReader callbacks
|
||||
handlerThread = HandlerThread("ImageReaderThreadKt").apply { start() }
|
||||
val imageReaderHandler = Handler(handlerThread.looper)
|
||||
|
||||
// 2. Use CompletableFuture to wait for the buffer from the listener
|
||||
val bufferFuture = CompletableFuture<HardwareBuffer>()
|
||||
|
||||
// 3. Create ImageReader
|
||||
val usageFlags =
|
||||
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE or
|
||||
HardwareBuffer.USAGE_GPU_COLOR_OUTPUT or
|
||||
HardwareBuffer.USAGE_CPU_READ_RARELY // Adjust as needed
|
||||
|
||||
imageReader =
|
||||
ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 1, usageFlags)
|
||||
|
||||
// 4. Set Listener to capture the buffer
|
||||
imageReader.setOnImageAvailableListener({ reader ->
|
||||
var image: Image? = null
|
||||
var hardwareBuffer: HardwareBuffer? = null
|
||||
try {
|
||||
// Use `use` block for automatic image.close()
|
||||
image = reader.acquireLatestImage()
|
||||
if (image == null) {
|
||||
Log.w(TAG, "ImageReader listener fired but no image available.")
|
||||
// Complete exceptionally if buffer wasn't already completed.
|
||||
bufferFuture.completeExceptionally(
|
||||
RuntimeException("ImageReader listener fired but no image available"),
|
||||
)
|
||||
return@setOnImageAvailableListener
|
||||
}
|
||||
|
||||
hardwareBuffer = image.hardwareBuffer
|
||||
if (hardwareBuffer != null) {
|
||||
// IMPORTANT: Don't close the HardwareBuffer here!
|
||||
// Transfer ownership via the CompletableFuture.
|
||||
if (!bufferFuture.isDone) { // Avoid completing more than once
|
||||
bufferFuture.complete(hardwareBuffer)
|
||||
} else {
|
||||
// Future was already completed (maybe exceptionally), close this buffer
|
||||
Log.w(TAG, "Future already done, closing redundant HardwareBuffer")
|
||||
hardwareBuffer.close()
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Failed to get HardwareBuffer from Image.")
|
||||
if (!bufferFuture.isDone) {
|
||||
bufferFuture.completeExceptionally(
|
||||
RuntimeException("Failed to get HardwareBuffer from Image"),
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error in ImageReader listener", e)
|
||||
if (!bufferFuture.isDone) {
|
||||
bufferFuture.completeExceptionally(e) // Propagate error
|
||||
}
|
||||
// If we got the buffer but failed elsewhere, ensure it's closed
|
||||
hardwareBuffer?.takeUnless { it.isClosed }?.close()
|
||||
} finally {
|
||||
// image?.close() // Handled by acquiring reader itself or image.use{} if used
|
||||
image?.close() // Close image if not using `use` or if error before `use` finishes
|
||||
}
|
||||
}, imageReaderHandler)
|
||||
|
||||
// 5. Get the Surface to draw onto
|
||||
surface =
|
||||
imageReader.surface
|
||||
?: throw RuntimeException("Failed to get Surface from ImageReader")
|
||||
|
||||
// 6. Lock Canvas and Draw
|
||||
val canvas: Canvas? = surface.lockHardwareCanvas() // Use hardware accelerated canvas
|
||||
if (canvas != null) {
|
||||
try {
|
||||
// --- Your Drawing Code Here ---
|
||||
val paint =
|
||||
Paint().apply {
|
||||
isAntiAlias = true // Good practice
|
||||
}
|
||||
|
||||
// Blue background
|
||||
paint.color = Color.BLUE
|
||||
canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint)
|
||||
|
||||
// White text
|
||||
paint.color = Color.WHITE
|
||||
paint.textSize = 40f
|
||||
paint.textAlign = Paint.Align.CENTER
|
||||
canvas.drawText(
|
||||
"Hello HardwareBuffer! (Kotlin)",
|
||||
width / 2f,
|
||||
height / 2f,
|
||||
paint,
|
||||
)
|
||||
// --- End Drawing Code ---
|
||||
} finally {
|
||||
// 7. Unlock Canvas and Post
|
||||
surface.unlockCanvasAndPost(canvas)
|
||||
}
|
||||
} else {
|
||||
throw RuntimeException("Failed to lock Hardware Canvas")
|
||||
}
|
||||
|
||||
// 8. Wait for the listener to provide the HardwareBuffer
|
||||
try {
|
||||
// Wait for the buffer; this blocks the current thread.
|
||||
receivedHardwareBuffer =
|
||||
bufferFuture.get(IMAGE_READER_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||
// Ownership of receivedHardwareBuffer is now transferred to the caller
|
||||
} catch (timeout: TimeoutException) {
|
||||
Log.e(TAG, "Timeout waiting for HardwareBuffer from ImageReader listener")
|
||||
bufferFuture.cancel(true) // Attempt to cancel listener processing
|
||||
throw timeout // Re-throw
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to draw to HardwareBuffer", e)
|
||||
// Ensure buffer is closed if acquired but an error occurred before returning it
|
||||
receivedHardwareBuffer?.takeUnless { it.isClosed }?.close()
|
||||
return null // Indicate failure
|
||||
} finally {
|
||||
// 9. Cleanup
|
||||
try {
|
||||
imageReader?.close() // Also releases the Surface implicitly
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error closing ImageReader", e)
|
||||
}
|
||||
try {
|
||||
handlerThread?.quitSafely()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error quitting HandlerThread", e)
|
||||
}
|
||||
// Note: Do NOT close receivedHardwareBuffer here if returning successfully.
|
||||
// The caller is responsible for closing the returned buffer.
|
||||
}
|
||||
|
||||
// Return the buffer; caller MUST close it.
|
||||
return receivedHardwareBuffer
|
||||
}
|
||||
|
||||
// --- Example Usage (must be called from appropriate context/thread, like a coroutine) ---
|
||||
/*
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
suspend fun exampleUsage() = withContext(Dispatchers.IO) { // Run blocking code off main thread
|
||||
val myBuffer: HardwareBuffer? = CanvasToHardwareBufferUtil.drawToHardwareBuffer(640, 480)
|
||||
|
||||
// Use the 'use' extension function for automatic closing
|
||||
myBuffer?.use { buffer ->
|
||||
// ... Use the buffer (e.g., create an EGLImage, pass to Vulkan, etc.) ...
|
||||
Log.d(TAG, "Successfully created HardwareBuffer: $buffer. Now using it...")
|
||||
// buffer.close() // 'use' handles this automatically
|
||||
|
||||
} ?: run {
|
||||
Log.e(TAG, "Failed to create HardwareBuffer.")
|
||||
}
|
||||
|
||||
Log.d(TAG,"HardwareBuffer processing finished (buffer closed if obtained).")
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
import android.graphics.*
|
||||
import android.hardware.HardwareBuffer
|
||||
import android.media.Image
|
||||
import android.media.ImageReader
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.util.Log
|
||||
import android.view.Surface
|
||||
import androidx.annotation.RequiresApi
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.TimeoutException
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
object CanvasToHardwareBufferUtil {
|
||||
|
||||
private const val TAG = "CanvasToHardwareBufferKt"
|
||||
private const val IMAGE_READER_TIMEOUT_MS = 3000L // Timeout for waiting buffer
|
||||
|
||||
fun drawToHardwareBuffer(width: Int, height: Int): HardwareBuffer? {
|
||||
if (width <= 0 || height <= 0) {
|
||||
Log.e(TAG, "Invalid dimensions: width=$width, height=$height")
|
||||
return null
|
||||
}
|
||||
|
||||
var handlerThread: HandlerThread? = null
|
||||
var imageReader: ImageReader? = null
|
||||
var surface: Surface? = null // Keep track for logging/debugging if needed
|
||||
// Use var as it's assigned within the try block after future completion
|
||||
var receivedHardwareBuffer: HardwareBuffer? = null
|
||||
|
||||
try {
|
||||
// 1. Setup HandlerThread for ImageReader callbacks
|
||||
handlerThread = HandlerThread("ImageReaderThreadKt").apply { start() }
|
||||
val imageReaderHandler = Handler(handlerThread.looper)
|
||||
|
||||
// 2. Use CompletableFuture to wait for the buffer from the listener
|
||||
val bufferFuture = CompletableFuture<HardwareBuffer>()
|
||||
|
||||
// 3. Create ImageReader
|
||||
val usageFlags = HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE or
|
||||
HardwareBuffer.USAGE_GPU_COLOR_OUTPUT or
|
||||
HardwareBuffer.USAGE_CPU_READ_RARELY // Adjust as needed
|
||||
|
||||
imageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 1, usageFlags)
|
||||
|
||||
// 4. Set Listener to capture the buffer
|
||||
imageReader.setOnImageAvailableListener({ reader ->
|
||||
var image: Image? = null
|
||||
var hardwareBuffer: HardwareBuffer? = null
|
||||
try {
|
||||
// Use `use` block for automatic image.close()
|
||||
image = reader.acquireLatestImage()
|
||||
if (image == null) {
|
||||
Log.w(TAG, "ImageReader listener fired but no image available.")
|
||||
// Complete exceptionally if buffer wasn't already completed.
|
||||
bufferFuture.completeExceptionally(RuntimeException("ImageReader listener fired but no image available"))
|
||||
return@setOnImageAvailableListener
|
||||
}
|
||||
|
||||
hardwareBuffer = image.hardwareBuffer
|
||||
if (hardwareBuffer != null) {
|
||||
// IMPORTANT: Don't close the HardwareBuffer here!
|
||||
// Transfer ownership via the CompletableFuture.
|
||||
if (!bufferFuture.isDone) { // Avoid completing more than once
|
||||
bufferFuture.complete(hardwareBuffer)
|
||||
} else {
|
||||
// Future was already completed (maybe exceptionally), close this buffer
|
||||
Log.w(TAG, "Future already done, closing redundant HardwareBuffer")
|
||||
hardwareBuffer.close()
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Failed to get HardwareBuffer from Image.")
|
||||
if (!bufferFuture.isDone) {
|
||||
bufferFuture.completeExceptionally(RuntimeException("Failed to get HardwareBuffer from Image"))
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error in ImageReader listener", e)
|
||||
if (!bufferFuture.isDone) {
|
||||
bufferFuture.completeExceptionally(e) // Propagate error
|
||||
}
|
||||
// If we got the buffer but failed elsewhere, ensure it's closed
|
||||
hardwareBuffer?.takeUnless { it.isClosed }?.close()
|
||||
} finally {
|
||||
// image?.close() // Handled by acquiring reader itself or image.use{} if used
|
||||
image?.close() // Close image if not using `use` or if error before `use` finishes
|
||||
}
|
||||
}, imageReaderHandler)
|
||||
|
||||
// 5. Get the Surface to draw onto
|
||||
surface = imageReader.surface ?: throw RuntimeException("Failed to get Surface from ImageReader")
|
||||
|
||||
// 6. Lock Canvas and Draw
|
||||
val canvas: Canvas? = surface.lockHardwareCanvas() // Use hardware accelerated canvas
|
||||
if (canvas != null) {
|
||||
try {
|
||||
// --- Your Drawing Code Here ---
|
||||
val paint = Paint().apply {
|
||||
isAntiAlias = true // Good practice
|
||||
}
|
||||
|
||||
// Blue background
|
||||
paint.color = Color.BLUE
|
||||
canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint)
|
||||
|
||||
// White text
|
||||
paint.color = Color.WHITE
|
||||
paint.textSize = 40f
|
||||
paint.textAlign = Paint.Align.CENTER
|
||||
canvas.drawText("Hello HardwareBuffer! (Kotlin)", width / 2f, height / 2f, paint)
|
||||
// --- End Drawing Code ---
|
||||
|
||||
} finally {
|
||||
// 7. Unlock Canvas and Post
|
||||
surface.unlockCanvasAndPost(canvas)
|
||||
}
|
||||
} else {
|
||||
throw RuntimeException("Failed to lock Hardware Canvas")
|
||||
}
|
||||
|
||||
// 8. Wait for the listener to provide the HardwareBuffer
|
||||
try {
|
||||
// Wait for the buffer; this blocks the current thread.
|
||||
receivedHardwareBuffer = bufferFuture.get(IMAGE_READER_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||
// Ownership of receivedHardwareBuffer is now transferred to the caller
|
||||
} catch(timeout: TimeoutException) {
|
||||
Log.e(TAG, "Timeout waiting for HardwareBuffer from ImageReader listener")
|
||||
bufferFuture.cancel(true) // Attempt to cancel listener processing
|
||||
throw timeout // Re-throw
|
||||
}
|
||||
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to draw to HardwareBuffer", e)
|
||||
// Ensure buffer is closed if acquired but an error occurred before returning it
|
||||
receivedHardwareBuffer?.takeUnless { it.isClosed }?.close()
|
||||
return null // Indicate failure
|
||||
|
||||
} finally {
|
||||
// 9. Cleanup
|
||||
try {
|
||||
imageReader?.close() // Also releases the Surface implicitly
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error closing ImageReader", e)
|
||||
}
|
||||
try {
|
||||
handlerThread?.quitSafely()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error quitting HandlerThread", e)
|
||||
}
|
||||
// Note: Do NOT close receivedHardwareBuffer here if returning successfully.
|
||||
// The caller is responsible for closing the returned buffer.
|
||||
}
|
||||
|
||||
// Return the buffer; caller MUST close it.
|
||||
return receivedHardwareBuffer
|
||||
}
|
||||
|
||||
// --- Example Usage (must be called from appropriate context/thread, like a coroutine) ---
|
||||
/*
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
suspend fun exampleUsage() = withContext(Dispatchers.IO) { // Run blocking code off main thread
|
||||
val myBuffer: HardwareBuffer? = CanvasToHardwareBufferUtil.drawToHardwareBuffer(640, 480)
|
||||
|
||||
// Use the 'use' extension function for automatic closing
|
||||
myBuffer?.use { buffer ->
|
||||
// ... Use the buffer (e.g., create an EGLImage, pass to Vulkan, etc.) ...
|
||||
Log.d(TAG, "Successfully created HardwareBuffer: $buffer. Now using it...")
|
||||
// buffer.close() // 'use' handles this automatically
|
||||
|
||||
} ?: run {
|
||||
Log.e(TAG, "Failed to create HardwareBuffer.")
|
||||
}
|
||||
|
||||
Log.d(TAG,"HardwareBuffer processing finished (buffer closed if obtained).")
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.filament.externalimg
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.app.Activity
|
||||
import android.hardware.HardwareBuffer
|
||||
import android.opengl.Matrix
|
||||
import android.os.Bundle
|
||||
import android.view.Choreographer
|
||||
import android.view.Surface
|
||||
import android.view.SurfaceView
|
||||
import android.view.animation.LinearInterpolator
|
||||
import androidx.core.app.ActivityCompat
|
||||
|
||||
import com.google.android.filament.*
|
||||
import com.google.android.filament.RenderableManager.*
|
||||
import com.google.android.filament.VertexBuffer.*
|
||||
import com.google.android.filament.android.DisplayHelper
|
||||
import com.google.android.filament.android.FilamentHelper
|
||||
import com.google.android.filament.android.UiHelper
|
||||
import com.google.android.filament.utils.ExternalImage
|
||||
import com.google.android.filament.utils.Utils
|
||||
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
import java.nio.channels.Channels
|
||||
|
||||
import kotlin.math.*
|
||||
|
||||
import android.util.Log
|
||||
|
||||
class MainActivity : Activity(), ActivityCompat.OnRequestPermissionsResultCallback {
|
||||
companion object {
|
||||
init {
|
||||
Filament.init()
|
||||
}
|
||||
}
|
||||
|
||||
private var TAG = "filament.externalimg"
|
||||
|
||||
private lateinit var surfaceView: SurfaceView
|
||||
private lateinit var uiHelper: UiHelper
|
||||
private lateinit var displayHelper: DisplayHelper
|
||||
private lateinit var choreographer: Choreographer
|
||||
|
||||
private lateinit var engine: Engine
|
||||
private lateinit var renderer: Renderer
|
||||
private lateinit var scene: Scene
|
||||
private lateinit var view: View
|
||||
|
||||
// This is the Filament camera, not the phone camera. :)
|
||||
private lateinit var camera: Camera
|
||||
|
||||
private var filamentTexture: Texture? = null
|
||||
|
||||
// Other Filament objects:
|
||||
private lateinit var material: Material
|
||||
private lateinit var materialInstance: MaterialInstance
|
||||
private lateinit var vertexBuffer: VertexBuffer
|
||||
private lateinit var indexBuffer: IndexBuffer
|
||||
|
||||
// Filament entity representing a renderable object
|
||||
@Entity private var renderable = 0
|
||||
@Entity private var light = 0
|
||||
|
||||
private var myCount : Int = 0
|
||||
|
||||
// A swap chain is Filament's representation of a surface
|
||||
private var swapChain: SwapChain? = null
|
||||
|
||||
// Performs the rendering and schedules new frames
|
||||
private val frameScheduler = FrameCallback()
|
||||
|
||||
private val animator = ValueAnimator.ofFloat(0.0f, 50.0f)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
Utils.init()
|
||||
|
||||
surfaceView = SurfaceView(this)
|
||||
setContentView(surfaceView)
|
||||
|
||||
choreographer = Choreographer.getInstance()
|
||||
|
||||
displayHelper = DisplayHelper(this)
|
||||
|
||||
setupSurfaceView()
|
||||
setupFilament()
|
||||
setupView()
|
||||
setupScene()
|
||||
|
||||
// ExternalImage.setOnTexture(engine,, texture, buffer, srgb)
|
||||
|
||||
// cameraHelper = CameraHelper(this, engine, materialInstance)
|
||||
// cameraHelper.openCamera()
|
||||
}
|
||||
|
||||
private fun setupSurfaceView() {
|
||||
uiHelper = UiHelper(UiHelper.ContextErrorPolicy.DONT_CHECK)
|
||||
uiHelper.renderCallback = SurfaceCallback()
|
||||
uiHelper.attachTo(surfaceView)
|
||||
}
|
||||
|
||||
private fun setupFilament() {
|
||||
engine = Engine.create()
|
||||
renderer = engine.createRenderer()
|
||||
scene = engine.createScene()
|
||||
view = engine.createView()
|
||||
camera = engine.createCamera(engine.entityManager.create())
|
||||
|
||||
}
|
||||
|
||||
private fun setupView() {
|
||||
scene.skybox = Skybox.Builder().color(0.035f, 0.035f, 0.035f, 1.0f).build(engine)
|
||||
view.camera = camera
|
||||
view.scene = scene
|
||||
}
|
||||
|
||||
private fun setupScene() {
|
||||
loadMaterial()
|
||||
setupMaterial()
|
||||
createMesh()
|
||||
|
||||
// To create a renderable we first create a generic entity
|
||||
renderable = EntityManager.get().create()
|
||||
|
||||
// We then create a renderable component on that entity
|
||||
// A renderable is made of several primitives; in this case we declare only 1
|
||||
// If we wanted each face of the cube to have a different material, we could
|
||||
// declare 6 primitives (1 per face) and give each of them a different material
|
||||
// instance, setup with different parameters
|
||||
RenderableManager.Builder(1)
|
||||
// Overall bounding box of the renderable
|
||||
.boundingBox(Box(0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f))
|
||||
// Sets the mesh data of the first primitive, 6 faces of 6 indices each
|
||||
.geometry(0, PrimitiveType.TRIANGLES, vertexBuffer, indexBuffer, 0, 6 * 6)
|
||||
// Sets the material of the first primitive
|
||||
.material(0, materialInstance)
|
||||
.build(engine, renderable)
|
||||
|
||||
// Add the entity to the scene to render it
|
||||
scene.addEntity(renderable)
|
||||
|
||||
// We now need a light, let's create a directional light
|
||||
light = EntityManager.get().create()
|
||||
|
||||
// Create a color from a temperature (5,500K)
|
||||
val (r, g, b) = Colors.cct(5_500.0f)
|
||||
LightManager.Builder(LightManager.Type.DIRECTIONAL)
|
||||
.color(r, g, b)
|
||||
// Intensity of the sun in lux on a clear day
|
||||
.intensity(110_000.0f)
|
||||
// The direction is normalized on our behalf
|
||||
.direction(0.0f, -0.5f, -1.0f)
|
||||
.castShadows(true)
|
||||
.build(engine, light)
|
||||
|
||||
// Add the entity to the scene to light it
|
||||
scene.addEntity(light)
|
||||
|
||||
// Set the exposure on the camera, this exposure follows the sunny f/16 rule
|
||||
// Since we've defined a light that has the same intensity as the sun, it
|
||||
// guarantees a proper exposure
|
||||
camera.setExposure(16.0f, 1.0f / 125.0f, 100.0f)
|
||||
|
||||
// Move the camera back to see the object
|
||||
camera.lookAt(0.0, 0.0, 6.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
|
||||
|
||||
startAnimation()
|
||||
}
|
||||
|
||||
private fun loadMaterial() {
|
||||
readUncompressedAsset("materials/lit.filamat").let {
|
||||
material = Material.Builder().payload(it, it.remaining()).build(engine)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupMaterial() {
|
||||
materialInstance = material.createInstance()
|
||||
materialInstance.setParameter("baseColor", Colors.RgbType.SRGB, 1.0f, 0.85f, 0.57f)
|
||||
materialInstance.setParameter("roughness", 0.3f)
|
||||
|
||||
val textureTransform = FloatArray(16)
|
||||
Matrix.setIdentityM(textureTransform, 0)
|
||||
|
||||
filamentTexture = Texture.Builder()
|
||||
.sampler(Texture.Sampler.SAMPLER_EXTERNAL)
|
||||
.width(400)
|
||||
.height(400)
|
||||
.format(Texture.InternalFormat.RGBA8)
|
||||
.build(engine)
|
||||
|
||||
val sampler = TextureSampler(TextureSampler.MinFilter.LINEAR, TextureSampler.MagFilter.LINEAR, TextureSampler.WrapMode.CLAMP_TO_EDGE)
|
||||
materialInstance.setParameter("videoTexture", filamentTexture!!, sampler)
|
||||
materialInstance.setParameter("textureTransform", MaterialInstance.FloatElement.MAT4, textureTransform, 0, 1)
|
||||
}
|
||||
|
||||
private fun createMesh() {
|
||||
val floatSize = 4
|
||||
val shortSize = 2
|
||||
// A vertex is a position + a tangent frame:
|
||||
// 3 floats for XYZ position, 4 floats for normal+tangents (quaternion)
|
||||
val vertexSize = 3 * floatSize + 4 * floatSize
|
||||
|
||||
// Define a vertex and a function to put a vertex in a ByteBuffer
|
||||
@Suppress("ArrayInDataClass")
|
||||
data class Vertex(val x: Float, val y: Float, val z: Float, val tangents: FloatArray)
|
||||
fun ByteBuffer.put(v: Vertex): ByteBuffer {
|
||||
putFloat(v.x)
|
||||
putFloat(v.y)
|
||||
putFloat(v.z)
|
||||
v.tangents.forEach { putFloat(it) }
|
||||
return this
|
||||
}
|
||||
|
||||
// 6 faces, 4 vertices per face
|
||||
val vertexCount = 6 * 4
|
||||
|
||||
// Create tangent frames, one per face
|
||||
val tfPX = FloatArray(4)
|
||||
val tfNX = FloatArray(4)
|
||||
val tfPY = FloatArray(4)
|
||||
val tfNY = FloatArray(4)
|
||||
val tfPZ = FloatArray(4)
|
||||
val tfNZ = FloatArray(4)
|
||||
|
||||
MathUtils.packTangentFrame( 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, tfPX)
|
||||
MathUtils.packTangentFrame( 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, -1.0f, 0.0f, 0.0f, tfNX)
|
||||
MathUtils.packTangentFrame(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, tfPY)
|
||||
MathUtils.packTangentFrame(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, tfNY)
|
||||
MathUtils.packTangentFrame( 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, tfPZ)
|
||||
MathUtils.packTangentFrame( 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, tfNZ)
|
||||
|
||||
val vertexData = ByteBuffer.allocate(vertexCount * vertexSize)
|
||||
// It is important to respect the native byte order
|
||||
.order(ByteOrder.nativeOrder())
|
||||
// Face -Z
|
||||
.put(Vertex(-1.5f, -1.5f, -1.0f, tfNZ))
|
||||
.put(Vertex(-1.5f, 1.5f, -1.0f, tfNZ))
|
||||
.put(Vertex( 1.5f, 1.5f, -1.0f, tfNZ))
|
||||
.put(Vertex( 1.5f, -1.5f, -1.0f, tfNZ))
|
||||
// Face +X
|
||||
.put(Vertex( 1.5f, -1.5f, -1.0f, tfPX))
|
||||
.put(Vertex( 1.5f, 1.5f, -1.0f, tfPX))
|
||||
.put(Vertex( 1.0f, 1.0f, 1.0f, tfPX))
|
||||
.put(Vertex( 1.0f, -1.0f, 1.0f, tfPX))
|
||||
// Face +Z
|
||||
.put(Vertex(-1.0f, -1.0f, 1.0f, tfPZ))
|
||||
.put(Vertex( 1.0f, -1.0f, 1.0f, tfPZ))
|
||||
.put(Vertex( 1.0f, 1.0f, 1.0f, tfPZ))
|
||||
.put(Vertex(-1.0f, 1.0f, 1.0f, tfPZ))
|
||||
// Face -X
|
||||
.put(Vertex(-1.0f, -1.0f, 1.0f, tfNX))
|
||||
.put(Vertex(-1.0f, 1.0f, 1.0f, tfNX))
|
||||
.put(Vertex(-1.5f, 1.5f, -1.0f, tfNX))
|
||||
.put(Vertex(-1.5f, -1.5f, -1.0f, tfNX))
|
||||
// Face -Y
|
||||
.put(Vertex(-1.0f, -1.0f, 1.0f, tfNY))
|
||||
.put(Vertex(-1.5f, -1.5f, -1.0f, tfNY))
|
||||
.put(Vertex( 1.5f, -1.5f, -1.0f, tfNY))
|
||||
.put(Vertex( 1.0f, -1.0f, 1.0f, tfNY))
|
||||
// Face +Y
|
||||
.put(Vertex(-1.5f, 1.5f, -1.0f, tfPY))
|
||||
.put(Vertex(-1.0f, 1.0f, 1.0f, tfPY))
|
||||
.put(Vertex( 1.0f, 1.0f, 1.0f, tfPY))
|
||||
.put(Vertex( 1.5f, 1.5f, -1.0f, tfPY))
|
||||
// Make sure the cursor is pointing in the right place in the byte buffer
|
||||
.flip()
|
||||
|
||||
// Declare the layout of our mesh
|
||||
vertexBuffer = VertexBuffer.Builder()
|
||||
.bufferCount(1)
|
||||
.vertexCount(vertexCount)
|
||||
// Because we interleave position and color data we must specify offset and stride
|
||||
// We could use de-interleaved data by declaring two buffers and giving each
|
||||
// attribute a different buffer index
|
||||
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT3, 0, vertexSize)
|
||||
.attribute(VertexAttribute.TANGENTS, 0, AttributeType.FLOAT4, 3 * floatSize, vertexSize)
|
||||
.build(engine)
|
||||
|
||||
// Feed the vertex data to the mesh
|
||||
// We only set 1 buffer because the data is interleaved
|
||||
vertexBuffer.setBufferAt(engine, 0, vertexData)
|
||||
|
||||
// Create the indices
|
||||
val indexData = ByteBuffer.allocate(6 * 2 * 3 * shortSize)
|
||||
.order(ByteOrder.nativeOrder())
|
||||
repeat(6) {
|
||||
val i = (it * 4).toShort()
|
||||
indexData
|
||||
.putShort(i).putShort((i + 1).toShort()).putShort((i + 2).toShort())
|
||||
.putShort(i).putShort((i + 2).toShort()).putShort((i + 3).toShort())
|
||||
}
|
||||
indexData.flip()
|
||||
|
||||
// 6 faces, 2 triangles per face,
|
||||
indexBuffer = IndexBuffer.Builder()
|
||||
.indexCount(vertexCount * 2)
|
||||
.bufferType(IndexBuffer.Builder.IndexType.USHORT)
|
||||
.build(engine)
|
||||
indexBuffer.setBuffer(engine, indexData)
|
||||
}
|
||||
|
||||
private fun startAnimation() {
|
||||
// Animate the triangle
|
||||
animator.interpolator = LinearInterpolator()
|
||||
animator.duration = 6000
|
||||
animator.repeatMode = ValueAnimator.RESTART
|
||||
animator.repeatCount = ValueAnimator.INFINITE
|
||||
animator.addUpdateListener(object : ValueAnimator.AnimatorUpdateListener {
|
||||
val transformMatrix = FloatArray(16)
|
||||
override fun onAnimationUpdate(animator: ValueAnimator) {
|
||||
val t = animator.animatedValue as Float
|
||||
val radians = sin(t) * 3.0f * PI.toFloat()
|
||||
Matrix.setRotateM(transformMatrix, 0, radians, 0.0f, 1.0f, 0.0f)
|
||||
val tcm = engine.transformManager
|
||||
tcm.setTransform(tcm.getInstance(renderable), transformMatrix)
|
||||
}
|
||||
})
|
||||
animator.start()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
choreographer.postFrameCallback(frameScheduler)
|
||||
animator.start()
|
||||
// cameraHelper.onResume()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
choreographer.removeFrameCallback(frameScheduler)
|
||||
animator.cancel()
|
||||
// cameraHelper.onPause()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
|
||||
// Stop the animation and any pending frame
|
||||
choreographer.removeFrameCallback(frameScheduler)
|
||||
animator.cancel()
|
||||
|
||||
// Always detach the surface before destroying the engine
|
||||
uiHelper.detach()
|
||||
|
||||
// Cleanup all resources
|
||||
engine.destroyEntity(light)
|
||||
engine.destroyEntity(renderable)
|
||||
engine.destroyRenderer(renderer)
|
||||
engine.destroyVertexBuffer(vertexBuffer)
|
||||
engine.destroyIndexBuffer(indexBuffer)
|
||||
engine.destroyMaterialInstance(materialInstance)
|
||||
engine.destroyMaterial(material)
|
||||
engine.destroyView(view)
|
||||
engine.destroyScene(scene)
|
||||
engine.destroyCameraComponent(camera.entity)
|
||||
|
||||
// Engine.destroyEntity() destroys Filament related resources only
|
||||
// (components), not the entity itself
|
||||
val entityManager = EntityManager.get()
|
||||
entityManager.destroy(light)
|
||||
entityManager.destroy(renderable)
|
||||
entityManager.destroy(camera.entity)
|
||||
|
||||
// Destroying the engine will free up any resource you may have forgotten
|
||||
// to destroy, but it's recommended to do the cleanup properly
|
||||
engine.destroy()
|
||||
}
|
||||
|
||||
inner class FrameCallback : Choreographer.FrameCallback {
|
||||
override fun doFrame(frameTimeNanos: Long) {
|
||||
// Schedule the next frame
|
||||
choreographer.postFrameCallback(this)
|
||||
|
||||
// This check guarantees that we have a swap chain
|
||||
if (uiHelper.isReadyToRender) {
|
||||
|
||||
if (myCount < 1) {
|
||||
val mybuffer: HardwareBuffer? = CanvasToHardwareBufferUtil.drawToHardwareBuffer(400, 400)
|
||||
mybuffer?.use { buffer : HardwareBuffer ->
|
||||
// ... Use the buffer (e.g., create an EGLImage, pass to Vulkan, etc.) ...
|
||||
Log.d(TAG, "Successfully created HardwareBuffer: $buffer. Now using it...")
|
||||
// buffer.close() // 'use' handles this automatically
|
||||
ExternalImage.setOnTexture(engine, filamentTexture!!, buffer, false)
|
||||
|
||||
} ?: run {
|
||||
Log.e(TAG, "Failed to create HardwareBuffer.")
|
||||
}
|
||||
}
|
||||
myCount ++;
|
||||
|
||||
// cameraHelper.pushExternalImageToFilament()
|
||||
|
||||
// If beginFrame() returns false you should skip the frame
|
||||
// This means you are sending frames too quickly to the GPU
|
||||
if (renderer.beginFrame(swapChain!!, frameTimeNanos)) {
|
||||
renderer.render(view)
|
||||
renderer.endFrame()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class SurfaceCallback : UiHelper.RendererCallback {
|
||||
override fun onNativeWindowChanged(surface: Surface) {
|
||||
swapChain?.let { engine.destroySwapChain(it) }
|
||||
swapChain = engine.createSwapChain(surface)
|
||||
displayHelper.attach(renderer, surfaceView.display)
|
||||
}
|
||||
|
||||
override fun onDetachedFromSurface() {
|
||||
displayHelper.detach()
|
||||
swapChain?.let {
|
||||
engine.destroySwapChain(it)
|
||||
// Required to ensure we don't return before Filament is done executing the
|
||||
// destroySwapChain command, otherwise Android might destroy the Surface
|
||||
// too early
|
||||
engine.flushAndWait()
|
||||
swapChain = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResized(width: Int, height: Int) {
|
||||
val aspect = width.toDouble() / height.toDouble()
|
||||
camera.setProjection(45.0, aspect, 0.1, 20.0, Camera.Fov.VERTICAL)
|
||||
|
||||
view.viewport = Viewport(0, 0, width, height)
|
||||
|
||||
FilamentHelper.synchronizePendingFrames(engine)
|
||||
}
|
||||
}
|
||||
|
||||
private fun readUncompressedAsset(@Suppress("SameParameterValue") assetName: String): ByteBuffer {
|
||||
assets.openFd(assetName).use { fd ->
|
||||
val input = fd.createInputStream()
|
||||
val dst = ByteBuffer.allocate(fd.length.toInt())
|
||||
|
||||
val src = Channels.newChannel(input)
|
||||
src.read(dst)
|
||||
src.close()
|
||||
|
||||
return dst.apply { rewind() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||
// if (!cameraHelper.onRequestPermissionsResult(requestCode, grantResults)) {
|
||||
// this.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,446 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.filament.externalimg
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.app.Activity
|
||||
import android.hardware.HardwareBuffer
|
||||
import android.opengl.Matrix
|
||||
import android.os.Bundle
|
||||
import android.view.Choreographer
|
||||
import android.view.Surface
|
||||
import android.view.SurfaceView
|
||||
import android.view.animation.LinearInterpolator
|
||||
import androidx.core.app.ActivityCompat
|
||||
|
||||
import com.google.android.filament.*
|
||||
import com.google.android.filament.RenderableManager.*
|
||||
import com.google.android.filament.VertexBuffer.*
|
||||
import com.google.android.filament.android.DisplayHelper
|
||||
import com.google.android.filament.android.FilamentHelper
|
||||
import com.google.android.filament.android.UiHelper
|
||||
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
import java.nio.channels.Channels
|
||||
|
||||
import kotlin.math.*
|
||||
|
||||
import android.util.Log
|
||||
|
||||
class MainActivity : Activity(), ActivityCompat.OnRequestPermissionsResultCallback {
|
||||
companion object {
|
||||
init {
|
||||
Filament.init()
|
||||
}
|
||||
}
|
||||
|
||||
private var TAG = "filament.externalimg"
|
||||
|
||||
private lateinit var surfaceView: SurfaceView
|
||||
private lateinit var uiHelper: UiHelper
|
||||
private lateinit var displayHelper: DisplayHelper
|
||||
private lateinit var choreographer: Choreographer
|
||||
|
||||
private lateinit var engine: Engine
|
||||
private lateinit var renderer: Renderer
|
||||
private lateinit var scene: Scene
|
||||
private lateinit var view: View
|
||||
|
||||
// This is the Filament camera, not the phone camera. :)
|
||||
private lateinit var camera: Camera
|
||||
|
||||
// Other Filament objects:
|
||||
private lateinit var material: Material
|
||||
private lateinit var materialInstance: MaterialInstance
|
||||
private lateinit var vertexBuffer: VertexBuffer
|
||||
private lateinit var indexBuffer: IndexBuffer
|
||||
|
||||
// Filament entity representing a renderable object
|
||||
@Entity private var renderable = 0
|
||||
@Entity private var light = 0
|
||||
|
||||
private var myCount : Int = 0
|
||||
|
||||
// A swap chain is Filament's representation of a surface
|
||||
private var swapChain: SwapChain? = null
|
||||
|
||||
// Performs the rendering and schedules new frames
|
||||
private val frameScheduler = FrameCallback()
|
||||
|
||||
private val animator = ValueAnimator.ofFloat(0.0f, 50.0f)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
surfaceView = SurfaceView(this)
|
||||
setContentView(surfaceView)
|
||||
|
||||
choreographer = Choreographer.getInstance()
|
||||
|
||||
displayHelper = DisplayHelper(this)
|
||||
|
||||
setupSurfaceView()
|
||||
setupFilament()
|
||||
setupView()
|
||||
setupScene()
|
||||
|
||||
// cameraHelper = CameraHelper(this, engine, materialInstance)
|
||||
// cameraHelper.openCamera()
|
||||
}
|
||||
|
||||
private fun setupSurfaceView() {
|
||||
uiHelper = UiHelper(UiHelper.ContextErrorPolicy.DONT_CHECK)
|
||||
uiHelper.renderCallback = SurfaceCallback()
|
||||
uiHelper.attachTo(surfaceView)
|
||||
}
|
||||
|
||||
private fun setupFilament() {
|
||||
engine = Engine.create()
|
||||
renderer = engine.createRenderer()
|
||||
scene = engine.createScene()
|
||||
view = engine.createView()
|
||||
camera = engine.createCamera(engine.entityManager.create())
|
||||
|
||||
}
|
||||
|
||||
private fun setupView() {
|
||||
scene.skybox = Skybox.Builder().color(0.035f, 0.035f, 0.035f, 1.0f).build(engine)
|
||||
view.camera = camera
|
||||
view.scene = scene
|
||||
}
|
||||
|
||||
private fun setupScene() {
|
||||
loadMaterial()
|
||||
setupMaterial()
|
||||
createMesh()
|
||||
|
||||
// To create a renderable we first create a generic entity
|
||||
renderable = EntityManager.get().create()
|
||||
|
||||
// We then create a renderable component on that entity
|
||||
// A renderable is made of several primitives; in this case we declare only 1
|
||||
// If we wanted each face of the cube to have a different material, we could
|
||||
// declare 6 primitives (1 per face) and give each of them a different material
|
||||
// instance, setup with different parameters
|
||||
RenderableManager.Builder(1)
|
||||
// Overall bounding box of the renderable
|
||||
.boundingBox(Box(0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f))
|
||||
// Sets the mesh data of the first primitive, 6 faces of 6 indices each
|
||||
.geometry(0, PrimitiveType.TRIANGLES, vertexBuffer, indexBuffer, 0, 6 * 6)
|
||||
// Sets the material of the first primitive
|
||||
.material(0, materialInstance)
|
||||
.build(engine, renderable)
|
||||
|
||||
// Add the entity to the scene to render it
|
||||
scene.addEntity(renderable)
|
||||
|
||||
// We now need a light, let's create a directional light
|
||||
light = EntityManager.get().create()
|
||||
|
||||
// Create a color from a temperature (5,500K)
|
||||
val (r, g, b) = Colors.cct(5_500.0f)
|
||||
LightManager.Builder(LightManager.Type.DIRECTIONAL)
|
||||
.color(r, g, b)
|
||||
// Intensity of the sun in lux on a clear day
|
||||
.intensity(110_000.0f)
|
||||
// The direction is normalized on our behalf
|
||||
.direction(0.0f, -0.5f, -1.0f)
|
||||
.castShadows(true)
|
||||
.build(engine, light)
|
||||
|
||||
// Add the entity to the scene to light it
|
||||
scene.addEntity(light)
|
||||
|
||||
// Set the exposure on the camera, this exposure follows the sunny f/16 rule
|
||||
// Since we've defined a light that has the same intensity as the sun, it
|
||||
// guarantees a proper exposure
|
||||
camera.setExposure(16.0f, 1.0f / 125.0f, 100.0f)
|
||||
|
||||
// Move the camera back to see the object
|
||||
camera.lookAt(0.0, 0.0, 6.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
|
||||
|
||||
startAnimation()
|
||||
}
|
||||
|
||||
private fun loadMaterial() {
|
||||
readUncompressedAsset("materials/lit.filamat").let {
|
||||
material = Material.Builder().payload(it, it.remaining()).build(engine)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupMaterial() {
|
||||
materialInstance = material.createInstance()
|
||||
materialInstance.setParameter("baseColor", Colors.RgbType.SRGB, 1.0f, 0.85f, 0.57f)
|
||||
materialInstance.setParameter("roughness", 0.3f)
|
||||
}
|
||||
|
||||
private fun createMesh() {
|
||||
val floatSize = 4
|
||||
val shortSize = 2
|
||||
// A vertex is a position + a tangent frame:
|
||||
// 3 floats for XYZ position, 4 floats for normal+tangents (quaternion)
|
||||
val vertexSize = 3 * floatSize + 4 * floatSize
|
||||
|
||||
// Define a vertex and a function to put a vertex in a ByteBuffer
|
||||
@Suppress("ArrayInDataClass")
|
||||
data class Vertex(val x: Float, val y: Float, val z: Float, val tangents: FloatArray)
|
||||
fun ByteBuffer.put(v: Vertex): ByteBuffer {
|
||||
putFloat(v.x)
|
||||
putFloat(v.y)
|
||||
putFloat(v.z)
|
||||
v.tangents.forEach { putFloat(it) }
|
||||
return this
|
||||
}
|
||||
|
||||
// 6 faces, 4 vertices per face
|
||||
val vertexCount = 6 * 4
|
||||
|
||||
// Create tangent frames, one per face
|
||||
val tfPX = FloatArray(4)
|
||||
val tfNX = FloatArray(4)
|
||||
val tfPY = FloatArray(4)
|
||||
val tfNY = FloatArray(4)
|
||||
val tfPZ = FloatArray(4)
|
||||
val tfNZ = FloatArray(4)
|
||||
|
||||
MathUtils.packTangentFrame( 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, tfPX)
|
||||
MathUtils.packTangentFrame( 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, -1.0f, 0.0f, 0.0f, tfNX)
|
||||
MathUtils.packTangentFrame(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, tfPY)
|
||||
MathUtils.packTangentFrame(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, tfNY)
|
||||
MathUtils.packTangentFrame( 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, tfPZ)
|
||||
MathUtils.packTangentFrame( 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, tfNZ)
|
||||
|
||||
val vertexData = ByteBuffer.allocate(vertexCount * vertexSize)
|
||||
// It is important to respect the native byte order
|
||||
.order(ByteOrder.nativeOrder())
|
||||
// Face -Z
|
||||
.put(Vertex(-1.5f, -1.5f, -1.0f, tfNZ))
|
||||
.put(Vertex(-1.5f, 1.5f, -1.0f, tfNZ))
|
||||
.put(Vertex( 1.5f, 1.5f, -1.0f, tfNZ))
|
||||
.put(Vertex( 1.5f, -1.5f, -1.0f, tfNZ))
|
||||
// Face +X
|
||||
.put(Vertex( 1.5f, -1.5f, -1.0f, tfPX))
|
||||
.put(Vertex( 1.5f, 1.5f, -1.0f, tfPX))
|
||||
.put(Vertex( 1.0f, 1.0f, 1.0f, tfPX))
|
||||
.put(Vertex( 1.0f, -1.0f, 1.0f, tfPX))
|
||||
// Face +Z
|
||||
.put(Vertex(-1.0f, -1.0f, 1.0f, tfPZ))
|
||||
.put(Vertex( 1.0f, -1.0f, 1.0f, tfPZ))
|
||||
.put(Vertex( 1.0f, 1.0f, 1.0f, tfPZ))
|
||||
.put(Vertex(-1.0f, 1.0f, 1.0f, tfPZ))
|
||||
// Face -X
|
||||
.put(Vertex(-1.0f, -1.0f, 1.0f, tfNX))
|
||||
.put(Vertex(-1.0f, 1.0f, 1.0f, tfNX))
|
||||
.put(Vertex(-1.5f, 1.5f, -1.0f, tfNX))
|
||||
.put(Vertex(-1.5f, -1.5f, -1.0f, tfNX))
|
||||
// Face -Y
|
||||
.put(Vertex(-1.0f, -1.0f, 1.0f, tfNY))
|
||||
.put(Vertex(-1.5f, -1.5f, -1.0f, tfNY))
|
||||
.put(Vertex( 1.5f, -1.5f, -1.0f, tfNY))
|
||||
.put(Vertex( 1.0f, -1.0f, 1.0f, tfNY))
|
||||
// Face +Y
|
||||
.put(Vertex(-1.5f, 1.5f, -1.0f, tfPY))
|
||||
.put(Vertex(-1.0f, 1.0f, 1.0f, tfPY))
|
||||
.put(Vertex( 1.0f, 1.0f, 1.0f, tfPY))
|
||||
.put(Vertex( 1.5f, 1.5f, -1.0f, tfPY))
|
||||
// Make sure the cursor is pointing in the right place in the byte buffer
|
||||
.flip()
|
||||
|
||||
// Declare the layout of our mesh
|
||||
vertexBuffer = VertexBuffer.Builder()
|
||||
.bufferCount(1)
|
||||
.vertexCount(vertexCount)
|
||||
// Because we interleave position and color data we must specify offset and stride
|
||||
// We could use de-interleaved data by declaring two buffers and giving each
|
||||
// attribute a different buffer index
|
||||
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT3, 0, vertexSize)
|
||||
.attribute(VertexAttribute.TANGENTS, 0, AttributeType.FLOAT4, 3 * floatSize, vertexSize)
|
||||
.build(engine)
|
||||
|
||||
// Feed the vertex data to the mesh
|
||||
// We only set 1 buffer because the data is interleaved
|
||||
vertexBuffer.setBufferAt(engine, 0, vertexData)
|
||||
|
||||
// Create the indices
|
||||
val indexData = ByteBuffer.allocate(6 * 2 * 3 * shortSize)
|
||||
.order(ByteOrder.nativeOrder())
|
||||
repeat(6) {
|
||||
val i = (it * 4).toShort()
|
||||
indexData
|
||||
.putShort(i).putShort((i + 1).toShort()).putShort((i + 2).toShort())
|
||||
.putShort(i).putShort((i + 2).toShort()).putShort((i + 3).toShort())
|
||||
}
|
||||
indexData.flip()
|
||||
|
||||
// 6 faces, 2 triangles per face,
|
||||
indexBuffer = IndexBuffer.Builder()
|
||||
.indexCount(vertexCount * 2)
|
||||
.bufferType(IndexBuffer.Builder.IndexType.USHORT)
|
||||
.build(engine)
|
||||
indexBuffer.setBuffer(engine, indexData)
|
||||
}
|
||||
|
||||
private fun startAnimation() {
|
||||
// Animate the triangle
|
||||
animator.interpolator = LinearInterpolator()
|
||||
animator.duration = 6000
|
||||
animator.repeatMode = ValueAnimator.RESTART
|
||||
animator.repeatCount = ValueAnimator.INFINITE
|
||||
animator.addUpdateListener(object : ValueAnimator.AnimatorUpdateListener {
|
||||
val transformMatrix = FloatArray(16)
|
||||
override fun onAnimationUpdate(animator: ValueAnimator) {
|
||||
val t = animator.animatedValue as Float
|
||||
val radians = sin(t) * 3.0f * PI.toFloat()
|
||||
Matrix.setRotateM(transformMatrix, 0, radians, 0.0f, 1.0f, 0.0f)
|
||||
val tcm = engine.transformManager
|
||||
tcm.setTransform(tcm.getInstance(renderable), transformMatrix)
|
||||
}
|
||||
})
|
||||
animator.start()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
choreographer.postFrameCallback(frameScheduler)
|
||||
animator.start()
|
||||
// cameraHelper.onResume()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
choreographer.removeFrameCallback(frameScheduler)
|
||||
animator.cancel()
|
||||
// cameraHelper.onPause()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
|
||||
// Stop the animation and any pending frame
|
||||
choreographer.removeFrameCallback(frameScheduler)
|
||||
animator.cancel()
|
||||
|
||||
// Always detach the surface before destroying the engine
|
||||
uiHelper.detach()
|
||||
|
||||
// Cleanup all resources
|
||||
engine.destroyEntity(light)
|
||||
engine.destroyEntity(renderable)
|
||||
engine.destroyRenderer(renderer)
|
||||
engine.destroyVertexBuffer(vertexBuffer)
|
||||
engine.destroyIndexBuffer(indexBuffer)
|
||||
engine.destroyMaterialInstance(materialInstance)
|
||||
engine.destroyMaterial(material)
|
||||
engine.destroyView(view)
|
||||
engine.destroyScene(scene)
|
||||
engine.destroyCameraComponent(camera.entity)
|
||||
|
||||
// Engine.destroyEntity() destroys Filament related resources only
|
||||
// (components), not the entity itself
|
||||
val entityManager = EntityManager.get()
|
||||
entityManager.destroy(light)
|
||||
entityManager.destroy(renderable)
|
||||
entityManager.destroy(camera.entity)
|
||||
|
||||
// Destroying the engine will free up any resource you may have forgotten
|
||||
// to destroy, but it's recommended to do the cleanup properly
|
||||
engine.destroy()
|
||||
}
|
||||
|
||||
inner class FrameCallback : Choreographer.FrameCallback {
|
||||
override fun doFrame(frameTimeNanos: Long) {
|
||||
// Schedule the next frame
|
||||
choreographer.postFrameCallback(this)
|
||||
|
||||
// This check guarantees that we have a swap chain
|
||||
if (uiHelper.isReadyToRender) {
|
||||
|
||||
if (myCount < 1) {
|
||||
val mybuffer: HardwareBuffer? = CanvasToHardwareBufferUtil.drawToHardwareBuffer(400, 400)
|
||||
mybuffer?.use { buffer : HardwareBuffer ->
|
||||
// ... Use the buffer (e.g., create an EGLImage, pass to Vulkan, etc.) ...
|
||||
Log.d(TAG, "Successfully created HardwareBuffer: $buffer. Now using it...")
|
||||
// buffer.close() // 'use' handles this automatically
|
||||
|
||||
} ?: run {
|
||||
Log.e(TAG, "Failed to create HardwareBuffer.")
|
||||
}
|
||||
}
|
||||
myCount ++;
|
||||
|
||||
// cameraHelper.pushExternalImageToFilament()
|
||||
|
||||
// If beginFrame() returns false you should skip the frame
|
||||
// This means you are sending frames too quickly to the GPU
|
||||
if (renderer.beginFrame(swapChain!!, frameTimeNanos)) {
|
||||
renderer.render(view)
|
||||
renderer.endFrame()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class SurfaceCallback : UiHelper.RendererCallback {
|
||||
override fun onNativeWindowChanged(surface: Surface) {
|
||||
swapChain?.let { engine.destroySwapChain(it) }
|
||||
swapChain = engine.createSwapChain(surface)
|
||||
displayHelper.attach(renderer, surfaceView.display)
|
||||
}
|
||||
|
||||
override fun onDetachedFromSurface() {
|
||||
displayHelper.detach()
|
||||
swapChain?.let {
|
||||
engine.destroySwapChain(it)
|
||||
// Required to ensure we don't return before Filament is done executing the
|
||||
// destroySwapChain command, otherwise Android might destroy the Surface
|
||||
// too early
|
||||
engine.flushAndWait()
|
||||
swapChain = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResized(width: Int, height: Int) {
|
||||
val aspect = width.toDouble() / height.toDouble()
|
||||
camera.setProjection(45.0, aspect, 0.1, 20.0, Camera.Fov.VERTICAL)
|
||||
|
||||
view.viewport = Viewport(0, 0, width, height)
|
||||
|
||||
FilamentHelper.synchronizePendingFrames(engine)
|
||||
}
|
||||
}
|
||||
|
||||
private fun readUncompressedAsset(@Suppress("SameParameterValue") assetName: String): ByteBuffer {
|
||||
assets.openFd(assetName).use { fd ->
|
||||
val input = fd.createInputStream()
|
||||
val dst = ByteBuffer.allocate(fd.length.toInt())
|
||||
|
||||
val src = Channels.newChannel(input)
|
||||
src.read(dst)
|
||||
src.close()
|
||||
|
||||
return dst.apply { rewind() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||
// if (!cameraHelper.onRequestPermissionsResult(requestCode, grantResults)) {
|
||||
// this.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// Simple lit material that defines 3 parameters:
|
||||
// - baseColor
|
||||
// - roughness
|
||||
// - metallic
|
||||
//
|
||||
// These parameters can be used by the application to change the appearance of the material.
|
||||
//
|
||||
// This source material must be compiled to a binary material using the matc tool.
|
||||
// The command used to compile this material is:
|
||||
// matc -p mobile -a opengl -o app/src/main/assets/lit.filamat app/src/materials/lit.mat
|
||||
//
|
||||
// See build.gradle for an example of how to compile materials automatically
|
||||
// Please refer to the documentation for more information about matc and the materials system.
|
||||
|
||||
material {
|
||||
name : lit,
|
||||
|
||||
// Dynamic lighting is enabled on this material
|
||||
shadingModel : lit,
|
||||
|
||||
// We don't need to declare a "requires" array, lit materials
|
||||
// always requires the "tangents" vertex attribute (the normal
|
||||
// is required for lighting, tangent/bitangent for normal mapping
|
||||
// and anisotropy)
|
||||
|
||||
// Custom vertex shader outputs
|
||||
variables : [
|
||||
uv
|
||||
],
|
||||
|
||||
// List of parameters exposed by this material
|
||||
parameters : [
|
||||
// The color must be passed in linear space, not sRGB
|
||||
{
|
||||
type : float3,
|
||||
name : baseColor
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : roughness
|
||||
},
|
||||
{
|
||||
type : samplerExternal,
|
||||
name : videoTexture
|
||||
},
|
||||
{
|
||||
type : mat4,
|
||||
name : textureTransform
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
vertex {
|
||||
void materialVertex(inout MaterialVertexInputs material) {
|
||||
material.uv = 0.5 * (getPosition() + vec4(1));
|
||||
}
|
||||
}
|
||||
|
||||
fragment {
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
material.roughness = materialParams.roughness;
|
||||
material.metallic = 0.0;
|
||||
|
||||
// Apply the video stream to the +Z face on the cube.
|
||||
if (variable_uv.z >= 1.0) {
|
||||
vec2 uv = (materialParams.textureTransform * vec4(variable_uv.xy, 0, 1)).xy;
|
||||
material.baseColor.rgb = inverseTonemapSRGB(texture(materialParams_videoTexture, uv).rgb);
|
||||
} else {
|
||||
material.baseColor.rgb = materialParams.baseColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="78.5885"
|
||||
android:endY="90.9159"
|
||||
android:startX="48.7653"
|
||||
android:startY="61.0927"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0"/>
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,171 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path
|
||||
android:fillColor="#26A69A"
|
||||
android:pathData="M0,0h108v108h-108z"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#3F51B5</color>
|
||||
<color name="colorPrimaryDark">#303F9F</color>
|
||||
<color name="colorAccent">#FF4081</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">External Image</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Hello Camera</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,8 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -18,5 +18,6 @@ include ':samples:sample-stream-test'
|
||||
include ':samples:sample-texture-view'
|
||||
include ':samples:sample-textured-object'
|
||||
include ':samples:sample-transparent-view'
|
||||
include ':samples:sample-external-image'
|
||||
|
||||
rootProject.name = 'filament'
|
||||
|
||||
@@ -151,7 +151,7 @@ function print_fgviewer_help {
|
||||
}
|
||||
|
||||
# Unless explicitly specified, NDK version will be selected as highest available version within same major release chain
|
||||
FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/build/common/versions | grep GITHUB_NDK_VERSION | sed s/GITHUB_NDK_VERSION=//g | cut -f 1 -d ".")}
|
||||
FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/build/android/ndk.version | cut -f 1 -d ".")}
|
||||
|
||||
# Requirements
|
||||
CMAKE_MAJOR=3
|
||||
@@ -200,9 +200,8 @@ WEBGPU_ANDROID_GRADLE_OPTION=""
|
||||
EGL_ON_LINUX_OPTION="-DFILAMENT_SUPPORTS_EGL_ON_LINUX=OFF"
|
||||
|
||||
MATDBG_OPTION="-DFILAMENT_ENABLE_MATDBG=OFF"
|
||||
MATDBG_GRADLE_OPTION=""
|
||||
FGVIEWER_OPTION="-DFILAMENT_ENABLE_FGVIEWER=OFF"
|
||||
FGVIEWER_GRADLE_OPTION=""
|
||||
MATDBG_GRADLE_OPTION=""
|
||||
|
||||
MATOPT_OPTION=""
|
||||
MATOPT_GRADLE_OPTION=""
|
||||
@@ -463,6 +462,16 @@ function ensure_android_build {
|
||||
echo "Error: Android NDK side-by-side version ${FILAMENT_NDK_VERSION} or compatible must be installed, exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local cmake_version=$(cmake --version)
|
||||
if [[ "${cmake_version}" =~ ([0-9]+)\.([0-9]+)\.[0-9]+ ]]; then
|
||||
if [[ "${BASH_REMATCH[1]}" -lt "${CMAKE_MAJOR}" ]] || \
|
||||
[[ "${BASH_REMATCH[2]}" -lt "${CMAKE_MINOR}" ]]; then
|
||||
echo "Error: cmake version ${CMAKE_MAJOR}.${CMAKE_MINOR}+ is required," \
|
||||
"${BASH_REMATCH[1]}.${BASH_REMATCH[2]} installed, exiting"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function build_android {
|
||||
@@ -524,7 +533,6 @@ function build_android {
|
||||
${VULKAN_ANDROID_GRADLE_OPTION} \
|
||||
${WEBGPU_ANDROID_GRADLE_OPTION} \
|
||||
${MATDBG_GRADLE_OPTION} \
|
||||
${FGVIEWER_GRADLE_OPTION} \
|
||||
${MATOPT_GRADLE_OPTION} \
|
||||
:filament-android:assembleDebug \
|
||||
:gltfio-android:assembleDebug \
|
||||
@@ -576,7 +584,6 @@ function build_android {
|
||||
${VULKAN_ANDROID_GRADLE_OPTION} \
|
||||
${WEBGPU_ANDROID_GRADLE_OPTION} \
|
||||
${MATDBG_GRADLE_OPTION} \
|
||||
${FGVIEWER_GRADLE_OPTION} \
|
||||
${MATOPT_GRADLE_OPTION} \
|
||||
:filament-android:assembleRelease \
|
||||
:gltfio-android:assembleRelease \
|
||||
|
||||
@@ -1,6 +1,28 @@
|
||||
#!/bin/bash
|
||||
|
||||
source `dirname $0`/../common/ci-check.sh
|
||||
# Usage: the first argument selects the build type:
|
||||
# - release, to build release only
|
||||
# - debug, to build debug only
|
||||
# - continuous, to build release and debug
|
||||
# - presubmit, for presubmit builds
|
||||
#
|
||||
# The default is release
|
||||
|
||||
echo "This script is intended to run in a CI environment and may modify your current environment."
|
||||
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..."
|
||||
;;
|
||||
n|N)
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
set -e
|
||||
set -x
|
||||
@@ -8,22 +30,30 @@ 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 1
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Unless explicitly specified, NDK version will be set to match exactly the required one
|
||||
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
|
||||
FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/ndk.version)}
|
||||
|
||||
# Install the required NDK version specifically (if not present)
|
||||
if [[ ! -d "${ANDROID_HOME}/ndk/$FILAMENT_NDK_VERSION" ]]; then
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
27.0.11718014
|
||||
@@ -1,20 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
# build-common.sh will generate the following variables:
|
||||
# $GENERATE_ARCHIVES
|
||||
# $BUILD_DEBUG
|
||||
# $BUILD_RELEASE
|
||||
|
||||
# Typically a build script (build.sh) would source this script. For example,
|
||||
# source `dirname $0`/../common/build-common.sh
|
||||
|
||||
# Usage: the first argument selects the build type:
|
||||
# - release, to build release only
|
||||
# - debug, to build debug only
|
||||
# - continuous, to build release and debug
|
||||
# - presubmit, for presubmit builds
|
||||
#
|
||||
# The default is release
|
||||
if [[ ! "$TARGET" ]]; then
|
||||
if [[ "$1" ]]; then
|
||||
TARGET=$1
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
function print_help {
|
||||
local SELF_NAME
|
||||
SELF_NAME=$(basename "$0")
|
||||
echo "$SELF_NAME. Check that public headers compile independently."
|
||||
echo ""
|
||||
echo "Usage:"
|
||||
echo " $SELF_NAME <public include directory>"
|
||||
echo ""
|
||||
echo "Example:"
|
||||
echo " $SELF_NAME out/release/filament/include"
|
||||
echo ""
|
||||
echo "Dependencies: clang"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " -h"
|
||||
echo " Print this help message and exit."
|
||||
}
|
||||
|
||||
while getopts "h" opt; do
|
||||
case ${opt} in
|
||||
h)
|
||||
print_help
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
print_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
if [[ "$#" -ne 1 ]]; then
|
||||
print_help
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FILAMENT_HEADERS="$1"
|
||||
|
||||
includes=()
|
||||
pushd "$FILAMENT_HEADERS" >/dev/null
|
||||
for f in $(find . -name '*.h'); do
|
||||
# Ignore platform headers. These may contain platform-specific includes.
|
||||
if [[ "$f" == *backend/platforms/* ]]; then
|
||||
continue
|
||||
fi
|
||||
include_path="${f#./}" # strip leading ./
|
||||
includes+=("${include_path}")
|
||||
done
|
||||
popd >/dev/null
|
||||
|
||||
rm -rf out/check-headers
|
||||
mkdir -p out/check-headers
|
||||
|
||||
echo "Checking that public headers compile independently..."
|
||||
for include in "${includes[@]}"; do
|
||||
echo "Checking ${include}"
|
||||
echo "#include <${include}>" >> out/check-headers/temp.cpp
|
||||
clang -std=c++17 -I "${FILAMENT_HEADERS}" out/check-headers/temp.cpp -c -o /dev/null
|
||||
done
|
||||
echo "Done!"
|
||||
@@ -1,19 +0,0 @@
|
||||
echo "This script is intended to run in a CI environment and may modify your current environment."
|
||||
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..."
|
||||
;;
|
||||
n|N)
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||
echo "Running workflow $GITHUB_WORKFLOW (event: $GITHUB_EVENT_NAME, action: $GITHUB_ACTION)"
|
||||
fi
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||
echo "Running workflow $GITHUB_WORKFLOW (event: $GITHUB_EVENT_NAME, action: $GITHUB_ACTION)"
|
||||
CONTINUOUS_INTEGRATION=true
|
||||
fi
|
||||
@@ -1,22 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -d "./emsdk" ]; then
|
||||
echo "emsdk folder found. Assume emsdk has been installed."
|
||||
cd emsdk
|
||||
./emsdk activate latest
|
||||
source ./emsdk_env.sh
|
||||
export EMSDK="$PWD"
|
||||
cd ..
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Install emscripten.
|
||||
EMSDK_VERSION=${GITHUB_EMSDK_VERSION-3.1.60}
|
||||
curl -L https://github.com/emscripten-core/emsdk/archive/refs/tags/${EMSDK_VERSION}.zip > emsdk.zip
|
||||
unzip emsdk.zip ; mv emsdk-* emsdk ; cd emsdk
|
||||
./emsdk install latest
|
||||
./emsdk activate latest
|
||||
source ./emsdk_env.sh
|
||||
|
||||
export EMSDK="$PWD"
|
||||
cd ..
|
||||
@@ -1,150 +0,0 @@
|
||||
# Copyright (C) 2024 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.
|
||||
|
||||
#!/usr/bin/bash
|
||||
|
||||
set -e
|
||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
OS_NAME=$(uname -s)
|
||||
LLVM_VERSION=${GITHUB_LLVM_VERSION-16}
|
||||
MESA_VERSION=${GITHUB_MESA_VERSION-24.2.1}
|
||||
ORIG_DIR=$(pwd)
|
||||
MESA_DIR=${MESA_DIR-${ORIG_DIR}/mesa}
|
||||
|
||||
if [[ "$OS_NAME" == "Linux" ]]; then
|
||||
sudo apt install python3-venv
|
||||
fi
|
||||
|
||||
# Install python deps
|
||||
python3 -m venv ${ORIG_DIR}/venv
|
||||
source ${ORIG_DIR}/venv/bin/activate
|
||||
|
||||
NEEDED_PYTHON_DEPS=("mako" "setuptools" "pyyaml")
|
||||
for cmd in "${NEEDED_PYTHON_DEPS[@]}"; do
|
||||
if ! python3 -m pip show -q "${cmd}" >/dev/null 2>&1; then
|
||||
python3 -m pip install ${cmd}
|
||||
fi
|
||||
done
|
||||
deactivate
|
||||
|
||||
# Install system deps
|
||||
if [[ "$OS_NAME" == "Linux" ]]; then
|
||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||
# We only want to do this if it is a CI machine.
|
||||
sudo apt-get -y remove llvm-*
|
||||
|
||||
# We do a manual install of dependencies instead of `apt-get -y build-dep mesa`
|
||||
# because this allows us to compile an older mesa, and also because build-deps
|
||||
# is constantly being updated and sometimes not compatible with the current
|
||||
# linux platform.
|
||||
# Note that we assume this platform is compatible with ubuntu-22.04 x86_64
|
||||
sudo apt-get -y install \
|
||||
autoconf automake autopoint autotools-dev bindgen bison build-essential bzip2 cpp cpp-11 debhelper debugedit dh-autoreconf dh-strip-nondeterminism diffstat directx-headers-dev dpkg-dev dwz flex g++ g++-11 gcc gcc-11 gcc-11-base:amd64 gettext glslang-tools icu-devtools intltool-debian lib32gcc-s1 lib32stdc++6 libarchive-zip-perl libasan6:amd64 libatomic1:amd64 libc-dev-bin libc6-dbg:amd64 libc6-dev:amd64 libc6-i386 libcc1-0:amd64 libclang-${GITHUB_CLANG_VERSION}-dev libclang-common-${GITHUB_CLANG_VERSION}-dev libclang-cpp${GITHUB_CLANG_VERSION} libclang-cpp${GITHUB_CLANG_VERSION}-dev libclang1-14 libclang1-${GITHUB_CLANG_VERSION} libclc-${GITHUB_CLANG_VERSION} libclc-${GITHUB_CLANG_VERSION}-dev libcrypt-dev:amd64 libdebhelper-perl libdpkg-perl libdrm-amdgpu1:amd64 libdrm-dev:amd64 libdrm-intel1:amd64 libdrm-nouveau2:amd64 libdrm-radeon1:amd64 libelf-dev:amd64 libexpat1-dev:amd64 libffi-dev:amd64 libfile-stripnondeterminism-perl libgc1:amd64 libgcc-11-dev:amd64 libgl1:amd64 libgl1-mesa-dri:amd64 libglapi-mesa:amd64 libglvnd-core-dev:amd64 libglvnd0:amd64 libglx-mesa0:amd64 libglx0:amd64 libgomp1:amd64 libicu-dev:amd64 libisl23:amd64 libitm1:amd64 libllvm14:amd64 libllvm${GITHUB_CLANG_VERSION}:amd64 libllvmspirvlib-${GITHUB_CLANG_VERSION}-dev:amd64 libllvmspirvlib${GITHUB_CLANG_VERSION}:amd64 liblsan0:amd64 libmpc3:amd64 libncurses-dev:amd64 libnsl-dev:amd64 libobjc-11-dev:amd64 libobjc4:amd64 libpciaccess-dev:amd64 libpciaccess0f:amd64 libpfm4:amd64 libpthread-stubs0-dev:amd64 libquadmath0:amd64 libsensors-config libsensors-dev:amd64 libsensors5:amd64 libset-scalar-perl libstd-rust-1.75:amd64 libstd-rust-dev:amd64 libstdc++-11-dev:amd64 libsub-override-perl libtinfo-dev:amd64 libtirpc-dev:amd64 libtool libtsan0:amd64 libubsan1:amd64 libva-dev:amd64 libva-drm2:amd64 libva-glx2:amd64 libva-wayland2:amd64 libva-x11-2:amd64 libva2:amd64 libvdpau-dev:amd64 libvdpau1:amd64 libvulkan-dev:amd64 libvulkan1:amd64 libwayland-bin libwayland-client0:amd64 libwayland-cursor0:amd64 libwayland-dev:amd64 libwayland-egl-backend-dev:amd64 libwayland-egl1:amd64 libwayland-server0:amd64 libx11-dev:amd64 libx11-xcb-dev:amd64 libx11-xcb1:amd64 libxau-dev:amd64 libxcb-dri2-0:amd64 libxcb-dri2-0-dev:amd64 libxcb-dri3-0:amd64 libxcb-dri3-dev:amd64 libxcb-glx0:amd64 libxcb-glx0-dev:amd64 libxcb-present-dev:amd64 libxcb-present0:amd64 libxcb-randr0:amd64 libxcb-randr0-dev:amd64 libxcb-render0:amd64 libxcb-render0-dev:amd64 libxcb-shape0:amd64 libxcb-shape0-dev:amd64 libxcb-shm0:amd64 libxcb-shm0-dev:amd64 libxcb-sync-dev:amd64 libxcb-sync1:amd64 libxcb-xfixes0:amd64 libxcb-xfixes0-dev:amd64 libxcb1-dev:amd64 libxdmcp-dev:amd64 libxext-dev:amd64 libxfixes-dev:amd64 libxfixes3:amd64 libxml2-dev:amd64 libxrandr-dev:amd64 libxrandr2:amd64 libxrender-dev:amd64 libxrender1:amd64 libxshmfence-dev:amd64 libxshmfence1:amd64 libxxf86vm-dev:amd64 libxxf86vm1:amd64 libz3-4:amd64 libz3-dev:amd64 libzstd-dev:amd64 linux-libc-dev:amd64 llvm-${LLVM_VERSION} llvm-${LLVM_VERSION}-dev llvm-${LLVM_VERSION}-linker-tools llvm-${LLVM_VERSION}-runtime llvm-${LLVM_VERSION}-tools llvm-spirv-${LLVM_VERSION} lto-disabled-list m4 make meson ninja-build pkg-config po-debconf python3-mako python3-ply python3-pygments quilt rpcsvc-proto rustc spirv-tools valgrind wayland-protocols x11proto-dev xorg-sgml-doctools xtrans-dev zlib1g-dev:amd64 \
|
||||
clang-$GITHUB_CLANG_VERSION libc++-$GITHUB_CLANG_VERSION-dev libc++abi-$GITHUB_CLANG_VERSION-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
|
||||
else
|
||||
set +e
|
||||
sudo apt-get -y build-dep mesa
|
||||
sudo apt -y remove llvm-18 llvm-18-* llvm-19 llvm-19-*
|
||||
set -e
|
||||
CURRENT_CLANG_VERSION=$(clang --version | head -n 1 | awk '{ print $4 }' | awk 'BEGIN { FS="\\." } { print $1 }')
|
||||
CLANG_VERSION=${CURRENT_CLANG_VERSION:-${LLVM_VERSION}}
|
||||
sudo apt-get -y install clang-${CLANG_VERSION} \
|
||||
libc++-${CLANG_VERSION}-dev \
|
||||
libc++abi-${CLANG_VERSION}-dev \
|
||||
llvm-${LLVM_VERSION} \
|
||||
llvm-${LLVM_VERSION}-{dev,tools,runtime}
|
||||
! command -v clang > /dev/null 2>&1 && \
|
||||
sudo ln -s /usr/bin/clang-${CLANG_VERSION} /usr/bin/clang && \
|
||||
sudo ln -s /usr/bin/clang++-${CLANG_VERSION} /usr/bin/clang++
|
||||
fi # [[ "$GITHUB_WORKFLOW" ]]
|
||||
elif [[ "$OS_NAME" == "Darwin" ]]; then
|
||||
if [[ ! "$GITHUB_WORKFLOW" ]]; then
|
||||
if [ ! command -v brew > /dev/null 2>&1 ]; then
|
||||
echo "Error: need to install homebrew to continue"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=true brew install autoconf automake libx11 libxext libxrandr llvm@${LLVM_VERSION} ninja meson pkg-config libxshmfence
|
||||
fi # [[ "$OS_NAME" == x ]]
|
||||
|
||||
LOCAL_LDFLAGS=${LDFLAGS}
|
||||
LOCAL_CPPFLAGS=${CPPFLAGS}
|
||||
LOCAL_PATH=${PATH}
|
||||
LOCAL_CXX=$(which clang++)
|
||||
LOCAL_CC=$(which clang)
|
||||
|
||||
CHECKOUT_MESA=false
|
||||
if [[ -d "${MESA_DIR}" ]]; then
|
||||
cd ${MESA_DIR}
|
||||
if ! git fsck --connectivity-only > /dev/null 2>&1; then
|
||||
echo "git fsck failed for mesa; try redownloading"
|
||||
CHECKOUT_MESA=true;
|
||||
fi
|
||||
cd ..;
|
||||
else
|
||||
CHECKOUT_MESA=true
|
||||
fi
|
||||
|
||||
if [[ "$CHECKOUT_MESA" = "true" ]]; then
|
||||
rm -rf ${MESA_DIR}
|
||||
|
||||
git clone https://gitlab.freedesktop.org/mesa/mesa.git
|
||||
if [[ "${MESA_DIR}" != "${ORIG_DIR}/mesa" ]]; then
|
||||
mv mesa ${MESA_DIR}
|
||||
fi
|
||||
fi
|
||||
|
||||
pushd .
|
||||
cd ${MESA_DIR}
|
||||
|
||||
# Need >= 24 to have llvmpipe for swrast. llvmpipe is needed for GL >= 4.1.
|
||||
git checkout mesa-${MESA_VERSION}
|
||||
|
||||
mkdir -p out
|
||||
|
||||
source ${ORIG_DIR}/venv/bin/activate
|
||||
|
||||
if [[ "$OS_NAME" == "Darwin" ]]; then
|
||||
LOCAL_LDFLAGS="-L/opt/homebrew/opt/llvm@${LLVM_VERSION}/lib"
|
||||
LOCAL_CPPFLAGS="-I/opt/homebrew/opt/llvm@${LLVM_VERSION}/include -I/opt/homebrew/include"
|
||||
LOCAL_PATH=${PATH}:/opt/homebrew/opt/llvm@${LLVM_VERSION}/bin
|
||||
|
||||
# This is necessary to be able to build vk (lavapipe) on macOS. Doesn't seem like a real dependency.
|
||||
sed -I '' "s/error('Vulkan drivers require dri3 for X11 support')//g" meson.build
|
||||
fi
|
||||
|
||||
# -Dosmesa=true => builds OSMesa, which is an offscreen GL context
|
||||
# -Dgallium-drivers=swrast => builds GL software rasterizer
|
||||
# -Dvulkan-drivers=swrast => builds VK software rasterizer
|
||||
# -Dgallium-drivers=llvmpipe is needed for GL >= 4.1 pipe-screen (see src/gallium/auxiliary/target-helpers/inline_sw_helper.h)
|
||||
CXX=${LOCAL_CXX} CC=${LOCAL_CC} PATH=${LOCAL_PATH} LDFLAGS=${LOCAL_LDFLAGS} CPPFLAGS=${LOCAL_CPPFLAGS} \
|
||||
meson setup --wipe builddir/ -Dprefix="${MESA_DIR}/out" -Dglx=xlib -Dosmesa=true -Dgallium-drivers=llvmpipe,swrast -Dvulkan-drivers=swrast
|
||||
CXX=${LOCAL_CXX} CC=${LOCAL_CC} PATH=${LOCAL_PATH} LDFLAGS=${LOCAL_LDFLAGS} CPPFLAGS=${LOCAL_CPPFLAGS} \
|
||||
meson install -C builddir/
|
||||
|
||||
# Disable python venv
|
||||
deactivate
|
||||
|
||||
popd
|
||||
|
||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||
set +x
|
||||
fi
|
||||
set +e
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/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
|
||||
@@ -1,7 +0,0 @@
|
||||
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
|
||||
GITHUB_EMSDK_VERSION=3.1.60
|
||||
@@ -1,11 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
source `dirname $0`/../common/ci-check.sh
|
||||
# Usage: the first argument selects the build type:
|
||||
# - release, to build release only
|
||||
# - debug, to build debug only
|
||||
# - continuous, to build release and debug
|
||||
# - presubmit, for presubmit builds
|
||||
#
|
||||
# The default is release
|
||||
|
||||
echo "This script is intended to run in a CI environment and may modify your current environment."
|
||||
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..."
|
||||
;;
|
||||
n|N)
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
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
|
||||
|
||||
# If we're generating an archive for release or continuous builds, then we'll also build for the
|
||||
@@ -16,3 +41,4 @@ if [[ "${GENERATE_ARCHIVES}" ]]; then
|
||||
fi
|
||||
|
||||
./build.sh -i -p ios -c $BUILD_SIMULATOR $GENERATE_ARCHIVES $BUILD_DEBUG $BUILD_RELEASE
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/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"
|
||||
@@ -1,11 +1,39 @@
|
||||
#!/bin/bash
|
||||
|
||||
source `dirname $0`/../common/ci-check.sh
|
||||
# Usage: the first argument selects the build type:
|
||||
# - release, to build release only
|
||||
# - debug, to build debug only
|
||||
# - continuous, to build release and debug
|
||||
# - presubmit, for presubmit builds
|
||||
#
|
||||
# The default is release
|
||||
|
||||
echo "This script is intended to run in a CI environment and may modify your current environment."
|
||||
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..."
|
||||
;;
|
||||
n|N)
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
# build-common.sh will generate the following variables:
|
||||
# $GENERATE_ARCHIVES
|
||||
# $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
|
||||
|
||||
pushd `dirname $0`/../.. > /dev/null
|
||||
./build.sh -c $RUN_TESTS $GENERATE_ARCHIVES $BUILD_DEBUG $BUILD_RELEASE
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#!/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
|
||||
@@ -1,11 +1,35 @@
|
||||
#!/bin/bash
|
||||
|
||||
source `dirname $0`/../common/ci-check.sh
|
||||
# Usage: the first argument selects the build type:
|
||||
# - release, to build release only
|
||||
# - debug, to build debug only
|
||||
# - continuous, to build release and debug
|
||||
# - presubmit, for presubmit builds
|
||||
#
|
||||
# The default is release
|
||||
|
||||
echo "This script is intended to run in a CI environment and may modify your current environment."
|
||||
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..."
|
||||
;;
|
||||
n|N)
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
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
|
||||
|
||||
pushd `dirname $0`/../.. > /dev/null
|
||||
./build.sh -c $RUN_TESTS $GENERATE_ARCHIVES $BUILD_DEBUG $BUILD_RELEASE
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#!/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,16 +31,10 @@ 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}/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()
|
||||
file(READ "${CMAKE_CURRENT_LIST_DIR}/android/ndk.version" FILAMENT_NDK_VERSION)
|
||||
string(REGEX MATCH "^\\d+" FILAMENT_NDK_VERSION ${FILAMENT_NDK_VERSION})
|
||||
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,16 +32,10 @@ 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}/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()
|
||||
file(READ "${CMAKE_CURRENT_LIST_DIR}/android/ndk.version" FILAMENT_NDK_VERSION)
|
||||
string(REGEX MATCH "^\\d+" FILAMENT_NDK_VERSION ${FILAMENT_NDK_VERSION})
|
||||
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,16 +31,10 @@ 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}/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()
|
||||
file(READ "${CMAKE_CURRENT_LIST_DIR}/android/ndk.version" FILAMENT_NDK_VERSION)
|
||||
string(REGEX MATCH "^\\d+" FILAMENT_NDK_VERSION ${FILAMENT_NDK_VERSION})
|
||||
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,16 +31,10 @@ 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}/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()
|
||||
file(READ "${CMAKE_CURRENT_LIST_DIR}/android/ndk.version" FILAMENT_NDK_VERSION)
|
||||
string(REGEX MATCH "^\\d+" FILAMENT_NDK_VERSION ${FILAMENT_NDK_VERSION})
|
||||
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,10 +1,34 @@
|
||||
#!/bin/bash
|
||||
|
||||
source `dirname $0`/../common/ci-check.sh
|
||||
# Usage: the first argument selects the build type:
|
||||
# - release, to build release only
|
||||
# - debug, to build debug only
|
||||
# - continuous, to build release and debug
|
||||
# - presubmit, for presubmit builds
|
||||
#
|
||||
# The default is release
|
||||
|
||||
echo "This script is intended to run in a CI environment and may modify your current environment."
|
||||
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..."
|
||||
;;
|
||||
n|N)
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/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
|
||||
unzip emsdk.zip ; mv emsdk-* emsdk ; cd emsdk
|
||||
./emsdk install latest
|
||||
./emsdk activate latest
|
||||
source ./emsdk_env.sh
|
||||
|
||||
export EMSDK="$PWD"
|
||||
cd ..
|
||||
@@ -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://bsky.app/profile/pixelflinger.bsky.social">@pixelflinger</a></li></ul>
|
||||
<li class="minus"><a href="https://github.com/pixelflinger">Mathias Agopian</a>, <a href="https://twitter.com/darthmoosious">@darthmoosious</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,27 +259,26 @@ 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">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">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">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">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">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">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">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">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>
|
||||
<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>
|
||||
</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>
|
||||
@@ -1487,13 +1486,10 @@ 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 have an optional <code>precision</code>, which can be
|
||||
name must be a valid GLSL identifier. Entries also 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>. 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.
|
||||
<a href="#table_materialparamstypes">table 14</a>.
|
||||
|
||||
</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>
|
||||
@@ -1756,13 +1752,7 @@ 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><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>
|
||||
</p></dd></dl><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>
|
||||
@@ -1789,7 +1779,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 5 strings, each must be a valid GLSL identifier.
|
||||
</p></dd><dt>Value</dt><dd><p> Up to 4 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
|
||||
@@ -1804,14 +1794,7 @@ 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><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>
|
||||
</p></dd></dl><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<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
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>matc -a opengl -p mobile -o plastic.filamat plastic.mat
|
||||
</pre></div>
|
||||
|
||||
<p>You should now have a material archive in your working directory, which we'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<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
|
||||
<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
|
||||
</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: #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>
|
||||
<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>
|
||||
|
||||
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;
|
||||
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>
|
||||
|
||||
<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: #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: #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: #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: #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: #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: #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><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>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>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>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>}
|
||||
}
|
||||
<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>
|
||||
</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: #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();
|
||||
<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>
|
||||
|
||||
<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>);
|
||||
<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>
|
||||
</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: #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);
|
||||
<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>
|
||||
|
||||
<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>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>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>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>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);
|
||||
<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>
|
||||
|
||||
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);
|
||||
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>
|
||||
|
||||
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);
|
||||
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>
|
||||
</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: #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);
|
||||
<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>
|
||||
|
||||
<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);
|
||||
<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>
|
||||
</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: #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;
|
||||
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>
|
||||
|
||||
<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: #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: #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">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">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: #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: #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">// 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">// 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);
|
||||
<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>
|
||||
|
||||
scene.setIndirectLight(indirectLight);
|
||||
scene.setIndirectLight(indirectLight);<span style="color: #bbbbbb"></span>
|
||||
</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: #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);
|
||||
<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>
|
||||
</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: #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);
|
||||
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>
|
||||
|
||||
<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);
|
||||
<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>
|
||||
</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: #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);
|
||||
<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>
|
||||
</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<span style="color: #BBB"> </span>--compress<span style="color: #BBB"> </span>monkey.obj<span style="color: #BBB"> </span>suzanne.filamesh
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>filamesh --compress monkey.obj suzanne.filamesh
|
||||
</pre></div>
|
||||
|
||||
<h2>Create mipmapped textures</h2>
|
||||
<p>Next, let'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<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
|
||||
mipgen albedo.png albedo.ktx2
|
||||
mipgen --compression<span style="color: #666666">=</span>uastc albedo.png albedo.ktx2
|
||||
|
||||
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the normal map and a compressed variant.</span>
|
||||
mipgen<span style="color: #BBB"> </span>--strip-alpha<span style="color: #BBB"> </span>--kernel<span style="color: #666">=</span>NORMALS<span style="color: #BBB"> </span>--linear<span style="color: #BBB"> </span>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
|
||||
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
|
||||
|
||||
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component roughness map and a compressed variant.</span>
|
||||
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
|
||||
mipgen --grayscale roughness.png roughness.ktx
|
||||
mipgen --grayscale --compression<span style="color: #666666">=</span>uastc roughness.png roughness.ktx2
|
||||
|
||||
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component metallic map and a compressed variant.</span>
|
||||
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
|
||||
mipgen --grayscale metallic.png metallic.ktx
|
||||
mipgen --grayscale --compression<span style="color: #666666">=</span>uastc metallic.png metallic.ktx2
|
||||
|
||||
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component occlusion map and a compressed variant.</span>
|
||||
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
|
||||
mipgen --grayscale ao.png ao.ktx
|
||||
mipgen --grayscale --compression<span style="color: #666666">=</span>uastc ao.png 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<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>-
|
||||
<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> -
|
||||
|
||||
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
|
||||
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
|
||||
</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<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
|
||||
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>matc -a opengl -p mobile -o textured.filamat 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>
|
||||
<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>
|
||||
|
||||
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>]);
|
||||
});
|
||||
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>
|
||||
|
||||
<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: #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: #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>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>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: #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: #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: #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: #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">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">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">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">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><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>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>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>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>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><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>}
|
||||
}
|
||||
<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>
|
||||
</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: #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>);
|
||||
<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>
|
||||
|
||||
<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>;
|
||||
<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>
|
||||
</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: #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);
|
||||
<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>
|
||||
</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: #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);
|
||||
<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>
|
||||
|
||||
<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">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">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: #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: #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: #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: #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: #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>
|
||||
</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: #666">=</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: #666666">=</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: #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>});
|
||||
<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>
|
||||
</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: #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>();
|
||||
<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>
|
||||
</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: #666">=</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: #666666">=</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: #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">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">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: #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">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">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: #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>}
|
||||
}
|
||||
<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>
|
||||
|
||||
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>);
|
||||
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>
|
||||
</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<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>
|
||||
<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>
|
||||
</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: #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);
|
||||
<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>
|
||||
</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: #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);
|
||||
<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>
|
||||
</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: #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>),
|
||||
]);
|
||||
<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>
|
||||
|
||||
<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>]);
|
||||
<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>
|
||||
</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: #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);
|
||||
<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>
|
||||
|
||||
<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);
|
||||
<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>
|
||||
</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: #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);
|
||||
<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>
|
||||
|
||||
<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>]));
|
||||
<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>
|
||||
</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: #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);
|
||||
<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>
|
||||
</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: #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);
|
||||
<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>
|
||||
|
||||
<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">// 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">// Adjust the initial viewport:</span>
|
||||
<span style="color: #008000; font-weight: bold">this</span>.resize();
|
||||
<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>
|
||||
</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: #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);
|
||||
}
|
||||
<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>
|
||||
</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: #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>();
|
||||
<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>
|
||||
|
||||
<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);
|
||||
<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>
|
||||
</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: #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]);
|
||||
<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>
|
||||
|
||||
<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>);
|
||||
<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>
|
||||
</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>
|
||||
|
||||
@@ -1023,12 +1023,8 @@ samplerCubemap | Cubemap texture
|
||||
[Table [materialParamsTypes]: Material parameter types]
|
||||
|
||||
Samplers
|
||||
: Sampler types can specify additional options:
|
||||
|
||||
- `format`: either `int` or `float` (defaults to `float`).
|
||||
- `stages`: array of strings containing the list of shader stages this
|
||||
sampler can be accessed from. Each entry must be either `vertex` or
|
||||
`fragment` (defaults to both).
|
||||
: Sampler types can also specify a `format` which can be either `int` or `float` (defaults to
|
||||
`float`).
|
||||
|
||||
Arrays
|
||||
: A parameter can define an array of values by appending `[size]` after the type name, where
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
- [Metal](./notes/metal_debugging.md)
|
||||
- [Vulkan](./notes/vulkan_debugging.md)
|
||||
- [SPIR-V](./notes/spirv_debugging.md)
|
||||
- [Running with ASAN and UBSAN](./notes/asan_ubsan.md)
|
||||
- [Using Instruments on macOS](./notes/instruments.md)
|
||||
- [Libraries](./notes/libs.md)
|
||||
- [bluegl](./dup/bluegl.md)
|
||||
- [bluevk](./dup/bluevk.md)
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
# Running with ASAN/UBSAN
|
||||
|
||||
## Enabling
|
||||
|
||||
When building though build.sh, pass the `-b` flag. This sets the cmake variable
|
||||
`FILAMENT_ENABLE_ASAN_UBSAN=ON` which eventually passes `"-fsanitize=address -fsanitize=undefined"`
|
||||
to all compile and link operations.
|
||||
|
||||
If building through CMake directly, or an IDE like CLion that doesn't use build.sh, instead pass
|
||||
`-DFILAMENT_ENABLE_ASAN_UBSAN=ON` to cmake in order to get the same result.
|
||||
|
||||
## Getting memory leak detection on Mac
|
||||
|
||||
Memory leak detection isn't enabled by default on MacOS. There are two issues to address, first is
|
||||
using a version of clang that supports memory leak detection and second is enabling it at runtime.
|
||||
|
||||
The version of clang distributed by Apple (with a version like "Apple clang version 16.0.0") doesn't
|
||||
currently support leak detection at all. Instead you will need to get or build a different LLVM,
|
||||
such as the one distributed through homebrew and get CMake to use that instead.
|
||||
|
||||
Then during runtime you'll need to have the environment variable `ASAN_OPTIONS` include the option
|
||||
`detect_leaks=1`. Multiple `ASAN_OPTIONS` values are concatenated with `:`.
|
||||
|
||||
## Getting memory leak output in CLion
|
||||
|
||||
### Setting variables
|
||||
|
||||
Under `Settings | Build, Execution, Deployment | Dynamic Analysis Tools | Sanitizers` there is an
|
||||
ASAN Settings field that overrides whatever other `ASAN_OPTIONS` you might set elsewhere, so you
|
||||
must use that instead of setting it through your Run/Debug Configuration.
|
||||
|
||||
To pass `-DFILAMENT_ENABLE_ASAN_UBSAN=ON` to CMake you'll want to create a new CMake Profile and
|
||||
pass it as a CMake argument.
|
||||
|
||||
### Avoiding losing output
|
||||
|
||||
CMake will consume ASAN output and display it through a separate "Sanitizers" tab. Unfortunately
|
||||
certain leak detection errors that interrupt the executable seem to not show up in this tab, but are
|
||||
still removed from the user-visible console output. If this is happening and you need to see the
|
||||
unfiltered console output you'll need to go to `Settings | Build, Execution, Deployment | Dynamic
|
||||
Analysis Tools | Sanitizers` and uncheck "Use visual representation for Sanitizer's output".
|
||||
@@ -1,36 +0,0 @@
|
||||
# Using Instruments on macOS
|
||||
|
||||
When running a binary under Instruments on macOS, you may run into the following issue when
|
||||
launching or attaching to an executable:
|
||||
|
||||
```
|
||||
Failed to gain authorization
|
||||
Recovery Suggestion: Target binary needs to be debuggable and signed with 'get-task-allow'
|
||||
```
|
||||
|
||||
This is a security precaution; the solution is to code sign the binary with the
|
||||
`com.apple.security.get-task-allow` entitlement.
|
||||
|
||||
1. Create an `entitlements.plist` file with the following contents:
|
||||
|
||||
```
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.get-task-allow</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
2. Run the following command:
|
||||
|
||||
```
|
||||
codesign -s - --entitlements entitlements.plist <binary>
|
||||
```
|
||||
|
||||
Replace `<binary>` with the name of the binary, for example: `out/cmake-debug/samples/gltf_viewer`.
|
||||
|
||||
Afterwards, you should be able to successfully launch and attach to the executable using
|
||||
Instruments.
|
||||