Merge branch 'rc/1.9.20' into release
This commit is contained in:
+8
-2
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
+14
@@ -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,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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+13
-1
File diff suppressed because one or more lines are too long
Binary file not shown.
+14
-6
@@ -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();
|
||||
|
||||
Executable
+17
@@ -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."
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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{};
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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",
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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)),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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" };
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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]));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
Generated
-58
@@ -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": {}
|
||||
}
|
||||
@@ -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::
|
||||
|
||||
Vendored
+24
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,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
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user