Merge branch 'rc/1.9.20' into release

This commit is contained in:
Benjamin Doherty
2021-04-12 11:36:17 -07:00
95 changed files with 2802 additions and 1117 deletions
+8 -2
View File
@@ -400,6 +400,13 @@ else()
option(FILAMENT_ENABLE_MATDBG "Enable the material debugger" OFF)
endif()
# Only optimize materials in Release mode (so error message lines match the source code)
if (CMAKE_BUILD_TYPE MATCHES Release)
option(FILAMENT_DISABLE_MATOPT "Disable material optimizations" OFF)
else()
option(FILAMENT_DISABLE_MATOPT "Disable material optimizations" ON)
endif()
# ==================================================================================================
# Material compilation flags
# ==================================================================================================
@@ -423,8 +430,7 @@ if (FILAMENT_SUPPORTS_METAL)
set(MATC_API_FLAGS ${MATC_API_FLAGS} -a metal)
endif()
# Only optimize materials in Release mode (so error message lines match the source code)
if (NOT CMAKE_BUILD_TYPE MATCHES Release)
if (FILAMENT_DISABLE_MATOPT)
set(MATC_OPT_FLAGS -g)
endif()
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.9.19'
implementation 'com.google.android.filament:filament-android:1.9.20'
}
```
@@ -63,7 +63,7 @@ A much smaller alternative to `filamat-android` that can only generate OpenGL sh
iOS projects can use CocoaPods to install the latest release:
```
pod 'Filament', '~> 1.9.19'
pod 'Filament', '~> 1.9.20'
```
### Snapshots
+14
View File
@@ -5,6 +5,20 @@ A new header is inserted each time a *tag* is created.
## Next release (main branch)
## v1.9.20
Android: Fix VSM.
engine: Introduce BufferObject API.
engine: Add new isTextureSwizzleSupported API on Texture.
engine: Add support to Metal and Vulkan backends for texture swizzling.
engine: Add new DoF settings (native/half res, gather kernel ring counts, CoC radius clamp).
engine: DoF quality and performance improvements.
engine: Fix high-quality upsampling issue with SSAO.
Java: Expose `TransformManager.getParent(int)`.
samples: Add Metal and Vulkan backend support to Suzanne sample.
WebGL: expose fitIntoUnitCube to JS.
WebGL: support for multiple <canvas> elements.
## v1.9.19
- engine: Fix Metal bug when setGeometryAt is called multiple times.
+2
View File
@@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.6)
option(FILAMENT_SUPPORTS_VULKAN "Enables Vulkan on Android" OFF)
option(FILAMENT_ENABLE_MATDBG "Enables Material debugger" OFF)
option(FILAMENT_DISABLE_MATOPT "Disables material optimizations" OFF)
set(FILAMENT_DIR ${FILAMENT_DIST_DIR})
@@ -55,6 +56,7 @@ set(VERSION_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/libfilament-jni.map")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl,--version-script=${VERSION_SCRIPT}")
add_library(filament-jni SHARED
src/main/cpp/BufferObject.cpp
src/main/cpp/Camera.cpp
src/main/cpp/Colors.cpp
src/main/cpp/ColorGrading.cpp
@@ -0,0 +1,99 @@
/*
* 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 <jni.h>
#include <functional>
#include <stdlib.h>
#include <string.h>
#include <filament/BufferObject.h>
#include <backend/BufferDescriptor.h>
#include "common/CallbackUtils.h"
#include "common/NioUtils.h"
using namespace filament;
using namespace backend;
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_BufferObject_nCreateBuilder(JNIEnv *env, jclass type) {
return (jlong) new BufferObject::Builder();
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_BufferObject_nDestroyBuilder(JNIEnv *env, jclass type,
jlong nativeBuilder) {
BufferObject::Builder* builder = (BufferObject::Builder *) nativeBuilder;
delete builder;
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_BufferObject_nBuilderSize(JNIEnv *env, jclass type,
jlong nativeBuilder, jint byteCount) {
BufferObject::Builder* builder = (BufferObject::Builder *) nativeBuilder;
builder->size((uint32_t) byteCount);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_BufferObject_nBuilderBindingType(JNIEnv *env, jclass type,
jlong nativeBuilder, jint bindingType) {
using BindingType = BufferObject::BindingType;
BufferObject::Builder* builder = (BufferObject::Builder *) nativeBuilder;
BindingType types[] = {BindingType::VERTEX};
builder->bindingType(types[bindingType]);
}
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_BufferObject_nBuilderBuild(JNIEnv *env, jclass type,
jlong nativeBuilder, jlong nativeEngine) {
BufferObject::Builder* builder = (BufferObject::Builder *) nativeBuilder;
Engine *engine = (Engine *) nativeEngine;
return (jlong) builder->build(*engine);
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_BufferObject_nGetByteCount(JNIEnv *env, jclass type,
jlong nativeBufferObject) {
BufferObject *bufferObject = (BufferObject *) nativeBufferObject;
return (jint) bufferObject->getByteCount();
}
extern "C" JNIEXPORT int JNICALL
Java_com_google_android_filament_BufferObject_nSetBuffer(JNIEnv *env, jclass type,
jlong nativeBufferObject, jlong nativeEngine, jobject buffer, int remaining,
jint destOffsetInBytes, jint count,
jobject handler, jobject runnable) {
BufferObject *bufferObject = (BufferObject *) nativeBufferObject;
Engine *engine = (Engine *) nativeEngine;
AutoBuffer nioBuffer(env, buffer, count);
void* data = nioBuffer.getData();
size_t sizeInBytes = nioBuffer.getSize();
if (sizeInBytes > (remaining << nioBuffer.getShift())) {
// BufferOverflowException
return -1;
}
auto* callback = JniBufferCallback::make(engine, env, handler, runnable, std::move(nioBuffer));
BufferDescriptor desc(data, sizeInBytes, &JniBufferCallback::invoke, callback);
bufferObject->setBuffer(*engine, std::move(desc), (uint32_t) destOffsetInBytes);
return 0;
}
@@ -51,6 +51,13 @@ Java_com_google_android_filament_Texture_nIsTextureFormatSupported(JNIEnv*, jcla
(Texture::InternalFormat) internalFormat);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Texture_nIsTextureSwizzleSupported(JNIEnv*, jclass,
jlong nativeEngine) {
Engine *engine = (Engine *) nativeEngine;
return (jboolean) Texture::isTextureSwizzleSupported(*engine);
}
// Texture::Builder...
extern "C" JNIEXPORT jlong JNICALL
@@ -86,6 +86,13 @@ Java_com_google_android_filament_TransformManager_nSetParent(JNIEnv*, jclass,
(TransformManager::Instance) newParent);
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_TransformManager_nGetParent(JNIEnv*, jclass,
jlong nativeTransformManager, jint i) {
TransformManager* tm = (TransformManager*) nativeTransformManager;
return tm->getParent((TransformManager::Instance) i).getId();
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_TransformManager_nSetTransform(JNIEnv* env,
jclass, jlong nativeTransformManager, jint i,
@@ -50,6 +50,13 @@ Java_com_google_android_filament_VertexBuffer_nBuilderVertexCount(JNIEnv *env, j
builder->vertexCount((uint32_t) vertexCount);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_VertexBuffer_nBuilderEnableBufferObjects(JNIEnv *env, jclass type,
jlong nativeBuilder, jboolean enabled) {
VertexBuffer::Builder* builder = (VertexBuffer::Builder *) nativeBuilder;
builder->enableBufferObjects(enabled);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_VertexBuffer_nBuilderBufferCount(JNIEnv *env, jclass type,
jlong nativeBuilder, jint bufferCount) {
@@ -115,6 +122,15 @@ Java_com_google_android_filament_VertexBuffer_nSetBufferAt(JNIEnv *env, jclass t
return 0;
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_VertexBuffer_nSetBufferObjectAt(JNIEnv *env, jclass type,
jlong nativeVertexBuffer, jlong nativeEngine, jint bufferIndex, jlong nativeBufferObject) {
VertexBuffer *vertexBuffer = (VertexBuffer *) nativeVertexBuffer;
Engine *engine = (Engine *) nativeEngine;
BufferObject *bufferObject = (BufferObject *) nativeBufferObject;
vertexBuffer->setBufferObjectAt(*engine, (uint8_t) bufferIndex, bufferObject);
}
extern "C" [[deprecated]] JNIEXPORT void JNICALL
Java_com_google_android_filament_VertexBuffer_nPopulateTangentQuaternions(JNIEnv *env,
jclass type, jint quatType, jint quatCount, jobject outBuffer, jint outRemaining,
+11 -2
View File
@@ -300,7 +300,9 @@ Java_com_google_android_filament_View_nSetBlendMode(JNIEnv *, jclass , jlong nat
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_View_nSetDepthOfFieldOptions(JNIEnv *, jclass ,
jlong nativeView, jfloat focusDistance, jfloat cocScale, jfloat maxApertureDiameter, jboolean enabled, jint filter) {
jlong nativeView, jfloat focusDistance, jfloat cocScale, jfloat maxApertureDiameter, jboolean enabled, jint filter,
jboolean nativeResolution, jint foregroundRingCount, jint backgroundRingCount, jint fastGatherRingCount,
jint maxForegroundCOC, jint maxBackgroundCOC) {
View* view = (View*) nativeView;
View::DepthOfFieldOptions::Filter eFilter{};
if (filter == 1) {
@@ -308,7 +310,14 @@ Java_com_google_android_filament_View_nSetDepthOfFieldOptions(JNIEnv *, jclass ,
eFilter = View::DepthOfFieldOptions::Filter::MEDIAN;
}
view->setDepthOfFieldOptions({.focusDistance = focusDistance, .cocScale = cocScale,
.maxApertureDiameter = maxApertureDiameter, .enabled = (bool)enabled, .filter = eFilter});
.maxApertureDiameter = maxApertureDiameter, .enabled = (bool)enabled, .filter = eFilter,
.nativeResolution = (bool)nativeResolution,
.foregroundRingCount = (uint8_t)foregroundRingCount,
.backgroundRingCount = (uint8_t)backgroundRingCount,
.fastGatherRingCount = (uint8_t)fastGatherRingCount,
.maxForegroundCOC = (uint8_t)maxForegroundCOC,
.maxBackgroundCOC = (uint8_t)maxBackgroundCOC,
});
}
extern "C"
@@ -0,0 +1,210 @@
/*
* 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.
*/
package com.google.android.filament;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.nio.Buffer;
import java.nio.BufferOverflowException;
/**
* A generic GPU buffer containing data.
*
* Usage of this BufferObject is optional. For simple use cases it is not necessary. It is useful
* only when you need to share data between multiple VertexBuffer instances. It also allows you to
* efficiently swap-out the buffers in VertexBuffer.
*
* NOTE: For now this is only used for vertex data, but in the future we may use it for other things
* (e.g. compute).
*
* @see VertexBuffer
*/
public class BufferObject {
private long mNativeObject;
private BufferObject(long nativeBufferObject) {
mNativeObject = nativeBufferObject;
}
public static class Builder {
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
// Keep to finalize native resources
private final BuilderFinalizer mFinalizer;
private final long mNativeBuilder;
public enum BindingType {
VERTEX,
}
public Builder() {
mNativeBuilder = nCreateBuilder();
mFinalizer = new BuilderFinalizer(mNativeBuilder);
}
/**
* Size of the buffer in bytes.
*
* @param byteCount Maximum number of bytes the BufferObject can hold.
* @return A reference to this Builder for chaining calls.
*/
@NonNull
public Builder size(@IntRange(from = 1) int byteCount) {
nBuilderSize(mNativeBuilder, byteCount);
return this;
}
/**
* The binding type for this buffer object. (defaults to VERTEX)
*
* @param BindingType Distinguishes between SSBO, VBO, etc. For now this must be VERTEX.
* @return A reference to this Builder for chaining calls.
*/
@NonNull
public Builder bindingType(@NonNull BindingType bindingType) {
nBuilderBindingType(mNativeBuilder, bindingType.ordinal());
return this;
}
/**
* Creates and returns the <code>BufferObject</code> object. After creation, the buffer
* is uninitialized. Use {@link #setBuffer} to initialize the <code>BufferObject</code>.
*
* @param engine reference to the {@link Engine} to associate this <code>BufferObject</code>
* with
*
* @return the newly created <code>BufferObject</code> object
*
* @exception IllegalStateException if the BufferObject could not be created
*
* @see #setBuffer
*/
@NonNull
public BufferObject build(@NonNull Engine engine) {
long nativeBufferObject = nBuilderBuild(mNativeBuilder, engine.getNativeObject());
if (nativeBufferObject == 0)
throw new IllegalStateException("Couldn't create BufferObject");
return new BufferObject(nativeBufferObject);
}
private static class BuilderFinalizer {
private final long mNativeObject;
BuilderFinalizer(long nativeObject) {
mNativeObject = nativeObject;
}
@Override
public void finalize() {
try {
super.finalize();
} catch (Throwable t) { // Ignore
} finally {
nDestroyBuilder(mNativeObject);
}
}
}
}
/**
* Returns the size of this <code>BufferObject</code> in elements.
*
* @return the number of bytes the <code>BufferObject</code> holds
*/
@IntRange(from = 0)
public int getByteCount() {
return nGetByteCount(getNativeObject());
}
/**
* Asynchronously copy-initializes this <code>BufferObject</code> from the data provided.
*
* @param engine reference to the {@link Engine} to associate this
* <code>BufferObject</code> with
* @param buffer a CPU-side {@link Buffer} with the data used to initialize the
* <code>BufferObject</code>.
*/
public void setBuffer(@NonNull Engine engine, @NonNull Buffer buffer) {
setBuffer(engine, buffer, 0, 0, null, null);
}
/**
* Asynchronously copy-initializes a region of this <code>BufferObject</code> from the data
* provided.
*
* @param engine reference to the {@link Engine} to associate this
* <code>BufferObject</code> with
* @param buffer a CPU-side {@link Buffer} with the data used to initialize the
* <code>BufferObject</code>.
* @param destOffsetInBytes offset in <i>bytes</i> into the <code>BufferObject</code>
* @param count number of bytes to consume, defaults to
* <code>buffer.remaining()</code>
*/
public void setBuffer(@NonNull Engine engine, @NonNull Buffer buffer,
@IntRange(from = 0) int destOffsetInBytes, @IntRange(from = 0) int count) {
setBuffer(engine, buffer, destOffsetInBytes, count, null, null);
}
/**
* Asynchronously copy-initializes a region of this <code>BufferObject</code> from the data
* provided.
*
* @param engine reference to the {@link Engine} to associate this
* <code>BufferObject</code> with
* @param buffer a CPU-side {@link Buffer} with the data used to initialize the
* <code>BufferObject</code>.
* @param destOffsetInBytes offset in <i>bytes</i> into the <code>BufferObject</code>
* @param count number of bytes to consume, defaults to
* <code>buffer.remaining()</code>
* @param handler an {@link java.util.concurrent.Executor Executor}. On Android this
* can also be a {@link android.os.Handler Handler}.
* @param callback a callback executed by <code>handler</code> when <code>buffer</code>
* is no longer needed.
*/
public void setBuffer(@NonNull Engine engine, @NonNull Buffer buffer,
@IntRange(from = 0) int destOffsetInBytes, @IntRange(from = 0) int count,
@Nullable Object handler, @Nullable Runnable callback) {
int result = nSetBuffer(getNativeObject(), engine.getNativeObject(), buffer, buffer.remaining(),
destOffsetInBytes, count == 0 ? buffer.remaining() : count, handler, callback);
if (result < 0) {
throw new BufferOverflowException();
}
}
public long getNativeObject() {
if (mNativeObject == 0) {
throw new IllegalStateException("Calling method on destroyed BufferObject");
}
return mNativeObject;
}
void clearNativeObject() {
mNativeObject = 0;
}
private static native long nCreateBuilder();
private static native void nDestroyBuilder(long nativeBuilder);
private static native void nBuilderSize(long nativeBuilder, int byteCount);
private static native void nBuilderBindingType(long nativeBuilder, int bindingType);
private static native long nBuilderBuild(long nativeBuilder, long nativeEngine);
private static native int nGetByteCount(long nativeBufferObject);
private static native int nSetBuffer(long nativeBufferObject, long nativeEngine,
Buffer buffer, int remaining,
int destOffsetInBytes, int count, Object handler, Runnable callback);
}
@@ -562,6 +562,17 @@ public class Texture {
return nIsTextureFormatSupported(engine.getNativeObject(), format.ordinal());
}
/**
* Checks whether texture swizzling is supported in this {@link Engine}.
* This depends on the selected backend.
*
* @param engine {@link Engine}
* @return <code>true</code> if texture swizzling.
*/
public static boolean isTextureSwizzleSupported(@NonNull Engine engine) {
return nIsTextureSwizzleSupported(engine.getNativeObject());
}
/**
* Use <code>Builder</code> to construct a <code>Texture</code> object instance.
*/
@@ -1137,6 +1148,7 @@ public class Texture {
}
private static native boolean nIsTextureFormatSupported(long nativeEngine, int internalFormat);
private static native boolean nIsTextureSwizzleSupported(long nativeEngine);
private static native long nCreateBuilder();
private static native void nDestroyBuilder(long nativeBuilder);
@@ -140,6 +140,19 @@ import androidx.annotation.Size;
nSetParent(mNativeObject, i, newParent);
}
/**
* Returns the actual parent entity of an {@link EntityInstance} originally defined
* by {@link #setParent(int, int)}.
*
* @param i the {@link EntityInstance} of the transform component to get the parent from.
* @return the parent {@link Entity}.
* @see #getInstance
*/
@Entity
public int getParent(@EntityInstance int i) {
return nGetParent(mNativeObject, i);
}
/**
* Sets a local transform of a transform component.
* <p>This operation can be slow if the hierarchy of transform is too deep, and this
@@ -241,6 +254,7 @@ import androidx.annotation.Size;
private static native int nCreateArray(long mNativeObject, int entity, int parent, float[] localTransform);
private static native void nDestroy(long nativeTransformManager, int entity);
private static native void nSetParent(long nativeTransformManager, int i, int newParent);
private static native int nGetParent(long nativeTransformManager, int i);
private static native void nSetTransform(long nativeTransformManager, int i, float[] localTransform);
private static native void nGetTransform(long nativeTransformManager, int i, float[] outLocalTransform);
private static native void nGetWorldTransform(long nativeTransformManager, int i, float[] outWorldTransform);
@@ -170,6 +170,21 @@ public class VertexBuffer {
return this;
}
/**
* Allows buffers to be swapped out and shared using BufferObject.
*
* If buffer objects mode is enabled, clients must call setBufferObjectAt rather than
* setBufferAt. This allows sharing of data between VertexBuffer objects, but it may
* slightly increase the memory footprint of Filament's internal bookkeeping.
*
* @param enabled If true, enables buffer object mode. False by default.
*/
@NonNull
public Builder enableBufferObjects(boolean enabled) {
nBuilderEnableBufferObjects(mNativeBuilder, enabled);
return this;
}
/**
* Defines how many buffers will be created in this vertex buffer set. These buffers are
* later referenced by index from 0 to <code>bufferCount</code> - 1.
@@ -397,6 +412,23 @@ public class VertexBuffer {
throw new BufferOverflowException();
}
}
/**
* Swaps in the given buffer object.
*
* To use this, you must first call enableBufferObjects() on the Builder.
*
* @param engine Reference to the filament::Engine to associate this VertexBuffer with.
* @param bufferIndex Index of the buffer to initialize. Must be between 0
* and Builder::bufferCount() - 1.
* @param bufferObject The handle to the GPU data that will be used in this buffer slot.
*/
public void setBufferObjectAt(@NonNull Engine engine, int bufferIndex,
@NonNull BufferObject bufferObject) {
nSetBufferObjectAt(getNativeObject(), engine.getNativeObject(), bufferIndex,
bufferObject.getNativeObject());
}
/**
* Convenience function that consumes normal vectors (and, optionally, tangent vectors) and
* produces quaternions that can be passed into a TANGENTS buffer.
@@ -443,6 +475,7 @@ public class VertexBuffer {
private static native long nCreateBuilder();
private static native void nDestroyBuilder(long nativeBuilder);
private static native void nBuilderVertexCount(long nativeBuilder, int vertexCount);
private static native void nBuilderEnableBufferObjects(long nativeBuilder, boolean enabled);
private static native void nBuilderBufferCount(long nativeBuilder, int bufferCount);
private static native void nBuilderAttribute(long nativeBuilder, int attribute,
int bufferIndex, int attributeType, int byteOffset, int byteStride);
@@ -455,6 +488,9 @@ public class VertexBuffer {
int bufferIndex, Buffer buffer, int remaining, int destOffsetInBytes, int count,
Object handler, Runnable callback);
private static native void nSetBufferObjectAt(long nativeVertexBuffer, long nativeEngine,
int bufferIndex, long nativeBufferObject);
private static native void nPopulateTangentQuaternions(int quatType, int quatCount,
Buffer outBuffer, int outRemaining, int outStride, Buffer normals, int normalsRemaining,
int normalsStride, Buffer tangents, int tangentsRemaining, int tangentsStride);
@@ -266,7 +266,7 @@ public class View {
/**
* Options for Temporal Anti-aliasing (TAA)
* @see View#setTemporalAntiAliasingOptions()
* @see View#setTemporalAntiAliasingOptions
*/
public static class TemporalAntiAliasingOptions {
/** reconstruction filter width typically between 0 (sharper, aliased) and 1 (smoother) */
@@ -465,6 +465,55 @@ public class View {
/** filter to use for filling gaps in the kernel */
@NonNull
public Filter filter = Filter.MEDIAN;
/** perform DoF processing at native resolution */
public boolean nativeResolution = false;
/**
* <p>Number of of rings used by the foreground kernel. The number of rings affects quality
* and performance. The actual number of sample per pixel is defined
* as (ringCount * 2 - 1)^2. Here are a few commonly used values:</p>
* 3 rings : 25 ( 5x 5 grid)
* 4 rings : 49 ( 7x 7 grid)
* 5 rings : 81 ( 9x 9 grid)
* 17 rings : 1089 (33x33 grid)
*
* <p>With a maximum circle-of-confusion of 32, it is never necessary to use more than 17 rings.</p>
*
* <p>Usually all three settings below are set to the same value, however, it is often
* acceptable to use a lower ring count for the "fast tiles", which improves performance.
* Fast tiles are regions of the screen where every pixels have a similar
* circle-of-confusion radius.</p>
*
* <p>A value of 0 means default, which is 5 on desktop and 3 on mobile.</p>
*/
public int foregroundRingCount = 0;
/**
* Number of of rings used by the background kernel. The number of rings affects quality
* and performance.
* @see #foregroundRingCount
*/
public int backgroundRingCount = 0;
/**
* Number of of rings used by the fast gather kernel. The number of rings affects quality
* and performance.
* @see #foregroundRingCount
*/
public int fastGatherRingCount = 0;
/**
* maximum circle-of-confusion in pixels for the foreground, must be in [0, 32] range.
* A value of 0 means default, which is 32 on desktop and 24 on mobile.
*/
public int maxForegroundCOC = 0;
/**
* maximum circle-of-confusion in pixels for the background, must be in [0, 32] range.
* A value of 0 means default, which is 32 on desktop and 24 on mobile.
*/
public int maxBackgroundCOC = 0;
};
/**
@@ -1393,7 +1442,10 @@ public class View {
*/
public void setDepthOfFieldOptions(@NonNull DepthOfFieldOptions options) {
mDepthOfFieldOptions = options;
nSetDepthOfFieldOptions(getNativeObject(), options.focusDistance, options.cocScale, options.maxApertureDiameter, options.enabled, options.filter.ordinal());
nSetDepthOfFieldOptions(getNativeObject(), options.focusDistance, options.cocScale,
options.maxApertureDiameter, options.enabled, options.filter.ordinal(),
options.nativeResolution, options.foregroundRingCount, options.backgroundRingCount,
options.fastGatherRingCount, options.maxForegroundCOC, options.maxBackgroundCOC);
}
/**
@@ -1452,7 +1504,8 @@ public class View {
private static native void nSetBloomOptions(long nativeView, long dirtNativeObject, float dirtStrength, float strength, int resolution, float anamorphism, int levels, int blendMode, boolean threshold, boolean enabled, float highlight);
private static native void nSetFogOptions(long nativeView, float distance, float maximumOpacity, float height, float heightFalloff, float v, float v1, float v2, float density, float inScatteringStart, float inScatteringSize, boolean fogColorFromIbl, boolean enabled);
private static native void nSetBlendMode(long nativeView, int blendMode);
private static native void nSetDepthOfFieldOptions(long nativeView, float focusDistance, float cocScale, float maxApertureDiameter, boolean enabled, int filter);
private static native void nSetDepthOfFieldOptions(long nativeView, float focusDistance, float cocScale, float maxApertureDiameter, boolean enabled, int filter,
boolean nativeResolution, int foregroundRingCount, int backgroundRingCount, int fastGatherRingCount, int maxForegroundCOC, int maxBackgroundCOC);
private static native void nSetVignetteOptions(long nativeView, float midPoint, float roundness, float feather, float r, float g, float b, float a, boolean enabled);
private static native void nSetTemporalAntiAliasingOptions(long nativeView, float feedback, float filterWidth, boolean enabled);
private static native boolean nIsShadowingEnabled(long nativeView);
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.9.19
VERSION_NAME=1.9.20
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
+37 -1
View File
@@ -17,6 +17,8 @@ function print_help {
echo " Generate .tgz build archives, implies -i."
echo " -c"
echo " Clean build directories."
echo " -d"
echo " Enable matdbg and disable material optimization."
echo " -f"
echo " Always invoke CMake before incremental builds."
echo " -i"
@@ -80,6 +82,27 @@ function print_help {
echo ""
}
function print_matdbg_help {
echo "matdbg is enabled in the build, but some extra steps are needed."
echo ""
echo "FOR DESKTOP BUILDS:"
echo ""
echo "Please set the port environment variable before launching. e.g., on macOS do:"
echo " export FILAMENT_MATDBG_PORT=8080"
echo ""
echo "FOR ANDROID BUILDS:"
echo ""
echo "1) The most reliable way to enable matdbg is to bypass Gradle and"
echo " directly modify the appropriate two lines in the following file:"
echo " ./android/filament-android/CMakeLists.txt"
echo ""
echo "2) The port number is hardcoded to 8081 so you will need to do:"
echo " adb forward tcp:8081 tcp:8081"
echo ""
echo "3) Be sure to enable INTERNET permission in your app's manifest file."
echo ""
}
# Requirements
CMAKE_MAJOR=3
CMAKE_MINOR=10
@@ -122,6 +145,8 @@ VULKAN_ANDROID_GRADLE_OPTION=""
SWIFTSHADER_OPTION="-DFILAMENT_USE_SWIFTSHADER=OFF"
MATDBG_OPTION="-DFILAMENT_ENABLE_MATDBG=OFF"
IOS_BUILD_SIMULATOR=false
BUILD_UNIVERSAL_LIBRARIES=false
@@ -174,6 +199,7 @@ function build_desktop_target {
-DCMAKE_INSTALL_PREFIX="../${lc_target}/filament" \
-DFILAMENT_ENABLE_JAVA="${FILAMENT_ENABLE_JAVA}" \
${SWIFTSHADER_OPTION} \
${MATDBG_OPTION} \
${deployment_target} \
${architectures} \
../..
@@ -298,6 +324,7 @@ function build_android_target {
-DCMAKE_BUILD_TYPE="$1" \
-DCMAKE_INSTALL_PREFIX="../android-${lc_target}/filament" \
-DCMAKE_TOOLCHAIN_FILE="../../build/toolchain-${arch}-linux-android.cmake" \
${MATDBG_OPTION} \
${VULKAN_ANDROID_OPTION} \
../..
fi
@@ -484,6 +511,7 @@ function build_ios_target {
-DPLATFORM_NAME="${platform}" \
-DIOS=1 \
-DCMAKE_TOOLCHAIN_FILE=../../third_party/clang/iOS.cmake \
${MATDBG_OPTION} \
../..
fi
@@ -654,7 +682,7 @@ function run_tests {
pushd "$(dirname "$0")" > /dev/null
while getopts ":hacfijmp:q:uvslwt" opt; do
while getopts ":hacfijmp:q:uvslwtd" opt; do
case ${opt} in
h)
print_help
@@ -667,6 +695,10 @@ while getopts ":hacfijmp:q:uvslwt" opt; do
c)
ISSUE_CLEAN=true
;;
d)
PRINT_MATDBG_HELP=true
MATDBG_OPTION="-DFILAMENT_ENABLE_MATDBG=ON, -DFILAMENT_DISABLE_MATOPT=ON"
;;
f)
ISSUE_CMAKE_ALWAYS=true
;;
@@ -825,3 +857,7 @@ fi
if [[ "${RUN_TESTS}" == "true" ]]; then
run_tests
fi
if [[ "${PRINT_MATDBG_HELP}" == "true" ]]; then
print_matdbg_help
fi
File diff suppressed because one or more lines are too long
Binary file not shown.
+14 -6
View File
@@ -135,7 +135,7 @@ class App {
// In the future we might want to draw stuff in the central 3D viewport.
const kInitialSidebarWidth = this.canvas.clientWidth * window.devicePixelRatio;
// Clear the central 3D viewport to light gray, whicht is not visible by default.
// Clear the central 3D viewport to light gray, which is not visible by default.
const L = 189 / 255;
const kBackgroundColor = [L, L, L, 1];
this.renderer.setClearOptions({clearColor: kBackgroundColor, clear: true});
@@ -145,7 +145,7 @@ class App {
this.mouseX = -1;
this.mouseY = -1;
this.mouseButton = false;
this.mouseButton = null;
this.mouseButtonEvents = [];
this.mouseWheelY = 0;
@@ -155,10 +155,17 @@ class App {
this.mouseX = e.offsetX * window.devicePixelRatio;
this.mouseY = e.offsetY * window.devicePixelRatio;
});
this.canvas.addEventListener("pointerup", e => this.mouseButtonEvents.push(false));
this.canvas.addEventListener("pointerdown", e => this.mouseButtonEvents.push(true));
this.canvas.addEventListener("pointerup", e => this.mouseButtonEvents.push(null));
this.canvas.addEventListener("pointerdown", e => this.mouseButtonEvents.push(e));
this.canvas.addEventListener("mousewheel", e => this.mouseWheelY = e.deltaY / 8);
this.canvas.addEventListener("contextmenu", event => event.preventDefault());
document.addEventListener("keydown", e => this.simpleViewer.keyDownEvent(e.keyCode));
document.addEventListener("keyup", e => this.simpleViewer.keyUpEvent(e.keyCode));
document.addEventListener("keypress", e => this.simpleViewer.keyPressEvent(e.charCode));
const resize = () => {
const dpr = window.devicePixelRatio;
const width = this.canvas.clientWidth * dpr;
@@ -263,6 +270,8 @@ class App {
}
const mouseWheel = this.mouseWheelY;
this.mouseWheelY = 0;
this.simpleViewer.mouseEvent(this.mouseX, this.mouseY, !!this.mouseButton,
mouseWheel, this.mouseButton && this.mouseButton.ctrlKey);
// If there's no connection, let Filament clear the canvas, but do not render the UI view.
if (!connection) {
@@ -276,8 +285,7 @@ class App {
// Draw the UI and potentially mutate the settings object.
const deltaTime = 1.0 / 60.0;
this.simpleViewer.renderUserInterface(deltaTime, this.uiview, window.devicePixelRatio,
this.mouseX, this.mouseY, this.mouseButton, mouseWheel);
this.simpleViewer.renderUserInterface(deltaTime, this.uiview, window.devicePixelRatio);
// Check if the user has changed any settings.
const settingsJson = this.serializer.writeJson(this.simpleViewer.getSettings()).slice();
+17
View File
@@ -0,0 +1,17 @@
#!/bin/bash
pushd "$(dirname "$0")" > /dev/null
curl -OL https://nightly.link/google/filament/workflows/web-continuous/main/filament-web.zip
unzip -q filament-web.zip
tar -xvzf filament-release-web.tgz
rm filament-release-web.tgz
rm filament-web.zip
rm filament.d.ts
cp ../../web/samples/remote.html index.html
popd
git status
echo ""
echo "All done! Next, make a git commit that updates docs/remote."
+9
View File
@@ -13,6 +13,7 @@ set(MATERIAL_DIR "${GENERATION_ROOT}/generated/material")
set(PUBLIC_HDRS
include/filament/Box.h
include/filament/BufferObject.h
include/filament/Camera.h
include/filament/Color.h
include/filament/ColorGrading.h
@@ -44,6 +45,7 @@ set(PUBLIC_HDRS
set(SRCS
src/Box.cpp
src/BufferObject.cpp
src/Camera.cpp
src/Color.cpp
src/ColorGrading.cpp
@@ -112,6 +114,7 @@ set(PRIVATE_HDRS
src/components/RenderableManager.h
src/components/TransformManager.h
src/details/Allocators.h
src/details/BufferObject.h
src/details/Camera.h
src/details/ColorGrading.h
src/details/Culler.h
@@ -163,6 +166,7 @@ set(MATERIAL_SRCS
src/materials/dof/dofDownsample.mat
src/materials/dof/dofCombine.mat
src/materials/dof/dofTiles.mat
src/materials/dof/dofTilesSwizzle.mat
src/materials/dof/dofDilate.mat
src/materials/dof/dofMipmap.mat
src/materials/dof/dofMedian.mat
@@ -190,6 +194,11 @@ list(APPEND SRCS ${RESGEN_SOURCE})
# Configuration
# ==================================================================================================
# whether we're building for mobile -- this can affect some default quality settings
if (IS_MOBILE_TARGET)
add_definitions(-DFILAMENT_TARGET_MOBILE=1)
endif()
# Size of the DFG lookup table
if (NOT DFG_LUT_SIZE)
if (IS_MOBILE_TARGET)
@@ -263,6 +263,11 @@ enum class ElementType : uint8_t {
HALF4,
};
//! Buffer object binding type
enum class BufferObjectBinding : uint8_t {
VERTEX,
};
//! Face culling Mode
enum class CullingMode : uint8_t {
NONE, //!< No culling, front and back faces are visible
@@ -513,7 +518,7 @@ enum class TextureUsage : uint8_t {
};
//! Texture swizzle
enum class TextureSwizzle {
enum class TextureSwizzle : uint8_t {
SUBSTITUTE_ZERO,
SUBSTITUTE_ONE,
CHANNEL_0,
@@ -24,6 +24,7 @@
namespace filament {
namespace backend {
struct HwBufferObject;
struct HwFence;
struct HwIndexBuffer;
struct HwProgram;
@@ -96,6 +97,7 @@ private:
// Types used by the command stream
// (we use this renaming because the macro-system doesn't deal well with "<" and ">")
using BufferObjectHandle = Handle<HwBufferObject>;
using FenceHandle = Handle<HwFence>;
using IndexBufferHandle = Handle<HwIndexBuffer>;
using ProgramHandle = Handle<HwProgram>;
@@ -168,13 +168,18 @@ DECL_DRIVER_API_R_N(backend::VertexBufferHandle, createVertexBuffer,
uint8_t, attributeCount,
uint32_t, vertexCount,
backend::AttributeArray, attributes,
backend::BufferUsage, usage)
backend::BufferUsage, usage,
bool, bufferObjectsEnabled)
DECL_DRIVER_API_R_N(backend::IndexBufferHandle, createIndexBuffer,
backend::ElementType, elementType,
uint32_t, indexCount,
backend::BufferUsage, usage)
DECL_DRIVER_API_R_N(backend::BufferObjectHandle, createBufferObject,
uint32_t, byteCount,
backend::BufferObjectBinding, bindingType)
DECL_DRIVER_API_R_N(backend::TextureHandle, createTexture,
backend::SamplerType, target,
uint8_t, levels,
@@ -261,6 +266,7 @@ DECL_DRIVER_API_R_0(backend::TimerQueryHandle, createTimerQuery)
DECL_DRIVER_API_N(destroyVertexBuffer, backend::VertexBufferHandle, vbh)
DECL_DRIVER_API_N(destroyIndexBuffer, backend::IndexBufferHandle, ibh)
DECL_DRIVER_API_N(destroyBufferObject, backend::BufferObjectHandle, ibh)
DECL_DRIVER_API_N(destroyRenderPrimitive, backend::RenderPrimitiveHandle, rph)
DECL_DRIVER_API_N(destroyProgram, backend::ProgramHandle, ph)
DECL_DRIVER_API_N(destroySamplerGroup, backend::SamplerGroupHandle, sbh)
@@ -287,6 +293,7 @@ DECL_DRIVER_API_SYNCHRONOUS_N(void, updateStreams, backend::DriverApi*, driver)
DECL_DRIVER_API_SYNCHRONOUS_N(void, destroyFence, backend::FenceHandle, fh)
DECL_DRIVER_API_SYNCHRONOUS_N(backend::FenceStatus, wait, backend::FenceHandle, fh, uint64_t, timeout)
DECL_DRIVER_API_SYNCHRONOUS_N(bool, isTextureFormatSupported, backend::TextureFormat, format)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isTextureSwizzleSupported)
DECL_DRIVER_API_SYNCHRONOUS_N(bool, isTextureFormatMipmappable, backend::TextureFormat, format)
DECL_DRIVER_API_SYNCHRONOUS_N(bool, isRenderTargetFormatSupported, backend::TextureFormat, format)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isFrameBufferFetchSupported)
@@ -310,11 +317,21 @@ DECL_DRIVER_API_N(updateVertexBuffer,
backend::BufferDescriptor&&, data,
uint32_t, byteOffset)
DECL_DRIVER_API_N(setVertexBufferObject,
backend::VertexBufferHandle, vbh,
size_t, index,
backend::BufferObjectHandle, bufferObject)
DECL_DRIVER_API_N(updateIndexBuffer,
backend::IndexBufferHandle, ibh,
backend::BufferDescriptor&&, data,
uint32_t, byteOffset)
DECL_DRIVER_API_N(updateBufferObject,
backend::BufferObjectHandle, ibh,
backend::BufferDescriptor&&, data,
uint32_t, byteOffset)
DECL_DRIVER_API_N(loadUniformBuffer,
backend::UniformBufferHandle, ubh,
backend::BufferDescriptor&&, buffer)
+7
View File
@@ -606,6 +606,13 @@ io::ostream& operator<<(io::ostream& out, RenderPassParams const& params) {
return out;
}
io::ostream& operator<<(io::ostream& out, BufferObjectBinding wrap) {
switch (wrap) {
CASE(BufferObjectBinding, VERTEX)
}
return out;
}
#undef CASE
#endif // !NDEBUG
+7 -3
View File
@@ -55,18 +55,22 @@ struct HwVertexBuffer : public HwBase {
uint32_t vertexCount{}; // 4
uint8_t bufferCount{}; // 1
uint8_t attributeCount{}; // 1
uint8_t padding[2]{}; // 2 -> total struct is 136 bytes
bool bufferObjectsEnabled{}; // 1
uint8_t bufferObjectsVersion{}; // 1 -> total struct is 136 bytes
HwVertexBuffer() noexcept = default;
HwVertexBuffer(uint8_t bufferCount, uint8_t attributeCount, uint32_t elementCount,
AttributeArray const& attributes) noexcept
AttributeArray const& attributes, bool bufferObjectsEnabled) noexcept
: attributes(attributes),
vertexCount(elementCount),
bufferCount(bufferCount),
attributeCount(attributeCount) {
attributeCount(attributeCount),
bufferObjectsEnabled(bufferObjectsEnabled) {
}
};
struct HwBufferObject : public HwBase {};
struct HwIndexBuffer : public HwBase {
uint32_t count{};
uint8_t elementSize{};
+67 -8
View File
@@ -160,10 +160,10 @@ void MetalDriver::finish(int) {
void MetalDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint8_t bufferCount,
uint8_t attributeCount, uint32_t vertexCount, AttributeArray attributes,
BufferUsage usage) {
BufferUsage usage, bool bufferObjectsEnabled) {
// TODO: Take BufferUsage into account when creating the buffer.
construct_handle<MetalVertexBuffer>(mHandleMap, vbh, *mContext, bufferCount,
attributeCount, vertexCount, attributes);
attributeCount, vertexCount, attributes, bufferObjectsEnabled);
}
void MetalDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
@@ -172,11 +172,17 @@ void MetalDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elem
construct_handle<MetalIndexBuffer>(mHandleMap, ibh, *mContext, elementSize, indexCount);
}
void MetalDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType) {
construct_handle<MetalBufferObject>(mHandleMap, boh, *mContext, byteCount);
}
void MetalDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height,
uint32_t depth, TextureUsage usage) {
construct_handle<MetalTexture>(mHandleMap, th, *mContext, target, levels, format, samples,
width, height, depth, usage);
width, height, depth, usage, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1,
TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_3);
}
void MetalDriver::createTextureSwizzledR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
@@ -184,8 +190,7 @@ void MetalDriver::createTextureSwizzledR(Handle<HwTexture> th, SamplerType targe
uint32_t depth, TextureUsage usage,
TextureSwizzle r, TextureSwizzle g, TextureSwizzle b, TextureSwizzle a) {
construct_handle<MetalTexture>(mHandleMap, th, *mContext, target, levels, format, samples,
width, height, depth, usage);
// TODO: implement texture swizzle
width, height, depth, usage, r, g, b, a);
}
void MetalDriver::importTextureR(Handle<HwTexture> th, intptr_t i,
@@ -321,6 +326,10 @@ Handle<HwIndexBuffer> MetalDriver::createIndexBufferS() noexcept {
return alloc_handle<MetalIndexBuffer, HwIndexBuffer>();
}
Handle<HwBufferObject> MetalDriver::createBufferObjectS() noexcept {
return alloc_handle<MetalBufferObject, HwBufferObject>();
}
Handle<HwTexture> MetalDriver::createTextureS() noexcept {
return alloc_handle<MetalTexture, HwTexture>();
}
@@ -399,6 +408,12 @@ void MetalDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
}
}
void MetalDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
if (boh) {
destruct_handle<MetalBufferObject>(mHandleMap, boh);
}
}
void MetalDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
if (rph) {
destruct_handle<MetalRenderPrimitive>(mHandleMap, rph);
@@ -550,6 +565,14 @@ bool MetalDriver::isTextureFormatSupported(TextureFormat format) {
TextureReshaper::canReshapeTextureFormat(format);
}
bool MetalDriver::isTextureSwizzleSupported() {
if (@available(macOS 10.15, iOS 13, *)) {
return true;
} else {
return false;
}
}
bool MetalDriver::isTextureFormatMipmappable(TextureFormat format) {
// Derived from the Metal 3.0 Feature Set Tables.
// In order for a format to be mipmappable, it must be color-renderable and filterable.
@@ -642,6 +665,22 @@ void MetalDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&
scheduleDestroy(std::move(data));
}
void MetalDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescriptor&& data,
uint32_t byteOffset) {
auto* bo = handle_cast<MetalBufferObject>(mHandleMap, boh);
bo->updateBuffer(data.buffer, data.size, byteOffset);
scheduleDestroy(std::move(data));
}
void MetalDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, size_t index,
Handle<HwBufferObject> boh) {
auto* vertexBuffer = handle_cast<MetalVertexBuffer>(mHandleMap, vbh);
auto* bufferObject = handle_cast<MetalBufferObject>(mHandleMap, boh);
assert_invariant(index < vertexBuffer->buffers.size());
assert_invariant(bufferObject->getBuffer());
vertexBuffer->buffers[index] = bufferObject->getBuffer();
}
void MetalDriver::update2DImage(Handle<HwTexture> th, uint32_t level, uint32_t xoffset,
uint32_t yoffset, uint32_t width, uint32_t height, PixelBufferDescriptor&& data) {
ASSERT_PRECONDITION(!isInRenderPass(mContext),
@@ -1211,7 +1250,8 @@ void MetalDriver::draw(backend::PipelineState ps, Handle<HwRenderPrimitive> rph)
return;
}
const auto metalTexture = handle_const_cast<MetalTexture>(mHandleMap, sampler->t);
texturesToBind[binding] = metalTexture->texture;
texturesToBind[binding] = metalTexture->swizzledTextureView ? metalTexture->swizzledTextureView
: metalTexture->texture;
if (metalTexture->externalImage.isValid()) {
texturesToBind[binding] = metalTexture->externalImage.getMetalTextureForDraw();
@@ -1254,9 +1294,28 @@ void MetalDriver::draw(backend::PipelineState ps, Handle<HwRenderPrimitive> rph)
withRange:samplerRange];
// Bind the vertex buffers.
MetalBuffer* buffers[MAX_VERTEX_ATTRIBUTE_COUNT];
size_t vertexBufferOffsets[MAX_VERTEX_ATTRIBUTE_COUNT];
size_t bufferIndex = 0;
auto vb = primitive->vertexBuffer;
for (uint32_t attributeIndex = 0; attributeIndex < vb->attributes.size(); attributeIndex++) {
const auto& attribute = vb->attributes[attributeIndex];
if (attribute.buffer == Attribute::BUFFER_UNUSED) {
continue;
}
assert_invariant(vb->buffers[attribute.buffer]);
buffers[bufferIndex] = vb->buffers[attribute.buffer].get();
vertexBufferOffsets[bufferIndex] = attribute.offset;
bufferIndex++;
}
const auto bufferCount = bufferIndex;
MetalBuffer::bindBuffers(getPendingCommandBuffer(mContext), mContext->currentRenderPassEncoder,
VERTEX_BUFFER_START, MetalBuffer::Stage::VERTEX, primitive->buffers.data(),
primitive->offsets.data(), primitive->buffers.size());
VERTEX_BUFFER_START, MetalBuffer::Stage::VERTEX, buffers,
vertexBufferOffsets, bufferCount);
// Bind the zero buffer, used for missing vertex attributes.
static const char bytes[16] = { 0 };
+25
View File
@@ -419,6 +419,31 @@ constexpr inline MTLCompareFunction getCompareFunction(SamplerCompareFunc compar
}
}
API_AVAILABLE(macos(10.15), ios(13.0))
constexpr inline MTLTextureSwizzle getSwizzle(TextureSwizzle swizzle) {
switch (swizzle) {
case TextureSwizzle::SUBSTITUTE_ZERO:
return MTLTextureSwizzleZero;
case TextureSwizzle::SUBSTITUTE_ONE:
return MTLTextureSwizzleOne;
case TextureSwizzle::CHANNEL_0:
return MTLTextureSwizzleRed;
case TextureSwizzle::CHANNEL_1:
return MTLTextureSwizzleGreen;
case TextureSwizzle::CHANNEL_2:
return MTLTextureSwizzleBlue;
case TextureSwizzle::CHANNEL_3:
return MTLTextureSwizzleAlpha;
}
}
API_AVAILABLE(macos(10.15), ios(13.0))
inline MTLTextureSwizzleChannels getSwizzleChannels(TextureSwizzle r, TextureSwizzle g, TextureSwizzle b,
TextureSwizzle a) {
return MTLTextureSwizzleChannelsMake(getSwizzle(r), getSwizzle(g), getSwizzle(b),
getSwizzle(a));
}
} // namespace backend
} // namespace filament
+23 -7
View File
@@ -112,12 +112,24 @@ private:
void* frameCompletedUserData = nullptr;
};
class MetalBufferObject : public HwBufferObject {
public:
MetalBufferObject(MetalContext& context, uint32_t byteCount);
void updateBuffer(void* data, size_t size, uint32_t byteOffset);
const std::shared_ptr<MetalBuffer>& getBuffer() const { return buffer; }
private:
uint32_t byteCount;
std::shared_ptr<MetalBuffer> buffer = nullptr;
};
struct MetalVertexBuffer : public HwVertexBuffer {
MetalVertexBuffer(MetalContext& context, uint8_t bufferCount, uint8_t attributeCount,
uint32_t vertexCount, AttributeArray const& attributes);
~MetalVertexBuffer();
uint32_t vertexCount, AttributeArray const& attributes, bool bufferObjectsEnabled);
std::vector<MetalBuffer*> buffers;
std::vector<std::shared_ptr<MetalBuffer>> buffers;
};
struct MetalIndexBuffer : public HwIndexBuffer {
@@ -142,9 +154,6 @@ struct MetalRenderPrimitive : public HwRenderPrimitive {
// This struct is used to create the pipeline description to describe vertex assembly.
VertexDescription vertexDescription = {};
std::vector<MetalBuffer*> buffers;
std::vector<NSUInteger> offsets;
};
struct MetalProgram : public HwProgram {
@@ -158,7 +167,8 @@ struct MetalProgram : public HwProgram {
struct MetalTexture : public HwTexture {
MetalTexture(MetalContext& context, SamplerType target, uint8_t levels, TextureFormat format,
uint8_t samples, uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage)
uint8_t samples, uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage,
TextureSwizzle r, TextureSwizzle g, TextureSwizzle b, TextureSwizzle a)
noexcept;
// Constructor for importing an id<MTLTexture> outside of Filament.
@@ -182,6 +192,12 @@ struct MetalTexture : public HwTexture {
MetalContext& context;
MetalExternalImage externalImage;
id<MTLTexture> texture = nil;
// If non-nil, a swizzled texture view to use instead of "texture".
// Filament swizzling only affects texture reads, so this should not be used when the texture is
// bound as a render target attachment.
id<MTLTexture> swizzledTextureView = nil;
uint8_t bytesPerElement; // The number of bytes per pixel, or block (for compressed texture formats).
uint8_t blockWidth; // The number of horizontal pixels per block (only for compressed texture formats).
uint8_t blockHeight; // The number of vertical pixels per block (only for compressed texture formats).
+47 -19
View File
@@ -266,11 +266,27 @@ void MetalSwapChain::scheduleFrameCompletedCallback() {
}];
}
MetalBufferObject::MetalBufferObject(MetalContext& context, uint32_t byteCount)
: byteCount(byteCount), buffer(std::make_shared<MetalBuffer>(context, byteCount)) {}
void MetalBufferObject::updateBuffer(void* data, size_t size, uint32_t byteOffset) {
assert_invariant(byteOffset + size <= byteCount);
buffer->copyIntoBuffer(data, size);
}
MetalVertexBuffer::MetalVertexBuffer(MetalContext& context, uint8_t bufferCount,
uint8_t attributeCount, uint32_t vertexCount, AttributeArray const& attributes)
: HwVertexBuffer(bufferCount, attributeCount, vertexCount, attributes) {
uint8_t attributeCount, uint32_t vertexCount, AttributeArray const& attributes,
bool bufferObjectsEnabled)
: HwVertexBuffer(bufferCount, attributeCount, vertexCount, attributes, bufferObjectsEnabled) {
buffers.reserve(bufferCount);
if (bufferObjectsEnabled) {
// If BufferObjects are used, we don't need to make any allocations. Simply reserve enough
// "slots" for future calls to setVertexBufferObject.
buffers.resize(bufferCount);
return;
}
for (uint8_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex) {
// Calculate buffer size.
uint32_t size = 0;
@@ -281,21 +297,14 @@ MetalVertexBuffer::MetalVertexBuffer(MetalContext& context, uint8_t bufferCount,
}
}
MetalBuffer* buffer = nullptr;
std::shared_ptr<MetalBuffer> buffer = nullptr;
if (size > 0) {
buffer = new MetalBuffer(context, size);
buffer = std::make_shared<MetalBuffer>(context, size);
}
buffers.push_back(buffer);
}
}
MetalVertexBuffer::~MetalVertexBuffer() {
for (auto* b : buffers) {
delete b;
}
buffers.clear();
}
MetalIndexBuffer::MetalIndexBuffer(MetalContext& context, uint8_t elementSize, uint32_t indexCount)
: HwIndexBuffer(elementSize, indexCount), buffer(context, elementSize * indexCount, true) { }
@@ -309,10 +318,6 @@ void MetalRenderPrimitive::setBuffers(MetalVertexBuffer* vertexBuffer, MetalInde
const size_t attributeCount = vertexBuffer->attributes.size();
buffers.clear();
buffers.reserve(attributeCount);
offsets.clear();
offsets.reserve(attributeCount);
vertexDescription = {};
// Each attribute gets its own vertex buffer.
@@ -339,9 +344,6 @@ void MetalRenderPrimitive::setBuffers(MetalVertexBuffer* vertexBuffer, MetalInde
continue;
}
buffers.push_back(vertexBuffer->buffers[attribute.buffer]);
offsets.push_back(attribute.offset);
vertexDescription.attributes[attributeIndex] = {
.format = getMetalFormat(attribute.type,
attribute.flags & Attribute::FLAG_NORMALIZED),
@@ -416,7 +418,8 @@ static MTLPixelFormat decidePixelFormat(id<MTLDevice> device, TextureFormat form
MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth,
TextureUsage usage) noexcept
TextureUsage usage, TextureSwizzle r, TextureSwizzle g, TextureSwizzle b,
TextureSwizzle a) noexcept
: HwTexture(target, levels, samples, width, height, depth, format, usage), context(context),
externalImage(context), reshaper(format) {
@@ -515,6 +518,31 @@ MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t le
texture = nil;
break;
}
// If swizzling is set, set up a swizzled texture view that we'll use when sampling this texture.
const bool isDefaultSwizzle =
r == TextureSwizzle::CHANNEL_0 &&
g == TextureSwizzle::CHANNEL_1 &&
b == TextureSwizzle::CHANNEL_2 &&
a == TextureSwizzle::CHANNEL_3;
// If texture is nil, then it must be a SAMPLER_EXTERNAL texture. We'll ignore this case for now.
// TODO: implement swizzling for external textures.
if (!isDefaultSwizzle && texture) {
if (@available(macOS 10.15, iOS 13, *)) {
NSUInteger slices = texture.arrayLength;
if (texture.textureType == MTLTextureTypeCube ||
texture.textureType == MTLTextureTypeCubeArray) {
slices *= 6;
}
NSUInteger mips = texture.mipmapLevelCount;
MTLTextureSwizzleChannels swizzle = getSwizzleChannels(r, g, b, a);
swizzledTextureView = [texture newTextureViewWithPixelFormat:texture.pixelFormat
textureType:texture.textureType
levels:NSMakeRange(0, mips)
slices:NSMakeRange(0, slices)
swizzle:swizzle];
}
}
}
MetalTexture::MetalTexture(MetalContext& context, SamplerType target, uint8_t levels, TextureFormat format,
+16
View File
@@ -85,6 +85,9 @@ void NoopDriver::destroyVertexBuffer(Handle<HwVertexBuffer> vbh) {
void NoopDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
}
void NoopDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
}
void NoopDriver::destroyTexture(Handle<HwTexture> th) {
}
@@ -144,6 +147,10 @@ bool NoopDriver::isTextureFormatSupported(TextureFormat format) {
return true;
}
bool NoopDriver::isTextureSwizzleSupported() {
return true;
}
bool NoopDriver::isTextureFormatMipmappable(backend::TextureFormat format) {
return true;
}
@@ -178,6 +185,15 @@ void NoopDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&&
scheduleDestroy(std::move(p));
}
void NoopDriver::updateBufferObject(Handle<HwBufferObject> ibh, BufferDescriptor&& p,
uint32_t byteOffset) {
scheduleDestroy(std::move(p));
}
void NoopDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, size_t index,
Handle<HwBufferObject> boh) {
}
void NoopDriver::update2DImage(Handle<HwTexture> th,
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height,
PixelBufferDescriptor&& data) {
@@ -22,6 +22,8 @@
#include <utils/CString.h>
#include <utils/debug.h>
#include <backend/Handle.h>
#include "GLUtils.h"
#include <set>
@@ -35,11 +37,23 @@ public:
typedef math::details::TVec4<GLint> vec4gli;
typedef math::details::TVec2<GLclampf> vec2glf;
// TODO: the footprint of this structure can be reduced. We need only 1 bit for index type, 16
// bits for vertexAttribArray. We can also use fewer bits for vertexBufferVersion, although
// this will require a corollary update in OpenGLDriver::setVertexBufferObject().
struct RenderPrimitive {
GLuint vao = 0;
GLenum indicesType = GL_UNSIGNED_INT;
GLuint elementArray = 0;
utils::bitset32 vertexAttribArray;
// The optional 32-bit handle to a GLVertexBuffer is necessary only if the referenced
// VertexBuffer supports buffer objects. If this is zero, then the VBO handles array is
// immutable.
backend::Handle<backend::HwVertexBuffer> vertexBufferWithObjects = {};
// If this version number does not match vertexBufferWithObjects->bufferObjectsVersion,
// then the VAO needs to be updated.
uint8_t vertexBufferVersion = 0;
} gl;
OpenGLContext() noexcept;
+158 -35
View File
@@ -412,6 +412,10 @@ Handle<HwIndexBuffer> OpenGLDriver::createIndexBufferS() noexcept {
return initHandle<GLIndexBuffer>();
}
Handle<HwBufferObject> OpenGLDriver::createBufferObjectS() noexcept {
return initHandle<GLBufferObject>();
}
Handle<HwRenderPrimitive> OpenGLDriver::createRenderPrimitiveS() noexcept {
return initHandle<GLRenderPrimitive>();
}
@@ -478,12 +482,13 @@ void OpenGLDriver::createVertexBufferR(
uint8_t attributeCount,
uint32_t elementCount,
AttributeArray attributes,
BufferUsage usage) {
BufferUsage usage,
bool bufferObjectsEnabled) {
DEBUG_MARKER()
auto& gl = mContext;
GLVertexBuffer* vb = construct<GLVertexBuffer>(vbh,
bufferCount, attributeCount, elementCount, attributes);
bufferCount, attributeCount, elementCount, attributes, bufferObjectsEnabled);
GLsizei n = GLsizei(vb->bufferCount);
@@ -524,6 +529,24 @@ void OpenGLDriver::createIndexBufferR(
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::createBufferObjectR(
Handle<HwBufferObject> boh,
uint32_t byteCount,
BufferObjectBinding bindingType) {
DEBUG_MARKER()
auto& gl = mContext;
GLBufferObject* bo = construct<GLBufferObject>(boh);
glGenBuffers(1, &bo->gl.id);
gl.bindVertexArray(nullptr);
assert_invariant(bindingType == BufferObjectBinding::VERTEX);
gl.bindBuffer(GL_ARRAY_BUFFER, bo->gl.id);
glBufferData(GL_ARRAY_BUFFER, byteCount, nullptr, GL_STATIC_DRAW);
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph, int) {
DEBUG_MARKER()
@@ -757,6 +780,57 @@ void OpenGLDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::updateVertexArrayObject(GLRenderPrimitive* rp, GLVertexBuffer const* vb) {
auto& gl = mContext;
// NOTE: this is called from draw() and must be as efficient as possible.
// The VAO for the given render primitive must already be bound.
#ifndef NDEBUG
GLint vaoBinding;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &vaoBinding);
assert_invariant(vaoBinding == (GLint) rp->gl.vao);
#endif
rp->gl.vertexBufferVersion = vb->bufferObjectsVersion;
rp->maxVertexCount = vb->vertexCount;
for (size_t i = 0, n = vb->attributes.size(); i < n; i++) {
const auto& attribute = vb->attributes[i];
if (attribute.buffer != Attribute::BUFFER_UNUSED) {
uint8_t bi = attribute.buffer;
gl.bindBuffer(GL_ARRAY_BUFFER, vb->gl.buffers[bi]);
if (UTILS_UNLIKELY(attribute.flags & Attribute::FLAG_INTEGER_TARGET)) {
glVertexAttribIPointer(GLuint(i),
getComponentCount(attribute.type),
getComponentType(attribute.type),
attribute.stride,
(void*) uintptr_t(attribute.offset));
} else {
glVertexAttribPointer(GLuint(i),
getComponentCount(attribute.type),
getComponentType(attribute.type),
getNormalization(attribute.flags & Attribute::FLAG_NORMALIZED),
attribute.stride,
(void*) uintptr_t(attribute.offset));
}
gl.enableVertexAttribArray(GLuint(i));
} else {
// In some OpenGL implementations, we must supply a properly-typed placeholder for
// every integer input that is declared in the vertex shader.
if (UTILS_UNLIKELY(attribute.flags & Attribute::FLAG_INTEGER_TARGET)) {
glVertexAttribI4ui(GLuint(i), 0, 0, 0, 0);
} else {
glVertexAttrib4f(GLuint(i), 0, 0, 0, 0);
}
gl.disableVertexAttribArray(GLuint(i));
}
}
}
void OpenGLDriver::framebufferTexture(backend::TargetBufferInfo const& binfo,
GLRenderTarget const* rt, GLenum attachment) noexcept {
@@ -847,6 +921,17 @@ void OpenGLDriver::framebufferTexture(backend::TargetBufferInfo const& binfo,
}
}
// We can't use FramebufferTexture2DMultisampleEXT with GL_TEXTURE_2D_ARRAY.
if (!(target == GL_TEXTURE_2D ||
target == GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X ||
target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y ||
target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y ||
target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z ||
target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)) {
attachmentTypeNotSupportedByMSRTT = true;
}
if (rt->gl.samples <= 1 ||
(rt->gl.samples > 1 && t->samples > 1 && gl.features.multisample_texture)) {
// on GL3.2 / GLES3.1 and above multisample is handled when creating the texture.
@@ -900,6 +985,7 @@ void OpenGLDriver::framebufferTexture(backend::TargetBufferInfo const& binfo,
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment,
GL_RENDERBUFFER, t->gl.id);
}
CHECK_GL_ERROR(utils::slog.e)
} else
#endif
if (!any(t->usage & TextureUsage::SAMPLEABLE) && t->samples > 1) {
@@ -1211,6 +1297,17 @@ void OpenGLDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
}
}
void OpenGLDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
DEBUG_MARKER()
if (boh) {
auto& gl = mContext;
GLBufferObject const* bo = handle_cast<const GLBufferObject*>(boh);
gl.deleteBuffers(1, &bo->gl.id, GL_ARRAY_BUFFER);
destruct(boh, bo);
}
}
void OpenGLDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
DEBUG_MARKER()
@@ -1479,6 +1576,10 @@ bool OpenGLDriver::isTextureFormatSupported(TextureFormat format) {
return getInternalFormat(format) != 0;
}
bool OpenGLDriver::isTextureSwizzleSupported() {
return true;
}
bool OpenGLDriver::isTextureFormatMipmappable(TextureFormat format) {
// The OpenGL spec for GenerateMipmap stipulates that it returns INVALID_OPERATION unless
// the sized internal format is both color-renderable and texture-filterable.
@@ -1617,6 +1718,7 @@ void OpenGLDriver::updateVertexBuffer(Handle<HwVertexBuffer> vbh,
auto& gl = mContext;
GLVertexBuffer* eb = handle_cast<GLVertexBuffer *>(vbh);
assert_invariant(!eb->bufferObjectsEnabled && "Please use setVertexBufferObject() instead.");
gl.bindBuffer(GL_ARRAY_BUFFER, eb->gl.buffers[index]);
glBufferSubData(GL_ARRAY_BUFFER, byteOffset, p.size, p.buffer);
@@ -1626,6 +1728,29 @@ void OpenGLDriver::updateVertexBuffer(Handle<HwVertexBuffer> vbh,
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh,
size_t index, Handle<HwBufferObject> boh) {
DEBUG_MARKER()
GLVertexBuffer* vb = handle_cast<GLVertexBuffer *>(vbh);
assert_invariant(vb->bufferObjectsEnabled && "Please use updateVertexBuffer() instead.");
GLBufferObject* bo = handle_cast<GLBufferObject *>(boh);
// If the specified VBO handle is different from what's already in the slot, then update the
// slot and bump the cyclical version number. Dependent VAOs use the version number to detect
// when they should be updated.
if (vb->gl.buffers[index] != bo->gl.id) {
vb->gl.buffers[index] = bo->gl.id;
static constexpr uint32_t kMaxVersion =
std::numeric_limits<decltype(vb->bufferObjectsVersion)>::max();
const uint32_t version = vb->bufferObjectsVersion;
vb->bufferObjectsVersion = (version + 1) % kMaxVersion;
}
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::updateIndexBuffer(
Handle<HwIndexBuffer> ibh, BufferDescriptor&& p, uint32_t byteOffset) {
DEBUG_MARKER()
@@ -1643,6 +1768,22 @@ void OpenGLDriver::updateIndexBuffer(
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::updateBufferObject(
Handle<HwBufferObject> boh, BufferDescriptor&& bd, uint32_t byteOffset) {
DEBUG_MARKER()
auto& gl = mContext;
GLBufferObject* bo = handle_cast<GLBufferObject *>(boh);
gl.bindVertexArray(nullptr);
gl.bindBuffer(GL_ARRAY_BUFFER, bo->gl.id);
glBufferSubData(GL_ARRAY_BUFFER, byteOffset, bd.size, bd.buffer);
scheduleDestroy(std::move(bd));
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::loadUniformBuffer(Handle<HwUniformBuffer> ubh, BufferDescriptor&& p) {
DEBUG_MARKER()
@@ -2373,41 +2514,13 @@ void OpenGLDriver::setRenderPrimitiveBuffer(Handle<HwRenderPrimitive> rph,
CHECK_GL_ERROR(utils::slog.e)
rp->gl.indicesType = ib->elementSize == 4 ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
rp->maxVertexCount = eb->vertexCount;
for (size_t i = 0, n = eb->attributes.size(); i < n; i++) {
const auto& attribute = eb->attributes[i];
if (attribute.buffer != Attribute::BUFFER_UNUSED) {
uint8_t bi = attribute.buffer;
gl.bindBuffer(GL_ARRAY_BUFFER, eb->gl.buffers[bi]);
if (UTILS_UNLIKELY(attribute.flags & Attribute::FLAG_INTEGER_TARGET)) {
glVertexAttribIPointer(GLuint(i),
getComponentCount(attribute.type),
getComponentType(attribute.type),
attribute.stride,
(void*) uintptr_t(attribute.offset));
} else {
glVertexAttribPointer(GLuint(i),
getComponentCount(attribute.type),
getComponentType(attribute.type),
getNormalization(attribute.flags & Attribute::FLAG_NORMALIZED),
attribute.stride,
(void*) uintptr_t(attribute.offset));
}
gl.enableVertexAttribArray(GLuint(i));
} else {
rp->gl.vertexBufferWithObjects = eb->bufferObjectsEnabled ? vbh :
backend::Handle<backend::HwVertexBuffer> {};
// In some OpenGL implementations, we must supply a properly-typed placeholder for
// every integer input that is declared in the vertex shader.
if (UTILS_UNLIKELY(attribute.flags & Attribute::FLAG_INTEGER_TARGET)) {
glVertexAttribI4ui(GLuint(i), 0, 0, 0, 0);
} else {
glVertexAttrib4f(GLuint(i), 0, 0, 0, 0);
}
// update the VBO bindings in the VAO
updateVertexArrayObject(rp, eb);
gl.disableVertexAttribArray(GLuint(i));
}
}
// this records the index buffer into the currently bound VAO
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib->gl.buffer);
@@ -3104,9 +3217,19 @@ void OpenGLDriver::draw(PipelineState state, Handle<HwRenderPrimitive> rph) {
useProgram(p);
const GLRenderPrimitive* rp = handle_cast<const GLRenderPrimitive *>(rph);
GLRenderPrimitive* rp = handle_cast<GLRenderPrimitive *>(rph);
gl.bindVertexArray(&rp->gl);
// If necessary, mutate the bindings in the VAO.
VertexBufferHandle vbwo = rp->gl.vertexBufferWithObjects;
if (UTILS_UNLIKELY(vbwo)) {
const GLVertexBuffer* vb = handle_cast<GLVertexBuffer*>(vbwo);
if (rp->gl.vertexBufferVersion != vb->bufferObjectsVersion) {
updateVertexArrayObject(rp, vb);
}
}
setRasterState(state.rasterState);
gl.polygonOffset(state.polygonOffset.slope, state.polygonOffset.constant);
@@ -69,6 +69,12 @@ public:
backend::BufferUsage usage = {};
};
struct GLBufferObject : public backend::HwBufferObject {
struct {
GLuint id = 0;
} gl;
};
struct GLVertexBuffer : public backend::HwVertexBuffer {
using HwVertexBuffer::HwVertexBuffer;
struct {
@@ -315,6 +321,8 @@ private:
/* Misc... */
void updateVertexArrayObject(GLRenderPrimitive* rp, GLVertexBuffer const* vb);
void framebufferTexture(backend::TargetBufferInfo const& binfo,
GLRenderTarget const* rt, GLenum attachment) noexcept;
+82 -10
View File
@@ -446,9 +446,9 @@ void VulkanDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
void VulkanDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint8_t bufferCount,
uint8_t attributeCount, uint32_t elementCount, AttributeArray attributes,
BufferUsage usage) {
BufferUsage usage, bool bufferObjectsEnabled) {
auto vertexBuffer = construct_handle<VulkanVertexBuffer>(mHandleMap, vbh, mContext, mStagePool,
mDisposer, bufferCount, attributeCount, elementCount, attributes);
mDisposer, bufferCount, attributeCount, elementCount, attributes, bufferObjectsEnabled);
mDisposer.createDisposable(vertexBuffer, [this, vbh] () {
destruct_handle<VulkanVertexBuffer>(mHandleMap, vbh);
});
@@ -478,6 +478,22 @@ void VulkanDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
}
}
void VulkanDriver::createBufferObjectR(Handle<HwBufferObject> boh,
uint32_t byteCount, BufferObjectBinding bindingType) {
auto bufferObject = construct_handle<VulkanBufferObject>(mHandleMap, boh, mContext, mStagePool,
mDisposer, byteCount);
mDisposer.createDisposable(bufferObject, [this, boh] () {
destruct_handle<VulkanBufferObject>(mHandleMap, boh);
});
}
void VulkanDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
if (boh) {
auto bufferObject = handle_cast<VulkanBufferObject>(mHandleMap, boh);
mDisposer.removeReference(bufferObject);
}
}
void VulkanDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
TextureUsage usage) {
@@ -492,19 +508,20 @@ void VulkanDriver::createTextureSwizzledR(Handle<HwTexture> th, SamplerType targ
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
TextureUsage usage,
TextureSwizzle r, TextureSwizzle g, TextureSwizzle b, TextureSwizzle a) {
TextureSwizzle swizzleArray[] = {r, g, b, a};
const VkComponentMapping swizzleMap = getSwizzleMap(swizzleArray);
auto vktexture = construct_handle<VulkanTexture>(mHandleMap, th, mContext, target, levels,
format, samples, w, h, depth, usage, mStagePool);
format, samples, w, h, depth, usage, mStagePool, swizzleMap);
mDisposer.createDisposable(vktexture, [this, th] () {
destruct_handle<VulkanTexture>(mHandleMap, th);
});
// TODO: implement texture swizzling
}
void VulkanDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
TextureUsage usage) {
// not support in this backend
// not supported in this backend
}
void VulkanDriver::destroyTexture(Handle<HwTexture> th) {
@@ -622,6 +639,10 @@ Handle<HwIndexBuffer> VulkanDriver::createIndexBufferS() noexcept {
return alloc_handle<VulkanIndexBuffer, HwIndexBuffer>();
}
Handle<HwBufferObject> VulkanDriver::createBufferObjectS() noexcept {
return alloc_handle<VulkanBufferObject, HwBufferObject>();
}
Handle<HwTexture> VulkanDriver::createTextureS() noexcept {
return alloc_handle<VulkanTexture, HwTexture>();
}
@@ -795,6 +816,10 @@ bool VulkanDriver::isTextureFormatSupported(TextureFormat format) {
return info.optimalTilingFeatures != 0;
}
bool VulkanDriver::isTextureSwizzleSupported() {
return true;
}
bool VulkanDriver::isTextureFormatMipmappable(backend::TextureFormat format) {
switch (format) {
case TextureFormat::DEPTH16:
@@ -847,6 +872,13 @@ void VulkanDriver::updateVertexBuffer(Handle<HwVertexBuffer> vbh, size_t index,
scheduleDestroy(std::move(p));
}
void VulkanDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, size_t index,
Handle<HwBufferObject> boh) {
auto& vb = *handle_cast<VulkanVertexBuffer>(mHandleMap, vbh);
auto& bo = *handle_cast<VulkanBufferObject>(mHandleMap, boh);
vb.buffers[index] = bo.buffer;
}
void VulkanDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
uint32_t byteOffset) {
auto& ib = *handle_cast<VulkanIndexBuffer>(mHandleMap, ibh);
@@ -854,6 +886,13 @@ void VulkanDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor
scheduleDestroy(std::move(p));
}
void VulkanDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescriptor&& bd,
uint32_t byteOffset) {
auto& bo = *handle_cast<VulkanBufferObject>(mHandleMap, boh);
bo.buffer->loadFromCpu(bd.buffer, byteOffset, bd.size);
scheduleDestroy(std::move(bd));
}
void VulkanDriver::update2DImage(Handle<HwTexture> th,
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height,
PixelBufferDescriptor&& data) {
@@ -1611,13 +1650,46 @@ void VulkanDriver::draw(PipelineState pipelineState, Handle<HwRenderPrimitive> r
mContext.rasterState.colorTargetCount = rt->getColorTargetCount(mContext.currentRenderPass);
VulkanBinder::ProgramBundle shaderHandles = program->bundle;
// Declare fixed-size arrays that get passed to the binder and to vkCmdBindVertexBuffers.
VulkanBinder::VertexArray varray = {};
VkBuffer buffers[backend::MAX_VERTEX_ATTRIBUTE_COUNT] = {};
VkDeviceSize offsets[backend::MAX_VERTEX_ATTRIBUTE_COUNT] = {};
// For each attribute, append to each of the above lists.
const uint32_t bufferCount = prim.vertexBuffer->attributes.size();
for (uint32_t attribIndex = 0; attribIndex < bufferCount; attribIndex++) {
Attribute attrib = prim.vertexBuffer->attributes[attribIndex];
VkFormat vkformat = getVkFormat(attrib.type, attrib.flags & Attribute::FLAG_NORMALIZED);
// HACK: Re-use the positions buffer as a dummy buffer for disabled attributes. Filament's
// vertex shaders declare all attributes as either vec4 or uvec4 (the latter for bone
// indices), and positions are always at least 32 bits per element. Therefore we can assign
// a dummy type of either R8G8B8A8_UINT or R8G8B8A8_SNORM, depending on whether the shader
// expects to receive floats or ints.
if (attrib.buffer == Attribute::BUFFER_UNUSED) {
const bool isInteger = attrib.flags & Attribute::FLAG_INTEGER_TARGET;
vkformat = isInteger ? VK_FORMAT_R8G8B8A8_UINT : VK_FORMAT_R8G8B8A8_SNORM;
attrib = prim.vertexBuffer->attributes[0];
}
buffers[attribIndex] = prim.vertexBuffer->buffers[attrib.buffer]->getGpuBuffer();
offsets[attribIndex] = attrib.offset;
varray.attributes[attribIndex] = {
.location = attribIndex, // matches the GLSL layout specifier
.binding = attribIndex, // matches the position within vkCmdBindVertexBuffers
.format = vkformat,
};
varray.buffers[attribIndex] = {
.binding = attribIndex,
.stride = attrib.stride,
};
}
// Push state changes to the VulkanBinder instance. This is fast and does not make VK calls.
mBinder.bindProgramBundle(shaderHandles);
mBinder.bindProgramBundle(program->bundle);
mBinder.bindRasterState(mContext.rasterState);
mBinder.bindPrimitiveTopology(prim.primitiveTopology);
mBinder.bindVertexArray(prim.varray);
mBinder.bindVertexArray(varray);
// Query the program for the mapping from (SamplerGroupBinding,Offset) to (SamplerBinding),
// where "SamplerBinding" is the integer in the GLSL, and SamplerGroupBinding is the abstract
@@ -1708,8 +1780,7 @@ void VulkanDriver::draw(PipelineState pipelineState, Handle<HwRenderPrimitive> r
// Next bind the vertex buffers and index buffer. One potential performance improvement is to
// avoid rebinding these if they are already bound, but since we do not (yet) support subranges
// it would be rare for a client to make consecutive draw calls with the same render primitive.
vkCmdBindVertexBuffers(cmdbuffer, 0, (uint32_t) prim.buffers.size(),
prim.buffers.data(), prim.offsets.data());
vkCmdBindVertexBuffers(cmdbuffer, 0, bufferCount, buffers, offsets);
vkCmdBindIndexBuffer(cmdbuffer, prim.indexBuffer->buffer->getGpuBuffer(), 0,
prim.indexBuffer->indexType);
@@ -1761,6 +1832,7 @@ void VulkanDriver::debugCommand(const char* methodName) {
"loadUniformBuffer",
"updateVertexBuffer",
"updateIndexBuffer",
"updateBufferObject",
"update2DImage",
"updateCubeImage",
};
+11 -61
View File
@@ -403,18 +403,18 @@ bool VulkanRenderTarget::invalidate() {
VulkanVertexBuffer::VulkanVertexBuffer(VulkanContext& context, VulkanStagePool& stagePool,
VulkanDisposer& disposer, uint8_t bufferCount, uint8_t attributeCount,
uint32_t elementCount, AttributeArray const& attributes) :
HwVertexBuffer(bufferCount, attributeCount, elementCount, attributes) {
uint32_t elementCount, AttributeArray const& attributes, bool boEnabled) :
HwVertexBuffer(bufferCount, attributeCount, elementCount, attributes, boEnabled) {
buffers.reserve(bufferCount);
for (uint8_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex) {
uint32_t size = 0;
for (auto const& item : attributes) {
if (item.buffer == bufferIndex) {
uint32_t end = item.offset + elementCount * item.stride;
uint32_t end = item.offset + elementCount * item.stride;
size = std::max(size, end);
}
}
buffers.emplace_back(new VulkanBuffer(context, stagePool, disposer, this,
buffers.push_back(std::make_shared<VulkanBuffer>(context, stagePool, disposer, this,
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, size));
}
}
@@ -479,14 +479,14 @@ VulkanUniformBuffer::~VulkanUniformBuffer() {
VulkanTexture::VulkanTexture(VulkanContext& context, SamplerType target, uint8_t levels,
TextureFormat tformat, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
TextureUsage usage, VulkanStagePool& stagePool) :
TextureUsage usage, VulkanStagePool& stagePool, VkComponentMapping swizzle) :
HwTexture(target, levels, samples, w, h, depth, tformat, usage),
mVkFormat(backend::getVkFormat(tformat)), mContext(context), mStagePool(stagePool) {
// Vulkan does not support 24-bit depth, use the official fallback format.
if (tformat == TextureFormat::DEPTH24) {
mVkFormat = mContext.finalDepthFormat;
}
// Vulkan does not support 24-bit depth, use the official fallback format.
mVkFormat(tformat == TextureFormat::DEPTH24 ? context.finalDepthFormat :
backend::getVkFormat(tformat)),
mSwizzle(swizzle), mContext(context), mStagePool(stagePool) {
// Create an appropriately-sized device-only VkImage, but do not fill it yet.
VkImageCreateInfo imageInfo {
@@ -752,7 +752,7 @@ VkImageView VulkanTexture::getImageView(VkImageSubresourceRange range) {
.image = mTextureImage,
.viewType = mViewType,
.format = mVkFormat,
.components = {},
.components = mSwizzle,
.subresourceRange = range
};
VkImageView imageView;
@@ -868,56 +868,6 @@ void VulkanRenderPrimitive::setBuffers(VulkanVertexBuffer* vertexBuffer,
VulkanIndexBuffer* indexBuffer) {
this->vertexBuffer = vertexBuffer;
this->indexBuffer = indexBuffer;
const size_t nattrs = vertexBuffer->attributes.size();
// These vectors are passed to vkCmdBindVertexBuffers at every draw call. This binds the
// VkBuffer objects, but does not describe the structure of a vertex.
buffers.clear();
buffers.reserve(nattrs);
offsets.clear();
offsets.reserve(nattrs);
// The following fixed-size arrays are consumed by VulkanBinder. They describe the vertex
// structure, but do not specify the actual buffer objects to bind.
memset(varray.attributes, 0, sizeof(varray.attributes));
memset(varray.buffers, 0, sizeof(varray.buffers));
// For each enabled attribute, append to each of the above lists. Note that a single VkBuffer
// handle might be appended more than once, which is perfectly fine.
uint32_t bufferIndex = 0;
for (uint32_t attribIndex = 0; attribIndex < nattrs; attribIndex++) {
Attribute attrib = vertexBuffer->attributes[attribIndex];
VkFormat vkformat = getVkFormat(attrib.type, attrib.flags & Attribute::FLAG_NORMALIZED);
// HACK: Re-use the positions buffer as a dummy buffer for disabled attributes.
// We know that position exists (see earlier assert)
if (attrib.buffer == Attribute::BUFFER_UNUSED) {
// HACK: Presently, Filament's vertex shaders declare all attributes as either vec4 or
// uvec4 (the latter is for bone indices), and positions are always at least 32 bits per
// element. Therefore we can assign a dummy type of either R8G8B8A8_UINT or
// R8G8B8A8_SNORM, depending on whether the shader expects to receive floats or ints.
const bool isInteger = attrib.flags & Attribute::FLAG_INTEGER_TARGET;
vkformat = isInteger ? VK_FORMAT_R8G8B8A8_UINT : VK_FORMAT_R8G8B8A8_SNORM;
attrib = vertexBuffer->attributes[0];
}
buffers.push_back(vertexBuffer->buffers[attrib.buffer]->getGpuBuffer());
offsets.push_back(attrib.offset);
varray.attributes[bufferIndex] = {
.location = attribIndex, // matches the GLSL layout specifier
.binding = bufferIndex, // matches the position within vkCmdBindVertexBuffers
.format = vkformat,
.offset = 0
};
varray.buffers[bufferIndex] = {
.binding = bufferIndex,
.stride = attrib.stride,
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
};
bufferIndex++;
}
}
VulkanTimerQuery::VulkanTimerQuery(VulkanContext& context) : mContext(context) {
+14 -11
View File
@@ -83,8 +83,8 @@ struct VulkanSwapChain : public HwSwapChain {
struct VulkanVertexBuffer : public HwVertexBuffer {
VulkanVertexBuffer(VulkanContext& context, VulkanStagePool& stagePool, VulkanDisposer& disposer,
uint8_t bufferCount, uint8_t attributeCount, uint32_t elementCount,
AttributeArray const& attributes);
std::vector<std::unique_ptr<VulkanBuffer>> buffers;
AttributeArray const& attributes, bool bufferObjectsEnabled);
std::vector<std::shared_ptr<VulkanBuffer>> buffers;
};
struct VulkanIndexBuffer : public HwIndexBuffer {
@@ -92,11 +92,19 @@ struct VulkanIndexBuffer : public HwIndexBuffer {
uint8_t elementSize, uint32_t indexCount) : HwIndexBuffer(elementSize, indexCount),
indexType(elementSize == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32),
buffer(new VulkanBuffer(context, stagePool, disposer, this,
VK_BUFFER_USAGE_INDEX_BUFFER_BIT, elementSize * indexCount)) {}
VK_BUFFER_USAGE_INDEX_BUFFER_BIT, elementSize * indexCount)) {}
const VkIndexType indexType;
const std::unique_ptr<VulkanBuffer> buffer;
};
struct VulkanBufferObject : public HwBufferObject {
VulkanBufferObject(VulkanContext& context, VulkanStagePool& stagePool, VulkanDisposer& disposer,
uint32_t byteCount) :
buffer(new VulkanBuffer(context, stagePool, disposer, this,
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, byteCount)) {}
const std::shared_ptr<VulkanBuffer> buffer;
};
struct VulkanUniformBuffer : public HwUniformBuffer {
VulkanUniformBuffer(VulkanContext& context, VulkanStagePool& stagePool,
VulkanDisposer& disposer, uint32_t numBytes, backend::BufferUsage usage);
@@ -119,7 +127,7 @@ struct VulkanSamplerGroup : public HwSamplerGroup {
struct VulkanTexture : public HwTexture {
VulkanTexture(VulkanContext& context, SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
TextureUsage usage, VulkanStagePool& stagePool);
TextureUsage usage, VulkanStagePool& stagePool, VkComponentMapping swizzle = {});
~VulkanTexture();
void update2DImage(const PixelBufferDescriptor& data, uint32_t width, uint32_t height,
int miplevel);
@@ -164,7 +172,8 @@ private:
uint32_t width, uint32_t height, uint32_t depth,
FaceOffsets const* faceOffsets, uint32_t miplevel);
VkFormat mVkFormat;
const VkFormat mVkFormat;
const VkComponentMapping mSwizzle;
VkImageViewType mViewType;
VkImage mTextureImage = VK_NULL_HANDLE;
VkDeviceMemory mTextureImageMemory = VK_NULL_HANDLE;
@@ -182,12 +191,6 @@ struct VulkanRenderPrimitive : public HwRenderPrimitive {
VulkanVertexBuffer* vertexBuffer = nullptr;
VulkanIndexBuffer* indexBuffer = nullptr;
VkPrimitiveTopology primitiveTopology;
// The "varray" field describes the structure of the vertex and gets passed to VulkanBinder,
// which in turn passes it to vkCreateGraphicsPipelines. The "buffers" and "offsets" vectors are
// passed to vkCmdBindVertexBuffers at draw call time.
VulkanBinder::VertexArray varray;
std::vector<VkBuffer> buffers;
std::vector<VkDeviceSize> offsets;
};
struct VulkanFence : public HwFence {
@@ -380,6 +380,33 @@ PixelDataType getComponentType(VkFormat format) {
return {};
}
VkComponentMapping getSwizzleMap(TextureSwizzle swizzle[4]) {
VkComponentMapping map;
VkComponentSwizzle* dst = &map.r;
for (int i = 0; i < 4; ++i, ++dst) {
switch (swizzle[i]) {
case TextureSwizzle::SUBSTITUTE_ZERO: *dst = VK_COMPONENT_SWIZZLE_ZERO; break;
case TextureSwizzle::SUBSTITUTE_ONE: *dst = VK_COMPONENT_SWIZZLE_ONE; break;
// NOTE: In some cases, IDENTITY is equivalent to one of the other enums, in which
// case we choose IDENTITY under the premise that it could be more efficient, or
// allow for more state sharing. In practice this probably has no impact.
case TextureSwizzle::CHANNEL_0:
*dst = i == 0 ? VK_COMPONENT_SWIZZLE_IDENTITY : VK_COMPONENT_SWIZZLE_R;
break;
case TextureSwizzle::CHANNEL_1:
*dst = i == 1 ? VK_COMPONENT_SWIZZLE_IDENTITY : VK_COMPONENT_SWIZZLE_G;
break;
case TextureSwizzle::CHANNEL_2:
*dst = i == 2 ? VK_COMPONENT_SWIZZLE_IDENTITY : VK_COMPONENT_SWIZZLE_B;
break;
case TextureSwizzle::CHANNEL_3:
*dst = i == 3 ? VK_COMPONENT_SWIZZLE_IDENTITY : VK_COMPONENT_SWIZZLE_A;
break;
}
}
return map;
}
} // namespace filament
} // namespace backend
@@ -33,6 +33,7 @@ VkBlendFactor getBlendFactor(BlendFunction mode);
VkCullModeFlags getCullMode(CullingMode mode);
VkFrontFace getFrontFace(bool inverseFrontFaces);
PixelDataType getComponentType(VkFormat format);
VkComponentMapping getSwizzleMap(TextureSwizzle swizzle[4]);
} // namespace filament
} // namespace backend
+1 -1
View File
@@ -48,7 +48,7 @@ TrianglePrimitive::TrianglePrimitive(filament::backend::DriverApi& driverApi,
enabledAttributes.set(VertexAttribute::POSITION);
mVertexBuffer = mDriverApi.createVertexBuffer(1, 1, mVertexCount, attributes,
BufferUsage::STATIC);
BufferUsage::STATIC, false);
BufferDescriptor vertexBufferDesc(gVertices, sizeof(filament::math::float2) * 3, nullptr);
mDriverApi.updateVertexBuffer(mVertexBuffer, 0, std::move(vertexBufferDesc), 0);
+117
View File
@@ -0,0 +1,117 @@
/*
* 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.
*/
//! \file
#ifndef TNT_FILAMENT_BUFFEROBJECT_H
#define TNT_FILAMENT_BUFFEROBJECT_H
#include <filament/FilamentAPI.h>
#include <backend/DriverEnums.h>
#include <backend/BufferDescriptor.h>
#include <utils/compiler.h>
namespace filament {
class FBufferObject;
class Engine;
/**
* A generic GPU buffer containing data.
*
* Usage of this BufferObject is optional. For simple use cases it is not necessary. It is useful
* only when you need to share data between multiple VertexBuffer instances. It also allows you to
* efficiently swap-out the buffers in VertexBuffer.
*
* NOTE: For now this is only used for vertex data, but in the future we may use it for other things
* (e.g. compute).
*
* @see VertexBuffer
*/
class UTILS_PUBLIC BufferObject : public FilamentAPI {
struct BuilderDetails;
public:
using BufferDescriptor = backend::BufferDescriptor;
using BindingType = backend::BufferObjectBinding;
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 buffer in bytes.
* @param byteCount Maximum number of bytes the BufferObject can hold.
* @return A reference to this Builder for chaining calls.
*/
Builder& size(uint32_t byteCount) noexcept;
/**
* The binding type for this buffer object. (defaults to VERTEX)
* @param BindingType Distinguishes between SSBO, VBO, etc. For now this must be VERTEX.
* @return A reference to this Builder for chaining calls.
*/
Builder& bindingType(BindingType bindingType) noexcept;
/**
* Creates the BufferObject and returns a pointer to it. After creation, the buffer
* object is uninitialized. Use BufferObject::setBuffer() to initialize it.
*
* @param engine Reference to the filament::Engine to associate this BufferObject 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.
*
* @see IndexBuffer::setBuffer
*/
BufferObject* build(Engine& engine);
private:
friend class FBufferObject;
};
/**
* Asynchronously copy-initializes a region of this BufferObject from the data provided.
*
* @param engine Reference to the filament::Engine associated with this BufferObject.
* @param buffer A BufferDescriptor representing the data used to initialize the BufferObject.
* @param byteOffset Offset in bytes into the BufferObject
*/
void setBuffer(Engine& engine, BufferDescriptor&& buffer, uint32_t byteOffset = 0);
/**
* Returns the size of this BufferObject in elements.
* @return The maximum capacity of the BufferObject.
*/
size_t getByteCount() const noexcept;
};
} // namespace filament
#endif // TNT_FILAMENT_BUFFEROBJECT_H
+2
View File
@@ -28,6 +28,7 @@ class JobSystem;
namespace filament {
class BufferObject;
class Camera;
class ColorGrading;
class DebugRegistry;
@@ -390,6 +391,7 @@ public:
*/
Fence* createFence() noexcept;
bool destroy(const BufferObject* p); //!< Destroys a BufferObject object.
bool destroy(const VertexBuffer* p); //!< Destroys an VertexBuffer object.
bool destroy(const Fence* p); //!< Destroys a Fence object.
bool destroy(const IndexBuffer* p); //!< Destroys an IndexBuffer object.
+1 -1
View File
@@ -84,7 +84,7 @@ public:
/**
* Creates the IndexBuffer object and returns a pointer to it. After creation, the index
* buffer is uninitialized. Use IndexBuffer::setBuffer() to initialized the IndexBuffer.
* buffer is uninitialized. Use IndexBuffer::setBuffer() to initialize the IndexBuffer.
*
* @param engine Reference to the filament::Engine to associate this IndexBuffer with.
*
+7
View File
@@ -79,8 +79,12 @@ public:
using Usage = backend::TextureUsage; //!< Usage affects texel layout
using Swizzle = backend::TextureSwizzle; //!< Texture swizzle
/** @return whether a backend supports a particular format. */
static bool isTextureFormatSupported(Engine& engine, InternalFormat format) noexcept;
/** @return whether a backend supports texture swizzling. */
static bool isTextureSwizzleSupported(Engine& engine) noexcept;
static size_t computeTextureDataSize(Texture::Format format, Texture::Type type,
size_t stride, size_t height, size_t alignment) noexcept;
@@ -177,11 +181,14 @@ public:
/**
* Specifies how a texture's channels map to color components
*
* Texture Swizzle is only supported is isTextureSwizzleSupported() returns true.
*
* @param r texture channel for red component
* @param g texture channel for green component
* @param b texture channel for blue component
* @param a texture channel for alpha component
* @return This Builder, for chaining calls.
* @see Texture::isTextureSwizzleSupported()
*/
Builder& swizzle(Swizzle r, Swizzle g, Swizzle b, Swizzle a) noexcept;
+26
View File
@@ -31,6 +31,7 @@ namespace filament {
class FVertexBuffer;
class BufferObject;
class Engine;
/**
@@ -86,6 +87,17 @@ public:
*/
Builder& vertexCount(uint32_t vertexCount) noexcept;
/**
* Allows buffers to be swapped out and shared using BufferObject.
*
* If buffer objects mode is enabled, clients must call setBufferObjectAt rather than
* setBufferAt. This allows sharing of data between VertexBuffer objects, but it may
* slightly increase the memory footprint of Filament's internal bookkeeping.
*
* @param enabled If true, enables buffer object mode. False by default.
*/
Builder& enableBufferObjects(bool enabled = true) noexcept;
/**
* Sets up an attribute for this vertex buffer set.
*
@@ -154,6 +166,8 @@ public:
/**
* Asynchronously copy-initializes the specified buffer from the given buffer data.
*
* Do not use this if you called enableBufferObjects() on the Builder.
*
* @param engine Reference to the filament::Engine to associate this VertexBuffer with.
* @param bufferIndex Index of the buffer to initialize. Must be between 0
* and Builder::bufferCount() - 1.
@@ -166,6 +180,18 @@ public:
void setBufferAt(Engine& engine, uint8_t bufferIndex, BufferDescriptor&& buffer,
uint32_t byteOffset = 0);
/**
* Swaps in the given buffer object.
*
* To use this, you must first call enableBufferObjects() on the Builder.
*
* @param engine Reference to the filament::Engine to associate this VertexBuffer with.
* @param bufferIndex Index of the buffer to initialize. Must be between 0
* and Builder::bufferCount() - 1.
* @param bufferObject The handle to the GPU data that will be used in this buffer slot.
*/
void setBufferObjectAt(Engine& engine, uint8_t bufferIndex, BufferObject const* bufferObject);
/**
* Specifies the quaternion type for the "populateTangentQuaternions" utility.
*/
+42 -5
View File
@@ -196,6 +196,43 @@ public:
float maxApertureDiameter = 0.01f; //!< maximum aperture diameter in meters (zero to disable rotation)
bool enabled = false; //!< enable or disable depth of field effect
Filter filter = Filter::MEDIAN; //!< filter to use for filling gaps in the kernel
bool nativeResolution = false; //!< perform DoF processing at native resolution
/**
* Number of of rings used by the gather kernels. The number of rings affects quality
* and performance. The actual number of sample per pixel is defined
* as (ringCount * 2 - 1)^2. Here are a few commonly used values:
* 3 rings : 25 ( 5x 5 grid)
* 4 rings : 49 ( 7x 7 grid)
* 5 rings : 81 ( 9x 9 grid)
* 17 rings : 1089 (33x33 grid)
*
* With a maximum circle-of-confusion of 32, it is never necessary to use more than 17 rings.
*
* Usually all three settings below are set to the same value, however, it is often
* acceptable to use a lower ring count for the "fast tiles", which improves performance.
* Fast tiles are regions of the screen where every pixels have a similar
* circle-of-confusion radius.
*
* A value of 0 means default, which is 5 on desktop and 3 on mobile.
*
* @{
*/
uint8_t foregroundRingCount = 0; //!< number of kernel rings for foreground tiles
uint8_t backgroundRingCount = 0; //!< number of kernel rings for background tiles
uint8_t fastGatherRingCount = 0; //!< number of kernel rings for fast tiles
/** @}*/
/**
* maximum circle-of-confusion in pixels for the foreground, must be in [0, 32] range.
* A value of 0 means default, which is 32 on desktop and 24 on mobile.
*/
uint16_t maxForegroundCOC = 0;
/**
* maximum circle-of-confusion in pixels for the background, must be in [0, 32] range.
* A value of 0 means default, which is 32 on desktop and 24 on mobile.
*/
uint16_t maxBackgroundCOC = 0;
};
/**
@@ -434,11 +471,11 @@ public:
*/
void setBlendMode(BlendMode blendMode) noexcept;
/**
*
* @return blending mode set by setBlendMode
* @see setBlendMode
*/
/**
*
* @return blending mode set by setBlendMode
* @see setBlendMode
*/
BlendMode getBlendMode() const noexcept;
/**
+82
View File
@@ -0,0 +1,82 @@
/*
* 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/BufferObject.h"
#include "details/Engine.h"
#include "FilamentAPI-impl.h"
namespace filament {
struct BufferObject::BuilderDetails {
BindingType mBindingType = BindingType::VERTEX;
uint32_t mByteCount = 0;
};
using BuilderType = BufferObject;
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;
BufferObject::Builder& BufferObject::Builder::size(uint32_t byteCount) noexcept {
mImpl->mByteCount = byteCount;
return *this;
}
BufferObject::Builder& BufferObject::Builder::bindingType(BindingType bindingType) noexcept {
mImpl->mBindingType = bindingType;
return *this;
}
BufferObject* BufferObject::Builder::build(Engine& engine) {
return upcast(engine).createBufferObject(*this);
}
// ------------------------------------------------------------------------------------------------
FBufferObject::FBufferObject(FEngine& engine, const BufferObject::Builder& builder)
: mByteCount(builder->mByteCount), mBindingType(builder->mBindingType) {
FEngine::DriverApi& driver = engine.getDriverApi();
mHandle = driver.createBufferObject(builder->mByteCount, builder->mBindingType);
}
void FBufferObject::terminate(FEngine& engine) {
FEngine::DriverApi& driver = engine.getDriverApi();
driver.destroyBufferObject(mHandle);
}
void FBufferObject::setBuffer(FEngine& engine, BufferDescriptor&& buffer, uint32_t byteOffset) {
engine.getDriverApi().updateBufferObject(mHandle, std::move(buffer), byteOffset);
}
// ------------------------------------------------------------------------------------------------
// Trampoline calling into private implementation
// ------------------------------------------------------------------------------------------------
void BufferObject::setBuffer(Engine& engine,
BufferObject::BufferDescriptor&& buffer, uint32_t byteOffset) {
upcast(this)->setBuffer(upcast(engine), std::move(buffer), byteOffset);
}
size_t BufferObject::getByteCount() const noexcept {
return upcast(this)->getByteCount();
}
} // namespace filament
+14
View File
@@ -20,6 +20,7 @@
#include "ResourceAllocator.h"
#include "backend/DriverEnums.h"
#include "details/BufferObject.h"
#include "details/DFG.h"
#include "details/VertexBuffer.h"
#include "details/Fence.h"
@@ -318,6 +319,7 @@ void FEngine::shutdown() {
// this must be done after Skyboxes and before materials
destroy(mSkyboxMaterial);
cleanupResourceList(mBufferObjects);
cleanupResourceList(mIndexBuffers);
cleanupResourceList(mVertexBuffers);
cleanupResourceList(mTextures);
@@ -546,6 +548,10 @@ inline T* FEngine::create(ResourceList<T>& list, typename T::Builder const& buil
return p;
}
FBufferObject* FEngine::createBufferObject(const BufferObject::Builder& builder) noexcept {
return create(mBufferObjects, builder);
}
FVertexBuffer* FEngine::createVertexBuffer(const VertexBuffer::Builder& builder) noexcept {
return create(mVertexBuffers, builder);
}
@@ -724,6 +730,10 @@ bool FEngine::terminateAndDestroy(const T* ptr, ResourceList<T, L>& list) {
// -----------------------------------------------------------------------------------------------
bool FEngine::destroy(const FBufferObject* p) {
return terminateAndDestroy(p, mBufferObjects);
}
bool FEngine::destroy(const FVertexBuffer* p) {
return terminateAndDestroy(p, mVertexBuffers);
}
@@ -925,6 +935,10 @@ SwapChain* Engine::createSwapChain(uint32_t width, uint32_t height, uint64_t fla
return upcast(this)->createSwapChain(width, height, flags);
}
bool Engine::destroy(const BufferObject* p) {
return upcast(this)->destroy(upcast(p));
}
bool Engine::destroy(const VertexBuffer* p) {
return upcast(this)->destroy(upcast(p));
}
+130 -114
View File
@@ -14,6 +14,14 @@
* limitations under the License.
*/
#ifdef FILAMENT_TARGET_MOBILE
# define DOF_DEFAULT_RING_COUNT 3
# define DOF_DEFAULT_MAX_COC 24
#else
# define DOF_DEFAULT_RING_COUNT 5
# define DOF_DEFAULT_MAX_COC 32
#endif
#include "PostProcessManager.h"
#include "details/Engine.h"
@@ -212,6 +220,7 @@ static const MaterialInfo sMaterialList[] = {
{ "dofCoc", MATERIAL(DOFCOC) },
{ "dofMipmap", MATERIAL(DOFMIPMAP) },
{ "dofTiles", MATERIAL(DOFTILES) },
{ "dofTilesSwizzle", MATERIAL(DOFTILESSWIZZLE) },
{ "dofDilate", MATERIAL(DOFDILATE) },
{ "dof", MATERIAL(DOF) },
{ "dofMedian", MATERIAL(DOFMEDIAN) },
@@ -808,10 +817,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
}
FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input,
const View::DepthOfFieldOptions& dofOptions,
bool translucent,
const CameraInfo& cameraInfo) noexcept {
FrameGraphId<FrameGraphTexture> input, const View::DepthOfFieldOptions& dofOptions,
bool translucent, const CameraInfo& cameraInfo, float2 scale) noexcept {
FEngine& engine = mEngine;
Handle<HwRenderPrimitive> const& fullScreenRenderPrimitive = engine.getFullScreenRenderPrimitive();
@@ -920,7 +927,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
* dofResolution is used (at compile time for now) to chose between full- or quarter-resolution
* for the DoF calculations. Set to [1] for full resolution or [2] for quarter-resolution.
*/
const uint32_t dofResolution = 2;
const uint32_t dofResolution = dofOptions.nativeResolution ? 1u : 2u;
constexpr const uint32_t maxMipLevels = 4u; // mip levels at full-resolution
constexpr const uint32_t maxMipLevelsMask = (1u << maxMipLevels) - 1u;
@@ -940,9 +947,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
struct PostProcessDofDownsample {
FrameGraphId<FrameGraphTexture> color;
FrameGraphId<FrameGraphTexture> depth;
FrameGraphId<FrameGraphTexture> outForeground;
FrameGraphId<FrameGraphTexture> outBackground;
FrameGraphId<FrameGraphTexture> outCocFgBg;
FrameGraphId<FrameGraphTexture> outColor;
FrameGraphId<FrameGraphTexture> outCoc;
};
auto& ppDoFDownsample = fg.addPass<PostProcessDofDownsample>("DoF Downsample",
@@ -950,21 +956,21 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
data.color = builder.sample(input);
data.depth = builder.sample(depth);
data.outForeground = builder.createTexture("dof foreground output", {
data.outColor = builder.createTexture("dof downsample output", {
.width = width, .height = height, .levels = mipmapCount, .format = format
});
data.outBackground = builder.createTexture("dof background output", {
.width = width, .height = height, .levels = mipmapCount, .format = format
});
data.outCocFgBg = builder.createTexture("dof CoC output", {
data.outCoc = builder.createTexture("dof CoC output", {
.width = width, .height = height, .levels = mipmapCount,
.format = TextureFormat::RG16F
.format = TextureFormat::R16F,
.swizzle = {
// the next stage expects min/max CoC in the red/green channel
.r = backend::TextureSwizzle::CHANNEL_0,
.g = backend::TextureSwizzle::CHANNEL_0 },
});
data.outForeground = builder.write(data.outForeground, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
data.outBackground = builder.write(data.outBackground, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
data.outCocFgBg = builder.write(data.outCocFgBg, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
data.outColor = builder.write(data.outColor, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
data.outCoc = builder.write(data.outCoc, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
builder.declareRenderPass("DoF Target", { .attachments = {
.color = { data.outForeground, data.outBackground, data.outCocFgBg }
.color = { data.outColor, data.outCoc }
}
});
},
@@ -979,6 +985,9 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
mi->setParameter("color", color, { .filterMin = SamplerMinFilter::NEAREST });
mi->setParameter("depth", depth, { .filterMin = SamplerMinFilter::NEAREST });
mi->setParameter("cocParams", cocParams);
mi->setParameter("cocClamp", float2{
-(dofOptions.maxForegroundCOC ? dofOptions.maxForegroundCOC : DOF_DEFAULT_MAX_COC),
dofOptions.maxBackgroundCOC ? dofOptions.maxBackgroundCOC : DOF_DEFAULT_MAX_COC});
mi->setParameter("uvscale", float4{ width, height,
1.0f / colorDesc.width, 1.0f / colorDesc.height });
commitAndRender(out, material, driver);
@@ -990,9 +999,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
*/
struct PostProcessDofMipmap {
FrameGraphId<FrameGraphTexture> inOutForeground;
FrameGraphId<FrameGraphTexture> inOutBackground;
FrameGraphId<FrameGraphTexture> inOutCocFgBg;
FrameGraphId<FrameGraphTexture> inOutColor;
FrameGraphId<FrameGraphTexture> inOutCoc;
uint32_t rp[maxMipLevels];
};
@@ -1000,25 +1008,22 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
auto& ppDoFMipmap = fg.addPass<PostProcessDofMipmap>("DoF Mipmap",
[&](FrameGraph::Builder& builder, auto& data) {
data.inOutForeground = builder.sample(ppDoFDownsample->outForeground);
data.inOutBackground = builder.sample(ppDoFDownsample->outBackground);
data.inOutCocFgBg = builder.sample(ppDoFDownsample->outCocFgBg);
data.inOutColor = builder.sample(ppDoFDownsample->outColor);
data.inOutCoc = builder.sample(ppDoFDownsample->outCoc);
for (size_t i = 0; i < mipmapCount - 1u; i++) {
// make sure inputs are always multiple of two (should be true by construction)
// (this is so that we can compute clean mip levels)
assert_invariant((FTexture::valueForLevel(uint8_t(i), fg.getDescriptor(data.inOutForeground).width ) & 0x1u) == 0);
assert_invariant((FTexture::valueForLevel(uint8_t(i), fg.getDescriptor(data.inOutForeground).height) & 0x1u) == 0);
assert_invariant((FTexture::valueForLevel(uint8_t(i), fg.getDescriptor(data.inOutColor).width ) & 0x1u) == 0);
assert_invariant((FTexture::valueForLevel(uint8_t(i), fg.getDescriptor(data.inOutColor).height) & 0x1u) == 0);
auto inOutForeground = builder.createSubresource(data.inOutForeground, "Forground mip", { .level = uint8_t(i + 1) });
auto inOutBackground = builder.createSubresource(data.inOutBackground, "Background mip", { .level = uint8_t(i + 1) });
auto inOutCocFgBg = builder.createSubresource(data.inOutCocFgBg , "CocFgBg mip", { .level = uint8_t(i + 1) });
auto inOutColor = builder.createSubresource(data.inOutColor, "Color mip", { .level = uint8_t(i + 1) });
auto inOutCoc = builder.createSubresource(data.inOutCoc, "Coc mip", { .level = uint8_t(i + 1) });
inOutForeground = builder.write(inOutForeground, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
inOutBackground = builder.write(inOutBackground, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
inOutCocFgBg = builder.write(inOutCocFgBg, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
inOutColor = builder.write(inOutColor, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
inOutCoc = builder.write(inOutCoc, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
data.rp[i] = builder.declareRenderPass("DoF Target", { .attachments = {
.color = { inOutForeground, inOutBackground, inOutCocFgBg }
.color = { inOutColor, inOutCoc }
}
});
}
@@ -1026,15 +1031,13 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
auto inOutForeground = resources.getTexture(data.inOutForeground);
auto inOutBackground = resources.getTexture(data.inOutBackground);
auto inOutCocFgBg = resources.getTexture(data.inOutCocFgBg);
auto inOutColor = resources.getTexture(data.inOutColor);
auto inOutCoc = resources.getTexture(data.inOutCoc);
auto const& material = getPostProcessMaterial("dofMipmap");
FMaterialInstance* const mi = material.getMaterialInstance();
mi->setParameter("foreground", inOutForeground, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
mi->setParameter("background", inOutBackground, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
mi->setParameter("cocFgBg", inOutCocFgBg, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
mi->setParameter("color", inOutColor, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
mi->setParameter("coc", inOutCoc, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
mi->use(driver);
const PipelineState pipeline(material.getPipelineState(variant));
@@ -1055,7 +1058,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
* - Generate min/max tiles for far/near fields (continued)
*/
auto inTilesCocMaxMin = ppDoFDownsample->outCocFgBg;
auto inTilesCocMinMax = ppDoFDownsample->outCoc;
// TODO: Should the tile size be in real pixels? i.e. always 16px instead of being dependant on
// the DoF effect resolution?
@@ -1067,38 +1070,41 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
const size_t tileReductionCount = std::log2(tileSize / dofResolution);
struct PostProcessDofTiling1 {
FrameGraphId<FrameGraphTexture> inCocMaxMin;
FrameGraphId<FrameGraphTexture> outTilesCocMaxMin;
FrameGraphId<FrameGraphTexture> inCocMinMax;
FrameGraphId<FrameGraphTexture> outTilesCocMinMax;
};
const bool textureSwizzleSupported = Texture::isTextureSwizzleSupported(mEngine);
for (size_t i = 0; i < tileReductionCount; i++) {
auto& ppDoFTiling = fg.addPass<PostProcessDofTiling1>("DoF Tiling",
[&](FrameGraph::Builder& builder, auto& data) {
assert_invariant(((tileBufferWidth >> i) & 1u) == 0);
assert_invariant(((tileBufferHeight >> i) & 1u) == 0);
data.inCocMaxMin = builder.sample(inTilesCocMaxMin);
data.outTilesCocMaxMin = builder.createTexture("dof tiles output", {
data.inCocMinMax = builder.sample(inTilesCocMinMax);
data.outTilesCocMinMax = builder.createTexture("dof tiles output", {
.width = tileBufferWidth >> (i + 1u),
.height = tileBufferHeight >> (i + 1u),
.format = TextureFormat::RG16F
});
data.outTilesCocMaxMin = builder.declareRenderPass(data.outTilesCocMaxMin);
data.outTilesCocMinMax = builder.declareRenderPass(data.outTilesCocMinMax);
},
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
auto const& inputDesc = resources.getDescriptor(data.inCocMaxMin);
auto const& outputDesc = resources.getDescriptor(data.outTilesCocMaxMin);
auto const& inputDesc = resources.getDescriptor(data.inCocMinMax);
auto const& outputDesc = resources.getDescriptor(data.outTilesCocMinMax);
auto const& out = resources.getRenderPassInfo();
auto inCocMaxMin = resources.getTexture(data.inCocMaxMin);
auto const& material = getPostProcessMaterial("dofTiles");
auto inCocMinMax = resources.getTexture(data.inCocMinMax);
auto const& material = (!textureSwizzleSupported && (i == 0)) ?
getPostProcessMaterial("dofTilesSwizzle") :
getPostProcessMaterial("dofTiles");
FMaterialInstance* const mi = material.getMaterialInstance();
mi->setParameter("cocMaxMin", inCocMaxMin, { .filterMin = SamplerMinFilter::NEAREST });
mi->setParameter("cocMinMax", inCocMinMax, { .filterMin = SamplerMinFilter::NEAREST });
mi->setParameter("uvscale", float4{
outputDesc.width, outputDesc.height,
1.0f / inputDesc.width, 1.0f / inputDesc.height });
commitAndRender(out, material, driver);
});
inTilesCocMaxMin = ppDoFTiling->outTilesCocMaxMin;
inTilesCocMinMax = ppDoFTiling->outTilesCocMinMax;
}
/*
@@ -1109,33 +1115,33 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
auto dilate = [&](FrameGraphId<FrameGraphTexture> input) -> FrameGraphId<FrameGraphTexture> {
struct PostProcessDofDilate {
FrameGraphId<FrameGraphTexture> inTilesCocMaxMin;
FrameGraphId<FrameGraphTexture> outTilesCocMaxMin;
FrameGraphId<FrameGraphTexture> inTilesCocMinMax;
FrameGraphId<FrameGraphTexture> outTilesCocMinMax;
};
auto& ppDoFDilate = fg.addPass<PostProcessDofDilate>("DoF Dilate",
[&](FrameGraph::Builder& builder, auto& data) {
auto const& inputDesc = fg.getDescriptor(input);
data.inTilesCocMaxMin = builder.sample(input);
data.outTilesCocMaxMin = builder.createTexture("dof dilated tiles output", inputDesc);
data.outTilesCocMaxMin = builder.declareRenderPass(data.outTilesCocMaxMin );
data.inTilesCocMinMax = builder.sample(input);
data.outTilesCocMinMax = builder.createTexture("dof dilated tiles output", inputDesc);
data.outTilesCocMinMax = builder.declareRenderPass(data.outTilesCocMinMax );
},
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
auto const& out = resources.getRenderPassInfo();
auto inTilesCocMaxMin = resources.getTexture(data.inTilesCocMaxMin);
auto inTilesCocMinMax = resources.getTexture(data.inTilesCocMinMax);
auto const& material = getPostProcessMaterial("dofDilate");
FMaterialInstance* const mi = material.getMaterialInstance();
mi->setParameter("tiles", inTilesCocMaxMin, { .filterMin = SamplerMinFilter::NEAREST });
mi->setParameter("tiles", inTilesCocMinMax, { .filterMin = SamplerMinFilter::NEAREST });
commitAndRender(out, material, driver);
});
return ppDoFDilate->outTilesCocMaxMin;
return ppDoFDilate->outTilesCocMinMax;
};
// Tiles of 16 full-resolution pixels requires two dilate rounds to accommodate our max Coc of 32 pixels
// (note: when running at half-res, the tiles are 8 half-resolution pixels, and still need two
// dilate rounds to accommodate the mac CoC pf 16 half-resolution pixels)
auto dilated = dilate(inTilesCocMaxMin);
auto dilated = dilate(inTilesCocMinMax);
dilated = dilate(dilated);
/*
@@ -1143,66 +1149,70 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
*/
struct PostProcessDof {
FrameGraphId<FrameGraphTexture> foreground;
FrameGraphId<FrameGraphTexture> background;
FrameGraphId<FrameGraphTexture> cocFgBg;
FrameGraphId<FrameGraphTexture> tilesCocMaxMin;
FrameGraphId<FrameGraphTexture> outForeground;
FrameGraphId<FrameGraphTexture> color;
FrameGraphId<FrameGraphTexture> coc;
FrameGraphId<FrameGraphTexture> tilesCocMinMax;
FrameGraphId<FrameGraphTexture> outColor;
FrameGraphId<FrameGraphTexture> outAlpha;
};
auto& ppDoF = fg.addPass<PostProcessDof>("DoF",
[&](FrameGraph::Builder& builder, auto& data) {
data.foreground = builder.sample(ppDoFMipmap->inOutForeground);
data.background = builder.sample(ppDoFMipmap->inOutBackground);
data.cocFgBg = builder.sample(ppDoFMipmap->inOutCocFgBg);
data.tilesCocMaxMin = builder.sample(dilated);
data.color = builder.sample(ppDoFMipmap->inOutColor);
data.coc = builder.sample(ppDoFMipmap->inOutCoc);
data.tilesCocMinMax = builder.sample(dilated);
// The DoF buffer (output) doesn't need to be a multiple of 8 because it's not
// mipmapped. We just need to adjust the uv properly.
data.outForeground = builder.createTexture("dof color output", {
data.outColor = builder.createTexture("dof color output", {
.width = (colorDesc.width + (dofResolution / 2u)) / dofResolution,
.height = (colorDesc.height + (dofResolution / 2u)) / dofResolution,
.format = fg.getDescriptor(data.foreground).format
.format = fg.getDescriptor(data.color).format
});
data.outAlpha = builder.createTexture("dof alpha output", {
.width = builder.getDescriptor(data.outForeground).width,
.height = builder.getDescriptor(data.outForeground).height,
.width = builder.getDescriptor(data.outColor).width,
.height = builder.getDescriptor(data.outColor).height,
.format = TextureFormat::R8
});
data.outForeground = builder.write(data.outForeground, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
data.outAlpha = builder.write(data.outAlpha, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
data.outColor = builder.write(data.outColor, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
data.outAlpha = builder.write(data.outAlpha, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
builder.declareRenderPass("DoF Target", {
.attachments = { .color = { data.outForeground, data.outAlpha }}
.attachments = { .color = { data.outColor, data.outAlpha }}
});
},
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
auto const& out = resources.getRenderPassInfo();
auto foreground = resources.getTexture(data.foreground);
auto background = resources.getTexture(data.background);
auto cocFgBg = resources.getTexture(data.cocFgBg);
auto tilesCocMaxMin = resources.getTexture(data.tilesCocMaxMin);
auto color = resources.getTexture(data.color);
auto coc = resources.getTexture(data.coc);
auto tilesCocMinMax = resources.getTexture(data.tilesCocMinMax);
auto const& inputDesc = resources.getDescriptor(data.cocFgBg);
auto const& outputDesc = resources.getDescriptor(data.outForeground);
auto const& tilesDesc = resources.getDescriptor(data.tilesCocMaxMin);
auto const& inputDesc = resources.getDescriptor(data.coc);
auto const& outputDesc = resources.getDescriptor(data.outColor);
auto const& tilesDesc = resources.getDescriptor(data.tilesCocMinMax);
auto const& material = getPostProcessMaterial("dof");
FMaterialInstance* const mi = material.getMaterialInstance();
// it's not safe to use bilinear filtering in the general case (causes artifacts around edges)
mi->setParameter("foreground", foreground,
mi->setParameter("color", color,
{ .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
mi->setParameter("foregroundLinear", foreground,
mi->setParameter("colorLinear", color,
{ .filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST });
mi->setParameter("background", background,
mi->setParameter("coc", coc,
{ .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
mi->setParameter("cocFgBg", cocFgBg,
{ .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
mi->setParameter("tiles", tilesCocMaxMin,
mi->setParameter("tiles", tilesCocMinMax,
{ .filterMin = SamplerMinFilter::NEAREST });
mi->setParameter("cocToTexelScale", (1.0f / dofResolution) / float2{ inputDesc.width, inputDesc.height });
// The bokeh height is always correct regardless of the dynamic resolution scaling.
// (because the CoC is calculated w.r.t. the height), so we only need to adjust
// the width.
const float aspectRatio = scale.x / scale.y;
mi->setParameter("cocToTexelScale", float2{
aspectRatio / (inputDesc.width * dofResolution),
1.0 / (inputDesc.height * dofResolution)
});
mi->setParameter("cocToPixelScale", (1.0f / dofResolution));
mi->setParameter("uvscale", float4{
outputDesc.width / float(inputDesc.width),
@@ -1210,6 +1220,12 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
outputDesc.width / float(tileSize / dofResolution * tilesDesc.width),
outputDesc.height / float(tileSize / dofResolution * tilesDesc.height)
});
mi->setParameter("ringCounts", float4{
dofOptions.foregroundRingCount ? dofOptions.foregroundRingCount : DOF_DEFAULT_RING_COUNT,
dofOptions.backgroundRingCount ? dofOptions.backgroundRingCount : DOF_DEFAULT_RING_COUNT,
dofOptions.fastGatherRingCount ? dofOptions.fastGatherRingCount : DOF_DEFAULT_RING_COUNT,
0.0 // unused for now
});
mi->setParameter("bokehAngle", bokehAngle);
commitAndRender(out, material, driver);
});
@@ -1220,43 +1236,43 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
struct PostProcessDofMedian {
FrameGraphId<FrameGraphTexture> inForeground;
FrameGraphId<FrameGraphTexture> inColor;
FrameGraphId<FrameGraphTexture> inAlpha;
FrameGraphId<FrameGraphTexture> tilesCocMaxMin;
FrameGraphId<FrameGraphTexture> outForeground;
FrameGraphId<FrameGraphTexture> tilesCocMinMax;
FrameGraphId<FrameGraphTexture> outColor;
FrameGraphId<FrameGraphTexture> outAlpha;
};
auto& ppDoFMedian = fg.addPass<PostProcessDofMedian>("DoF Median",
[&](FrameGraph::Builder& builder, auto& data) {
data.inForeground = builder.sample(ppDoF->outForeground);
data.inColor = builder.sample(ppDoF->outColor);
data.inAlpha = builder.sample(ppDoF->outAlpha);
data.tilesCocMaxMin = builder.sample(dilated);
data.tilesCocMinMax = builder.sample(dilated);
data.outForeground = builder.createTexture("dof color output", fg.getDescriptor(data.inForeground));
data.outAlpha = builder.createTexture("dof alpha output", fg.getDescriptor(data.inAlpha));
data.outForeground = builder.write(data.outForeground, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
data.outAlpha = builder.write(data.outAlpha, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
data.outColor = builder.createTexture("dof color output", fg.getDescriptor(data.inColor));
data.outAlpha = builder.createTexture("dof alpha output", fg.getDescriptor(data.inAlpha));
data.outColor = builder.write(data.outColor, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
data.outAlpha = builder.write(data.outAlpha, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
builder.declareRenderPass("DoF Target", {
.attachments = { .color = { data.outForeground, data.outAlpha }}
.attachments = { .color = { data.outColor, data.outAlpha }}
});
},
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
auto const& out = resources.getRenderPassInfo();
auto inForeground = resources.getTexture(data.inForeground);
auto inColor = resources.getTexture(data.inColor);
auto inAlpha = resources.getTexture(data.inAlpha);
auto tilesCocMaxMin = resources.getTexture(data.tilesCocMaxMin);
auto tilesCocMinMax = resources.getTexture(data.tilesCocMinMax);
auto const& outputDesc = resources.getDescriptor(data.outForeground);
auto const& tilesDesc = resources.getDescriptor(data.tilesCocMaxMin);
auto const& outputDesc = resources.getDescriptor(data.outColor);
auto const& tilesDesc = resources.getDescriptor(data.tilesCocMinMax);
auto const& material = getPostProcessMaterial("dofMedian");
FMaterialInstance* const mi = material.getMaterialInstance();
mi->setParameter("dof", inForeground, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
mi->setParameter("dof", inColor, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
mi->setParameter("alpha", inAlpha, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
mi->setParameter("tiles", tilesCocMaxMin, { .filterMin = SamplerMinFilter::NEAREST });
mi->setParameter("tiles", tilesCocMinMax, { .filterMin = SamplerMinFilter::NEAREST });
mi->setParameter("uvscale", float2{
outputDesc.width / float(tileSize / dofResolution * tilesDesc.width),
outputDesc.height / float(tileSize / dofResolution * tilesDesc.height)
@@ -1269,10 +1285,10 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
* DoF recombine
*/
auto outForeground = ppDoFMedian->outForeground;
auto outColor = ppDoFMedian->outColor;
auto outAlpha = ppDoFMedian->outAlpha;
if (dofOptions.filter == View::DepthOfFieldOptions::Filter::NONE) {
outForeground = ppDoF->outForeground;
outColor = ppDoF->outColor;
outAlpha = ppDoF->outAlpha;
}
@@ -1280,16 +1296,16 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> color;
FrameGraphId<FrameGraphTexture> dof;
FrameGraphId<FrameGraphTexture> alpha;
FrameGraphId<FrameGraphTexture> tilesCocMaxMin;
FrameGraphId<FrameGraphTexture> tilesCocMinMax;
FrameGraphId<FrameGraphTexture> output;
};
auto& ppDoFCombine = fg.addPass<PostProcessDofCombine>("DoF combine",
[&](FrameGraph::Builder& builder, auto& data) {
data.color = builder.sample(input);
data.dof = builder.sample(outForeground);
data.dof = builder.sample(outColor);
data.alpha = builder.sample(outAlpha);
data.tilesCocMaxMin = builder.sample(dilated);
data.tilesCocMinMax = builder.sample(dilated);
auto const& inputDesc = fg.getDescriptor(data.color);
data.output = builder.createTexture("DoF output", inputDesc);
data.output = builder.declareRenderPass(data.output);
@@ -1297,20 +1313,20 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
auto const& dofDesc = resources.getDescriptor(data.dof);
auto const& tilesDesc = resources.getDescriptor(data.tilesCocMaxMin);
auto const& tilesDesc = resources.getDescriptor(data.tilesCocMinMax);
auto const& out = resources.getRenderPassInfo();
auto color = resources.getTexture(data.color);
auto dof = resources.getTexture(data.dof);
auto alpha = resources.getTexture(data.alpha);
auto tilesCocMaxMin = resources.getTexture(data.tilesCocMaxMin);
auto tilesCocMinMax = resources.getTexture(data.tilesCocMinMax);
auto const& material = getPostProcessMaterial("dofCombine");
FMaterialInstance* const mi = material.getMaterialInstance();
mi->setParameter("color", color, { .filterMin = SamplerMinFilter::NEAREST });
mi->setParameter("dof", dof, { .filterMag = SamplerMagFilter::NEAREST });
mi->setParameter("alpha", alpha, { .filterMag = SamplerMagFilter::NEAREST });
mi->setParameter("tiles", tilesCocMaxMin, { .filterMin = SamplerMinFilter::NEAREST });
mi->setParameter("tiles", tilesCocMinMax, { .filterMin = SamplerMinFilter::NEAREST });
mi->setParameter("uvscale", float4{
colorDesc.width / (dofDesc.width * float(dofResolution)),
colorDesc.height / (dofDesc.height * float(dofResolution)),
+3 -5
View File
@@ -79,11 +79,9 @@ public:
size_t kernelWidth, float sigmaRatio = 6.0f) noexcept;
// Depth-of-field
FrameGraphId<FrameGraphTexture> dof(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input,
const View::DepthOfFieldOptions& dofOptions,
bool translucent,
const CameraInfo& cameraInfo) noexcept;
FrameGraphId<FrameGraphTexture> dof(FrameGraph& fg, FrameGraphId<FrameGraphTexture> input,
const View::DepthOfFieldOptions& dofOptions, bool translucent,
const CameraInfo& cameraInfo, math::float2 scale) noexcept;
// Color grading, tone mapping, etc.
void colorGradingPrepareSubpass(backend::DriverApi& driver, const FColorGrading* colorGrading,
+3 -3
View File
@@ -445,13 +445,13 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
});
// resolve depth -- which might be needed because of TAA or DoF. This pass will be culled
// if the depth is not use below.
// if the depth is not used below.
auto& blackboard = fg.getBlackboard();
auto depth = blackboard.get<FrameGraphTexture>("depth");
depth = ppm.resolve(fg, "Resolved Depth Buffer", depth);
blackboard.put("depth", depth);
// TODO: DoF should be applied here, before TAA -- but if we do this it'll result is a lot
// TODO: DoF should be applied here, before TAA -- but if we do this it'll result in a lot of
// fireflies due to the instability of the highlights. This can be fixed with a
// dedicated TAA pass for the DoF, as explained in
// "Life of a Bokeh" by Guillaume Abadie, SIGGRAPH 2018
@@ -466,7 +466,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
if (hasPostProcess) {
if (dofOptions.enabled) {
input = ppm.dof(fg, input, dofOptions, needsAlphaChannel, cameraInfo);
input = ppm.dof(fg, input, dofOptions, needsAlphaChannel, cameraInfo, scale);
}
if (colorGrading) {
if (!colorGradingConfig.asSubpass) {
+16 -6
View File
@@ -109,9 +109,10 @@ void ResourceAllocator::destroyRenderTarget(RenderTargetHandle h) noexcept {
}
backend::TextureHandle ResourceAllocator::createTexture(const char* name,
backend::SamplerType target, uint8_t levels,
backend::TextureFormat format, uint8_t samples, uint32_t width, uint32_t height,
uint32_t depth, backend::TextureUsage usage) noexcept {
backend::SamplerType target, uint8_t levels, backend::TextureFormat format, uint8_t samples,
uint32_t width, uint32_t height, uint32_t depth,
std::array<backend::TextureSwizzle, 4> swizzle,
backend::TextureUsage usage) noexcept {
// Some WebGL implementations complain about an incomplete framebuffer when the attachment sizes
// are heterogeneous. This merits further investigation.
@@ -133,7 +134,7 @@ backend::TextureHandle ResourceAllocator::createTexture(const char* name,
TextureHandle handle;
if (mEnabled) {
auto& textureCache = mTextureCache;
const TextureKey key{ name, target, levels, format, samples, width, height, depth, usage };
const TextureKey key{ name, target, levels, format, samples, width, height, depth, usage, swizzle };
auto it = textureCache.find(key);
if (UTILS_LIKELY(it != textureCache.end())) {
// we do, move the entry to the in-use list, and remove from the cache
@@ -142,8 +143,17 @@ backend::TextureHandle ResourceAllocator::createTexture(const char* name,
textureCache.erase(it);
} else {
// we don't, allocate a new texture and populate the in-use list
handle = mBackend.createTexture(
target, levels, format, samples, width, height, depth, usage);
using TS = backend::TextureSwizzle;
constexpr const auto defaultSwizzle = std::array<backend::TextureSwizzle, 4>{
TS::CHANNEL_0, TS::CHANNEL_1, TS::CHANNEL_2, TS::CHANNEL_3};
if (swizzle == defaultSwizzle) {
handle = mBackend.createTexture(
target, levels, format, samples, width, height, depth, usage);
} else {
handle = mBackend.createTextureSwizzled(
target, levels, format, samples, width, height, depth, usage,
swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
}
}
mInUseTextures.emplace(handle, key);
} else {
+16 -7
View File
@@ -25,6 +25,7 @@
#include <utils/Hash.h>
#include <array>
#include <vector>
#include <stdint.h>
@@ -47,9 +48,10 @@ public:
virtual void destroyRenderTarget(backend::RenderTargetHandle h) noexcept = 0;
virtual backend::TextureHandle createTexture(const char* name, backend::SamplerType target,
uint8_t levels,
backend::TextureFormat format, uint8_t samples, uint32_t width, uint32_t height,
uint32_t depth, backend::TextureUsage usage) noexcept = 0;
uint8_t levels,backend::TextureFormat format, uint8_t samples,
uint32_t width, uint32_t height, uint32_t depth,
std::array<backend::TextureSwizzle, 4> swizzle,
backend::TextureUsage usage) noexcept = 0;
virtual void destroyTexture(backend::TextureHandle h) noexcept = 0;
@@ -77,9 +79,10 @@ public:
void destroyRenderTarget(backend::RenderTargetHandle h) noexcept override;
backend::TextureHandle createTexture(const char* name, backend::SamplerType target,
uint8_t levels,
backend::TextureFormat format, uint8_t samples, uint32_t width, uint32_t height,
uint32_t depth, backend::TextureUsage usage) noexcept override;
uint8_t levels, backend::TextureFormat format, uint8_t samples,
uint32_t width, uint32_t height, uint32_t depth,
std::array<backend::TextureSwizzle, 4> swizzle,
backend::TextureUsage usage) noexcept override;
void destroyTexture(backend::TextureHandle h) noexcept override;
@@ -100,6 +103,7 @@ private:
uint32_t height;
uint32_t depth;
backend::TextureUsage usage;
std::array<backend::TextureSwizzle, 4> swizzle;
size_t getSize() const noexcept;
@@ -111,7 +115,8 @@ private:
width == other.width &&
height == other.height &&
depth == other.depth &&
usage == other.usage;
usage == other.usage &&
swizzle == other.swizzle;
}
friend size_t hash_value(TextureKey const& k) {
@@ -124,6 +129,10 @@ private:
utils::hash::combine_fast(seed, k.height);
utils::hash::combine_fast(seed, k.depth);
utils::hash::combine_fast(seed, k.usage);
utils::hash::combine_fast(seed, k.swizzle[0]);
utils::hash::combine_fast(seed, k.swizzle[1]);
utils::hash::combine_fast(seed, k.swizzle[2]);
utils::hash::combine_fast(seed, k.swizzle[3]);
return seed;
}
};
+8
View File
@@ -443,6 +443,10 @@ bool FTexture::isTextureFormatSupported(FEngine& engine, InternalFormat format)
return engine.getDriverApi().isTextureFormatSupported(format);
}
bool FTexture::isTextureSwizzleSupported(FEngine& engine) noexcept {
return engine.getDriverApi().isTextureSwizzleSupported();
}
size_t FTexture::computeTextureDataSize(Texture::Format format, Texture::Type type,
size_t stride, size_t height, size_t alignment) noexcept {
return PixelBufferDescriptor::computeDataSize(format, type, stride, height, alignment);
@@ -1090,6 +1094,10 @@ bool Texture::isTextureFormatSupported(Engine& engine, InternalFormat format) no
return FTexture::isTextureFormatSupported(upcast(engine), format);
}
bool Texture::isTextureSwizzleSupported(Engine& engine) noexcept {
return FTexture::isTextureSwizzleSupported(upcast(engine));
}
size_t Texture::computeTextureDataSize(Texture::Format format, Texture::Type type, size_t stride,
size_t height, size_t alignment) noexcept {
return FTexture::computeTextureDataSize(format, type, stride, height, alignment);
+31 -4
View File
@@ -16,6 +16,7 @@
#include "details/VertexBuffer.h"
#include "details/BufferObject.h"
#include "details/Engine.h"
#include "FilamentAPI-impl.h"
@@ -36,6 +37,7 @@ struct VertexBuffer::BuilderDetails {
AttributeBitset mDeclaredAttributes;
uint32_t mVertexCount = 0;
uint8_t mBufferCount = 0;
bool mBufferObjectsEnabled = false;
};
using BuilderType = VertexBuffer;
@@ -51,6 +53,11 @@ VertexBuffer::Builder& VertexBuffer::Builder::vertexCount(uint32_t vertexCount)
return *this;
}
VertexBuffer::Builder& VertexBuffer::Builder::enableBufferObjects(bool enabled) noexcept {
mImpl->mBufferObjectsEnabled = enabled;
return *this;
}
VertexBuffer::Builder& VertexBuffer::Builder::bufferCount(uint8_t bufferCount) noexcept {
mImpl->mBufferCount = bufferCount;
return *this;
@@ -140,7 +147,8 @@ VertexBuffer* VertexBuffer::Builder::build(Engine& engine) {
// ------------------------------------------------------------------------------------------------
FVertexBuffer::FVertexBuffer(FEngine& engine, const VertexBuffer::Builder& builder)
: mVertexCount(builder->mVertexCount), mBufferCount(builder->mBufferCount) {
: mVertexCount(builder->mVertexCount), mBufferCount(builder->mBufferCount),
mBufferObjectsEnabled(builder->mBufferObjectsEnabled) {
std::copy(std::begin(builder->mAttributes), std::end(builder->mAttributes), mAttributes.begin());
mDeclaredAttributes = builder->mDeclaredAttributes;
@@ -174,7 +182,8 @@ FVertexBuffer::FVertexBuffer(FEngine& engine, const VertexBuffer::Builder& build
FEngine::DriverApi& driver = engine.getDriverApi();
mHandle = driver.createVertexBuffer(
mBufferCount, attributeCount, mVertexCount, attributeArray, backend::BufferUsage::STATIC);
mBufferCount, attributeCount, mVertexCount, attributeArray,
backend::BufferUsage::STATIC, mBufferObjectsEnabled);
}
void FVertexBuffer::terminate(FEngine& engine) {
@@ -188,12 +197,25 @@ size_t FVertexBuffer::getVertexCount() const noexcept {
void FVertexBuffer::setBufferAt(FEngine& engine, uint8_t bufferIndex,
backend::BufferDescriptor&& buffer, uint32_t byteOffset) {
ASSERT_PRECONDITION(!mBufferObjectsEnabled, "Please use setBufferObjectAt()");
if (bufferIndex < mBufferCount) {
engine.getDriverApi().updateVertexBuffer(mHandle,
bufferIndex, std::move(buffer), byteOffset);
} else {
ASSERT_PRECONDITION_NON_FATAL(bufferIndex < mBufferCount,
"bufferIndex must be < bufferCount");
ASSERT_PRECONDITION(bufferIndex < mBufferCount, "bufferIndex must be < bufferCount");
}
}
void FVertexBuffer::setBufferObjectAt(FEngine& engine, uint8_t bufferIndex,
FBufferObject const * bufferObject) {
ASSERT_PRECONDITION(mBufferObjectsEnabled, "Please use setBufferAt()");
ASSERT_PRECONDITION(bufferObject->getBindingType() == BufferObject::BindingType::VERTEX,
"Binding type must be VERTEX.");
if (bufferIndex < mBufferCount) {
auto hwBufferObject = bufferObject->getHwHandle();
engine.getDriverApi().setVertexBufferObject(mHandle, bufferIndex, hwBufferObject);
} else {
ASSERT_PRECONDITION(bufferIndex < mBufferCount, "bufferIndex must be < bufferCount");
}
}
@@ -210,6 +232,11 @@ void VertexBuffer::setBufferAt(Engine& engine, uint8_t bufferIndex,
upcast(this)->setBufferAt(upcast(engine), bufferIndex, std::move(buffer), byteOffset);
}
void VertexBuffer::setBufferObjectAt(Engine& engine, uint8_t bufferIndex,
BufferObject const* bufferObject) {
upcast(this)->setBufferObjectAt(upcast(engine), bufferIndex, upcast(bufferObject));
}
void VertexBuffer::populateTangentQuaternions(const QuatTangentContext& ctx) {
auto* quats = geometry::SurfaceOrientation::Builder()
.vertexCount(ctx.quatCount)
+58
View File
@@ -0,0 +1,58 @@
/*
* 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_BUFFEROBJECT_H
#define TNT_FILAMENT_DETAILS_BUFFEROBJECT_H
#include "upcast.h"
#include <backend/Handle.h>
#include <filament/BufferObject.h>
#include <utils/compiler.h>
namespace filament {
class FEngine;
class FBufferObject : public BufferObject {
public:
FBufferObject(FEngine& engine, const Builder& builder);
// frees driver resources, object becomes invalid
void terminate(FEngine& engine);
backend::Handle<backend::HwBufferObject> getHwHandle() const noexcept { return mHandle; }
size_t getByteCount() const noexcept { return mByteCount; }
void setBuffer(FEngine& engine, BufferDescriptor&& buffer, uint32_t byteOffset = 0);
BindingType getBindingType() const noexcept { return mBindingType; }
private:
friend class BufferObject;
backend::Handle<backend::HwBufferObject> mHandle;
uint32_t mByteCount;
BindingType mBindingType;
};
FILAMENT_UPCAST(BufferObject)
} // namespace filament
#endif // TNT_FILAMENT_DETAILS_BUFFEROBJECT_H
+4
View File
@@ -26,6 +26,7 @@
#include "components/RenderableManager.h"
#include "details/Allocators.h"
#include "details/BufferObject.h"
#include "details/Camera.h"
#include "details/DebugRegistry.h"
#include "details/Fence.h"
@@ -223,6 +224,7 @@ public:
template <typename T>
T* create(ResourceList<T>& list, typename T::Builder const& builder) noexcept;
FBufferObject* createBufferObject(const BufferObject::Builder& builder) noexcept;
FVertexBuffer* createVertexBuffer(const VertexBuffer::Builder& builder) noexcept;
FIndexBuffer* createIndexBuffer(const IndexBuffer::Builder& builder) noexcept;
FIndirectLight* createIndirectLight(const IndirectLight::Builder& builder) noexcept;
@@ -250,6 +252,7 @@ public:
void destroyCameraComponent(utils::Entity entity) noexcept;
bool destroy(const FBufferObject* p);
bool destroy(const FVertexBuffer* p);
bool destroy(const FFence* p);
bool destroy(const FIndexBuffer* p);
@@ -340,6 +343,7 @@ private:
FCameraManager mCameraManager;
ResourceAllocator* mResourceAllocator = nullptr;
ResourceList<FBufferObject> mBufferObjects{ "BufferObject" };
ResourceList<FRenderer> mRenderers{ "Renderer" };
ResourceList<FView> mViews{ "View" };
ResourceList<FScene> mScenes{ "Scene" };
+3
View File
@@ -86,6 +86,9 @@ public:
// synchronous call to the backend. returns whether a backend supports a particular format.
static bool isTextureFormatSupported(FEngine& engine, InternalFormat format) noexcept;
// synchronous call to the backend. returns whether a backend supports texture swizzling.
static bool isTextureSwizzleSupported(FEngine& engine) noexcept;
// storage needed on the CPU side for texture data uploads
static size_t computeTextureDataSize(Texture::Format format, Texture::Type type,
size_t stride, size_t height, size_t alignment) noexcept;
+5
View File
@@ -32,6 +32,7 @@
namespace filament {
class FBufferObject;
class FEngine;
class FVertexBuffer : public VertexBuffer {
@@ -53,6 +54,9 @@ public:
void setBufferAt(FEngine& engine, uint8_t bufferIndex,
backend::BufferDescriptor&& buffer, uint32_t byteOffset = 0);
void setBufferObjectAt(FEngine& engine, uint8_t bufferIndex,
FBufferObject const * bufferObject);
private:
friend class VertexBuffer;
@@ -65,6 +69,7 @@ private:
AttributeBitset mDeclaredAttributes;
uint32_t mVertexCount = 0;
uint8_t mBufferCount = 0;
bool mBufferObjectsEnabled = false;
};
FILAMENT_UPCAST(VertexBuffer)
+6 -1
View File
@@ -24,10 +24,15 @@ namespace filament {
void FrameGraphTexture::create(ResourceAllocatorInterface& resourceAllocator, const char* name,
FrameGraphTexture::Descriptor const& descriptor, FrameGraphTexture::Usage usage) noexcept {
std::array<backend::TextureSwizzle, 4> swizzle = {
descriptor.swizzle.r,
descriptor.swizzle.g,
descriptor.swizzle.b,
descriptor.swizzle.a };
handle = resourceAllocator.createTexture(name,
descriptor.type, descriptor.levels, descriptor.format, descriptor.samples,
descriptor.width, descriptor.height, descriptor.depth,
usage);
swizzle, usage);
}
void FrameGraphTexture::destroy(ResourceAllocatorInterface& resourceAllocator) noexcept {
+10
View File
@@ -49,6 +49,16 @@ struct FrameGraphTexture {
uint8_t samples = 0; // 0=auto, 1=request not multisample, >1 only for NOT SAMPLEABLE
backend::SamplerType type = backend::SamplerType::SAMPLER_2D; // texture target type
backend::TextureFormat format = backend::TextureFormat::RGBA8; // resource internal format
struct {
using TS = backend::TextureSwizzle;
union {
backend::TextureSwizzle channels[4] = {
TS::CHANNEL_0, TS::CHANNEL_1, TS::CHANNEL_2, TS::CHANNEL_3 };
struct {
backend::TextureSwizzle r, g, b, a;
};
};
} swizzle;
};
/** Describes a FrameGraphTexture sub-resource */
+75 -52
View File
@@ -3,22 +3,17 @@ material {
parameters : [
{
type : sampler2d,
name : foreground,
name : color,
precision: medium
},
{
type : sampler2d,
name : foregroundLinear,
name : colorLinear,
precision: medium
},
{
type : sampler2d,
name : background,
precision: medium
},
{
type : sampler2d,
name : cocFgBg,
name : coc,
precision: medium
},
{
@@ -36,14 +31,19 @@ material {
name : cocToPixelScale,
precision: medium
},
{
type : float,
name : bokehAngle,
},
{
type : float4,
name : uvscale,
precision: high
},
{
type : float,
name : bokehAngle,
type : float4,
name : ringCounts,
precision: medium
}
],
outputs : [
@@ -80,20 +80,6 @@ fragment {
#define DOF_DIAPHRAGM_STRAIGHT_BLADES 1
#define DOF_DIAPHRAGM DOF_DIAPHRAGM_CIRCLE
// # of sample w.r.t. ring count and density of 8
// 3 rings : 25 ( 5^2 grid)
// 4 rings : 49 ( 7^2 grid)
// 5 rings : 81 ( 9^2 grid)
// 17 rings : 1089 (33^2 grid) -- maximum needed for a CoC of 32
#if defined(TARGET_MOBILE)
#define RING_COUNT_GATHER 3
#define RING_COUNT_FAST 3
#else
#define RING_COUNT_GATHER 4
#define RING_COUNT_FAST 4
#endif
// Enabled by default. Mipmaped taps look a lot better, but do cause some
// aliasing issues which force us to set all sample weights to 1.0
// This is here mostly for debugging.
@@ -111,6 +97,22 @@ struct NoiseState {
vec2 randomDisk;
};
// # of sample w.r.t. ring count and density of 8
// 3 rings : 25 ( 5^2 grid)
// 4 rings : 49 ( 7^2 grid)
// 5 rings : 81 ( 9^2 grid)
// 17 rings : 1089 (33^2 grid) -- maximum needed for a CoC of 32
float ringCountForeground() {
return materialParams.ringCounts[0];
}
float ringCountBackground() {
return materialParams.ringCounts[1];
}
float ringCountFast() {
return materialParams.ringCounts[2];
}
float sampleCount(const float ringCount) {
float s = (ringCount * 2.0 - 1.0);
return s * s;
@@ -207,8 +209,9 @@ struct Bucket {
precision mediump float;
struct Sample {
vec4 s; // sample color
float coc; // sample coc
vec4 s; // sample color
float coc; // sample coc
float inLayer; // whether is sample is in the considered layer
};
void initBucket(out Bucket ring) {
@@ -268,7 +271,7 @@ void mergeRings(inout Bucket curr, inout Bucket prev, const float count) {
void accumulate(inout Bucket curr, inout Bucket prev, const Sample tap,
const float radius, const float border, const float mip, const bool first) {
float inLayer = isBackground(tap.coc);
float inLayer = tap.inLayer;
float coc = abs(tap.coc);
float w = inLayer * intersection(radius, coc, mip) * sampleWeight(coc, mip);
@@ -303,16 +306,43 @@ void accumulate(inout Bucket curr, inout Bucket prev, const Sample tap,
void accumulateBackground(inout Bucket curr, inout Bucket prev, const highp vec2 pos,
const float radius, const float border, const float mip, const bool first) {
Sample tap;
tap.s = textureLod(materialParams_foreground, pos, mip);
tap.coc = textureLod(materialParams_cocFgBg, pos, mip).r;
tap.s = textureLod(materialParams_color, pos, mip);
tap.coc = textureLod(materialParams_coc, pos, mip).r;
tap.inLayer = isBackground(tap.coc);
accumulate(curr, prev, tap, radius, border, mip, first);
}
void accumulateBackgroundMirror(inout Bucket curr, inout Bucket prev,
const highp vec2 center, const vec2 offset,
const float radius, const float border, const float mip, const bool first) {
accumulateBackground(curr, prev, diaphragm(center, offset), radius, border, mip, first);
accumulateBackground(curr, prev, diaphragm(center, -offset), radius, border, mip, first);
// The code below is equivalent (without hole filling) to:
// accumulateBackground(curr, prev, diaphragm(center, offset), radius, border, mip, first);
// accumulateBackground(curr, prev, diaphragm(center, -offset), radius, border, mip, first);
// return;
// We use the technique used by Jimenez for the foreground applied to the background, where
// we "guess" the missing background information from neighboring pixels. In several papers it's
// not deemed useful for the background, however, it does improve the blur quality a lot very
// shallow DoF, i.e. when a moderately blurred background sits over a strongly blured one.
Sample tap0;
Sample tap1;
highp vec2 pos0 = diaphragm(center, offset);
tap0.coc = textureLod(materialParams_coc, pos0, mip).r;
highp vec2 pos1 = diaphragm(center, -offset);
tap1.coc = textureLod(materialParams_coc, pos1, mip).r;
float coc = min(tap0.coc, tap1.coc);
tap0.coc =
tap1.coc = coc;
tap0.inLayer =
tap1.inLayer = isBackground(coc);
tap0.s = textureLod(materialParams_color, pos0, mip);
accumulate(curr, prev, tap0, radius, border, mip, first);
tap1.s = textureLod(materialParams_color, pos1, mip);
accumulate(curr, prev, tap1, radius, border, mip, first);
}
void accumulateBackgroundCenter(inout Bucket prev,
@@ -384,8 +414,8 @@ float foregroundFadding(const float coc) {
void accumulateForeground(inout Layer layer[2], const vec2 tiles,
const highp vec2 pos, const float border, const float mip) {
float coc = textureLod(materialParams_cocFgBg, pos, mip).r;
vec4 s = textureLod(materialParams_foreground, pos, mip);
float coc = textureLod(materialParams_coc, pos, mip).r;
vec4 s = textureLod(materialParams_color, pos, mip);
float inLayer = isForeground(coc) * foregroundFadding(coc);
float i = intersection(border, abs(coc), mip) * sampleWeight(coc, mip);
@@ -414,12 +444,12 @@ void accumulateForegroundMirror(inout Layer layer[2], const vec2 tiles,
// the geometry.
highp vec2 pos0 = diaphragm(center, offset);
float coc0 = textureLod(materialParams_cocFgBg, pos0, mip).r;
vec4 s0 = textureLod(materialParams_foreground, pos0, mip);
float coc0 = textureLod(materialParams_coc, pos0, mip).r;
vec4 s0 = textureLod(materialParams_color, pos0, mip);
highp vec2 pos1 = diaphragm(center, -offset);
float coc1 = textureLod(materialParams_cocFgBg, pos1, mip).r;
vec4 s1 = textureLod(materialParams_foreground, pos1, mip);
float coc1 = textureLod(materialParams_coc, pos1, mip).r;
vec4 s1 = textureLod(materialParams_color, pos1, mip);
float coc = min(coc0, coc1);
float inLayer = isForeground(coc) * foregroundFadding(coc);
@@ -446,7 +476,7 @@ void fastTile(inout vec4 color, inout float alpha,
// The whole tile has mostly the same CoC
float kernelSize = (abs(tiles.r) + abs(tiles.g)) * 0.5;
float ringCountFast = min(float(RING_COUNT_FAST), computeNeededRings(kernelSize * cocToPixelScale));
float ringCountFast = min(ringCountFast(), computeNeededRings(kernelSize * cocToPixelScale));
float mip = getMipLevel(ringCountFast, kernelSize * cocToPixelScale);
vec2 noise = vec2(0.0);
@@ -457,7 +487,7 @@ void fastTile(inout vec4 color, inout float alpha,
highp vec2 uvCenter = uv + noise * cocToTexelScale;
color = textureLod(materialParams_foregroundLinear, uvCenter, mip);
color = textureLod(materialParams_colorLinear, uvCenter, mip);
for (float i = 1.0; i < ringCountFast; i += 1.0) {
float radius;
float count;
@@ -467,9 +497,9 @@ void fastTile(inout vec4 color, inout float alpha,
// we must use this temporary in order to accomodate mediump precision
vec4 t = vec4(0.0);
for (float j = 0.0; j < count; j += 2.0) {
t += textureLod(materialParams_foregroundLinear,
t += textureLod(materialParams_colorLinear,
diaphragm(uvCenter, p * cocToTexelScale), mip)
+ textureLod(materialParams_foregroundLinear,
+ textureLod(materialParams_colorLinear,
diaphragm(uvCenter, -p * cocToTexelScale), mip);
p = r * p;
}
@@ -487,7 +517,7 @@ void foregroundTile(inout vec4 foreground, inout float fgOpacity,
// Here we know that tiles.r < 0, by definition of a foreground tile.
// For a foreground tile, the kernel size is the largest CoC radius of the whole tile.
float kernelSize = -tiles.r;
float ringCountGather = min(float(RING_COUNT_GATHER), computeNeededRings(kernelSize * cocToPixelScale));
float ringCountGather = min(ringCountForeground(), computeNeededRings(kernelSize * cocToPixelScale));
float mip = getMipLevel(ringCountGather, kernelSize * cocToPixelScale);
vec2 noise = vec2(0.0);
@@ -540,9 +570,9 @@ void backgroundTile(inout vec4 background, inout float bgOpacity,
float cocToPixelScale = materialParams.cocToPixelScale;
// we select a ring cound per tile, to avoid divergence between pixels
float ringCountGather = min(float(RING_COUNT_GATHER), computeNeededRings(tiles.g * cocToPixelScale));
float ringCountGather = min(ringCountBackground(), computeNeededRings(tiles.g * cocToPixelScale));
float centerCoc = textureLod(materialParams_cocFgBg, uv, 0.0).g;
float centerCoc = textureLod(materialParams_coc, uv, 0.0).r;
float kernelSize = abs(centerCoc);
float mip = getMipLevel(ringCountGather, kernelSize * cocToPixelScale);
float noiseRadius = 0.0;
@@ -559,16 +589,9 @@ void backgroundTile(inout vec4 background, inout float bgOpacity,
initBucket(prev);
accumulateRing(prev, 0.0, ringCountGather, kernelSize, noise, uvCenter, cocToTexelScale, mip, true);
// the optimizer is not able to remove this loop when it has only one iteration
#if RING_COUNT_GATHER == 3
accumulateRing(prev, 1.0, ringCountGather, kernelSize, noise, uvCenter, cocToTexelScale, mip, false);
#else
for (float i = 1.0; i < ringCountGather - 1.0 ; i += 1.0) {
accumulateRing(prev, i, ringCountGather, kernelSize, noise, uvCenter, cocToTexelScale, mip, false);
}
#endif
accumulateBackgroundCenter(prev, uvCenter, ringCountGather, kernelSize, noiseRadius, mip);
float kernelArea = sampleWeight(kernelSize * ((ringCountGather + 0.5) / ringCountGather), mip);
@@ -647,7 +670,7 @@ void postProcess(inout PostProcessInputs postProcess) {
// TODO: make this a quality setting
if (fgOpacity > 0.0 && fgOpacity < 1.0 && bgOpacity == 0.0) {
// this happens on very few pixels
float centerCoc = textureLod(materialParams_cocFgBg, uv, 0.0).r;
float centerCoc = textureLod(materialParams_coc, uv, 0.0).r;
float correctedOpacity = max(fgOpacity, cocToAlpha(centerCoc));
float updateOpacity = correctedOpacity / fgOpacity;
foreground *= updateOpacity;
+19 -16
View File
@@ -15,6 +15,10 @@ material {
type : float2,
name : cocParams
},
{
type : float2,
name : cocClamp
},
{
type : float4,
name : uvscale,
@@ -31,14 +35,9 @@ material {
type : float4
},
{
name : background,
name : coc,
target : color,
type : float4
},
{
name : cocFgBg,
target : color,
type : float2
type : float
}
],
domain : postprocess,
@@ -64,26 +63,30 @@ void dummy(){}
void postProcess(inout PostProcessInputs postProcess) {
highp vec2 uv = variable_vertex.xy;
vec4 color = textureLod(materialParams_color, uv, 0.0);
vec4 outColor = textureLod(materialParams_color, uv, 0.0);
float d = textureLod(materialParams_depth, uv, 0.0).r;
// Get the CoC radius.
// We multiply by 0.5 to convert from diameter to radius.
float coc = getCOC(d, materialParams.cocParams) * 0.5;
float outCoc = getCOC(d, materialParams.cocParams) * 0.5;
// Clamp to maximum allowable CoC radius.
outCoc = clamp(outCoc, materialParams.cocClamp[0], materialParams.cocClamp[1]);
// If CoC is less that 0.5 full resolution pixel, we clamp to 0, this will reduce
// artifacts in the "in focus" area and allow us to skip more tiles trivially.
if (abs(coc) < MAX_IN_FOCUS_COC) {
coc = 0.0;
if (abs(outCoc) < MAX_IN_FOCUS_COC) {
outCoc = 0.0;
}
// Clamp to maximum allowable CoC radius.
coc = clamp(coc, -MAX_COC_RADIUS, MAX_COC_RADIUS);
#if POST_PROCESS_OPAQUE
// kill the work performed above
outColor.a = 1.0;
#endif
// Output to MRTs
postProcess.color = color;
postProcess.background = color;
postProcess.cocFgBg = vec2(coc, coc);
postProcess.color = outColor;
postProcess.coc = outCoc;
}
}
+2 -2
View File
@@ -64,9 +64,9 @@ void postProcess(inout PostProcessInputs postProcess) {
highp vec2 uv0 = variable_vertex.xy;
highp vec2 uv1 = variable_vertex.xy * materialParams.uvscale.xy;
float alpha = textureLod(materialParams_alpha, uv1, 0.0).r;
vec4 foreground = textureLod(materialParams_dof, uv1, 0.0);
vec4 dof = textureLod(materialParams_dof, uv1, 0.0);
color = textureLod(materialParams_color, uv0, 0.0);
color = foreground + (1.0 - alpha) * color;
color = dof + (1.0 - alpha) * color;
}
#if POST_PROCESS_OPAQUE
-12
View File
@@ -35,20 +35,8 @@ vec2 tap(const vec2 uv, const vec2 offset) {
}
vec2 dilate(inout vec2 center, const vec2 tap) {
// 2.24 tiles is the longest distance between 2 pixels of adjacent tiles.
// sqrt(2^2 + 1^2) = 2.24
const float maxDistance = max(-MAX_COC_RADIUS, -2.24 * TILE_SIZE);
// Tiles that can affect us need to transfer their CoC to us (for the foreground it's
// min(ourCoc, theirCoc) because CoC are negative (the min is the larger radius).
// TODO: However, if their CoC is very large, we can limit it by the distance to that
// tile, because we only need to reach *them*).
// The difficuty here is the this clamping depends on if we're negative or positive.
// e.g. for positive values
// center.g = min(center.g, max(tap.g, maxDistance));
// center.r = max(center.r, max(tap.r, maxDistance));
center.r = min(center.r, tap.r);
center.g = max(center.g, tap.g);
return center;
+25 -44
View File
@@ -15,6 +15,10 @@ material {
type : float2,
name : cocParams
},
{
type : float2,
name : cocClamp
},
{
type : float4,
name : uvscale,
@@ -31,14 +35,9 @@ material {
type : float4
},
{
name : background,
name : coc,
target : color,
type : float4
},
{
name : cocFgBg,
target : color,
type : float2
type : float
}
],
domain : postprocess,
@@ -73,63 +72,45 @@ void postProcess(inout PostProcessInputs postProcess) {
vec4 hdr;
// fireflies/flickering filtering
hdr.x = 1.0 / (1.0 + max3(s00.rgb));
hdr.y = 1.0 / (1.0 + max3(s11.rgb));
hdr.z = 1.0 / (1.0 + max3(s10.rgb));
hdr.w = 1.0 / (1.0 + max3(s00.rgb));
hdr[0] = 1.0 / (1.0 + max3(s01.rgb));
hdr[1] = 1.0 / (1.0 + max3(s11.rgb));
hdr[2] = 1.0 / (1.0 + max3(s10.rgb));
hdr[3] = 1.0 / (1.0 + max3(s00.rgb));
vec4 d;
#if defined(TARGET_VULKAN_ENVIRONMENT) || !defined(TARGET_MOBILE)
d = textureGather(materialParams_depth, uv, 0); // 01, 11, 10, 00
#else
d.x = textureLodOffset(materialParams_depth, uv, 0.0, ivec2(0, 1)).r;
d.y = textureLodOffset(materialParams_depth, uv, 0.0, ivec2(1, 1)).r;
d.z = textureLodOffset(materialParams_depth, uv, 0.0, ivec2(1, 0)).r;
d.w = textureLodOffset(materialParams_depth, uv, 0.0, ivec2(0, 0)).r;
d[0] = textureLodOffset(materialParams_depth, uv, 0.0, ivec2(0, 1)).r;
d[1] = textureLodOffset(materialParams_depth, uv, 0.0, ivec2(1, 1)).r;
d[2] = textureLodOffset(materialParams_depth, uv, 0.0, ivec2(1, 0)).r;
d[3] = textureLodOffset(materialParams_depth, uv, 0.0, ivec2(0, 0)).r;
#endif
// Get the CoC radius of each four samples to downsample.
// We multiply by 0.5 to convert from diameter to radius.
vec4 w = getCOC(d, materialParams.cocParams) * 0.5;
vec4 c = getCOC(d, materialParams.cocParams) * 0.5;
float outCoc = downsampleCoC(c);
vec4 w = downsampleCocWeights(c, outCoc, 1.0) * hdr;
vec4 outColor = (s01 * w[0] + s11 * w[1] + s10 * w[2] + s00 * w[3]) * rcp(dot(vec4(1.0), w));
// We calculates the downsampled CoC to be conservative, that is if any
// of the 4 texels are foreground or background, then the whole new texel is too.
float fgCoc = min2(min(w.xy, w.zw));
// The forground bilateral weight is calculated as saturate(1.0 - (fgCoc - w)), which always
// yields 1.0. Note the "missing" abs(), this is because we want to let the background layer
// leak into the foreground layer, to avoid aliasing artifacts.
vec4 foreground = (s01 * hdr.x + s11 * hdr.y + s10 * hdr.z + s00 * hdr.w) * (1.0 / (hdr.x + hdr.y + hdr.z + hdr.w));
// the background bilateral weight is calculated as saturate(1.0 - abs(bgCoc - w)), but the
// abs() is not needed since bgCoc - w is guaranteed to be >= 0.
float bgCoc = max2(max(w.xy, w.zw));
vec4 bw = saturate(1.0 - (bgCoc - w)) * hdr;
vec4 background = (s01 * bw.x + s11 * bw.y + s10 * bw.z + s00 * bw.w) * (1.0 / (bw.x + bw.y + bw.z + bw.w));
// Clamp to maximum allowable CoC radius.
outCoc = clamp(outCoc, materialParams.cocClamp[0], materialParams.cocClamp[1]);
// If CoC is less that 0.5 full resolution pixel, we clamp to 0, this will reduce
// artifacts in the "in focus" area and allow us to skip more tiles trivially.
if (abs(fgCoc) < MAX_IN_FOCUS_COC) {
fgCoc = 0.0;
if (abs(outCoc) < MAX_IN_FOCUS_COC) {
outCoc = 0.0;
}
if (abs(bgCoc) < MAX_IN_FOCUS_COC){
bgCoc = 0.0;
}
// Clamp to maximum allowable CoC radius.
fgCoc = clamp(fgCoc, -MAX_COC_RADIUS, MAX_COC_RADIUS);
bgCoc = clamp(bgCoc, -MAX_COC_RADIUS, MAX_COC_RADIUS);
#if POST_PROCESS_OPAQUE
// kill the work performed above
foreground.a = 1.0;
background.a = 1.0;
outColor.a = 1.0;
#endif
// Output to MRTs
postProcess.color = foreground;
postProcess.background = background;
postProcess.cocFgBg = vec2(fgCoc, bgCoc);
postProcess.color = outColor;
postProcess.coc = outCoc;
}
}
+21 -61
View File
@@ -3,17 +3,12 @@ material {
parameters : [
{
type : sampler2d,
name : foreground,
name : color,
precision: medium
},
{
type : sampler2d,
name : background,
precision: medium
},
{
type : sampler2d,
name : cocFgBg,
name : coc,
precision: medium
},
{
@@ -35,14 +30,9 @@ material {
type : float4
},
{
name : background,
name : coc,
target : color,
type : float4
},
{
name : cocFgBg,
target : color,
type : float2
type : float
}
],
domain : postprocess,
@@ -63,7 +53,7 @@ fragment {
void dummy(){}
void postProcess(inout PostProcessInputs postProcess) {
highp vec2 pixelSize = 1.0 / vec2(textureSize(materialParams_foreground, materialParams.mip));
highp vec2 pixelSize = 1.0 / vec2(textureSize(materialParams_color, materialParams.mip));
highp vec2 uv = variable_vertex.xy - pixelSize.xy * 0.5;
// the source is guaranteed to be a multiple of two, so we now the bilinear weights are 0.25
@@ -72,60 +62,30 @@ void postProcess(inout PostProcessInputs postProcess) {
float weightScale = materialParams.weightScale;
float mip = float(materialParams.mip);
// fetch the 4 corresponding CoC
vec4 d0, d1;
d0.xy = textureLodOffset(materialParams_cocFgBg, uv, mip, ivec2(0, 1)).rg;
d0.zw = textureLodOffset(materialParams_cocFgBg, uv, mip, ivec2(1, 1)).rg;
d1.xy = textureLodOffset(materialParams_cocFgBg, uv, mip, ivec2(1, 0)).rg;
d1.zw = textureLodOffset(materialParams_cocFgBg, uv, mip, ivec2(0, 0)).rg;
vec4 fw = vec4(d0.xz, d1.xz);
vec4 bw = vec4(d0.yw, d1.yw);
vec4 s01 = textureLodOffset(materialParams_color, uv, mip, ivec2(0, 1));
vec4 s11 = textureLodOffset(materialParams_color, uv, mip, ivec2(1, 1));
vec4 s10 = textureLodOffset(materialParams_color, uv, mip, ivec2(1, 0));
vec4 s00 = textureLodOffset(materialParams_color, uv, mip, ivec2(0, 0));
/*
* foreground
*/
// fetch the 4 corresponding CoC (textureGather with LOD doesn't exist)
vec4 c;
c[0] = textureLodOffset(materialParams_coc, uv, mip, ivec2(0, 1)).r;
c[1] = textureLodOffset(materialParams_coc, uv, mip, ivec2(1, 1)).r;
c[2] = textureLodOffset(materialParams_coc, uv, mip, ivec2(1, 0)).r;
c[3] = textureLodOffset(materialParams_coc, uv, mip, ivec2(0, 0)).r;
vec4 fg01 = textureLodOffset(materialParams_foreground, uv, mip, ivec2(0, 1));
vec4 fg11 = textureLodOffset(materialParams_foreground, uv, mip, ivec2(1, 1));
vec4 fg10 = textureLodOffset(materialParams_foreground, uv, mip, ivec2(1, 0));
vec4 fg00 = textureLodOffset(materialParams_foreground, uv, mip, ivec2(0, 0));
// We calculates the downsampled CoC to be conservative, that is if any
// of the 4 texels are foreground or background, then the whole new texel is too.
float fgCoc = min4(fw);
// The forground bilateral weight is calculated as saturate(1.0 - (fgCoc - w)), which always
// yields 1.0. Note the "missing" abs(), this is because we want to let the background layer
// leak into the foreground layer, to avoid aliasing artifacts.
vec4 foreground = (fg01 + fg11 + fg10 + fg00) * 0.25;
/*
* background
*/
vec4 bg01 = textureLodOffset(materialParams_background, uv, mip, ivec2(0, 1));
vec4 bg11 = textureLodOffset(materialParams_background, uv, mip, ivec2(1, 1));
vec4 bg10 = textureLodOffset(materialParams_background, uv, mip, ivec2(1, 0));
vec4 bg00 = textureLodOffset(materialParams_background, uv, mip, ivec2(0, 0));
float bgCoc = max4(bw);
// The background bilateral weight is calculated as saturate(1.0 - abs(bgCoc - w)),
// but the abs() is not needed since bgCoc - w is guaranteed to be >= 0.
bw = saturate(1.0 - (bgCoc - bw) * weightScale);
float bgScale = 1.0 / (bw.x + bw.y + bw.z + bw.w);
vec4 background = (bg01 * bw.x + bg11 * bw.y + bg10 * bw.z + bg00 * bw.w) * bgScale;
float outCoc = downsampleCoC(c);
vec4 w = downsampleCocWeights(c, outCoc, weightScale);
vec4 outColor = (s01 * w[0] + s11 * w[1] + s10 * w[2] + s00 * w[3]) * rcp(dot(vec4(1.0), w));
#if POST_PROCESS_OPAQUE
// kill the work performed above
foreground.a = 1.0;
background.a = 1.0;
outColor.a = 1.0;
#endif
// Output to MRTs
postProcess.color = foreground;
postProcess.background = background;
postProcess.cocFgBg = vec2(fgCoc, bgCoc);
postProcess.color = outColor;
postProcess.coc = outCoc;
}
}
+14 -12
View File
@@ -3,7 +3,7 @@ material {
parameters : [
{
type : sampler2d,
name : cocMaxMin,
name : cocMinMax,
precision: medium
},
{
@@ -42,27 +42,29 @@ float min4(const vec4 f) {
void postProcess(inout PostProcessInputs postProcess) {
highp vec2 uv = variable_vertex.xy;
highp vec2 size = vec2(textureSize(materialParams_cocMaxMin, 0));
highp vec2 size = vec2(textureSize(materialParams_cocMinMax, 0));
ivec2 i = ivec2(uv * size - 0.5);
// note: the first time, the source texture is swizzled -- so .r and .g are the same channel
// if swizzling is not supported, we use dofTilesSwizzle instead.
#if defined(TARGET_VULKAN_ENVIRONMENT) || !defined(TARGET_MOBILE)
vec4 f = textureGather(materialParams_cocMaxMin, uv, 0); // 01, 11, 10, 00
vec4 b = textureGather(materialParams_cocMaxMin, uv, 1); // 01, 11, 10, 00
vec4 mi = textureGather(materialParams_cocMinMax, uv, 0); // 01, 11, 10, 00
vec4 ma = textureGather(materialParams_cocMinMax, uv, 1); // 01, 11, 10, 00
#else
vec2 s01 = texelFetchOffset(materialParams_cocMaxMin, i, 0, ivec2(0, 1)).rg;
vec2 s11 = texelFetchOffset(materialParams_cocMaxMin, i, 0, ivec2(1, 1)).rg;
vec2 s10 = texelFetchOffset(materialParams_cocMaxMin, i, 0, ivec2(1, 0)).rg;
vec2 s00 = texelFetchOffset(materialParams_cocMaxMin, i, 0, ivec2(0, 0)).rg;
vec4 f = vec4(s01.r, s11.r, s10.r, s00.r);
vec4 b = vec4(s01.g, s11.g, s10.g, s00.g);
vec2 s01 = texelFetchOffset(materialParams_cocMinMax, i, 0, ivec2(0, 1)).rg;
vec2 s11 = texelFetchOffset(materialParams_cocMinMax, i, 0, ivec2(1, 1)).rg;
vec2 s10 = texelFetchOffset(materialParams_cocMinMax, i, 0, ivec2(1, 0)).rg;
vec2 s00 = texelFetchOffset(materialParams_cocMinMax, i, 0, ivec2(0, 0)).rg;
vec4 mi = vec4(s01.r, s11.r, s10.r, s00.r);
vec4 ma = vec4(s01.g, s11.g, s10.g, s00.g);
#endif
// compute tile's min CoC
postProcess.color.r = min4(min(f, b));
postProcess.color.r = min4(mi);
// compute tile's max CoC
postProcess.color.g = max4(max(f, b));
postProcess.color.g = max4(ma);
}
}
@@ -0,0 +1,66 @@
material {
name : dofTilesSwizzle,
parameters : [
{
type : sampler2d,
name : cocMinMax,
precision: medium
},
{
type : float4,
name : uvscale,
precision: high
}
],
variables : [
vertex
],
domain : postprocess,
depthWrite : false,
depthCulling : false
}
vertex {
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
postProcess.vertex.xy = (postProcess.normalizedUV * materialParams.uvscale.xy * 2.0 - 0.5) * materialParams.uvscale.zw;
}
}
fragment {
void dummy(){}
float max4(const vec4 f) {
vec2 t = max(f.xy, f.zw);
return max(t.x, t.y);
}
float min4(const vec4 f) {
vec2 t = min(f.xy, f.zw);
return min(t.x, t.y);
}
void postProcess(inout PostProcessInputs postProcess) {
highp vec2 uv = variable_vertex.xy;
highp vec2 size = vec2(textureSize(materialParams_cocMinMax, 0));
ivec2 i = ivec2(uv * size - 0.5);
#if defined(TARGET_VULKAN_ENVIRONMENT) || !defined(TARGET_MOBILE)
vec4 mi = textureGather(materialParams_cocMinMax, uv, 0); // 01, 11, 10, 00
#else
vec4 mi;
mi[0] = texelFetchOffset(materialParams_cocMinMax, i, 0, ivec2(0, 1)).r;
mi[1] = texelFetchOffset(materialParams_cocMinMax, i, 0, ivec2(1, 1)).r;
mi[2] = texelFetchOffset(materialParams_cocMinMax, i, 0, ivec2(1, 0)).r;
mi[3] = texelFetchOffset(materialParams_cocMinMax, i, 0, ivec2(0, 0)).r;
#endif
// compute tile's min CoC
postProcess.color.r = min4(mi);
// compute tile's max CoC
postProcess.color.g = max4(mi);
}
}
+20
View File
@@ -96,3 +96,23 @@ bool isTrivialTile(const vec2 tiles) {
float maxCocRadius = max(abs(tiles.r), abs(tiles.g));
return maxCocRadius < MAX_IN_FOCUS_COC;
}
float downsampleCoC(const vec4 c) {
// We need to compute a suitable CoC to represent the 4 pixels that are downsampled.
// We pick the min because this always selects the most foreground sample if there is one,
// because the foreground can leak on the background, but not the reverse.
return min4(c);
}
vec4 downsampleCocWeights(const vec4 c, const float outCoc, const float scale) {
// The bilateral weight is normally computed as saturate(1 - |outCoc - c|) which selects
// the sample with the outCoc weight (and does a little bit of cross-fade if other samples
// are close). However, this can also cause some aliasing with dithered objects, so by
// omitting the abs() we allow samples in the background to "leak" into the foreground, which
// is not completely different from the "mirror hole filling" of the DoF pass.
// See "Life of a Bokeh" by Guillaume Abadie, SIGGRAPH 2018.
// Note: With the implementation of downsampleCoC() above, this always resolves to 1.0;
// return saturate(1.0 - (outCoc - c) * scale);
return vec4(1.0);
}
+2 -1
View File
@@ -51,7 +51,8 @@ public:
backend::TextureHandle createTexture(const char* name, backend::SamplerType target,
uint8_t levels,
backend::TextureFormat format, uint8_t samples, uint32_t width, uint32_t height,
uint32_t depth, backend::TextureUsage usage) noexcept override {
uint32_t depth, std::array<backend::TextureSwizzle, 4>,
backend::TextureUsage usage) noexcept override {
return backend::TextureHandle(++handle);
}
+2 -2
View File
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.9.19"
spec.version = "1.9.20"
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.9.19/filament-v1.9.19-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.9.20/filament-v1.9.20-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {
+2
View File
@@ -40,6 +40,7 @@ set(COMMON_DIR ${ANDROID_DIR}/common)
include_directories(${JNI_INCLUDE_DIRS} ${ANDROID_DIR})
set(JNI_SOURCE_FILES
${FILAMENT_DIR}/src/main/cpp/BufferObject.cpp
${FILAMENT_DIR}/src/main/cpp/Camera.cpp
${FILAMENT_DIR}/src/main/cpp/Colors.cpp
${FILAMENT_DIR}/src/main/cpp/ColorGrading.cpp
@@ -116,6 +117,7 @@ get_filename_component(FILAMENT_JAVA_DIR ${FILAMENT_JAVA_DIR} ABSOLUTE)
set(JAVA_SOURCE_FILES
${FILAMENT_JAVA_DIR}/com/google/android/filament/Asserts.java
${FILAMENT_JAVA_DIR}/com/google/android/filament/Box.java
${FILAMENT_JAVA_DIR}/com/google/android/filament/BufferObject.java
${FILAMENT_JAVA_DIR}/com/google/android/filament/Camera.java
${FILAMENT_JAVA_DIR}/com/google/android/filament/Colors.java
${FILAMENT_JAVA_DIR}/com/google/android/filament/ColorGrading.java
+2 -1
View File
@@ -47,7 +47,8 @@ public:
using Callback = std::function<void(filament::Engine*, filament::View*)>;
// The constructor creates its own Scene and places it in the given View.
ImGuiHelper(filament::Engine* engine, filament::View* view, const utils::Path& fontPath);
ImGuiHelper(filament::Engine* engine, filament::View* view, const utils::Path& fontPath,
ImGuiContext* imGuiContext = nullptr);
~ImGuiHelper();
// Informs ImGui of the current display size, as well as a scaling factor when scissoring.
+5 -4
View File
@@ -45,9 +45,10 @@ namespace filagui {
#include "generated/resources/filagui_resources.h"
ImGuiHelper::ImGuiHelper(Engine* engine, filament::View* view, const Path& fontPath) :
mEngine(engine), mView(view), mScene(engine->createScene()),
mImGuiContext(ImGui::CreateContext()) {
ImGuiHelper::ImGuiHelper(Engine* engine, filament::View* view, const Path& fontPath,
ImGuiContext *imGuiContext)
: mEngine(engine), mView(view), mScene(engine->createScene()),
mImGuiContext(imGuiContext ? imGuiContext : ImGui::CreateContext()) {
ImGuiIO& io = ImGui::GetIO();
// Create a simple alpha-blended 2D blitting material.
@@ -63,7 +64,7 @@ ImGuiHelper::ImGuiHelper(Engine* engine, filament::View* view, const Path& fontP
createAtlasTexture(engine);
// For proggy, switch to NEAREST for pixel-perfect text.
if (fontPath.isEmpty()) {
if (fontPath.isEmpty() && !imGuiContext) {
TextureSampler sampler(MinFilter::NEAREST, MagFilter::NEAREST);
mMaterial->setDefaultParameter("albedo", mTexture, sampler);
}
+1 -5
View File
@@ -24,7 +24,6 @@
#include <filament/Box.h>
#include <filament/Camera.h>
#include <filament/Engine.h>
#include <filament/Exposure.h>
#include <filament/IndexBuffer.h>
#include <filament/LightManager.h>
#include <filament/Material.h>
@@ -989,10 +988,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_material* inp
}
const float* e = inputMat->emissive_factor;
// To force emissive to bloom when emissiveFactor is at 1, we multiply by a luminance
// of 6EV. At 6EV, the luminance will be 2^(6-3) = 8 which is about the HDR range of
// our default tone mappers.
mi->setParameter("emissiveFactor", float3(e[0], e[1], e[2]) * Exposure::luminance(6.0f));
mi->setParameter("emissiveFactor", float3(e[0], e[1], e[2]));
const float* c = mrConfig.base_color_factor;
mi->setParameter("baseColorFactor", float4(c[0], c[1], c[2], c[3]));
+14 -3
View File
@@ -31,6 +31,7 @@
#include <utils/Entity.h>
#include <math/mat4.h>
#include <math/vec3.h>
namespace filagui {
@@ -122,8 +123,18 @@ public:
* its callback. Note that the first call might be slower since it requires the creation of the
* internal ImGuiHelper instance.
*/
void renderUserInterface(float timeStepInSeconds, filament::View* guiView, float pixelRatio,
float mouseX, float mouseY, bool mouseButton, float mouseWheelY);
void renderUserInterface(float timeStepInSeconds, filament::View* guiView, float pixelRatio);
/**
* Event-passing methods, useful only when SimpleViewer manages its own instance of ImGuiHelper.
* The key codes used in these methods are just normal ASCII/ANSI codes.
* @{
*/
void mouseEvent(float mouseX, float mouseY, bool mouseButton, float mouseWheelY, bool control);
void keyDownEvent(int keyCode);
void keyUpEvent(int keyCode);
void keyPressEvent(int charCode);
/** @}*/
/**
* Retrieves the current width of the ImGui "window" which we are using as a sidebar.
@@ -233,7 +244,7 @@ private:
float mCurvePlot[1024 * 3];
};
filament::math::mat4f fitIntoUnitCube(const filament::Aabb& bounds);
filament::math::mat4f fitIntoUnitCube(const filament::Aabb& bounds, float zoffset);
} // namespace viewer
} // namespace filament
+5 -1
View File
@@ -140,7 +140,11 @@ void AutomationEngine::applySettings(const char* json, size_t jsonLength, View*
MaterialInstance* const* materials, size_t materialCount, IndirectLight* ibl,
utils::Entity sunlight, LightManager* lm, Scene* scene, Renderer* renderer) {
JsonSerializer serializer;
serializer.readJson(json, jsonLength, mSettings);
if (!serializer.readJson(json, jsonLength, mSettings)) {
std::string jsonWithTerminator(json, json + jsonLength);
slog.e << "Badly formed JSON:\n" << jsonWithTerminator.c_str() << io::endl;
return;
}
viewer::applySettings(mSettings->view, view);
for (size_t i = 0; i < materialCount; i++) {
viewer::applySettings(mSettings->material, materials[i]);
+25 -3
View File
@@ -71,6 +71,12 @@ static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, uint8_t*
return i + 1;
}
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, uint16_t* val) {
CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
*val = strtol(jsonChunk + tokens[i].start, nullptr, 10);
return i + 1;
}
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, uint32_t* val) {
CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
*val = strtol(jsonChunk + tokens[i].start, nullptr, 10);
@@ -481,6 +487,18 @@ static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, DepthOfF
i = parse(tokens, i + 1, jsonChunk, &out->enabled);
} else if (0 == compare(tok, jsonChunk, "filter")) {
i = parse(tokens, i + 1, jsonChunk, &out->filter);
} else if (0 == compare(tok, jsonChunk, "nativeResolution")) {
i = parse(tokens, i + 1, jsonChunk, &out->nativeResolution);
} else if (0 == compare(tok, jsonChunk, "foregroundRingCount")) {
i = parse(tokens, i + 1, jsonChunk, &out->foregroundRingCount);
} else if (0 == compare(tok, jsonChunk, "backgroundRingCount")) {
i = parse(tokens, i + 1, jsonChunk, &out->backgroundRingCount);
} else if (0 == compare(tok, jsonChunk, "fastGatherRingCount")) {
i = parse(tokens, i + 1, jsonChunk, &out->fastGatherRingCount);
} else if (0 == compare(tok, jsonChunk, "maxForegroundCOC")) {
i = parse(tokens, i + 1, jsonChunk, &out->maxForegroundCOC);
} else if (0 == compare(tok, jsonChunk, "maxBackgroundCOC")) {
i = parse(tokens, i + 1, jsonChunk, &out->maxBackgroundCOC);
} else {
slog.w << "Invalid dof options key: '" << STR(tok, jsonChunk) << "'" << io::endl;
i = parse(tokens, i + 1);
@@ -1185,7 +1203,13 @@ static std::ostream& operator<<(std::ostream& out, const DepthOfFieldOptions& in
<< "\"cocScale\": " << (in.cocScale) << ",\n"
<< "\"maxApertureDiameter\": " << (in.maxApertureDiameter) << ",\n"
<< "\"enabled\": " << to_string(in.enabled) << ",\n"
<< "\"filter\": " << (in.filter) << "\n"
<< "\"filter\": " << (in.filter) << ",\n"
<< "\"nativeResolution\": " << (in.nativeResolution) << ",\n"
<< "\"foregroundRingCount\": " << int(in.foregroundRingCount) << ",\n"
<< "\"backgroundRingCount\": " << int(in.backgroundRingCount) << ",\n"
<< "\"fastGatherRingCount\": " << int(in.fastGatherRingCount) << ",\n"
<< "\"maxForegroundCOC\": " << (in.maxForegroundCOC) << ",\n"
<< "\"maxBackgroundCOC\": " << (in.maxBackgroundCOC) << "\n"
<< "}";
}
@@ -1306,7 +1330,6 @@ bool JsonSerializer::readJson(const char* jsonChunk, size_t size, Settings* out)
int tokenCount = jsmn_parse(&parser, jsonChunk, size, nullptr, 0);
if (tokenCount <= 0) {
slog.e << "Badly formed JSON." << io::endl;
return false;
}
@@ -1318,7 +1341,6 @@ bool JsonSerializer::readJson(const char* jsonChunk, size_t size, Settings* out)
if (tokenCount <= 0) {
free(tokens);
slog.e << "Badly formed JSON." << io::endl;
return false;
}
+77 -19
View File
@@ -42,7 +42,7 @@ using namespace filament::math;
namespace filament {
namespace viewer {
filament::math::mat4f fitIntoUnitCube(const filament::Aabb& bounds) {
filament::math::mat4f fitIntoUnitCube(const filament::Aabb& bounds, float zoffset) {
using namespace filament::math;
auto minpt = bounds.min;
auto maxpt = bounds.max;
@@ -51,7 +51,7 @@ filament::math::mat4f fitIntoUnitCube(const filament::Aabb& bounds) {
maxExtent = std::max(maxExtent, maxpt.z - minpt.z);
float scaleFactor = 2.0f / maxExtent;
float3 center = (minpt + maxpt) / 2.0f;
center.z += 4.0f / scaleFactor;
center.z += zoffset / scaleFactor;
return mat4f::scaling(float3(scaleFactor)) * mat4f::translation(-center);
}
@@ -348,7 +348,7 @@ void SimpleViewer::populateScene(FilamentAsset* asset, bool scale,
if (scale) {
auto& tcm = mEngine->getTransformManager();
auto root = tcm.getInstance(mAsset->getRoot());
filament::math::mat4f transform = fitIntoUnitCube(mAsset->getBoundingBox());
filament::math::mat4f transform = fitIntoUnitCube(mAsset->getBoundingBox(), 4);
tcm.setTransform(root, transform);
}
@@ -418,34 +418,79 @@ void SimpleViewer::applyAnimation(double currentTime) {
mAnimator->updateBoneMatrices();
}
void SimpleViewer::renderUserInterface(float timeStepInSeconds, View* guiView, float pixelRatio,
float mouseX, float mouseY, bool mouseButton, float mouseWheelY) {
void SimpleViewer::renderUserInterface(float timeStepInSeconds, View* guiView, float pixelRatio) {
if (mImGuiHelper == nullptr) {
mImGuiHelper = new ImGuiHelper(mEngine, guiView, "");
auto& io = ImGui::GetIO();
// The following table uses normal ANSI codes, which is consistent with the keyCode that
// comes from a web "keydown" event.
io.KeyMap[ImGuiKey_Tab] = 9;
io.KeyMap[ImGuiKey_LeftArrow] = 37;
io.KeyMap[ImGuiKey_RightArrow] = 39;
io.KeyMap[ImGuiKey_UpArrow] = 38;
io.KeyMap[ImGuiKey_DownArrow] = 40;
io.KeyMap[ImGuiKey_Home] = 36;
io.KeyMap[ImGuiKey_End] = 35;
io.KeyMap[ImGuiKey_Delete] = 46;
io.KeyMap[ImGuiKey_Backspace] = 8;
io.KeyMap[ImGuiKey_Enter] = 13;
io.KeyMap[ImGuiKey_Escape] = 27;
io.KeyMap[ImGuiKey_A] = 65;
io.KeyMap[ImGuiKey_C] = 67;
io.KeyMap[ImGuiKey_V] = 86;
io.KeyMap[ImGuiKey_X] = 88;
io.KeyMap[ImGuiKey_Y] = 89;
io.KeyMap[ImGuiKey_Z] = 90;
// TODO: this is not the best way to handle high DPI in ImGui, but it is fine when using the
// proggy font. Users need to refresh their window when dragging between displays with
// different pixel ratios.
ImGui::GetIO().FontGlobalScale = pixelRatio;
io.FontGlobalScale = pixelRatio;
ImGui::GetStyle().ScaleAllSizes(pixelRatio);
}
const auto size = guiView->getViewport();
mImGuiHelper->setDisplaySize(size.width, size.height, 1, 1);
ImGuiIO& io = ImGui::GetIO();
io.MousePos.x = mouseX;
io.MousePos.y = mouseY;
io.MouseWheel += mouseWheelY;
io.MouseDown[0] = mouseButton;
io.MouseDown[1] = false;
io.MouseDown[2] = false;
mImGuiHelper->render(timeStepInSeconds, [this](Engine*, View*) {
this->updateUserInterface();
});
}
void SimpleViewer::mouseEvent(float mouseX, float mouseY, bool mouseButton, float mouseWheelY,
bool control) {
if (mImGuiHelper) {
ImGuiIO& io = ImGui::GetIO();
io.MousePos.x = mouseX;
io.MousePos.y = mouseY;
io.MouseWheel += mouseWheelY;
io.MouseDown[0] = mouseButton != 0;
io.MouseDown[1] = false;
io.MouseDown[2] = false;
io.KeyCtrl = control;
}
}
void SimpleViewer::keyDownEvent(int keyCode) {
if (mImGuiHelper && keyCode < IM_ARRAYSIZE(ImGui::GetIO().KeysDown)) {
ImGui::GetIO().KeysDown[keyCode] = true;
}
}
void SimpleViewer::keyUpEvent(int keyCode) {
if (mImGuiHelper && keyCode < IM_ARRAYSIZE(ImGui::GetIO().KeysDown)) {
ImGui::GetIO().KeysDown[keyCode] = false;
}
}
void SimpleViewer::keyPressEvent(int charCode) {
if (mImGuiHelper) {
ImGui::GetIO().AddInputCharacter(charCode);
}
}
void SimpleViewer::updateUserInterface() {
using namespace filament;
@@ -684,7 +729,11 @@ void SimpleViewer::updateUserInterface() {
16.0f, 90.0f);
}
bool median = mSettings.view.dof.filter == View::DepthOfFieldOptions::Filter::MEDIAN;
bool dofMedian = mSettings.view.dof.filter == View::DepthOfFieldOptions::Filter::MEDIAN;
int dofRingCount = mSettings.view.dof.fastGatherRingCount;
int dofMaxCoC = mSettings.view.dof.maxForegroundCOC;
if (!dofRingCount) dofRingCount = 5;
if (!dofMaxCoC) dofMaxCoC = 32;
ImGui::SliderFloat("Aperture", &mSettings.viewer.cameraAperture, 1.0f, 32.0f);
ImGui::SliderFloat("Speed (1/s)", &mSettings.viewer.cameraSpeed, 1000.0f, 1.0f);
@@ -692,10 +741,19 @@ void SimpleViewer::updateUserInterface() {
ImGui::Checkbox("DoF", &mSettings.view.dof.enabled);
ImGui::SliderFloat("Focus distance", &mSettings.view.dof.focusDistance, 0.0f, 30.0f);
ImGui::SliderFloat("Blur scale", &mSettings.view.dof.cocScale, 0.1f, 10.0f);
ImGui::Checkbox("Median Filter", &median);
mSettings.view.dof.filter = median ?
View::DepthOfFieldOptions::Filter::MEDIAN :
View::DepthOfFieldOptions::Filter::NONE;
ImGui::SliderInt("Ring count", &dofRingCount, 1, 17);
ImGui::SliderInt("Max CoC", &dofMaxCoC, 1, 32);
ImGui::Checkbox("Native Resolution", &mSettings.view.dof.nativeResolution);
ImGui::Checkbox("Median Filter", &dofMedian);
mSettings.view.dof.filter = dofMedian ?
View::DepthOfFieldOptions::Filter::MEDIAN :
View::DepthOfFieldOptions::Filter::NONE;
mSettings.view.dof.backgroundRingCount = dofRingCount;
mSettings.view.dof.foregroundRingCount = dofRingCount;
mSettings.view.dof.fastGatherRingCount = dofRingCount;
mSettings.view.dof.maxForegroundCOC = dofMaxCoC;
mSettings.view.dof.maxBackgroundCOC = dofMaxCoC;
if (ImGui::CollapsingHeader("Vignette")) {
ImGui::Checkbox("Enabled##vignetteEnabled", &mSettings.view.vignette.enabled);
+17
View File
@@ -162,6 +162,23 @@ TEST_F(ViewSettingsTest, JsonTestDefaults) {
ASSERT_EQ(serializer.writeJson(settings2), serializer.writeJson(settings3));
}
TEST_F(ViewSettingsTest, JsonTestSerialization) {
auto canParse = [](bool parseResult, std::string json) {
if (parseResult) {
return testing::AssertionSuccess() << "Settings can be serialized.";
} else {
return testing::AssertionFailure() << "JSON has errors:\n" << json.c_str() << std::endl;
}
};
JsonSerializer serializer;
Settings outSettings = {};
std::string jsonstr = serializer.writeJson(outSettings);
Settings inSettings = {};
bool result = serializer.readJson(jsonstr.c_str(), jsonstr.size(), &inSettings);
ASSERT_TRUE(canParse(result, jsonstr));
}
TEST_F(ViewSettingsTest, JsonTestMaterial) {
JsonSerializer serializer;
Settings settings = {0};
+7 -5
View File
@@ -117,7 +117,7 @@ function(add_ktxfiles SOURCE TARGET EXTRA_ARGS)
set(MONKEY_FILES ${MONKEY_FILES} ${target_path} PARENT_SCOPE)
add_custom_command(
OUTPUT ${target_path}
COMMAND mipgen --quiet --strip-alpha ${EXTRA_ARGS} ${source_path} ${target_path}
COMMAND mipgen --quiet ${EXTRA_ARGS} ${source_path} ${target_path}
MAIN_DEPENDENCY ${source_path}
DEPENDS mipgen
COMMENT "Generating mip levels for ${source_path}")
@@ -146,10 +146,12 @@ endfunction()
add_mesh("assets/models/monkey/monkey.obj" "suzanne.filamesh")
add_ktxfiles("assets/models/monkey/albedo.png" "albedo_s3tc.ktx" "--compression=s3tc_rgb_dxt1")
add_ktxfiles("assets/models/monkey/roughness.png" "roughness.ktx" "--grayscale")
add_ktxfiles("assets/models/monkey/metallic.png" "metallic.ktx" "--grayscale")
add_ktxfiles("assets/models/monkey/ao.png" "ao.ktx" "--grayscale")
# Use a RGBA compression format for Metal and Vulkan support.
set (COMPRESSION "--compression=s3tc_rgba_dxt5")
add_ktxfiles("assets/models/monkey/albedo.png" "albedo_s3tc.ktx" "${COMPRESSION}")
add_ktxfiles("assets/models/monkey/roughness.png" "roughness.ktx" "${COMPRESSION};--grayscale")
add_ktxfiles("assets/models/monkey/metallic.png" "metallic.ktx" "${COMPRESSION};--grayscale")
add_ktxfiles("assets/models/monkey/ao.png" "ao.ktx" "${COMPRESSION};--grayscale")
add_pngfile("assets/models/monkey/normal.png" "normal.png")
+22 -1
View File
@@ -261,7 +261,7 @@ static void createGroundPlane(Engine* engine, Scene* scene, App& app) {
Aabb aabb = app.asset->getBoundingBox();
if (!app.actualSize) {
mat4f transform = fitIntoUnitCube(aabb);
mat4f transform = fitIntoUnitCube(aabb, 4);
aabb = aabb.transform(transform);
}
@@ -341,6 +341,9 @@ static LinearColor inverseTonemapSRGB(sRGBColor x) {
return (x * -0.155) / (x - 1.019);
}
static float sGlobalScale = 1.0f;
static float sGlobalScaleAnamorphism = 0.0f;
int main(int argc, char** argv) {
App app;
@@ -567,6 +570,8 @@ int main(int argc, char** argv) {
debug.getPropertyAddress<bool>("d.renderer.doFrameCapture");
*captureFrame = true;
}
ImGui::SliderFloat("scale", &sGlobalScale, 0.25f, 1.0f);
ImGui::SliderFloat("anamorphism", &sGlobalScaleAnamorphism, -1.0f, 1.0f);
}
if (ImGui::BeginPopupModal("MessageBox", NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
@@ -679,6 +684,22 @@ int main(int argc, char** argv) {
} else {
view->setColorGrading(nullptr);
}
view->setDynamicResolutionOptions({
.minScale = {
lerp(sGlobalScale, 1.0f,
sGlobalScaleAnamorphism >= 0.0f ? sGlobalScaleAnamorphism : 0.0f),
lerp(sGlobalScale, 1.0f,
sGlobalScaleAnamorphism <= 0.0f ? -sGlobalScaleAnamorphism : 0.0f),
},
.maxScale = {
lerp(sGlobalScale, 1.0f,
sGlobalScaleAnamorphism >= 0.0f ? sGlobalScaleAnamorphism : 0.0f),
lerp(sGlobalScale, 1.0f,
sGlobalScaleAnamorphism <= 0.0f ? -sGlobalScaleAnamorphism : 0.0f),
},
.enabled = sGlobalScale != 1.0f,
});
};
auto postRender = [&app](Engine* engine, View* view, Scene* scene, Renderer* renderer) {
+59
View File
@@ -35,8 +35,14 @@
#include <filamentapp/FilamentApp.h>
#include <filamentapp/IBL.h>
#include <getopt/getopt.h>
#include <utils/Path.h>
#include <stb_image.h>
#include <iostream>
#include "generated/resources/resources.h"
#include "generated/resources/monkey.h"
@@ -58,6 +64,57 @@ struct App {
static const char* IBL_FOLDER = "default_env";
static void printUsage(char* name) {
std::string exec_name(utils::Path(name).getName());
std::string usage(
"SHOWCASE renders a Suzanne model with S3TC textures.\n"
"Usage:\n"
" SHOWCASE [options]\n"
"Options:\n"
" --help, -h\n"
" Prints this message\n\n"
" --api, -a\n"
" Specify the backend API: opengl (default), vulkan, or metal\n"
);
const std::string from("SHOWCASE");
for (size_t pos = usage.find(from); pos != std::string::npos; pos = usage.find(from, pos)) {
usage.replace(pos, from.length(), exec_name);
}
std::cout << usage;
}
static int handleCommandLineArguments(int argc, char* argv[], Config* config) {
static constexpr const char* OPTSTR = "ha:";
static const struct option OPTIONS[] = {
{ "help", no_argument, nullptr, 'h' },
{ "api", required_argument, nullptr, 'a' },
{ nullptr, 0, nullptr, 0 }
};
int opt;
int option_index = 0;
while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &option_index)) >= 0) {
std::string arg(optarg ? optarg : "");
switch (opt) {
default:
case 'h':
printUsage(argv[0]);
exit(0);
case 'a':
if (arg == "opengl") {
config->backend = Engine::Backend::OPENGL;
} else if (arg == "vulkan") {
config->backend = Engine::Backend::VULKAN;
} else if (arg == "metal") {
config->backend = Engine::Backend::METAL;
} else {
std::cerr << "Unrecognized backend. Must be 'opengl'|'vulkan'|'metal'.\n";
}
break;
}
}
return optind;
}
static Texture* loadNormalMap(Engine* engine, const uint8_t* normals, size_t nbytes) {
int w, h, n;
unsigned char* data = stbi_load_from_memory(normals, nbytes, &w, &h, &n, 3);
@@ -80,6 +137,8 @@ int main(int argc, char** argv) {
config.title = "suzanne";
config.iblDirectory = FilamentApp::getRootAssetsPath() + IBL_FOLDER;
handleCommandLineArguments(argc, argv, &config);
App app;
auto setup = [config, &app](Engine* engine, View* view, Scene* scene) {
auto& tcm = engine->getTransformManager();
+3 -3
View File
@@ -58,9 +58,9 @@ float evaluateSSAO() {
depths.z = unpack(vec2(dg.z, db.z));
depths.w = unpack(vec2(dg.w, db.w));
depths *= -frameUniforms.cameraFar;
mat4 m = getViewFromWorldMatrix();
float d = dot(vec3(m[0].z, m[1].z, m[2].z), shading_position) + m[3].z;
vec4 w = (vec4(d) - depths) * frameUniforms.aoSamplingQualityAndEdgeDistance;
highp mat4 m = getViewFromWorldMatrix();
highp float d = dot(vec3(m[0].z, m[1].z, m[2].z), shading_position) + m[3].z;
highp vec4 w = (vec4(d) - depths) * frameUniforms.aoSamplingQualityAndEdgeDistance;
w = max(vec4(MEDIUMP_FLT_MIN), 1.0 - w * w) * b;
return dot(ao, w) * (1.0 / (w.x + w.y + w.z + w.w));
} else {
+5 -3
View File
@@ -224,9 +224,9 @@ float prefilteredImportanceSampling(float ipdf, float iblRoughnessOneLevel) {
// Prefiltering doesn't work with anisotropy
const float numSamples = float(IBL_INTEGRATION_IMPORTANCE_SAMPLING_COUNT);
const float invNumSamples = 1.0 / float(numSamples);
const float dim = float(textureSize(light_iblSpecular, 0).x);
const float omegaP = (4.0 * PI) / (6.0 * dim * dim);
const float invOmegaP = 1.0 / omegaP;
float dim = float(textureSize(light_iblSpecular, 0).x);
float omegaP = (4.0 * PI) / (6.0 * dim * dim);
float invOmegaP = 1.0 / omegaP;
const float K = 4.0;
float omegaS = invNumSamples * ipdf;
float mipLevel = clamp(log2(K * omegaS * invOmegaP) * 0.5, 0.0, iblRoughnessOneLevel);
@@ -304,7 +304,9 @@ void isEvaluateClearCoatIBL(const PixelParams pixel, float specularAO, inout vec
p.perceptualRoughness = pixel.clearCoatPerceptualRoughness;
p.f0 = vec3(0.04);
p.roughness = perceptualRoughnessToRoughness(p.perceptualRoughness);
#if defined(MATERIAL_HAS_ANISOTROPY)
p.anisotropy = 0.0;
#endif
vec3 clearCoatLobe = isEvaluateIBL(p, clearCoatNormal, shading_view, clearCoatNoV);
Fr += clearCoatLobe * (specularAO * pixel.clearCoat);
+1 -1
View File
@@ -70,7 +70,7 @@ static void printUsage(const char* name) {
" DDS: 8, 16 (default), 32\n\n"
);
const std::string from("ROUGHNESSPREFILTER");
const std::string from("CSO-LUT");
for (size_t pos = usage.find(from); pos != std::string::npos; pos = usage.find(from, pos)) {
usage.replace(pos, from.length(), execName);
}
+473 -473
View File
@@ -99,485 +99,485 @@ static int handleArguments(int argc, char* argv[]) {
return optind;
}
// CIE 1931 2-deg color matching functions (CMFs), from 360nm to 830nm, at 1nm intervals
// CIE 1931 10-deg color matching functions (CMFs), from 360nm to 830nm, at 1nm intervals
//
// Data source:
// http://cvrl.ioo.ucl.ac.uk/cmfs.htm
// http://cvrl.ioo.ucl.ac.uk/database/text/cmfs/ciexyz31.htm
// http://cvrl.ioo.ucl.ac.uk/database/text/cmfs/ciexyz64.htm
const size_t CIE_XYZ_START = 360;
const size_t CIE_XYZ_COUNT = 471;
const float3 CIE_XYZ[CIE_XYZ_COUNT] = { // NOLINT
{ 0.0001299f, 0.000003917f, 0.0006061f },
{ 0.000145847f, 0.000004393581f, 0.0006808792f },
{ 0.0001638021f, 0.000004929604f, 0.0007651456f },
{ 0.0001840037f, 0.000005532136f, 0.0008600124f },
{ 0.0002066902f, 0.000006208245f, 0.0009665928f },
{ 0.0002321f, 0.000006965f, 0.001086f },
{ 0.000260728f, 0.000007813219f, 0.001220586f },
{ 0.000293075f, 0.000008767336f, 0.001372729f },
{ 0.000329388f, 0.000009839844f, 0.001543579f },
{ 0.000369914f, 0.00001104323f, 0.001734286f },
{ 0.0004149f, 0.00001239f, 0.001946f },
{ 0.0004641587f, 0.00001388641f, 0.002177777f },
{ 0.000518986f, 0.00001555728f, 0.002435809f },
{ 0.000581854f, 0.00001744296f, 0.002731953f },
{ 0.0006552347f, 0.00001958375f, 0.003078064f },
{ 0.0007416f, 0.00002202f, 0.003486f },
{ 0.0008450296f, 0.00002483965f, 0.003975227f },
{ 0.0009645268f, 0.00002804126f, 0.00454088f },
{ 0.001094949f, 0.00003153104f, 0.00515832f },
{ 0.001231154f, 0.00003521521f, 0.005802907f },
{ 0.001368f, 0.000039f, 0.006450001f },
{ 0.00150205f, 0.0000428264f, 0.007083216f },
{ 0.001642328f, 0.0000469146f, 0.007745488f },
{ 0.001802382f, 0.0000515896f, 0.008501152f },
{ 0.001995757f, 0.0000571764f, 0.009414544f },
{ 0.002236f, 0.000064f, 0.01054999f },
{ 0.002535385f, 0.00007234421f, 0.0119658f },
{ 0.002892603f, 0.00008221224f, 0.01365587f },
{ 0.003300829f, 0.00009350816f, 0.01558805f },
{ 0.003753236f, 0.0001061361f, 0.01773015f },
{ 0.004243f, 0.00012f, 0.02005001f },
{ 0.004762389f, 0.000134984f, 0.02251136f },
{ 0.005330048f, 0.000151492f, 0.02520288f },
{ 0.005978712f, 0.000170208f, 0.02827972f },
{ 0.006741117f, 0.000191816f, 0.03189704f },
{ 0.00765f, 0.000217f, 0.03621f },
{ 0.008751373f, 0.0002469067f, 0.04143771f },
{ 0.01002888f, 0.00028124f, 0.04750372f },
{ 0.0114217f, 0.00031852f, 0.05411988f },
{ 0.01286901f, 0.0003572667f, 0.06099803f },
{ 0.01431f, 0.000396f, 0.06785001f },
{ 0.01570443f, 0.0004337147f, 0.07448632f },
{ 0.01714744f, 0.000473024f, 0.08136156f },
{ 0.01878122f, 0.000517876f, 0.08915364f },
{ 0.02074801f, 0.0005722187f, 0.09854048f },
{ 0.02319f, 0.00064f, 0.1102f },
{ 0.02620736f, 0.00072456f, 0.1246133f },
{ 0.02978248f, 0.0008255f, 0.1417017f },
{ 0.03388092f, 0.00094116f, 0.1613035f },
{ 0.03846824f, 0.00106988f, 0.1832568f },
{ 0.04351f, 0.00121f, 0.2074f },
{ 0.0489956f, 0.001362091f, 0.2336921f },
{ 0.0550226f, 0.001530752f, 0.2626114f },
{ 0.0617188f, 0.001720368f, 0.2947746f },
{ 0.069212f, 0.001935323f, 0.3307985f },
{ 0.07763f, 0.00218f, 0.3713f },
{ 0.08695811f, 0.0024548f, 0.4162091f },
{ 0.09717672f, 0.002764f, 0.4654642f },
{ 0.1084063f, 0.0031178f, 0.5196948f },
{ 0.1207672f, 0.0035264f, 0.5795303f },
{ 0.13438f, 0.004f, 0.6456f },
{ 0.1493582f, 0.00454624f, 0.7184838f },
{ 0.1653957f, 0.00515932f, 0.7967133f },
{ 0.1819831f, 0.00582928f, 0.8778459f },
{ 0.198611f, 0.00654616f, 0.959439f },
{ 0.21477f, 0.0073f, 1.0390501f },
{ 0.2301868f, 0.008086507f, 1.1153673f },
{ 0.2448797f, 0.00890872f, 1.1884971f },
{ 0.2587773f, 0.00976768f, 1.2581233f },
{ 0.2718079f, 0.01066443f, 1.3239296f },
{ 0.2839f, 0.0116f, 1.3856f },
{ 0.2949438f, 0.01257317f, 1.4426352f },
{ 0.3048965f, 0.01358272f, 1.4948035f },
{ 0.3137873f, 0.01462968f, 1.5421903f },
{ 0.3216454f, 0.01571509f, 1.5848807f },
{ 0.3285f, 0.01684f, 1.62296f },
{ 0.3343513f, 0.01800736f, 1.6564048f },
{ 0.3392101f, 0.01921448f, 1.6852959f },
{ 0.3431213f, 0.02045392f, 1.7098745f },
{ 0.3461296f, 0.02171824f, 1.7303821f },
{ 0.34828f, 0.023f, 1.74706f },
{ 0.3495999f, 0.02429461f, 1.7600446f },
{ 0.3501474f, 0.02561024f, 1.7696233f },
{ 0.350013f, 0.02695857f, 1.7762637f },
{ 0.349287f, 0.02835125f, 1.7804334f },
{ 0.34806f, 0.0298f, 1.7826f },
{ 0.3463733f, 0.03131083f, 1.7829682f },
{ 0.3442624f, 0.03288368f, 1.7816998f },
{ 0.3418088f, 0.03452112f, 1.7791982f },
{ 0.3390941f, 0.03622571f, 1.7758671f },
{ 0.3362f, 0.038f, 1.77211f },
{ 0.3331977f, 0.03984667f, 1.7682589f },
{ 0.3300411f, 0.041768f, 1.764039f },
{ 0.3266357f, 0.043766f, 1.7589438f },
{ 0.3228868f, 0.04584267f, 1.7524663f },
{ 0.3187f, 0.048f, 1.7441f },
{ 0.3140251f, 0.05024368f, 1.7335595f },
{ 0.308884f, 0.05257304f, 1.7208581f },
{ 0.3032904f, 0.05498056f, 1.7059369f },
{ 0.2972579f, 0.05745872f, 1.6887372f },
{ 0.2908f, 0.06f, 1.6692f },
{ 0.2839701f, 0.06260197f, 1.6475287f },
{ 0.2767214f, 0.06527752f, 1.6234127f },
{ 0.2689178f, 0.06804208f, 1.5960223f },
{ 0.2604227f, 0.07091109f, 1.564528f },
{ 0.2511f, 0.0739f, 1.5281f },
{ 0.2408475f, 0.077016f, 1.4861114f },
{ 0.2298512f, 0.0802664f, 1.4395215f },
{ 0.2184072f, 0.0836668f, 1.3898799f },
{ 0.2068115f, 0.0872328f, 1.3387362f },
{ 0.19536f, 0.09098f, 1.28764f },
{ 0.1842136f, 0.09491755f, 1.2374223f },
{ 0.1733273f, 0.09904584f, 1.1878243f },
{ 0.1626881f, 0.1033674f, 1.1387611f },
{ 0.1522833f, 0.1078846f, 1.090148f },
{ 0.1421f, 0.1126f, 1.0419f },
{ 0.1321786f, 0.117532f, 0.9941976f },
{ 0.1225696f, 0.1226744f, 0.9473473f },
{ 0.1132752f, 0.1279928f, 0.9014531f },
{ 0.1042979f, 0.1334528f, 0.8566193f },
{ 0.09564f, 0.13902f, 0.8129501f },
{ 0.08729955f, 0.1446764f, 0.7705173f },
{ 0.07930804f, 0.1504693f, 0.7294448f },
{ 0.07171776f, 0.1564619f, 0.6899136f },
{ 0.06458099f, 0.1627177f, 0.6521049f },
{ 0.05795001f, 0.1693f, 0.6162f },
{ 0.05186211f, 0.1762431f, 0.5823286f },
{ 0.04628152f, 0.1835581f, 0.5504162f },
{ 0.04115088f, 0.1912735f, 0.5203376f },
{ 0.03641283f, 0.199418f, 0.4919673f },
{ 0.03201f, 0.20802f, 0.46518f },
{ 0.0279172f, 0.2171199f, 0.4399246f },
{ 0.0241444f, 0.2267345f, 0.4161836f },
{ 0.020687f, 0.2368571f, 0.3938822f },
{ 0.0175404f, 0.2474812f, 0.3729459f },
{ 0.0147f, 0.2586f, 0.3533f },
{ 0.01216179f, 0.2701849f, 0.3348578f },
{ 0.00991996f, 0.2822939f, 0.3175521f },
{ 0.00796724f, 0.2950505f, 0.3013375f },
{ 0.006296346f, 0.308578f, 0.2861686f },
{ 0.0049f, 0.323f, 0.272f },
{ 0.003777173f, 0.3384021f, 0.2588171f },
{ 0.00294532f, 0.3546858f, 0.2464838f },
{ 0.00242488f, 0.3716986f, 0.2347718f },
{ 0.002236293f, 0.3892875f, 0.2234533f },
{ 0.0024f, 0.4073f, 0.2123f },
{ 0.00292552f, 0.4256299f, 0.2011692f },
{ 0.00383656f, 0.4443096f, 0.1901196f },
{ 0.00517484f, 0.4633944f, 0.1792254f },
{ 0.00698208f, 0.4829395f, 0.1685608f },
{ 0.0093f, 0.503f, 0.1582f },
{ 0.01214949f, 0.5235693f, 0.1481383f },
{ 0.01553588f, 0.544512f, 0.1383758f },
{ 0.01947752f, 0.56569f, 0.1289942f },
{ 0.02399277f, 0.5869653f, 0.1200751f },
{ 0.0291f, 0.6082f, 0.1117f },
{ 0.03481485f, 0.6293456f, 0.1039048f },
{ 0.04112016f, 0.6503068f, 0.09666748f },
{ 0.04798504f, 0.6708752f, 0.08998272f },
{ 0.05537861f, 0.6908424f, 0.08384531f },
{ 0.06327f, 0.71f, 0.07824999f },
{ 0.07163501f, 0.7281852f, 0.07320899f },
{ 0.08046224f, 0.7454636f, 0.06867816f },
{ 0.08973996f, 0.7619694f, 0.06456784f },
{ 0.09945645f, 0.7778368f, 0.06078835f },
{ 0.1096f, 0.7932f, 0.05725001f },
{ 0.1201674f, 0.8081104f, 0.05390435f },
{ 0.1311145f, 0.8224962f, 0.05074664f },
{ 0.1423679f, 0.8363068f, 0.04775276f },
{ 0.1538542f, 0.8494916f, 0.04489859f },
{ 0.1655f, 0.862f, 0.04216f },
{ 0.1772571f, 0.8738108f, 0.03950728f },
{ 0.18914f, 0.8849624f, 0.03693564f },
{ 0.2011694f, 0.8954936f, 0.03445836f },
{ 0.2133658f, 0.9054432f, 0.03208872f },
{ 0.2257499f, 0.9148501f, 0.02984f },
{ 0.2383209f, 0.9237348f, 0.02771181f },
{ 0.2510668f, 0.9320924f, 0.02569444f },
{ 0.2639922f, 0.9399226f, 0.02378716f },
{ 0.2771017f, 0.9472252f, 0.02198925f },
{ 0.2904f, 0.954f, 0.0203f },
{ 0.3038912f, 0.9602561f, 0.01871805f },
{ 0.3175726f, 0.9660074f, 0.01724036f },
{ 0.3314384f, 0.9712606f, 0.01586364f },
{ 0.3454828f, 0.9760225f, 0.01458461f },
{ 0.3597f, 0.9803f, 0.0134f },
{ 0.3740839f, 0.9840924f, 0.01230723f },
{ 0.3886396f, 0.9874182f, 0.01130188f },
{ 0.4033784f, 0.9903128f, 0.01037792f },
{ 0.4183115f, 0.9928116f, 0.009529306f },
{ 0.4334499f, 0.9949501f, 0.008749999f },
{ 0.4487953f, 0.9967108f, 0.0080352f },
{ 0.464336f, 0.9980983f, 0.0073816f },
{ 0.480064f, 0.999112f, 0.0067854f },
{ 0.4959713f, 0.9997482f, 0.0062428f },
{ 0.5120501f, 1.0f, 0.005749999f },
{ 0.5282959f, 0.9998567f, 0.0053036f },
{ 0.5446916f, 0.9993046f, 0.0048998f },
{ 0.5612094f, 0.9983255f, 0.0045342f },
{ 0.5778215f, 0.9968987f, 0.0042024f },
{ 0.5945f, 0.995f, 0.0039f },
{ 0.6112209f, 0.9926005f, 0.0036232f },
{ 0.6279758f, 0.9897426f, 0.0033706f },
{ 0.6447602f, 0.9864444f, 0.0031414f },
{ 0.6615697f, 0.9827241f, 0.0029348f },
{ 0.6784f, 0.9786f, 0.002749999f },
{ 0.6952392f, 0.9740837f, 0.0025852f },
{ 0.7120586f, 0.9691712f, 0.0024386f },
{ 0.7288284f, 0.9638568f, 0.0023094f },
{ 0.7455188f, 0.9581349f, 0.0021968f },
{ 0.7621f, 0.952f, 0.0021f },
{ 0.7785432f, 0.9454504f, 0.002017733f },
{ 0.7948256f, 0.9384992f, 0.0019482f },
{ 0.8109264f, 0.9311628f, 0.0018898f },
{ 0.8268248f, 0.9234576f, 0.001840933f },
{ 0.8425f, 0.9154f, 0.0018f },
{ 0.8579325f, 0.9070064f, 0.001766267f },
{ 0.8730816f, 0.8982772f, 0.0017378f },
{ 0.8878944f, 0.8892048f, 0.0017112f },
{ 0.9023181f, 0.8797816f, 0.001683067f },
{ 0.9163f, 0.87f, 0.001650001f },
{ 0.9297995f, 0.8598613f, 0.001610133f },
{ 0.9427984f, 0.849392f, 0.0015644f },
{ 0.9552776f, 0.838622f, 0.0015136f },
{ 0.9672179f, 0.8275813f, 0.001458533f },
{ 0.9786f, 0.8163f, 0.0014f },
{ 0.9893856f, 0.8047947f, 0.001336667f },
{ 0.9995488f, 0.793082f, 0.00127f },
{ 1.0090892f, 0.781192f, 0.001205f },
{ 1.0180064f, 0.7691547f, 0.001146667f },
{ 1.0263f, 0.757f, 0.0011f },
{ 1.0339827f, 0.7447541f, 0.0010688f },
{ 1.040986f, 0.7324224f, 0.0010494f },
{ 1.047188f, 0.7200036f, 0.0010356f },
{ 1.0524667f, 0.7074965f, 0.0010212f },
{ 1.0567f, 0.6949f, 0.001f },
{ 1.0597944f, 0.6822192f, 0.00096864f },
{ 1.0617992f, 0.6694716f, 0.00092992f },
{ 1.0628068f, 0.6566744f, 0.00088688f },
{ 1.0629096f, 0.6438448f, 0.00084256f },
{ 1.0622f, 0.631f, 0.0008f },
{ 1.0607352f, 0.6181555f, 0.00076096f },
{ 1.0584436f, 0.6053144f, 0.00072368f },
{ 1.0552244f, 0.5924756f, 0.00068592f },
{ 1.0509768f, 0.5796379f, 0.00064544f },
{ 1.0456f, 0.5668f, 0.0006f },
{ 1.0390369f, 0.5539611f, 0.0005478667f },
{ 1.0313608f, 0.5411372f, 0.0004916f },
{ 1.0226662f, 0.5283528f, 0.0004354f },
{ 1.0130477f, 0.5156323f, 0.0003834667f },
{ 1.0026f, 0.503f, 0.00034f },
{ 0.9913675f, 0.4904688f, 0.0003072533f },
{ 0.9793314f, 0.4780304f, 0.00028316f },
{ 0.9664916f, 0.4656776f, 0.00026544f },
{ 0.9528479f, 0.4534032f, 0.0002518133f },
{ 0.9384f, 0.4412f, 0.00024f },
{ 0.923194f, 0.42908f, 0.0002295467f },
{ 0.907244f, 0.417036f, 0.00022064f },
{ 0.890502f, 0.405032f, 0.00021196f },
{ 0.87292f, 0.393032f, 0.0002021867f },
{ 0.8544499f, 0.381f, 0.00019f },
{ 0.835084f, 0.3689184f, 0.0001742133f },
{ 0.814946f, 0.3568272f, 0.00015564f },
{ 0.794186f, 0.3447768f, 0.00013596f },
{ 0.772954f, 0.3328176f, 0.0001168533f },
{ 0.7514f, 0.321f, 0.0001f },
{ 0.7295836f, 0.3093381f, 0.00008613333f },
{ 0.7075888f, 0.2978504f, 0.0000746f },
{ 0.6856022f, 0.2865936f, 0.000065f },
{ 0.6638104f, 0.2756245f, 0.00005693333f },
{ 0.6424f, 0.265f, 0.00004999999f },
{ 0.6215149f, 0.2547632f, 0.00004416f },
{ 0.6011138f, 0.2448896f, 0.00003948f },
{ 0.5811052f, 0.2353344f, 0.00003572f },
{ 0.5613977f, 0.2260528f, 0.00003264f },
{ 0.5419f, 0.217f, 0.00003f },
{ 0.5225995f, 0.2081616f, 0.00002765333f },
{ 0.5035464f, 0.1995488f, 0.00002556f },
{ 0.4847436f, 0.1911552f, 0.00002364f },
{ 0.4661939f, 0.1829744f, 0.00002181333f },
{ 0.4479f, 0.175f, 0.00002f },
{ 0.4298613f, 0.1672235f, 0.00001813333f },
{ 0.412098f, 0.1596464f, 0.0000162f },
{ 0.394644f, 0.1522776f, 0.0000142f },
{ 0.3775333f, 0.1451259f, 0.00001213333f },
{ 0.3608f, 0.1382f, 0.00001f },
{ 0.3444563f, 0.1315003f, 0.000007733333f },
{ 0.3285168f, 0.1250248f, 0.0000054f },
{ 0.3130192f, 0.1187792f, 0.0000032f },
{ 0.2980011f, 0.1127691f, 0.000001333333f },
{ 0.2835f, 0.107f, 0.0f },
{ 0.2695448f, 0.1014762f, 0.0f },
{ 0.2561184f, 0.09618864f, 0.0f },
{ 0.2431896f, 0.09112296f, 0.0f },
{ 0.2307272f, 0.08626485f, 0.0f },
{ 0.2187f, 0.0816f, 0.0f },
{ 0.2070971f, 0.07712064f, 0.0f },
{ 0.1959232f, 0.07282552f, 0.0f },
{ 0.1851708f, 0.06871008f, 0.0f },
{ 0.1748323f, 0.06476976f, 0.0f },
{ 0.1649f, 0.061f, 0.0f },
{ 0.1553667f, 0.05739621f, 0.0f },
{ 0.14623f, 0.05395504f, 0.0f },
{ 0.13749f, 0.05067376f, 0.0f },
{ 0.1291467f, 0.04754965f, 0.0f },
{ 0.1212f, 0.04458f, 0.0f },
{ 0.1136397f, 0.04175872f, 0.0f },
{ 0.106465f, 0.03908496f, 0.0f },
{ 0.09969044f, 0.03656384f, 0.0f },
{ 0.09333061f, 0.03420048f, 0.0f },
{ 0.0874f, 0.032f, 0.0f },
{ 0.08190096f, 0.02996261f, 0.0f },
{ 0.07680428f, 0.02807664f, 0.0f },
{ 0.07207712f, 0.02632936f, 0.0f },
{ 0.06768664f, 0.02470805f, 0.0f },
{ 0.0636f, 0.0232f, 0.0f },
{ 0.05980685f, 0.02180077f, 0.0f },
{ 0.05628216f, 0.02050112f, 0.0f },
{ 0.05297104f, 0.01928108f, 0.0f },
{ 0.04981861f, 0.01812069f, 0.0f },
{ 0.04677f, 0.017f, 0.0f },
{ 0.04378405f, 0.01590379f, 0.0f },
{ 0.04087536f, 0.01483718f, 0.0f },
{ 0.03807264f, 0.01381068f, 0.0f },
{ 0.03540461f, 0.01283478f, 0.0f },
{ 0.0329f, 0.01192f, 0.0f },
{ 0.03056419f, 0.01106831f, 0.0f },
{ 0.02838056f, 0.01027339f, 0.0f },
{ 0.02634484f, 0.009533311f, 0.0f },
{ 0.02445275f, 0.008846157f, 0.0f },
{ 0.0227f, 0.00821f, 0.0f },
{ 0.02108429f, 0.007623781f, 0.0f },
{ 0.01959988f, 0.007085424f, 0.0f },
{ 0.01823732f, 0.006591476f, 0.0f },
{ 0.01698717f, 0.006138485f, 0.0f },
{ 0.01584f, 0.005723f, 0.0f },
{ 0.01479064f, 0.005343059f, 0.0f },
{ 0.01383132f, 0.004995796f, 0.0f },
{ 0.01294868f, 0.004676404f, 0.0f },
{ 0.0121292f, 0.004380075f, 0.0f },
{ 0.01135916f, 0.004102f, 0.0f },
{ 0.01062935f, 0.003838453f, 0.0f },
{ 0.009938846f, 0.003589099f, 0.0f },
{ 0.009288422f, 0.003354219f, 0.0f },
{ 0.008678854f, 0.003134093f, 0.0f },
{ 0.008110916f, 0.002929f, 0.0f },
{ 0.007582388f, 0.002738139f, 0.0f },
{ 0.007088746f, 0.002559876f, 0.0f },
{ 0.006627313f, 0.002393244f, 0.0f },
{ 0.006195408f, 0.002237275f, 0.0f },
{ 0.005790346f, 0.002091f, 0.0f },
{ 0.005409826f, 0.001953587f, 0.0f },
{ 0.005052583f, 0.00182458f, 0.0f },
{ 0.004717512f, 0.00170358f, 0.0f },
{ 0.004403507f, 0.001590187f, 0.0f },
{ 0.004109457f, 0.001484f, 0.0f },
{ 0.003833913f, 0.001384496f, 0.0f },
{ 0.003575748f, 0.001291268f, 0.0f },
{ 0.003334342f, 0.001204092f, 0.0f },
{ 0.003109075f, 0.001122744f, 0.0f },
{ 0.002899327f, 0.001047f, 0.0f },
{ 0.002704348f, 0.0009765896f, 0.0f },
{ 0.00252302f, 0.0009111088f, 0.0f },
{ 0.002354168f, 0.0008501332f, 0.0f },
{ 0.002196616f, 0.0007932384f, 0.0f },
{ 0.00204919f, 0.00074f, 0.0f },
{ 0.00191096f, 0.0006900827f, 0.0f },
{ 0.001781438f, 0.00064331f, 0.0f },
{ 0.00166011f, 0.000599496f, 0.0f },
{ 0.001546459f, 0.0005584547f, 0.0f },
{ 0.001439971f, 0.00052f, 0.0f },
{ 0.001340042f, 0.0004839136f, 0.0f },
{ 0.001246275f, 0.0004500528f, 0.0f },
{ 0.001158471f, 0.0004183452f, 0.0f },
{ 0.00107643f, 0.0003887184f, 0.0f },
{ 0.0009999493f, 0.0003611f, 0.0f },
{ 0.0009287358f, 0.0003353835f, 0.0f },
{ 0.0008624332f, 0.0003114404f, 0.0f },
{ 0.0008007503f, 0.0002891656f, 0.0f },
{ 0.000743396f, 0.0002684539f, 0.0f },
{ 0.0006900786f, 0.0002492f, 0.0f },
{ 0.0006405156f, 0.0002313019f, 0.0f },
{ 0.0005945021f, 0.0002146856f, 0.0f },
{ 0.0005518646f, 0.0001992884f, 0.0f },
{ 0.000512429f, 0.0001850475f, 0.0f },
{ 0.0004760213f, 0.0001719f, 0.0f },
{ 0.0004424536f, 0.0001597781f, 0.0f },
{ 0.0004115117f, 0.0001486044f, 0.0f },
{ 0.0003829814f, 0.0001383016f, 0.0f },
{ 0.0003566491f, 0.0001287925f, 0.0f },
{ 0.0003323011f, 0.00012f, 0.0f },
{ 0.0003097586f, 0.0001118595f, 0.0f },
{ 0.0002888871f, 0.0001043224f, 0.0f },
{ 0.0002695394f, 0.0000973356f, 0.0f },
{ 0.0002515682f, 0.00009084587f, 0.0f },
{ 0.0002348261f, 0.0000848f, 0.0f },
{ 0.000219171f, 0.00007914667f, 0.0f },
{ 0.0002045258f, 0.000073858f, 0.0f },
{ 0.0001908405f, 0.000068916f, 0.0f },
{ 0.0001780654f, 0.00006430267f, 0.0f },
{ 0.0001661505f, 0.00006f, 0.0f },
{ 0.0001550236f, 0.00005598187f, 0.0f },
{ 0.0001446219f, 0.0000522256f, 0.0f },
{ 0.0001349098f, 0.0000487184f, 0.0f },
{ 0.000125852f, 0.00004544747f, 0.0f },
{ 0.000117413f, 0.0000424f, 0.0f },
{ 0.0001095515f, 0.00003956104f, 0.0f },
{ 0.0001022245f, 0.00003691512f, 0.0f },
{ 0.00009539445f, 0.00003444868f, 0.0f },
{ 0.0000890239f, 0.00003214816f, 0.0f },
{ 0.00008307527f, 0.00003f, 0.0f },
{ 0.00007751269f, 0.00002799125f, 0.0f },
{ 0.00007231304f, 0.00002611356f, 0.0f },
{ 0.00006745778f, 0.00002436024f, 0.0f },
{ 0.00006292844f, 0.00002272461f, 0.0f },
{ 0.00005870652f, 0.0000212f, 0.0f },
{ 0.00005477028f, 0.00001977855f, 0.0f },
{ 0.00005109918f, 0.00001845285f, 0.0f },
{ 0.00004767654f, 0.00001721687f, 0.0f },
{ 0.00004448567f, 0.00001606459f, 0.0f },
{ 0.00004150994f, 0.00001499f, 0.0f },
{ 0.00003873324f, 0.00001398728f, 0.0f },
{ 0.00003614203f, 0.00001305155f, 0.0f },
{ 0.00003372352f, 0.00001217818f, 0.0f },
{ 0.00003146487f, 0.00001136254f, 0.0f },
{ 0.00002935326f, 0.0000106f, 0.0f },
{ 0.00002737573f, 0.000009885877f, 0.0f },
{ 0.00002552433f, 0.000009217304f, 0.0f },
{ 0.00002379376f, 0.000008592362f, 0.0f },
{ 0.0000221787f, 0.000008009133f, 0.0f },
{ 0.00002067383f, 0.0000074657f, 0.0f },
{ 0.00001927226f, 0.000006959567f, 0.0f },
{ 0.0000179664f, 0.000006487995f, 0.0f },
{ 0.00001674991f, 0.000006048699f, 0.0f },
{ 0.00001561648f, 0.000005639396f, 0.0f },
{ 0.00001455977f, 0.0000052578f, 0.0f },
{ 0.00001357387f, 0.000004901771f, 0.0f },
{ 0.00001265436f, 0.00000456972f, 0.0f },
{ 0.00001179723f, 0.000004260194f, 0.0f },
{ 0.00001099844f, 0.000003971739f, 0.0f },
{ 0.00001025398f, 0.0000037029f, 0.0f },
{ 0.000009559646f, 0.000003452163f, 0.0f },
{ 0.000008912044f, 0.000003218302f, 0.0f },
{ 0.000008308358f, 0.0000030003f, 0.0f },
{ 0.000007745769f, 0.000002797139f, 0.0f },
{ 0.000007221456f, 0.0000026078f, 0.0f },
{ 0.000006732475f, 0.00000243122f, 0.0f },
{ 0.000006276423f, 0.000002266531f, 0.0f },
{ 0.000005851304f, 0.000002113013f, 0.0f },
{ 0.000005455118f, 0.000001969943f, 0.0f },
{ 0.000005085868f, 0.0000018366f, 0.0f },
{ 0.000004741466f, 0.00000171223f, 0.0f },
{ 0.000004420236f, 0.000001596228f, 0.0f },
{ 0.000004120783f, 0.00000148809f, 0.0f },
{ 0.000003841716f, 0.000001387314f, 0.0f },
{ 0.000003581652f, 0.0000012934f, 0.0f },
{ 0.000003339127f, 0.00000120582f, 0.0f },
{ 0.000003112949f, 0.000001124143f, 0.0f },
{ 0.000002902121f, 0.000001048009f, 0.0f },
{ 0.000002705645f, 0.000000977058f, 0.0f },
{ 0.000002522525f, 0.00000091093f, 0.0f },
{ 0.000002351726f, 0.000000849251f, 0.0f },
{ 0.000002192415f, 0.000000791721f, 0.0f },
{ 0.000002043902f, 0.00000073809f, 0.0f },
{ 0.000001905497f, 0.00000068811f, 0.0f },
{ 0.000001776509f, 0.00000064153f, 0.0f },
{ 0.000001656215f, 0.00000059809f, 0.0f },
{ 0.000001544022f, 0.000000557575f, 0.0f },
{ 0.00000143944f, 0.000000519808f, 0.0f },
{ 0.000001341977f, 0.000000484612f, 0.0f },
{ 0.000001251141f, 0.00000045181f, 0.0f }
{ 0.000000122200f, 0.000000013398f, 0.000000535027f },
{ 0.000000185138f, 0.000000020294f, 0.000000810720f },
{ 0.000000278830f, 0.000000030560f, 0.000001221200f },
{ 0.000000417470f, 0.000000045740f, 0.000001828700f },
{ 0.000000621330f, 0.000000068050f, 0.000002722200f },
{ 0.000000919270f, 0.000000100650f, 0.000004028300f },
{ 0.000001351980f, 0.000000147980f, 0.000005925700f },
{ 0.000001976540f, 0.000000216270f, 0.000008665100f },
{ 0.000002872500f, 0.000000314200f, 0.000012596000f },
{ 0.000004149500f, 0.000000453700f, 0.000018201000f },
{ 0.000005958600f, 0.000000651100f, 0.000026143700f },
{ 0.000008505600f, 0.000000928800f, 0.000037330000f },
{ 0.000012068600f, 0.000001317500f, 0.000052987000f },
{ 0.000017022600f, 0.000001857200f, 0.000074764000f },
{ 0.000023868000f, 0.000002602000f, 0.000104870000f },
{ 0.000033266000f, 0.000003625000f, 0.000146220000f },
{ 0.000046087000f, 0.000005019000f, 0.000202660000f },
{ 0.000063472000f, 0.000006907000f, 0.000279230000f },
{ 0.000086892000f, 0.000009449000f, 0.000382450000f },
{ 0.000118246000f, 0.000012848000f, 0.000520720000f },
{ 0.000159952000f, 0.000017364000f, 0.000704776000f },
{ 0.000215080000f, 0.000023327000f, 0.000948230000f },
{ 0.000287490000f, 0.000031150000f, 0.001268200000f },
{ 0.000381990000f, 0.000041350000f, 0.001686100000f },
{ 0.000504550000f, 0.000054560000f, 0.002228500000f },
{ 0.000662440000f, 0.000071560000f, 0.002927800000f },
{ 0.000864500000f, 0.000093300000f, 0.003823700000f },
{ 0.001121500000f, 0.000120870000f, 0.004964200000f },
{ 0.001446160000f, 0.000155640000f, 0.006406700000f },
{ 0.001853590000f, 0.000199200000f, 0.008219300000f },
{ 0.002361600000f, 0.000253400000f, 0.010482200000f },
{ 0.002990600000f, 0.000320200000f, 0.013289000000f },
{ 0.003764500000f, 0.000402400000f, 0.016747000000f },
{ 0.004710200000f, 0.000502300000f, 0.020980000000f },
{ 0.005858100000f, 0.000623200000f, 0.026127000000f },
{ 0.007242300000f, 0.000768500000f, 0.032344000000f },
{ 0.008899600000f, 0.000941700000f, 0.039802000000f },
{ 0.010870900000f, 0.001147800000f, 0.048691000000f },
{ 0.013198900000f, 0.001390300000f, 0.059210000000f },
{ 0.015929200000f, 0.001674000000f, 0.071576000000f },
{ 0.019109700000f, 0.002004400000f, 0.086010900000f },
{ 0.022788000000f, 0.002386000000f, 0.102740000000f },
{ 0.027011000000f, 0.002822000000f, 0.122000000000f },
{ 0.031829000000f, 0.003319000000f, 0.144020000000f },
{ 0.037278000000f, 0.003880000000f, 0.168990000000f },
{ 0.043400000000f, 0.004509000000f, 0.197120000000f },
{ 0.050223000000f, 0.005209000000f, 0.228570000000f },
{ 0.057764000000f, 0.005985000000f, 0.263470000000f },
{ 0.066038000000f, 0.006833000000f, 0.301900000000f },
{ 0.075033000000f, 0.007757000000f, 0.343870000000f },
{ 0.084736000000f, 0.008756000000f, 0.389366000000f },
{ 0.095041000000f, 0.009816000000f, 0.437970000000f },
{ 0.105836000000f, 0.010918000000f, 0.489220000000f },
{ 0.117066000000f, 0.012058000000f, 0.542900000000f },
{ 0.128682000000f, 0.013237000000f, 0.598810000000f },
{ 0.140638000000f, 0.014456000000f, 0.656760000000f },
{ 0.152893000000f, 0.015717000000f, 0.716580000000f },
{ 0.165416000000f, 0.017025000000f, 0.778120000000f },
{ 0.178191000000f, 0.018399000000f, 0.841310000000f },
{ 0.191214000000f, 0.019848000000f, 0.906110000000f },
{ 0.204492000000f, 0.021391000000f, 0.972542000000f },
{ 0.217650000000f, 0.022992000000f, 1.038900000000f },
{ 0.230267000000f, 0.024598000000f, 1.103100000000f },
{ 0.242311000000f, 0.026213000000f, 1.165100000000f },
{ 0.253793000000f, 0.027841000000f, 1.224900000000f },
{ 0.264737000000f, 0.029497000000f, 1.282500000000f },
{ 0.275195000000f, 0.031195000000f, 1.338200000000f },
{ 0.285301000000f, 0.032927000000f, 1.392600000000f },
{ 0.295143000000f, 0.034738000000f, 1.446100000000f },
{ 0.304869000000f, 0.036654000000f, 1.499400000000f },
{ 0.314679000000f, 0.038676000000f, 1.553480000000f },
{ 0.324355000000f, 0.040792000000f, 1.607200000000f },
{ 0.333570000000f, 0.042946000000f, 1.658900000000f },
{ 0.342243000000f, 0.045114000000f, 1.708200000000f },
{ 0.350312000000f, 0.047333000000f, 1.754800000000f },
{ 0.357719000000f, 0.049602000000f, 1.798500000000f },
{ 0.364482000000f, 0.051934000000f, 1.839200000000f },
{ 0.370493000000f, 0.054337000000f, 1.876600000000f },
{ 0.375727000000f, 0.056822000000f, 1.910500000000f },
{ 0.380158000000f, 0.059399000000f, 1.940800000000f },
{ 0.383734000000f, 0.062077000000f, 1.967280000000f },
{ 0.386327000000f, 0.064737000000f, 1.989100000000f },
{ 0.387858000000f, 0.067285000000f, 2.005700000000f },
{ 0.388396000000f, 0.069764000000f, 2.017400000000f },
{ 0.387978000000f, 0.072218000000f, 2.024400000000f },
{ 0.386726000000f, 0.074704000000f, 2.027300000000f },
{ 0.384696000000f, 0.077272000000f, 2.026400000000f },
{ 0.382006000000f, 0.079979000000f, 2.022300000000f },
{ 0.378709000000f, 0.082874000000f, 2.015300000000f },
{ 0.374915000000f, 0.086000000000f, 2.006000000000f },
{ 0.370702000000f, 0.089456000000f, 1.994800000000f },
{ 0.366089000000f, 0.092947000000f, 1.981400000000f },
{ 0.361045000000f, 0.096275000000f, 1.965300000000f },
{ 0.355518000000f, 0.099535000000f, 1.946400000000f },
{ 0.349486000000f, 0.102829000000f, 1.924800000000f },
{ 0.342957000000f, 0.106256000000f, 1.900700000000f },
{ 0.335893000000f, 0.109901000000f, 1.874100000000f },
{ 0.328284000000f, 0.113835000000f, 1.845100000000f },
{ 0.320150000000f, 0.118167000000f, 1.813900000000f },
{ 0.311475000000f, 0.122932000000f, 1.780600000000f },
{ 0.302273000000f, 0.128201000000f, 1.745370000000f },
{ 0.292858000000f, 0.133457000000f, 1.709100000000f },
{ 0.283502000000f, 0.138323000000f, 1.672300000000f },
{ 0.274044000000f, 0.143042000000f, 1.634700000000f },
{ 0.264263000000f, 0.147787000000f, 1.595600000000f },
{ 0.254085000000f, 0.152761000000f, 1.554900000000f },
{ 0.243392000000f, 0.158102000000f, 1.512200000000f },
{ 0.232187000000f, 0.163941000000f, 1.467300000000f },
{ 0.220488000000f, 0.170362000000f, 1.419900000000f },
{ 0.208198000000f, 0.177425000000f, 1.370000000000f },
{ 0.195618000000f, 0.185190000000f, 1.317560000000f },
{ 0.183034000000f, 0.193025000000f, 1.262400000000f },
{ 0.170222000000f, 0.200313000000f, 1.205000000000f },
{ 0.157348000000f, 0.207156000000f, 1.146600000000f },
{ 0.144650000000f, 0.213644000000f, 1.088000000000f },
{ 0.132349000000f, 0.219940000000f, 1.030200000000f },
{ 0.120584000000f, 0.226170000000f, 0.973830000000f },
{ 0.109456000000f, 0.232467000000f, 0.919430000000f },
{ 0.099042000000f, 0.239025000000f, 0.867460000000f },
{ 0.089388000000f, 0.245997000000f, 0.818280000000f },
{ 0.080507000000f, 0.253589000000f, 0.772125000000f },
{ 0.072034000000f, 0.261876000000f, 0.728290000000f },
{ 0.063710000000f, 0.270643000000f, 0.686040000000f },
{ 0.055694000000f, 0.279645000000f, 0.645530000000f },
{ 0.048117000000f, 0.288694000000f, 0.606850000000f },
{ 0.041072000000f, 0.297665000000f, 0.570060000000f },
{ 0.034642000000f, 0.306469000000f, 0.535220000000f },
{ 0.028896000000f, 0.315035000000f, 0.502340000000f },
{ 0.023876000000f, 0.323335000000f, 0.471400000000f },
{ 0.019628000000f, 0.331366000000f, 0.442390000000f },
{ 0.016172000000f, 0.339133000000f, 0.415254000000f },
{ 0.013300000000f, 0.347860000000f, 0.390024000000f },
{ 0.010759000000f, 0.358326000000f, 0.366399000000f },
{ 0.008542000000f, 0.370001000000f, 0.344015000000f },
{ 0.006661000000f, 0.382464000000f, 0.322689000000f },
{ 0.005132000000f, 0.395379000000f, 0.302356000000f },
{ 0.003982000000f, 0.408482000000f, 0.283036000000f },
{ 0.003239000000f, 0.421588000000f, 0.264816000000f },
{ 0.002934000000f, 0.434619000000f, 0.247848000000f },
{ 0.003114000000f, 0.447601000000f, 0.232318000000f },
{ 0.003816000000f, 0.460777000000f, 0.218502000000f },
{ 0.005095000000f, 0.474340000000f, 0.205851000000f },
{ 0.006936000000f, 0.488200000000f, 0.193596000000f },
{ 0.009299000000f, 0.502340000000f, 0.181736000000f },
{ 0.012147000000f, 0.516740000000f, 0.170281000000f },
{ 0.015444000000f, 0.531360000000f, 0.159249000000f },
{ 0.019156000000f, 0.546190000000f, 0.148673000000f },
{ 0.023250000000f, 0.561180000000f, 0.138609000000f },
{ 0.027690000000f, 0.576290000000f, 0.129096000000f },
{ 0.032444000000f, 0.591500000000f, 0.120215000000f },
{ 0.037465000000f, 0.606741000000f, 0.112044000000f },
{ 0.042956000000f, 0.622150000000f, 0.104710000000f },
{ 0.049114000000f, 0.637830000000f, 0.098196000000f },
{ 0.055920000000f, 0.653710000000f, 0.092361000000f },
{ 0.063349000000f, 0.669680000000f, 0.087088000000f },
{ 0.071358000000f, 0.685660000000f, 0.082248000000f },
{ 0.079901000000f, 0.701550000000f, 0.077744000000f },
{ 0.088909000000f, 0.717230000000f, 0.073456000000f },
{ 0.098293000000f, 0.732570000000f, 0.069268000000f },
{ 0.107949000000f, 0.747460000000f, 0.065060000000f },
{ 0.117749000000f, 0.761757000000f, 0.060709000000f },
{ 0.127839000000f, 0.775340000000f, 0.056457000000f },
{ 0.138450000000f, 0.788220000000f, 0.052609000000f },
{ 0.149516000000f, 0.800460000000f, 0.049122000000f },
{ 0.161041000000f, 0.812140000000f, 0.045954000000f },
{ 0.172953000000f, 0.823330000000f, 0.043050000000f },
{ 0.185209000000f, 0.834120000000f, 0.040368000000f },
{ 0.197755000000f, 0.844600000000f, 0.037839000000f },
{ 0.210538000000f, 0.854870000000f, 0.035384000000f },
{ 0.223460000000f, 0.865040000000f, 0.032949000000f },
{ 0.236491000000f, 0.875211000000f, 0.030451000000f },
{ 0.249633000000f, 0.885370000000f, 0.028029000000f },
{ 0.262972000000f, 0.895370000000f, 0.025862000000f },
{ 0.276515000000f, 0.905150000000f, 0.023920000000f },
{ 0.290269000000f, 0.914650000000f, 0.022174000000f },
{ 0.304213000000f, 0.923810000000f, 0.020584000000f },
{ 0.318361000000f, 0.932550000000f, 0.019127000000f },
{ 0.332705000000f, 0.940810000000f, 0.017740000000f },
{ 0.347232000000f, 0.948520000000f, 0.016403000000f },
{ 0.361926000000f, 0.955600000000f, 0.015064000000f },
{ 0.376772000000f, 0.961988000000f, 0.013676000000f },
{ 0.391683000000f, 0.967540000000f, 0.012308000000f },
{ 0.406594000000f, 0.972230000000f, 0.011056000000f },
{ 0.421539000000f, 0.976170000000f, 0.009915000000f },
{ 0.436517000000f, 0.979460000000f, 0.008872000000f },
{ 0.451584000000f, 0.982200000000f, 0.007918000000f },
{ 0.466782000000f, 0.984520000000f, 0.007030000000f },
{ 0.482147000000f, 0.986520000000f, 0.006223000000f },
{ 0.497738000000f, 0.988320000000f, 0.005453000000f },
{ 0.513606000000f, 0.990020000000f, 0.004714000000f },
{ 0.529826000000f, 0.991761000000f, 0.003988000000f },
{ 0.546440000000f, 0.993530000000f, 0.003289000000f },
{ 0.563426000000f, 0.995230000000f, 0.002646000000f },
{ 0.580726000000f, 0.996770000000f, 0.002063000000f },
{ 0.598290000000f, 0.998090000000f, 0.001533000000f },
{ 0.616053000000f, 0.999110000000f, 0.001091000000f },
{ 0.633948000000f, 0.999770000000f, 0.000711000000f },
{ 0.651901000000f, 1.000000000000f, 0.000407000000f },
{ 0.669824000000f, 0.999710000000f, 0.000184000000f },
{ 0.687632000000f, 0.998850000000f, 0.000047000000f },
{ 0.705224000000f, 0.997340000000f, 0.000000000000f },
{ 0.722773000000f, 0.995260000000f, 0.000000000000f },
{ 0.740483000000f, 0.992740000000f, 0.000000000000f },
{ 0.758273000000f, 0.989750000000f, 0.000000000000f },
{ 0.776083000000f, 0.986300000000f, 0.000000000000f },
{ 0.793832000000f, 0.982380000000f, 0.000000000000f },
{ 0.811436000000f, 0.977980000000f, 0.000000000000f },
{ 0.828822000000f, 0.973110000000f, 0.000000000000f },
{ 0.845879000000f, 0.967740000000f, 0.000000000000f },
{ 0.862525000000f, 0.961890000000f, 0.000000000000f },
{ 0.878655000000f, 0.955552000000f, 0.000000000000f },
{ 0.894208000000f, 0.948601000000f, 0.000000000000f },
{ 0.909206000000f, 0.940981000000f, 0.000000000000f },
{ 0.923672000000f, 0.932798000000f, 0.000000000000f },
{ 0.937638000000f, 0.924158000000f, 0.000000000000f },
{ 0.951162000000f, 0.915175000000f, 0.000000000000f },
{ 0.964283000000f, 0.905954000000f, 0.000000000000f },
{ 0.977068000000f, 0.896608000000f, 0.000000000000f },
{ 0.989590000000f, 0.887249000000f, 0.000000000000f },
{ 1.001910000000f, 0.877986000000f, 0.000000000000f },
{ 1.014160000000f, 0.868934000000f, 0.000000000000f },
{ 1.026500000000f, 0.860164000000f, 0.000000000000f },
{ 1.038800000000f, 0.851519000000f, 0.000000000000f },
{ 1.051000000000f, 0.842963000000f, 0.000000000000f },
{ 1.062900000000f, 0.834393000000f, 0.000000000000f },
{ 1.074300000000f, 0.825623000000f, 0.000000000000f },
{ 1.085200000000f, 0.816764000000f, 0.000000000000f },
{ 1.095200000000f, 0.807544000000f, 0.000000000000f },
{ 1.104200000000f, 0.797947000000f, 0.000000000000f },
{ 1.112000000000f, 0.787893000000f, 0.000000000000f },
{ 1.118520000000f, 0.777405000000f, 0.000000000000f },
{ 1.123800000000f, 0.766490000000f, 0.000000000000f },
{ 1.128000000000f, 0.755309000000f, 0.000000000000f },
{ 1.131100000000f, 0.743845000000f, 0.000000000000f },
{ 1.133200000000f, 0.732190000000f, 0.000000000000f },
{ 1.134300000000f, 0.720353000000f, 0.000000000000f },
{ 1.134300000000f, 0.708281000000f, 0.000000000000f },
{ 1.133300000000f, 0.696055000000f, 0.000000000000f },
{ 1.131200000000f, 0.683621000000f, 0.000000000000f },
{ 1.128100000000f, 0.671048000000f, 0.000000000000f },
{ 1.123990000000f, 0.658341000000f, 0.000000000000f },
{ 1.118900000000f, 0.645545000000f, 0.000000000000f },
{ 1.112900000000f, 0.632718000000f, 0.000000000000f },
{ 1.105900000000f, 0.619815000000f, 0.000000000000f },
{ 1.098000000000f, 0.606887000000f, 0.000000000000f },
{ 1.089100000000f, 0.593878000000f, 0.000000000000f },
{ 1.079200000000f, 0.580781000000f, 0.000000000000f },
{ 1.068400000000f, 0.567653000000f, 0.000000000000f },
{ 1.056700000000f, 0.554490000000f, 0.000000000000f },
{ 1.044000000000f, 0.541228000000f, 0.000000000000f },
{ 1.030480000000f, 0.527963000000f, 0.000000000000f },
{ 1.016000000000f, 0.514634000000f, 0.000000000000f },
{ 1.000800000000f, 0.501363000000f, 0.000000000000f },
{ 0.984790000000f, 0.488124000000f, 0.000000000000f },
{ 0.968080000000f, 0.474935000000f, 0.000000000000f },
{ 0.950740000000f, 0.461834000000f, 0.000000000000f },
{ 0.932800000000f, 0.448823000000f, 0.000000000000f },
{ 0.914340000000f, 0.435917000000f, 0.000000000000f },
{ 0.895390000000f, 0.423153000000f, 0.000000000000f },
{ 0.876030000000f, 0.410526000000f, 0.000000000000f },
{ 0.856297000000f, 0.398057000000f, 0.000000000000f },
{ 0.836350000000f, 0.385835000000f, 0.000000000000f },
{ 0.816290000000f, 0.373951000000f, 0.000000000000f },
{ 0.796050000000f, 0.362311000000f, 0.000000000000f },
{ 0.775610000000f, 0.350863000000f, 0.000000000000f },
{ 0.754930000000f, 0.339554000000f, 0.000000000000f },
{ 0.733990000000f, 0.328309000000f, 0.000000000000f },
{ 0.712780000000f, 0.317118000000f, 0.000000000000f },
{ 0.691290000000f, 0.305936000000f, 0.000000000000f },
{ 0.669520000000f, 0.294737000000f, 0.000000000000f },
{ 0.647467000000f, 0.283493000000f, 0.000000000000f },
{ 0.625110000000f, 0.272222000000f, 0.000000000000f },
{ 0.602520000000f, 0.260990000000f, 0.000000000000f },
{ 0.579890000000f, 0.249877000000f, 0.000000000000f },
{ 0.557370000000f, 0.238946000000f, 0.000000000000f },
{ 0.535110000000f, 0.228254000000f, 0.000000000000f },
{ 0.513240000000f, 0.217853000000f, 0.000000000000f },
{ 0.491860000000f, 0.207780000000f, 0.000000000000f },
{ 0.471080000000f, 0.198072000000f, 0.000000000000f },
{ 0.450960000000f, 0.188748000000f, 0.000000000000f },
{ 0.431567000000f, 0.179828000000f, 0.000000000000f },
{ 0.412870000000f, 0.171285000000f, 0.000000000000f },
{ 0.394750000000f, 0.163059000000f, 0.000000000000f },
{ 0.377210000000f, 0.155151000000f, 0.000000000000f },
{ 0.360190000000f, 0.147535000000f, 0.000000000000f },
{ 0.343690000000f, 0.140211000000f, 0.000000000000f },
{ 0.327690000000f, 0.133170000000f, 0.000000000000f },
{ 0.312170000000f, 0.126400000000f, 0.000000000000f },
{ 0.297110000000f, 0.119892000000f, 0.000000000000f },
{ 0.282500000000f, 0.113640000000f, 0.000000000000f },
{ 0.268329000000f, 0.107633000000f, 0.000000000000f },
{ 0.254590000000f, 0.101870000000f, 0.000000000000f },
{ 0.241300000000f, 0.096347000000f, 0.000000000000f },
{ 0.228480000000f, 0.091063000000f, 0.000000000000f },
{ 0.216140000000f, 0.086010000000f, 0.000000000000f },
{ 0.204300000000f, 0.081187000000f, 0.000000000000f },
{ 0.192950000000f, 0.076583000000f, 0.000000000000f },
{ 0.182110000000f, 0.072198000000f, 0.000000000000f },
{ 0.171770000000f, 0.068024000000f, 0.000000000000f },
{ 0.161920000000f, 0.064052000000f, 0.000000000000f },
{ 0.152568000000f, 0.060281000000f, 0.000000000000f },
{ 0.143670000000f, 0.056697000000f, 0.000000000000f },
{ 0.135200000000f, 0.053292000000f, 0.000000000000f },
{ 0.127130000000f, 0.050059000000f, 0.000000000000f },
{ 0.119480000000f, 0.046998000000f, 0.000000000000f },
{ 0.112210000000f, 0.044096000000f, 0.000000000000f },
{ 0.105310000000f, 0.041345000000f, 0.000000000000f },
{ 0.098786000000f, 0.038750700000f, 0.000000000000f },
{ 0.092610000000f, 0.036297800000f, 0.000000000000f },
{ 0.086773000000f, 0.033983200000f, 0.000000000000f },
{ 0.081260600000f, 0.031800400000f, 0.000000000000f },
{ 0.076048000000f, 0.029739500000f, 0.000000000000f },
{ 0.071114000000f, 0.027791800000f, 0.000000000000f },
{ 0.066454000000f, 0.025955100000f, 0.000000000000f },
{ 0.062062000000f, 0.024226300000f, 0.000000000000f },
{ 0.057930000000f, 0.022601700000f, 0.000000000000f },
{ 0.054050000000f, 0.021077900000f, 0.000000000000f },
{ 0.050412000000f, 0.019650500000f, 0.000000000000f },
{ 0.047006000000f, 0.018315300000f, 0.000000000000f },
{ 0.043823000000f, 0.017068600000f, 0.000000000000f },
{ 0.040850800000f, 0.015905100000f, 0.000000000000f },
{ 0.038072000000f, 0.014818300000f, 0.000000000000f },
{ 0.035468000000f, 0.013800800000f, 0.000000000000f },
{ 0.033031000000f, 0.012849500000f, 0.000000000000f },
{ 0.030753000000f, 0.011960700000f, 0.000000000000f },
{ 0.028623000000f, 0.011130300000f, 0.000000000000f },
{ 0.026635000000f, 0.010355500000f, 0.000000000000f },
{ 0.024781000000f, 0.009633200000f, 0.000000000000f },
{ 0.023052000000f, 0.008959900000f, 0.000000000000f },
{ 0.021441000000f, 0.008332400000f, 0.000000000000f },
{ 0.019941300000f, 0.007748800000f, 0.000000000000f },
{ 0.018544000000f, 0.007204600000f, 0.000000000000f },
{ 0.017241000000f, 0.006697500000f, 0.000000000000f },
{ 0.016027000000f, 0.006225100000f, 0.000000000000f },
{ 0.014896000000f, 0.005785000000f, 0.000000000000f },
{ 0.013842000000f, 0.005375100000f, 0.000000000000f },
{ 0.012862000000f, 0.004994100000f, 0.000000000000f },
{ 0.011949000000f, 0.004639200000f, 0.000000000000f },
{ 0.011100000000f, 0.004309300000f, 0.000000000000f },
{ 0.010311000000f, 0.004002800000f, 0.000000000000f },
{ 0.009576880000f, 0.003717740000f, 0.000000000000f },
{ 0.008894000000f, 0.003452620000f, 0.000000000000f },
{ 0.008258100000f, 0.003205830000f, 0.000000000000f },
{ 0.007666400000f, 0.002976230000f, 0.000000000000f },
{ 0.007116300000f, 0.002762810000f, 0.000000000000f },
{ 0.006605200000f, 0.002564560000f, 0.000000000000f },
{ 0.006130600000f, 0.002380480000f, 0.000000000000f },
{ 0.005690300000f, 0.002209710000f, 0.000000000000f },
{ 0.005281900000f, 0.002051320000f, 0.000000000000f },
{ 0.004903300000f, 0.001904490000f, 0.000000000000f },
{ 0.004552630000f, 0.001768470000f, 0.000000000000f },
{ 0.004227500000f, 0.001642360000f, 0.000000000000f },
{ 0.003925800000f, 0.001525350000f, 0.000000000000f },
{ 0.003645700000f, 0.001416720000f, 0.000000000000f },
{ 0.003385900000f, 0.001315950000f, 0.000000000000f },
{ 0.003144700000f, 0.001222390000f, 0.000000000000f },
{ 0.002920800000f, 0.001135550000f, 0.000000000000f },
{ 0.002713000000f, 0.001054940000f, 0.000000000000f },
{ 0.002520200000f, 0.000980140000f, 0.000000000000f },
{ 0.002341100000f, 0.000910660000f, 0.000000000000f },
{ 0.002174960000f, 0.000846190000f, 0.000000000000f },
{ 0.002020600000f, 0.000786290000f, 0.000000000000f },
{ 0.001877300000f, 0.000730680000f, 0.000000000000f },
{ 0.001744100000f, 0.000678990000f, 0.000000000000f },
{ 0.001620500000f, 0.000631010000f, 0.000000000000f },
{ 0.001505700000f, 0.000586440000f, 0.000000000000f },
{ 0.001399200000f, 0.000545110000f, 0.000000000000f },
{ 0.001300400000f, 0.000506720000f, 0.000000000000f },
{ 0.001208700000f, 0.000471110000f, 0.000000000000f },
{ 0.001123600000f, 0.000438050000f, 0.000000000000f },
{ 0.001044760000f, 0.000407410000f, 0.000000000000f },
{ 0.000971560000f, 0.000378962000f, 0.000000000000f },
{ 0.000903600000f, 0.000352543000f, 0.000000000000f },
{ 0.000840480000f, 0.000328001000f, 0.000000000000f },
{ 0.000781870000f, 0.000305208000f, 0.000000000000f },
{ 0.000727450000f, 0.000284041000f, 0.000000000000f },
{ 0.000676900000f, 0.000264375000f, 0.000000000000f },
{ 0.000629960000f, 0.000246109000f, 0.000000000000f },
{ 0.000586370000f, 0.000229143000f, 0.000000000000f },
{ 0.000545870000f, 0.000213376000f, 0.000000000000f },
{ 0.000508258000f, 0.000198730000f, 0.000000000000f },
{ 0.000473300000f, 0.000185115000f, 0.000000000000f },
{ 0.000440800000f, 0.000172454000f, 0.000000000000f },
{ 0.000410580000f, 0.000160678000f, 0.000000000000f },
{ 0.000382490000f, 0.000149730000f, 0.000000000000f },
{ 0.000356380000f, 0.000139550000f, 0.000000000000f },
{ 0.000332110000f, 0.000130086000f, 0.000000000000f },
{ 0.000309550000f, 0.000121290000f, 0.000000000000f },
{ 0.000288580000f, 0.000113106000f, 0.000000000000f },
{ 0.000269090000f, 0.000105501000f, 0.000000000000f },
{ 0.000250969000f, 0.000098428000f, 0.000000000000f },
{ 0.000234130000f, 0.000091853000f, 0.000000000000f },
{ 0.000218470000f, 0.000085738000f, 0.000000000000f },
{ 0.000203910000f, 0.000080048000f, 0.000000000000f },
{ 0.000190350000f, 0.000074751000f, 0.000000000000f },
{ 0.000177730000f, 0.000069819000f, 0.000000000000f },
{ 0.000165970000f, 0.000065222000f, 0.000000000000f },
{ 0.000155020000f, 0.000060939000f, 0.000000000000f },
{ 0.000144800000f, 0.000056942000f, 0.000000000000f },
{ 0.000135280000f, 0.000053217000f, 0.000000000000f },
{ 0.000126390000f, 0.000049737000f, 0.000000000000f },
{ 0.000118100000f, 0.000046491000f, 0.000000000000f },
{ 0.000110370000f, 0.000043464000f, 0.000000000000f },
{ 0.000103150000f, 0.000040635000f, 0.000000000000f },
{ 0.000096427000f, 0.000038000000f, 0.000000000000f },
{ 0.000090151000f, 0.000035540500f, 0.000000000000f },
{ 0.000084294000f, 0.000033244800f, 0.000000000000f },
{ 0.000078830000f, 0.000031100600f, 0.000000000000f },
{ 0.000073729000f, 0.000029099000f, 0.000000000000f },
{ 0.000068969000f, 0.000027230700f, 0.000000000000f },
{ 0.000064525800f, 0.000025486000f, 0.000000000000f },
{ 0.000060376000f, 0.000023856100f, 0.000000000000f },
{ 0.000056500000f, 0.000022333200f, 0.000000000000f },
{ 0.000052880000f, 0.000020910400f, 0.000000000000f },
{ 0.000049498000f, 0.000019580800f, 0.000000000000f },
{ 0.000046339000f, 0.000018338400f, 0.000000000000f },
{ 0.000043389000f, 0.000017177700f, 0.000000000000f },
{ 0.000040634000f, 0.000016093400f, 0.000000000000f },
{ 0.000038060000f, 0.000015080000f, 0.000000000000f },
{ 0.000035657000f, 0.000014133600f, 0.000000000000f },
{ 0.000033411700f, 0.000013249000f, 0.000000000000f },
{ 0.000031315000f, 0.000012422600f, 0.000000000000f },
{ 0.000029355000f, 0.000011649900f, 0.000000000000f },
{ 0.000027524000f, 0.000010927700f, 0.000000000000f },
{ 0.000025811000f, 0.000010251900f, 0.000000000000f },
{ 0.000024209000f, 0.000009619600f, 0.000000000000f },
{ 0.000022711000f, 0.000009028100f, 0.000000000000f },
{ 0.000021308000f, 0.000008474000f, 0.000000000000f },
{ 0.000019994000f, 0.000007954800f, 0.000000000000f },
{ 0.000018764000f, 0.000007468600f, 0.000000000000f },
{ 0.000017611500f, 0.000007012800f, 0.000000000000f },
{ 0.000016532000f, 0.000006585800f, 0.000000000000f },
{ 0.000015521000f, 0.000006185700f, 0.000000000000f },
{ 0.000014574000f, 0.000005810700f, 0.000000000000f },
{ 0.000013686000f, 0.000005459000f, 0.000000000000f },
{ 0.000012855000f, 0.000005129800f, 0.000000000000f },
{ 0.000012075000f, 0.000004820600f, 0.000000000000f },
{ 0.000011345000f, 0.000004531200f, 0.000000000000f },
{ 0.000010659000f, 0.000004259100f, 0.000000000000f },
{ 0.000010017000f, 0.000004004200f, 0.000000000000f },
{ 0.000009413630f, 0.000003764730f, 0.000000000000f },
{ 0.000008847900f, 0.000003539950f, 0.000000000000f },
{ 0.000008317100f, 0.000003329140f, 0.000000000000f },
{ 0.000007819000f, 0.000003131150f, 0.000000000000f },
{ 0.000007351600f, 0.000002945290f, 0.000000000000f },
{ 0.000006913000f, 0.000002770810f, 0.000000000000f },
{ 0.000006501500f, 0.000002607050f, 0.000000000000f },
{ 0.000006115300f, 0.000002453290f, 0.000000000000f },
{ 0.000005752900f, 0.000002308940f, 0.000000000000f },
{ 0.000005412700f, 0.000002173380f, 0.000000000000f },
{ 0.000005093470f, 0.000002046130f, 0.000000000000f },
{ 0.000004793800f, 0.000001926620f, 0.000000000000f },
{ 0.000004512500f, 0.000001814400f, 0.000000000000f },
{ 0.000004248300f, 0.000001708950f, 0.000000000000f },
{ 0.000004000200f, 0.000001609880f, 0.000000000000f },
{ 0.000003767100f, 0.000001516770f, 0.000000000000f },
{ 0.000003548000f, 0.000001429210f, 0.000000000000f },
{ 0.000003342100f, 0.000001346860f, 0.000000000000f },
{ 0.000003148500f, 0.000001269450f, 0.000000000000f },
{ 0.000002966500f, 0.000001196620f, 0.000000000000f },
{ 0.000002795310f, 0.000001128090f, 0.000000000000f },
{ 0.000002634500f, 0.000001063680f, 0.000000000000f },
{ 0.000002483400f, 0.000001003130f, 0.000000000000f },
{ 0.000002341400f, 0.000000946220f, 0.000000000000f },
{ 0.000002207800f, 0.000000892630f, 0.000000000000f },
{ 0.000002082000f, 0.000000842160f, 0.000000000000f },
{ 0.000001963600f, 0.000000794640f, 0.000000000000f },
{ 0.000001851900f, 0.000000749780f, 0.000000000000f },
{ 0.000001746500f, 0.000000707440f, 0.000000000000f },
{ 0.000001647100f, 0.000000667480f, 0.000000000000f },
{ 0.000001553140f, 0.000000629700f, 0.000000000000f }
};
// CIE Standard Illuminant D65 relative spectral power distribution,
-58
View File
@@ -1,58 +0,0 @@
{
"_meta": {
"hash": {
"sha256": "64fb040f71095c2ee61210e3b1cab5dfde8866fcc1121829f2106ea38abbd125"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.8"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"editorconfig": {
"hashes": [
"sha256:1b0ef345f9c3a673e492cfe608ed644b236139f7fceab5c6f513a71bcaf8a56c",
"sha256:60d6f10b87d2572ac1581cb8c9f018163e2b13a9e49588f9fb6dc8c715a1744c"
],
"version": "==0.12.2"
},
"jsbeautifier": {
"hashes": [
"sha256:4f670c6f4f8d4caca9a348271010742f494becb96fe0a9be6ffac8b3d46350ca"
],
"index": "pypi",
"version": "==1.11.0"
},
"mistletoe": {
"hashes": [
"sha256:24d0f18cc5f0381c2cfb8a24ef3de83eb9f7929cb7d0e71ecb164b671d86e6a3",
"sha256:3e2d31b2fa6231ea2ee46981274ebac8d5e5736e3aad2d1cd449e2c053b7023b"
],
"index": "pypi",
"version": "==0.7.2"
},
"pygments": {
"hashes": [
"sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44",
"sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324"
],
"index": "pypi",
"version": "==2.6.1"
},
"six": {
"hashes": [
"sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a",
"sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"
],
"version": "==1.14.0"
}
},
"develop": {}
}
+34 -3
View File
@@ -73,16 +73,35 @@ Filament.loadClassExtensions = function() {
// Create the WebGL 2.0 context.
const ctx = canvas.getContext("webgl2", options);
Filament.glOptions = options;
Filament.glContext = ctx;
// Enable all desired extensions by calling getExtension on each one.
ctx.getExtension('WEBGL_compressed_texture_s3tc');
ctx.getExtension('WEBGL_compressed_texture_astc');
ctx.getExtension('WEBGL_compressed_texture_etc');
// These transient globals are used temporarily during Engine construction.
window.filament_glOptions = options;
window.filament_glContext = ctx;
// Register the GL context with emscripten and create the Engine.
return Filament.Engine._create();
const engine = Filament.Engine._create();
// Annotate the engine with the GL context to support multiple canvases.
engine.context = window.filament_glContext;
engine.handle = window.filament_contextHandle;
// Ensure that we do not pollute the global namespace.
delete window.filament_glOptions;
delete window.filament_glContext;
delete window.filament_contextHandle;
return engine;
};
Filament.Engine.prototype.execute = function() {
window.filament_contextHandle = this.handle;
this._execute();
delete window.filament_contextHandle;
};
/// createMaterial ::method::
@@ -306,6 +325,18 @@ Filament.loadClassExtensions = function() {
this._setVignetteOptions(options);
};
/// BufferObject ::core class::
/// setBuffer ::method::
/// engine ::argument:: [Engine]
/// buffer ::argument:: asset string, or Uint8Array, or [Buffer]
/// byteOffset ::argument:: non-negative integer
Filament.BufferObject.prototype.setBuffer = function(engine, buffer, byteOffset = 0) {
buffer = getBufferDescriptor(buffer);
this._setBuffer(engine, buffer, byteOffset);
buffer.delete();
};
/// VertexBuffer ::core class::
/// setBufferAt ::method::
+24
View File
@@ -143,6 +143,9 @@ export interface View$VignetteOptions {
enabled?: boolean;
}
export function fitIntoUnitCube(box: Aabb): mat4;
export function multiplyMatrices(a: mat4, b: mat4): mat4;
// Clients should use the [PixelBuffer/CompressedPixelBuffer] helper function to contruct PixelBufferDescriptor objects.
export class driver$PixelBufferDescriptor {
constructor(byteLength: number, format: PixelDataFormat, datatype: PixelDataType);
@@ -225,6 +228,7 @@ export class VertexBuffer$Builder {
public bufferCount(count: number): VertexBuffer$Builder;
public attribute(attrib: VertexAttribute, bufindex: number, atype: VertexBuffer$AttributeType,
offset: number, stride: number): VertexBuffer$Builder;
public enableBufferObjects(enabled: boolean): VertexBuffer$Builder;
public normalized(attrib: VertexAttribute): VertexBuffer$Builder;
public normalizedIf(attrib: VertexAttribute, normalized: boolean): VertexBuffer$Builder;
public build(engine: Engine): VertexBuffer;
@@ -236,6 +240,12 @@ export class IndexBuffer$Builder {
public build(engine: Engine): IndexBuffer;
}
export class BufferObject$Builder {
public size(byteCount: number): BufferObject$Builder;
public bindingType(type: BufferObject$BindingType): BufferObject$Builder;
public build(engine: Engine): BufferObject;
}
export class RenderableManager$Builder {
public geometry(slot: number, ptype: RenderableManager$PrimitiveType, vb: VertexBuffer,
ib: IndexBuffer): RenderableManager$Builder;
@@ -364,6 +374,12 @@ export class VertexBuffer {
public static Builder(): VertexBuffer$Builder;
public setBufferAt(engine: Engine, bufindex: number, f32array: BufferReference,
byteOffset?: number): void;
public setBufferObjectAt(engine: Engine, bufindex: number, bo: BufferObject): void;
}
export class BufferObject {
public static Builder(): BufferObject$Builder;
public setBuffer(engine: Engine, data: BufferReference, byteOffset?: number): void;
}
export class IndexBuffer {
@@ -719,6 +735,10 @@ export enum IndexBuffer$IndexType {
UINT,
}
export enum BufferObject$BindingType {
VERTEX_BINDING,
}
export enum LightManager$Type {
SUN,
DIRECTIONAL,
@@ -955,6 +975,10 @@ export enum VertexAttribute {
MORPH_TANGENTS_3 = CUSTOM7,
}
export enum BufferObject$BindingType {
VERTEX,
}
export enum VertexBuffer$AttributeType {
BYTE,
BYTE2,
+58 -4
View File
@@ -34,6 +34,7 @@
#include <filameshio/MeshReader.h>
#include <filament/BufferObject.h>
#include <filament/Camera.h>
#include <filament/ColorGrading.h>
#include <filament/Engine.h>
@@ -117,6 +118,7 @@ namespace emscripten {
namespace internal {
BIND(Animator)
BIND(AssetLoader)
BIND(BufferObject)
BIND(Camera)
BIND(ColorGrading)
BIND(Engine)
@@ -204,6 +206,7 @@ using SkyBuilder = Skybox::Builder;
using SurfaceBuilder = SurfaceOrientation::Builder;
using TexBuilder = Texture::Builder;
using VertexBuilder = VertexBuffer::Builder;
using BufferBuilder = BufferObject::Builder;
// We avoid directly exposing backend::BufferDescriptor because embind does not support move
// semantics and void* doesn't make sense to JavaScript anyway. This little wrapper class is exposed
@@ -368,7 +371,13 @@ value_object<filament::View::DepthOfFieldOptions>("View$DepthOfFieldOptions")
.field("cocScale", &filament::View::DepthOfFieldOptions::cocScale)
.field("maxApertureDiameter", &filament::View::DepthOfFieldOptions::maxApertureDiameter)
.field("enabled", &filament::View::DepthOfFieldOptions::enabled)
.field("filter", &filament::View::DepthOfFieldOptions::filter);
.field("filter", &filament::View::DepthOfFieldOptions::filter)
.field("nativeResolution", &filament::View::DepthOfFieldOptions::nativeResolution)
.field("foregroundRingCount", &filament::View::DepthOfFieldOptions::foregroundRingCount)
.field("backgroundRingCount", &filament::View::DepthOfFieldOptions::backgroundRingCount)
.field("fastGatherRingCount", &filament::View::DepthOfFieldOptions::fastGatherRingCount)
.field("maxForegroundCOC", &filament::View::DepthOfFieldOptions::maxForegroundCOC)
.field("maxBackgroundCOC", &filament::View::DepthOfFieldOptions::maxBackgroundCOC);
value_object<filament::View::BloomOptions>("View$BloomOptions")
.field("dirtStrength", &filament::View::BloomOptions::dirtStrength)
@@ -463,16 +472,27 @@ register_vector<const MaterialInstance*>("MaterialInstanceVector");
class_<Engine>("Engine")
.class_function("_create", (Engine* (*)()) [] {
EM_ASM_INT({
const handle = GL.registerContext(Filament.glContext, Filament.glOptions);
const options = window.filament_glOptions;
const context = window.filament_glContext;
const handle = GL.registerContext(context, options);
window.filament_contextHandle = handle;
GL.makeContextCurrent(handle);
});
return Engine::create();
}, allow_raw_pointers())
.function("_execute", EMBIND_LAMBDA(void, (Engine* engine), {
EM_ASM_INT({
const handle = window.filament_contextHandle;
GL.makeContextCurrent(handle);
});
engine->execute();
}), allow_raw_pointers())
/// destroy ::static method:: Destroys an engine instance and cleans up resources.
/// engine ::argument:: the instance to destroy
.class_function("destroy", (void (*)(Engine*)) []
(Engine* engine) { Engine::destroy(&engine); }, allow_raw_pointers())
.function("execute", &Engine::execute)
/// getTransformManager ::method::
/// ::retval:: an instance of [TransformManager]
@@ -1156,6 +1176,25 @@ class_<LightManager>("LightManager")
class_<LightManager::Instance>("LightManager$Instance");
/// delete ::method:: Frees an instance obtained via `getInstance`
class_<BufferBuilder>("BufferObject$Builder")
.function("_build", EMBIND_LAMBDA(BufferObject*, (BufferBuilder* builder, Engine* engine), {
return builder->build(*engine);
}), allow_raw_pointers())
.BUILDER_FUNCTION("bindingType", BufferBuilder, (BufferBuilder* builder,
BufferObject::BindingType bt), {
return &builder->bindingType(bt); })
.BUILDER_FUNCTION("size", BufferBuilder, (BufferBuilder* builder, int byteCount), {
return &builder->size(byteCount); });
/// BufferObject ::core class:: Represents a single GPU buffer.
class_<BufferObject>("BufferObject")
.class_function("Builder", (BufferBuilder (*)()) [] { return BufferBuilder(); })
.function("getByteCount", &BufferObject::getByteCount)
.function("_setBuffer", EMBIND_LAMBDA(void, (BufferObject* self,
Engine* engine, BufferDescriptor bd, uint32_t byteOffset), {
self->setBuffer(*engine, std::move(*bd.bd), byteOffset);
}), allow_raw_pointers());
class_<VertexBuilder>("VertexBuffer$Builder")
.function("_build", EMBIND_LAMBDA(VertexBuffer*, (VertexBuilder* builder, Engine* engine), {
return builder->build(*engine);
@@ -1169,6 +1208,8 @@ class_<VertexBuilder>("VertexBuffer$Builder")
return &builder->attribute(attr, bufferIndex, attrType, byteOffset, byteStride); })
.BUILDER_FUNCTION("vertexCount", VertexBuilder, (VertexBuilder* builder, int count), {
return &builder->vertexCount(count); })
.BUILDER_FUNCTION("enableBufferObjects", VertexBuilder, (VertexBuilder* builder, bool enable), {
return &builder->enableBufferObjects(enable); })
.BUILDER_FUNCTION("normalized", VertexBuilder, (VertexBuilder* builder,
VertexAttribute attrib), {
return &builder->normalized(attrib); })
@@ -1181,6 +1222,7 @@ class_<VertexBuilder>("VertexBuffer$Builder")
/// VertexBuffer ::core class:: Bundle of buffers and associated vertex attributes.
class_<VertexBuffer>("VertexBuffer")
.class_function("Builder", (VertexBuilder (*)()) [] { return VertexBuilder(); })
.function("setBufferObjectAt", &VertexBuffer::setBufferObjectAt, allow_raw_pointers())
.function("_setBufferAt", EMBIND_LAMBDA(void, (VertexBuffer* self,
Engine* engine, uint8_t bufferIndex, BufferDescriptor vbd, uint32_t byteOffset), {
self->setBufferAt(*engine, bufferIndex, std::move(*vbd.bd), byteOffset);
@@ -1855,7 +1897,19 @@ class_<JsonSerializer>("JsonSerializer")
class_<SimpleViewer>("SimpleViewer")
.constructor<Engine*, Scene*, View*, int>()
.function("renderUserInterface", &SimpleViewer::renderUserInterface, allow_raw_pointers())
.function("getSettings", &SimpleViewer::getSettings);
.function("getSettings", &SimpleViewer::getSettings)
.function("mouseEvent", &SimpleViewer::mouseEvent)
.function("keyDownEvent", &SimpleViewer::keyDownEvent)
.function("keyUpEvent", &SimpleViewer::keyUpEvent)
.function("keyPressEvent", &SimpleViewer::keyPressEvent);
function("fitIntoUnitCube", EMBIND_LAMBDA(flatmat4, (Aabb box, float zoffset), {
return flatmat4 { fitIntoUnitCube(box, zoffset) };
}));
function("multiplyMatrices", EMBIND_LAMBDA(flatmat4, (flatmat4 a, flatmat4 b), {
return flatmat4 { a.m * b.m };
}));
} // EMSCRIPTEN_BINDINGS
+4
View File
@@ -14,6 +14,7 @@
* limitations under the License.
*/
#include <filament/BufferObject.h>
#include <filament/Camera.h>
#include <filament/ColorGrading.h>
#include <filament/Color.h>
@@ -69,6 +70,9 @@ enum_<VertexAttribute>("VertexAttribute")
.value("MORPH_TANGENTS_2", MORPH_TANGENTS_2)
.value("MORPH_TANGENTS_3", MORPH_TANGENTS_3);
enum_<BufferObject::BindingType>("BufferObject$BindingType")
.value("VERTEX_BINDING", BufferObject::BindingType::VERTEX);
enum_<VertexBuffer::AttributeType>("VertexBuffer$AttributeType")
.value("BYTE", VertexBuffer::AttributeType::BYTE)
.value("BYTE2", VertexBuffer::AttributeType::BYTE2)
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "filament",
"version": "1.9.19",
"version": "1.9.20",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",
+14 -6
View File
@@ -135,7 +135,7 @@ class App {
// In the future we might want to draw stuff in the central 3D viewport.
const kInitialSidebarWidth = this.canvas.clientWidth * window.devicePixelRatio;
// Clear the central 3D viewport to light gray, whicht is not visible by default.
// Clear the central 3D viewport to light gray, which is not visible by default.
const L = 189 / 255;
const kBackgroundColor = [L, L, L, 1];
this.renderer.setClearOptions({clearColor: kBackgroundColor, clear: true});
@@ -145,7 +145,7 @@ class App {
this.mouseX = -1;
this.mouseY = -1;
this.mouseButton = false;
this.mouseButton = null;
this.mouseButtonEvents = [];
this.mouseWheelY = 0;
@@ -155,10 +155,17 @@ class App {
this.mouseX = e.offsetX * window.devicePixelRatio;
this.mouseY = e.offsetY * window.devicePixelRatio;
});
this.canvas.addEventListener("pointerup", e => this.mouseButtonEvents.push(false));
this.canvas.addEventListener("pointerdown", e => this.mouseButtonEvents.push(true));
this.canvas.addEventListener("pointerup", e => this.mouseButtonEvents.push(null));
this.canvas.addEventListener("pointerdown", e => this.mouseButtonEvents.push(e));
this.canvas.addEventListener("mousewheel", e => this.mouseWheelY = e.deltaY / 8);
this.canvas.addEventListener("contextmenu", event => event.preventDefault());
document.addEventListener("keydown", e => this.simpleViewer.keyDownEvent(e.keyCode));
document.addEventListener("keyup", e => this.simpleViewer.keyUpEvent(e.keyCode));
document.addEventListener("keypress", e => this.simpleViewer.keyPressEvent(e.charCode));
const resize = () => {
const dpr = window.devicePixelRatio;
const width = this.canvas.clientWidth * dpr;
@@ -263,6 +270,8 @@ class App {
}
const mouseWheel = this.mouseWheelY;
this.mouseWheelY = 0;
this.simpleViewer.mouseEvent(this.mouseX, this.mouseY, !!this.mouseButton,
mouseWheel, this.mouseButton && this.mouseButton.ctrlKey);
// If there's no connection, let Filament clear the canvas, but do not render the UI view.
if (!connection) {
@@ -276,8 +285,7 @@ class App {
// Draw the UI and potentially mutate the settings object.
const deltaTime = 1.0 / 60.0;
this.simpleViewer.renderUserInterface(deltaTime, this.uiview, window.devicePixelRatio,
this.mouseX, this.mouseY, this.mouseButton, mouseWheel);
this.simpleViewer.renderUserInterface(deltaTime, this.uiview, window.devicePixelRatio);
// Check if the user has changed any settings.
const settingsJson = this.serializer.writeJson(this.simpleViewer.getSettings()).slice();