Compare commits

...

21 Commits

Author SHA1 Message Date
prideout
a82d93914e Bump to v1.4.2 2019-10-30 13:49:36 -07:00
Philip Rideout
389349198f gltfio-jni: Fix double-init panic caused by build issues.
Filament keeps a global static list of engines for verification purposes
which was being recreated multiple times, causing a panic. After a lot
of experimentation with the build, I was not able to fix this while
keeping the current scheme of dynamically loading both libraries.

As a "solution", we now staticly link filament into gltfio-jni, and ask
clients to load only that.

Fixes #1811.
2019-10-30 09:51:14 -07:00
Philip Rideout
225a844e0f Minor improvements to Engine validation.
This enhances the assert added in 2548da9 in the following ways:

- Adds console output at startup to help detect "double load" bugs.
- Adds PRETTY_FUNCTION to show where the invalid usage is coming from.
- Tweaks the wording since use-after-destroy is not always the cause.
- Consolidates usage of static globals into a helper class.

Motivated by #1811.
2019-10-29 15:48:29 -07:00
Mathias Agopian
f018c719a6 a test for the skinning math 2019-10-29 15:38:40 -07:00
Philip Rideout
2a229571ad Minor fixes to gltf-bloom demo. 2019-10-29 10:20:28 -07:00
Romain Guy
35959b547c Use unnormalized vectors to compute bump mapping. (#1813)
If we assume the tangents and bitangents were generated using mikktspace,
we should use the unnormalized vectors, as indicated at mikktspace.com
or in http://www.metalliandy.com/mikktspace/downloads/mikktspace/mikktspace.h
(see last comment at the end of the file).
2019-10-29 09:41:15 +00:00
Philip Rideout
796007377d Revert the Engine validation commit.
This needs to wait until code review and was pushed by accident.

This reverts commit bb90103e74.
2019-10-28 16:14:07 -07:00
Philip Rideout
5c73d0ae75 Update package.json for npm release. 2019-10-28 16:05:45 -07:00
Philip Rideout
bb90103e74 Minor improvements to Engine validation.
This enhances the assert added in 2548da9 in the following ways:

- Adds console output at startup to help detect "double load" bugs.
- Adds PRETTY_FUNCTION to show where the invalid usage is coming from.
- Tweak the wording since use-after-destroy is not always the cause.

Motivated by #1811.
2019-10-28 14:08:54 -07:00
Ben Doherty
0149bc504d Fix Windows GitHub Action (#1814) 2019-10-28 12:22:42 -07:00
Philip Rideout
3db035520b gltf-bloom now invokes the gltfio animator.
Tested with CesiumMan.
2019-10-28 09:32:39 -07:00
Philip Rideout
618b59932c gltfio: Add Java / Kotlin bindings for Animator.
Fixes #1529.
2019-10-28 09:32:39 -07:00
Mathias Agopian
9ef05ad456 better fix for NoopDriver on iOS 2019-10-24 14:17:29 -07:00
Adrian Perez
c8a0dbb59a Fix OpenGL ES 3.0 support on iOS (#1803) 2019-10-24 12:43:23 -07:00
dsternfeld7
35a0b045f8 Adds missing include in NoopDriver that prevented the correct shader model from being picked when using the Noop backend. 2019-10-24 10:58:16 -07:00
Ben Doherty
a4369c833d Add README section on Filament CMake options (#1801) 2019-10-23 13:27:08 -07:00
Philip Rideout
354f1da708 Enhance KHR_debug output + code cleanup. 2019-10-22 12:41:34 -07:00
Philip Rideout
7e47d257d1 OpenGL Driver: add support for KHR_debug.
This extension dumps out some interesting vendor-specific information
to the log, which could be useful for debugging. Interestingly, some
of Android demos produce this output on Pixel 3:

  KHR_debug: EsxBufferObject::Map - Ignoring EsxBufferMapUnsyncedBit

Enabled for debug builds only.
2019-10-22 12:41:34 -07:00
Ben Doherty
c3d2b3578d Add Javadoc for Colors, Box, and MathUtils (#1796) 2019-10-21 17:59:05 -07:00
tpsiaki
783aa06a46 Fix typo in Noop on mobile. (#1799) 2019-10-21 17:41:32 -07:00
Mathias Agopian
faa82ff35a implement diag() in TMatSquareFunctions
this requires using 'auto' as the return type.
2019-10-21 14:27:40 -07:00
46 changed files with 739 additions and 178 deletions

View File

@@ -42,6 +42,7 @@ jobs:
git config gc.auto 0
git fetch --tags --prune --progress --no-recurse-submodules origin +%GITHUB_REF%:%GITHUB_REF:refs/=refs/remote/%
git checkout --progress --force %GITHUB_REF:refs/=refs/remote/%
shell: cmd
- name: Run build script
run: |
build\windows\build-github.bat

View File

@@ -249,6 +249,28 @@ $ ./build.sh -j release
If you use CMake directly instead of the build script, pass `-DENABLE_JAVA=OFF` to CMake instead.
### Filament-specific CMake Options
The following CMake options are boolean options specific to Filament:
- `ENABLE_JAVA`: Compile Java projects: requires a JDK and the JAVA_HOME env var
- `ENABLE_LTO`: Enable link-time optimizations if supported by the compiler
- `FILAMENT_BUILD_FILAMAT`: Build filamat and JNI buildings
- `FILAMENT_SUPPORTS_METAL`: Include the Metal backend
- `FILAMENT_SUPPORTS_VULKAN`: Include the Vulkan backend
- `GENERATE_JS_DOCS`: Build WebGL documentation and tutorials
- `INSTALL_BACKEND_TEST`: Install the backend test library so it can be consumed on iOS
- `USE_EXTERNAL_GLES3`: Experimental: Compile Filament against OpenGL ES 3
To turn an option on or off:
```
$ cd <cmake-build-directory>
$ cmake . -DOPTION=ON # Relace OPTION with the option name, set to ON / OFF
```
Options can also be set with the CMake GUI.
### Linux
Make sure you've installed the following dependencies:

View File

@@ -3,6 +3,15 @@
This file contains one line summaries of commits that are worthy of mentioning in release notes.
A new header is inserted each time a *tag* is created.
## v1.4.2
- Cleaned up the validation strategy in Engine (checks for use-after-destroy etc).
- OpenGL: Fixed ES 3.0 support on iOS.
- OpenGL: Added support for KHR_debug in debug builds.
- gltfio: Added Java / Kotlin bindings for Animator.
- gltfio: Fixed panic with the Android gltf-bloom demo.
- gltfio: Java clients should no longer call Filament#init.
## v1.4.1
- Added missing API documentation.

View File

@@ -50,57 +50,66 @@ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fomit-frame-pointer -ff
set(CMAKE_SHARED_LINKER_FLAGS" ${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections")
set(CMAKE_SHARED_LINKER_FLAGS" ${CMAKE_SHARED_LINKER_FLAGS} -Wl,-Bsymbolic-functions")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${CMAKE_SOURCE_DIR}/libfilament-jni.map")
add_library(filament-jni SHARED
src/main/cpp/Camera.cpp
src/main/cpp/Colors.cpp
src/main/cpp/VertexBuffer.cpp
src/main/cpp/Engine.cpp
src/main/cpp/EntityManager.cpp
src/main/cpp/Fence.cpp
src/main/cpp/IndexBuffer.cpp
src/main/cpp/IndirectLight.cpp
src/main/cpp/LightManager.cpp
src/main/cpp/Material.cpp
src/main/cpp/MaterialInstance.cpp
src/main/cpp/MathUtils.cpp
src/main/cpp/RenderableManager.cpp
src/main/cpp/Renderer.cpp
src/main/cpp/RenderTarget.cpp
src/main/cpp/Scene.cpp
src/main/cpp/SkyBox.cpp
src/main/cpp/Stream.cpp
src/main/cpp/Texture.cpp
src/main/cpp/TextureSampler.cpp
src/main/cpp/TransformManager.cpp
src/main/cpp/View.cpp
# Android specific
src/main/cpp/nativewindow/Android.cpp
# Private utils
src/main/cpp/Filament.cpp
# Common utils
../common/CallbackUtils.cpp
../common/NioUtils.cpp
add_library(filament-jni-obj OBJECT
src/main/cpp/Camera.cpp
src/main/cpp/Colors.cpp
src/main/cpp/VertexBuffer.cpp
src/main/cpp/Engine.cpp
src/main/cpp/EntityManager.cpp
src/main/cpp/Fence.cpp
src/main/cpp/IndexBuffer.cpp
src/main/cpp/IndirectLight.cpp
src/main/cpp/LightManager.cpp
src/main/cpp/Material.cpp
src/main/cpp/MaterialInstance.cpp
src/main/cpp/MathUtils.cpp
src/main/cpp/RenderableManager.cpp
src/main/cpp/Renderer.cpp
src/main/cpp/RenderTarget.cpp
src/main/cpp/Scene.cpp
src/main/cpp/SkyBox.cpp
src/main/cpp/Stream.cpp
src/main/cpp/Texture.cpp
src/main/cpp/TextureSampler.cpp
src/main/cpp/TransformManager.cpp
src/main/cpp/View.cpp
# Android specific
src/main/cpp/nativewindow/Android.cpp
)
target_link_libraries(filament-jni
filament
backend
filaflat
filabridge
geometry
ibl
utils
log
GLESv3
EGL
android
jnigraphics
)
if (NOT DISABLE_FILAMENT_JNI)
option(FILAMENT_SUPPORTS_VULKAN "Enables Vulkan on Android" OFF)
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libfilament-jni.map")
add_library(filament-jni SHARED
$<TARGET_OBJECTS:filament-jni-obj>
# Private utils
src/main/cpp/Filament.cpp
# Common utils
../common/CallbackUtils.cpp
../common/NioUtils.cpp
)
target_link_libraries(filament-jni
filament
backend
filaflat
filabridge
geometry
ibl
utils
log
GLESv3
EGL
android
jnigraphics
)
option(FILAMENT_SUPPORTS_VULKAN "Enables Vulkan on Android" OFF)
if (FILAMENT_SUPPORTS_VULKAN)
target_link_libraries(filament-jni bluevk smol-v)
endif()
if (FILAMENT_SUPPORTS_VULKAN)
target_link_libraries(filament-jni bluevk smol-v)
endif()

View File

@@ -19,12 +19,25 @@ package com.google.android.filament;
import android.support.annotation.NonNull;
import android.support.annotation.Size;
/**
* An axis-aligned 3D box represented by its center and half-extent.
*
* The half-extent is a vector representing the distance from the center to the edge of the box in
* each dimension. For example, a box of size 2 units in X, 4 units in Y, and 10 units in Z would
* have a half-extent of (1, 2, 5).
*/
public class Box {
private final float[] mCenter = new float[3];
private final float[] mHalfExtent = new float[3];
/**
* Default-initializes the 3D box to have a center and half-extent of (0,0,0).
*/
public Box() { }
/**
* Initializes the 3D box from its center and half-extent.
*/
public Box(float centerX, float centerY, float centerZ,
float halfExtentX, float halfExtentY, float halfExtentZ) {
mCenter[0] = centerX;
@@ -35,6 +48,13 @@ public class Box {
mHalfExtent[2] = halfExtentZ;
}
/**
* Initializes the 3D box from its center and half-extent.
*
* @param center a float array with XYZ coordinates representing the center of the box
* @param halfExtent a float array with XYZ coordinates representing half the size of the box in
* each dimension
*/
public Box(@NonNull @Size(min = 3) float[] center, @NonNull @Size(min = 3) float[] halfExtent) {
mCenter[0] = center[0];
mCenter[1] = center[1];
@@ -44,21 +64,37 @@ public class Box {
mHalfExtent[2] = halfExtent[2];
}
/**
* Sets the center of of the 3D box.
*/
public void setCenter(float centerX, float centerY, float centerZ) {
mCenter[0] = centerX;
mCenter[1] = centerY;
mCenter[2] = centerZ;
}
/**
* Sets the half-extent of the 3D box.
*/
public void setHalfExtent(float halfExtentX, float halfExtentY, float halfExtentZ) {
mHalfExtent[0] = halfExtentX;
mHalfExtent[1] = halfExtentY;
mHalfExtent[2] = halfExtentZ;
}
/**
* Returns the center of the 3D box.
*
* @return an XYZ float array of size 3
*/
@NonNull @Size(min = 3)
public float[] getCenter() { return mCenter; }
/**
* Returns the half-extent from the center of the 3D box.
*
* @return an XYZ float array of size 3
*/
@NonNull @Size(min = 3)
public float[] getHalfExtent() { return mHalfExtent; }
}

View File

@@ -28,6 +28,9 @@ import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Utilities to manipulate and convert colors.
*/
public class Colors {
private Colors() {
}
@@ -37,23 +40,67 @@ public class Colors {
public @interface LinearColor {
}
/**
* Types of RGB colors.
*/
public enum RgbType {
/** The color is defined in sRGB space. */
SRGB,
/** The color is defined in linear space. */
LINEAR
}
/**
* Types of RGBA colors.
*/
public enum RgbaType {
/**
* The color is defined in sRGB space and the RGB values have not been premultiplied by the
* alpha (for instance, a 50% transparent red is <1,0,0,0.5>).
*/
SRGB,
/**
* The color is defined in linear space and the RGB values have not been premultiplied by
* the alpha (for instance, a 50% transparent red is <1,0,0,0.5>).
*/
LINEAR,
/**
* The color is defined in sRGB space and the RGB values have been premultiplied by the
* alpha (for instance, a 50% transparent red is <0.5,0,0,0.5>).
*/
PREMULTIPLIED_SRGB,
/**
* The color is defined in linear space and the RGB values have been premultiplied by the
* alpha (for instance, a 50% transparent red is <0.5,0,0,0.5>).
*/
PREMULTIPLIED_LINEAR
}
/**
* Type of color conversion to use when converting to/from sRGB and linear spaces.
*/
public enum Conversion {
/** Accurate conversion using the sRGB standard. */
ACCURATE,
/** Fast conversion using a simple gamma 2.2 curve. */
FAST
}
/**
* Converts an RGB color to linear space, the conversion depends on the specified type.
*
* @param type the color space of the RGB color values provided
* @param r the red component
* @param g the green component
* @param b the blue component
*
* @return an RGB float array of size 3 with the result of the conversion
*/
@NonNull
@Size(3)
@LinearColor
@@ -61,6 +108,14 @@ public class Colors {
return toLinear(type, new float[] { r, g, b });
}
/**
* Converts an RGB color to linear space, the conversion depends on the specified type.
*
* @param type the color space of the RGB color values provided
* @param rgb an RGB float array of size 3, will be modified
*
* @return the passed-in <code>rgb</code> array, after applying the conversion
*/
@NonNull
@Size(min = 3)
@LinearColor
@@ -68,6 +123,17 @@ public class Colors {
return (type == RgbType.LINEAR) ? rgb : toLinear(Conversion.ACCURATE, rgb);
}
/**
* Converts an RGBA color to linear space, with pre-multiplied alpha.
*
* @param type the color space and type of RGBA color values provided
* @param r the red component
* @param g the green component
* @param b the blue component
* @param a the alpha component
*
* @return an RGBA float array of size 4 with the result of the conversion
*/
@NonNull
@Size(4)
@LinearColor
@@ -75,6 +141,14 @@ public class Colors {
return toLinear(type, new float[] { r, g, b, a });
}
/**
* Converts an RGBA color to linear space, with pre-multiplied alpha.
*
* @param type the color space of the RGBA color values provided
* @param rgba an RGBA float array of size 4, will be modified
*
* @return the passed-in <code>rgba</code> array, after applying the conversion
*/
@NonNull
@Size(min = 4)
@LinearColor
@@ -97,6 +171,15 @@ public class Colors {
return rgba;
}
/**
* Converts an RGB color in sRGB space to an RGB color in linear space.
*
* @param conversion the conversion algorithm to use
* @param rgb an RGB float array of at least size 3, will be modified
*
* @return the passed-in <code>rgb</code> array, after applying the conversion. The alpha
* channel, if present, is left unmodified.
*/
@NonNull
@LinearColor
public static float[] toLinear(@NonNull Conversion conversion, @NonNull @Size(min = 3) float[] rgb) {
@@ -116,6 +199,14 @@ public class Colors {
return rgb;
}
/**
* Converts a correlated color temperature to a linear RGB color in sRGB space. The temperature
* must be expressed in Kelvin and must be in the range 1,000K to 15,000K.
*
* @param temperature the temperature, in Kelvin
*
* @return an RGB float array of size 3 with the result of the conversion
*/
@NonNull
@Size(3)
@LinearColor
@@ -125,6 +216,14 @@ public class Colors {
return color;
}
/**
* Converts a CIE standard illuminant series D to a linear RGB color in sRGB space. The
* temperature must be expressed in Kelvin and must be in the range 4,000K to 25,000K.
*
* @param temperature the temperature, in Kelvin
*
* @return an RGB float array of size 3 with the result of the conversion
*/
@NonNull
@Size(3)
@LinearColor

View File

@@ -23,6 +23,29 @@ import android.support.annotation.Size;
public final class MathUtils {
private MathUtils() { }
/**
* Packs the tangent frame represented by the specified tangent, bitangent, and normal into a
* quaternion.
*
* <p>
* Reflection is preserved by encoding it as the sign of the w component in the resulting
* quaternion. Since -0 cannot always be represented on the GPU, this function computes a bias
* to ensure values are always either positive or negative, never 0. The bias is computed based
* on a per-element storage size of 2 bytes, making the resulting quaternion suitable for
* storage into an SNORM16 vector.
* </p>
*
* @param tangentX the X component of the tangent
* @param tangentY the Y component of the tangent
* @param tangentZ the Z component of the tangent
* @param bitangentX the X component of the bitangent
* @param bitangentY the Y component of the bitangent
* @param bitangentZ the Z component of the bitangent
* @param normalX the X component of the normal
* @param normalY the Y component of the normal
* @param normalZ the Z component of the normal
* @param quaternion a float array of at least size 4 for the quaternion result to be stored
*/
public static void packTangentFrame(
float tangentX, float tangentY, float tangentZ,
float bitangentX, float bitangentY, float bitangentZ,
@@ -34,6 +57,30 @@ public final class MathUtils {
normalX, normalY, normalZ, quaternion, 0);
}
/**
* Packs the tangent frame represented by the specified tangent, bitangent, and normal into a
* quaternion.
*
* <p>
* Reflection is preserved by encoding it as the sign of the w component in the resulting
* quaternion. Since -0 cannot always be represented on the GPU, this function computes a bias
* to ensure values are always either positive or negative, never 0. The bias is computed based
* on a per-element storage size of 2 bytes, making the resulting quaternion suitable for
* storage into an SNORM16 vector.
* </p>
*
* @param tangentX the X component of the tangent
* @param tangentY the Y component of the tangent
* @param tangentZ the Z component of the tangent
* @param bitangentX the X component of the bitangent
* @param bitangentY the Y component of the bitangent
* @param bitangentZ the Z component of the bitangent
* @param normalX the X component of the normal
* @param normalY the Y component of the normal
* @param normalZ the Z component of the normal
* @param quaternion a float array of at least size 4 for the quaternion result to be stored
* @param offset offset, in elements, into the quaternion array to store the results
*/
public static void packTangentFrame(
float tangentX, float tangentY, float tangentZ,
float bitangentX, float bitangentY, float bitangentZ,

View File

@@ -2,19 +2,22 @@ cmake_minimum_required(VERSION 3.6)
set(FILAMENT_DIR ${FILAMENT_DIST_DIR})
add_library(filament SHARED IMPORTED)
set(DISABLE_FILAMENT_JNI TRUE)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../filament-android ${CMAKE_CURRENT_BINARY_DIR}/filament-android)
add_library(filament STATIC IMPORTED)
set_target_properties(filament PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilament.a)
add_library(backend SHARED IMPORTED)
add_library(backend STATIC IMPORTED)
set_target_properties(backend PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libbackend.a)
add_library(utils SHARED IMPORTED)
add_library(utils STATIC IMPORTED)
set_target_properties(utils PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libutils.a)
add_library(filaflat SHARED IMPORTED)
add_library(filaflat STATIC IMPORTED)
set_target_properties(filaflat PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilaflat.a)
@@ -26,27 +29,27 @@ add_library(ibl STATIC IMPORTED)
set_target_properties(ibl PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libibl.a)
add_library(geometry SHARED IMPORTED)
add_library(geometry STATIC IMPORTED)
set_target_properties(geometry PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libgeometry.a)
add_library(filabridge SHARED IMPORTED)
add_library(filabridge STATIC IMPORTED)
set_target_properties(filabridge PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfilabridge.a)
add_library(gltfio SHARED IMPORTED)
add_library(gltfio STATIC IMPORTED)
set_target_properties(gltfio PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libgltfio_core.a)
add_library(gltfio_resources SHARED IMPORTED)
add_library(gltfio_resources STATIC IMPORTED)
set_target_properties(gltfio_resources PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libgltfio_resources.a)
add_library(bluevk SHARED IMPORTED)
add_library(bluevk STATIC IMPORTED)
set_target_properties(bluevk PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libbluevk.a)
add_library(smol-v SHARED IMPORTED)
add_library(smol-v STATIC IMPORTED)
set_target_properties(smol-v PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libsmol-v.a)
@@ -54,25 +57,20 @@ include_directories(${FILAMENT_DIR}/include
..
../../libs/utils/include)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-stack-protector")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffast-math -ffp-contract=fast")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fvisibility-inlines-hidden")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fvisibility=hidden")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fomit-frame-pointer -ffunction-sections -fdata-sections")
set(CMAKE_SHARED_LINKER_FLAGS " ${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections")
set(CMAKE_SHARED_LINKER_FLAGS " ${CMAKE_SHARED_LINKER_FLAGS} -Wl,-Bsymbolic-functions")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${CMAKE_SOURCE_DIR}/libgltfio-jni.map")
add_library(gltfio-jni SHARED
src/main/cpp/Animator.cpp
src/main/cpp/AssetLoader.cpp
src/main/cpp/FilamentAsset.cpp
src/main/cpp/KtxLoader.cpp
src/main/cpp/MaterialProvider.cpp
src/main/cpp/ResourceLoader.cpp
../common/CallbackUtils.cpp
../common/NioUtils.cpp
$<TARGET_OBJECTS:filament-jni-obj>
)
set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS
@@ -80,21 +78,22 @@ set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS
# The ordering in the following list is important because CMake does not have dependency information.
target_link_libraries(gltfio-jni
android
gltfio
gltfio_resources
filament
filabridge
backend
filaflat
filabridge
geometry
image
ibl
utils
log
GLESv3
EGL
android
jnigraphics
gltfio_resources
m
log
)
if (FILAMENT_SUPPORTS_VULKAN)

View File

@@ -0,0 +1,59 @@
/*
* 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.
*/
#include <jni.h>
#include <gltfio/Animator.h>
using namespace filament;
using namespace filament::math;
using namespace gltfio;
using namespace utils;
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_gltfio_Animator_nApplyAnimation(JNIEnv*, jclass, jlong nativeAnimator,
jint index, jfloat time) {
Animator* animator = (Animator*) nativeAnimator;
animator->applyAnimation(index, time);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_gltfio_Animator_nUpdateBoneMatrices(JNIEnv*, jclass, jlong nativeAnimator) {
Animator* animator = (Animator*) nativeAnimator;
animator->updateBoneMatrices();
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_gltfio_Animator_nGetAnimationCount(JNIEnv*, jclass, jlong nativeAnimator) {
Animator* animator = (Animator*) nativeAnimator;
return animator->getAnimationCount();
}
extern "C" JNIEXPORT float JNICALL
Java_com_google_android_filament_gltfio_Animator_nGetAnimationDuration(JNIEnv*, jclass,
jlong nativeAnimator, jint index) {
Animator* animator = (Animator*) nativeAnimator;
return animator->getAnimationDuration(index);
}
extern "C" JNIEXPORT jstring JNICALL
Java_com_google_android_filament_gltfio_Animator_nGetAnimationName(JNIEnv* env, jclass,
jlong nativeAnimator, jint index) {
Animator* animator = (Animator*) nativeAnimator;
const char* val = animator->getAnimationName(index);
return val ? env->NewStringUTF(val) : nullptr;
}

View File

@@ -71,3 +71,10 @@ Java_com_google_android_filament_gltfio_FilamentAsset_nGetName(JNIEnv* env, jcla
const char* val = asset->getName(*entity);
return val ? env->NewStringUTF(val) : nullptr;
}
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_gltfio_FilamentAsset_nGetAnimator(JNIEnv* env, jclass,
jlong nativeAsset) {
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
return (jlong) asset->getAnimator();
}

View File

@@ -0,0 +1,103 @@
/*
* 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.gltfio;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
/**
* Updates matrices according to glTF <code>animation</code> and <code>skin</code> definitions.
*
* <p>Animator can be used for two things:
* <ul>
* <li>Updating matrices in <code>TransformManager</code> components according to glTF <code>animation</code> definitions.</li>
* <li>Updating bone matrices in <code>RenderableManager</code> components according to glTF <code>skin</code> definitions.</li>
* </ul>
* </p>
*
* @see AssetLoader
* @see FilamentAsset
* @see ResourceLoader
*/
public class Animator {
private long mNativeObject;
Animator(long nativeObject) {
mNativeObject = nativeObject;
}
/**
* Applies rotation, translation, and scale to entities that have been targeted by the given
* animation definition. Uses <code>TransformManager</code>.
*
* @param animationIndex Zero-based index for the <code>animation</code> of interest.
* @param time Elapsed time of interest in seconds.
*
* @see #getAnimationCount
*/
public void applyAnimation(@IntRange(from = 0) int animationIndex, float time) {
nApplyAnimation(mNativeObject, animationIndex, time);
}
/**
* Computes root-to-node transforms for all bone nodes, then passes
* the results into {@see RenderableManager#setBones}.
* Uses <code>TransformManager</code> and <code>RenderableManager</code>.
*
* <p>NOTE: this operation is independent of <code>animation</code>.</p>
*/
public void updateBoneMatrices() {
nUpdateBoneMatrices(mNativeObject);
}
/**
* Returns the number of <code>animation</code> definitions in the glTF asset.
*/
public int getAnimationCount() {
return nGetAnimationCount(mNativeObject);
}
/**
* Returns the duration of the specified glTF <code>animation</code> in seconds.
*
* @param animationIndex Zero-based index for the <code>animation</code> of interest.
*
* @see #getAnimationCount
* */
public float getAnimationDuration(@IntRange(from = 0) int animationIndex) {
return nGetAnimationDuration(mNativeObject, animationIndex);
}
/**
* Returns a weak reference to the string name of the specified <code>animation</code>, or an
* empty string if none was specified.
*
* @param animationIndex Zero-based index for the <code>animation</code> of interest.
*
* @see #getAnimationCount
*/
public String getAnimationName(@IntRange(from = 0) int animationIndex) {
return nGetAnimationName(mNativeObject, animationIndex);
}
private static native void nApplyAnimation(long nativeAnimator, int index, float time);
private static native void nUpdateBoneMatrices(long nativeAnimator);
private static native int nGetAnimationCount(long nativeAnimator);
private static native float nGetAnimationDuration(long nativeAnimator, int index);
private static native String nGetAnimationName(long nativeAnimator, int index);
}

View File

@@ -55,10 +55,13 @@ import java.nio.Buffer;
* }
*
* ResourceLoader(engine).loadResources(filamentAsset).destroy()
* animator = asset.getAnimator()
*
* scene.addEntities(filamentAsset.entities)
* }
* </pre>
*
* @see Animator
* @see FilamentAsset
* @see ResourceLoader
*/

View File

@@ -37,16 +37,17 @@ import com.google.android.filament.Entity;
* <p>Clients can use {@link ResourceLoader} to create textures, compute tangent quaternions, and
* upload data into vertex buffers and index buffers.</p>
*
* <p>TODO: <code>Animator</code> is not yet exposed to Java / Kotlin clients.</p>
*
* @see ResourceLoader
* @see Animator
* @see AssetLoader
*/
public class FilamentAsset {
private long mNativeObject;
private Animator mAnimator;
FilamentAsset(long nativeObject) {
mNativeObject = nativeObject;
mAnimator = null;
}
long getNativeObject() {
@@ -82,12 +83,26 @@ public class FilamentAsset {
}
/**
* Gets the <code>NameComponentManager<?code> label for the given entity, if it exists.
* Gets the <code>NameComponentManager</code> label for the given entity, if it exists.
*/
public String getName(@Entity int entity) {
return nGetName(getNativeObject(), entity);
}
/**
* Creates or retrieves the <code>Animator</code> for this asset.
*
* <p>When calling this for the first time, this must be called after
* {@see ResourceLoader#loadResources}.</p>
*/
public Animator getAnimator() {
if (mAnimator != null) {
return mAnimator;
}
mAnimator = new Animator(nGetAnimator(getNativeObject()));
return mAnimator;
}
void clearNativeObject() {
mNativeObject = 0;
}
@@ -97,4 +112,5 @@ public class FilamentAsset {
private static native void nGetEntities(long nativeAsset, int[] result);
private static native void nGetBoundingBox(long nativeAsset, float[] box);
private static native String nGetName(long nativeAsset, int entity);
private static native long nGetAnimator(long nativeAsset);
}

View File

@@ -43,10 +43,9 @@ data class Framebuffer(
class MainActivity : Activity() {
// Be sure to initialize not only Filament, but also gltfio (via AssetLoader)
// We are using the gltfio library, so init the AssetLoader rather than Filament.
companion object {
init {
Filament.init()
AssetLoader.init()
}
}
@@ -155,7 +154,7 @@ class MainActivity : Activity() {
// IndirectLight and SkyBox
// ------------------------
val ibl = "venetian_crossroads_2k";
val ibl = "venetian_crossroads_2k"
readUncompressedAsset("envs/$ibl/${ibl}_ibl.ktx").let {
primary.scene.indirectLight = KtxLoader.createIndirectLight(engine, it, KtxLoader.Options())
@@ -242,6 +241,13 @@ class MainActivity : Activity() {
0.0f, -1.7f, 0.0f, 1.0f
))
// The lucy asset does not have animation but we invoke the asset animator for demonstration purposes.
if (filamentAsset.animator.animationCount > 0) {
val elapsedTimeInSeconds = a.currentPlayTime.toFloat() / 1000.0f
filamentAsset.animator.applyAnimation(0, elapsedTimeInSeconds)
filamentAsset.animator.updateBoneMatrices()
}
}
animator.start()
}
@@ -429,7 +435,7 @@ class MainActivity : Activity() {
// Stop the animation and any pending frame
choreographer.removeFrameCallback(frameScheduler)
animator.cancel();
animator.cancel()
// Always detach the surface before destroying the engine
uiHelper.detach()

View File

@@ -31,10 +31,10 @@ NoopDriver::NoopDriver() noexcept : DriverBase(new ConcreteDispatcher<NoopDriver
NoopDriver::~NoopDriver() noexcept = default;
backend::ShaderModel NoopDriver::getShaderModel() const noexcept {
#if defined(GLES31_HEADERS)
return backend::ShaderModel::GL_CORE_30;
#if defined(ANDROID) || defined(IOS)
return ShaderModel::GL_ES_30;
#else
return backend::ShaderModel::GL_CORE_41;
return ShaderModel::GL_CORE_41;
#endif
}

View File

@@ -75,7 +75,7 @@ void OpenGLBlitter::init() noexcept {
GLint status;
char const* vsource[2] = { s_vertexES, s_vertexGL };
char const* fsource[2] = { s_fragmentES, s_fragmentGL };
const size_t index = GLES31_HEADERS ? 0 : 1;
const size_t index = GLES30_HEADERS ? 0 : 1;
mVertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(mVertexShader, 1, vsource + index, nullptr);

View File

@@ -90,7 +90,7 @@ OpenGLContext::OpenGLContext() noexcept {
}
ShaderModel shaderModel = ShaderModel::UNKNOWN;
if (GLES31_HEADERS) {
if (GLES30_HEADERS) {
if (major == 3 && minor >= 0) {
shaderModel = ShaderModel::GL_ES_30;
}
@@ -105,6 +105,7 @@ OpenGLContext::OpenGLContext() noexcept {
initExtensionsGL(major, minor, exts);
features.multisample_texture = true;
};
assert(shaderModel != ShaderModel::UNKNOWN);
mShaderModel = shaderModel;
/*
@@ -138,6 +139,35 @@ OpenGLContext::OpenGLContext() noexcept {
glHint(GL_FRAGMENT_SHADER_DERIVATIVE_HINT, GL_NICEST);
#endif
#if !defined(NDEBUG) && defined(GL_KHR_debug)
if (ext.KHR_debug) {
auto cb = [](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
const GLchar* message, const void *userParam) {
io::LogStream* stream;
switch (severity) {
case GL_DEBUG_SEVERITY_HIGH: stream = &slog.e; break;
case GL_DEBUG_SEVERITY_MEDIUM: stream = &slog.w; break;
case GL_DEBUG_SEVERITY_LOW: stream = &slog.d; break;
case GL_DEBUG_SEVERITY_NOTIFICATION: stream = &slog.i; break;
}
io::LogStream& out = *stream;
out << "KHR_debug ";
switch (type) {
case GL_DEBUG_TYPE_ERROR: out << "ERROR"; break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: out << "DEPRECATED_BEHAVIOR"; break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: out << "UNDEFINED_BEHAVIOR"; break;
case GL_DEBUG_TYPE_PORTABILITY: out << "PORTABILITY"; break;
case GL_DEBUG_TYPE_PERFORMANCE: out << "PERFORMANCE"; break;
case GL_DEBUG_TYPE_OTHER: out << "OTHER"; break;
case GL_DEBUG_TYPE_MARKER: out << "MARKER"; break;
}
out << ": " << message << io::endl;
};
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback(cb, nullptr);
}
#endif
}
UTILS_NOINLINE
@@ -157,6 +187,7 @@ void OpenGLContext::initExtensionsGLES(GLint major, GLint minor, ExtentionSet co
ext.APPLE_color_buffer_packed_float = hasExtension(exts, "GL_APPLE_color_buffer_packed_float");
ext.texture_compression_s3tc = hasExtension(exts, "WEBGL_compressed_texture_s3tc");
ext.EXT_multisampled_render_to_texture = hasExtension(exts, "GL_EXT_multisampled_render_to_texture");
ext.KHR_debug = hasExtension(exts, "GL_KHR_debug");
// ES 3.2 implies EXT_color_buffer_float
if (major >= 3 && minor >= 2) {
ext.EXT_color_buffer_float = true;
@@ -172,6 +203,7 @@ void OpenGLContext::initExtensionsGL(GLint major, GLint minor, ExtentionSet cons
ext.EXT_color_buffer_half_float = true; // Assumes core profile.
ext.EXT_color_buffer_float = true; // Assumes core profile.
ext.APPLE_color_buffer_packed_float = true; // Assumes core profile.
ext.KHR_debug = major >= 4 && minor >= 3;
}
void OpenGLContext::bindBuffer(GLenum target, GLuint buffer) noexcept {

View File

@@ -121,6 +121,7 @@ public:
bool EXT_color_buffer_float = false;
bool APPLE_color_buffer_packed_float = false;
bool EXT_multisampled_render_to_texture = false;
bool KHR_debug = false;
} ext;
struct {

View File

@@ -93,7 +93,7 @@ Driver* OpenGLDriver::create(
return {};
}
if (GLES31_HEADERS) {
if (GLES30_HEADERS) {
// we require GLES 3.1 headers, but we support GLES 3.0
if (UTILS_UNLIKELY(!(major >= 3 && minor >= 0))) {
PANIC_LOG("OpenGL ES 3.0 minimum needed (current %d.%d)", major, minor);
@@ -201,7 +201,7 @@ void OpenGLDriver::initClearProgram() noexcept {
}
)SHADER";
if (GLES31_HEADERS) {
if (GLES30_HEADERS) {
GLint status;
char const* const vsource = clearVertexES;
char const* const fsource = clearFragmentES;
@@ -234,7 +234,7 @@ void OpenGLDriver::initClearProgram() noexcept {
}
void OpenGLDriver::terminateClearProgram() noexcept {
if (GLES31_HEADERS) {
if (GLES30_HEADERS) {
glDetachShader(mClearProgram, mClearVertexShader);
glDetachShader(mClearProgram, mClearFragmentShader);
glDeleteShader(mClearVertexShader);
@@ -1810,7 +1810,7 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
// glInvalidateFramebuffer appeared on GLES 3.0 and GL4.3, for simplicity we just
// ignore it on GL (rather than having to do a runtime check).
if (GLES31_HEADERS) {
if (GLES30_HEADERS) {
if (!gl.bugs.disable_invalidate_framebuffer) {
std::array<GLenum, 3> attachments; // NOLINT
GLsizei attachmentCount = getAttachments(attachments, rt, discardFlags);
@@ -1862,7 +1862,7 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
} else {
gl.disable(GL_SCISSOR_TEST);
}
if (respectScissor && GLES31_HEADERS && gl.bugs.clears_hurt_performance) {
if (respectScissor && GLES30_HEADERS && gl.bugs.clears_hurt_performance) {
// With OpenGL ES, we clear the viewport using geometry to improve performance on certain
// OpenGL drivers. e.g. on Adreno this avoids needless loads from the GMEM.
clearWithGeometryPipe(clearColor, params.clearColor,
@@ -1898,7 +1898,7 @@ void OpenGLDriver::endRenderPass(int) {
// glInvalidateFramebuffer appeared on GLES 3.0 and GL4.3, for simplicity we just
// ignore it on GL (rather than having to do a runtime check).
if (GLES31_HEADERS) {
if (GLES30_HEADERS) {
if (!gl.bugs.disable_invalidate_framebuffer) {
// we wouldn't have to bind the framebuffer if we had glInvalidateNamedFramebuffer()
gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
@@ -1950,7 +1950,7 @@ void OpenGLDriver::discardSubRenderTargetBuffers(Handle<HwRenderTarget> rth,
// glInvalidateSubFramebuffer appeared on GLES 3.0 and GL4.3, for simplicity we just
// ignore it on GL (rather than having to do a runtime check).
if (GLES31_HEADERS) {
if (GLES30_HEADERS) {
// we wouldn't have to bind the framebuffer if we had glInvalidateNamedFramebuffer()
GLRenderTarget const* rt = handle_cast<GLRenderTarget const*>(rth);
@@ -2510,7 +2510,7 @@ void OpenGLDriver::clearWithGeometryPipe(
auto& gl = mContext;
// GLES is required to use this method; see initClearProgram.
assert(GLES31_HEADERS);
assert(GLES30_HEADERS);
// TODO: handle stencil clear with geometry as well
if (clearStencil) {

View File

@@ -38,6 +38,10 @@ PFNGLPOPGROUPMARKEREXTPROC glPopGroupMarkerEXT;
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT;
PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT;
#endif
#ifdef GL_KHR_debug
PFNGLDEBUGMESSAGECALLBACKKHRPROC glDebugMessageCallbackKHR;
PFNGLGETDEBUGMESSAGELOGKHRPROC glGetDebugMessageLogKHR;
#endif
static std::once_flag sGlExtInitialized;
@@ -79,6 +83,14 @@ void importGLESExtensionsEntryPoints() {
glRenderbufferStorageMultisampleEXT =
(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)eglGetProcAddress(
"glRenderbufferStorageMultisampleEXT");
#endif
#ifdef GL_KHR_debug
glDebugMessageCallbackKHR =
(PFNGLDEBUGMESSAGECALLBACKKHRPROC)eglGetProcAddress(
"glDebugMessageCallbackKHR");
glGetDebugMessageLogKHR =
(PFNGLGETDEBUGMESSAGELOGKHRPROC)eglGetProcAddress(
"glGetDebugMessageLogKHR");
#endif
});
}

View File

@@ -43,9 +43,32 @@
#if GL_EXT_multisampled_render_to_texture
extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT;
extern PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT;
#endif
#ifdef GL_KHR_debug
extern PFNGLDEBUGMESSAGECALLBACKKHRPROC glDebugMessageCallbackKHR;
extern PFNGLGETDEBUGMESSAGELOGKHRPROC glGetDebugMessageLogKHR;
#endif
}
// Prevent lots of #ifdef's between desktop and mobile by providing some suffix-free constants:
#define GL_DEBUG_OUTPUT 0x92E0
#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
#define GL_DEBUG_SEVERITY_HIGH 0x9146
#define GL_DEBUG_SEVERITY_MEDIUM 0x9147
#define GL_DEBUG_SEVERITY_LOW 0x9148
#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B
#define GL_DEBUG_TYPE_MARKER 0x8268
#define GL_DEBUG_TYPE_ERROR 0x824C
#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E
#define GL_DEBUG_TYPE_PORTABILITY 0x824F
#define GL_DEBUG_TYPE_PERFORMANCE 0x8250
#define GL_DEBUG_TYPE_OTHER 0x8251
#define glDebugMessageCallback glext::glDebugMessageCallbackKHR
using namespace glext;
#elif defined(IOS)
@@ -75,6 +98,12 @@
#error "Minimum header version must be OpenGL ES 3.0 or OpenGL 4.1"
#endif
#if defined(GL_ES_VERSION_3_0)
#define GLES30_HEADERS true
#else
#define GLES30_HEADERS false
#endif
#if defined(GL_ES_VERSION_3_1)
#define GLES31_HEADERS true
#else

View File

@@ -60,9 +60,42 @@ using namespace filaflat;
namespace details {
// The global list of engines
static std::unordered_map<Engine const*, std::unique_ptr<FEngine>> sEngines;
static std::mutex sEnginesLock;
// Global list of engines used for diagnostic purposes only.
// This console output in the constructor helps catch situations where the Filament library is
// loaded twice, or not at all. Note that we avoid using slog due to static initialization.
class EngineList {
public:
EngineList() {
io::LogStream cinfo(io::LogStream::Priority::INFO);
cinfo << "Filament library loaded." << io::endl;
}
void add(FEngine* instance) {
std::unique_ptr<FEngine> engine(instance);
std::lock_guard<std::mutex> guard(mLock);
Engine* handle = engine.get();
mEngines[handle] = std::move(engine);
}
std::unique_ptr<FEngine> remove(FEngine* instance) {
std::unique_ptr<FEngine> filamentEngine;
std::lock_guard<std::mutex> guard(mLock);
auto const& pos = mEngines.find(instance);
if (pos != mEngines.end()) {
std::swap(filamentEngine, pos->second);
mEngines.erase(pos);
}
return filamentEngine;
}
bool isValid(Engine const& engine, const char* function) {
std::lock_guard<std::mutex> guard(mLock);
auto const& pos = mEngines.find(&engine);
return pos != mEngines.end();
}
private:
std::unordered_map<Engine const*, std::unique_ptr<FEngine>> mEngines;
std::mutex mLock;
};
static EngineList sEngines;
FEngine* FEngine::create(Backend backend, Platform* platform, void* sharedGLContext) {
FEngine* instance = new FEngine(backend, platform, sharedGLContext);
@@ -98,13 +131,7 @@ FEngine* FEngine::create(Backend backend, Platform* platform, void* sharedGLCont
}
}
// Add this Engine to the list of active Engines
{ // scope for the lock
std::unique_ptr<FEngine> engine(instance);
std::lock_guard<std::mutex> guard(sEnginesLock);
Engine* handle = engine.get();
sEngines[handle] = std::move(engine);
}
sEngines.add(instance);
// now we can initialize the largest part of the engine
instance->init();
@@ -116,16 +143,10 @@ FEngine* FEngine::create(Backend backend, Platform* platform, void* sharedGLCont
return instance;
}
void FEngine::assertValid(Engine const& engine) {
bool valid;
{ // scope for the lock
std::lock_guard<std::mutex> guard(sEnginesLock);
auto const& engines = sEngines;
auto const& pos = engines.find(&engine);
valid = pos != engines.end();
}
void FEngine::assertValid(Engine const& engine, const char* function) {
bool valid = sEngines.isValid(engine, function);
ASSERT_POSTCONDITION(valid,
"Using an Engine instance (@ %p) after it's been destroyed", &engine);
"Using an invalid Engine instance (@ %p) from %s.", &engine, function);
}
// these must be static because only a pointer is copied to the render stream
@@ -751,17 +772,7 @@ bool FEngine::execute() {
void FEngine::destroy(FEngine* engine) {
if (engine) {
std::unique_ptr<FEngine> filamentEngine;
std::unique_lock<std::mutex> guard(sEnginesLock);
auto const& pos = sEngines.find(engine);
if (pos != sEngines.end()) {
std::swap(filamentEngine, pos->second);
sEngines.erase(pos);
}
guard.unlock();
// Make sure to call into shutdown() without the lock held
std::unique_ptr<FEngine> filamentEngine = sEngines.remove(engine);
if (filamentEngine) {
filamentEngine->shutdown();
}

View File

@@ -48,7 +48,7 @@ IndexBuffer::Builder& IndexBuffer::Builder::bufferType(IndexType indexType) noex
}
IndexBuffer* IndexBuffer::Builder::build(Engine& engine) {
FEngine::assertValid(engine);
FEngine::assertValid(engine, __PRETTY_FUNCTION__);
return upcast(engine).createIndexBuffer(*this);
}

View File

@@ -148,7 +148,7 @@ IndirectLight::Builder& IndirectLight::Builder::rotation(mat3f const& rotation)
}
IndirectLight* IndirectLight::Builder::build(Engine& engine) {
FEngine::assertValid(engine);
FEngine::assertValid(engine, __PRETTY_FUNCTION__);
if (mImpl->mReflectionsMap) {
if (!ASSERT_POSTCONDITION_NON_FATAL(
mImpl->mReflectionsMap->getTarget() == Texture::Sampler::SAMPLER_CUBEMAP,

View File

@@ -73,7 +73,7 @@ Material::Builder& Material::Builder::package(const void* payload, size_t size)
}
Material* Material::Builder::build(Engine& engine) {
FEngine::assertValid(engine);
FEngine::assertValid(engine, __PRETTY_FUNCTION__);
MaterialParser* materialParser = FMaterial::createParser(
upcast(engine).getBackend(), mImpl->mPayload, mImpl->mSize);

View File

@@ -61,7 +61,7 @@ RenderTarget::Builder& RenderTarget::Builder::layer(AttachmentPoint pt, uint32_t
}
RenderTarget* RenderTarget::Builder::build(Engine& engine) {
FEngine::assertValid(engine);
FEngine::assertValid(engine, __PRETTY_FUNCTION__);
using backend::TextureUsage;
const FRenderTarget::Attachment& color = mImpl->mAttachments[COLOR];
const FRenderTarget::Attachment& depth = mImpl->mAttachments[DEPTH];

View File

@@ -68,7 +68,7 @@ Skybox::Builder& Skybox::Builder::showSun(bool show) noexcept {
}
Skybox* Skybox::Builder::build(Engine& engine) {
FEngine::assertValid(engine);
FEngine::assertValid(engine, __PRETTY_FUNCTION__);
FTexture* cubemap = upcast(mImpl->mEnvironmentMap);
if (!ASSERT_PRECONDITION_NON_FATAL(cubemap, "environment texture not set")) {

View File

@@ -69,7 +69,7 @@ Stream::Builder& Stream::Builder::height(uint32_t height) noexcept {
}
Stream* Stream::Builder::build(Engine& engine) {
FEngine::assertValid(engine);
FEngine::assertValid(engine, __PRETTY_FUNCTION__);
if (!ASSERT_PRECONDITION_NON_FATAL(!mImpl->mStream || !mImpl->mExternalTextureId,
"One and only one of the stream or external texture can be specified")) {
return nullptr;

View File

@@ -92,7 +92,7 @@ Texture::Builder& Texture::Builder::usage(Texture::Usage usage) noexcept {
}
Texture* Texture::Builder::build(Engine& engine) {
FEngine::assertValid(engine);
FEngine::assertValid(engine, __PRETTY_FUNCTION__);
if (!ASSERT_POSTCONDITION_NON_FATAL(Texture::isTextureFormatSupported(engine, mImpl->mFormat),
"Texture format %u not supported on this platform", mImpl->mFormat)) {
return nullptr;

View File

@@ -108,7 +108,7 @@ VertexBuffer::Builder& VertexBuffer::Builder::normalized(VertexAttribute attribu
}
VertexBuffer* VertexBuffer::Builder::build(Engine& engine) {
FEngine::assertValid(engine);
FEngine::assertValid(engine, __PRETTY_FUNCTION__);
if (!ASSERT_PRECONDITION_NON_FATAL(mImpl->mVertexCount > 0, "vertexCount cannot be 0")) {
return nullptr;
}

View File

@@ -128,7 +128,7 @@ LightManager::Builder& LightManager::Builder::sunHaloFalloff(float haloFalloff)
}
LightManager::Builder::Result LightManager::Builder::build(Engine& engine, Entity entity) {
FEngine::assertValid(engine);
FEngine::assertValid(engine, __PRETTY_FUNCTION__);
upcast(engine).createLight(*this, entity);
return Success;
}

View File

@@ -167,7 +167,7 @@ RenderableManager::Builder& RenderableManager::Builder::blendOrder(size_t index,
}
RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& engine, Entity entity) {
FEngine::assertValid(engine);
FEngine::assertValid(engine, __PRETTY_FUNCTION__);
bool isEmpty = true;
if (!ASSERT_PRECONDITION_NON_FATAL(mImpl->mSkinningBoneCount <= CONFIG_MAX_BONE_COUNT,

View File

@@ -134,7 +134,7 @@ public:
static void destroy(FEngine* engine);
static void assertValid(Engine const& engine);
static void assertValid(Engine const& engine, const char* function);
~FEngine() noexcept;

View File

@@ -61,6 +61,96 @@ static bool vec3eq(float3 a, float3 b) {
almostEqualUlps(a.z, b.z, 1);
}
TEST(FilamentTest, SkinningMath) {
struct Bone {
quatf q;
float4 t;
float4 s;
};
auto makeBone = [&](mat4f m) -> Bone {
// figure out the scales
float4 s = { length(m[0]), length(m[1]), length(m[2]), 0.0f };
if (dot(cross(m[0].xyz, m[1].xyz), m[2].xyz) < 0) {
s[2] = -s[2];
}
// compute the inverse scales
float4 is = { 1.0f/s.x, 1.0f/s.y, 1.0f/s.z, 0.0f };
// normalize the matrix
m[0] *= is[0];
m[1] *= is[1];
m[2] *= is[2];
Bone bone;
bone.s = s;
bone.q = m.toQuaternion();
bone.t = m[3];
return bone;
};
auto applyBone = [](Bone const& bone, float3 v) -> float3 {
float4 q = bone.q.xyzw;
float3 t = bone.t.xyz;
float3 s = bone.s.xyz;
// apply the non-uniform scales
v *= s;
// apply the rigid transform (valid only for unit quaternions)
v += 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v);
// apply the translation
v += t;
return v;
};
auto check = [&](mat4f m, float3 v) {
float3 expect = (m * v).xyz;
float3 actual = applyBone(makeBone(m), v);
static constexpr float value_eps = 40 * std::numeric_limits<float>::epsilon();
EXPECT_NEAR(expect.x, actual.x, value_eps);
EXPECT_NEAR(expect.y, actual.y, value_eps);
EXPECT_NEAR(expect.z, actual.z, value_eps);
};
mat4f m;
float3 v = {1, 2, 3};
m = mat4f::translation(float3{1, 2, 3});
check(m, v);
m = mat4f::scaling(float3{1, 2, 3});
check(m, v);
m = mat4f::scaling(float3{1, 2, 3}) * mat4f::translation(float3{1, 2, 3});
check(m, v);
m = mat4f::translation(float3{1, 2, 3}) * mat4f::scaling(float3{1, 2, 3});
check(m, v);
m = mat4f::translation(float3{1, 2, 3}) * mat4f::scaling(float3{1, -4, 1});
check(m, v);
std::default_random_engine generator(82828); // NOLINT
std::uniform_real_distribution<float> distribution(-4, 4);
std::uniform_real_distribution<float> dangle(-2.0 * F_PI, 2.0 * F_PI);
auto rand_gen = std::bind(distribution, generator);
for (size_t i = 0; i < 100; ++i) {
m =
mat4f::translation(float3{rand_gen(), rand_gen(), rand_gen()}) *
mat4f::rotation(dangle(generator), normalize(float3{rand_gen(), rand_gen(), rand_gen()})) *
mat4f::scaling(float3{rand_gen(), rand_gen(), rand_gen()});
check(m, v);
}
}
TEST(FilamentTest, TransformManager) {
filament::details::FTransformManager tcm;
EntityManager& em = EntityManager::get();

View File

@@ -51,6 +51,7 @@ set(JNI_SOURCE_FILES
${FILAMENT_DIR}/src/main/cpp/LightManager.cpp
${FILAMENT_DIR}/src/main/cpp/Material.cpp
${FILAMENT_DIR}/src/main/cpp/MaterialInstance.cpp
${FILAMENT_DIR}/src/main/cpp/MathUtils.cpp
${FILAMENT_DIR}/src/main/cpp/NativeSurface.cpp
${FILAMENT_DIR}/src/main/cpp/RenderableManager.cpp
${FILAMENT_DIR}/src/main/cpp/Renderer.cpp
@@ -127,6 +128,7 @@ set(JAVA_SOURCE_FILES
${FILAMENT_JAVA_DIR}/com/google/android/filament/LightManager.java
${FILAMENT_JAVA_DIR}/com/google/android/filament/Material.java
${FILAMENT_JAVA_DIR}/com/google/android/filament/MaterialInstance.java
${FILAMENT_JAVA_DIR}/com/google/android/filament/MathUtils.java
${FILAMENT_JAVA_DIR}/com/google/android/filament/NativeSurface.java
${FILAMENT_JAVA_DIR}/com/google/android/filament/NioUtils.java
${FILAMENT_JAVA_DIR}/com/google/android/filament/Platform.java

View File

@@ -656,6 +656,12 @@ private:
friend inline constexpr T MATH_PURE det(const BASE<T>& m) {
return matrix::det(m);
}
// unclear why we have to use 'auto' here. 'typename BASE<T>::col_type' produces
// error: no type named 'col_type' in 'filament::math::details::TMat44<float>'
friend inline constexpr auto MATH_PURE diag(const BASE<T>& m) {
return matrix::diag(m);
}
};
template<template<typename U> class BASE, typename T>

View File

@@ -108,10 +108,7 @@ private:
public:
// array access
inline constexpr col_type const& operator[](size_t column) const noexcept {
#if __cplusplus >= 201402L
// only possible in C++0x14 with constexpr
assert(column < NUM_COLS);
#endif
return m_value[column];
}
@@ -320,16 +317,6 @@ constexpr TMat22<T>::TMat22(const TVec2<A>& v0, const TVec2<B>& v1) noexcept
: m_value{ v0, v1 } {
}
// ----------------------------------------------------------------------------------------
/* FIXME: this should go into TMatSquareFunctions<> but for some reason
* BASE<T>::col_type is not accessible from there (???)
*/
template<typename T>
constexpr typename TMat22<T>::col_type MATH_PURE diag(const TMat22<T>& m) noexcept {
return matrix::diag(m);
}
} // namespace details
// ----------------------------------------------------------------------------------------

View File

@@ -114,7 +114,6 @@ private:
public:
// array access
inline constexpr col_type const& operator[](size_t column) const noexcept {
// only possible in C++0x14 with constexpr
assert(column < NUM_COLS);
return m_value[column];
}
@@ -412,16 +411,6 @@ constexpr TQuaternion<T> TMat33<T>::packTangentFrame(const TMat33<T>& m, size_t
return q;
}
// ----------------------------------------------------------------------------------------
/* FIXME: this should go into TMatSquareFunctions<> but for some reason
* BASE<T>::col_type is not accessible from there (???)
*/
template<typename T>
constexpr typename TMat33<T>::col_type MATH_PURE diag(const TMat33<T>& m) noexcept {
return matrix::diag(m);
}
} // namespace details
// ----------------------------------------------------------------------------------------

View File

@@ -122,7 +122,6 @@ private:
public:
// array access
inline constexpr col_type const& operator[](size_t column) const noexcept {
// only possible in C++0x14 with constexpr
assert(column < NUM_COLS);
return m_value[column];
}
@@ -552,16 +551,6 @@ constexpr typename TMat44<T>::col_type MATH_PURE operator*(const TMat44<T>& lhs,
return lhs * TVec4<U>{ rhs, 1 };
}
// ----------------------------------------------------------------------------------------
/* FIXME: this should go into TMatSquareFunctions<> but for some reason
* BASE<T>::col_type is not accessible from there (???)
*/
template<typename T>
constexpr typename TMat44<T>::col_type MATH_PURE diag(const TMat44<T>& m) noexcept {
return matrix::diag(m);
}
} // namespace details
// ----------------------------------------------------------------------------------------

View File

@@ -57,7 +57,6 @@ public:
// array access
inline constexpr T const& operator[](size_t i) const noexcept {
// only possible in C++0x14 with constexpr
assert(i < SIZE);
return v[i];
}

View File

@@ -70,7 +70,6 @@ public:
// array access
inline constexpr T const& operator[](size_t i) const noexcept {
// only possible in C++0x14 with constexpr
assert(i < SIZE);
return v[i];
}

View File

@@ -70,7 +70,6 @@ public:
// array access
inline constexpr T const& operator[](size_t i) const noexcept {
// only possible in C++0x14 with constexpr
assert(i < SIZE);
return v[i];
}

View File

@@ -3,7 +3,8 @@
highp mat3 shading_tangentToWorld; // TBN matrix
highp vec3 shading_position; // position of the fragment in world space
vec3 shading_view; // normalized vector from the fragment to the eye
vec3 shading_normal; // normalized normal, in world space
vec3 shading_normal; // normalized transformed normal, in world space
vec3 shading_geometricNormal; // normalized geometric normal, in world space
vec3 shading_reflected; // reflection of view about normal
float shading_NoV; // dot(normal, view), always strictly >= MIN_N_DOT_V

View File

@@ -48,7 +48,7 @@ vec3 getWorldNormalVector() {
/** @public-api */
vec3 getWorldGeometricNormalVector() {
return shading_tangentToWorld[2];
return shading_geometricNormal;
}
/** @public-api */

View File

@@ -16,13 +16,12 @@ void computeShadingParams() {
}
#endif
shading_geometricNormal = normalize(n);
#if defined(MATERIAL_HAS_ANISOTROPY) || defined(MATERIAL_HAS_NORMAL) || defined(MATERIAL_HAS_CLEAR_COAT_NORMAL)
// Re-normalize post-interpolation values
shading_tangentToWorld = mat3(
normalize(vertex_worldTangent), normalize(vertex_worldBitangent), normalize(n));
// We use unnormalized post-interpolation values, assuming mikktspace tangents
shading_tangentToWorld = mat3(vertex_worldTangent, vertex_worldBitangent, n);
#endif
// Leave the tangent and bitangent uninitialized, we won't use them
shading_tangentToWorld[2] = normalize(n);
#endif
shading_position = vertex_worldPosition;

View File

@@ -1,6 +1,6 @@
{
"name": "filament",
"version": "1.4.0",
"version": "1.4.2",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",