Merge branch 'rc/1.17.0' into release

This commit is contained in:
Benjamin Doherty
2022-01-24 12:50:22 -08:00
127 changed files with 4999 additions and 2734 deletions
+5 -1
View File
@@ -123,6 +123,10 @@ if (ANDROID OR WEBGL OR IOS OR FILAMENT_LINUX_IS_MOBILE)
set(IS_MOBILE_TARGET TRUE)
endif()
if (ANDROID)
add_definitions(-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__)
endif()
if (NOT ANDROID AND NOT WEBGL AND NOT IOS AND NOT FILAMENT_LINUX_IS_MOBILE)
set(IS_HOST_PLATFORM TRUE)
endif()
@@ -295,7 +299,7 @@ if (LINUX)
endif()
if (ANDROID)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Werror=unguarded-availability")
endif()
if (CYGWIN)
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.16.1'
implementation 'com.google.android.filament:filament-android:1.17.0'
}
```
@@ -52,7 +52,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release:
```
pod 'Filament', '~> 1.16.1'
pod 'Filament', '~> 1.17.0'
```
### Snapshots
+9 -1
View File
@@ -3,7 +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.16.2 (currently main branch)
## v1.17.1 (currently main branch)
## v1.17.0
- engine: Add experimental glossy screen-space reflections.
- engine: Add support for GPU morphing and 128 morph targets.
- engine: Fix crash with non-shadow receiving renderables and VSM.
- engine: Bring back the 3x3 filter for PCF shadows.
- engine: Correct AABB calculation for skinned glTF models.
## v1.16.1
@@ -114,14 +114,14 @@ public class MaterialBuilder {
BONE_INDICES, // indices of 4 bones (uvec4)
BONE_WEIGHTS, // weights of the 4 bones (normalized float4)
UNUSED, // reserved for future use
CUSTOM0, // custom or MORPH_POSITION_0
CUSTOM1, // custom or MORPH_POSITION_1
CUSTOM2, // custom or MORPH_POSITION_2
CUSTOM3, // custom or MORPH_POSITION_3
CUSTOM4, // custom or MORPH_TANGENTS_0
CUSTOM5, // custom or MORPH_TANGENTS_1
CUSTOM6, // custom or MORPH_TANGENTS_2
CUSTOM7 // custom or MORPH_TANGENTS_3
CUSTOM0, // custom
CUSTOM1, // custom
CUSTOM2, // custom
CUSTOM3, // custom
CUSTOM4, // custom
CUSTOM5, // custom
CUSTOM6, // custom
CUSTOM7 // custom
}
public enum BlendingMode {
@@ -270,9 +270,9 @@ Java_com_google_android_filament_RenderableManager_nSetMorphWeights(JNIEnv* env,
jlong nativeRenderableManager, jint instance, jfloatArray weights) {
RenderableManager *rm = (RenderableManager *) nativeRenderableManager;
jfloat* vec = env->GetFloatArrayElements(weights, NULL);
math::float4 floatvec(vec[0], vec[1], vec[2], vec[3]);
jsize count = env->GetArrayLength(weights);
rm->setMorphWeights((RenderableManager::Instance)instance, vec, count);
env->ReleaseFloatArrayElements(weights, vec, JNI_ABORT);
rm->setMorphWeights((RenderableManager::Instance)instance, floatvec);
}
extern "C" JNIEXPORT void JNICALL
@@ -49,8 +49,8 @@ Java_com_google_android_filament_ToneMapper_nCreateFilmicToneMapper(JNIEnv*, jcl
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_ToneMapper_nCreateGenericToneMapper(JNIEnv*, jclass,
jfloat contrast, jfloat shoulder, jfloat midGrayIn, jfloat midGrayOut, jfloat hdrMax) {
return (jlong) new GenericToneMapper(contrast, shoulder, midGrayIn, midGrayOut, hdrMax);
jfloat contrast, jfloat midGrayIn, jfloat midGrayOut, jfloat hdrMax) {
return (jlong) new GenericToneMapper(contrast, midGrayIn, midGrayOut, hdrMax);
}
extern "C" JNIEXPORT jfloat JNICALL
@@ -58,11 +58,6 @@ Java_com_google_android_filament_ToneMapper_nGenericGetContrast(JNIEnv*, jclass,
return ((GenericToneMapper*) nativeObject)->getContrast();
}
extern "C" JNIEXPORT jfloat JNICALL
Java_com_google_android_filament_ToneMapper_nGenericGetShoulder(JNIEnv*, jclass, jlong nativeObject) {
return ((GenericToneMapper*) nativeObject)->getShoulder();
}
extern "C" JNIEXPORT jfloat JNICALL
Java_com_google_android_filament_ToneMapper_nGenericGetMidGrayIn(JNIEnv*, jclass, jlong nativeObject) {
return ((GenericToneMapper*) nativeObject)->getMidGrayIn();
@@ -84,12 +79,6 @@ Java_com_google_android_filament_ToneMapper_nGenericSetContrast(JNIEnv*, jclass,
((GenericToneMapper*) nativeObject)->setContrast(contrast);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_ToneMapper_nGenericSetShoulder(JNIEnv*, jclass,
jlong nativeObject, jfloat shoulder) {
((GenericToneMapper*) nativeObject)->setShoulder(shoulder);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_ToneMapper_nGenericSetMidGrayIn(JNIEnv*, jclass,
jlong nativeObject, jfloat midGrayIn) {
@@ -402,9 +402,6 @@ public class RenderableManager {
/**
* Controls if the renderable has vertex morphing targets, false by default.
*
* <p>This is required to enable GPU morphing for up to 4 attributes. The attached VertexBuffer
* must provide data in the appropriate VertexAttribute slots (<code>MORPH_POSITION_0</code> etc).</p>
*
* <p>See also {@link RenderableManager#setMorphWeights}, which can be called on a per-frame basis
* to advance the animation.</p>
*/
@@ -497,14 +494,11 @@ public class RenderableManager {
/**
* Updates the vertex morphing weights on a renderable, all zeroes by default.
*
* <p>This is specified using a 4-tuple, one float per morph target. If the renderable has fewer
* than 4 morph targets, then clients should fill the unused components with zeroes.</p>
*
* <p>The renderable must be built with morphing enabled.</p>
*
* @see Builder#morphing
*/
public void setMorphWeights(@EntityInstance int i, @NonNull @Size(min = 4) float[] weights) {
public void setMorphWeights(@EntityInstance int i, @NonNull float[] weights) {
nSetMorphWeights(mNativeObject, i, weights);
}
@@ -109,7 +109,6 @@ public class ToneMapper {
* The tone mapping curve is defined by 5 parameters:
* <ul>
* <li>contrast: controls the contrast of the curve</li>
* <li>shoulder: controls the shoulder of the curve, i.e. how quickly scene
* referred values map to output white</li>
* <li>midGrayIn: sets the input middle gray</li>
* <li>midGrayOut: sets the output middle gray</li>
@@ -123,15 +122,14 @@ public class ToneMapper {
* the {@link ACESLegacy} tone mapper. The default values are:
*
* <ul>
* <li>contrast = 1.585f</li>
* <li>shoulder = 0.5f</li>
* <li>contrast = 1.55f</li>
* <li>midGrayIn = 0.18f</li>
* <li>midGrayOut = 0.268f</li>
* <li>midGrayOut = 0.215f</li>
* <li>hdrMax = 10.0f</li>
* </ul>
*/
public Generic() {
this(1.585f, 0.5f, 0.18f, 0.268f, 10.0f);
this(1.55f, 0.18f, 0.215f, 10.0f);
}
/**
@@ -139,16 +137,14 @@ public class ToneMapper {
*
* @param contrast: controls the contrast of the curve, must be > 0.0, values
* in the range 0.5..2.0 are recommended.
* @param shoulder: controls the shoulder of the curve, i.e. how quickly scene
* referred values map to output white, between 0.0 and 1.0.
* @param midGrayIn: sets the input middle gray, between 0.0 and 1.0.
* @param midGrayOut: sets the output middle gray, between 0.0 and 1.0.
* @param hdrMax: defines the maximum input value that will be mapped to
* output white. Must be >= 1.0.
*/
public Generic(
float contrast, float shoulder, float midGrayIn, float midGrayOut, float hdrMax) {
super(nCreateGenericToneMapper(contrast, shoulder, midGrayIn, midGrayOut, hdrMax));
float contrast, float midGrayIn, float midGrayOut, float hdrMax) {
super(nCreateGenericToneMapper(contrast, midGrayIn, midGrayOut, hdrMax));
}
/** Returns the contrast of the curve as a strictly positive value. */
@@ -161,16 +157,6 @@ public class ToneMapper {
nGenericSetContrast(getNativeObject(), contrast);
}
/** Returns how fast scene referred values map to output white as a value between 0.0 and 1.0. */
public float getShoulder() {
return nGenericGetShoulder(getNativeObject());
}
/** Sets how quickly scene referred values map to output white, between 0.0 and 1.0. */
public void setShoulder(float shoulder) {
nGenericSetShoulder(getNativeObject(), shoulder);
}
/** Returns the middle gray point for input values as a value between 0.0 and 1.0. */
public float getMidGrayIn() {
return nGenericGetMidGrayIn(getNativeObject());
@@ -209,17 +195,15 @@ public class ToneMapper {
private static native long nCreateACESLegacyToneMapper();
private static native long nCreateFilmicToneMapper();
private static native long nCreateGenericToneMapper(
float contrast, float shoulder, float midGrayIn, float midGrayOut, float hdrMax);
float contrast, float midGrayIn, float midGrayOut, float hdrMax);
// Generic tone mappper
private static native float nGenericGetContrast(long nativeObject);
private static native float nGenericGetShoulder(long nativeObject);
private static native float nGenericGetMidGrayIn(long nativeObject);
private static native float nGenericGetMidGrayOut(long nativeObject);
private static native float nGenericGetHdrMax(long nativeObject);
private static native void nGenericSetContrast(long nativeObject, float contrast);
private static native void nGenericSetShoulder(long nativeObject, float shoulder);
private static native void nGenericSetMidGrayIn(long nativeObject, float midGrayIn);
private static native void nGenericSetMidGrayOut(long nativeObject, float midGrayOut);
private static native void nGenericSetHdrMax(long nativeObject, float hdrMax);
@@ -66,14 +66,14 @@ public class VertexBuffer {
BONE_INDICES, // indices of 4 bones (uvec4)
BONE_WEIGHTS, // weights of the 4 bones (normalized float4)
UNUSED, // reserved for future use
CUSTOM0, // custom or MORPH_POSITION_0
CUSTOM1, // custom or MORPH_POSITION_1
CUSTOM2, // custom or MORPH_POSITION_2
CUSTOM3, // custom or MORPH_POSITION_3
CUSTOM4, // custom or MORPH_TANGENTS_0
CUSTOM5, // custom or MORPH_TANGENTS_1
CUSTOM6, // custom or MORPH_TANGENTS_2
CUSTOM7 // custom or MORPH_TANGENTS_3
CUSTOM0, // custom
CUSTOM1, // custom
CUSTOM2, // custom
CUSTOM3, // custom
CUSTOM4, // custom
CUSTOM5, // custom
CUSTOM6, // custom
CUSTOM7 // custom
}
public enum AttributeType {
@@ -1337,21 +1337,26 @@ public class View {
*
* <p>Post-processing includes:</p>
* <ul>
* <li>Tone-mapping & gamma encoding</li>
* <li>Depth-of-field</li>
* <li>Bloom</li>
* <li>Vignetting</li>
* <li>Temporal Anti-aliasing (TAA)</li>
* <li>Color grading & gamma encoding</li>
* <li>Dithering</li>
* <li>MSAA</li>
* <li>FXAA</li>
* <li>Dynamic scaling</li>
* </ul>
*
* <p>
* Disabling post-processing forgoes color correctness as well as anti-aliasing and
* should only be used experimentally (e.g., for UI overlays).
* Disabling post-processing forgoes color correctness as well as some anti-aliasing techniques
* and should only be used for debugging, UI overlays or when using custom render targets
* (see RenderTarget).
* </p>
*
* @param enabled true enables post processing, false disables it
*
* @see #setToneMapping
* @see #setBloomOptions
* @see #setColorGrading
* @see #setAntiAliasing
* @see #setDithering
* @see #setSampleCount
@@ -58,7 +58,10 @@ private const val kSensitivity = 100f
*
* See `sample-gltf-viewer` for a usage example.
*/
class ModelViewer(val engine: Engine) : android.view.View.OnTouchListener {
class ModelViewer(
val engine: Engine,
private val uiHelper: UiHelper
) : android.view.View.OnTouchListener {
var asset: FilamentAsset? = null
private set
@@ -71,6 +74,7 @@ class ModelViewer(val engine: Engine) : android.view.View.OnTouchListener {
var normalizeSkinningWeights = true
var recomputeBoundingBoxes = false
var ignoreBindTransform = false
var cameraFocalLength = 28f
set(value) {
@@ -84,7 +88,6 @@ class ModelViewer(val engine: Engine) : android.view.View.OnTouchListener {
val renderer: Renderer
@Entity val light: Int
private val uiHelper: UiHelper = UiHelper(UiHelper.ContextErrorPolicy.DONT_CHECK)
private lateinit var displayHelper: DisplayHelper
private lateinit var cameraManipulator: Manipulator
private lateinit var gestureDetector: GestureDetector
@@ -111,7 +114,7 @@ class ModelViewer(val engine: Engine) : android.view.View.OnTouchListener {
view.camera = camera
assetLoader = AssetLoader(engine, UbershaderLoader(engine), EntityManager.get())
resourceLoader = ResourceLoader(engine, normalizeSkinningWeights, recomputeBoundingBoxes)
resourceLoader = ResourceLoader(engine, normalizeSkinningWeights, recomputeBoundingBoxes, ignoreBindTransform)
// Always add a direct light source since it is required for shadowing.
// We highly recommend adding an indirect light as well.
@@ -129,7 +132,12 @@ class ModelViewer(val engine: Engine) : android.view.View.OnTouchListener {
scene.addEntity(light)
}
constructor(surfaceView: SurfaceView, engine: Engine = Engine.create(), manipulator: Manipulator? = null) : this(engine) {
constructor(
surfaceView: SurfaceView,
engine: Engine = Engine.create(),
uiHelper: UiHelper = UiHelper(UiHelper.ContextErrorPolicy.DONT_CHECK),
manipulator: Manipulator? = null
) : this(engine, uiHelper) {
cameraManipulator = manipulator ?: Manipulator.Builder()
.targetPosition(kDefaultObjectPosition.x, kDefaultObjectPosition.y, kDefaultObjectPosition.z)
.viewport(surfaceView.width, surfaceView.height)
@@ -144,7 +152,12 @@ class ModelViewer(val engine: Engine) : android.view.View.OnTouchListener {
}
@Suppress("unused")
constructor(textureView: TextureView, engine: Engine = Engine.create(), manipulator: Manipulator? = null) : this(engine) {
constructor(
textureView: TextureView,
engine: Engine = Engine.create(),
uiHelper: UiHelper = UiHelper(UiHelper.ContextErrorPolicy.DONT_CHECK),
manipulator: Manipulator? = null
) : this(engine, uiHelper) {
cameraManipulator = manipulator ?: Manipulator.Builder()
.targetPosition(kDefaultObjectPosition.x, kDefaultObjectPosition.y, kDefaultObjectPosition.z)
.viewport(textureView.width, textureView.height)
@@ -215,8 +228,8 @@ class ModelViewer(val engine: Engine) : android.view.View.OnTouchListener {
fun transformToUnitCube(centerPoint: Float3 = kDefaultObjectPosition) {
asset?.let { asset ->
val tm = engine.transformManager
var center = asset.boundingBox.center.let { v-> Float3(v[0], v[1], v[2]) }
val halfExtent = asset.boundingBox.halfExtent.let { v-> Float3(v[0], v[1], v[2]) }
var center = asset.boundingBox.center.let { v -> Float3(v[0], v[1], v[2]) }
val halfExtent = asset.boundingBox.halfExtent.let { v -> Float3(v[0], v[1], v[2]) }
val maxExtent = 2.0f * max(halfExtent)
val scaleFactor = 2.0f / maxExtent
center -= centerPoint / scaleFactor
@@ -284,9 +297,9 @@ class ModelViewer(val engine: Engine) : android.view.View.OnTouchListener {
private fun populateScene(asset: FilamentAsset) {
val rcm = engine.renderableManager
var count = 0
val popRenderables = {count = asset.popRenderables(readyRenderables); count != 0}
val popRenderables = { count = asset.popRenderables(readyRenderables); count != 0 }
while (popRenderables()) {
for (i in 0..count-1) {
for (i in 0..count - 1) {
val ri = rcm.getInstance(readyRenderables[i])
rcm.setScreenSpaceContactShadows(ri, true)
}
@@ -383,4 +396,4 @@ class ModelViewer(val engine: Engine) : android.view.View.OnTouchListener {
companion object {
private val kDefaultObjectPosition = Float3(0.0f, 0.0f, -4.0f)
}
}
}
@@ -35,10 +35,11 @@ static void destroy(void*, size_t, void *userData) {
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_gltfio_ResourceLoader_nCreateResourceLoader(JNIEnv*, jclass,
jlong nativeEngine, jboolean normalizeSkinningWeights, jboolean recomputeBoundingBoxes) {
jlong nativeEngine, jboolean normalizeSkinningWeights, jboolean recomputeBoundingBoxes,
jboolean ignoreBindTransform) {
Engine* engine = (Engine*) nativeEngine;
return (jlong) new ResourceLoader({ engine, {}, (bool) normalizeSkinningWeights,
(bool) recomputeBoundingBoxes });
(bool) recomputeBoundingBoxes, (bool) ignoreBindTransform});
}
extern "C" JNIEXPORT void JNICALL
@@ -45,7 +45,7 @@ public class ResourceLoader {
*/
public ResourceLoader(@NonNull Engine engine) {
long nativeEngine = engine.getNativeObject();
mNativeObject = nCreateResourceLoader(nativeEngine, false, false);
mNativeObject = nCreateResourceLoader(nativeEngine, false, false, false);
}
/**
@@ -54,14 +54,15 @@ public class ResourceLoader {
* @param engine the engine that gets passed to all builder methods
* @param normalizeSkinningWeights scale non-conformant skinning weights so they sum to 1
* @param recomputeBoundingBoxes use computed bounding boxes rather than the ones in the asset
* @param ignoreBindTransform ignore skinned primitives bind transform when compute bounding boxes
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
public ResourceLoader(@NonNull Engine engine, boolean normalizeSkinningWeights,
boolean recomputeBoundingBoxes) {
boolean recomputeBoundingBoxes, boolean ignoreBindTransform) {
long nativeEngine = engine.getNativeObject();
mNativeObject = nCreateResourceLoader(nativeEngine, normalizeSkinningWeights,
recomputeBoundingBoxes);
recomputeBoundingBoxes, ignoreBindTransform);
}
/**
@@ -166,7 +167,7 @@ public class ResourceLoader {
}
private static native long nCreateResourceLoader(long nativeEngine,
boolean normalizeSkinningWeights, boolean recomputeBoundingBoxes);
boolean normalizeSkinningWeights, boolean recomputeBoundingBoxes, boolean ignoreBindTransform);
private static native void nDestroyResourceLoader(long nativeLoader);
private static native void nAddResourceData(long nativeLoader, String url, Buffer buffer,
int remaining);
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.16.1
VERSION_NAME=1.17.0
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -713,7 +713,8 @@ Filament.loadClassExtensions = function() {
const interval = asyncInterval || 30;
const defaults = {
normalizeSkinningWeights: true,
recomputeBoundingBoxes: false
recomputeBoundingBoxes: false,
ignoreBindTransform: false
};
config = Object.assign(defaults, config || {});
@@ -736,7 +737,8 @@ Filament.loadClassExtensions = function() {
// Construct a resource loader and start decoding after all textures are fetched.
const resourceLoader = new Filament.gltfio$ResourceLoader(engine,
config.normalizeSkinningWeights,
config.recomputeBoundingBoxes);
config.recomputeBoundingBoxes,
config.ignoreBindTransform);
const onComplete = () => {
resourceLoader.asyncBeginLoad(asset);
+3 -1
View File
@@ -307,6 +307,7 @@ class FilamentViewer extends LitElement {
const config = {
normalizeSkinningWeights: true,
recomputeBoundingBoxes: false,
ignoreBindTransform: false,
asyncInterval: 30
};
@@ -333,7 +334,8 @@ class FilamentViewer extends LitElement {
const resourceLoader = new Filament.gltfio$ResourceLoader(this.engine,
config.normalizeSkinningWeights,
config.recomputeBoundingBoxes);
config.recomputeBoundingBoxes,
config.ignoreBindTransform);
let remaining = Object.keys(this.srcBlobResources).length;
for (const name in this.srcBlobResources) {
+4 -2
View File
@@ -713,7 +713,8 @@ Filament.loadClassExtensions = function() {
const interval = asyncInterval || 30;
const defaults = {
normalizeSkinningWeights: true,
recomputeBoundingBoxes: false
recomputeBoundingBoxes: false,
ignoreBindTransform: false
};
config = Object.assign(defaults, config || {});
@@ -736,7 +737,8 @@ Filament.loadClassExtensions = function() {
// Construct a resource loader and start decoding after all textures are fetched.
const resourceLoader = new Filament.gltfio$ResourceLoader(engine,
config.normalizeSkinningWeights,
config.recomputeBoundingBoxes);
config.recomputeBoundingBoxes,
config.ignoreBindTransform);
const onComplete = () => {
resourceLoader.asyncBeginLoad(asset);
-8
View File
@@ -1438,14 +1438,6 @@ This defines the following functions:</p>
<li>CUSTOM5</li>
<li>CUSTOM6</li>
<li>CUSTOM7</li>
<li>MORPH_POSITION_0</li>
<li>MORPH_POSITION_1</li>
<li>MORPH_POSITION_2</li>
<li>MORPH_POSITION_3</li>
<li>MORPH_TANGENTS_0</li>
<li>MORPH_TANGENTS_1</li>
<li>MORPH_TANGENTS_2</li>
<li>MORPH_TANGENTS_3</li>
</ul>
</div>
<div class='enumdoc'>
+3
View File
@@ -28,6 +28,7 @@ set(PUBLIC_HDRS
include/filament/LightManager.h
include/filament/Material.h
include/filament/MaterialInstance.h
include/filament/MorphTargetBuffer.h
include/filament/Options.h
include/filament/RenderTarget.h
include/filament/RenderableManager.h
@@ -69,6 +70,7 @@ set(SRCS
src/Material.cpp
src/MaterialInstance.cpp
src/MaterialParser.cpp
src/MorphTargetBuffer.cpp
src/PerViewUniforms.cpp
src/PostProcessManager.cpp
src/RenderPass.cpp
@@ -140,6 +142,7 @@ set(PRIVATE_HDRS
src/details/IndirectLight.h
src/details/Material.h
src/details/MaterialInstance.h
src/details/MorphTargetBuffer.h
src/details/RenderTarget.h
src/details/Renderer.h
src/details/Scene.h
@@ -809,10 +809,10 @@ using AttributeArray = std::array<Attribute, MAX_VERTEX_ATTRIBUTE_COUNT>;
//! Raster state descriptor
struct RasterState {
using CullingMode = CullingMode;
using DepthFunc = SamplerCompareFunc;
using BlendEquation = BlendEquation;
using BlendFunction = BlendFunction;
using CullingMode = backend::CullingMode;
using DepthFunc = backend::SamplerCompareFunc;
using BlendEquation = backend::BlendEquation;
using BlendFunction = backend::BlendFunction;
RasterState() noexcept { // NOLINT
static_assert(sizeof(RasterState) == sizeof(uint32_t),
@@ -95,33 +95,25 @@ void ExternalTextureManagerAndroid::destroy(ExternalTextureManagerAndroid* pExte
// called on gl thread
ExternalTextureManagerAndroid::ExternalTextureManagerAndroid() noexcept
: mVm(VirtualMachineEnv::get()) {
// if we compile for API 26 (Oreo) and above, we're guaranteed to have AHardwareBuffer
// in all other cases, we need to get them at runtime.
#ifndef PLATFORM_HAS_HARDWAREBUFFER
// the following dlsym() calls don't work on API 19
if (api_level() >= 21) {
loadSymbol(AHardwareBuffer_allocate, "AHardwareBuffer_allocate");
loadSymbol(AHardwareBuffer_release, "AHardwareBuffer_release");
}
#endif
}
// not quite sure on which thread this is going to be called
ExternalTextureManagerAndroid::~ExternalTextureManagerAndroid() noexcept {
#ifndef PLATFORM_HAS_HARDWAREBUFFER
if (mGraphicBufferClass) {
JNIEnv* env = VirtualMachineEnv::getThreadEnvironment();
if (env) {
env->DeleteGlobalRef(mGraphicBufferClass);
if (__builtin_available(android 26, *)) {
} else {
if (mGraphicBufferClass) {
JNIEnv* env = VirtualMachineEnv::getThreadEnvironment();
if (env) {
env->DeleteGlobalRef(mGraphicBufferClass);
}
}
}
#endif
}
// called on gl thread
backend::Platform::ExternalTexture* ExternalTextureManagerAndroid::createExternalTexture() noexcept {
#ifndef PLATFORM_HAS_HARDWAREBUFFER
if (!AHardwareBuffer_allocate) {
if (__builtin_available(android 26, *)) {
} else {
// initialize java stuff on-demand
if (!mGraphicBufferClass) {
JNIEnv* env = mVm.getEnvironment();
@@ -134,7 +126,6 @@ backend::Platform::ExternalTexture* ExternalTextureManagerAndroid::createExterna
mGraphicBufferClass = static_cast<jclass>(env->NewGlobalRef(mGraphicBufferClass));
}
}
#endif
EGLExternalTexture* ets = new EGLExternalTexture;
return ets;
}
@@ -181,9 +172,7 @@ void ExternalTextureManagerAndroid::alloc(
return;
}
#ifndef PLATFORM_HAS_HARDWAREBUFFER
if (AHardwareBuffer_allocate) {
#endif
if (__builtin_available(android 26, *)) {
// allocate new storage...
AHardwareBuffer* buffer = nullptr;
if (AHardwareBuffer_allocate(&desc, &buffer) < 0) {
@@ -191,7 +180,6 @@ void ExternalTextureManagerAndroid::alloc(
return;
}
ets->hardwareBuffer = buffer;
#ifndef PLATFORM_HAS_HARDWAREBUFFER
} else {
// note: This is called on the application thread (not the GL thread)
JNIEnv* env = VirtualMachineEnv::getThreadEnvironment();
@@ -209,23 +197,17 @@ void ExternalTextureManagerAndroid::alloc(
ets->clientBuffer = static_cast<ANativeWindowBuffer*>(gb);
}
}
#endif
}
// called on gl thread
void ExternalTextureManagerAndroid::destroyStorage(backend::Platform::ExternalTexture* t) noexcept {
EGLExternalTexture* ets = static_cast<EGLExternalTexture*>(t);
#ifndef PLATFORM_HAS_HARDWAREBUFFER
if (AHardwareBuffer_allocate) {
#endif
if (__builtin_available(android 26, *)) {
// destroy the current storage if any
if (ets->hardwareBuffer) {
AHardwareBuffer_release(ets->hardwareBuffer);
ets->hardwareBuffer = nullptr;
}
#ifndef PLATFORM_HAS_HARDWAREBUFFER
} else {
if (ets->graphicBufferWrapper) {
JNIEnv* env = VirtualMachineEnv::get().getEnvironment();
@@ -235,7 +217,6 @@ void ExternalTextureManagerAndroid::destroyStorage(backend::Platform::ExternalTe
ets->graphicBufferWrapper = nullptr;
}
}
#endif
}
} // namespace filament
@@ -25,10 +25,6 @@
#include <android/api-level.h>
#include <android/hardware_buffer.h>
#if __ANDROID_API__ >= 26
# define PLATFORM_HAS_HARDWAREBUFFER
#endif
namespace filament {
/*
@@ -78,16 +74,9 @@ private:
VirtualMachineEnv& mVm;
#ifndef PLATFORM_HAS_HARDWAREBUFFER
// if we compile for API 26 (Oreo) and above, we're guaranteed to have AHardwareBuffer
// in all other cases, we need to get them at runtime.
int (*AHardwareBuffer_allocate)(const AHardwareBuffer_Desc*, AHardwareBuffer**) = nullptr;
void (*AHardwareBuffer_release)(AHardwareBuffer*) = nullptr;
jclass mGraphicBufferClass = nullptr;
jmethodID mGraphicBuffer_nCreateGraphicBuffer = nullptr;
jmethodID mGraphicBuffer_nDestroyGraphicBuffer = nullptr;
#endif
};
@@ -272,6 +272,9 @@ void OpenGLProgram::updateSamplers(OpenGLDriver* gld) noexcept {
for (uint8_t i = 0, tmu = 0, n = mUsedBindingsCount; i < n; i++) {
BlockInfo blockInfo = blockInfos[i];
HwSamplerGroup const * const UTILS_RESTRICT hwsb = samplerBindings[blockInfo.binding];
if (UTILS_UNLIKELY(!hwsb)) {
continue;
}
SamplerGroup const& UTILS_RESTRICT sb = *(hwsb->sb);
SamplerGroup::Sampler const* const UTILS_RESTRICT samplers = sb.getSamplers();
for (uint8_t j = 0, m = blockInfo.count ; j <= m; ++j, ++tmu) { // "<=" on purpose here
@@ -47,18 +47,7 @@ void ExternalStreamManagerAndroid::destroy(ExternalStreamManagerAndroid* pExtern
ExternalStreamManagerAndroid::ExternalStreamManagerAndroid() noexcept
: mVm(VirtualMachineEnv::get()) {
// the following dlsym() calls don't work on API 19
if (api_level() >= 21) {
loadSymbol(ASurfaceTexture_fromSurfaceTexture, "ASurfaceTexture_fromSurfaceTexture");
loadSymbol(ASurfaceTexture_release, "ASurfaceTexture_release");
loadSymbol(ASurfaceTexture_attachToGLContext, "ASurfaceTexture_attachToGLContext");
loadSymbol(ASurfaceTexture_detachFromGLContext, "ASurfaceTexture_detachFromGLContext");
loadSymbol(ASurfaceTexture_updateTexImage, "ASurfaceTexture_updateTexImage");
loadSymbol(ASurfaceTexture_getTimestamp, "ASurfaceTexture_getTimestamp");
}
if (ASurfaceTexture_fromSurfaceTexture) {
if (__builtin_available(android 28, *)) {
slog.d << "Using ASurfaceTexture" << io::endl;
}
}
@@ -95,7 +84,7 @@ Stream* ExternalStreamManagerAndroid::acquire(jobject surfaceTexture) noexcept {
}
EGLStream* stream = new EGLStream();
stream->jSurfaceTexture = env->NewGlobalRef(surfaceTexture);
if (ASurfaceTexture_fromSurfaceTexture) {
if (__builtin_available(android 28, *)) {
stream->nSurfaceTexture = ASurfaceTexture_fromSurfaceTexture(env, surfaceTexture);
}
return stream;
@@ -103,7 +92,7 @@ Stream* ExternalStreamManagerAndroid::acquire(jobject surfaceTexture) noexcept {
void ExternalStreamManagerAndroid::release(Stream* handle) noexcept {
EGLStream* stream = static_cast<EGLStream*>(handle);
if (ASurfaceTexture_fromSurfaceTexture) {
if (__builtin_available(android 28, *)) {
ASurfaceTexture_release(stream->nSurfaceTexture);
}
JNIEnv* const env = getEnvironment();
@@ -114,7 +103,7 @@ void ExternalStreamManagerAndroid::release(Stream* handle) noexcept {
void ExternalStreamManagerAndroid::attach(Stream* handle, intptr_t tname) noexcept {
EGLStream* stream = static_cast<EGLStream*>(handle);
if (ASurfaceTexture_fromSurfaceTexture) {
if (__builtin_available(android 28, *)) {
// associate our GL texture to the SurfaceTexture
ASurfaceTexture* const aSurfaceTexture = stream->nSurfaceTexture;
if (UTILS_UNLIKELY(ASurfaceTexture_attachToGLContext(aSurfaceTexture, (uint32_t)tname))) {
@@ -152,7 +141,7 @@ void ExternalStreamManagerAndroid::attach(Stream* handle, intptr_t tname) noexce
void ExternalStreamManagerAndroid::detach(Stream* handle) noexcept {
EGLStream* stream = static_cast<EGLStream*>(handle);
if (ASurfaceTexture_fromSurfaceTexture) {
if (__builtin_available(android 28, *)) {
ASurfaceTexture_detachFromGLContext(stream->nSurfaceTexture);
} else {
JNIEnv* const env = mVm.getEnvironment();
@@ -164,14 +153,9 @@ void ExternalStreamManagerAndroid::detach(Stream* handle) noexcept {
void ExternalStreamManagerAndroid::updateTexImage(Stream* handle, int64_t* timestamp) noexcept {
EGLStream* stream = static_cast<EGLStream*>(handle);
if (ASurfaceTexture_fromSurfaceTexture) {
if (__builtin_available(android 28, *)) {
ASurfaceTexture_updateTexImage(stream->nSurfaceTexture);
if (ASurfaceTexture_getTimestamp) {
*timestamp = ASurfaceTexture_getTimestamp(stream->nSurfaceTexture);
} else {
// if we're not at least on API 28, we may not have getTimestamp()
*timestamp = (std::chrono::steady_clock::now().time_since_epoch().count());
}
*timestamp = ASurfaceTexture_getTimestamp(stream->nSurfaceTexture);
} else {
JNIEnv* const env = mVm.getEnvironment();
assert_invariant(env); // we should have called attach() by now
@@ -84,13 +84,6 @@ private:
jmethodID mSurfaceTextureClass_getTimestamp{};
jmethodID mSurfaceTextureClass_attachToGLContext{};
jmethodID mSurfaceTextureClass_detachFromGLContext{};
ASurfaceTexture* (*ASurfaceTexture_fromSurfaceTexture)(JNIEnv*, jobject){};
void (*ASurfaceTexture_release)(ASurfaceTexture*){};
int (*ASurfaceTexture_attachToGLContext)(ASurfaceTexture*, uint32_t){};
int (*ASurfaceTexture_detachFromGLContext)(ASurfaceTexture*){};
int (*ASurfaceTexture_updateTexImage)(ASurfaceTexture*){};
int64_t (*ASurfaceTexture_getTimestamp)(ASurfaceTexture*){}; // available since api 28
};
} // namespace filament
+2
View File
@@ -39,6 +39,7 @@ class SkinningBuffer;
class IndirectLight;
class Material;
class MaterialInstance;
class MorphTargetBuffer;
class Renderer;
class RenderTarget;
class Scene;
@@ -421,6 +422,7 @@ public:
bool destroy(const Fence* p); //!< Destroys a Fence object.
bool destroy(const IndexBuffer* p); //!< Destroys an IndexBuffer object.
bool destroy(const SkinningBuffer* p); //!< Destroys a SkinningBuffer object.
bool destroy(const MorphTargetBuffer* p); //!< Destroys a MorphTargetBuffer object.
bool destroy(const IndirectLight* p); //!< Destroys an IndirectLight object.
/**
+4 -1
View File
@@ -193,9 +193,12 @@ public:
//! Returns the refraction mode used by this material.
RefractionMode getRefractionMode() const noexcept;
// Return the refraction type used by this material.
//! Return the refraction type used by this material.
RefractionType getRefractionType() const noexcept;
//! Returns the reflection mode used by this material.
ReflectionMode getReflectionMode() const noexcept;
/**
* Returns the number of parameters declared by this material.
* The returned value can be 0.
@@ -0,0 +1,119 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_FILAMENT_MORPHTARGETBUFFER_H
#define TNT_FILAMENT_MORPHTARGETBUFFER_H
#include <filament/FilamentAPI.h>
#include <filament/Engine.h>
#include <math/mathfwd.h>
namespace filament {
/**
* MorphTargetBuffer is used to hold morphing data (positions and tangents).
*/
class UTILS_PUBLIC MorphTargetBuffer : public FilamentAPI {
struct BuilderDetails;
public:
class Builder : public BuilderBase<BuilderDetails> {
friend struct BuilderDetails;
public:
Builder() noexcept;
Builder(Builder const& rhs) noexcept;
Builder(Builder&& rhs) noexcept;
~Builder() noexcept;
Builder& operator=(Builder const& rhs) noexcept;
Builder& operator=(Builder&& rhs) noexcept;
/**
* Size of the morph targets in vertex counts.
* @param vertexCount Number of vertex counts the morph targets can hold.
* @return A reference to this Builder for chaining calls.
*/
Builder& vertexCount(size_t vertexCount) noexcept;
/**
* Size of the morph targets in targets.
* @param count Number of targets the morph targets can hold.
* @return A reference to this Builder for chaining calls.
*/
Builder& count(size_t count) noexcept;
/**
* Creates the MorphTargetBuffer object and returns a pointer to it.
*
* @param engine Reference to the filament::Engine to associate this MorphTargetBuffer with.
*
* @return pointer to the newly created object or nullptr if exceptions are disabled and
* an error occurred.
*
* @exception utils::PostConditionPanic if a runtime error occurred, such as running out of
* memory or other resources.
* @exception utils::PreConditionPanic if a parameter to a builder function was invalid.
*/
MorphTargetBuffer* build(Engine& engine);
private:
friend class FMorphTargetBuffer;
};
/**
* Updates the position of morph target at the index.
* @param engine Reference to the filament::Engine associated with this MorphTargetBuffer.
* @param targetIndex the index of morph target to be updated.
* @param weights pointer to at least count positions
* @param count number of position elements in positions
*/
void setPositionsAt(Engine& engine, size_t targetIndex, math::float3 const* positions, size_t count);
/**
* Updates the position of morph target at the index.
* @param engine Reference to the filament::Engine associated with this MorphTargetBuffer.
* @param targetIndex the index of morph target to be updated.
* @param weights pointer to at least count positions
* @param count number of position elements in positions
*/
void setPositionsAt(Engine& engine, size_t targetIndex, math::float4 const* positions, size_t count);
/**
* Updates the position of morph target at the index.
* @param engine Reference to the filament::Engine associated with this MorphTargetBuffer.
* @param targetIndex the index of morph target to be updated.
* @param tangents pointer to at least count tangents
* @param count number of tangent elements in tangents
*/
void setTangentsAt(Engine& engine, size_t targetIndex, math::short4 const* tangents, size_t count);
/**
* Returns the vertex count of this MorphTargetBuffer.
* @return The number of vertices the MorphTargetBuffer holds.
*/
size_t getVertexCount() const noexcept;
/**
* Returns the target count of this MorphTargetBuffer.
* @return The number of targets the MorphTargetBuffer holds.
*/
size_t getCount() const noexcept;
};
} // namespace filament
#endif //TNT_FILAMENT_MORPHTARGETBUFFER_H
+12
View File
@@ -316,6 +316,18 @@ struct TemporalAntiAliasingOptions {
bool enabled = false; //!< enables or disables temporal anti-aliasing
};
/**
* Options for Screen-space Reflections.
* @see setScreenSpaceReflectionsOptions()
*/
struct ScreenSpaceReflectionsOptions {
float thickness = 0.5f; //!< ray thickness, in world units
float bias = 0.01f; //!< bias, in world units, to prevent self-intersections
float maxDistance = 3.0f; //!< maximum distance, in world units, to raycast
float stride = 1.0f; //!< stride, in texels, for samples along the ray.
bool enabled = false;
};
/**
* List of available post-processing anti-aliasing techniques.
* @see setAntiAliasing, getAntiAliasing, setSampleCount
+14
View File
@@ -37,6 +37,12 @@ class Texture;
* An offscreen render target that can be associated with a View and contains
* weak references to a set of attached Texture objects.
*
* RenderTarget is intended to be used with the View's post-processing disabled for the most part.
* especially when a DEPTH attachment is also used (see Builder::texture()).
*
* Custom RenderTarget are ultimately intended to render into textures that might be used during
* the main render pass.
*
* Clients are responsible for the lifetime of all associated Texture attachments.
*
* @see View
@@ -87,6 +93,14 @@ public:
*
* All RenderTargets must have a non-null COLOR attachment.
*
* When using a DEPTH attachment, it is important to always disable post-processing
* in the View. Failing to do so will cause the DEPTH attachment to be ignored in most
* cases.
*
* When the intention is to keep the content of the DEPTH attachment after rendering,
* Usage::SAMPLEABLE must be set on the DEPTH attachment, otherwise the content of the
* DEPTH buffer may be discarded.
*
* @param attachment The attachment point of the texture.
* @param texture The associated texture object.
* @return A reference to this Builder for chaining calls.
+10 -7
View File
@@ -41,9 +41,11 @@ class Engine;
class IndexBuffer;
class Material;
class MaterialInstance;
class MorphTargetBuffer;
class Renderer;
class SkinningBuffer;
class VertexBuffer;
class Texture;
class FEngine;
class FRenderPrimitive;
@@ -300,9 +302,6 @@ public:
/**
* Controls if the renderable has vertex morphing targets, false by default.
*
* This is required to enable GPU morphing for up to 4 attributes. The attached VertexBuffer
* must provide data in the appropriate VertexAttribute slots (\c MORPH_POSITION_0 etc).
*
* See also RenderableManager::setMorphWeights(), which can be called on a per-frame basis
* to advance the animation.
*/
@@ -456,12 +455,16 @@ public:
/**
* Updates the vertex morphing weights on a renderable, all zeroes by default.
*
* This is specified using a 4-tuple, one float per morph target. If the renderable has fewer
* than 4 morph targets, then clients should fill the unused components with zeroes.
*
* The renderable must be built with morphing enabled, see Builder::morphing().
*/
void setMorphWeights(Instance instance, math::float4 const& weights) noexcept;
void setMorphWeights(Instance instance, float const* weights, size_t count) noexcept;
/**
* Associates a MorphTargetBuffer to the given primitive.
*/
void setMorphTargetBufferAt(Instance instance,
size_t primitiveIndex, MorphTargetBuffer* morphTargetBuffer) noexcept;
/**
* Gets the bounding box used for frustum culling.
+2 -10
View File
@@ -123,8 +123,6 @@ struct UTILS_PUBLIC FilmicToneMapper final : public ToneMapper {
*
* The tone mapping curve is defined by 5 parameters:
* - contrast: controls the contrast of the curve
* - shoulder: controls the shoulder of the curve, i.e. how quickly scene
* referred values map to output white
* - midGrayIn: sets the input middle gray
* - midGrayOut: sets the output middle gray
* - hdrMax: defines the maximum input value that will be mapped to
@@ -138,18 +136,15 @@ struct UTILS_PUBLIC GenericToneMapper final : public ToneMapper {
*
* @param contrast: controls the contrast of the curve, must be > 0.0, values
* in the range 0.5..2.0 are recommended.
* @param shoulder: controls the shoulder of the curve, i.e. how quickly scene
* referred values map to output white, between 0.0 and 1.0.
* @param midGrayIn: sets the input middle gray, between 0.0 and 1.0.
* @param midGrayOut: sets the output middle gray, between 0.0 and 1.0.
* @param hdrMax: defines the maximum input value that will be mapped to
* output white. Must be >= 1.0.
*/
explicit GenericToneMapper(
float contrast = 1.585f,
float shoulder = 0.5f,
float contrast = 1.55f,
float midGrayIn = 0.18f,
float midGrayOut = 0.268f,
float midGrayOut = 0.215f,
float hdrMax = 10.0f
) noexcept;
~GenericToneMapper() noexcept final;
@@ -179,9 +174,6 @@ struct UTILS_PUBLIC GenericToneMapper final : public ToneMapper {
/** Sets the contrast of the curve, must be > 0.0, values in the range 0.5..2.0 are recommended. */
void setContrast(float contrast) noexcept;
/** Sets how quickly scene referred values map to output white, between 0.0 and 1.0. */
void setShoulder(float shoulder) noexcept;
/** Sets the input middle gray, between 0.0 and 1.0. */
void setMidGrayIn(float midGrayIn) noexcept;
+22 -4
View File
@@ -83,6 +83,7 @@ public:
using MultiSampleAntiAliasingOptions = MultiSampleAntiAliasingOptions;
using VsmShadowOptions = VsmShadowOptions;
using SoftShadowOptions = SoftShadowOptions;
using ScreenSpaceReflectionsOptions = ScreenSpaceReflectionsOptions;
/**
* Sets the View's name. Only useful for debugging.
@@ -330,6 +331,20 @@ public:
*/
TemporalAntiAliasingOptions const& getTemporalAntiAliasingOptions() const noexcept;
/**
* Enables or disable screen-space reflections. Disabled by default.
*
* @param options screen-space reflections options
*/
void setScreenSpaceReflectionsOptions(ScreenSpaceReflectionsOptions options) noexcept;
/**
* Returns screen-space reflections options.
*
* @return screen-space reflections options
*/
ScreenSpaceReflectionsOptions const& getScreenSpaceReflectionsOptions() const noexcept;
/**
* Enables or disable multi-sample anti-aliasing (MSAA). Disabled by default.
*
@@ -564,15 +579,18 @@ public:
* Enables or disables post processing. Enabled by default.
*
* Post-processing includes:
* - Depth-of-field
* - Bloom
* - Tone-mapping & gamma encoding
* - Vignetting
* - Temporal Anti-aliasing (TAA)
* - Color grading & gamma encoding
* - Dithering
* - MSAA
* - FXAA
* - Dynamic scaling
*
* Disabling post-processing forgoes color correctness as well as anti-aliasing and
* should only be used experimentally (e.g., for UI overlays).
* Disabling post-processing forgoes color correctness as well as some anti-aliasing techniques
* and should only be used for debugging, UI overlays or when using custom render targets
* (see RenderTarget).
*
* @param enabled true enables post processing, false disables it.
*
+2 -2
View File
@@ -22,11 +22,11 @@
#include "private/backend/BackendUtils.h"
#ifndef FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB
# define FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB 2
# define FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB 3
#endif
#ifndef FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB
# define FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB 1
# define FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB 2
#endif
namespace filament {
+5 -5
View File
@@ -400,7 +400,7 @@ constexpr mat3f adaptationTransform(float2 whiteBalance) noexcept {
float y = chromaticityCoordinateIlluminantD(x) + t * 0.066f;
float3 lms = XYZ_to_CIECAT16 * xyY_to_XYZ({x, y, 1.0f});
return LMS_CAT16_to_REC2020 * mat3f{ILLUMINANT_D65_LMS_CAT16 / lms} * REC2020_to_LMS_CAT16;
return LMS_CAT16_to_Rec2020 * mat3f{ILLUMINANT_D65_LMS_CAT16 / lms} * Rec2020_to_LMS_CAT16;
}
UTILS_ALWAYS_INLINE
@@ -575,21 +575,21 @@ static mat3f selectColorGradingTransformIn(ColorGrading::ToneMapping toneMapping
if (toneMapping == ColorGrading::ToneMapping::FILMIC) {
return mat3f{};
}
return sRGB_to_REC2020;
return sRGB_to_Rec2020;
}
static mat3f selectColorGradingTransformOut(ColorGrading::ToneMapping toneMapping) noexcept {
if (toneMapping == ColorGrading::ToneMapping::FILMIC) {
return mat3f{};
}
return REC2020_to_sRGB;
return Rec2020_to_sRGB;
}
static float3 selectColorGradingLuminance(ColorGrading::ToneMapping toneMapping) noexcept {
if (toneMapping == ColorGrading::ToneMapping::FILMIC) {
return LUMINANCE_REC709;
return LUMINANCE_Rec709;
}
return LUMINANCE_REC2020;
return LUMINANCE_Rec2020;
}
#pragma clang diagnostic pop
+41 -17
View File
@@ -52,13 +52,13 @@ constexpr mat3f sRGB_to_XYZ{
0.1804380f, 0.0721750f, 0.9503040f
};
constexpr mat3f REC2020_to_XYZ{
constexpr mat3f Rec2020_to_XYZ{
0.6369530f, 0.2626983f, 0.0000000f,
0.1446169f, 0.6780088f, 0.0280731f,
0.1688558f, 0.0592929f, 1.0608272f
};
constexpr mat3f XYZ_to_REC2020{
constexpr mat3f XYZ_to_Rec2020{
1.7166634f, -0.6666738f, 0.0176425f,
-0.3556733f, 1.6164557f, -0.0427770f,
-0.2533681f, 0.0157683f, 0.9422433f
@@ -130,6 +130,18 @@ constexpr mat3f sRGB_to_OkLab_LMS{
0.0514459929f, 0.1073969566f, 0.6299787005f
};
constexpr mat3f XYZ_to_OkLab_LMS{
0.8189330101f, 0.3618667424f, -0.1288597137f,
0.0329845436f, 0.9293118715f, 0.0361456387f,
0.0482003018f, 0.2643662691f, 0.6338517070f
};
constexpr mat3f OkLab_LMS_to_XYZ{
1.227014f, -0.557800f, 0.281256f,
-0.040580f, 1.112257f, -0.071677f,
-0.076381f, -0.421482f, 1.586163f
};
constexpr mat3f OkLab_LMS_to_OkLab{
0.2104542553f, 1.9779984951f, 0.0259040371f,
0.7936177850f, -2.4285922050f, 0.7827717662f,
@@ -148,21 +160,25 @@ constexpr mat3f OkLab_LMS_to_sRGB{
0.2309699292f, -0.3413193965f, 1.7076147010f
};
constexpr mat3f sRGB_to_REC2020 = XYZ_to_REC2020 * sRGB_to_XYZ;
constexpr mat3f sRGB_to_Rec2020 = XYZ_to_Rec2020 * sRGB_to_XYZ;
constexpr mat3f REC2020_to_sRGB = XYZ_to_sRGB * REC2020_to_XYZ;
constexpr mat3f Rec2020_to_sRGB = XYZ_to_sRGB * Rec2020_to_XYZ;
constexpr mat3f sRGB_to_LMS_CAT16 = XYZ_to_CIECAT16 * sRGB_to_XYZ;
constexpr mat3f LMS_CAT16_to_sRGB = XYZ_to_sRGB * CIECAT16_to_XYZ;
constexpr mat3f REC2020_to_LMS_CAT16 = XYZ_to_CIECAT16 * REC2020_to_XYZ;
constexpr mat3f Rec2020_to_LMS_CAT16 = XYZ_to_CIECAT16 * Rec2020_to_XYZ;
constexpr mat3f LMS_CAT16_to_REC2020 = XYZ_to_REC2020 * CIECAT16_to_XYZ;
constexpr mat3f LMS_CAT16_to_Rec2020 = XYZ_to_Rec2020 * CIECAT16_to_XYZ;
constexpr mat3f REC2020_to_AP0 = AP1_to_AP0 * XYZ_to_AP1 * REC2020_to_XYZ;
constexpr mat3f Rec2020_to_AP0 = AP1_to_AP0 * XYZ_to_AP1 * Rec2020_to_XYZ;
constexpr mat3f AP1_to_REC2020 = XYZ_to_REC2020 * AP1_to_XYZ;
constexpr mat3f AP1_to_Rec2020 = XYZ_to_Rec2020 * AP1_to_XYZ;
constexpr mat3f Rec2020_to_OkLab_LMS = XYZ_to_OkLab_LMS * Rec2020_to_XYZ;
constexpr mat3f OkLab_LMS_to_Rec2020 = XYZ_to_Rec2020 * OkLab_LMS_to_XYZ;
//------------------------------------------------------------------------------
// Constants
@@ -175,17 +191,17 @@ constexpr float3 ILLUMINANT_D65_xyY{0.31271f, 0.32902f, 1.0f};
// Result of: XYZ_to_CIECAT16 * xyY_to_XYZ(ILLUMINANT_D65_xyY);
constexpr float3 ILLUMINANT_D65_LMS_CAT16{0.975533f, 1.016483f, 1.084837f};
// RGB to luminance coefficients for Rec.2020, from REC2020_to_XYZ
constexpr float3 LUMINANCE_REC2020{0.2627002f, 0.6779981f, 0.0593017f};
// RGB to luminance coefficients for Rec.2020, from Rec2020_to_XYZ
constexpr float3 LUMINANCE_Rec2020{0.2627002f, 0.6779981f, 0.0593017f};
// RGB to luminance coefficients for ACEScg (AP1), from AP1_to_XYZ
constexpr float3 LUMINANCE_AP1{0.272229f, 0.674082f, 0.0536895f};
// RGB to luminance coefficients for Rec.709, from sRGB_to_XYZ
constexpr float3 LUMINANCE_REC709{0.2126730f, 0.7151520f, 0.0721750f};
constexpr float3 LUMINANCE_Rec709{0.2126730f, 0.7151520f, 0.0721750f};
// RGB to luminance coefficients for Rec.709 with HK-like weighting
constexpr float3 LUMINANCE_HK_REC709{0.13913043f, 0.73043478f, 0.13043478f};
constexpr float3 LUMINANCE_HK_Rec709{0.13913043f, 0.73043478f, 0.13043478f};
constexpr float MIDDLE_GRAY_ACEScg = 0.18f;
@@ -212,21 +228,29 @@ inline constexpr XYZ xyY_to_XYZ(xyY v) noexcept {
}
inline constexpr xyY XYZ_to_xyY(XYZ v) noexcept {
return float3(v.xy / max(v.x + v.y + v.z, 1e-5f), v.y);
}
inline float3 sRGB_to_OkLab(float3 x) noexcept {
return OkLab_LMS_to_OkLab * cbrt(sRGB_to_OkLab_LMS * x);
return {v.xy / max(v.x + v.y + v.z, 1e-5f), v.y};
}
inline constexpr float3 pow3(float3 x) noexcept {
return x * x * x;
}
inline float3 sRGB_to_OkLab(float3 x) noexcept {
return OkLab_LMS_to_OkLab * cbrt(sRGB_to_OkLab_LMS * x);
}
inline float3 Rec2020_to_OkLab(float3 x) noexcept {
return OkLab_LMS_to_OkLab * cbrt(Rec2020_to_OkLab_LMS * x);
}
inline float3 OkLab_to_sRGB(float3 x) noexcept {
return OkLab_LMS_to_sRGB * pow3(OkLab_to_OkLab_LMS * x);
}
inline float3 OkLab_to_Rec2020(float3 x) noexcept {
return OkLab_LMS_to_Rec2020 * pow3(OkLab_to_OkLab_LMS * x);
}
//------------------------------------------------------------------------------
// Conversion functions and encoding/decoding
//------------------------------------------------------------------------------
+13
View File
@@ -333,6 +333,7 @@ void FEngine::shutdown() {
cleanupResourceList(mBufferObjects);
cleanupResourceList(mIndexBuffers);
cleanupResourceList(mMorphTargetBuffers);
cleanupResourceList(mSkinningBuffers);
cleanupResourceList(mVertexBuffers);
cleanupResourceList(mTextures);
@@ -567,6 +568,10 @@ FSkinningBuffer* FEngine::createSkinningBuffer(const SkinningBuffer::Builder& bu
return create(mSkinningBuffers, builder);
}
FMorphTargetBuffer* FEngine::createMorphTargetBuffer(const MorphTargetBuffer::Builder& builder) noexcept {
return create(mMorphTargetBuffers, builder);
}
FTexture* FEngine::createTexture(const Texture::Builder& builder) noexcept {
return create(mTextures, builder);
}
@@ -753,6 +758,10 @@ bool FEngine::destroy(const FSkinningBuffer* p) {
return terminateAndDestroy(p, mSkinningBuffers);
}
bool FEngine::destroy(const FMorphTargetBuffer* p) {
return terminateAndDestroy(p, mMorphTargetBuffers);
}
inline bool FEngine::destroy(const FRenderer* p) {
return terminateAndDestroy(p, mRenderers);
}
@@ -966,6 +975,10 @@ bool Engine::destroy(const SkinningBuffer* p) {
return upcast(this)->destroy(upcast(p));
}
bool Engine::destroy(const MorphTargetBuffer* p) {
return upcast(this)->destroy(upcast(p));
}
bool Engine::destroy(const IndirectLight* p) {
return upcast(this)->destroy(upcast(p));
}
+5 -1
View File
@@ -28,7 +28,7 @@ namespace filament {
struct FrameHistoryEntry {
FrameGraphTexture color;
FrameGraphTexture::Descriptor colorDesc;
math::mat4f projection;
math::mat4f projection; // world space to clip space
math::float2 jitter{};
uint32_t frameId = 0;
@@ -60,6 +60,10 @@ public:
return mCurrentEntry;
}
const T& getCurrent() const noexcept {
return mCurrentEntry;
}
// This pushes the current frame info to the FIFO, effectively destroying
// the oldest state (note: only the structure is destroyed, handles stored in it may
// have to be destroyed prior to calling this).
+9
View File
@@ -189,6 +189,7 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder)
parser->getRequiredAttributes(&mRequiredAttributes);
parser->getRefractionMode(&mRefractionMode);
parser->getRefractionType(&mRefractionType);
parser->getReflectionMode(&mReflectionMode);
if (mBlendingMode == BlendingMode::MASKED) {
parser->getMaskThreshold(&mMaskThreshold);
@@ -378,6 +379,10 @@ Handle<HwProgram> FMaterial::getSurfaceProgramSlow(uint8_t variantKey) const noe
if (Variant(variantKey).hasSkinningOrMorphing()) {
pb.setUniformBlock(BindingPoints::PER_RENDERABLE_BONES, PerRenderableUibBone::_name);
pb.setUniformBlock(BindingPoints::PER_RENDERABLE_MORPHING, PerRenderableMorphingUib::_name);
addSamplerGroup(pb, BindingPoints::PER_RENDERABLE_MORPHING,
SibGenerator::getPerRenderPrimitiveMorphingSib(variantKey), mSamplerBindings);
}
addSamplerGroup(pb, BindingPoints::PER_VIEW, SibGenerator::getPerViewSib(variantKey), mSamplerBindings);
@@ -649,6 +654,10 @@ RefractionType Material::getRefractionType() const noexcept {
return upcast(this)->getRefractionType();
}
ReflectionMode Material::getReflectionMode() const noexcept {
return upcast(this)->getReflectionMode();
}
bool Material::hasParameter(const char* name) const noexcept {
return upcast(this)->hasParameter(name);
}
+6
View File
@@ -269,6 +269,12 @@ bool MaterialParser::getRefractionType(RefractionType* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialRefractionType, (uint8_t*)value);
}
bool MaterialParser::getReflectionMode(ReflectionMode* value) const noexcept {
static_assert(sizeof(ReflectionMode) == sizeof(uint8_t),
"ReflectionMode expected size is wrong");
return mImpl.getFromSimpleChunk(ChunkType::MaterialReflectionMode, (uint8_t*)value);
}
bool MaterialParser::getShader(ShaderBuilder& shader,
ShaderModel shaderModel, uint8_t variant, ShaderType stage) noexcept {
return mImpl.mMaterialChunk.getShader(shader,
+1
View File
@@ -85,6 +85,7 @@ public:
bool getRequiredAttributes(AttributeBitset*) const noexcept;
bool getRefractionMode(RefractionMode* value) const noexcept;
bool getRefractionType(RefractionType* value) const noexcept;
bool getReflectionMode(ReflectionMode* value) const noexcept;
bool hasCustomDepthShader(bool* value) const noexcept;
bool hasSpecularAntiAliasing(bool* value) const noexcept;
bool getSpecularAntiAliasingVariance(float* value) const noexcept;
+225
View File
@@ -0,0 +1,225 @@
/*
* Copyright (C) 2021 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 "details/MorphTargetBuffer.h"
#include "private/filament/SibGenerator.h"
#include "details/Engine.h"
#include "FilamentAPI-impl.h"
#include <math/mat4.h>
#include <math/norm.h>
namespace filament {
using namespace backend;
using namespace math;
struct MorphTargetBuffer::BuilderDetails {
size_t mVertexCount = 0;
size_t mCount = 0;
};
using BuilderType = MorphTargetBuffer;
BuilderType::Builder::Builder() noexcept = default;
BuilderType::Builder::~Builder() noexcept = default;
BuilderType::Builder::Builder(BuilderType::Builder const& rhs) noexcept = default;
BuilderType::Builder::Builder(BuilderType::Builder&& rhs) noexcept = default;
BuilderType::Builder& BuilderType::Builder::operator=(BuilderType::Builder const& rhs) noexcept = default;
BuilderType::Builder& BuilderType::Builder::operator=(BuilderType::Builder&& rhs) noexcept = default;
MorphTargetBuffer::Builder& MorphTargetBuffer::Builder::vertexCount(size_t vertexCount) noexcept {
mImpl->mVertexCount = vertexCount;
return *this;
}
MorphTargetBuffer::Builder& MorphTargetBuffer::Builder::count(size_t count) noexcept {
mImpl->mCount = count;
return *this;
}
MorphTargetBuffer* MorphTargetBuffer::Builder::build(Engine& engine) {
return upcast(engine).createMorphTargetBuffer(*this);
}
// ------------------------------------------------------------------------------------------------
// This value is limited by ES3.0, ES3.0 only guarantees 2048.
// When you change this value, you must change MAX_MORPH_TARGET_BUFFER_WIDTH at getters.vs
constexpr size_t MAX_MORPH_TARGET_BUFFER_WIDTH = 2048;
static const auto FREE_CALLBACK = [](void* mem, size_t, void*) { ::free(mem); };
static inline size_t getWidth(size_t vertexCount) noexcept {
return std::min(vertexCount, MAX_MORPH_TARGET_BUFFER_WIDTH);
}
static inline size_t getHeight(size_t vertexCount) noexcept {
return (vertexCount + MAX_MORPH_TARGET_BUFFER_WIDTH) / MAX_MORPH_TARGET_BUFFER_WIDTH;
}
static inline size_t getDepth(size_t targetCount) noexcept {
return targetCount * 2;
}
static inline size_t getSize(size_t vertexCount) noexcept {
const size_t stride = getWidth(vertexCount) * sizeof(float4);
return Texture::PixelBufferDescriptor::computeDataSize(
Texture::PixelBufferDescriptor::PixelDataFormat::RGBA,
Texture::PixelBufferDescriptor::PixelDataType::FLOAT,
stride, getHeight(vertexCount), 1);
}
static inline size_t getPositionIndex(size_t targetIndex) noexcept {
return targetIndex * 2 + 0;
}
static inline size_t getTangentIndex(size_t targetIndex) noexcept {
return targetIndex * 2 + 1;
}
FMorphTargetBuffer::FMorphTargetBuffer(FEngine& engine, const Builder& builder)
: mSBuffer(PerRenderPrimitiveMorphingSib::SAMPLER_COUNT),
mVertexCount(builder->mVertexCount),
mCount(builder->mCount) {
FEngine::DriverApi& driver = engine.getDriverApi();
mSbHandle = driver.createSamplerGroup(PerRenderPrimitiveMorphingSib::SAMPLER_COUNT);
mTbHandle = driver.createTexture(SamplerType::SAMPLER_2D_ARRAY, 1, TextureFormat::RGBA32F, 1,
getWidth(mVertexCount), getHeight(mVertexCount), getDepth(mCount),
TextureUsage::DEFAULT);
SamplerParams samplerParams{};
samplerParams.filterMin = SamplerMinFilter::NEAREST;
samplerParams.filterMag = SamplerMagFilter::NEAREST;
mSBuffer.setSampler(PerRenderPrimitiveMorphingSib::TARGETS, mTbHandle, samplerParams);
}
void FMorphTargetBuffer::terminate(FEngine& engine) {
FEngine::DriverApi& driver = engine.getDriverApi();
driver.destroySamplerGroup(mSbHandle);
driver.destroyTexture(mTbHandle);
}
void FMorphTargetBuffer::setPositionsAt(FEngine& engine, size_t targetIndex, math::float3 const* positions, size_t count) {
ASSERT_PRECONDITION(targetIndex < mCount, "targetIndex must be < count");
auto size = getSize(mVertexCount);
ASSERT_PRECONDITION((int)sizeof(math::float3) * count <= size,
"MorphTargetBuffer (size=%lu) overflow (size=%lu)",
size, sizeof(math::float3) * count);
// We could use a pool instead of malloc() directly.
auto* out = (float4*) malloc(size);
std::transform(positions, positions + count, out,
[](const float3& p) { return float4(p, 1.0f); });
Texture::PixelBufferDescriptor buffer(out, size, Texture::Format::RGBA, Texture::Type::FLOAT,
FREE_CALLBACK);
FEngine::DriverApi& driver = engine.getDriverApi();
driver.update3DImage(mTbHandle, 0, 0, 0, getPositionIndex(targetIndex),
getWidth(mVertexCount), getHeight(mVertexCount), 1,
std::move(buffer));
}
void FMorphTargetBuffer::setPositionsAt(FEngine& engine, size_t targetIndex, math::float4 const* positions, size_t count) {
ASSERT_PRECONDITION(targetIndex < mCount, "targetIndex must be < count");
auto size = getSize(mVertexCount);
ASSERT_PRECONDITION((int)sizeof(math::float4) * count <= size,
"MorphTargetBuffer (size=%lu) overflow (size=%lu)",
size, sizeof(math::float4) * count);
// We could use a pool instead of malloc() directly.
auto* out = (float4*) malloc(size);
memcpy(out, positions, sizeof(math::float4) * count);
Texture::PixelBufferDescriptor buffer(out, size, Texture::Format::RGBA, Texture::Type::FLOAT,
FREE_CALLBACK);
FEngine::DriverApi& driver = engine.getDriverApi();
driver.update3DImage(mTbHandle, 0, 0, 0, getPositionIndex(targetIndex),
getWidth(mVertexCount), getHeight(mVertexCount), 1,
std::move(buffer));
}
void FMorphTargetBuffer::setTangentsAt(FEngine& engine, size_t targetIndex, math::short4 const* tangents, size_t count) {
ASSERT_PRECONDITION(targetIndex < mCount, "targetIndex must be < count");
auto size = getSize(mVertexCount);
ASSERT_PRECONDITION((int)sizeof(math::short4) * count <= size,
"MorphTargetBuffer (size=%lu) overflow (size=%lu)",
size, sizeof(math::short4) * count);
// We could use a pool instead of malloc() directly.
auto* out = (float4*) malloc(size);
std::transform(tangents, tangents + count, out,
[](const short4& t) { return unpackSnorm16(t); });
Texture::PixelBufferDescriptor buffer(out, size, Texture::Format::RGBA, Texture::Type::FLOAT,
FREE_CALLBACK);
FEngine::DriverApi& driver = engine.getDriverApi();
driver.update3DImage(mTbHandle, 0, 0, 0, getTangentIndex(targetIndex),
getWidth(mVertexCount), getHeight(mVertexCount), 1,
std::move(buffer));
}
void FMorphTargetBuffer::commit(FEngine& engine) const noexcept {
if (mSBuffer.isDirty()) {
FEngine::DriverApi& driver = engine.getDriverApi();
driver.updateSamplerGroup(mSbHandle, std::move(mSBuffer.toCommandStream()));
}
}
void FMorphTargetBuffer::bind(backend::DriverApi& driver) const noexcept {
driver.bindSamplers(BindingPoints::PER_RENDERABLE_MORPHING, mSbHandle);
}
// ------------------------------------------------------------------------------------------------
// Trampoline calling into private implementation
// ------------------------------------------------------------------------------------------------
void MorphTargetBuffer::setPositionsAt(Engine& engine, size_t targetIndex, math::float3 const* positions, size_t count) {
upcast(this)->setPositionsAt(upcast(engine), targetIndex, positions, count);
}
void MorphTargetBuffer::setPositionsAt(Engine& engine, size_t targetIndex, math::float4 const* positions, size_t count) {
upcast(this)->setPositionsAt(upcast(engine), targetIndex, positions, count);
}
void MorphTargetBuffer::setTangentsAt(Engine& engine, size_t targetIndex, math::short4 const* tangents, size_t count) {
upcast(this)->setTangentsAt(upcast(engine), targetIndex, tangents, count);
}
size_t MorphTargetBuffer::getVertexCount() const noexcept {
return upcast(this)->getVertexCount();
}
size_t MorphTargetBuffer::getCount() const noexcept {
return upcast(this)->getCount();
}
} // namespace filament
+25
View File
@@ -177,6 +177,31 @@ void PerViewUniforms::prepareSSR(Handle<HwTexture> ssr, float refractionLodOffse
s.refractionLodOffset = refractionLodOffset;
}
void PerViewUniforms::prepareSSReflections(TextureHandle ssr, math::mat4f const& historyProjection,
math::mat4f const& projectToPixelMatrix,
ScreenSpaceReflectionsOptions const& ssrOptions) noexcept {
mPerViewSb.setSampler(PerViewSib::SSR, ssr, {
.filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR
});
auto& s = mPerViewUb.edit();
s.ssrReprojection = historyProjection;
s.ssrProjectToPixelMatrix = projectToPixelMatrix;
s.ssrThickness = ssrOptions.thickness;
s.ssrBias = ssrOptions.bias;
s.ssrDistance = ssrOptions.maxDistance;
s.ssrStride = ssrOptions.stride;
}
void PerViewUniforms::disableSSReflections() noexcept {
// We must bind a placeholder texture, even if reflections are disabled, to avoid a
// "no texture unit bound" warning.
Handle<backend::HwTexture> placeholder = mEngine.getPostProcessManager().getOneTexture();
auto& s = mPerViewUb.edit();
mPerViewSb.setSampler(PerViewSib::SSR, placeholder, {});
s.ssrDistance = 0.0f;
}
void PerViewUniforms::prepareStructure(Handle<HwTexture> structure) noexcept {
// sampler must be NEAREST
mPerViewSb.setSampler(PerViewSib::STRUCTURE, structure, {});
+5
View File
@@ -35,6 +35,7 @@ namespace filament {
struct AmbientOcclusionOptions;
struct DynamicResolutionOptions;
struct FogOptions;
struct ScreenSpaceReflectionsOptions;
struct SoftShadowOptions;
struct TemporalAntiAliasingOptions;
struct VsmShadowOptions;
@@ -72,6 +73,10 @@ public:
void prepareStructure(TextureHandle structure) noexcept;
void prepareSSAO(TextureHandle ssao, AmbientOcclusionOptions const& options) noexcept;
void prepareSSR(TextureHandle ssr, float refractionLodOffset) noexcept;
void prepareSSReflections(TextureHandle ssr, math::mat4f const& historyProjection,
math::mat4f const& projectToPixelMatrix,
ScreenSpaceReflectionsOptions const& ssrOptions) noexcept;
void disableSSReflections() noexcept;
void prepareShadowMapping(ShadowMappingUniforms const& shadowMappingUniforms,
VsmShadowOptions const& options) noexcept;
+7 -7
View File
@@ -317,7 +317,8 @@ void PostProcessManager::commitAndRender(FrameGraphResources::RenderPassInfo con
// ------------------------------------------------------------------------------------------------
FrameGraphId<FrameGraphTexture> PostProcessManager::structure(FrameGraph& fg,
RenderPass const& pass, uint32_t width, uint32_t height,
RenderPass const& pass, uint8_t structureRenderFlags,
uint32_t width, uint32_t height,
StructurePassConfig const& config) noexcept {
const float scale = config.scale;
@@ -367,10 +368,13 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::structure(FrameGraph& fg,
.clearFlags = TargetBufferFlags::COLOR0 | TargetBufferFlags::DEPTH
});
},
[=](FrameGraphResources const& resources,
[=, renderPass = pass](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) mutable {
auto out = resources.getRenderPassInfo();
pass.execute(resources.getPassName(), out.target, out.params);
renderPass.setRenderFlags(structureRenderFlags);
renderPass.appendCommands(RenderPass::CommandTypeFlags::SSAO);
renderPass.sortCommands();
renderPass.execute(resources.getPassName(), out.target, out.params);
});
auto depth = structurePass->depth;
@@ -2167,12 +2171,8 @@ void PostProcessManager::prepareTaa(FrameHistory& frameHistory,
auto& current = frameHistory.getCurrent();
// get sample position within a pixel [-0.5, 0.5]
const float2 jitter = halton(previous.frameId) - 0.5f;
// compute the world-space to clip-space matrix for this frame
current.projection = cameraInfo.projection * (cameraInfo.view * cameraInfo.worldOrigin);
// save this frame's sample position
current.jitter = jitter;
// update frame id
current.frameId = previous.frameId + 1;
}
FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
+2 -1
View File
@@ -70,7 +70,8 @@ public:
// methods below are ordered relative to their position in the pipeline (as much as possible)
// structure (depth) pass
FrameGraphId<FrameGraphTexture> structure(FrameGraph& fg, RenderPass const& pass,
FrameGraphId<FrameGraphTexture> structure(FrameGraph& fg,
RenderPass const& pass, uint8_t structureRenderFlags,
uint32_t width, uint32_t height, StructurePassConfig const& config) noexcept;
// SSAO
+15
View File
@@ -381,6 +381,7 @@ void RenderPass::generateCommandsImpl(uint32_t extraFlags,
FMaterialInstance const* const mi = primitive.getMaterialInstance();
if constexpr (isColorPass) {
cmdColor.primitive.primitiveHandle = primitive.getHwHandle();
cmdColor.primitive.morphTargetBuffer = primitive.getMorphTargetBuffer();
cmdColor.primitive.materialVariant = materialVariant;
RenderPass::setupColorCommand(cmdColor, mi, inverseFrontFaces);
@@ -470,6 +471,7 @@ void RenderPass::generateCommandsImpl(uint32_t extraFlags,
// unconditionally write the command
cmdDepth.primitive.primitiveHandle = primitive.getHwHandle();
cmdDepth.primitive.mi = mi;
cmdDepth.primitive.morphTargetBuffer = primitive.getMorphTargetBuffer();
cmdDepth.primitive.rasterState.culling = mi->getCullingMode();
// FIXME: should writeDepthForShadowCasters take precedence over mi->getDepthWrite()?
@@ -529,6 +531,7 @@ void RenderPass::Executor::recordDriverCommands(backend::DriverApi& driver,
SYSTRACE_VALUE32("commandCount", last - first);
auto const* const UTILS_RESTRICT soaSkinning = soa.data<FScene::SKINNING_BUFFER>();
auto const* const UTILS_RESTRICT soaMorphing = soa.data<FScene::MORPHING_BUFFER>();
PolygonOffset dummyPolyOffset;
PipelineState pipeline{ .polygonOffset = mPolygonOffset };
@@ -577,6 +580,18 @@ void RenderPass::Executor::recordDriverCommands(backend::DriverApi& driver,
skinning.offset * sizeof(PerRenderableUibBone),
CONFIG_MAX_BONE_COUNT * sizeof(PerRenderableUibBone));
}
auto morphTargetBuffer = info.morphTargetBuffer;
if (UTILS_UNLIKELY(morphTargetBuffer)) {
// Instead of using a UBO per primitive, we could also have a single UBO for all primitives
// and use bindUniformBufferRange which might be more efficient.
auto morphing = soaMorphing[info.index];
assert_invariant(morphing.handle);
driver.bindUniformBuffer(BindingPoints::PER_RENDERABLE_MORPHING, morphing.handle);
assert_invariant(morphing.count <= morphTargetBuffer->getCount());
morphTargetBuffer->bind(driver);
}
driver.draw(pipeline, info.primitiveHandle);
}
}
+7 -6
View File
@@ -208,19 +208,20 @@ public:
return boolish ? std::numeric_limits<uint64_t>::max() : uint64_t(0);
}
struct PrimitiveInfo { // 24 bytes
struct PrimitiveInfo { // 32 bytes
FMaterialInstance const* mi = nullptr; // 8 bytes (4)
FMorphTargetBuffer const* morphTargetBuffer = nullptr; // 8 bytes (4)
backend::Handle<backend::HwRenderPrimitive> primitiveHandle; // 4 bytes
backend::RasterState rasterState; // 4 bytes
uint16_t index = 0; // 2 bytes
Variant materialVariant; // 1 byte
uint8_t reserved[13 - sizeof(void*)] = {}; // 5 byte (9)
uint8_t reserved[21 - sizeof(void*) - sizeof(void*)] = {}; // 5 bytes (13)
};
static_assert(sizeof(PrimitiveInfo) == 24);
static_assert(sizeof(PrimitiveInfo) == 32);
struct alignas(8) Command { // 32 bytes
struct alignas(8) Command { // 40 bytes
CommandKey key = 0; // 8 bytes
PrimitiveInfo primitive; // 24 bytes
PrimitiveInfo primitive; // 32 bytes
bool operator < (Command const& rhs) const noexcept { return key < rhs.key; }
// placement new declared as "throw" to avoid the compiler's null-check
inline void* operator new (std::size_t, void* ptr) {
@@ -228,7 +229,7 @@ public:
return ptr;
}
};
static_assert(sizeof(Command) == 32);
static_assert(sizeof(Command) == 40);
static_assert(std::is_trivially_destructible_v<Command>,
"Command isn't trivially destructible");
+4
View File
@@ -83,4 +83,8 @@ void FRenderPrimitive::set(FEngine& engine, RenderableManager::PrimitiveType typ
mPrimitiveType = type;
}
void FRenderPrimitive::set(FMorphTargetBuffer* morphTargetBuffer) noexcept {
mMorphTargetBuffer = morphTargetBuffer;
}
} // namespace filament
+5
View File
@@ -30,6 +30,7 @@ namespace filament {
class FEngine;
class FVertexBuffer;
class FIndexBuffer;
class FMorphTargetBuffer;
class FRenderer;
class FRenderPrimitive {
@@ -45,6 +46,8 @@ public:
void set(FEngine& engine, RenderableManager::PrimitiveType type,
size_t offset, size_t minIndex, size_t maxIndex, size_t count) noexcept;
void set(FMorphTargetBuffer* morphTargetBuffer) noexcept;
// frees driver resources, object becomes invalid
void terminate(FEngine& engine);
@@ -53,6 +56,7 @@ public:
backend::PrimitiveType getPrimitiveType() const noexcept { return mPrimitiveType; }
AttributeBitset getEnabledAttributes() const noexcept { return mEnabledAttributes; }
uint16_t getBlendOrder() const noexcept { return mBlendOrder; }
FMorphTargetBuffer* getMorphTargetBuffer() const noexcept { return mMorphTargetBuffer; }
void setMaterialInstance(FMaterialInstance const* mi) noexcept { mMaterialInstance = mi; }
void setBlendOrder(uint16_t order) noexcept {
@@ -65,6 +69,7 @@ private:
backend::PrimitiveType mPrimitiveType = backend::PrimitiveType::NONE;
AttributeBitset mEnabledAttributes;
uint16_t mBlendOrder = 0;
FMorphTargetBuffer* mMorphTargetBuffer = nullptr;
};
} // namespace filament
+99 -19
View File
@@ -240,6 +240,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
auto taaOptions = view.getTemporalAntiAliasingOptions();
auto vignetteOptions = view.getVignetteOptions();
auto colorGrading = view.getColorGrading();
auto ssReflectionsOptions = view.getScreenSpaceReflectionsOptions();
if (!hasPostProcess) {
// disable all effects that are part of post-processing
dofOptions.enabled = false;
@@ -384,7 +385,8 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
.msaa = msaaSampleCount,
.clearFlags = clearFlags,
.clearColor = clearColor,
.hasContactShadows = scene.hasContactShadows()
.hasContactShadows = scene.hasContactShadows(),
.hasScreenSpaceReflections = ssReflectionsOptions.enabled
};
// asSubpass is disabled with TAA (although it's supported) because performance was degraded
@@ -416,6 +418,9 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
// of RenderPass::setCamera / RenderPass::setGeometry calls.
view.updatePrimitivesLod(engine, cameraInfo,
scene.getRenderableData(), view.getVisibleRenderables());
// updatePrimitivesMorphTargetBuffer must be run after updatePrimitivesLod.
view.updatePrimitivesMorphTargetBuffer(engine, cameraInfo,
scene.getRenderableData(), view.getVisibleRenderables());
pass.setCamera(cameraInfo);
pass.setGeometry(scene.getRenderableData(), view.getVisibleRenderables(), scene.getRenderableUBO());
@@ -433,14 +438,8 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
// Currently it consists of a simple depth pass.
// This is normally used by SSAO and contact-shadows
// TODO: ideally this should be a FrameGraph pass to participate to automatic culling
RenderPass structurePass(pass);
structurePass.setRenderFlags(structureRenderFlags);
structurePass.appendCommands(RenderPass::CommandTypeFlags::SSAO);
structurePass.sortCommands();
// TODO: the scaling should depends on all passes that need the structure pass
ppm.structure(fg, structurePass, svp.width, svp.height, {
ppm.structure(fg, pass, structureRenderFlags, svp.width, svp.height, {
.scale = aoOptions.resolution,
.picking = view.hasPicking()
});
@@ -467,6 +466,17 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
});
}
// Store this frame's camera projection in the frame history.
if (UTILS_UNLIKELY(taaOptions.enabled || ssReflectionsOptions.enabled)) {
auto projection = cameraInfo.projection * (cameraInfo.view * cameraInfo.worldOrigin);
setHistoryProjection(view, projection);
// update frame id
auto& history = view.getFrameHistory();
auto const& previous = history[0];
auto& current = history.getCurrent();
current.frameId = previous.frameId + 1;
}
// Apply the TAA jitter to everything after the structure pass, starting with the color pass.
if (taaOptions.enabled) {
auto& history = view.getFrameHistory();
@@ -494,7 +504,8 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
// --------------------------------------------------------------------------------------------
// Color passes
// TODO: ideally this should be a FrameGraph pass to participate to automatic culling
// This one doesn't need to be a FrameGraph pass because it always happens by construction
// (i.e. it won't be culled, unless everything is culled), so no need to complexify things.
pass.setRenderFlags(colorRenderFlags);
pass.appendCommands(RenderPass::COLOR);
pass.sortCommands();
@@ -533,7 +544,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
colorGradingConfigForColor.asSubpass = colorGradingConfigForColor.asSubpass && !taaOptions.enabled;
if (colorGradingConfigForColor.asSubpass) {
// append colorgrading subpass after all other passes
// append color grading subpass after all other passes
pass.appendCustomCommand(
RenderPass::Pass::BLENDED,
RenderPass::CustomCommand::EPILOG,
@@ -596,7 +607,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
struct ExportColorHistoryData {
FrameGraphId<FrameGraphTexture> color;
};
if (taaOptions.enabled) {
if (taaOptions.enabled || ssReflectionsOptions.enabled) {
fg.addPass<ExportColorHistoryData>("Export color history", [&](FrameGraph::Builder& builder,
auto& data) {
// We need to use sideEffect here to ensure this pass won't be culled. The "output" of
@@ -829,12 +840,25 @@ FrameGraphId<FrameGraphTexture> FRenderer::colorPass(FrameGraph& fg, const char*
FrameGraphId<FrameGraphTexture> output;
FrameGraphId<FrameGraphTexture> depth;
FrameGraphId<FrameGraphTexture> ssao;
FrameGraphId<FrameGraphTexture> ssr;
FrameGraphId<FrameGraphTexture> ssr; // either screen-space reflections or refractions
FrameGraphId<FrameGraphTexture> structure;
float4 clearColor{};
TargetBufferFlags clearFlags{};
};
FrameGraphId<FrameGraphTexture> colorHistory;
mat4f historyProjection;
if (config.hasScreenSpaceReflections) {
colorHistory = getColorHistory(fg, view.getFrameHistory());
if (UTILS_UNLIKELY(!colorHistory)) {
// if we don't have a history yet, don't render reflections this frame
} else {
const FrameHistory& frameHistory = view.getFrameHistory();
FrameHistoryEntry const& entry = frameHistory[0];
historyProjection = entry.projection;
}
}
auto& colorPass = fg.addPass<ColorPassData>(name,
[&](FrameGraph::Builder& builder, ColorPassData& data) {
@@ -843,12 +867,24 @@ FrameGraphId<FrameGraphTexture> FRenderer::colorPass(FrameGraph& fg, const char*
TargetBufferFlags clearColorFlags = config.clearFlags & TargetBufferFlags::COLOR;
data.shadows = blackboard.get<FrameGraphTexture>("shadows");
data.ssr = blackboard.get<FrameGraphTexture>("ssr");
data.ssao = blackboard.get<FrameGraphTexture>("ssao");
data.color = blackboard.get<FrameGraphTexture>("color");
data.depth = blackboard.get<FrameGraphTexture>("depth");
if (config.hasContactShadows) {
// TODO: we currently only allow either screen-space reflections or refractions,
// but not both. If SS reflections are enabled, we prefer those.
if (config.hasScreenSpaceReflections && colorHistory) {
// Screen-space reflections
data.ssr = builder.sample(colorHistory);
} else {
// Screen-space refractions
data.ssr = blackboard.get<FrameGraphTexture>("ssr");
if (data.ssr) {
data.ssr = builder.sample(data.ssr);
}
}
if (config.hasContactShadows || config.hasScreenSpaceReflections) {
data.structure = blackboard.get<FrameGraphTexture>("structure");
assert_invariant(data.structure);
data.structure = builder.sample(data.structure);
@@ -858,10 +894,6 @@ FrameGraphId<FrameGraphTexture> FRenderer::colorPass(FrameGraph& fg, const char*
data.shadows = builder.sample(data.shadows);
}
if (data.ssr) {
data.ssr = builder.sample(data.ssr);
}
if (data.ssao) {
data.ssao = builder.sample(data.ssao);
}
@@ -939,8 +971,32 @@ FrameGraphId<FrameGraphTexture> FRenderer::colorPass(FrameGraph& fg, const char*
view.prepareStructure(data.structure ?
resources.getTexture(data.structure) : ppm.getOneTexture());
// set screen-space reflections or screen-space refractions
if (data.ssr) {
view.prepareSSR(resources.getTexture(data.ssr), config.refractionLodOffset);
// We currently only allow either SS reflections or refractions.
auto const& ssrOptions = view.getScreenSpaceReflectionsOptions();
const bool reflections = config.hasScreenSpaceReflections && ssrOptions.enabled;
const bool refractions = !config.hasScreenSpaceReflections;
if (reflections) {
const auto& cameraInfo = view.getCameraInfo();
auto reprojection =
getClipSpaceToTextureSpaceMatrix() *
historyProjection *
inverse(cameraInfo.view * cameraInfo.worldOrigin);
auto projectToPixelMatrix =
getClipSpaceToTextureSpaceMatrix() *
cameraInfo.projection;
view.prepareSSReflections(resources.getTexture(data.ssr), reprojection,
projectToPixelMatrix, ssrOptions);
} else if (refractions) { // TODO: support both
view.prepareSSR(resources.getTexture(data.ssr), config.refractionLodOffset);
}
} else {
// Screen-space reflections must be explicitly disabled.
view.disableSSReflections();
}
view.prepareViewport(static_cast<filament::Viewport&>(out.params.viewport));
@@ -1266,6 +1322,30 @@ void FRenderer::initializeClearFlags() {
| TargetBufferFlags::DEPTH_AND_STENCIL;
}
math::mat4f FRenderer::getClipSpaceToTextureSpaceMatrix() const noexcept {
// Compute a clip-space [-1 to 1] to texture space [0 to 1] matrix, taking into account
// API-level differences.
const bool textureSpaceYFlipped =
mEngine.getBackend() == Backend::METAL || mEngine.getBackend() == Backend::VULKAN;
return mat4f(textureSpaceYFlipped ? mat4f::row_major_init{
0.5f, 0.0f, 0.0f, 0.5f,
0.0f, -0.5f, 0.0f, 0.5f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
} : mat4f::row_major_init{
0.5f, 0.0f, 0.0f, 0.5f,
0.0f, 0.5f, 0.0f, 0.5f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
});
}
void FRenderer::setHistoryProjection(FView& view, math::mat4f const& projection) {
auto& history = view.getFrameHistory();
auto& current = history.getCurrent();
current.projection = projection;
}
FrameGraphId<FrameGraphTexture> FRenderer::getColorHistory(FrameGraph& fg,
FrameHistory const& frameHistory) noexcept {
// Here we import the previous frame's color output and cache it in the blackboard. This ensures
+3 -3
View File
@@ -138,9 +138,9 @@ void FScene::prepare(const mat4& worldOriginTransform, bool shadowReceiversAreCa
worldTransform, // WORLD_TRANSFORM
visibility, // VISIBILITY_STATE
rcm.getSkinningBufferInfo(ri), // SKINNING_BUFFER
rcm.getMorphingBufferInfo(ri), // MORPHING_BUFFER
worldAABB.center, // WORLD_AABB_CENTER
0, // VISIBLE_MASK
rcm.getMorphWeights(ri), // MORPH_WEIGHTS
rcm.getChannels(ri), // CHANNELS
rcm.getLayerMask(ri), // LAYERS
worldAABB.halfExtent, // WORLD_AABB_EXTENT
@@ -254,8 +254,8 @@ void FScene::updateUBOs(utils::Range<uint32_t> visibleRenderables, backend::Hand
visibility.screenSpaceContactShadows));
UniformBuffer::setUniform(buffer,
offset + offsetof(PerRenderableUib, morphWeights),
sceneData.elementAt<MORPH_WEIGHTS>(i));
offset + offsetof(PerRenderableUib, morphTargetCount),
sceneData.elementAt<MORPHING_BUFFER>(i).count);
UniformBuffer::setUniform(buffer,
offset + offsetof(PerRenderableUib, channels),
+2
View File
@@ -264,6 +264,8 @@ void ShadowMapManager::render(FrameGraph& fg, FEngine& engine, backend::DriverAp
// updatePrimitivesLod must be run before RenderPass::appendCommands.
view.updatePrimitivesLod(engine, cameraInfo, scene->getRenderableData(), entry.range);
// updatePrimitivesMorphTargetBuffer must be run after updatePrimitivesLod.
view.updatePrimitivesMorphTargetBuffer(engine, cameraInfo, scene->getRenderableData(), entry.range);
// generate and sort the commands for rendering the shadow map
RenderPass entryPass(pass);
+15 -50
View File
@@ -111,7 +111,7 @@ inline float3 darkSurround_to_dimSurround(float3 linearCV) {
float3 XYZ = AP1_to_XYZ * linearCV;
float3 xyY = XYZ_to_xyY(XYZ);
xyY.z = clamp(xyY.z, 0.0f, (float)std::numeric_limits<half>::max());
xyY.z = clamp(xyY.z, 0.0f, (float) std::numeric_limits<half>::max());
xyY.z = std::pow(xyY.z, DIM_SURROUND_GAMMA);
XYZ = xyY_to_XYZ(xyY);
@@ -135,7 +135,7 @@ float3 ACES(float3 color, float brightness) noexcept {
constexpr float RRT_SAT_FACTOR = 0.96f;
constexpr float ODT_SAT_FACTOR = 0.93f;
float3 ap0 = REC2020_to_AP0 * color;
float3 ap0 = Rec2020_to_AP0 * color;
// Glow module
float saturation = rgb_2_saturation(ap0);
@@ -177,7 +177,7 @@ float3 ACES(float3 color, float brightness) noexcept {
// Apply desaturation to compensate for luminance difference
linearCV = mix(float3(dot(linearCV, LUMINANCE_AP1)), linearCV, ODT_SAT_FACTOR);
return AP1_to_REC2020 * linearCV;
return AP1_to_Rec2020 * linearCV;
}
} // namespace aces
@@ -261,7 +261,7 @@ float3 DisplayRangeToneMapper::operator()(math::float3 c) const noexcept {
// The 5th color in the array (cyan) represents middle gray (18%)
// Every stop above or below middle gray causes a color shift
// TODO: This should depend on the working color grading color space
float v = log2(dot(c, LUMINANCE_REC2020) / 0.18f);
float v = log2(dot(c, LUMINANCE_Rec2020) / 0.18f);
v = clamp(v + 5.0f, 0.0f, 15.0f);
size_t index = size_t(v);
@@ -272,71 +272,52 @@ float3 DisplayRangeToneMapper::operator()(math::float3 c) const noexcept {
// Generic tone mapper
//------------------------------------------------------------------------------
// Lottes, 2016,"Advanced Techniques and Optimization of VDR Color Pipelines":
// https://gpuopen.com/wp-content/uploads/2016/03/GdcVdrLottes.pdf
// Includes fix from Bart Wronski:
// https://bartwronski.com/2016/09/01/dynamic-range-and-evs/
struct GenericToneMapper::Options {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshadow"
void setParameters(
float contrast,
float shoulder,
float midGrayIn,
float midGrayOut,
float hdrMax
) {
contrast = max(contrast, 1e-5f);
shoulder = saturate(shoulder);
midGrayIn = clamp(midGrayIn, 1e-5f, 1.0f);
midGrayOut = clamp(midGrayOut, 1e-5f, 1.0f);
hdrMax = max(hdrMax, 1.0f);
this->contrast = contrast;
this->shoulder = shoulder;
this->midGrayIn = midGrayIn;
this->midGrayOut = midGrayOut;
this->hdrMax = hdrMax;
// remap shoulder
d = 0.8f + 0.4f * shoulder;
float a = pow(midGrayIn, contrast);
float b = pow(hdrMax, contrast);
float c = a - midGrayOut * b;
float mc = std::pow(midGrayIn, contrast);
float mcs = std::pow(mc, d);
float hc = std::pow(hdrMax, contrast);
float hcs = std::pow(hc, d);
float u = (hcs - mcs) * midGrayOut;
float v = mcs * midGrayOut;
b = -((-mc + (midGrayOut * (hcs * mc - hc * v)) / u) / v);
c = (hcs * mc - hc * v) / u;
inputScale = (a * b * (midGrayOut - 1.0f)) / c;
outputScale = midGrayOut * (a - b) / c;
}
#pragma clang diagnostic pop
float contrast;
float shoulder;
float midGrayIn;
float midGrayOut;
float hdrMax;
// Computed fields, do not modify
float b;
float c;
float d;
// TEMP
float inputScale;
float outputScale;
};
GenericToneMapper::GenericToneMapper(
float contrast,
float shoulder,
float midGrayIn,
float midGrayOut,
float hdrMax
) noexcept {
mOptions = new Options();
mOptions->setParameters(contrast, shoulder, midGrayIn, midGrayOut, hdrMax);
mOptions->setParameters(contrast, midGrayIn, midGrayOut, hdrMax);
}
GenericToneMapper::~GenericToneMapper() noexcept {
@@ -354,12 +335,11 @@ GenericToneMapper& GenericToneMapper::operator=(GenericToneMapper&& rhs) noexcep
}
float3 GenericToneMapper::operator()(math::float3 x) const noexcept {
float3 xc = pow(clamp(x, 0.0f, mOptions->hdrMax), mOptions->contrast);
return saturate(xc / (pow(xc, mOptions->d) * mOptions->b + mOptions->c));
x = pow(x, mOptions->contrast);
return mOptions->outputScale * x / (x + mOptions->inputScale);
}
float GenericToneMapper::getContrast() const noexcept { return mOptions->contrast; }
float GenericToneMapper::getShoulder() const noexcept { return mOptions->shoulder; }
float GenericToneMapper::getMidGrayIn() const noexcept { return mOptions->midGrayIn; }
float GenericToneMapper::getMidGrayOut() const noexcept { return mOptions->midGrayOut; }
float GenericToneMapper::getHdrMax() const noexcept { return mOptions->hdrMax; }
@@ -367,27 +347,14 @@ float GenericToneMapper::getHdrMax() const noexcept { return mOptions->hdrMax;
void GenericToneMapper::setContrast(float contrast) noexcept {
mOptions->setParameters(
contrast,
mOptions->shoulder,
mOptions->midGrayIn,
mOptions->midGrayOut,
mOptions->hdrMax
);
}
void GenericToneMapper::setShoulder(float shoulder) noexcept {
mOptions->setParameters(
mOptions->contrast,
shoulder,
mOptions->midGrayIn,
mOptions->midGrayOut,
mOptions->hdrMax
);
}
void GenericToneMapper::setMidGrayIn(float midGrayIn) noexcept {
mOptions->setParameters(
mOptions->contrast,
mOptions->shoulder,
midGrayIn,
mOptions->midGrayOut,
mOptions->hdrMax
@@ -397,7 +364,6 @@ void GenericToneMapper::setMidGrayIn(float midGrayIn) noexcept {
void GenericToneMapper::setMidGrayOut(float midGrayOut) noexcept {
mOptions->setParameters(
mOptions->contrast,
mOptions->shoulder,
mOptions->midGrayIn,
midGrayOut,
mOptions->hdrMax
@@ -407,7 +373,6 @@ void GenericToneMapper::setMidGrayOut(float midGrayOut) noexcept {
void GenericToneMapper::setHdrMax(float hdrMax) noexcept {
mOptions->setParameters(
mOptions->contrast,
mOptions->shoulder,
mOptions->midGrayIn,
mOptions->midGrayOut,
hdrMax
+36
View File
@@ -19,6 +19,7 @@
#include "Culler.h"
#include "DFG.h"
#include "Froxelizer.h"
#include "RenderPrimitive.h"
#include "ResourceAllocator.h"
#include "details/Engine.h"
@@ -657,9 +658,23 @@ void FView::prepareSSAO(Handle<HwTexture> ssao) const noexcept {
}
void FView::prepareSSR(Handle<HwTexture> ssr, float refractionLodOffset) const noexcept {
// If screen-space refractions are enabled, make sure to disable screen-space reflections.
// disableSSReflections binds a dummy texture to light_ssr, but this is overridden by prepareSSR.
// TODO: support simultaneous screen-space refractions and reflections.
mPerViewUniforms.disableSSReflections();
mPerViewUniforms.prepareSSR(ssr, refractionLodOffset);
}
void FView::disableSSReflections() const noexcept {
mPerViewUniforms.disableSSReflections();
}
void FView::prepareSSReflections(backend::Handle<backend::HwTexture> ssr,
math::mat4f historyProjection, math::mat4f projectToPixelMatrix,
ScreenSpaceReflectionsOptions const& ssrOptions) const noexcept {
mPerViewUniforms.prepareSSReflections(ssr, historyProjection, projectToPixelMatrix, ssrOptions);
}
void FView::prepareStructure(Handle<HwTexture> structure) const noexcept {
// sampler must be NEAREST
mPerViewUniforms.prepareStructure(structure);
@@ -868,6 +883,19 @@ void FView::updatePrimitivesLod(FEngine& engine, const CameraInfo&,
}
}
void FView::updatePrimitivesMorphTargetBuffer(FEngine& engine, const CameraInfo&,
FScene::RenderableSoa& renderableData, Range visible) noexcept {
for (uint32_t index : visible) {
Slice<FRenderPrimitive> primitives = renderableData.elementAt<FScene::PRIMITIVES>(index);
for (auto& primitive : primitives) {
auto morphTargetBuffer = primitive.getMorphTargetBuffer();
if (morphTargetBuffer) {
morphTargetBuffer->commit(engine);
}
}
}
}
void FView::renderShadowMaps(FrameGraph& fg, FEngine& engine, FEngine::DriverApi& driver,
RenderPass const& pass) noexcept {
mShadowMapManager.render(fg, engine, driver, pass, *this);
@@ -1016,6 +1044,14 @@ const View::MultiSampleAntiAliasingOptions& View::getMultiSampleAntiAliasingOpti
return upcast(this)->getMultiSampleAntiAliasingOptions();
}
void View::setScreenSpaceReflectionsOptions(ScreenSpaceReflectionsOptions options) noexcept {
upcast(this)->setScreenSpaceReflectionsOptions(options);
}
const View::ScreenSpaceReflectionsOptions& View::getScreenSpaceReflectionsOptions() const noexcept {
return upcast(this)->getScreenSpaceReflectionsOptions();
}
void View::setColorGrading(ColorGrading* colorGrading) noexcept {
return upcast(this)->setColorGrading(upcast(colorGrading));
}
+62 -8
View File
@@ -23,8 +23,11 @@
#include "details/Engine.h"
#include "details/VertexBuffer.h"
#include "details/IndexBuffer.h"
#include "details/Texture.h"
#include "details/Material.h"
#include "private/filament/SibGenerator.h"
#include <backend/DriverEnums.h>
#include <utils/Log.h>
@@ -316,7 +319,6 @@ void FRenderableManager::create(
setCulling(ci, builder->mCulling);
setSkinning(ci, false);
setMorphing(ci, builder->mMorphingEnabled);
setMorphWeights(ci, {0, 0, 0, 0});
mManager[ci].channels = builder->mChannels;
const uint32_t count = builder->mSkinningBoneCount;
@@ -372,6 +374,18 @@ void FRenderableManager::create(
}
}
}
if (builder->mMorphingEnabled) {
// Instead of using a UBO per primitive, we could also have a single UBO for all primitives
// and use bindUniformBufferRange which might be more efficient.
MorphWeights& morphWeights = manager[ci].morphWeights;
morphWeights = MorphWeights {
.handle = driver.createBufferObject(
sizeof(PerRenderableMorphingUib),
BufferObjectBinding::UNIFORM,
backend::BufferUsage::DYNAMIC),
.count = 0 };
}
}
engine.flushIfNeeded();
}
@@ -416,6 +430,12 @@ void FRenderableManager::destroyComponent(Instance ci) noexcept {
if (bones.handle && !bones.skinningBufferMode) {
driver.destroyBufferObject(bones.handle);
}
// destroy the weights structures if any
MorphWeights const& morphWeights = manager[ci].morphWeights;
if (morphWeights.handle) {
driver.destroyBufferObject(morphWeights.handle);
}
}
void FRenderableManager::destroyComponentPrimitives(
@@ -562,9 +582,38 @@ void FRenderableManager::setSkinningBuffer(FRenderableManager::Instance ci,
bones.offset = uint16_t(offset);
}
void FRenderableManager::setMorphWeights(Instance ci, const float4& weights) noexcept {
if (ci) {
mManager[ci].morphWeights = weights;
static void updateMorphWeights(FEngine& engine, backend::Handle<backend::HwBufferObject> handle,
float const* weights, size_t count) noexcept {
auto& driver = engine.getDriverApi();
auto size = sizeof(PerRenderableMorphingUib);
auto* UTILS_RESTRICT out = (PerRenderableMorphingUib*)driver.allocate(size);
memset(out, 0, size);
std::transform(weights, weights + count, out->weights,
[](float value) { return float4(value); });
driver.updateBufferObject(handle, { out, size }, 0);
}
void FRenderableManager::setMorphWeights(Instance instance, float const* weights, size_t count) noexcept {
if (instance) {
MorphWeights& morphWeights = mManager[instance].morphWeights;
morphWeights.count = count;
ASSERT_PRECONDITION(count < CONFIG_MAX_MORPH_TARGET_COUNT,
"Only %d morph targets are supported (count=%d)", CONFIG_MAX_MORPH_TARGET_COUNT, count);
if (morphWeights.handle) {
updateMorphWeights(mEngine, morphWeights.handle, weights, count);
}
}
}
void FRenderableManager::setMorphTargetBufferAt(Instance instance,
size_t primitiveIndex, FMorphTargetBuffer* morphTargetBuffer) noexcept {
if (instance) {
Slice<FRenderPrimitive>& primitives = getRenderPrimitives(instance, 0);
if (primitiveIndex < primitives.size()) {
primitives[primitiveIndex].set(morphTargetBuffer);
}
}
}
@@ -693,15 +742,20 @@ void RenderableManager::setBones(Instance instance,
upcast(this)->setBones(instance, transforms, boneCount, offset);
}
void RenderableManager::setMorphWeights(Instance instance, float4 const& weights) noexcept {
upcast(this)->setMorphWeights(instance, weights);
}
void RenderableManager::setSkinningBuffer(Instance instance,
SkinningBuffer* skinningBuffer, size_t count, size_t offset) noexcept {
upcast(this)->setSkinningBuffer(instance, upcast(skinningBuffer), count, offset);
}
void RenderableManager::setMorphWeights(Instance instance, float const* weights, size_t count) noexcept {
upcast(this)->setMorphWeights(instance, weights, count);
}
void RenderableManager::setMorphTargetBufferAt(Instance instance,
size_t primitiveIndex, MorphTargetBuffer* morphTargetBuffer) noexcept {
upcast(this)->setMorphTargetBufferAt(instance, primitiveIndex, upcast(morphTargetBuffer));
}
void RenderableManager::setLightChannel(Instance instance, unsigned int channel, bool enable) noexcept {
upcast(this)->setLightChannel(instance, channel, enable);
}
+30 -9
View File
@@ -40,9 +40,11 @@ namespace filament {
class FBufferObject;
class FIndexBuffer;
class FMaterialInstance;
class FMorphTargetBuffer;
class FRenderPrimitive;
class FSkinningBuffer;
class FVertexBuffer;
class FTexture;
class FRenderableManager : public RenderableManager {
public:
@@ -106,9 +108,11 @@ public:
inline void setPrimitives(Instance instance, utils::Slice<FRenderPrimitive> const& primitives) noexcept;
inline void setBones(Instance instance, Bone const* transforms, size_t boneCount, size_t offset = 0) noexcept;
inline void setBones(Instance instance, math::mat4f const* transforms, size_t boneCount, size_t offset = 0) noexcept;
inline void setMorphWeights(Instance instance, const math::float4& weights) noexcept;
inline void setSkinningBuffer(Instance instance, FSkinningBuffer* skinningBuffer,
size_t count, size_t offset) noexcept;
void setMorphWeights(Instance instance, float const* weights, size_t count) noexcept;
void setMorphTargetBufferAt(Instance instance,
size_t primitiveIndex, FMorphTargetBuffer* morphTargetBuffer) noexcept;
inline void setLightChannel(Instance instance, unsigned int channel, bool enable) noexcept;
inline bool getLightChannel(Instance instance, unsigned int channel) const noexcept;
@@ -123,7 +127,6 @@ public:
inline Visibility getVisibility(Instance instance) const noexcept;
inline uint8_t getLayerMask(Instance instance) const noexcept;
inline uint8_t getPriority(Instance instance) const noexcept;
inline math::float4 getMorphWeights(Instance instance) const noexcept;
inline uint8_t getChannels(Instance instance) const noexcept;
struct SkinningBindingInfo {
@@ -134,6 +137,12 @@ public:
inline SkinningBindingInfo getSkinningBufferInfo(Instance instance) const noexcept;
inline uint32_t getBoneCount(Instance instance) const noexcept;
struct MorphingBindingInfo {
backend::Handle<backend::HwBufferObject> handle;
uint32_t count;
};
inline MorphingBindingInfo getMorphingBufferInfo(Instance instance) const noexcept;
inline int getMorphTargetCount(Instance instance) const noexcept;
utils::Entity getEntity(Instance instance) const noexcept {
return mManager.getEntity(instance);
@@ -165,13 +174,18 @@ private:
uint16_t offset = 0;
bool skinningBufferMode = false;
};
static_assert(sizeof(Bones) == 12);
struct MorphWeights {
backend::Handle<backend::HwBufferObject> handle;
uint32_t count = 0;
};
static_assert(sizeof(MorphWeights) == 8);
enum {
AABB, // user data
LAYERS, // user data
MORPH_WEIGHTS, // user data
MORPH_WEIGHTS, // filament data, UBO storing a pointer to the morph weights information
CHANNELS, // user data
VISIBILITY, // user data
PRIMITIVES, // user data
@@ -181,7 +195,7 @@ private:
using Base = utils::SingleInstanceComponentManager<
Box, // AABB
uint8_t, // LAYERS
math::float4, // MORPH_WEIGHTS
MorphWeights, // MORPH_WEIGHTS
uint8_t, // CHANNELS
Visibility, // VISIBILITY
utils::Slice<FRenderPrimitive>, // PRIMITIVES
@@ -325,10 +339,6 @@ uint8_t FRenderableManager::getPriority(Instance instance) const noexcept {
return getVisibility(instance).priority;
}
math::float4 FRenderableManager::getMorphWeights(Instance instance) const noexcept {
return mManager[instance].morphWeights;
}
uint8_t FRenderableManager::getChannels(Instance instance) const noexcept {
return mManager[instance].channels;
}
@@ -348,6 +358,17 @@ inline uint32_t FRenderableManager::getBoneCount(Instance instance) const noexce
return bones.count;
}
FRenderableManager::MorphingBindingInfo
FRenderableManager::getMorphingBufferInfo(Instance instance) const noexcept {
MorphWeights const& morphWeights = mManager[instance].morphWeights;
return { morphWeights.handle, morphWeights.count };
}
int FRenderableManager::getMorphTargetCount(Instance instance) const noexcept {
MorphWeights const& morphWeights = mManager[instance].morphWeights;
return morphWeights.count;
}
utils::Slice<FRenderPrimitive> const& FRenderableManager::getRenderPrimitives(
Instance instance, uint8_t level) const noexcept {
return mManager[instance].primitives;
+4
View File
@@ -36,6 +36,7 @@
#include "details/IndexBuffer.h"
#include "details/RenderTarget.h"
#include "details/SkinningBuffer.h"
#include "details/MorphTargetBuffer.h"
#include "details/Skybox.h"
#include "private/backend/CommandBufferQueue.h"
@@ -234,6 +235,7 @@ public:
FVertexBuffer* createVertexBuffer(const VertexBuffer::Builder& builder) noexcept;
FIndexBuffer* createIndexBuffer(const IndexBuffer::Builder& builder) noexcept;
FSkinningBuffer* createSkinningBuffer(const SkinningBuffer::Builder& builder) noexcept;
FMorphTargetBuffer* createMorphTargetBuffer(const MorphTargetBuffer::Builder& builder) noexcept;
FIndirectLight* createIndirectLight(const IndirectLight::Builder& builder) noexcept;
FMaterial* createMaterial(const Material::Builder& builder) noexcept;
FTexture* createTexture(const Texture::Builder& builder) noexcept;
@@ -265,6 +267,7 @@ public:
bool destroy(const FFence* p);
bool destroy(const FIndexBuffer* p);
bool destroy(const FSkinningBuffer* p);
bool destroy(const FMorphTargetBuffer* p);
bool destroy(const FIndirectLight* p);
bool destroy(const FMaterial* p);
bool destroy(const FMaterialInstance* p);
@@ -376,6 +379,7 @@ private:
ResourceList<FStream> mStreams{ "Stream" };
ResourceList<FIndexBuffer> mIndexBuffers{ "IndexBuffer" };
ResourceList<FSkinningBuffer> mSkinningBuffers{ "SkinningBuffer" };
ResourceList<FMorphTargetBuffer> mMorphTargetBuffers{ "MorphTargetBuffer" };
ResourceList<FVertexBuffer> mVertexBuffers{ "VertexBuffer" };
ResourceList<FIndirectLight> mIndirectLights{ "IndirectLight" };
ResourceList<FMaterial> mMaterials{ "Material" };
+2
View File
@@ -118,6 +118,7 @@ public:
AttributeBitset getRequiredAttributes() const noexcept { return mRequiredAttributes; }
RefractionMode getRefractionMode() const noexcept { return mRefractionMode; }
RefractionType getRefractionType() const noexcept { return mRefractionType; }
ReflectionMode getReflectionMode() const noexcept { return mReflectionMode; }
bool hasSpecularAntiAliasing() const noexcept { return mSpecularAntiAliasing; }
float getSpecularAntiAliasingVariance() const noexcept { return mSpecularAntiAliasingVariance; }
@@ -188,6 +189,7 @@ private:
AttributeBitset mRequiredAttributes;
RefractionMode mRefractionMode = RefractionMode::NONE;
RefractionType mRefractionType = RefractionType::SOLID;
ReflectionMode mReflectionMode = ReflectionMode::DEFAULT;
uint64_t mMaterialProperties = 0;
float mMaskThreshold = 0.4f;
+69
View File
@@ -0,0 +1,69 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_FILAMENT_DETAILS_MORPHTARGETBUFFER_H
#define TNT_FILAMENT_DETAILS_MORPHTARGETBUFFER_H
#include "upcast.h"
#include <filament/MorphTargetBuffer.h>
#include "private/backend/DriverApiForward.h"
#include "private/backend/SamplerGroup.h"
#include <backend/Handle.h>
#include <utils/Allocator.h>
#include <vector>
namespace filament {
class FEngine;
class FMorphTargetBuffer : public MorphTargetBuffer {
public:
FMorphTargetBuffer(FEngine& engine, const Builder& builder);
// frees driver resources, object becomes invalid
void terminate(FEngine& engine);
void setPositionsAt(FEngine& engine, size_t targetIndex, math::float3 const* positions, size_t count);
void setPositionsAt(FEngine& engine, size_t targetIndex, math::float4 const* positions, size_t count);
void setTangentsAt(FEngine& engine, size_t targetIndex, math::short4 const* tangents, size_t count);
inline size_t getVertexCount() const noexcept { return mVertexCount; }
inline size_t getCount() const noexcept { return mCount; }
private:
friend class FView;
friend class RenderPass;
void commit(FEngine& engine) const noexcept;
void bind(backend::DriverApi& driver) const noexcept;
backend::Handle<backend::HwSamplerGroup> mSbHandle;
backend::Handle<backend::HwTexture> mTbHandle;
backend::SamplerGroup mSBuffer;
size_t mVertexCount;
size_t mCount;
};
FILAMENT_UPCAST(MorphTargetBuffer)
} // namespace filament
#endif //TNT_FILAMENT_DETAILS_MORPHTARGETBUFFER_H
+5
View File
@@ -152,6 +152,7 @@ private:
math::float4 clearColor = {};
float refractionLodOffset;
bool hasContactShadows;
bool hasScreenSpaceReflections;
};
FrameGraphId<FrameGraphTexture> colorPass(FrameGraph& fg, const char* name,
@@ -187,6 +188,10 @@ private:
return clock::now() - getUserEpoch();
}
math::mat4f getClipSpaceToTextureSpaceMatrix() const noexcept;
void setHistoryProjection(FView& view, math::mat4f const& projection);
static FrameGraphId<FrameGraphTexture> getColorHistory(FrameGraph& fg,
FrameHistory const& frameHistory) noexcept;
+2 -2
View File
@@ -105,9 +105,9 @@ public:
WORLD_TRANSFORM, // 16 | instance of the Transform component
VISIBILITY_STATE, // 1 | visibility data of the component
SKINNING_BUFFER, // 8 | bones uniform buffer handle, count, offset
MORPHING_BUFFER, // 8 | weights uniform buffer handle, count
WORLD_AABB_CENTER, // 12 | world-space bounding box center of the renderable
VISIBLE_MASK, // 2 | each bit represents a visibility in a pass
MORPH_WEIGHTS, // 4 | floats for morphing
CHANNELS, // 1 | currently light channels only
// These are not needed anymore after culling
@@ -127,9 +127,9 @@ public:
math::mat4f, // WORLD_TRANSFORM
FRenderableManager::Visibility, // VISIBILITY_STATE
FRenderableManager::SkinningBindingInfo, // SKINNING_BUFFER
FRenderableManager::MorphingBindingInfo, // MORPHING_BUFFER
math::float3, // WORLD_AABB_CENTER
VisibleMaskType, // VISIBLE_MASK
math::float4, // MORPH_WEIGHTS
uint8_t, // CHANNELS
uint8_t, // LAYERS
math::float3, // WORLD_AABB_EXTENT
+21
View File
@@ -172,6 +172,10 @@ public:
void prepareSSAO(backend::Handle<backend::HwTexture> ssao) const noexcept;
void prepareSSR(backend::Handle<backend::HwTexture> ssr, float refractionLodOffset) const noexcept;
void disableSSReflections() const noexcept;
void prepareSSReflections(backend::Handle<backend::HwTexture> ssr,
math::mat4f historyProjection, math::mat4f projectToPixelMatrix,
ScreenSpaceReflectionsOptions const& ssrOptions) const noexcept;
void prepareStructure(backend::Handle<backend::HwTexture> structure) const noexcept;
void prepareShadow(backend::Handle<backend::HwTexture> structure) const noexcept;
void prepareShadowMap() const noexcept;
@@ -198,6 +202,10 @@ public:
FEngine& engine, const CameraInfo& camera,
FScene::RenderableSoa& renderableData, Range visible) noexcept;
void updatePrimitivesMorphTargetBuffer(
FEngine& engine, const CameraInfo&,
FScene::RenderableSoa& renderableData, Range visible) noexcept;
void setShadowingEnabled(bool enabled) noexcept { mShadowingEnabled = enabled; }
bool isShadowingEnabled() const noexcept { return mShadowingEnabled; }
@@ -255,6 +263,18 @@ public:
return mMultiSampleAntiAliasingOptions;
}
void setScreenSpaceReflectionsOptions(ScreenSpaceReflectionsOptions options) noexcept {
options.thickness = std::max(0.0f, options.thickness);
options.bias = std::max(0.0f, options.bias);
options.maxDistance = std::max(0.0f, options.maxDistance);
options.stride = std::max(1.0f, options.stride);
mScreenSpaceReflectionsOptions = options;
}
const ScreenSpaceReflectionsOptions& getScreenSpaceReflectionsOptions() const noexcept {
return mScreenSpaceReflectionsOptions;
}
void setColorGrading(FColorGrading* colorGrading) noexcept {
mColorGrading = colorGrading == nullptr ? mDefaultColorGrading : colorGrading;
}
@@ -570,6 +590,7 @@ private:
VignetteOptions mVignetteOptions;
TemporalAntiAliasingOptions mTemporalAntiAliasingOptions;
MultiSampleAntiAliasingOptions mMultiSampleAntiAliasingOptions;
ScreenSpaceReflectionsOptions mScreenSpaceReflectionsOptions;
BlendMode mBlendMode = BlendMode::OPAQUE;
const FColorGrading* mColorGrading = nullptr;
const FColorGrading* mDefaultColorGrading = nullptr;
+1 -1
View File
@@ -21,7 +21,7 @@ highp float linearizeDepth(highp float depth) {
// Our far plane is at infinity, which causes a division by zero below, which in turn
// causes some issues on some GPU. We workaround it by replacing "infinity" by the closest
// value representable in a 24 bit depth buffer.
const float preventDiv0 = 1.0 / 16777216.0;
const highp float preventDiv0 = 1.0 / 16777216.0;
mat4 p = getViewFromClipMatrix();
// this works with perspective and ortho projections, for a perspective projection
// this resolves to -near/depth, for an ortho projection this resolves to depth*(far - near) - far
+2 -2
View File
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.16.1"
spec.version = "1.17.0"
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
spec.homepage = "https://google.github.io/filament"
spec.authors = "Google LLC."
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
spec.platform = :ios, "11.0"
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.16.1/filament-v1.16.1-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.17.0/filament-v1.17.0-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {
@@ -62,6 +62,7 @@ enum UTILS_PUBLIC ChunkType : uint64_t {
MaterialDomain = charTo64bitNum("MAT_DOMN"),
MaterialRefraction = charTo64bitNum("MAT_REFM"),
MaterialRefractionType = charTo64bitNum("MAT_REFT"),
MaterialReflectionMode = charTo64bitNum("MAT_REFL"),
MaterialRequiredAttributes = charTo64bitNum("MAT_REQA"),
MaterialDepthWriteSet = charTo64bitNum("MAT_DEWS"),
@@ -27,7 +27,7 @@
namespace filament {
// update this when a new version of filament wouldn't work with older materials
static constexpr size_t MATERIAL_VERSION = 16;
static constexpr size_t MATERIAL_VERSION = 17;
/**
* Supported shading models
@@ -136,20 +136,10 @@ enum VertexAttribute : uint8_t {
CUSTOM6 = 14,
CUSTOM7 = 15,
// Aliases for vertex morphing.
MORPH_POSITION_0 = CUSTOM0,
MORPH_POSITION_1 = CUSTOM1,
MORPH_POSITION_2 = CUSTOM2,
MORPH_POSITION_3 = CUSTOM3,
MORPH_TANGENTS_0 = CUSTOM4,
MORPH_TANGENTS_1 = CUSTOM5,
MORPH_TANGENTS_2 = CUSTOM6,
MORPH_TANGENTS_3 = CUSTOM7,
// this is limited by driver::MAX_VERTEX_ATTRIBUTE_COUNT
};
static constexpr size_t MAX_MORPH_TARGETS = 4;
static constexpr size_t MAX_MORPH_TARGETS = 128; // this is limited by filament::CONFIG_MAX_MORPH_TARGET_COUNT
static constexpr size_t MAX_CUSTOM_ATTRIBUTES = 8;
/**
@@ -186,6 +176,14 @@ enum class RefractionType : uint8_t {
THIN = 1, //!< refraction through thin objects (e.g. window)
};
/**
* Reflection mode
*/
enum class ReflectionMode : uint8_t {
DEFAULT = 0, //! reflections sample from the scene's IBL only
SCREEN_SPACE = 1, //! reflections sample from screen space, and fallback to the scene's IBL
};
// can't really use std::underlying_type<AttributeIndex>::type because the driver takes a uint32_t
using AttributeBitset = utils::bitset32;
@@ -33,14 +33,15 @@ enum class PostProcessVariant : uint8_t {
// Binding points for uniform buffers and sampler buffers.
// Effectively, these are just names.
namespace BindingPoints {
constexpr uint8_t PER_VIEW = 0; // uniforms/samplers updated per view
constexpr uint8_t PER_RENDERABLE = 1; // uniforms/samplers updated per renderable
constexpr uint8_t PER_RENDERABLE_BONES = 2; // bones data, per renderable
constexpr uint8_t LIGHTS = 3; // lights data array
constexpr uint8_t SHADOW = 4; // punctual shadow data
constexpr uint8_t FROXEL_RECORDS = 5;
constexpr uint8_t PER_MATERIAL_INSTANCE = 6; // uniforms/samplers updates per material
constexpr uint8_t COUNT = 7;
constexpr uint8_t PER_VIEW = 0; // uniforms/samplers updated per view
constexpr uint8_t PER_RENDERABLE = 1; // uniforms/samplers updated per renderable
constexpr uint8_t PER_RENDERABLE_BONES = 2; // bones data, per renderable
constexpr uint8_t PER_RENDERABLE_MORPHING = 3; // morphing uniform/sampler updated per render primitive
constexpr uint8_t LIGHTS = 4; // lights data array
constexpr uint8_t SHADOW = 5; // punctual shadow data
constexpr uint8_t FROXEL_RECORDS = 6;
constexpr uint8_t PER_MATERIAL_INSTANCE = 7; // uniforms/samplers updates per material
constexpr uint8_t COUNT = 8;
// These are limited by Program::UNIFORM_BINDING_COUNT (currently 8)
}
@@ -66,6 +67,11 @@ constexpr size_t CONFIG_MAX_SHADOW_CASCADES = 4;
// We store 64 bytes per bone.
constexpr size_t CONFIG_MAX_BONE_COUNT = 256;
// The maximum number of morph target count.
// This value is limited by ES3.0, ES3.0 only guarantees 256 layers in an array texture.
// For morphing, 128 layers are used for the positions and others are used for tangents.
constexpr int CONFIG_MAX_MORPH_TARGET_COUNT = 128;
} // namespace filament
#endif // TNT_FILAMENT_driver/EngineEnums.h
@@ -30,6 +30,7 @@ class SamplerInterfaceBlock;
class SibGenerator {
public:
static SamplerInterfaceBlock const& getPerViewSib(uint8_t variantKey) noexcept;
static SamplerInterfaceBlock const& getPerRenderPrimitiveMorphingSib(uint8_t variantKey) noexcept;
static SamplerInterfaceBlock const* getSib(uint8_t bindingPoint, uint8_t variantKey) noexcept;
// When adding a sampler block here, make sure to also update
// FMaterial::getSurfaceProgramSlow and FMaterial::getPostProcessProgramSlow if needed
@@ -48,5 +49,14 @@ struct PerViewSib {
static constexpr size_t SAMPLER_COUNT = 7;
};
struct PerRenderPrimitiveMorphingSib {
// Morph positions and normals are packed into one texture.
// Because some materials exceed MAX_SAMPLER_COUNT(16)
// when morph positions and normals are bound to samplers separately.
static constexpr size_t TARGETS = 0; // morph positions and normals
static constexpr size_t SAMPLER_COUNT = 1;
};
}
#endif // TNT_FILABRIDGE_SIBGENERATOR_H
@@ -136,8 +136,16 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
float nearOverFarMinusNear; // n / (f-n), always positive
float temporalNoise; // noise [0,1] when TAA is used, 0 otherwise
// Screen-space reflections
math::mat4f ssrReprojection;
math::mat4f ssrProjectToPixelMatrix;
float ssrThickness; // ssr thickness, in world units
float ssrBias; // ssr bias, in world units
float ssrDistance; // ssr world raycast distance, 0 when ssr is off
float ssrStride; // ssr texel stride, >= 1.0
// bring PerViewUib to 2 KiB
math::float4 padding2[58];
math::float4 padding3[49];
};
// 2 KiB == 128 float4s
@@ -149,7 +157,7 @@ struct alignas(256) PerRenderableUib { // NOLINT(cppcoreguidelines-pro-type-memb
static constexpr utils::StaticString _name{ "ObjectUniforms" };
math::mat4f worldFromModelMatrix;
math::mat3f worldFromModelNormalMatrix; // this gets expanded to 48 bytes during the copy to the UBO
alignas(16) math::float4 morphWeights; // morph weights (we could easily have 8 using half)
alignas(16) uint32_t morphTargetCount;
uint32_t flags; // see packFlags() below
uint32_t channels; // 0x000000ll
uint32_t objectId; // used for picking
@@ -227,6 +235,14 @@ struct PerRenderableUibBone { // NOLINT(cppcoreguidelines-pro-type-member-init)
static_assert(CONFIG_MAX_BONE_COUNT * sizeof(PerRenderableUibBone) <= 16384,
"PerRenderableUibBone exceed max UBO size");
struct alignas(16) PerRenderableMorphingUib {
static constexpr utils::StaticString _name{ "MorphingUniforms" };
// The array stride(the bytes between array elements) is always rounded up to the size of a vec4 in std140.
math::float4 weights[CONFIG_MAX_MORPH_TARGET_COUNT];
};
static_assert(sizeof(PerRenderableMorphingUib) <= 16384,
"PerRenderableMorphingUib exceed max UBO size");
} // namespace filament
#endif // TNT_FILABRIDGE_UIBSTRUCTS_H
@@ -185,6 +185,10 @@ namespace filament {
if (isValidDepthVariant(variantKey)) {
return variantKey;
}
// if shadow receiver is disabled, turn off VSM
if (isLit && !(variantKey & SHADOW_RECEIVER)) {
return variantKey & ~VSM;
}
// when the shading mode is unlit, remove all the lighting variants
return isLit ? variantKey : (variantKey & UNLIT_MASK);
}
+15
View File
@@ -66,12 +66,27 @@ SamplerInterfaceBlock const& SibGenerator::getPerViewSib(uint8_t variantKey) noe
return v.hasVsm() ? sibVsm : sibPcf;
}
SamplerInterfaceBlock const& SibGenerator::getPerRenderPrimitiveMorphingSib(uint8_t variantKey) noexcept {
using Type = SamplerInterfaceBlock::Type;
using Format = SamplerInterfaceBlock::Format;
using Precision = SamplerInterfaceBlock::Precision;
static SamplerInterfaceBlock sib = SamplerInterfaceBlock::Builder()
.name("Morphing")
.add("targets", Type::SAMPLER_2D_ARRAY, Format::FLOAT, Precision::HIGH)
.build();
return sib;
}
SamplerInterfaceBlock const* SibGenerator::getSib(uint8_t bindingPoint, uint8_t variantKey) noexcept {
switch (bindingPoint) {
case BindingPoints::PER_VIEW:
return &getPerViewSib(variantKey);
case BindingPoints::PER_RENDERABLE:
return nullptr;
case BindingPoints::PER_RENDERABLE_MORPHING:
return &getPerRenderPrimitiveMorphingSib(variantKey);
case BindingPoints::LIGHTS:
return nullptr;
default:
@@ -190,6 +190,7 @@ public:
using MaterialDomain = filament::MaterialDomain;
using RefractionMode = filament::RefractionMode;
using RefractionType = filament::RefractionType;
using ReflectionMode = filament::ReflectionMode;
using VertexAttribute = filament::VertexAttribute;
using ShaderQuality = filament::ShaderQuality;
@@ -461,6 +462,9 @@ public:
//! Specify the refraction type
MaterialBuilder& refractionType(RefractionType refractionType) noexcept;
//! Specifies how reflections should be rendered (default is DEFAULT).
MaterialBuilder& reflectionMode(ReflectionMode mode) noexcept;
//! Specifies how transparent objects should be rendered (default is DEFAULT).
MaterialBuilder& transparencyMode(TransparencyMode mode) noexcept;
@@ -702,6 +706,7 @@ private:
MaterialDomain mMaterialDomain = MaterialDomain::SURFACE;
RefractionMode mRefractionMode = RefractionMode::NONE;
RefractionType mRefractionType = RefractionType::SOLID;
ReflectionMode mReflectionMode = ReflectionMode::DEFAULT;
Interpolation mInterpolation = Interpolation::SMOOTH;
VertexDomain mVertexDomain = VertexDomain::OBJECT;
TransparencyMode mTransparencyMode = TransparencyMode::DEFAULT;
+7
View File
@@ -374,6 +374,11 @@ MaterialBuilder& MaterialBuilder::transparencyMode(TransparencyMode mode) noexce
return *this;
}
MaterialBuilder& MaterialBuilder::reflectionMode(ReflectionMode mode) noexcept {
mReflectionMode = mode;
return *this;
}
MaterialBuilder& MaterialBuilder::platform(Platform platform) noexcept {
mPlatform = platform;
return *this;
@@ -480,6 +485,7 @@ void MaterialBuilder::prepareToBuild(MaterialInfo& info) noexcept {
info.specularAOSet = mSpecularAOSet;
info.refractionMode = mRefractionMode;
info.refractionType = mRefractionType;
info.reflectionMode = mReflectionMode;
info.quality = mShaderQuality;
info.hasCustomSurfaceShading = mCustomSurfaceShading;
}
@@ -1026,6 +1032,7 @@ void MaterialBuilder::writeCommonChunks(ChunkContainer& container, MaterialInfo&
container.addSimpleChild<uint8_t>(ChunkType::MaterialBlendingMode, static_cast<uint8_t>(mBlendingMode));
container.addSimpleChild<uint8_t>(ChunkType::MaterialTransparencyMode, static_cast<uint8_t>(mTransparencyMode));
container.addSimpleChild<uint8_t>(ChunkType::MaterialReflectionMode, static_cast<uint8_t>(mReflectionMode));
container.addSimpleChild<bool>(ChunkType::MaterialDepthWriteSet, mDepthWriteSet);
container.addSimpleChild<bool>(ChunkType::MaterialColorWrite, mColorWrite);
container.addSimpleChild<bool>(ChunkType::MaterialDepthWrite, mDepthWrite);
+18 -2
View File
@@ -117,8 +117,16 @@ UniformInterfaceBlock const& UibGenerator::getPerViewUib() noexcept {
.add("nearOverFarMinusNear", 1, UniformInterfaceBlock::Type::FLOAT, Precision::HIGH)
.add("temporalNoise", 1, UniformInterfaceBlock::Type::FLOAT, Precision::HIGH)
// Screen-space reflection parameters
.add("ssrReprojection", 1, UniformInterfaceBlock::Type::MAT4, Precision::HIGH)
.add("ssrProjectToPixelMatrix", 1, UniformInterfaceBlock::Type::MAT4, Precision::HIGH)
.add("ssrThickness", 1, UniformInterfaceBlock::Type::FLOAT)
.add("ssrBias", 1, UniformInterfaceBlock::Type::FLOAT)
.add("ssrDistance", 1, UniformInterfaceBlock::Type::FLOAT)
.add("ssrStride", 1, UniformInterfaceBlock::Type::FLOAT)
// bring PerViewUib to 2 KiB
.add("padding2", 58, UniformInterfaceBlock::Type::FLOAT4)
.add("padding3", 49, UniformInterfaceBlock::Type::FLOAT4)
.build();
return uib;
}
@@ -128,7 +136,7 @@ UniformInterfaceBlock const& UibGenerator::getPerRenderableUib() noexcept {
.name(PerRenderableUib::_name)
.add("worldFromModelMatrix", 1, UniformInterfaceBlock::Type::MAT4, Precision::HIGH)
.add("worldFromModelNormalMatrix", 1, UniformInterfaceBlock::Type::MAT3, Precision::HIGH)
.add("morphWeights", 1, UniformInterfaceBlock::Type::FLOAT4, Precision::HIGH)
.add("morphTargetCount", 1, UniformInterfaceBlock::Type::UINT)
.add("flags", 1, UniformInterfaceBlock::Type::UINT)
.add("channels", 1, UniformInterfaceBlock::Type::UINT)
.add("objectId", 1, UniformInterfaceBlock::Type::UINT)
@@ -161,6 +169,14 @@ UniformInterfaceBlock const& UibGenerator::getPerRenderableBonesUib() noexcept {
return uib;
}
UniformInterfaceBlock const& UibGenerator::getPerRenderableMorphingUib() noexcept {
static UniformInterfaceBlock uib = UniformInterfaceBlock::Builder()
.name(PerRenderableMorphingUib::_name)
.add("weights", CONFIG_MAX_MORPH_TARGET_COUNT, UniformInterfaceBlock::Type::FLOAT4)
.build();
return uib;
}
UniformInterfaceBlock const& UibGenerator::getFroxelRecordUib() noexcept {
static UniformInterfaceBlock uib = UniformInterfaceBlock::Builder()
.name(FroxelRecordUib::_name)
+1
View File
@@ -28,6 +28,7 @@ public:
static UniformInterfaceBlock const& getLightsUib() noexcept;
static UniformInterfaceBlock const& getShadowUib() noexcept;
static UniformInterfaceBlock const& getPerRenderableBonesUib() noexcept;
static UniformInterfaceBlock const& getPerRenderableMorphingUib() noexcept;
static UniformInterfaceBlock const& getFroxelRecordUib() noexcept;
// When adding an UBO here, make sure to also update
// FMaterial::getSurfaceProgramSlow and FMaterial::getPostProcessProgramSlow if needed
@@ -611,6 +611,7 @@ io::sstream& CodeGenerator::generateShaderLit(io::sstream& out, ShaderType type,
if (shading != Shading::UNLIT) {
out << SHADERS_AMBIENT_OCCLUSION_FS_DATA;
out << SHADERS_LIGHT_REFLECTIONS_FS_DATA;
out << SHADERS_LIGHT_INDIRECT_FS_DATA;
}
if (variant.hasDirectionalLighting()) {
+1
View File
@@ -48,6 +48,7 @@ struct UTILS_PUBLIC MaterialInfo {
filament::SpecularAmbientOcclusion specularAO;
filament::RefractionMode refractionMode;
filament::RefractionType refractionType;
filament::ReflectionMode reflectionMode;
filament::AttributeBitset requiredAttributes;
filament::BlendingMode blendingMode;
filament::BlendingMode postLightingBlendingMode;
+19 -8
View File
@@ -218,14 +218,6 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel,
if (variant.hasSkinningOrMorphing()) {
attributes.set(VertexAttribute::BONE_INDICES);
attributes.set(VertexAttribute::BONE_WEIGHTS);
attributes.set(VertexAttribute::MORPH_POSITION_0);
attributes.set(VertexAttribute::MORPH_POSITION_1);
attributes.set(VertexAttribute::MORPH_POSITION_2);
attributes.set(VertexAttribute::MORPH_POSITION_3);
attributes.set(VertexAttribute::MORPH_TANGENTS_0);
attributes.set(VertexAttribute::MORPH_TANGENTS_1);
attributes.set(VertexAttribute::MORPH_TANGENTS_2);
attributes.set(VertexAttribute::MORPH_TANGENTS_3);
}
CodeGenerator::generateShaderInputs(vs, ShaderType::VERTEX, attributes, interpolation);
@@ -247,6 +239,12 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel,
cg.generateUniforms(vs, ShaderType::VERTEX,
BindingPoints::PER_RENDERABLE_BONES,
UibGenerator::getPerRenderableBonesUib());
cg.generateUniforms(vs, ShaderType::VERTEX,
BindingPoints::PER_RENDERABLE_MORPHING,
UibGenerator::getPerRenderableMorphingUib());
cg.generateSamplers(vs,
material.samplerBindings.getBlockOffset(BindingPoints::PER_RENDERABLE_MORPHING),
SibGenerator::getPerRenderPrimitiveMorphingSib(variantKey));
}
cg.generateUniforms(vs, ShaderType::VERTEX,
BindingPoints::PER_MATERIAL_INSTANCE, material.uib);
@@ -310,6 +308,11 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel,
auto specularAO = material.specularAOSet ? material.specularAO : defaultSpecularAO;
CodeGenerator::generateDefine(fs, "SPECULAR_AMBIENT_OCCLUSION", uint32_t(specularAO));
// Currently, we only support either screen-space refractions or reflections.
// The HAS_REFRACTION/HAS_REFLECTIONS defines signify if refraction/reflections are supported by
// the material, yet only one technique will be selected at runtime.
// TODO: support simultaneous screen-space refractions and reflections.
CodeGenerator::generateDefine(fs, "HAS_REFRACTION", material.refractionMode != RefractionMode::NONE);
if (material.refractionMode != RefractionMode::NONE) {
CodeGenerator::generateDefine(fs, "REFRACTION_MODE_CUBEMAP", uint32_t(RefractionMode::CUBEMAP));
@@ -337,6 +340,14 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel,
}
}
CodeGenerator::generateDefine(fs, "HAS_REFLECTIONS", material.reflectionMode != ReflectionMode::DEFAULT);
if (material.reflectionMode != ReflectionMode::DEFAULT) {
CodeGenerator::generateDefine(fs, "REFLECTION_MODE_SCREEN_SPACE", uint32_t(ReflectionMode::SCREEN_SPACE));
if (material.reflectionMode == ReflectionMode::SCREEN_SPACE) {
CodeGenerator::generateDefine(fs, "REFLECTION_MODE", "REFLECTION_MODE_SCREEN_SPACE");
}
}
bool multiBounceAO = material.multiBounceAOSet ?
material.multiBounceAO : !isMobileTarget(shaderModel);
CodeGenerator::generateDefine(fs, "MULTI_BOUNCE_AMBIENT_OCCLUSION", multiBounceAO ? 1u : 0u);
@@ -203,6 +203,16 @@ public:
*/
Animator* getAnimator() noexcept;
/**
* Updates the morphing weights in the given entity.
*/
void setMorphWeights(utils::Entity entity, const float* weights, size_t count);
/**
* Gets the number of morphing in the given entity.
*/
int getMorphTargetCount(utils::Entity entity) noexcept;
/**
* Lazily creates a single LINES renderable that draws the transformed bounding-box hierarchy
* for diagnostic purposes. The wireframe is owned by the asset so clients should not delete it.
@@ -52,6 +52,10 @@ struct ResourceConfiguration {
//! If true, computes the bounding boxes of all \c POSITION attibutes. Well formed glTF files
//! do not need this, but it is useful for robustness.
bool recomputeBoundingBoxes;
//! If true, ignore skinned primitives bind transform when compute bounding box. Implicitly true
//! for instanced asset. Only applicable when recomputeBoundingBoxes is set to true
bool ignoreBindTransform;
};
/**
+1
View File
@@ -8,6 +8,7 @@ material {
flipUV : false,
specularAmbientOcclusion : simple,
specularAntiAliasing : true,
reflections : screenspace,
parameters : [
// Base Color
+1
View File
@@ -9,6 +9,7 @@ material {
flipUV : false,
specularAmbientOcclusion : simple,
specularAntiAliasing : true,
reflections : screenspace,
parameters : [
// Base Color
@@ -10,6 +10,7 @@ material {
specularAntiAliasing : true,
refractionMode: screenspace,
refractionType: thin,
reflections: screenspace,
parameters : [
// Base Color
+1
View File
@@ -9,6 +9,7 @@ material {
specularAmbientOcclusion : simple,
specularAntiAliasing : true,
clearCoatIorChange : false,
reflections : screenspace,
parameters : [
{ type : float3, name : specularFactor },
+1
View File
@@ -10,6 +10,7 @@ material {
specularAntiAliasing : true,
refractionMode: screenspace,
refractionType: solid,
reflections: screenspace,
parameters : [
// Base Color
+3 -3
View File
@@ -176,7 +176,6 @@ Animator::Animator(FFilamentAsset* asset, FFilamentInstance* instance) {
mImpl->instance = instance;
mImpl->renderableManager = &asset->mEngine->getRenderableManager();
mImpl->transformManager = &asset->mEngine->getTransformManager();
mImpl->morpher = new MorphHelper(asset, instance);
const cgltf_data* srcAsset = asset->mSourceAsset->hierarchy;
const cgltf_animation* srcAnims = srcAsset->animations;
@@ -222,6 +221,8 @@ Animator::Animator(FFilamentAsset* asset, FFilamentInstance* instance) {
}
}
}
mImpl->morpher = asset->mMorpher;
}
void Animator::addInstance(FFilamentInstance* instance) {
@@ -235,7 +236,6 @@ void Animator::addInstance(FFilamentInstance* instance) {
}
Animator::~Animator() {
delete mImpl->morpher;
delete mImpl;
}
@@ -461,7 +461,7 @@ void AnimatorImpl::applyAnimation(const Channel& channel, float t, size_t prevIn
}
}
morpher->applyWeights(channel.targetEntity, weights.data(), weights.size());
morpher->setWeights(channel.targetEntity, weights.data(), weights.size());
return;
}
}
+9 -27
View File
@@ -28,6 +28,7 @@
#include <filament/IndexBuffer.h>
#include <filament/LightManager.h>
#include <filament/Material.h>
#include <filament/MorphTargetBuffer.h>
#include <filament/RenderableManager.h>
#include <filament/Scene.h>
#include <filament/TextureSampler.h>
@@ -520,14 +521,15 @@ void FAssetLoader::createRenderable(const cgltf_node* node, Entity entity, const
// node weights are provided, they override the ones specified on the mesh.
if (numMorphTargets > 0) {
RenderableManager::Instance renderable = mRenderableManager.getInstance(entity);
float4 weights(0, 0, 0, 0);
for (cgltf_size i = 0; i < std::min(MAX_MORPH_TARGETS, mesh->weights_count); ++i) {
const auto size = std::min(MAX_MORPH_TARGETS, std::max(mesh->weights_count, node->weights_count));
std::vector<float> weights(size);
for (cgltf_size i = 0, c = std::min(size, mesh->weights_count); i < c; ++i) {
weights[i] = mesh->weights[i];
}
for (cgltf_size i = 0; i < std::min(MAX_MORPH_TARGETS, node->weights_count); ++i) {
for (cgltf_size i = 0, c = std::min(size, node->weights_count); i < c; ++i) {
weights[i] = node->weights[i];
}
mRenderableManager.setMorphWeights(renderable, weights);
mRenderableManager.setMorphWeights(renderable, weights.data(), size);
}
}
@@ -688,15 +690,11 @@ bool FAssetLoader::createPrimitive(const cgltf_primitive* inPrim, Primitive* out
cgltf_size targetsCount = inPrim->targets_count;
// There is no need to emit a warning if there are more than 4 targets. This is only the base
// VertexBuffer and more might be created by MorphHelper.
if (targetsCount > MAX_MORPH_TARGETS) {
utils::slog.w << "WARNING: Exceeded max morph target count of " << MAX_MORPH_TARGETS << utils::io::endl;
targetsCount = MAX_MORPH_TARGETS;
}
constexpr int baseTangentsAttr = (int) VertexAttribute::MORPH_TANGENTS_0;
constexpr int basePositionAttr = (int) VertexAttribute::MORPH_POSITION_0;
for (cgltf_size targetIndex = 0; targetIndex < targetsCount; targetIndex++) {
const cgltf_morph_target& morphTarget = inPrim->targets[targetIndex];
for (cgltf_size aindex = 0; aindex < morphTarget.attributes_count; aindex++) {
@@ -705,17 +703,8 @@ bool FAssetLoader::createPrimitive(const cgltf_primitive* inPrim, Primitive* out
const cgltf_attribute_type atype = attribute.type;
const int morphId = targetIndex + 1;
// The glTF tangent data is ignored here, but honored in ResourceLoader.
if (atype == cgltf_attribute_type_tangent) {
continue;
}
if (atype == cgltf_attribute_type_normal) {
VertexAttribute attr = (VertexAttribute) (baseTangentsAttr + targetIndex);
vbb.attribute(attr, slot, VertexBuffer::AttributeType::SHORT4);
vbb.normalized(attr);
outPrim->morphTangents[targetIndex] = slot;
addBufferSlot({&mResult->mGenerateTangents, atype, slot++, morphId});
// The glTF normal and tangent data are ignored here, but honored in ResourceLoader.
if (atype == cgltf_attribute_type_normal || atype == cgltf_attribute_type_tangent) {
continue;
}
@@ -736,13 +725,6 @@ bool FAssetLoader::createPrimitive(const cgltf_primitive* inPrim, Primitive* out
slog.e << "Unsupported accessor type in " << name << io::endl;
return false;
}
const int stride = (fatype == actualType) ? accessor->stride : 0;
VertexAttribute attr = (VertexAttribute) (basePositionAttr + targetIndex);
vbb.attribute(attr, slot, fatype, 0, stride);
vbb.normalized(attr, accessor->normalized);
outPrim->morphPositions[targetIndex] = slot;
addBufferSlot({accessor, atype, slot++, morphId});
}
}
+6 -3
View File
@@ -65,13 +65,13 @@ namespace gltfio {
class Animator;
class Wireframe;
class MorphHelper;
// Encapsulates VertexBuffer::setBufferAt() or IndexBuffer::setBuffer().
struct BufferSlot {
const cgltf_accessor* accessor;
cgltf_attribute_type attribute;
int bufferIndex; // for vertex buffers only
int morphTarget; // 0 if no morphing, otherwise 1-based index
filament::VertexBuffer* vertexBuffer;
filament::IndexBuffer* indexBuffer;
};
@@ -97,8 +97,6 @@ struct Primitive {
filament::IndexBuffer* indices = nullptr;
filament::Aabb aabb; // object-space bounding box
UvMap uvmap; // mapping from each glTF UV set to either UV0 or UV1 (8 bytes)
uint8_t morphPositions[4] = {}; // Buffer indices for MORPH_POSITION_0, MORPH_POSITION_1 etc.
uint8_t morphTangents[4] = {}; // Buffer indices for MORPH_TANGENTS_0, MORPH_TANGENTS_1, etc.
};
using MeshCache = tsl::robin_map<const cgltf_mesh*, std::vector<Primitive>>;
@@ -194,6 +192,10 @@ struct FFilamentAsset : public FilamentAsset {
Animator* getAnimator() noexcept;
void setMorphWeights(utils::Entity entity , const float* weights, size_t count) noexcept;
int getMorphTargetCount(utils::Entity entity) noexcept;
utils::Entity getWireframe() noexcept;
filament::Engine* getEngine() const noexcept {
@@ -243,6 +245,7 @@ struct FFilamentAsset : public FilamentAsset {
std::vector<FFilamentInstance*> mInstances;
SkinVector mSkins; // unused for instanced assets
Animator* mAnimator = nullptr;
MorphHelper* mMorpher = nullptr;
Wireframe* mWireframe = nullptr;
bool mResourcesLoaded = false;
DependencyGraph mDependencyGraph;
+23
View File
@@ -22,6 +22,7 @@
#include <utils/Log.h>
#include <utils/NameComponentManager.h>
#include "MorphHelper.h"
#include "Wireframe.h"
using namespace filament;
@@ -41,6 +42,7 @@ FFilamentAsset::~FFilamentAsset() {
delete mAnimator;
delete mWireframe;
delete mMorpher;
mEngine->destroy(mRoot);
mEntityManager->destroy(mRoot);
@@ -95,6 +97,19 @@ Animator* FFilamentAsset::getAnimator() noexcept {
return mAnimator;
}
void FFilamentAsset::setMorphWeights(utils::Entity entity, const float* weights, size_t count) noexcept {
if (mResourcesLoaded) {
mMorpher->setWeights(entity, weights, count);
}
}
int FFilamentAsset::getMorphTargetCount(utils::Entity entity) noexcept {
if (mResourcesLoaded) {
return mMorpher->getTargetCount(entity);
}
return 0;
}
Entity FFilamentAsset::getWireframe() noexcept {
if (!mWireframe) {
mWireframe = new Wireframe(this);
@@ -274,6 +289,14 @@ Animator* FilamentAsset::getAnimator() noexcept {
return upcast(this)->getAnimator();
}
void FilamentAsset::setMorphWeights(utils::Entity entity, const float* weights, size_t count) {
return upcast(this)->setMorphWeights(entity, weights, count);
}
int FilamentAsset::getMorphTargetCount(utils::Entity entity) noexcept {
return upcast(this)->getMorphTargetCount(entity);
}
Entity FilamentAsset::getWireframe() noexcept {
return upcast(this)->getWireframe();
}
+1
View File
@@ -324,6 +324,7 @@ static Material* createMaterial(Engine* engine, const MaterialKey& config, const
.transparencyMode(config.doubleSided ?
MaterialBuilder::TransparencyMode::TWO_PASSES_TWO_SIDES :
MaterialBuilder::TransparencyMode::DEFAULT)
.reflectionMode(MaterialBuilder::ReflectionMode::SCREEN_SPACE)
.targetApi(filamat::targetApiFromBackend(engine->getBackend()));
if (!optimizeShaders) {
+41 -101
View File
@@ -16,11 +16,12 @@
#include "MorphHelper.h"
#include <filament/BufferObject.h>
#include <filament/RenderableManager.h>
#include <filament/VertexBuffer.h>
#include <utils/JobSystem.h>
#include <math/norm.h>
#include <filament/MorphTargetBuffer.h>
#include "GltfEnums.h"
#include "TangentsJob.h"
using namespace filament;
@@ -45,14 +46,6 @@ static bool isSubsetOf(ubyte4 a, ubyte4 b) {
return true;
}
static int indexOf(int a, ubyte4 b) {
if (a == b.x) return 0;
if (a == b.y) return 1;
if (a == b.z) return 2;
if (a == b.w) return 3;
return -1;
}
MorphHelper::MorphHelper(FFilamentAsset* asset, FFilamentInstance* inst) : mAsset(asset),
mInstance(inst) {
NodeMap& sourceNodes = asset->isInstanced() ? asset->mInstances[0]->nodeMap : asset->mNodeMap;
@@ -62,7 +55,7 @@ MorphHelper::MorphHelper(FFilamentAsset* asset, FFilamentInstance* inst) : mAsse
if (mesh) {
cgltf_primitive const* prims = mesh->primitives;
for (cgltf_size pi = 0, count = mesh->primitives_count; pi < count; ++pi) {
addPrimitive(mesh, pi, &mMorphTable[pair.second]);
addPrimitive(mesh, pi, pair.second);
}
}
}
@@ -72,96 +65,50 @@ MorphHelper::~MorphHelper() {
auto engine = mAsset->mEngine;
for (auto& entry : mMorphTable) {
for (auto& prim : entry.second.primitives) {
for (auto& target : prim.targets) {
engine->destroy(target.bufferObject);
if (prim.targets) {
engine->destroy(prim.targets);
}
}
}
}
void MorphHelper::applyWeights(Entity entity, float const* weights, size_t count) noexcept {
void MorphHelper::setWeights(Entity entity, float const* weights, int count) noexcept {
auto& engine = *mAsset->mEngine;
auto renderableManager = &engine.getRenderableManager();
auto renderable = renderableManager->getInstance(entity);
auto& rcm = engine.getRenderableManager();
rcm.setMorphWeights(rcm.getInstance(entity), weights, count);
}
// If there are 4 or fewer targets, we can simply re-use the original VertexBuffer.
if (count <= 4) {
float4 vec{};
for (size_t i = 0; i < count; i++) {
vec[i] = weights[i];
}
renderableManager->setMorphWeights(renderable, vec);
return;
}
// We honor up to 255 weights because our set representation is a 4-tuple of bytes, with one
// slot reserved for a sentinel value. Note that 255 is much more than the glTF min spec of 4.
count = std::min(count, size_t(255));
// Make a copy of the weights because we want to re-order them.
auto& sorted = mPartiallySortedWeights;
sorted.clear();
sorted.insert(sorted.begin(), weights, weights + count);
// Find the four highest weights in O(n) by doing a partial sort.
std::nth_element(sorted.begin(), sorted.begin() + 4, sorted.end(), [](float a, float b) {
return a > b;
});
// Find the "primary indices" which are the indices of the four highest weights. This is O(n).
ubyte4 primaryIndices = {kUnused, kUnused, kUnused, kUnused};
for (size_t index = 0, primary = 0; index < count && primary < 4; ++index) {
const float w = weights[index];
if (w > 0 && (w == sorted[0] || w == sorted[1] || w == sorted[2] || w == sorted[3])) {
primaryIndices[primary++] = index;
int MorphHelper::getTargetCount(Entity entity) const noexcept {
if (mMorphTable.count(entity)) {
auto& primitive = mMorphTable.at(entity).primitives;
if (!primitive.empty() && primitive[0].targets) {
return primitive[0].targets->getCount();
}
}
// Swap out the buffer objects for the primary indices.
for (const auto& prim : mMorphTable[entity].primitives) {
for (const auto& target : prim.targets) {
const int index = indexOf(target.morphTargetIndex, primaryIndices);
if (index > -1) {
assert_invariant(primaryIndices[index] == target.morphTargetIndex);
VertexBuffer* vb = prim.vertexBuffer;
const int bufferObjectSlot = target.type == cgltf_attribute_type_position ?
prim.positions[index] : prim.tangents[index];
// Slot 0 is always used for the base position so if it's getting clobbered, then
// something is seriously wrong. Should never occur, assert just in case.
assert_invariant(bufferObjectSlot != 0);
vb->setBufferObjectAt(engine, bufferObjectSlot, target.bufferObject);
// Do not break out early because there could be more than one target entry for this
// particular target index (e.g. positions + tangents).
}
}
}
// Finally, set the 4-tuple uniform for the weight values by derefing the primary indices.
// Note that we first create a "safe set" by replacing the unused sentinel with zero.
float4 highest;
for (int i = 0; i < 4; i++) {
highest[i] = (primaryIndices[i] == kUnused) ? 0 : weights[primaryIndices[i]];
}
renderableManager->setMorphWeights(renderable, highest);
return 0;
}
// This method copies various morphing-related data from the FilamentAsset MeshCache primitive
// (which lives in transient memory) into the MorphHelper primitive (which will stay resident).
void MorphHelper::addPrimitive(cgltf_mesh const* mesh, int primitiveIndex, TableEntry* entry) {
void MorphHelper::addPrimitive(cgltf_mesh const* mesh, int primitiveIndex, Entity entity){
auto& entry = mMorphTable[entity];
auto& engine = *mAsset->mEngine;
const cgltf_primitive& prim = mesh->primitives[primitiveIndex];
const auto& gltfioPrim = mAsset->mMeshCache.at(mesh)[primitiveIndex];
VertexBuffer* vertexBuffer = gltfioPrim.vertices;
entry.primitives.push_back({ nullptr });
entry->primitives.push_back({ vertexBuffer });
auto& morphHelperPrim = entry->primitives.back();
auto& morphHelperPrim = entry.primitives.back();
for (int i = 0; i < 4; i++) {
morphHelperPrim.positions[i] = gltfioPrim.morphPositions[i];
morphHelperPrim.tangents[i] = gltfioPrim.morphTangents[i];
if (prim.targets_count) {
morphHelperPrim.targets = MorphTargetBuffer::Builder()
.vertexCount(vertexBuffer->getVertexCount())
.count(prim.targets_count)
.build(engine);
auto& rcm = engine.getRenderableManager();
rcm.setMorphTargetBufferAt(rcm.getInstance(entity),
primitiveIndex, morphHelperPrim.targets);
}
const cgltf_accessor* previous = nullptr;
@@ -175,19 +122,15 @@ void MorphHelper::addPrimitive(cgltf_mesh const* mesh, int primitiveIndex, Table
continue;
}
if (atype == cgltf_attribute_type_normal) {
// TODO: use JobSystem for this, like what we do for non-morph tangents.
TangentsJob job;
TangentsJob::Params params = { .in = { &prim, targetIndex } };
TangentsJob::run(&params);
if (params.out.results) {
const size_t size = params.out.vertexCount * sizeof(short4);
BufferObject* bufferObject = BufferObject::Builder().size(size).build(engine);
VertexBuffer::BufferDescriptor bd(params.out.results, size, FREE_CALLBACK);
bufferObject->setBuffer(engine, std::move(bd));
params.out.results = nullptr;
morphHelperPrim.targets.push_back({bufferObject, targetIndex, atype});
morphHelperPrim.targets->setTangentsAt(engine, targetIndex,
params.out.results, params.out.vertexCount);
free(params.out.results);
}
continue;
}
@@ -201,19 +144,16 @@ void MorphHelper::addPrimitive(cgltf_mesh const* mesh, int primitiveIndex, Table
if (accessor->buffer_view) {
auto bufferData = (const uint8_t*) accessor->buffer_view->buffer->data;
assert_invariant(bufferData);
const uint8_t* data = computeBindingOffset(accessor) + bufferData;
const uint32_t size = computeBindingSize(accessor);
auto* data = computeBindingOffset(accessor) + bufferData;
// This creates a copy because we don't know when the user will free the cgltf
// source data. For non-morphed vertex buffers, we use a sharing mechanism to
// prevent copies, but here we just want to keep it as simple as possible.
uint8_t* clone = (uint8_t*) malloc(size);
memcpy(clone, data, size);
BufferObject* bufferObject = BufferObject::Builder().size(size).build(engine);
VertexBuffer::BufferDescriptor bd(clone, size, FREE_CALLBACK);
bufferObject->setBuffer(engine, std::move(bd));
morphHelperPrim.targets.push_back({bufferObject, targetIndex, atype});
if (accessor->type == cgltf_type_vec3) {
morphHelperPrim.targets->setPositionsAt(engine, targetIndex,
(const float3*) data, vertexBuffer->getVertexCount());
} else {
assert_invariant(accessor->type == cgltf_type_vec4);
morphHelperPrim.targets->setPositionsAt(engine, targetIndex,
(const float4*) data, vertexBuffer->getVertexCount());
}
}
}
}
+11 -16
View File
@@ -14,9 +14,14 @@
* limitations under the License.
*/
#ifndef GLTFIO_MORPHHELPER_H
#define GLTFIO_MORPHHELPER_H
#include "FFilamentAsset.h"
#include "FFilamentInstance.h"
#include <filament/MorphTargetBuffer.h>
#include <math/vec4.h>
#include <tsl/robin_map.h>
@@ -44,35 +49,25 @@ public:
MorphHelper(FFilamentAsset* asset, FFilamentInstance* inst);
~MorphHelper();
/**
* Picks the 4 most influential weights and applies them to the target entity.
*/
void applyWeights(Entity targetEntity, float const* weights, size_t count) noexcept;
void setWeights(Entity entity, float const* weights, int count) noexcept;
int getTargetCount(Entity entity) const noexcept;
private:
struct GltfTarget {
filament::BufferObject* bufferObject;
int morphTargetIndex;
cgltf_attribute_type type;
};
struct GltfPrimitive {
filament::VertexBuffer* vertexBuffer;
uint8_t positions[4];
uint8_t tangents[4];
std::vector<GltfTarget> targets; // TODO: flatten this?
filament::MorphTargetBuffer* targets;
};
struct TableEntry {
std::vector<GltfPrimitive> primitives; // TODO: flatten this?
};
void addPrimitive(cgltf_mesh const* mesh, int primitiveIndex, TableEntry* entry);
void addPrimitive(cgltf_mesh const* mesh, int primitiveIndex, Entity entity);
std::vector<float> mPartiallySortedWeights;
tsl::robin_map<Entity, TableEntry> mMorphTable;
const FFilamentAsset* mAsset;
const FFilamentInstance* mInstance;
};
} // namespace gltfio
#endif // GLTFIO_MORPHHELPER_H
+98 -24
View File
@@ -20,6 +20,7 @@
#include "GltfEnums.h"
#include "FFilamentAsset.h"
#include "TangentsJob.h"
#include "MorphHelper.h"
#include "upcast.h"
#include <filament/BufferObject.h>
@@ -86,13 +87,19 @@ struct ResourceLoader::Impl {
mEngine = config.engine;
mNormalizeSkinningWeights = config.normalizeSkinningWeights;
mRecomputeBoundingBoxes = config.recomputeBoundingBoxes;
mIgnoreBindTransform = config.ignoreBindTransform;
}
Engine* mEngine;
bool mNormalizeSkinningWeights;
bool mRecomputeBoundingBoxes;
bool mIgnoreBindTransform;
std::string mGltfPath;
// This is used to calculate skinIndex when updateBoundingBoxes, so that the correspondency between
// cgltf_node* and FFilamentInstance::Skin can be retrieved. This pointer doesn't need to be freed.
cgltf_skin* cgltfSkinBaseAddress;
// User-provided resource data with URI string keys, populated with addResourceData().
// This is used on platforms without traditional file systems, such as Android, iOS, and WebGL.
UriDataCache mUriDataCache;
@@ -458,6 +465,11 @@ bool ResourceLoader::loadResources(FFilamentAsset* asset, bool async) {
}
if (pImpl->mRecomputeBoundingBoxes) {
// asset->mSkins is unused for instanced assets
if (!pImpl->mIgnoreBindTransform) {
pImpl->mIgnoreBindTransform = asset->isInstanced();
}
pImpl->cgltfSkinBaseAddress = &gltf->skins[0];
updateBoundingBoxes(asset);
}
@@ -861,15 +873,10 @@ void ResourceLoader::Impl::computeTangents(FFilamentAsset* asset) {
// Collect all TANGENT vertex attribute slots that need to be populated.
tsl::robin_map<VertexBuffer*, uint8_t> baseTangents;
tsl::robin_map<VertexBuffer*, uint8_t> morphTangents[4];
for (auto slot : asset->mBufferSlots) {
if (slot.accessor != kGenerateTangents && slot.accessor != kGenerateNormals) {
continue;
}
if (slot.morphTarget) {
morphTangents[slot.morphTarget - 1][slot.vertexBuffer] = slot.bufferIndex;
continue;
}
baseTangents[slot.vertexBuffer] = slot.bufferIndex;
}
@@ -885,13 +892,6 @@ void ResourceLoader::Impl::computeTangents(FFilamentAsset* asset) {
if (iter != baseTangents.end()) {
jobParams.emplace_back(Params {{ pair.first }, {vb, iter->second }});
}
for (int morphTarget = 0; morphTarget < 4; morphTarget++) {
const auto& tangents = morphTangents[morphTarget];
auto iter = tangents.find(vb);
if (iter != tangents.end()) {
jobParams.emplace_back(Params {{ pair.first, morphTarget }, {vb, iter->second }});
}
}
}
// Kick off jobs for computing tangent frames.
@@ -912,6 +912,8 @@ void ResourceLoader::Impl::computeTangents(FFilamentAsset* asset) {
params.out.results, bo->getByteCount(), FREE_CALLBACK));
params.context.vb->setBufferObjectAt(*mEngine, params.context.slot, bo);
}
asset->mMorpher = new MorphHelper(asset, nullptr);
}
ResourceLoader::Impl::~Impl() {
@@ -1005,27 +1007,99 @@ void ResourceLoader::updateBoundingBoxes(FFilamentAsset* asset) const {
*result = aabb;
};
// Collect all mesh primitives that we wish to find bounds for.
std::vector<cgltf_primitive const*> prims;
const size_t posAttrSize = cgltf_num_components(cgltf_type_vec3);
const size_t skinningAttrSize = cgltf_num_components(cgltf_type_vec4);
auto computeBoundingBoxSkinned = [&](const cgltf_primitive* prim, const Skin* skin, Aabb* result) {
Aabb aabb;
std::vector<mat4f> inverseGlobalTransforms(skin->targets.size());
for (size_t i = 0; i < skin->targets.size(); i++) {
auto xformable = tm.getInstance(skin->targets[i]);
if (xformable) {
inverseGlobalTransforms[i] = inverse(tm.getWorldTransform(xformable));
}
}
std::vector<float> verts;
std::vector<float> rawJoints;
std::vector<float> weights;
for (cgltf_size slot = 0; slot < prim->attributes_count; slot++) {
const cgltf_attribute& attr = prim->attributes[slot];
const cgltf_accessor* accessor = attr.data;
if (attr.type == cgltf_attribute_type_position && cgltf_num_components(accessor->type) >= posAttrSize) {
verts.resize(accessor->count * posAttrSize);
cgltf_accessor_unpack_floats(accessor, &verts[0], accessor->count * posAttrSize);
}
if (attr.type == cgltf_attribute_type_joints && cgltf_num_components(accessor->type) >= skinningAttrSize) {
rawJoints.resize(accessor->count * skinningAttrSize);
cgltf_accessor_unpack_floats(accessor, &rawJoints[0], accessor->count * skinningAttrSize);
}
if (attr.type == cgltf_attribute_type_weights && cgltf_num_components(accessor->type) >= skinningAttrSize) {
weights.resize(accessor->count * skinningAttrSize);
cgltf_accessor_unpack_floats(accessor, &weights[0], accessor->count * skinningAttrSize);
}
}
std::vector<size_t> jointIndices(rawJoints.begin(), rawJoints.end());
auto primitiveCount = static_cast<size_t>(verts.size() / posAttrSize);
for (size_t i = 0; i < primitiveCount; i++) {
float3 point(verts[posAttrSize * i], verts[posAttrSize * i + 1], verts[posAttrSize * i + 2]);
mat4f tmp = mat4f(0.0f);
for (size_t j = 0; j < skinningAttrSize; j++) {
size_t jointIndex = jointIndices[skinningAttrSize * i + j];
float jointWeight = weights[skinningAttrSize * i + j];
Entity jointEntity = skin->joints[jointIndex];
mat4f globalJointTransform = tm.getWorldTransform(tm.getInstance(jointEntity));
mat4f inverseBindMatrix = skin->inverseBindMatrices[jointIndex];
tmp += jointWeight * globalJointTransform * inverseBindMatrix;
}
for (const auto& inverseGlobalTransform: inverseGlobalTransforms) {
mat4f skinMatrix = inverseGlobalTransform * tmp;
if (!pImpl->mNormalizeSkinningWeights) {
skinMatrix /= skinMatrix[3].w;
}
float3 skinnedPoint = (point.x * skinMatrix[0] + point.y * skinMatrix[1] + point.z * skinMatrix[2] + skinMatrix[3]).xyz;
aabb.min = min(aabb.min, skinnedPoint);
aabb.max = max(aabb.max, skinnedPoint);
}
}
*result = aabb;
};
// Collect all mesh primitives that we wish to find bounds for. For each mesh primitive, we also
// collect the skin it bound to (nullptr if not skinned) for bounds computation.
std::vector<std::pair<cgltf_primitive*, const Skin*>> primitives;
for (auto iter : nodeMap) {
const cgltf_mesh* mesh = iter.first->mesh;
if (mesh) {
for (cgltf_size index = 0, nprims = mesh->primitives_count; index < nprims; ++index) {
prims.push_back(&mesh->primitives[index]);
const Skin* skin = nullptr;
cgltf_skin* const cgltfSkin = iter.first->skin;
if (cgltfSkin) {
// importSkins unpacked cgltfSkin into FFilamentInstance::SkinVector bijectively so that
// the unpacked Skin can be retrieved given cgltfSkin index
int skinIndex = cgltfSkin - pImpl->cgltfSkinBaseAddress;
skin = &asset->mSkins[skinIndex];
}
const cgltf_mesh* cgltfMesh = iter.first->mesh;
if (cgltfMesh) {
for (cgltf_size index = 0, nprims = cgltfMesh->primitives_count; index < nprims; ++index) {
primitives.push_back({&cgltfMesh->primitives[index], skin});
}
}
}
// Kick off a bounding box job for every primitive.
std::vector<Aabb> bounds(prims.size());
std::vector<Aabb> bounds(primitives.size());
JobSystem* js = &pImpl->mEngine->getJobSystem();
JobSystem::Job* parent = js->createJob();
for (size_t i = 0; i < prims.size(); ++i) {
cgltf_primitive const* prim = prims[i];
for (size_t i = 0; i < primitives.size(); ++i) {
Aabb* result = &bounds[i];
js->run(jobs::createJob(*js, parent, [prim, result, computeBoundingBox] {
computeBoundingBox(prim, result);
}));
if (pImpl->mIgnoreBindTransform || !primitives[i].second) {
cgltf_primitive const* prim = primitives[i].first;
js->run(jobs::createJob(*js, parent, [prim, result, computeBoundingBox] {
computeBoundingBox(prim, result);
}));
} else {
std::pair<cgltf_primitive*, const Skin*> skinnedPrimitive = primitives[i];
js->run(jobs::createJob(*js, parent, [skinnedPrimitive, result, computeBoundingBoxSkinned] {
computeBoundingBoxSkinned(skinnedPrimitive.first, skinnedPrimitive.second, result);
}));
}
}
js->runAndWait(parent);
+1 -1
View File
@@ -131,7 +131,7 @@ Material* UbershaderLoader::getMaterial(const MaterialKey& config) const {
case MATINDEX(LIT, AlphaMode::OPAQUE, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(LIT_OPAQUE); break;
#endif
#if !GLTFIO_LITE || defined(GLTFRESOURCES_LITE_LIT_BLEND_DATA)
#if !GLTFIO_LITE || defined(GLTFRESOURCES_LITE_LIT_FADE_DATA)
case MATINDEX(LIT, AlphaMode::BLEND, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(LIT_FADE); break;
#endif
+7
View File
@@ -477,6 +477,13 @@ private:
return v;
}
friend inline VECTOR<T> MATH_PURE sign(VECTOR<T> v) {
for (size_t i = 0; i < v.size(); i++) {
v[i] = std::copysign(T(1), v[i]);
}
return v;
}
friend inline VECTOR<T> MATH_PURE pow(VECTOR<T> v, T p) {
for (size_t i = 0; i < v.size(); i++) {
v[i] = std::pow(v[i], p);
+3
View File
@@ -73,6 +73,9 @@ set(SRCS
if (WIN32)
list(APPEND SRCS src/win32/Path.cpp)
endif()
if (ANDROID)
list(APPEND SRCS src/android/ThermalManager.cpp)
endif()
if (LINUX OR ANDROID)
list(APPEND SRCS src/linux/Condition.cpp)
list(APPEND SRCS src/linux/Mutex.cpp)
+26
View File
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_UTILS_THERMALMANAGER_H
#define TNT_UTILS_THERMALMANAGER_H
#if defined(__ANDROID__)
#include <utils/android/ThermalManager.h>
#else
#include <utils/generic/ThermalManager.h>
#endif
#endif // TNT_UTILS_THERMALMANAGER_H

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