Merge branch 'google:main' into main

This commit is contained in:
Serge Metral
2024-06-26 17:26:00 -07:00
committed by GitHub
68 changed files with 1054 additions and 126 deletions
+3 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.53.0'
implementation 'com.google.android.filament:filament-android:1.53.1'
}
```
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release:
```shell
pod 'Filament', '~> 1.53.0'
pod 'Filament', '~> 1.53.1'
```
### Snapshots
@@ -176,6 +176,7 @@ steps:
- [x] KHR_materials_unlit
- [x] KHR_materials_variants
- [x] KHR_materials_volume
- [x] KHR_materials_specular
- [x] KHR_mesh_quantization
- [x] KHR_texture_basisu
- [x] KHR_texture_transform
+3
View File
@@ -7,6 +7,9 @@ A new header is inserted each time a *tag* is created.
Instead, if you are authoring a PR for the main branch, add your release note to
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
## v1.53.2
## v1.53.1
@@ -571,3 +571,9 @@ Java_com_google_android_filament_Engine_nBuilderBuild(JNIEnv*, jclass, jlong nat
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
return (jlong) builder->build();
}
extern "C"
JNIEXPORT jlong JNICALL
Java_com_google_android_filament_Engine_getSteadyClockTimeNano(JNIEnv *env, jclass clazz) {
return (jlong)Engine::getSteadyClockTimeNano();
}
@@ -25,12 +25,17 @@ using namespace filament;
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_Material_nBuilderBuild(JNIEnv *env, jclass,
jlong nativeEngine, jobject buffer_, jint size) {
jlong nativeEngine, jobject buffer_, jint size, jint shBandCount) {
Engine* engine = (Engine*) nativeEngine;
AutoBuffer buffer(env, buffer_, size);
Material* material = Material::Builder()
auto builder = Material::Builder();
if (shBandCount) {
builder.sphericalHarmonicsBandCount(shBandCount);
}
Material* material = builder
.package(buffer.getData(), buffer.getSize())
.build(*engine);
return (jlong) material;
}
@@ -187,3 +187,10 @@ Java_com_google_android_filament_Renderer_nSetPresentationTime(JNIEnv *, jclass
Renderer *renderer = (Renderer *) nativeRenderer;
renderer->setPresentationTime(monotonicClockNanos);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_Renderer_nSetVsyncTime(JNIEnv *, jclass,
jlong nativeRenderer, jlong steadyClockTimeNano) {
Renderer *renderer = (Renderer *) nativeRenderer;
renderer->setVsyncTime(steadyClockTimeNano);
}
@@ -1292,7 +1292,6 @@ public class Engine {
/**
* Switch the command queue to unprotected mode. Protected mode can be activated via
* Renderer::beginFrame() using a protected SwapChain.
* @see Renderer
* @see SwapChain
*/
@@ -1300,6 +1299,13 @@ public class Engine {
nUnprotected(getNativeObject());
}
/**
* Get the current time. This is a convenience function that simply returns the
* time in nanosecond since epoch of std::chrono::steady_clock.
* @return current time in nanosecond since epoch of std::chrono::steady_clock.
* @see Renderer#beginFrame
*/
public static native long getSteadyClockTimeNano();
@UsedByReflection("TextureHelper.java")
public long getNativeObject() {
@@ -346,6 +346,7 @@ public class Material {
public static class Builder {
private Buffer mBuffer;
private int mSize;
private int mShBandCount = 0;
/**
* Specifies the material data. The material data is a binary blob produced by
@@ -361,6 +362,22 @@ public class Material {
return this;
}
/**
* Sets the quality of the indirect lights computations. This is only taken into account
* if this material is lit and in the surface domain. This setting will affect the
* IndirectLight computation if one is specified on the Scene and Spherical Harmonics
* are used for the irradiance.
*
* @param shBandCount Number of spherical harmonic bands. Must be 1, 2 or 3 (default).
* @return Reference to this Builder for chaining calls.
* @see IndirectLight
*/
@NonNull
public Builder sphericalHarmonicsBandCount(@IntRange(from = 0) int shBandCount) {
mShBandCount = shBandCount;
return this;
}
/**
* Creates and returns the Material object.
*
@@ -372,7 +389,8 @@ public class Material {
*/
@NonNull
public Material build(@NonNull Engine engine) {
long nativeMaterial = nBuilderBuild(engine.getNativeObject(), mBuffer, mSize);
long nativeMaterial = nBuilderBuild(engine.getNativeObject(),
mBuffer, mSize, mShBandCount);
if (nativeMaterial == 0) throw new IllegalStateException("Couldn't create Material");
return new Material(nativeMaterial);
}
@@ -1023,7 +1041,7 @@ public class Material {
mNativeObject = 0;
}
private static native long nBuilderBuild(long nativeEngine, @NonNull Buffer buffer, int size);
private static native long nBuilderBuild(long nativeEngine, @NonNull Buffer buffer, int size, int shBandCount);
private static native long nCreateInstance(long nativeMaterial);
private static native long nCreateInstanceWithName(long nativeMaterial, @NonNull String name);
private static native long nGetDefaultInstance(long nativeMaterial);
@@ -284,6 +284,19 @@ public class Renderer {
nSetPresentationTime(getNativeObject(), monotonicClockNanos);
}
/**
* The use of this method is optional. It sets the VSYNC time expressed as the duration in
* nanosecond since epoch of std::chrono::steady_clock.
* If called, passing 0 to frameTimeNanos in Renderer.BeginFrame will use this
* time instead.
* @param steadyClockTimeNano duration in nanosecond since epoch of std::chrono::steady_clock
* @see Engine#getSteadyClockTimeNano
* @see Renderer#beginFrame
*/
public void setVsyncTime(long steadyClockTimeNano) {
nSetVsyncTime(getNativeObject(), steadyClockTimeNano);
}
/**
* Sets up a frame for this <code>Renderer</code>.
* <p><code>beginFrame</code> manages frame pacing, and returns whether or not a frame should be
@@ -702,6 +715,7 @@ public class Renderer {
}
private static native void nSetPresentationTime(long nativeObject, long monotonicClockNanos);
private static native void nSetVsyncTime(long nativeObject, long steadyClockTimeNano);
private static native boolean nBeginFrame(long nativeRenderer, long nativeSwapChain, long frameTimeNanos);
private static native void nEndFrame(long nativeRenderer);
private static native void nRender(long nativeRenderer, long nativeView);
@@ -125,6 +125,11 @@ extern "C" JNIEXPORT void Java_com_google_android_filament_utils_Manipulator_nBu
builder->groundPlane(a, b, c, d);
}
extern "C" JNIEXPORT void Java_com_google_android_filament_utils_Manipulator_nBuilderPanning(JNIEnv*, jclass, jlong nativeBuilder, jboolean enabled) {
Builder* builder = (Builder*) nativeBuilder;
builder->panning(enabled);
}
extern "C" JNIEXPORT long Java_com_google_android_filament_utils_Manipulator_nBuilderBuild(JNIEnv*, jclass, jlong nativeBuilder, jint mode) {
Builder* builder = (Builder*) nativeBuilder;
return (jlong) builder->build((Mode) mode);
@@ -274,6 +274,17 @@ public class Manipulator {
return this;
}
/**
* Sets whether panning is enabled in the manipulator.
*
* @return this <code>Builder</code> object for chaining calls
*/
@NonNull
public Builder panning(Boolean enabled) {
nBuilderPanning(mNativeBuilder, enabled);
return this;
}
/**
* Creates and returns the <code>Manipulator</code> object.
*
@@ -483,6 +494,7 @@ public class Manipulator {
private static native void nBuilderFlightPanSpeed(long nativeBuilder, float x, float y);
private static native void nBuilderFlightMoveDamping(long nativeBuilder, float damping);
private static native void nBuilderGroundPlane(long nativeBuilder, float a, float b, float c, float d);
private static native void nBuilderPanning(long nativeBuilder, Boolean enabled);
private static native long nBuilderBuild(long nativeBuilder, int mode);
private static native void nDestroyManipulator(long nativeManip);
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.53.0
VERSION_NAME=1.53.1
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
@@ -75,6 +75,8 @@ public:
*/
size_t textureUseAfterFreePoolSize = 0;
size_t metalUploadBufferSizeBytes = 512 * 1024;
/**
* Set to `true` to forcibly disable parallel shader compilation in the backend.
* Currently only honored by the GL and Metal backends.
@@ -181,6 +181,18 @@ public:
return static_cast<Dp>(p);
}
template<typename B>
bool is_valid(Handle<B>& handle) {
if (handle && isPoolHandle(handle.getId())) {
auto [p, tag] = handleToPointer(handle.getId());
uint8_t const age = (tag & HANDLE_AGE_MASK) >> HANDLE_AGE_SHIFT;
auto const pNode = static_cast<typename Allocator::Node*>(p);
uint8_t const expectedAge = pNode[-1].age;
return expectedAge == age;
}
return true;
}
template<typename Dp, typename B>
inline typename std::enable_if_t<
std::is_pointer_v<Dp> &&
+9
View File
@@ -204,6 +204,15 @@ public:
private:
enum class UploadStrategy {
POOL,
BUMP_ALLOCATOR,
};
void uploadWithPoolBuffer(void* src, size_t size, size_t byteOffset) const;
void uploadWithBumpAllocator(void* src, size_t size, size_t byteOffset) const;
UploadStrategy mUploadStrategy;
TrackedMetalBuffer mBuffer;
size_t mBufferSize = 0;
void* mCpuBuffer = nullptr;
+58 -23
View File
@@ -27,7 +27,16 @@ MetalPlatform* TrackedMetalBuffer::platform = nullptr;
MetalPlatform* ScopedAllocationTimer::platform = nullptr;
MetalBuffer::MetalBuffer(MetalContext& context, BufferObjectBinding bindingType, BufferUsage usage,
size_t size, bool forceGpuBuffer) : mBufferSize(size), mContext(context) {
size_t size, bool forceGpuBuffer)
: mBufferSize(size), mContext(context) {
const MetalBumpAllocator& allocator = *mContext.bumpAllocator;
// VERTEX is also used for index buffers
if (allocator.getCapacity() > 0 && bindingType == BufferObjectBinding::VERTEX) {
mUploadStrategy = UploadStrategy::BUMP_ALLOCATOR;
} else {
mUploadStrategy = UploadStrategy::POOL;
}
// If the buffer is less than 4K in size and is updated frequently, we don't use an explicit
// buffer. Instead, we use immediate command encoder methods like setVertexBytes:length:atIndex:.
// This won't work for SSBOs, since they are read/write.
@@ -61,34 +70,23 @@ void MetalBuffer::copyIntoBuffer(void* src, size_t size, size_t byteOffset) {
FILAMENT_CHECK_PRECONDITION(size + byteOffset <= mBufferSize)
<< "Attempting to copy " << size << " bytes into a buffer of size " << mBufferSize
<< " at offset " << byteOffset;
// The copy blit requires that byteOffset be a multiple of 4.
FILAMENT_CHECK_PRECONDITION(!(byteOffset & 0x3)) << "byteOffset must be a multiple of 4";
// Either copy into the Metal buffer or into our cpu buffer.
// If we have a cpu buffer, we can directly copy into it.
if (mCpuBuffer) {
memcpy(static_cast<uint8_t*>(mCpuBuffer) + byteOffset, src, size);
return;
}
// Acquire a staging buffer to hold the contents of this update.
MetalBufferPool* bufferPool = mContext.bufferPool;
const MetalBufferPoolEntry* const staging = bufferPool->acquireBuffer(size);
memcpy(staging->buffer.get().contents, src, size);
// The blit below requires that byteOffset be a multiple of 4.
FILAMENT_CHECK_PRECONDITION(!(byteOffset & 0x3u)) << "byteOffset must be a multiple of 4";
// Encode a blit from the staging buffer into the private GPU buffer.
id<MTLCommandBuffer> cmdBuffer = getPendingCommandBuffer(&mContext);
id<MTLBlitCommandEncoder> blitEncoder = [cmdBuffer blitCommandEncoder];
blitEncoder.label = @"Buffer upload blit";
[blitEncoder copyFromBuffer:staging->buffer.get()
sourceOffset:0
toBuffer:mBuffer.get()
destinationOffset:byteOffset
size:size];
[blitEncoder endEncoding];
[cmdBuffer addCompletedHandler:^(id<MTLCommandBuffer> cb) {
bufferPool->releaseBuffer(staging);
}];
switch (mUploadStrategy) {
case UploadStrategy::BUMP_ALLOCATOR:
uploadWithBumpAllocator(src, size, byteOffset);
break;
case UploadStrategy::POOL:
uploadWithPoolBuffer(src, size, byteOffset);
break;
}
}
void MetalBuffer::copyIntoBufferUnsynchronized(void* src, size_t size, size_t byteOffset) {
@@ -199,5 +197,42 @@ void MetalBuffer::bindBuffers(id<MTLCommandBuffer> cmdBuffer, id<MTLCommandEncod
}
}
void MetalBuffer::uploadWithPoolBuffer(void* src, size_t size, size_t byteOffset) const {
MetalBufferPool* bufferPool = mContext.bufferPool;
const MetalBufferPoolEntry* const staging = bufferPool->acquireBuffer(size);
memcpy(staging->buffer.get().contents, src, size);
// Encode a blit from the staging buffer into the private GPU buffer.
id<MTLCommandBuffer> cmdBuffer = getPendingCommandBuffer(&mContext);
id<MTLBlitCommandEncoder> blitEncoder = [cmdBuffer blitCommandEncoder];
blitEncoder.label = @"Buffer upload blit - pool buffer";
[blitEncoder copyFromBuffer:staging->buffer.get()
sourceOffset:0
toBuffer:mBuffer.get()
destinationOffset:byteOffset
size:size];
[blitEncoder endEncoding];
[cmdBuffer addCompletedHandler:^(id<MTLCommandBuffer> cb) {
bufferPool->releaseBuffer(staging);
}];
}
void MetalBuffer::uploadWithBumpAllocator(void* src, size_t size, size_t byteOffset) const {
MetalBumpAllocator& allocator = *mContext.bumpAllocator;
auto [buffer, offset] = allocator.allocateStagingArea(size);
memcpy(static_cast<char*>(buffer.contents) + offset, src, size);
// Encode a blit from the staging buffer into the private GPU buffer.
id<MTLCommandBuffer> cmdBuffer = getPendingCommandBuffer(&mContext);
id<MTLBlitCommandEncoder> blitEncoder = [cmdBuffer blitCommandEncoder];
blitEncoder.label = @"Buffer upload blit - bump allocator";
[blitEncoder copyFromBuffer:buffer
sourceOffset:offset
toBuffer:mBuffer.get()
destinationOffset:byteOffset
size:size];
[blitEncoder endEncoding];
}
} // namespace backend
} // namespace filament
@@ -38,6 +38,28 @@ struct MetalBufferPoolEntry {
mutable uint32_t referenceCount;
};
class MetalBumpAllocator {
public:
MetalBumpAllocator(id<MTLDevice> device, size_t capacity);
/**
* Allocates a staging area of the given size. Returns a pair of the buffer and the offset
* within the buffer. The buffer is guaranteed to be at least the given size, but may be larger.
* Clients must not write to the buffer beyond the returned offset + size.
* Clients are responsible for holding a reference to the returned buffer.
* Allocations are guaranteed to be aligned to 4 bytes.
*/
std::pair<id<MTLBuffer>, size_t> allocateStagingArea(size_t size);
size_t getCapacity() const noexcept { return mCapacity; }
private:
id<MTLDevice> mDevice;
TrackedMetalBuffer mCurrentUploadBuffer = nil;
size_t mHead = 0;
size_t mCapacity;
};
// Manages a pool of Metal buffers, periodically releasing ones that have been unused for awhile.
class MetalBufferPool {
public:
@@ -116,5 +116,38 @@ void MetalBufferPool::reset() noexcept {
mFreeStages.clear();
}
MetalBumpAllocator::MetalBumpAllocator(id<MTLDevice> device, size_t capacity)
: mDevice(device), mCapacity(capacity) {
if (mCapacity > 0) {
mCurrentUploadBuffer = { [device newBufferWithLength:capacity options:MTLStorageModeShared],
TrackedMetalBuffer::Type::STAGING };
}
}
std::pair<id<MTLBuffer>, size_t> MetalBumpAllocator::allocateStagingArea(size_t size) {
if (size == 0) {
return { nil, 0 };
}
if (size > mCapacity) {
return { [mDevice newBufferWithLength:size options:MTLStorageModeShared], 0 };
}
assert_invariant(mCurrentUploadBuffer);
// Align the head to a 4-byte boundary.
mHead = (mHead + 3) & ~3;
if (UTILS_LIKELY(mHead + size <= mCapacity)) {
const size_t oldHead = mHead;
mHead += size;
return { mCurrentUploadBuffer.get(), oldHead };
}
// We're finished with the current allocation.
mCurrentUploadBuffer = { [mDevice newBufferWithLength:mCapacity options:MTLStorageModeShared],
TrackedMetalBuffer::Type::STAGING };
return { mCurrentUploadBuffer.get(), 0 };
}
} // namespace backend
} // namespace filament
@@ -44,6 +44,7 @@ namespace backend {
class MetalDriver;
class MetalBlitter;
class MetalBufferPool;
class MetalBumpAllocator;
class MetalRenderTarget;
class MetalSamplerGroup;
class MetalSwapChain;
@@ -141,6 +142,7 @@ struct MetalContext {
utils::FixedCircularBuffer<Handle<HwTexture>> texturesToDestroy;
MetalBufferPool* bufferPool;
MetalBumpAllocator* bumpAllocator;
MetalSwapChain* currentDrawSwapChain = nil;
MetalSwapChain* currentReadSwapChain = nil;
@@ -171,6 +171,8 @@ MetalDriver::MetalDriver(MetalPlatform* platform, const Platform::DriverConfig&
mContext->samplerStateCache.setDevice(mContext->device);
mContext->argumentEncoderCache.setDevice(mContext->device);
mContext->bufferPool = new MetalBufferPool(*mContext);
mContext->bumpAllocator =
new MetalBumpAllocator(mContext->device, driverConfig.metalUploadBufferSizeBytes);
mContext->blitter = new MetalBlitter(*mContext);
if (@available(iOS 12, *)) {
@@ -209,6 +211,7 @@ MetalDriver::~MetalDriver() noexcept {
mContext->emptyTexture = nil;
CFRelease(mContext->textureCache);
delete mContext->bufferPool;
delete mContext->bumpAllocator;
delete mContext->blitter;
delete mContext->timerQueryImpl;
delete mContext->shaderCompiler;
+1 -1
View File
@@ -109,7 +109,7 @@ private:
NSUInteger headlessWidth = 0;
NSUInteger headlessHeight = 0;
CAMetalLayer* layer = nullptr;
std::mutex layerDrawableMutex;
std::shared_ptr<std::mutex> layerDrawableMutex;
MetalExternalImage externalImage;
SwapChainType type;
+13 -10
View File
@@ -73,6 +73,7 @@ MetalSwapChain::MetalSwapChain(MetalContext& context, CAMetalLayer* nativeWindow
: context(context),
depthStencilFormat(decideDepthStencilFormat(flags)),
layer(nativeWindow),
layerDrawableMutex(std::make_shared<std::mutex>()),
externalImage(context),
type(SwapChainType::CAMETALLAYER) {
@@ -179,7 +180,7 @@ id<MTLTexture> MetalSwapChain::acquireDrawable() {
// calling -nextDrawable, or when releasing the last known reference
// to any CAMetalDrawable returned from a previous -nextDrawable.
{
std::lock_guard<std::mutex> lock(layerDrawableMutex);
std::lock_guard<std::mutex> lock(*layerDrawableMutex);
drawable = [layer nextDrawable];
}
@@ -188,8 +189,10 @@ id<MTLTexture> MetalSwapChain::acquireDrawable() {
}
void MetalSwapChain::releaseDrawable() {
std::lock_guard<std::mutex> lock(layerDrawableMutex);
drawable = nil;
if (drawable) {
std::lock_guard<std::mutex> lock(*layerDrawableMutex);
drawable = nil;
}
}
id<MTLTexture> MetalSwapChain::acquireDepthTexture() {
@@ -265,7 +268,7 @@ public:
PresentDrawableData& operator=(const PresentDrawableData&) = delete;
static PresentDrawableData* create(id<CAMetalDrawable> drawable,
std::mutex* drawableMutex, MetalDriver* driver) {
std::shared_ptr<std::mutex> drawableMutex, MetalDriver* driver) {
assert_invariant(drawableMutex);
assert_invariant(driver);
return new PresentDrawableData(drawable, drawableMutex, driver);
@@ -287,22 +290,22 @@ public:
}
private:
PresentDrawableData(id<CAMetalDrawable> drawable, std::mutex* drawableMutex,
PresentDrawableData(id<CAMetalDrawable> drawable, std::shared_ptr<std::mutex> drawableMutex,
MetalDriver* driver)
: mDrawable(drawable), mDrawableMutex(drawableMutex), mDriver(driver) {}
static void cleanupAndDestroy(PresentDrawableData *that) {
{
if (that->mDrawable) {
std::lock_guard<std::mutex> lock(*(that->mDrawableMutex));
that->mDrawable = nil;
}
that->mDrawableMutex = nullptr;
that->mDrawableMutex.reset();
that->mDriver = nullptr;
delete that;
}
id<CAMetalDrawable> mDrawable;
std::mutex* mDrawableMutex = nullptr;
std::shared_ptr<std::mutex> mDrawableMutex;
MetalDriver* mDriver = nullptr;
};
@@ -320,7 +323,7 @@ void MetalSwapChain::scheduleFrameScheduledCallback() {
struct Callback {
Callback(std::shared_ptr<FrameScheduledCallback> callback, id<CAMetalDrawable> drawable,
std::mutex* drawableMutex, MetalDriver* driver)
std::shared_ptr<std::mutex> drawableMutex, MetalDriver* driver)
: f(callback), data(PresentDrawableData::create(drawable, drawableMutex, driver)) {}
std::shared_ptr<FrameScheduledCallback> f;
// PresentDrawableData* is destroyed by maybePresentAndDestroyAsync() later.
@@ -337,7 +340,7 @@ void MetalSwapChain::scheduleFrameScheduledCallback() {
// This callback pointer will be captured by the block. Even if the scheduled handler is never
// called, the unique_ptr will still ensure we don't leak memory.
__block auto callback = std::make_unique<Callback>(
frameScheduled.callback, drawable, &layerDrawableMutex, context.driver);
frameScheduled.callback, drawable, layerDrawableMutex, context.driver);
backend::CallbackHandler* handler = frameScheduled.handler;
MetalDriver* driver = context.driver;
+4 -4
View File
@@ -2336,9 +2336,9 @@ void OpenGLDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh,
auto const* const pSamplers = (SamplerDescriptor const*)data.buffer;
for (size_t i = 0, c = sb->textureUnitEntries.size(); i < c; i++) {
GLuint samplerId = 0u;
const GLTexture* t = nullptr;
if (UTILS_LIKELY(pSamplers[i].t)) {
t = handle_cast<const GLTexture*>(pSamplers[i].t);
Handle<HwTexture> th = pSamplers[i].t;
if (UTILS_LIKELY(th)) {
GLTexture const* const t = handle_cast<const GLTexture*>(th);
assert_invariant(t);
SamplerParams params = pSamplers[i].s;
@@ -2394,7 +2394,7 @@ void OpenGLDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh,
// which is not an error.
}
sb->textureUnitEntries[i] = { t, samplerId };
sb->textureUnitEntries[i] = { th, samplerId };
}
scheduleDestroy(std::move(data));
}
+6 -1
View File
@@ -126,7 +126,7 @@ public:
struct GLSamplerGroup : public HwSamplerGroup {
using HwSamplerGroup::HwSamplerGroup;
struct Entry {
GLTexture const* texture = nullptr;
Handle<HwTexture> th;
GLuint sampler = 0u;
};
utils::FixedCapacityVector<Entry> textureUnitEntries;
@@ -256,6 +256,11 @@ private:
return mHandleAllocator.handle_cast<Dp, B>(handle);
}
template<typename B>
bool is_valid(Handle<B>& handle) {
return mHandleAllocator.is_valid(handle);
}
template<typename Dp, typename B>
inline typename std::enable_if_t<
std::is_pointer_v<Dp> &&
@@ -20,21 +20,24 @@
#include "OpenGLDriver.h"
#include "ShaderCompilerService.h"
#include <backend/DriverEnums.h>
#include <backend/Program.h>
#include <backend/Handle.h>
#include <private/backend/BackendUtils.h>
#include <utils/debug.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Log.h>
#include <utils/Systrace.h>
#include <algorithm>
#include <array>
#include <string_view>
#include <utility>
#include <new>
#include <stddef.h>
#include <stdint.h>
namespace filament::backend {
@@ -241,8 +244,9 @@ void OpenGLProgram::updateSamplers(OpenGLDriver* const gld) const noexcept {
assert_invariant(sb);
if (!sb) continue; // should never happen, this would be a user error.
for (uint8_t j = 0, m = sb->textureUnitEntries.size(); j < m; ++j, ++tmu) { // "<=" on purpose here
const GLTexture* const t = sb->textureUnitEntries[j].texture;
if (t) { // program may not use all samplers of sampler group
Handle<HwTexture> th = sb->textureUnitEntries[j].th;
if (th) { // program may not use all samplers of sampler group
GLTexture const* const t = gld->handle_cast<GLTexture const*>(th);
gld->bindTexture(tmu, t);
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
if (UTILS_LIKELY(!es2)) {
@@ -572,16 +572,23 @@ void ShaderCompilerService::compileShaders(OpenGLContext& context,
// split shader source, so we can insert the specialization constants and the packing
// functions
auto const [prolog, body] = splitShaderSource({ shader_src, shader_len });
auto [version, prolog, body] = splitShaderSource({ shader_src, shader_len });
const std::array<const char*, 4> sources = {
// enable ESSL 3.10 if available
if (context.isAtLeastGLES<3, 1>()) {
version = "#version 310 es\n";
}
const std::array<const char*, 5> sources = {
version.data(),
prolog.data(),
specializationConstantString.c_str(),
packingFunctions.data(),
body.data()
};
const std::array<GLint, 4> lengths = {
const std::array<GLint, 5> lengths = {
(GLint)version.length(),
(GLint)prolog.length(),
(GLint)specializationConstantString.length(),
(GLint)packingFunctions.length(),
@@ -661,6 +668,7 @@ void ShaderCompilerService::process_OVR_multiview2(OpenGLContext& context,
// Tragically, OpenGL 4.1 doesn't support unpackHalf2x16 (appeared in 4.2) and
// macOS doesn't support GL_ARB_shading_language_packing
// Also GLES3.0 didn't have the full set of packing/unpacking functions
std::string_view ShaderCompilerService::process_ARB_shading_language_packing(OpenGLContext& context) noexcept {
using namespace std::literals;
#ifdef BACKEND_OPENGL_VERSION_GL
@@ -700,21 +708,92 @@ highp uint packHalf2x16(vec2 v) {
highp uint y = fp32tou16(v.y);
return (y << 16u) | x;
}
highp uint packUnorm4x8(mediump vec4 v) {
v = round(clamp(v, 0.0, 1.0) * 255.0);
highp uint a = uint(v.x);
highp uint b = uint(v.y) << 8;
highp uint c = uint(v.z) << 16;
highp uint d = uint(v.w) << 24;
return (a|b|c|d);
}
highp uint packSnorm4x8(mediump vec4 v) {
v = round(clamp(v, -1.0, 1.0) * 127.0);
highp uint a = uint((int(v.x) & 0xff));
highp uint b = uint((int(v.y) & 0xff)) << 8;
highp uint c = uint((int(v.z) & 0xff)) << 16;
highp uint d = uint((int(v.w) & 0xff)) << 24;
return (a|b|c|d);
}
mediump vec4 unpackUnorm4x8(highp uint v) {
return vec4(float((v & 0x000000ffu) ),
float((v & 0x0000ff00u) >> 8),
float((v & 0x00ff0000u) >> 16),
float((v & 0xff000000u) >> 24)) / 255.0;
}
mediump vec4 unpackSnorm4x8(highp uint v) {
int a = int(((v ) & 0xffu) << 24u) >> 24 ;
int b = int(((v >> 8u) & 0xffu) << 24u) >> 24 ;
int c = int(((v >> 16u) & 0xffu) << 24u) >> 24 ;
int d = int(((v >> 24u) & 0xffu) << 24u) >> 24 ;
return clamp(vec4(float(a), float(b), float(c), float(d)) / 127.0, -1.0, 1.0);
}
)"sv;
}
#endif // BACKEND_OPENGL_VERSION_GL
#ifdef BACKEND_OPENGL_VERSION_GLES
if (!context.isES2() && !context.isAtLeastGLES<3, 1>()) {
return R"(
highp uint packUnorm4x8(mediump vec4 v) {
v = round(clamp(v, 0.0, 1.0) * 255.0);
highp uint a = uint(v.x);
highp uint b = uint(v.y) << 8;
highp uint c = uint(v.z) << 16;
highp uint d = uint(v.w) << 24;
return (a|b|c|d);
}
highp uint packSnorm4x8(mediump vec4 v) {
v = round(clamp(v, -1.0, 1.0) * 127.0);
highp uint a = uint((int(v.x) & 0xff));
highp uint b = uint((int(v.y) & 0xff)) << 8;
highp uint c = uint((int(v.z) & 0xff)) << 16;
highp uint d = uint((int(v.w) & 0xff)) << 24;
return (a|b|c|d);
}
mediump vec4 unpackUnorm4x8(highp uint v) {
return vec4(float((v & 0x000000ffu) ),
float((v & 0x0000ff00u) >> 8),
float((v & 0x00ff0000u) >> 16),
float((v & 0xff000000u) >> 24)) / 255.0;
}
mediump vec4 unpackSnorm4x8(highp uint v) {
int a = int(((v ) & 0xffu) << 24u) >> 24 ;
int b = int(((v >> 8u) & 0xffu) << 24u) >> 24 ;
int c = int(((v >> 16u) & 0xffu) << 24u) >> 24 ;
int d = int(((v >> 24u) & 0xffu) << 24u) >> 24 ;
return clamp(vec4(float(a), float(b), float(c), float(d)) / 127.0, -1.0, 1.0);
}
)"sv;
}
#endif // BACKEND_OPENGL_VERSION_GLES
return ""sv;
}
// split shader source code in two, the first section goes from the start to the line after the
// last #extension, and the 2nd part goes from there to the end.
std::array<std::string_view, 2> ShaderCompilerService::splitShaderSource(std::string_view source) noexcept {
// split shader source code in three:
// - the version line
// - extensions
// - everything else
std::array<std::string_view, 3> ShaderCompilerService::splitShaderSource(std::string_view source) noexcept {
auto start = source.find("#version");
assert_invariant(start != std::string_view::npos);
auto version_eol = source.find('\n', start) + 1;
assert_invariant(version_eol != std::string_view::npos);
auto pos = source.rfind("\n#extension");
if (pos == std::string_view::npos) {
pos = start;
pos = version_eol;
} else {
++pos;
}
@@ -722,9 +801,10 @@ std::array<std::string_view, 2> ShaderCompilerService::splitShaderSource(std::st
auto eol = source.find('\n', pos) + 1;
assert_invariant(eol != std::string_view::npos);
std::string_view const version = source.substr(start, eol - start);
std::string_view const body = source.substr(version.length(), source.length() - version.length());
return { version, body };
std::string_view const version = source.substr(start, version_eol - start);
std::string_view const prolog = source.substr(version_eol, eol - version_eol);
std::string_view const body = source.substr(eol, source.length() - eol);
return { version, prolog, body };
}
/*
@@ -146,7 +146,7 @@ private:
static std::string_view process_ARB_shading_language_packing(OpenGLContext& context) noexcept;
static std::array<std::string_view, 2> splitShaderSource(std::string_view source) noexcept;
static std::array<std::string_view, 3> splitShaderSource(std::string_view source) noexcept;
static GLuint linkProgram(OpenGLContext& context,
std::array<GLuint, Program::SHADER_TYPE_COUNT> shaders,
+33
View File
@@ -298,6 +298,24 @@ public:
*/
size_t textureUseAfterFreePoolSize = 0;
/**
* When uploading vertex or index data, the Filament Metal backend copies data
* into a shared staging area before transferring it to the GPU. This setting controls
* the total size of the buffer used to perform these allocations.
*
* Higher values can improve performance when performing many uploads across a small
* number of frames.
*
* This buffer remains alive throughout the lifetime of the Engine, so this size adds to the
* memory footprint of the app and should be set as conservative as possible.
*
* A value of 0 disables the shared staging buffer entirely; uploads will acquire an
* individual buffer from a pool of shared buffers.
*
* Only respected by the Metal backend.
*/
size_t metalUploadBufferSizeBytes = 512 * 1024;
/**
* Set to `true` to forcibly disable parallel shader compilation in the backend.
* Currently only honored by the GL and Metal backends.
@@ -1021,6 +1039,21 @@ public:
void resetBackendState() noexcept;
#endif
/**
* Get the current time. This is a convenience function that simply returns the
* time in nanosecond since epoch of std::chrono::steady_clock.
* A possible implementation is:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* return std::chrono::steady_clock::now().time_since_epoch().count();
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* @return current time in nanosecond since epoch of std::chrono::steady_clock.
* @see Renderer::beginFrame()
*/
static uint64_t getSteadyClockTimeNano() noexcept;
DebugRegistry& getDebugRegistry() noexcept;
protected:
@@ -158,6 +158,8 @@ public:
*
* @return This Builder, for chaining calls.
*
* @see Material::Builder::sphericalHarmonicsBandCount()
*
* @note
* Because the coefficients are pre-scaled, `sh[0]` is the environment's
* average irradiance.
+12
View File
@@ -140,6 +140,18 @@ public:
return constant(name, strlen(name), value);
}
/**
* Sets the quality of the indirect lights computations. This is only taken into account
* if this material is lit and in the surface domain. This setting will affect the
* IndirectLight computation if one is specified on the Scene and Spherical Harmonics
* are used for the irradiance.
*
* @param shBandCount Number of spherical harmonic bands. Must be 1, 2 or 3 (default).
* @return Reference to this Builder for chaining calls.
* @see IndirectLight
*/
Builder& sphericalHarmonicsBandCount(size_t shBandCount) noexcept;
/**
* Creates the Material object and returns a pointer to it.
*
+11
View File
@@ -227,6 +227,17 @@ public:
static constexpr CopyFrameFlag CLEAR = 0x4;
/**
* The use of this method is optional. It sets the VSYNC time expressed as the duration in
* nanosecond since epoch of std::chrono::steady_clock.
* If called, passing 0 to vsyncSteadyClockTimeNano in Renderer::BeginFrame will use this
* time instead.
* @param steadyClockTimeNano duration in nanosecond since epoch of std::chrono::steady_clock
* @see Engine::getSteadyClockTimeNano()
* @see Renderer::BeginFrame()
*/
void setVsyncTime(uint64_t steadyClockTimeNano) noexcept;
/**
* Set-up a frame for this Renderer.
*
+7 -1
View File
@@ -39,6 +39,8 @@
#include <utils/compiler.h>
#include <utils/Panic.h>
#include <chrono>
#include <stddef.h>
#include <stdint.h>
@@ -361,7 +363,7 @@ const Engine::Config& Engine::getConfig() const noexcept {
return downcast(this)->getConfig();
}
bool Engine::isStereoSupported(StereoscopicType stereoscopicType) const noexcept {
bool Engine::isStereoSupported(StereoscopicType) const noexcept {
return downcast(this)->isStereoSupported();
}
@@ -369,6 +371,10 @@ size_t Engine::getMaxStereoscopicEyes() noexcept {
return FEngine::getMaxStereoscopicEyes();
}
uint64_t Engine::getSteadyClockTimeNano() noexcept {
return std::chrono::steady_clock::now().time_since_epoch().count();
}
#if defined(__EMSCRIPTEN__)
void Engine::resetBackendState() noexcept {
downcast(this)->resetBackendState();
+4
View File
@@ -89,4 +89,8 @@ void Renderer::renderStandaloneView(View const* view) {
downcast(this)->renderStandaloneView(downcast(view));
}
void Renderer::setVsyncTime(uint64_t steadyClockTimeNano) noexcept {
downcast(this)->setVsyncTime(steadyClockTimeNano);
}
} // namespace filament
+2
View File
@@ -102,6 +102,7 @@ Engine* FEngine::create(Engine::Builder const& builder) {
DriverConfig const driverConfig{
.handleArenaSize = instance->getRequestedDriverHandleArenaSize(),
.textureUseAfterFreePoolSize = instance->getConfig().textureUseAfterFreePoolSize,
.metalUploadBufferSizeBytes = instance->getConfig().metalUploadBufferSizeBytes,
.disableParallelShaderCompile = instance->getConfig().disableParallelShaderCompile,
.disableHandleUseAfterFreeCheck = instance->getConfig().disableHandleUseAfterFreeCheck,
.forceGLES2Context = instance->getConfig().forceGLES2Context,
@@ -678,6 +679,7 @@ int FEngine::loop() {
DriverConfig const driverConfig {
.handleArenaSize = getRequestedDriverHandleArenaSize(),
.textureUseAfterFreePoolSize = mConfig.textureUseAfterFreePoolSize,
.metalUploadBufferSizeBytes = mConfig.metalUploadBufferSizeBytes,
.disableParallelShaderCompile = mConfig.disableParallelShaderCompile,
.disableHandleUseAfterFreeCheck = mConfig.disableHandleUseAfterFreeCheck,
.forceGLES2Context = mConfig.forceGLES2Context,
+8
View File
@@ -119,6 +119,7 @@ struct Material::BuilderDetails {
const void* mPayload = nullptr;
size_t mSize = 0;
bool mDefaultMaterial = false;
int32_t mShBandsCount = 3;
std::unordered_map<
utils::CString,
std::variant<int32_t, float, bool>,
@@ -143,6 +144,11 @@ Material::Builder& Material::Builder::package(const void* payload, size_t size)
return *this;
}
Material::Builder& Material::Builder::sphericalHarmonicsBandCount(size_t shBandCount) noexcept {
mImpl->mShBandsCount = math::clamp(shBandCount, size_t(1), size_t(3));
return *this;
}
template<typename T, typename>
Material::Builder& Material::Builder::constant(const char* name, size_t nameLength, T value) {
FILAMENT_CHECK_PRECONDITION(name != nullptr) << "name cannot be null";
@@ -897,6 +903,8 @@ void FMaterial::processSpecializationConstants(FEngine& engine, Material::Builde
mSpecializationConstants.push_back({
+ReservedSpecializationConstants::CONFIG_STEREO_EYE_COUNT,
(int)engine.getConfig().stereoscopicEyeCount });
mSpecializationConstants.push_back({
+ReservedSpecializationConstants::CONFIG_SH_BANDS_COUNT, builder->mShBandsCount });
if (UTILS_UNLIKELY(parser->getShaderLanguage() == ShaderLanguage::ESSL1)) {
// The actual value of this spec-constant is set in the OpenGLDriver backend.
mSpecializationConstants.push_back({
+9
View File
@@ -232,6 +232,10 @@ void FRenderer::setPresentationTime(int64_t monotonic_clock_ns) {
driver.setPresentationTime(monotonic_clock_ns);
}
void FRenderer::setVsyncTime(uint64_t steadyClockTimeNano) noexcept {
mVsyncSteadyClockTimeNano = steadyClockTimeNano;
}
bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeNano) {
assert_invariant(swapChain);
@@ -252,6 +256,11 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN
}
#endif
if (!vsyncSteadyClockTimeNano) {
vsyncSteadyClockTimeNano = mVsyncSteadyClockTimeNano;
mVsyncSteadyClockTimeNano = 0;
}
// get the timestamp as soon as possible
using namespace std::chrono;
const steady_clock::time_point now{ steady_clock::now() };
+13 -3
View File
@@ -29,9 +29,6 @@
#include "backend/DriverApiForward.h"
#include <fg/FrameGraphId.h>
#include <fg/FrameGraphTexture.h>
#include <filament/Renderer.h>
#include <filament/Viewport.h>
@@ -41,8 +38,18 @@
#include <utils/compiler.h>
#include <utils/Allocator.h>
#include <math/vec4.h>
#include <tsl/robin_set.h>
#include <algorithm>
#include <chrono>
#include <functional>
#include <utility>
#include <stddef.h>
#include <stdint.h>
namespace filament {
namespace backend {
@@ -78,6 +85,8 @@ public:
void setPresentationTime(int64_t monotonic_clock_ns);
void setVsyncTime(uint64_t steadyClockTimeNano) noexcept;
// start a frame
bool beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeNano);
@@ -187,6 +196,7 @@ private:
backend::TargetBufferFlags mClearFlags{};
tsl::robin_set<FRenderTarget*> mPreviousRenderTargets;
std::function<void()> mBeginFrameInternal;
uint64_t mVsyncSteadyClockTimeNano = 0;
};
FILAMENT_DOWNCAST(Renderer)
+2 -2
View File
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.53.0"
spec.version = "1.53.1"
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.53.0/filament-v1.53.0-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.53.1/filament-v1.53.1-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {
@@ -109,6 +109,7 @@ public:
vec4 groundPlane;
RayCallback raycastCallback;
void* raycastUserdata;
bool panning = true;
};
struct Builder {
@@ -143,6 +144,8 @@ public:
Builder& groundPlane(FLOAT a, FLOAT b, FLOAT c, FLOAT d); //! Plane equation used as a raycast fallback
Builder& raycastCallback(RayCallback cb, void* userdata); //! Raycast function for accurate grab-and-pan
Builder& panning(bool enabled); //! Sets whether panning is enabled
/**
* Creates a new camera manipulator, either ORBIT, MAP, or FREE_FLIGHT.
*
+8
View File
@@ -144,6 +144,14 @@ Manipulator<FLOAT>::Builder& Manipulator<FLOAT>::Builder::raycastCallback(RayCal
return *this;
}
template <typename FLOAT> typename
Manipulator<FLOAT>::Builder& Manipulator<FLOAT>::Builder::panning(bool enabled) {
details.panning = enabled;
return *this;
}
template <typename FLOAT>
Manipulator<FLOAT>* Manipulator<FLOAT>::Builder::build(Mode mode) {
switch (mode) {
+1 -1
View File
@@ -69,7 +69,7 @@ public:
}
void grabBegin(int x, int y, bool strafe) override {
mGrabState = strafe ? PANNING : ORBITING;
mGrabState = strafe && Base::mProps.panning ? PANNING : ORBITING;
mGrabPivot = mPivot;
mGrabEye = Base::mEye;
mGrabTarget = Base::mTarget;
@@ -203,7 +203,7 @@ enum class ReflectionMode : uint8_t {
// can't really use std::underlying_type<AttributeIndex>::type because the driver takes a uint32_t
using AttributeBitset = utils::bitset32;
static constexpr size_t MATERIAL_PROPERTIES_COUNT = 27;
static constexpr size_t MATERIAL_PROPERTIES_COUNT = 29;
enum class Property : uint8_t {
BASE_COLOR, //!< float4, all shading models
ROUGHNESS, //!< float, lit shading models only
@@ -232,6 +232,8 @@ enum class Property : uint8_t {
IOR, //!< float, material's index of refraction
MICRO_THICKNESS, //!< float, thickness of the thin layer
BENT_NORMAL, //!< float3, all shading models only, except unlit
SPECULAR_FACTOR, //!< float, lit shading models only, except subsurface and cloth
SPECULAR_COLOR_FACTOR, //!< float3, lit shading models only, except subsurface and cloth
// when adding new Properties, make sure to update MATERIAL_PROPERTIES_COUNT
};
@@ -70,6 +70,7 @@ enum class ReservedSpecializationConstants : uint8_t {
CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP = 6,
CONFIG_DEBUG_FROXEL_VISUALIZATION = 7,
CONFIG_STEREO_EYE_COUNT = 8, // don't change (hardcoded in ShaderCompilerService.cpp)
CONFIG_SH_BANDS_COUNT = 9
};
enum class PushConstantIds : uint8_t {
+28 -26
View File
@@ -21,33 +21,35 @@
namespace filamat {
std::unordered_map<std::string, Property> Enums::mStringToProperty = {
{ "baseColor", Property::BASE_COLOR },
{ "roughness", Property::ROUGHNESS },
{ "metallic", Property::METALLIC },
{ "reflectance", Property::REFLECTANCE },
{ "ambientOcclusion", Property::AMBIENT_OCCLUSION },
{ "clearCoat", Property::CLEAR_COAT },
{ "clearCoatRoughness", Property::CLEAR_COAT_ROUGHNESS },
{ "clearCoatNormal", Property::CLEAR_COAT_NORMAL },
{ "anisotropy", Property::ANISOTROPY },
{ "anisotropyDirection", Property::ANISOTROPY_DIRECTION },
{ "thickness", Property::THICKNESS },
{ "subsurfacePower", Property::SUBSURFACE_POWER },
{ "subsurfaceColor", Property::SUBSURFACE_COLOR },
{ "sheenColor", Property::SHEEN_COLOR },
{ "sheenRoughness", Property::SHEEN_ROUGHNESS },
{ "glossiness", Property::GLOSSINESS },
{ "specularColor", Property::SPECULAR_COLOR },
{ "emissive", Property::EMISSIVE },
{ "normal", Property::NORMAL },
{ "postLightingColor", Property::POST_LIGHTING_COLOR },
{ "baseColor", Property::BASE_COLOR },
{ "roughness", Property::ROUGHNESS },
{ "metallic", Property::METALLIC },
{ "reflectance", Property::REFLECTANCE },
{ "ambientOcclusion", Property::AMBIENT_OCCLUSION },
{ "clearCoat", Property::CLEAR_COAT },
{ "clearCoatRoughness", Property::CLEAR_COAT_ROUGHNESS },
{ "clearCoatNormal", Property::CLEAR_COAT_NORMAL },
{ "anisotropy", Property::ANISOTROPY },
{ "anisotropyDirection", Property::ANISOTROPY_DIRECTION },
{ "thickness", Property::THICKNESS },
{ "subsurfacePower", Property::SUBSURFACE_POWER },
{ "subsurfaceColor", Property::SUBSURFACE_COLOR },
{ "sheenColor", Property::SHEEN_COLOR },
{ "sheenRoughness", Property::SHEEN_ROUGHNESS },
{ "glossiness", Property::GLOSSINESS },
{ "specularColor", Property::SPECULAR_COLOR },
{ "emissive", Property::EMISSIVE },
{ "normal", Property::NORMAL },
{ "postLightingColor", Property::POST_LIGHTING_COLOR },
{ "postLightingMixFactor", Property::POST_LIGHTING_MIX_FACTOR },
{ "clipSpaceTransform", Property::CLIP_SPACE_TRANSFORM },
{ "absorption", Property::ABSORPTION },
{ "transmission", Property::TRANSMISSION },
{ "ior", Property::IOR },
{ "microThickness", Property::MICRO_THICKNESS },
{ "bentNormal", Property::BENT_NORMAL },
{ "clipSpaceTransform", Property::CLIP_SPACE_TRANSFORM },
{ "absorption", Property::ABSORPTION },
{ "transmission", Property::TRANSMISSION },
{ "ior", Property::IOR },
{ "microThickness", Property::MICRO_THICKNESS },
{ "bentNormal", Property::BENT_NORMAL },
{ "specularFactor", Property::SPECULAR_FACTOR },
{ "specularColorFactor", Property::SPECULAR_COLOR_FACTOR }
};
template <>
@@ -332,6 +332,9 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade
generateSpecializationConstant(out, "CONFIG_STEREO_EYE_COUNT",
+ReservedSpecializationConstants::CONFIG_STEREO_EYE_COUNT, material.stereoscopicEyeCount);
generateSpecializationConstant(out, "CONFIG_SH_BANDS_COUNT",
+ReservedSpecializationConstants::CONFIG_SH_BANDS_COUNT, 3);
// CONFIG_MAX_STEREOSCOPIC_EYES is used to size arrays and on Adreno GPUs + vulkan, this has to
// be explicitly, statically defined (as in #define). Otherwise (using const int for
// example), we'd run into a GPU crash.
@@ -1189,6 +1192,8 @@ char const* CodeGenerator::getConstantName(MaterialBuilder::Property property) n
case Property::IOR: return "IOR";
case Property::MICRO_THICKNESS: return "MICRO_THICKNESS";
case Property::BENT_NORMAL: return "BENT_NORMAL";
case Property::SPECULAR_FACTOR: return "SPECULAR_FACTOR";
case Property::SPECULAR_COLOR_FACTOR: return "SPECULAR_COLOR_FACTOR";
}
}
+3
View File
@@ -147,6 +147,9 @@ build_ubershader(volume_opaque volume lit opaque)
build_ubershader(volume_fade volume lit fade)
build_ubershader(volume_masked volume lit masked)
build_ubershader(sheen sheen _ _)
build_ubershader(specular_opaque specular lit opaque)
build_ubershader(specular_fade specular lit fade)
build_ubershader(specular_masked specular lit masked)
add_custom_target(uberz_file DEPENDS ${UBERZ_OUTPUT_PATH})
set_target_properties(uberz_file PROPERTIES FOLDER Libs)
@@ -93,10 +93,17 @@ struct alignas(4) MaterialKey {
bool hasSheen : 1;
bool hasIOR : 1;
bool hasVolume : 1;
uint8_t padding : 5;
bool hasSpecular : 1;
bool hasSpecularTexture : 1;
bool hasSpecularColorTexture : 1;
bool padding : 2;
// -- 32 bit boundary --
uint8_t specularTextureUV;
uint8_t specularColorTextureUV;
uint16_t padding2;
};
static_assert(sizeof(MaterialKey) == 16, "MaterialKey has unexpected size.");
static_assert(sizeof(MaterialKey) == 20, "MaterialKey has unexpected size.");
UTILS_WARNING_POP
+5
View File
@@ -30,3 +30,8 @@ TransmissionTexture = unsupported
# Volume Features
Volume = unsupported
VolumeThicknessTexture = unsupported
# Specular Features
Specular = unsupported
SpecularTexture = unsupported
SpecularColorTexture = unsupported
+19 -1
View File
@@ -55,7 +55,16 @@ material {
{ type : mat3, name : sheenRoughnessUvMatrix, precision: high },
// Reflectance
{ type : float, name : reflectance }
{ type : float, name : reflectance },
// KHR_materials_specular
{ type : float, name : specularStrength },
{ type : float3, name : specularColorFactor },
{ type : int, name : specularIndex },
{ type : sampler2d, name : specularMap },
{ type : mat3, name : specularUvMatrix, precision: high },
{ type : int, name : specularColorIndex },
{ type : mat3, name : specularColorUvMatrix, precision: high }
${CUSTOM_PARAMS}
],
@@ -136,6 +145,15 @@ fragment {
material.emissive.rgb *= texture(materialParams_emissiveMap, uv).rgb;
}
material.specularFactor = materialParams.specularStrength;
material.specularColorFactor = materialParams.specularColorFactor;
if (materialParams.specularIndex > -1) {
highp float2 uv = uvs[materialParams.specularIndex];
uv = (vec3(uv, 1.0) * materialParams.specularUvMatrix).xy;
material.specularFactor *= texture(materialParams_specularMap, uv).a;
}
${CUSTOM_FRAGMENT}
}
}
+5
View File
@@ -17,3 +17,8 @@ TextureTransforms=optional
Sheen=optional
SheenColorTexture=optional
SheenRoughnessTexture=optional
# KHR_material_specular Features
Specular=optional
SpecularTexture=optional
SpecularColorTexture=unsupported
+168
View File
@@ -0,0 +1,168 @@
material {
name : specular_ubershader,
requires : [ uv0, uv1, color ],
shadingModel : lit,
blending : ${BLENDING},
doubleSided : ${DOUBLESIDED},
transparency : ${TRANSPARENCY},
flipUV : false,
specularAmbientOcclusion : simple,
specularAntiAliasing : true,
clearCoatIorChange : false,
reflections: screenspace,
parameters : [
// Base Color
{ type : int, name : baseColorIndex },
{ type : float4, name : baseColorFactor },
{ type : sampler2d, name : baseColorMap },
{ type : mat3, name : baseColorUvMatrix, precision: high },
// Metallic-Roughness Map
{ type : int, name : metallicRoughnessIndex },
{ type : float, name : metallicFactor },
{ type : float, name : roughnessFactor },
{ type : sampler2d, name : metallicRoughnessMap },
{ type : mat3, name : metallicRoughnessUvMatrix, precision: high },
// Normal Map
{ type : int, name : normalIndex },
{ type : float, name : normalScale },
{ type : sampler2d, name : normalMap },
{ type : mat3, name : normalUvMatrix, precision: high },
// Ambient Occlusion
{ type : int, name : aoIndex },
{ type : float, name : aoStrength },
{ type : sampler2d, name : occlusionMap },
{ type : mat3, name : occlusionUvMatrix, precision: high },
// Emissive Map
{ type : int, name : emissiveIndex },
{ type : float3, name : emissiveFactor },
{ type : float, name : emissiveStrength },
{ type : sampler2d, name : emissiveMap },
{ type : mat3, name : emissiveUvMatrix, precision: high },
// Clear coat, we drop texture support for clear coat due to 8 texture limits.
{ type : float, name : clearCoatFactor },
{ type : float, name : clearCoatRoughnessFactor },
{ type : int, name : clearCoatIndex },
{ type : sampler2d, name : clearCoatMap },
{ type : mat3, name : clearCoatUvMatrix, precision: high },
{ type : int, name : clearCoatRoughnessIndex },
{ type : mat3, name : clearCoatRoughnessUvMatrix, precision: high },
{ type : int, name : clearCoatNormalIndex },
{ type : mat3, name : clearCoatNormalUvMatrix, precision: high },
{ type : float, name : clearCoatNormalScale },
// KHR_materials_specular
{ type : float, name : specularStrength },
{ type : float3, name : specularColorFactor },
{ type : int, name : specularIndex },
{ type : sampler2d, name : specularMap },
{ type : mat3, name : specularUvMatrix, precision: high },
{ type : int, name : specularColorIndex },
{ type : sampler2d, name : specularColorMap },
{ type : mat3, name : specularColorUvMatrix, precision: high },
// IOR
{ type : float, name : ior }
${CUSTOM_PARAMS}
],
}
vertex {
void materialVertex(inout MaterialVertexInputs material) {
${CUSTOM_VERTEX}
}
}
fragment {
void material(inout MaterialInputs material) {
highp float2 uvs[2];
uvs[0] = getUV0();
uvs[1] = getUV1();
if (materialParams.normalIndex > -1) {
highp float2 uv = uvs[materialParams.normalIndex];
uv = (vec3(uv, 1.0) * materialParams.normalUvMatrix).xy;
material.normal = texture(materialParams_normalMap, uv).xyz * 2.0 - 1.0;
material.normal.xy *= materialParams.normalScale;
}
prepareMaterial(material);
material.baseColor = materialParams.baseColorFactor;
if (materialParams.baseColorIndex > -1) {
highp float2 uv = uvs[materialParams.baseColorIndex];
uv = (vec3(uv, 1.0) * materialParams.baseColorUvMatrix).xy;
material.baseColor *= texture(materialParams_baseColorMap, uv);
}
#if defined(BLEND_MODE_TRANSPARENT)
material.baseColor.rgb *= material.baseColor.a;
#endif
material.baseColor *= getColor();
material.roughness = materialParams.roughnessFactor;
material.metallic = materialParams.metallicFactor;
material.ior = materialParams.ior;
material.emissive = vec4(materialParams.emissiveStrength *
materialParams.emissiveFactor.rgb, 0.0);
// KHR_materials_clearcoat forbids clear coat from
// being applied in the specular/glossiness model
material.clearCoat = materialParams.clearCoatFactor;
material.clearCoatRoughness = materialParams.clearCoatRoughnessFactor;
if (materialParams.clearCoatIndex > -1) {
highp float2 uv = uvs[materialParams.clearCoatIndex];
uv = (vec3(uv, 1.0) * materialParams.clearCoatUvMatrix).xy;
material.clearCoat *= texture(materialParams_clearCoatMap, uv).r;
}
material.specularFactor = materialParams.specularStrength;
material.specularColorFactor = materialParams.specularColorFactor;
if (materialParams.specularIndex > -1) {
highp float2 uv = uvs[materialParams.specularIndex];
uv = (vec3(uv, 1.0) * materialParams.specularUvMatrix).xy;
material.specularFactor *= texture(materialParams_specularMap, uv).a;
}
if (materialParams.specularColorIndex > -1) {
highp float2 uv = uvs[materialParams.specularColorIndex];
uv = (vec3(uv, 1.0) * materialParams.specularColorUvMatrix).xy;
vec4 sc = texture(materialParams_specularColorMap, uv);
material.specularColorFactor.r *= sc.r;
material.specularColorFactor.g *= sc.g;
material.specularColorFactor.b *= sc.b;
}
if (materialParams.metallicRoughnessIndex > -1) {
highp float2 uv = uvs[materialParams.metallicRoughnessIndex];
uv = (vec3(uv, 1.0) * materialParams.metallicRoughnessUvMatrix).xy;
vec4 mr = texture(materialParams_metallicRoughnessMap, uv);
material.roughness *= mr.g;
material.metallic *= mr.b;
}
if (materialParams.aoIndex > -1) {
highp float2 uv = uvs[materialParams.aoIndex];
uv = (vec3(uv, 1.0) * materialParams.occlusionUvMatrix).xy;
float occlusion = texture(materialParams_occlusionMap, uv).r;
material.ambientOcclusion = 1.0 + materialParams.aoStrength * (occlusion - 1.0);
}
if (materialParams.emissiveIndex > -1) {
highp float2 uv = uvs[materialParams.emissiveIndex];
uv = (vec3(uv, 1.0) * materialParams.emissiveUvMatrix).xy;
material.emissive.rgb *= texture(materialParams_emissiveMap, uv).rgb;
}
${CUSTOM_FRAGMENT}
}
}
+35
View File
@@ -0,0 +1,35 @@
ShadingModel=lit
# Required Aspects
BlendingMode = ${BLENDING}
VertexColors = optional
BaseColorTexture = optional
NormalTexture = optional
OcclusionTexture = optional
EmissiveTexture = optional
MetallicRoughnessTexture = optional
TextureTransforms = optional
# KHR_materials_specular Features
Specular = optional
SpecularTexture = optional
SpecularColorTexture = optional
# ClearCoat Features
ClearCoat = optional
ClearCoatTexture = optional
# Sheen Features
Sheen = unsupported
SheenColorTexture = unsupported
SheenRoughnessTexture = unsupported
# Transmission and IOR Features
Transmission = unsupported
Ior = optional
TransmissionTexture = unsupported
# Volume Features
Volume = unsupported
VolumeThicknessTexture = unsupported
+30 -1
View File
@@ -52,7 +52,18 @@ material {
{ type : mat3, name : transmissionUvMatrix, precision: high },
// IOR
{ type : float, name : ior }
{ type : float, name : ior },
// KHR_materials_specular
{ type : float, name : specularStrength },
{ type : float3, name : specularColorFactor },
{ type : int, name : specularIndex },
{ type : sampler2d, name : specularMap },
{ type : mat3, name : specularUvMatrix, precision: high },
{ type : int, name : specularColorIndex },
{ type : sampler2d, name : specularColorMap },
{ type : mat3, name : specularColorUvMatrix, precision: high }
${CUSTOM_PARAMS}
],
@@ -126,6 +137,24 @@ fragment {
material.emissive.rgb *= texture(materialParams_emissiveMap, uv).rgb;
}
material.specularFactor = materialParams.specularStrength;
material.specularColorFactor = materialParams.specularColorFactor;
if (materialParams.specularIndex > -1) {
highp float2 uv = uvs[materialParams.specularIndex];
uv = (vec3(uv, 1.0) * materialParams.specularUvMatrix).xy;
material.specularFactor *= texture(materialParams_specularMap, uv).a;
}
if (materialParams.specularColorIndex > -1) {
highp float2 uv = uvs[materialParams.specularColorIndex];
uv = (vec3(uv, 1.0) * materialParams.specularColorUvMatrix).xy;
vec4 sc = texture(materialParams_specularColorMap, uv);
material.specularColorFactor.r *= sc.r;
material.specularColorFactor.g *= sc.g;
material.specularColorFactor.b *= sc.b;
}
${CUSTOM_FRAGMENT}
}
}
@@ -15,6 +15,11 @@ EmissiveTexture=optional
MetallicRoughnessTexture=optional
TextureTransforms=optional
# KHR_materials_specular Features
Specular=optional
SpecularTexture=optional
SpecularColorTexture=optional
Transmission=optional
Ior=optional
TransmissionTexture=optional
+18
View File
@@ -58,6 +58,15 @@ material {
{ type : sampler2d, name : volumeThicknessMap },
{ type : mat3, name : volumeThicknessUvMatrix, precision: high },
// KHR_materials_specular
{ type : float, name : specularStrength },
{ type : float3, name : specularColorFactor },
{ type : int, name : specularIndex },
{ type : sampler2d, name : specularMap },
{ type : mat3, name : specularUvMatrix, precision: high },
{ type : int, name : specularColorIndex },
{ type : mat3, name : specularColorUvMatrix, precision: high },
// IOR
{ type : float, name : ior }
@@ -142,6 +151,15 @@ fragment {
material.emissive.rgb *= texture(materialParams_emissiveMap, uv).rgb;
}
material.specularFactor = materialParams.specularStrength;
material.specularColorFactor = materialParams.specularColorFactor;
if (materialParams.specularIndex > -1) {
highp float2 uv = uvs[materialParams.specularIndex];
uv = (vec3(uv, 1.0) * materialParams.specularUvMatrix).xy;
material.specularFactor *= texture(materialParams_specularMap, uv).a;
}
${CUSTOM_FRAGMENT}
}
}
+5
View File
@@ -26,3 +26,8 @@ TransmissionTexture=optional
# Volume Features
Volume=optional
VolumeThicknessTexture=optional
# KHR_materials_specular Features
Specular=optional
SpecularTexture=optional
SpecularColorTexture=unsupported
+34 -1
View File
@@ -1222,6 +1222,7 @@ MaterialKey FAssetLoader::getMaterialKey(const cgltf_data* srcAsset,
auto trConfig = inputMat->transmission;
auto shConfig = inputMat->sheen;
auto vlConfig = inputMat->volume;
auto spConfig = inputMat->specular;
*baseColorTexture = mrConfig.base_color_texture;
*metallicRoughnessTexture = mrConfig.metallic_roughness_texture;
@@ -1238,7 +1239,9 @@ MaterialKey FAssetLoader::getMaterialKey(const cgltf_data* srcAsset,
ccConfig.clearcoat_normal_texture.has_transform ||
shConfig.sheen_color_texture.has_transform ||
shConfig.sheen_roughness_texture.has_transform ||
trConfig.transmission_texture.has_transform;
trConfig.transmission_texture.has_transform ||
spConfig.specular_color_texture.has_transform ||
spConfig.specular_texture.has_transform;
MaterialKey matkey {
.doubleSided = !!inputMat->double_sided,
@@ -1273,6 +1276,11 @@ MaterialKey FAssetLoader::getMaterialKey(const cgltf_data* srcAsset,
.hasSheen = !!inputMat->has_sheen,
.hasIOR = !!inputMat->has_ior,
.hasVolume = !!inputMat->has_volume,
.hasSpecular = !!inputMat->has_specular,
.hasSpecularTexture = spConfig.specular_texture.texture != nullptr,
.hasSpecularColorTexture = spConfig.specular_color_texture.texture != nullptr,
.specularTextureUV = (uint8_t) spConfig.specular_texture.texcoord,
.specularColorTextureUV = (uint8_t) spConfig.specular_color_texture.texcoord,
};
if (inputMat->has_pbr_specular_glossiness) {
@@ -1361,6 +1369,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_material* inp
auto trConfig = inputMat->transmission;
auto shConfig = inputMat->sheen;
auto vlConfig = inputMat->volume;
auto spConfig = inputMat->specular;
// Check the material blending mode, not the cgltf blending mode, because the provider
// might have selected an alternative blend mode (e.g. to support transmission).
@@ -1560,6 +1569,30 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_material* inp
inputMat->emissive_strength.emissive_strength : 1.0f);
}
if (matkey.hasSpecular) {
const float* s = spConfig.specular_color_factor;
mi->setParameter("specularColorFactor", float3{s[0], s[1], s[2]});
mi->setParameter("specularStrength", spConfig.specular_factor);
if (matkey.hasSpecularColorTexture) {
fAsset->addTextureBinding(mi, "specularColorMap", spConfig.specular_color_texture.texture, sRGB);
if (matkey.hasTextureTransforms) {
const cgltf_texture_transform uvt = spConfig.specular_color_texture.transform;
auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale);
mi->setParameter("specularColorUvMatrix", uvmat);
}
}
if (matkey.hasSpecularTexture) {
bool sameTexture = spConfig.specular_color_texture.texture == spConfig.specular_texture.texture;
fAsset->addTextureBinding(mi, "specularMap", spConfig.specular_texture.texture, sameTexture ? sRGB : LINEAR);
if (matkey.hasTextureTransforms) {
const cgltf_texture_transform uvt = spConfig.specular_texture.transform;
auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale);
mi->setParameter("specularUvMatrix", uvmat);
}
}
}
*cacheEntry = { mi, *uvmap };
return mi;
}
+49
View File
@@ -308,6 +308,35 @@ std::string shaderFromKey(const MaterialKey& config) {
material.ior = materialParams.ior;
)SHADER";
}
if (config.hasSpecular) {
shader += R"SHADER(
material.specularFactor = materialParams.specularStrength;
material.specularColorFactor = materialParams.specularColorFactor;
)SHADER";
if (config.hasSpecularTexture) {
shader += "highp float2 specularUV = ${specular};\n";
if (config.hasTextureTransforms) {
shader += "specularUV = (vec3(specularUV, 1.0) * "
"materialParams.specularUvMatrix).xy;\n";
}
shader += R"SHADER(
material.specularFactor *= texture(materialParams_specularMap, specularUV).a;
)SHADER";
}
if (config.hasSpecularColorTexture) {
shader += "highp float2 specularColorUV = ${specularColor};\n";
if (config.hasTextureTransforms) {
shader += "specularColorUV = (vec3(specularColorUV, 1.0) * "
"materialParams.specularColorUvMatrix).xy;\n";
}
shader += R"SHADER(
material.specularColorFactor *= texture(materialParams_specularColorMap, specularColorUV).rgb;
)SHADER";
}
}
}
shader += "}\n";
@@ -463,6 +492,26 @@ Material* createMaterial(Engine* engine, const MaterialKey& config, const UvMap&
}
}
// SPECULAR
if (config.hasSpecular) {
builder.parameter("specularStrength", MaterialBuilder::UniformType::FLOAT);
builder.parameter("specularColorFactor", MaterialBuilder::UniformType::FLOAT3);
if (config.hasSpecularTexture) {
builder.parameter("specularMap", MaterialBuilder::SamplerType::SAMPLER_2D);
if (config.hasTextureTransforms) {
builder.parameter("specularUvMatrix", MaterialBuilder::UniformType::MAT3,
MaterialBuilder::ParameterPrecision::HIGH);
}
}
if (config.hasSpecularColorTexture) {
builder.parameter("specularColorMap", MaterialBuilder::SamplerType::SAMPLER_2D);
if (config.hasTextureTransforms) {
builder.parameter("specularColorUvMatrix", MaterialBuilder::UniformType::MAT3,
MaterialBuilder::ParameterPrecision::HIGH);
}
}
}
// BLENDING
switch (config.alphaMode) {
case AlphaMode::OPAQUE:
+19
View File
@@ -143,6 +143,21 @@ void constrainMaterial(MaterialKey* key, UvMap* uvmap) {
retval[key->volumeThicknessUV] = (UvSet) index++;
}
}
if (key->hasSpecularTexture && retval[key->specularTextureUV] == UNUSED) {
if (index > MAX_INDEX) {
key->hasSpecularTexture = false;
} else {
retval[key->specularTextureUV] = (UvSet) index++;
}
}
if (key->hasSpecularColorTexture && retval[key->specularColorTextureUV] == UNUSED) {
if (index > MAX_INDEX) {
key->hasSpecularColorTexture = false;
} else {
retval[key->specularColorTextureUV] = (UvSet) index++;
}
}
// NOTE: KHR_materials_clearcoat does not provide separate UVs, we'll assume UV0
*uvmap = retval;
}
@@ -167,6 +182,8 @@ void processShaderString(std::string* shader, const UvMap& uvmap, const Material
const auto& sheenColorUV = uvstrings[uvmap[config.sheenColorUV]];
const auto& sheenRoughnessUV = uvstrings[uvmap[config.sheenRoughnessUV]];
const auto& volumeThicknessUV = uvstrings[uvmap[config.volumeThicknessUV]];
const auto& specularUV = uvstrings[uvmap[config.specularTextureUV]];
const auto& specularColorUV = uvstrings[uvmap[config.specularColorTextureUV]];
replaceAll("${normal}", normalUV);
replaceAll("${color}", baseColorUV);
@@ -180,6 +197,8 @@ void processShaderString(std::string* shader, const UvMap& uvmap, const Material
replaceAll("${sheenColor}", sheenColorUV);
replaceAll("${sheenRoughness}", sheenRoughnessUV);
replaceAll("${volumeThickness}", volumeThicknessUV);
replaceAll("${specular}", specularUV);
replaceAll("${specularColor}", specularColorUV);
}
} // namespace filament::gltfio
+55
View File
@@ -63,6 +63,42 @@ static void prepareConfig(MaterialKey* config, const char* label) {
config->hasSheen = false;
config->hasIOR = false;
}
if (config->useSpecularGlossiness && config->hasSpecular) {
slog.w << "SpecularGlossiness and specular are not supported together in ubershader mode,"
" removing specularGlossiness (" << label << ")." << io::endl;
config->useSpecularGlossiness = false;
}
if (config->unlit && config->hasSpecular) {
slog.w << "Unlit and specular are not supported together in ubershader mode,"
" removing unlit (" << label << ")." << io::endl;
config->unlit = false;
}
// Also due to sampler overload, clearcoat with specular, we can only support with specular map.
if ((config->hasClearCoatNormalTexture || config->hasClearCoatRoughnessTexture) && config->hasSpecular) {
slog.w << "Specular can only work with clearcoat that does not use clear coat normal or clear coat roughness map,"
" removing clear coat normal and roughness (" << label << ")." << io::endl;
config->hasClearCoatNormalTexture = false;
config->hasClearCoatRoughnessTexture = false;
}
// Also due to sampler overload, sheen with specular, we can only support without specular color texture.
if (config->hasSpecularColorTexture && config->hasSheen) {
slog.w << "Sheen can only work with specular that does not use specular color map,"
" removing specular color (" << label << ")." << io::endl;
config->hasSpecularColorTexture = false;
}
// Also due to sampler overload, volume with specular, we can only support without specular color texture.
if (config->hasSpecularColorTexture && config->hasVolume) {
slog.w << "Volume can only work with specular that does not use specular color map,"
"removing specular color (" << label << ")." << io::endl;
config->hasSpecularColorTexture = false;
}
}
class UbershaderProvider : public MaterialProvider {
@@ -155,6 +191,9 @@ Material* UbershaderProvider::getMaterial(const MaterialKey& config) const {
requirements.features["SheenColorTexture"] = config.hasSheenColorTexture;
requirements.features["SheenRoughnessTexture"] = config.hasSheenRoughnessTexture;
requirements.features["VolumeThicknessTexture"] = config.hasVolumeThicknessTexture;
requirements.features["Specular"] = config.hasSpecular;
requirements.features["SpecularTexture"] = config.hasSpecularTexture;
requirements.features["SpecularColorTexture"] = config.hasSpecularColorTexture;
if (Material* mat = mMaterials.getMaterial(requirements); mat != nullptr) {
return mat;
@@ -250,6 +289,14 @@ MaterialInstance* UbershaderProvider::createMaterialInstance(MaterialKey* config
mi->setParameter("transmissionIndex",
getUvIndex(config->transmissionUV, config->hasTransmissionTexture));
}
if (config->hasSpecular) {
mi->setParameter("specularUvMatrix", identity);
mi->setParameter("specularIndex",
getUvIndex(config->specularTextureUV, config->hasSpecularTexture));
mi->setParameter("specularColorUvMatrix", identity);
mi->setParameter("specularColorIndex",
getUvIndex(config->specularColorTextureUV, config->hasSpecularColorTexture));
}
}
TextureSampler sampler;
@@ -300,6 +347,14 @@ MaterialInstance* UbershaderProvider::createMaterialInstance(MaterialKey* config
mi->setParameter("reflectance", 0.5f);
}
if (needsTexture("SpecularTexture")) {
mi->setParameter("specularMap", mDummyTexture, sampler);
}
if (needsTexture("SpecularColorTexture")) {
mi->setParameter("specularColorMap", mDummyTexture, sampler);
}
return mi;
}
+3 -2
View File
@@ -547,10 +547,11 @@ static bool checkAsset(const utils::Path& filename) {
return false;
}
// Parse the glTF file and create Filament entities.
// Try parsing the glTF file to check the validity of the file format.
cgltf_options options{};
cgltf_data* sourceAsset;
cgltf_data* sourceAsset = nullptr;
cgltf_result result = cgltf_parse(&options, buffer.data(), contentSize, &sourceAsset);
cgltf_free(sourceAsset);
if (result != cgltf_result_success) {
slog.e << "Unable to parse glTF file." << io::endl;
return false;
+10
View File
@@ -181,6 +181,16 @@ vec3 fresnel(const vec3 f0, float LoH) {
#endif
}
vec3 fresnel(const vec3 f0, const float f90, float LoH) {
#if BRDF_SPECULAR_F == SPECULAR_F_SCHLICK
#if FILAMENT_QUALITY == FILAMENT_QUALITY_LOW
return F_Schlick(f0, LoH); // f90 = 1.0
#else
return F_Schlick(f0, f90, LoH);
#endif
#endif
}
float distributionAnisotropic(float at, float ab, float ToH, float BoH, float NoH) {
#if BRDF_ANISOTROPIC_D == SPECULAR_D_GGX_ANISOTROPIC
return D_GGX_Anisotropic(at, ab, ToH, BoH, NoH);
+5
View File
@@ -18,6 +18,11 @@ struct PixelParams {
float perceptualRoughness;
float perceptualRoughnessUnclamped;
vec3 f0;
#if defined(MATERIAL_HAS_SPECULAR_COLOR_FACTOR) || defined(MATERIAL_HAS_SPECULAR_FACTOR)
float f90;
float specular;
vec3 specularColor;
#endif
float roughness;
vec3 dfg;
vec3 energyCompensation;
+23 -19
View File
@@ -2,9 +2,6 @@
// Image based lighting configuration
//------------------------------------------------------------------------------
// Number of spherical harmonics bands (1, 2 or 3)
#define SPHERICAL_HARMONICS_BANDS 3
// IBL integration algorithm
#define IBL_INTEGRATION_PREFILTERED_CUBEMAP 0
#define IBL_INTEGRATION_IMPORTANCE_SAMPLING 1
@@ -44,21 +41,25 @@ vec3 prefilteredDFG(float perceptualRoughness, float NoV) {
//------------------------------------------------------------------------------
vec3 Irradiance_SphericalHarmonics(const vec3 n) {
return max(
frameUniforms.iblSH[0]
#if SPHERICAL_HARMONICS_BANDS >= 2
+ frameUniforms.iblSH[1] * (n.y)
+ frameUniforms.iblSH[2] * (n.z)
+ frameUniforms.iblSH[3] * (n.x)
#endif
#if SPHERICAL_HARMONICS_BANDS >= 3
+ frameUniforms.iblSH[4] * (n.y * n.x)
+ frameUniforms.iblSH[5] * (n.y * n.z)
+ frameUniforms.iblSH[6] * (3.0 * n.z * n.z - 1.0)
+ frameUniforms.iblSH[7] * (n.z * n.x)
+ frameUniforms.iblSH[8] * (n.x * n.x - n.y * n.y)
#endif
, 0.0);
vec3 sphericalHarmonics = frameUniforms.iblSH[0];
if (CONFIG_SH_BANDS_COUNT >= 2) {
sphericalHarmonics +=
frameUniforms.iblSH[1] * (n.y)
+ frameUniforms.iblSH[2] * (n.z)
+ frameUniforms.iblSH[3] * (n.x);
}
if (CONFIG_SH_BANDS_COUNT >= 3) {
sphericalHarmonics +=
frameUniforms.iblSH[4] * (n.y * n.x)
+ frameUniforms.iblSH[5] * (n.y * n.z)
+ frameUniforms.iblSH[6] * (3.0 * n.z * n.z - 1.0)
+ frameUniforms.iblSH[7] * (n.z * n.x)
+ frameUniforms.iblSH[8] * (n.x * n.x - n.y * n.y);
}
return max(sphericalHarmonics, 0.0);
}
vec3 Irradiance_RoughnessOne(const vec3 n) {
@@ -135,9 +136,13 @@ vec3 getSpecularDominantDirection(const vec3 n, const vec3 r, float roughness) {
vec3 specularDFG(const PixelParams pixel) {
#if defined(SHADING_MODEL_CLOTH)
return pixel.f0 * pixel.dfg.z;
#else
#if defined(MATERIAL_HAS_SPECULAR_COLOR_FACTOR) || defined(MATERIAL_HAS_SPECULAR_FACTOR)
return mix(pixel.dfg.xxx, pixel.dfg.yyy, pixel.f0) * pixel.specular;
#else
return mix(pixel.dfg.xxx, pixel.dfg.yyy, pixel.f0);
#endif
#endif
}
vec3 getReflectedVector(const PixelParams pixel, const vec3 n) {
@@ -662,7 +667,6 @@ void evaluateIBL(const MaterialInputs material, const PixelParams pixel, inout v
// Combine all terms
// Note: iblLuminance is already premultiplied by the exposure
color.rgb += Fr + Fd;
#if defined(MATERIAL_HAS_REFRACTION)
color.rgb += Ft;
+18
View File
@@ -89,6 +89,15 @@ struct MaterialInputs {
#endif
#endif
#endif
#if defined(MATERIAL_HAS_SPECULAR_FACTOR)
float specularFactor;
#endif
#if defined(MATERIAL_HAS_SPECULAR_COLOR_FACTOR)
vec3 specularColorFactor;
#endif
};
void initMaterial(out MaterialInputs material) {
@@ -177,6 +186,15 @@ void initMaterial(out MaterialInputs material) {
#endif
#endif
#endif
#if defined(MATERIAL_HAS_SPECULAR_FACTOR)
material.specularFactor = 1.0;
#endif
#if defined(MATERIAL_HAS_SPECULAR_COLOR_FACTOR)
material.specularColorFactor = vec3(1.0);
#endif
}
#if defined(MATERIAL_HAS_CUSTOM_SURFACE_SHADING)
+25
View File
@@ -75,7 +75,21 @@ void getCommonPixelParams(const MaterialInputs material, inout PixelParams pixel
// Assumes an interface from air to an IOR of 1.5 for dielectrics
float reflectance = computeDielectricF0(material.reflectance);
#endif
#if !defined(MATERIAL_HAS_SPECULAR_FACTOR) && !defined(MATERIAL_HAS_SPECULAR_COLOR_FACTOR)
pixel.f0 = computeF0(baseColor, material.metallic, reflectance);
#else
vec3 dielectricSpecularF0 = vec3(0.0);
float dielectricSpecularF90 = 0.0;
#if defined(MATERIAL_HAS_SPECULAR_COLOR_FACTOR)
dielectricSpecularF0 = min(reflectance * material.specularColorFactor, vec3(1.0));
#endif
#if defined(MATERIAL_HAS_SPECULAR_FACTOR)
dielectricSpecularF0 *= material.specularFactor;
dielectricSpecularF90 = material.specularFactor;
#endif
pixel.f0 = baseColor.rgb * material.metallic + dielectricSpecularF0 * (1.0 - material.metallic);
pixel.f90 = material.metallic + dielectricSpecularF90 * (1.0 - material.metallic);
#endif
#else
pixel.diffuseColor = baseColor.rgb;
pixel.f0 = material.sheenColor;
@@ -123,6 +137,16 @@ void getCommonPixelParams(const MaterialInputs material, inout PixelParams pixel
#endif
}
void getSpecularPixelParams(const MaterialInputs material, inout PixelParams pixel) {
#if defined(MATERIAL_HAS_SPECULAR_FACTOR)
pixel.specular = material.specularFactor;
#endif
#if defined(MATERIAL_HAS_SPECULAR_COLOR_FACTOR)
pixel.specularColor = material.specularColorFactor;
#endif
}
void getSheenPixelParams(const MaterialInputs material, inout PixelParams pixel) {
#if defined(MATERIAL_HAS_SHEEN_COLOR) && !defined(SHADING_MODEL_CLOTH) && !defined(SHADING_MODEL_SUBSURFACE)
pixel.sheenColor = material.sheenColor;
@@ -232,6 +256,7 @@ void getEnergyCompensationPixelParams(inout PixelParams pixel) {
* testing fails.
*/
void getPixelParams(const MaterialInputs material, out PixelParams pixel) {
getSpecularPixelParams(material, pixel);
getCommonPixelParams(material, pixel);
getSheenPixelParams(material, pixel);
getClearCoatPixelParams(material, pixel);
+4 -2
View File
@@ -63,8 +63,11 @@ vec3 isotropicLobe(const PixelParams pixel, const Light light, const vec3 h,
float D = distribution(pixel.roughness, NoH, h);
float V = visibility(pixel.roughness, NoV, NoL);
#if defined(MATERIAL_HAS_SPECULAR_COLOR_FACTOR) || defined(MATERIAL_HAS_SPECULAR_FACTOR)
vec3 F = fresnel(pixel.f0, pixel.f90, LoH);
#else
vec3 F = fresnel(pixel.f0, LoH);
#endif
return (D * V) * F;
}
@@ -144,7 +147,6 @@ vec3 surfaceShading(const PixelParams pixel, const Light light, float occlusion)
color += clearCoat;
#endif
#endif
return (color * light.colorIntensity.rgb) *
(light.colorIntensity.w * light.attenuation * NoL * occlusion);
}
+4
View File
@@ -388,6 +388,8 @@ class_<Engine>("Engine")
return Engine::create();
}, allow_raw_pointers())
.class_function("getSteadyClockTimeNano", &Engine::getSteadyClockTimeNano)
.function("unprotected", &Engine::unprotected)
.function("enableAccurateTranslations", &Engine::enableAccurateTranslations)
@@ -623,6 +625,8 @@ class_<Renderer>("Renderer")
}), allow_raw_pointers())
.function("_setClearOptions", &Renderer::setClearOptions, allow_raw_pointers())
.function("getClearOptions", &Renderer::getClearOptions)
.function("setPresentationTime", &Renderer::setPresentationTime)
.function("setVsyncTime", &Renderer::setVsyncTime)
.function("beginFrame", EMBIND_LAMBDA(bool, (Renderer* self, SwapChain* swapChain), {
return self->beginFrame(swapChain);
}), allow_raw_pointers())
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "filament",
"version": "1.53.0",
"version": "1.53.1",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",