diff --git a/android/src/main/kotlin/com/example/mimetic_avatar/MimeticAvatarPlugin.kt b/android/src/main/kotlin/com/example/mimetic_avatar/MimeticAvatarPlugin.kt deleted file mode 100644 index 22fe6be8..00000000 --- a/android/src/main/kotlin/com/example/mimetic_avatar/MimeticAvatarPlugin.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.example.holovox_filament - -import androidx.annotation.NonNull - -import io.flutter.embedding.engine.plugins.FlutterPlugin -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import io.flutter.plugin.common.MethodChannel.MethodCallHandler -import io.flutter.plugin.common.MethodChannel.Result - -/** MimeticAvatarPlugin */ -class MimeticAvatarPlugin: FlutterPlugin, MethodCallHandler { - /// The MethodChannel that will the communication between Flutter and native Android - /// - /// This local reference serves to register the plugin with the Flutter Engine and unregister it - /// when the Flutter Engine is detached from the Activity - private lateinit var channel : MethodChannel - - override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { - channel = MethodChannel(flutterPluginBinding.binaryMessenger, "holovox_filament") - channel.setMethodCallHandler(this) - } - - override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { - if (call.method == "getPlatformVersion") { - result.success("Android ${android.os.Build.VERSION.RELEASE}") - } else { - result.notImplemented() - } - } - - override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { - channel.setMethodCallHandler(null) - } -} diff --git a/android/src/main/kotlin/com/example/mimetic_filament/MimeticFilamentPlugin.kt b/android/src/main/kotlin/com/example/mimetic_filament/MimeticFilamentPlugin.kt deleted file mode 100644 index 5333bf9e..00000000 --- a/android/src/main/kotlin/com/example/mimetic_filament/MimeticFilamentPlugin.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.example.holovox_filament - -import androidx.annotation.NonNull - -import io.flutter.embedding.engine.plugins.FlutterPlugin -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import io.flutter.plugin.common.MethodChannel.MethodCallHandler -import io.flutter.plugin.common.MethodChannel.Result - -/** MimeticFilamentPlugin */ -class MimeticFilamentPlugin: FlutterPlugin, MethodCallHandler { - /// The MethodChannel that will the communication between Flutter and native Android - /// - /// This local reference serves to register the plugin with the Flutter Engine and unregister it - /// when the Flutter Engine is detached from the Activity - private lateinit var channel : MethodChannel - - override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { - channel = MethodChannel(flutterPluginBinding.binaryMessenger, "holovox_filament") - channel.setMethodCallHandler(this) - } - - override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { - if (call.method == "getPlatformVersion") { - result.success("Android ${android.os.Build.VERSION.RELEASE}") - } else { - result.notImplemented() - } - } - - override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { - channel.setMethodCallHandler(null) - } -} diff --git a/ios/Classes/HolovoxFilamentPlugin.h b/ios/Classes/HolovoxFilamentPlugin.h index 3df66ba2..357a20af 100644 --- a/ios/Classes/HolovoxFilamentPlugin.h +++ b/ios/Classes/HolovoxFilamentPlugin.h @@ -1,4 +1,4 @@ #import -@interface MimeticFilamentPlugin : NSObject +@interface HolovoxFilamentPlugin : NSObject @end diff --git a/ios/Classes/HolovoxFilamentPlugin.mm b/ios/Classes/HolovoxFilamentPlugin.mm index 916908de..bc16cfbf 100644 --- a/ios/Classes/HolovoxFilamentPlugin.mm +++ b/ios/Classes/HolovoxFilamentPlugin.mm @@ -1,9 +1,9 @@ -#import "MimeticFilamentPlugin.h" +#import "HolovoxFilamentPlugin.h" #import "filament/FilamentNativeViewFactory.h" FilamentNativeViewFactory* factory; -@implementation MimeticFilamentPlugin +@implementation HolovoxFilamentPlugin + (void)registerWithRegistrar:(NSObject*)registrar { factory = [[FilamentNativeViewFactory alloc] initWithRegistrar:registrar]; diff --git a/ios/Classes/filament/FilamentMethodCallHandler.mm b/ios/Classes/filament/FilamentMethodCallHandler.mm index 4c0eca84..8afb0049 100644 --- a/ios/Classes/filament/FilamentMethodCallHandler.mm +++ b/ios/Classes/filament/FilamentMethodCallHandler.mm @@ -43,20 +43,26 @@ static void* freeResourceGlobal(void* mem, size_t size, void* misc) { - (void)handleMethodCall:(FlutterMethodCall* _Nonnull)call result:(FlutterResult _Nonnull )result { if([@"initialize" isEqualToString:call.method]) { if(!call.arguments) - _viewer = new holovox::FilamentViewer(_layer, nullptr, loadResourceGlobal, freeResourceGlobal); + _viewer = new holovox::FilamentViewer(_layer, nullptr, nullptr, loadResourceGlobal, freeResourceGlobal); else - _viewer = new holovox::FilamentViewer(_layer, [call.arguments UTF8String], loadResourceGlobal, freeResourceGlobal); + _viewer = new holovox::FilamentViewer(_layer, [call.arguments[0] UTF8String], [call.arguments[1] UTF8String], loadResourceGlobal, freeResourceGlobal); [_controller setViewer:_viewer]; [_controller startDisplayLink]; result(@"OK"); } else if([@"loadSkybox" isEqualToString:call.method]) { if(!_viewer) return; + _viewer->loadSkybox([call.arguments[0] UTF8String], [call.arguments[1] UTF8String]); result(@"OK"); + } else if([@"loadGlb" isEqualToString:call.method]) { + if(!_viewer) + return; // TODO should throw exception here + _viewer->loadGlb([call.arguments UTF8String]); + result(@"OK"); } else if([@"loadGltf" isEqualToString:call.method]) { if(!_viewer) - return; + return; // TODO should throw exception here _viewer->loadGltf([call.arguments[0] UTF8String], [call.arguments[1] UTF8String]); result(@"OK"); } else if([@"panStart" isEqualToString:call.method]) { diff --git a/ios/holovox_filament.podspec b/ios/holovox_filament.podspec index 496fbf4a..3ea668ff 100644 --- a/ios/holovox_filament.podspec +++ b/ios/holovox_filament.podspec @@ -13,11 +13,12 @@ A new flutter plugin project. s.license = { :file => '../LICENSE' } s.author = { 'Your Company' => 'email@example.com' } s.source = { :path => '.' } - s.source_files = 'Classes/**/*', 'src/*.*', 'src/morph/*' - s.dependency 'Filament', '~> 1.12.4' + s.source_files = 'Classes/**/*', 'src/*.*', 'src/morph/*.*', 'src/morph/UbershaderLoader.cpp' + #s.dependency 'Filament', '~> 1.12.8' s.dependency 'Flutter' s.platform = :ios, '12.1' s.static_framework = true + s.vendored_libraries = "lib/*.a" # Flutter.framework does not contain a i386 slice. s.user_target_xcconfig = { @@ -26,6 +27,7 @@ A new flutter plugin project. 'USER_HEADER_SEARCH_PATHS' => '"${PODS_ROOT}/../.symlinks/plugins/holovox_filament/ios/include" "${PODS_ROOT}/../.symlinks/plugins/holovox_filament/ios/src", "${PODS_ROOT}/../.symlinks/plugins/holovox_filament/ios/morph"', 'OTHER_CXXFLAGS' => '--std=c++17 -fmodules -fcxx-modules', "CLANG_CXX_LANGUAGE_STANDARD" => "c++17", + 'LIBRARY_SEARCH_PATHS' => '"${PODS_ROOT}/../.symlinks/plugins/holovox_filament/ios/lib"', #"CLANG_CXX_LIBRARY" => "libc++" } s.pod_target_xcconfig = { @@ -33,8 +35,11 @@ A new flutter plugin project. 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386', "CLANG_CXX_LANGUAGE_STANDARD" => "c++17", 'OTHER_CXXFLAGS' => '--std=c++17 -fmodules -fcxx-modules', + "OTHER_LDFLAGS" => '-lfilament -lbackend -lmathio -lfilameshio -lviewer -lfilamat -lgeometry -lutils -lfilabridge -lgltfio_resources_lite -lgltfio_core -lfilament-iblprefilter -limage -lcamutils -lgltfio_resources -lmath -lfilaflat -ldracodec -libl', 'USER_HEADER_SEARCH_PATHS' => '"${PODS_ROOT}/../.symlinks/plugins/holovox_filament/ios/include" "${PODS_ROOT}/../.symlinks/plugins/holovox_filament/ios/src", "${PODS_ROOT}/../.symlinks/plugins/holovox_filament/ios/morph"', 'ALWAYS_SEARCH_USER_PATHS' => 'YES', + 'LIBRARY_SEARCH_PATHS' => '"${PODS_ROOT}/../.symlinks/plugins/holovox_filament/ios/lib"', } + s.swift_version = '5.0' end diff --git a/ios/include/backend/BufferDescriptor.h b/ios/include/backend/BufferDescriptor.h index f6c7c69b..8e72eaed 100644 --- a/ios/include/backend/BufferDescriptor.h +++ b/ios/include/backend/BufferDescriptor.h @@ -16,16 +16,16 @@ //! \file -#ifndef TNT_FILAMENT_DRIVER_BUFFERDESCRIPTOR_H -#define TNT_FILAMENT_DRIVER_BUFFERDESCRIPTOR_H +#ifndef TNT_FILAMENT_BACKEND_BUFFERDESCRIPTOR_H +#define TNT_FILAMENT_BACKEND_BUFFERDESCRIPTOR_H #include +#include #include #include -namespace filament { -namespace backend { +namespace filament::backend { /** * A CPU memory-buffer descriptor, typically used to transfer data from the CPU to the GPU. @@ -91,6 +91,56 @@ public: : buffer(const_cast(buffer)), size(size), callback(callback), user(user) { } + // -------------------------------------------------------------------------------------------- + + /** + * Helper to create a BufferDescriptor that uses a KNOWN method pointer w/ object passed + * by pointer as the callback. e.g.: + * auto bd = BufferDescriptor::make(buffer, size, &Foo::method, foo); + * + * @param buffer Memory address of the CPU buffer to reference + * @param size Size of the CPU buffer in bytes + * @return a new BufferDescriptor + */ + template + static BufferDescriptor make( + void const* buffer, size_t size, T* data) noexcept { + return { + buffer, size, + [](void* b, size_t s, void* u) { + (*static_cast(u)->*method)(b, s); + }, data + }; + } + + /** + * Helper to create a BufferDescriptor that uses a functor as the callback. + * + * Caveats: + * - DO NOT CALL setCallback() when using this helper. + * - This make a heap allocation + * + * @param buffer Memory address of the CPU buffer to reference + * @param size Size of the CPU buffer in bytes + * @param functor functor of type f(void const* buffer, size_t size) + * @return a new BufferDescriptor + */ + template + static BufferDescriptor make( + void const* buffer, size_t size, T&& functor) noexcept { + return { + buffer, size, + [](void* b, size_t s, void* u) { + T& that = *static_cast(u); + that(b, s); + delete &that; + }, + new T(std::forward(functor)) + }; + } + + // -------------------------------------------------------------------------------------------- + /** * Set or replace the release callback function * @param callback The new callback function @@ -126,7 +176,10 @@ private: void* user = nullptr; }; -} // namespace backend -} // namespace filament +} // namespace filament::backend -#endif // TNT_FILAMENT_DRIVER_BUFFERDESCRIPTOR_H +#if !defined(NDEBUG) +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::BufferDescriptor& b); +#endif + +#endif // TNT_FILAMENT_BACKEND_BUFFERDESCRIPTOR_H diff --git a/ios/include/backend/DriverEnums.h b/ios/include/backend/DriverEnums.h index 0be3b219..97cb3a08 100644 --- a/ios/include/backend/DriverEnums.h +++ b/ios/include/backend/DriverEnums.h @@ -16,14 +16,16 @@ //! \file -#ifndef TNT_FILAMENT_DRIVER_DRIVERENUMS_H -#define TNT_FILAMENT_DRIVER_DRIVERENUMS_H +#ifndef TNT_FILAMENT_BACKEND_DRIVERENUMS_H +#define TNT_FILAMENT_BACKEND_DRIVERENUMS_H #include #include // Because we define ERROR in the FenceStatus enum. #include +#include + #include #include // FIXME: STL headers are not allowed in public headers @@ -318,7 +320,7 @@ enum class PixelDataType : uint8_t { BYTE, //!< signed byte USHORT, //!< unsigned short (16-bit) SHORT, //!< signed short (16-bit) - UINT, //!< unsigned int (16-bit) + UINT, //!< unsigned int (32-bit) INT, //!< signed int (32-bit) HALF, //!< half-float (16-bit float) FLOAT, //!< float (32-bits float) @@ -561,6 +563,48 @@ static constexpr bool isDepthFormat(TextureFormat format) noexcept { } } +static constexpr bool isUnsignedIntFormat(TextureFormat format) { + switch (format) { + case TextureFormat::R8UI: + case TextureFormat::R16UI: + case TextureFormat::R32UI: + case TextureFormat::RG8UI: + case TextureFormat::RG16UI: + case TextureFormat::RG32UI: + case TextureFormat::RGB8UI: + case TextureFormat::RGB16UI: + case TextureFormat::RGB32UI: + case TextureFormat::RGBA8UI: + case TextureFormat::RGBA16UI: + case TextureFormat::RGBA32UI: + return true; + + default: + return false; + } +} + +static constexpr bool isSignedIntFormat(TextureFormat format) { + switch (format) { + case TextureFormat::R8I: + case TextureFormat::R16I: + case TextureFormat::R32I: + case TextureFormat::RG8I: + case TextureFormat::RG16I: + case TextureFormat::RG32I: + case TextureFormat::RGB8I: + case TextureFormat::RGB16I: + case TextureFormat::RGB32I: + case TextureFormat::RGBA8I: + case TextureFormat::RGBA16I: + case TextureFormat::RGBA32I: + return true; + + default: + return false; + } +} + //! returns whether this format a compressed format static constexpr bool isCompressedFormat(TextureFormat format) noexcept { return format >= TextureFormat::EAC_R11; @@ -917,6 +961,9 @@ using FrameScheduledCallback = void(*)(PresentCallable callable, void* user); using FrameCompletedCallback = void(*)(void* user); +enum class Workaround : uint16_t { + SPLIT_EASU +}; } // namespace backend } // namespace filament @@ -926,4 +973,36 @@ template<> struct utils::EnableBitMaskOperators struct utils::EnableBitMaskOperators : public std::true_type {}; -#endif // TNT_FILAMENT_DRIVER_DRIVERENUMS_H + +#if !defined(NDEBUG) +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::BufferUsage usage); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::CullingMode mode); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::ElementType type); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::PixelDataFormat format); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::PixelDataType type); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::Precision precision); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::PrimitiveType type); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::TargetBufferFlags f); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerCompareFunc func); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerCompareMode mode); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerFormat format); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerMagFilter filter); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerMinFilter filter); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerParams params); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerType type); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::SamplerWrapMode wrap); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::ShaderModel model); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::TextureCubemapFace face); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::TextureFormat format); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::TextureUsage usage); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::BufferObjectBinding binding); +utils::io::ostream& operator<<(utils::io::ostream& out, filament::backend::TextureSwizzle swizzle); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::AttributeArray& type); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::FaceOffsets& type); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::PolygonOffset& po); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::RasterState& rs); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::RenderPassParams& b); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::Viewport& v); +#endif + +#endif // TNT_FILAMENT_BACKEND_DRIVERENUMS_H diff --git a/ios/include/backend/Handle.h b/ios/include/backend/Handle.h index e7737ed5..8dd8ed6f 100644 --- a/ios/include/backend/Handle.h +++ b/ios/include/backend/Handle.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef TNT_FILAMENT_DRIVER_HANDLE_H -#define TNT_FILAMENT_DRIVER_HANDLE_H +#ifndef TNT_FILAMENT_BACKEND_HANDLE_H +#define TNT_FILAMENT_BACKEND_HANDLE_H #include #include @@ -113,4 +113,4 @@ using VertexBufferHandle = Handle; } // namespace backend } // namespace filament -#endif // TNT_FILAMENT_DRIVER_HANDLE_H +#endif // TNT_FILAMENT_BACKEND_HANDLE_H diff --git a/ios/include/backend/PipelineState.h b/ios/include/backend/PipelineState.h index a3bac43a..6238988e 100644 --- a/ios/include/backend/PipelineState.h +++ b/ios/include/backend/PipelineState.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef TNT_FILAMENT_DRIVER_PIPELINESTATE_H -#define TNT_FILAMENT_DRIVER_PIPELINESTATE_H +#ifndef TNT_FILAMENT_BACKEND_PIPELINESTATE_H +#define TNT_FILAMENT_BACKEND_PIPELINESTATE_H #include #include @@ -24,8 +24,7 @@ #include -namespace filament { -namespace backend { +namespace filament::backend { //! \privatesection @@ -39,8 +38,10 @@ struct PipelineState { }; }; +} // namespace filament::backend -} // namespace backend -} // namespace filament +#if !defined(NDEBUG) +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::PipelineState& ps); +#endif -#endif //TNT_FILAMENT_DRIVER_PIPELINESTATE_H +#endif //TNT_FILAMENT_BACKEND_PIPELINESTATE_H diff --git a/ios/include/backend/PixelBufferDescriptor.h b/ios/include/backend/PixelBufferDescriptor.h index 327f49a4..69678d06 100644 --- a/ios/include/backend/PixelBufferDescriptor.h +++ b/ios/include/backend/PixelBufferDescriptor.h @@ -16,8 +16,8 @@ //! \file -#ifndef TNT_FILAMENT_DRIVER_PIXEL_BUFFERDESCRIPTOR_H -#define TNT_FILAMENT_DRIVER_PIXEL_BUFFERDESCRIPTOR_H +#ifndef TNT_FILAMENT_BACKEND_PIXELBUFFERDESCRIPTOR_H +#define TNT_FILAMENT_BACKEND_PIXELBUFFERDESCRIPTOR_H #include #include @@ -105,6 +105,71 @@ public: alignment(1) { } + // -------------------------------------------------------------------------------------------- + + template + static PixelBufferDescriptor make(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, uint8_t alignment, + uint32_t left, uint32_t top, uint32_t stride, T* data) noexcept { + return { buffer, size, format, type, alignment, left, top, stride, + [](void* b, size_t s, void* u) { + (*static_cast(u)->*method)(b, s); }, data }; + } + + template + static PixelBufferDescriptor make(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, T* data) noexcept { + return { buffer, size, format, type, [](void* b, size_t s, void* u) { + (*static_cast(u)->*method)(b, s); }, data }; + } + + template + static PixelBufferDescriptor make(void const* buffer, size_t size, + backend::CompressedPixelDataType format, uint32_t imageSize, T* data) noexcept { + return { buffer, size, format, imageSize, [](void* b, size_t s, void* u) { + (*static_cast(u)->*method)(b, s); }, data + }; + } + + template + static PixelBufferDescriptor make(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, uint8_t alignment, + uint32_t left, uint32_t top, uint32_t stride, T&& functor) noexcept { + return { buffer, size, format, type, alignment, left, top, stride, + [](void* b, size_t s, void* u) { + T& that = *static_cast(u); + that(b, s); + delete &that; + }, new T(std::forward(functor)) + }; + } + + template + static PixelBufferDescriptor make(void const* buffer, size_t size, + PixelDataFormat format, PixelDataType type, T&& functor) noexcept { + return { buffer, size, format, type, + [](void* b, size_t s, void* u) { + T& that = *static_cast(u); + that(b, s); + delete &that; + }, new T(std::forward(functor)) + }; + } + + template + static PixelBufferDescriptor make(void const* buffer, size_t size, + backend::CompressedPixelDataType format, uint32_t imageSize, T&& functor) noexcept { + return { buffer, size, format, imageSize, + [](void* b, size_t s, void* u) { + T& that = *static_cast(u); + that(b, s); + delete &that; + }, new T(std::forward(functor)) + }; + } + + // -------------------------------------------------------------------------------------------- + /** * Computes the size in bytes needed to fit an image of given dimensions and format * @@ -213,4 +278,8 @@ public: } // namespace backend } // namespace filament -#endif // TNT_FILAMENT_DRIVER_PIXEL_BUFFERDESCRIPTOR_H +#if !defined(NDEBUG) +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::PixelBufferDescriptor& b); +#endif + +#endif // TNT_FILAMENT_BACKEND_PIXELBUFFERDESCRIPTOR_H diff --git a/ios/include/backend/Platform.h b/ios/include/backend/Platform.h index b667dbb0..26ba709f 100644 --- a/ios/include/backend/Platform.h +++ b/ios/include/backend/Platform.h @@ -16,8 +16,8 @@ //! \file -#ifndef TNT_FILAMENT_DRIVER_PLATFORM_H -#define TNT_FILAMENT_DRIVER_PLATFORM_H +#ifndef TNT_FILAMENT_BACKEND_PLATFORM_H +#define TNT_FILAMENT_BACKEND_PLATFORM_H #include @@ -100,4 +100,4 @@ public: } // namespace backend } // namespace filament -#endif // TNT_FILAMENT_DRIVER_PLATFORM_H +#endif // TNT_FILAMENT_BACKEND_PLATFORM_H diff --git a/ios/include/backend/PresentCallable.h b/ios/include/backend/PresentCallable.h index 5a12e686..26579420 100644 --- a/ios/include/backend/PresentCallable.h +++ b/ios/include/backend/PresentCallable.h @@ -16,8 +16,8 @@ //! \file -#ifndef TNT_FILAMENT_BACKEND_PRESENT_CALLABLE -#define TNT_FILAMENT_BACKEND_PRESENT_CALLABLE +#ifndef TNT_FILAMENT_BACKEND_PRESENTCALLABLE +#define TNT_FILAMENT_BACKEND_PRESENTCALLABLE #include @@ -101,4 +101,4 @@ using FrameFinishedCallback UTILS_DEPRECATED = void(*)(PresentCallable callable, } // namespace backend } // namespace filament -#endif // TNT_FILAMENT_BACKEND_PRESENT_FRAME_CALLABLE +#endif // TNT_FILAMENT_BACKEND_PRESENTCALLABLE diff --git a/ios/include/backend/TargetBufferInfo.h b/ios/include/backend/TargetBufferInfo.h index 3c505d06..c43df551 100644 --- a/ios/include/backend/TargetBufferInfo.h +++ b/ios/include/backend/TargetBufferInfo.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef TNT_FILAMENT_DRIVER_TARGETBUFFERINFO_H -#define TNT_FILAMENT_DRIVER_TARGETBUFFERINFO_H +#ifndef TNT_FILAMENT_BACKEND_TARGETBUFFERINFO_H +#define TNT_FILAMENT_BACKEND_TARGETBUFFERINFO_H #include #include @@ -104,4 +104,9 @@ public: } // namespace backend } // namespace filament -#endif //TNT_FILAMENT_DRIVER_TARGETBUFFERINFO_H +#if !defined(NDEBUG) +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::TargetBufferInfo& tbi); +utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::MRT& mrt); +#endif + +#endif //TNT_FILAMENT_BACKEND_TARGETBUFFERINFO_H diff --git a/ios/include/filament/Camera.h b/ios/include/filament/Camera.h index f0574020..a4597156 100644 --- a/ios/include/filament/Camera.h +++ b/ios/include/filament/Camera.h @@ -383,7 +383,7 @@ public: //! Returns the camera's field of view in degrees float getFieldOfViewInDegrees(Fov direction) const noexcept; - //! Returns a Frustum object in world space + //! Returns the camera's culling Frustum in world space class Frustum getFrustum() const noexcept; //! Returns the entity representing this camera diff --git a/ios/include/filament/ColorGrading.h b/ios/include/filament/ColorGrading.h index be25267b..101efa3e 100644 --- a/ios/include/filament/ColorGrading.h +++ b/ios/include/filament/ColorGrading.h @@ -16,8 +16,8 @@ //! \file -#ifndef TNT_FILAMENT_COLOR_GRADING_H -#define TNT_FILAMENT_COLOR_GRADING_H +#ifndef TNT_FILAMENT_COLORGRADING_H +#define TNT_FILAMENT_COLORGRADING_H #include #include @@ -66,6 +66,7 @@ class FColorGrading; * * The various transforms held by ColorGrading are applied in the following order: * - Exposure + * - Night adaptation * - White balance * - Channel mixer * - Shadows/mid-tones/highlights @@ -76,12 +77,14 @@ class FColorGrading; * - Curves * - Tone mapping * - Luminance scaling + * - Gamut mapping * * Defaults * ======== * * Here are the default color grading options: * - Exposure: 0.0 + * - Night adaptation: 0.0 * - White balance: temperature 0, and tint 0 * - Channel mixer: red {1,0,0}, green {0,1,0}, blue {0,0,1} * - Shadows/mid-tones/highlights: shadows {1,1,1,0}, mid-tones {1,1,1,0}, highlights {1,1,1,0}, @@ -93,6 +96,7 @@ class FColorGrading; * - Curves: gamma {1,1,1}, midPoint {1,1,1}, and scale {1,1,1} * - Tone mapping: ACESLegacyToneMapper * - Luminance scaling: false + * - Gamut mapping: false * * @see View */ @@ -186,12 +190,25 @@ public: * When luminance scaling is enabled, tone mapping is performed on the luminance of each * pixel instead of per-channel. * - * @param luminanceScaling Enables or disables EVILS post-tone mapping + * @param luminanceScaling Enables or disables luminance scaling post-tone mapping * * @return This Builder, for chaining calls */ Builder& luminanceScaling(bool luminanceScaling) noexcept; + /** + * Enables or disables gamut mapping to the destination color space's gamut. When gamut + * mapping is turned off, out-of-gamut colors are clipped to the destination's gamut, + * which may produce hue skews (blue skewing to purple, green to yellow, etc.). When + * gamut mapping is enabled, out-of-gamut colors are brought back in gamut by trying to + * preserve the perceived chroma and lightness of the original values. + * + * @param gamutMapping Enables or disables gamut mapping + * + * @return This Builder, for chaining calls + */ + Builder& gamutMapping(bool gamutMapping) noexcept; + /** * Adjusts the exposure of this image. The exposure is specified in stops: * each stop brightens (positive values) or darkens (negative values) the image by @@ -205,6 +222,19 @@ public: */ Builder& exposure(float exposure) noexcept; + /** + * Controls the amount of night adaptation to replicate a more natural representation of + * low-light conditions as perceived by the human vision system. In low-light conditions, + * peak luminance sensitivity of the eye shifts toward the blue end of the color spectrum: + * darker tones appear brighter, reducing contrast, and colors are blue shifted (the darker + * the more intense the effect). + * + * @param adaptation Amount of adaptation, between 0 (no adaptation) and 1 (full adaptation). + * + * @return This Builder, for chaining calls + */ + Builder& nightAdaptation(float adaptation) noexcept; + /** * Adjusts the while balance of the image. This can be used to remove color casts * and correct the appearance of the white point in the scene, or to alter the @@ -402,4 +432,4 @@ public: } // namespace filament -#endif // TNT_FILAMENT_COLOR_GRADING_H +#endif // TNT_FILAMENT_COLORGRADING_H diff --git a/ios/include/filament/DebugRegistry.h b/ios/include/filament/DebugRegistry.h index 018df14d..a7a9e804 100644 --- a/ios/include/filament/DebugRegistry.h +++ b/ios/include/filament/DebugRegistry.h @@ -16,8 +16,8 @@ //! \file -#ifndef TNT_FILAMENT_DEBUG_H -#define TNT_FILAMENT_DEBUG_H +#ifndef TNT_FILAMENT_DEBUGREGISTRY_H +#define TNT_FILAMENT_DEBUGREGISTRY_H #include @@ -128,4 +128,4 @@ public: } // namespace filament -#endif /* TNT_FILAMENT_DEBUG_H */ +#endif /* TNT_FILAMENT_DEBUGREGISTRY_H */ diff --git a/ios/include/filament/Engine.h b/ios/include/filament/Engine.h index d69d7364..3e32de68 100644 --- a/ios/include/filament/Engine.h +++ b/ios/include/filament/Engine.h @@ -444,7 +444,7 @@ public: /** * Kicks the hardware thread (e.g. the OpenGL, Vulkan or Metal thread) and blocks until - * all commands to this point are executed. Note that this doesn't guarantee that the + * all commands to this point are executed. Note that does guarantee that the * hardware is actually finished. * *

This is typically used right after destroying the SwapChain, @@ -454,8 +454,25 @@ public: */ void flushAndWait(); + /** + * Kicks the hardware thread (e.g. the OpenGL, Vulkan or Metal thread) but does not wait + * for commands to be either executed or the hardware finished. + * + *

This is typically used after creating a lot of objects to start draining the command + * queue which has a limited size.

+ */ void flush(); + /** + * Drains the user callback message queue and immediately execute all pending callbacks. + * + *

Typically this should be called once per frame right after the application's vsync tick, + * and typically just before computing parameters (e.g. object positions) for the next frame. + * This is useful because otherwise callbacks will be executed by filament at a later time, + * which may increase latency in certain applications.

+ */ + void pumpMessageQueues(); + /** * Returns the default Material. * diff --git a/ios/include/filament/FilamentAPI.h b/ios/include/filament/FilamentAPI.h index 8b89a8c3..e0f35cab 100644 --- a/ios/include/filament/FilamentAPI.h +++ b/ios/include/filament/FilamentAPI.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef TNT_FILAMENT_FILAMENT_API_H -#define TNT_FILAMENT_FILAMENT_API_H +#ifndef TNT_FILAMENT_FILAMENTAPI_H +#define TNT_FILAMENT_FILAMENTAPI_H #include @@ -88,4 +88,4 @@ protected: } // namespace filament -#endif // TNT_FILAMENT_FILAMENT_API_H +#endif // TNT_FILAMENT_FILAMENTAPI_H diff --git a/ios/include/filament/Frustum.h b/ios/include/filament/Frustum.h index 3ab31d0e..5d496e57 100644 --- a/ios/include/filament/Frustum.h +++ b/ios/include/filament/Frustum.h @@ -52,8 +52,9 @@ public: Frustum& operator=(Frustum&& rhs) noexcept = default; /** - * Creates a frustum from a projection matrix (usually the projection * view matrix) - * @param pv a 4x4 projection matrix + * Creates a frustum from a projection matrix in GL convention + * (usually the projection * view matrix) + * @param pv a 4x4 projection matrix in GL convention */ explicit Frustum(const math::mat4f& pv); diff --git a/ios/include/filament/IndirectLight.h b/ios/include/filament/IndirectLight.h index 166dcc2b..2ddc148f 100644 --- a/ios/include/filament/IndirectLight.h +++ b/ios/include/filament/IndirectLight.h @@ -16,8 +16,8 @@ //! \file -#ifndef TNT_FILAMENT_INDIRECT_LIGHT_H -#define TNT_FILAMENT_INDIRECT_LIGHT_H +#ifndef TNT_FILAMENT_INDIRECTLIGHT_H +#define TNT_FILAMENT_INDIRECTLIGHT_H #include @@ -346,4 +346,4 @@ public: } // namespace filament -#endif // TNT_FILAMENT_INDIRECT_LIGHT_H +#endif // TNT_FILAMENT_INDIRECTLIGHT_H diff --git a/ios/include/filament/MaterialInstance.h b/ios/include/filament/MaterialInstance.h index 98b52681..fee1ca0d 100644 --- a/ios/include/filament/MaterialInstance.h +++ b/ios/include/filament/MaterialInstance.h @@ -20,6 +20,8 @@ #include #include +#include + #include #include @@ -37,6 +39,7 @@ class UniformInterfaceBlock; class UTILS_PUBLIC MaterialInstance : public FilamentAPI { public: using CullingMode = filament::backend::CullingMode; + using TransparencyMode = filament::TransparencyMode; template using is_supported_parameter_t = typename std::enable_if< @@ -197,6 +200,11 @@ public: */ void setDoubleSided(bool doubleSided) noexcept; + /** + * Specifies how transparent objects should be rendered (default is DEFAULT). + */ + void setTransparencyMode(TransparencyMode mode) noexcept; + /** * Overrides the default triangle culling state that was set on the material. */ diff --git a/ios/include/filament/Options.h b/ios/include/filament/Options.h new file mode 100644 index 00000000..fd9a58a1 --- /dev/null +++ b/ios/include/filament/Options.h @@ -0,0 +1,362 @@ +/* + * 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_OPTIONS_H +#define TNT_FILAMENT_OPTIONS_H + +#include + +#include + +namespace filament { + +class Texture; + +enum class QualityLevel : uint8_t { + LOW, + MEDIUM, + HIGH, + ULTRA +}; + +enum class BlendMode : uint8_t { + OPAQUE, + TRANSLUCENT +}; + +/** + * Dynamic resolution can be used to either reach a desired target frame rate + * by lowering the resolution of a View, or to increase the quality when the + * rendering is faster than the target frame rate. + * + * This structure can be used to specify the minimum scale factor used when + * lowering the resolution of a View, and the maximum scale factor used when + * increasing the resolution for higher quality rendering. The scale factors + * can be controlled on each X and Y axis independently. By default, all scale + * factors are set to 1.0. + * + * enabled: enable or disables dynamic resolution on a View + * + * homogeneousScaling: by default the system scales the major axis first. Set this to true + * to force homogeneous scaling. + * + * minScale: the minimum scale in X and Y this View should use + * + * maxScale: the maximum scale in X and Y this View should use + * + * quality: upscaling quality. + * LOW: 1 bilinear tap, Medium: 4 bilinear taps, High: 9 bilinear taps (tent) + * + * \note + * Dynamic resolution is only supported on platforms where the time to render + * a frame can be measured accurately. Dynamic resolution is currently only + * supported on Android. + * + * @see Renderer::FrameRateOptions + * + */ +struct DynamicResolutionOptions { + math::float2 minScale = math::float2(0.5f); //!< minimum scale factors in x and y + math::float2 maxScale = math::float2(1.0f); //!< maximum scale factors in x and y + float sharpness = 0.9f; //!< sharpness when QualityLevel::MEDIUM or higher is used [0 (disabled), 1 (sharpest)] + bool enabled = false; //!< enable or disable dynamic resolution + bool homogeneousScaling = false; //!< set to true to force homogeneous scaling + + /** + * Upscaling quality + * LOW: bilinear filtered blit. Fastest, poor quality + * MEDIUM: AMD FidelityFX FSR1 w/ mobile optimizations + * HIGH: AMD FidelityFX FSR1 w/ mobile optimizations + * ULTRA: AMD FidelityFX FSR1 + * FSR1 require a well anti-aliased (MSAA or TAA), noise free scene. + * + * The default upscaling quality is set to LOW. + */ + QualityLevel quality = QualityLevel::LOW; +}; + +/** + * Options to control the bloom effect + * + * enabled: Enable or disable the bloom post-processing effect. Disabled by default. + * + * levels: Number of successive blurs to achieve the blur effect, the minimum is 3 and the + * maximum is 12. This value together with resolution influences the spread of the + * blur effect. This value can be silently reduced to accommodate the original + * image size. + * + * resolution: Resolution of bloom's minor axis. The minimum value is 2^levels and the + * the maximum is lower of the original resolution and 4096. This parameter is + * silently clamped to the minimum and maximum. + * It is highly recommended that this value be smaller than the target resolution + * after dynamic resolution is applied (horizontally and vertically). + * + * strength: how much of the bloom is added to the original image. Between 0 and 1. + * + * blendMode: Whether the bloom effect is purely additive (false) or mixed with the original + * image (true). + * + * anamorphism: Bloom's aspect ratio (x/y), for artistic purposes. + * + * threshold: When enabled, a threshold at 1.0 is applied on the source image, this is + * useful for artistic reasons and is usually needed when a dirt texture is used. + * + * dirt: A dirt/scratch/smudges texture (that can be RGB), which gets added to the + * bloom effect. Smudges are visible where bloom occurs. Threshold must be + * enabled for the dirt effect to work properly. + * + * dirtStrength: Strength of the dirt texture. + */ +struct BloomOptions { + enum class BlendMode : uint8_t { + ADD, //!< Bloom is modulated by the strength parameter and added to the scene + INTERPOLATE //!< Bloom is interpolated with the scene using the strength parameter + }; + Texture* dirt = nullptr; //!< user provided dirt texture + float dirtStrength = 0.2f; //!< strength of the dirt texture + float strength = 0.10f; //!< bloom's strength between 0.0 and 1.0 + uint32_t resolution = 360; //!< resolution of vertical axis (2^levels to 2048) + float anamorphism = 1.0f; //!< bloom x/y aspect-ratio (1/32 to 32) + uint8_t levels = 6; //!< number of blur levels (3 to 11) + BlendMode blendMode = BlendMode::ADD; //!< how the bloom effect is applied + bool threshold = true; //!< whether to threshold the source + bool enabled = false; //!< enable or disable bloom + float highlight = 1000.0f; //!< limit highlights to this value before bloom [10, +inf] + + bool lensFlare = false; //!< enable screen-space lens flare + bool starburst = true; //!< enable starburst effect on lens flare + float chromaticAberration = 0.005f; //!< amount of chromatic aberration + uint8_t ghostCount = 4; //!< number of flare "ghosts" + float ghostSpacing = 0.6f; //!< spacing of the ghost in screen units [0, 1[ + float ghostThreshold = 10.0f; //!< hdr threshold for the ghosts + float haloThickness = 0.1f; //!< thickness of halo in vertical screen units, 0 to disable + float haloRadius = 0.4f; //!< radius of halo in vertical screen units [0, 0.5] + float haloThreshold = 10.0f; //!< hdr threshold for the halo +}; + +/** + * Options to control fog in the scene + */ +struct FogOptions { + float distance = 0.0f; //!< distance in world units from the camera where the fog starts ( >= 0.0 ) + float maximumOpacity = 1.0f; //!< fog's maximum opacity between 0 and 1 + float height = 0.0f; //!< fog's floor in world units + float heightFalloff = 1.0f; //!< how fast fog dissipates with altitude + LinearColor color{0.5f}; //!< fog's color (linear), see fogColorFromIbl + float density = 0.1f; //!< fog's density at altitude given by 'height' + float inScatteringStart = 0.0f; //!< distance in world units from the camera where in-scattering starts + float inScatteringSize = -1.0f; //!< size of in-scattering (>0 to activate). Good values are >> 1 (e.g. ~10 - 100). + bool fogColorFromIbl = false; //!< Fog color will be modulated by the IBL color in the view direction. + bool enabled = false; //!< enable or disable fog +}; + +/** + * Options to control Depth of Field (DoF) effect in the scene. + * + * cocScale can be used to set the depth of field blur independently from the camera + * aperture, e.g. for artistic reasons. This can be achieved by setting: + * cocScale = cameraAperture / desiredDoFAperture + * + * @see Camera + */ +struct DepthOfFieldOptions { + enum class Filter : uint8_t { + NONE = 0, + MEDIAN = 2 + }; + float cocScale = 1.0f; //!< circle of confusion scale factor (amount of blur) + 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; +}; + +/** + * Options to control the vignetting effect. + */ +struct VignetteOptions { + float midPoint = 0.5f; //!< high values restrict the vignette closer to the corners, between 0 and 1 + float roundness = 0.5f; //!< controls the shape of the vignette, from a rounded rectangle (0.0), to an oval (0.5), to a circle (1.0) + float feather = 0.5f; //!< softening amount of the vignette effect, between 0 and 1 + LinearColorA color{0.0f, 0.0f, 0.0f, 1.0f}; //!< color of the vignette effect, alpha is currently ignored + bool enabled = false; //!< enables or disables the vignette effect +}; + +/** + * Structure used to set the precision of the color buffer and related quality settings. + * + * @see setRenderQuality, getRenderQuality + */ +struct RenderQuality { + /** + * Sets the quality of the HDR color buffer. + * + * A quality of HIGH or ULTRA means using an RGB16F or RGBA16F color buffer. This means + * colors in the LDR range (0..1) have a 10 bit precision. A quality of LOW or MEDIUM means + * using an R11G11B10F opaque color buffer or an RGBA16F transparent color buffer. With + * R11G11B10F colors in the LDR range have a precision of either 6 bits (red and green + * channels) or 5 bits (blue channel). + */ + QualityLevel hdrColorBuffer = QualityLevel::HIGH; +}; + +/** + * Options for screen space Ambient Occlusion (SSAO) and Screen Space Cone Tracing (SSCT) + * @see setAmbientOcclusionOptions() + */ +struct AmbientOcclusionOptions { + float radius = 0.3f; //!< Ambient Occlusion radius in meters, between 0 and ~10. + float power = 1.0f; //!< Controls ambient occlusion's contrast. Must be positive. + float bias = 0.0005f; //!< Self-occlusion bias in meters. Use to avoid self-occlusion. Between 0 and a few mm. + float resolution = 0.5f;//!< How each dimension of the AO buffer is scaled. Must be either 0.5 or 1.0. + float intensity = 1.0f; //!< Strength of the Ambient Occlusion effect. + float bilateralThreshold = 0.05f; //!< depth distance that constitute an edge for filtering + QualityLevel quality = QualityLevel::LOW; //!< affects # of samples used for AO. + QualityLevel lowPassFilter = QualityLevel::MEDIUM; //!< affects AO smoothness + QualityLevel upsampling = QualityLevel::LOW; //!< affects AO buffer upsampling quality + bool enabled = false; //!< enables or disables screen-space ambient occlusion + bool bentNormals = false; //!< enables bent normals computation from AO, and specular AO + float minHorizonAngleRad = 0.0f; //!< min angle in radian to consider + /** + * Screen Space Cone Tracing (SSCT) options + * Ambient shadows from dominant light + */ + struct Ssct { + float lightConeRad = 1.0f; //!< full cone angle in radian, between 0 and pi/2 + float shadowDistance = 0.3f; //!< how far shadows can be cast + float contactDistanceMax = 1.0f; //!< max distance for contact + float intensity = 0.8f; //!< intensity + math::float3 lightDirection{ 0, -1, 0 }; //!< light direction + float depthBias = 0.01f; //!< depth bias in world units (mitigate self shadowing) + float depthSlopeBias = 0.01f; //!< depth slope bias (mitigate self shadowing) + uint8_t sampleCount = 4; //!< tracing sample count, between 1 and 255 + uint8_t rayCount = 1; //!< # of rays to trace, between 1 and 255 + bool enabled = false; //!< enables or disables SSCT + } ssct; +}; + +/** + * Options for Temporal Anti-aliasing (TAA) + * @see setTemporalAntiAliasingOptions() + */ +struct TemporalAntiAliasingOptions { + float filterWidth = 1.0f; //!< reconstruction filter width typically between 0 (sharper, aliased) and 1 (smoother) + float feedback = 0.04f; //!< history feedback, between 0 (maximum temporal AA) and 1 (no temporal AA). + bool enabled = false; //!< enables or disables temporal anti-aliasing +}; + +/** + * List of available post-processing anti-aliasing techniques. + * @see setAntiAliasing, getAntiAliasing, setSampleCount + */ +enum class AntiAliasing : uint8_t { + NONE = 0, //!< no anti aliasing performed as part of post-processing + FXAA = 1 //!< FXAA is a low-quality but very efficient type of anti-aliasing. (default). +}; + +/** + * List of available post-processing dithering techniques. + */ +enum class Dithering : uint8_t { + NONE = 0, //!< No dithering + TEMPORAL = 1 //!< Temporal dithering (default) +}; + +/** + * List of available shadow mapping techniques. + * @see setShadowType + */ +enum class ShadowType : uint8_t { + PCF, //!< percentage-closer filtered shadows (default) + VSM //!< variance shadows +}; + +/** + * View-level options for VSM Shadowing. + * @see setVsmShadowOptions() + * @warning This API is still experimental and subject to change. + */ +struct VsmShadowOptions { + /** + * Sets the number of anisotropic samples to use when sampling a VSM shadow map. If greater + * than 0, mipmaps will automatically be generated each frame for all lights. + * + * The number of anisotropic samples = 2 ^ vsmAnisotropy. + */ + uint8_t anisotropy = 0; + + /** + * Whether to generate mipmaps for all VSM shadow maps. + */ + bool mipmapping = false; + + /** + * EVSM exponent. + * The maximum value permissible is 5.54 for a shadow map in fp16, or 42.0 for a + * shadow map in fp32. Currently the shadow map bit depth is always fp16. + */ + float exponent = 5.54f; + + /** + * VSM minimum variance scale, must be positive. + */ + float minVarianceScale = 0.5f; + + /** + * VSM light bleeding reduction amount, between 0 and 1. + */ + float lightBleedReduction = 0.15f; +}; + +} // namespace filament + +#endif //TNT_FILAMENT_OPTIONS_H diff --git a/ios/include/filament/RenderableManager.h b/ios/include/filament/RenderableManager.h index b9e05771..0e602c3e 100644 --- a/ios/include/filament/RenderableManager.h +++ b/ios/include/filament/RenderableManager.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef TNT_FILAMENT_RENDERABLECOMPONENTMANAGER_H -#define TNT_FILAMENT_RENDERABLECOMPONENTMANAGER_H +#ifndef TNT_FILAMENT_RENDERABLEMANAGER_H +#define TNT_FILAMENT_RENDERABLEMANAGER_H #include #include @@ -582,4 +582,4 @@ Box RenderableManager::computeAABB(VECTOR const* vertices, INDEX const* indices, } // namespace filament -#endif // TNT_FILAMENT_RENDERABLECOMPONENTMANAGER_H +#endif // TNT_FILAMENT_RENDERABLEMANAGER_H diff --git a/ios/include/filament/Texture.h b/ios/include/filament/Texture.h index 71550ba6..2656023e 100644 --- a/ios/include/filament/Texture.h +++ b/ios/include/filament/Texture.h @@ -181,7 +181,7 @@ public: /** * Specifies how a texture's channels map to color components * - * Texture Swizzle is only supported is isTextureSwizzleSupported() returns true. + * Texture Swizzle is only supported if isTextureSwizzleSupported() returns true. * * @param r texture channel for red component * @param g texture channel for green component diff --git a/ios/include/filament/ToneMapper.h b/ios/include/filament/ToneMapper.h index 03a8f6b6..b961e952 100644 --- a/ios/include/filament/ToneMapper.h +++ b/ios/include/filament/ToneMapper.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef TNT_FILAMENT_TONE_MAPPER_H -#define TNT_FILAMENT_TONE_MAPPER_H +#ifndef TNT_FILAMENT_TONEMAPPER_H +#define TNT_FILAMENT_TONEMAPPER_H #include @@ -232,4 +232,4 @@ struct UTILS_PUBLIC DisplayRangeToneMapper final : public ToneMapper { } // namespace filament -#endif // TNT_FILAMENT_TONE_MAPPER_H +#endif // TNT_FILAMENT_TONEMAPPER_H diff --git a/ios/include/filament/View.h b/ios/include/filament/View.h index 7b0c1f60..dc692bd5 100644 --- a/ios/include/filament/View.h +++ b/ios/include/filament/View.h @@ -21,10 +21,12 @@ #include #include +#include #include #include +#include #include @@ -35,7 +37,6 @@ class ColorGrading; class MaterialInstance; class RenderTarget; class Scene; -class Texture; class Viewport; /** @@ -61,325 +62,21 @@ class Viewport; */ class UTILS_PUBLIC View : public FilamentAPI { public: - enum class QualityLevel : uint8_t { - LOW, - MEDIUM, - HIGH, - ULTRA - }; + using QualityLevel = QualityLevel; + using BlendMode = BlendMode; + using AntiAliasing = AntiAliasing; + using Dithering = Dithering; + using ShadowType = ShadowType; - enum class BlendMode : uint8_t { - OPAQUE, - TRANSLUCENT - }; - - /** - * Dynamic resolution can be used to either reach a desired target frame rate - * by lowering the resolution of a View, or to increase the quality when the - * rendering is faster than the target frame rate. - * - * This structure can be used to specify the minimum scale factor used when - * lowering the resolution of a View, and the maximum scale factor used when - * increasing the resolution for higher quality rendering. The scale factors - * can be controlled on each X and Y axis independently. By default, all scale - * factors are set to 1.0. - * - * enabled: enable or disables dynamic resolution on a View - * - * homogeneousScaling: by default the system scales the major axis first. Set this to true - * to force homogeneous scaling. - * - * minScale: the minimum scale in X and Y this View should use - * - * maxScale: the maximum scale in X and Y this View should use - * - * quality: upscaling quality. - * LOW: 1 bilinear tap, Medium: 4 bilinear taps, High: 9 bilinear taps (tent) - * - * \note - * Dynamic resolution is only supported on platforms where the time to render - * a frame can be measured accurately. Dynamic resolution is currently only - * supported on Android. - * - * @see Renderer::FrameRateOptions - * - */ - struct DynamicResolutionOptions { - math::float2 minScale = math::float2(0.5f); //!< minimum scale factors in x and y - math::float2 maxScale = math::float2(1.0f); //!< maximum scale factors in x and y - bool enabled = false; //!< enable or disable dynamic resolution - bool homogeneousScaling = false; //!< set to true to force homogeneous scaling - QualityLevel quality = QualityLevel::LOW; //!< Upscaling quality - }; - - /** - * Options to control the bloom effect - * - * enabled: Enable or disable the bloom post-processing effect. Disabled by default. - * - * levels: Number of successive blurs to achieve the blur effect, the minimum is 3 and the - * maximum is 12. This value together with resolution influences the spread of the - * blur effect. This value can be silently reduced to accommodate the original - * image size. - * - * resolution: Resolution of bloom's minor axis. The minimum value is 2^levels and the - * the maximum is lower of the original resolution and 4096. This parameter is - * silently clamped to the minimum and maximum. - * It is highly recommended that this value be smaller than the target resolution - * after dynamic resolution is applied (horizontally and vertically). - * - * strength: how much of the bloom is added to the original image. Between 0 and 1. - * - * blendMode: Whether the bloom effect is purely additive (false) or mixed with the original - * image (true). - * - * anamorphism: Bloom's aspect ratio (x/y), for artistic purposes. - * - * threshold: When enabled, a threshold at 1.0 is applied on the source image, this is - * useful for artistic reasons and is usually needed when a dirt texture is used. - * - * dirt: A dirt/scratch/smudges texture (that can be RGB), which gets added to the - * bloom effect. Smudges are visible where bloom occurs. Threshold must be - * enabled for the dirt effect to work properly. - * - * dirtStrength: Strength of the dirt texture. - */ - struct BloomOptions { - enum class BlendMode : uint8_t { - ADD, //!< Bloom is modulated by the strength parameter and added to the scene - INTERPOLATE //!< Bloom is interpolated with the scene using the strength parameter - }; - Texture* dirt = nullptr; //!< user provided dirt texture - float dirtStrength = 0.2f; //!< strength of the dirt texture - float strength = 0.10f; //!< bloom's strength between 0.0 and 1.0 - uint32_t resolution = 360; //!< resolution of vertical axis (2^levels to 2048) - float anamorphism = 1.0f; //!< bloom x/y aspect-ratio (1/32 to 32) - uint8_t levels = 6; //!< number of blur levels (3 to 11) - BlendMode blendMode = BlendMode::ADD; //!< how the bloom effect is applied - bool threshold = true; //!< whether to threshold the source - bool enabled = false; //!< enable or disable bloom - float highlight = 1000.0f; //!< limit highlights to this value before bloom [10, +inf] - - bool lensFlare = false; //!< enable screen-space lens flare - bool starburst = true; //!< enable starburst effect on lens flare - float chromaticAberration = 0.005f; //!< amount of chromatic aberration - uint8_t ghostCount = 4; //!< number of flare "ghosts" - float ghostSpacing = 0.6f; //!< spacing of the ghost in screen units [0, 1[ - float ghostThreshold = 10.0f; //!< hdr threshold for the ghosts - float haloThickness = 0.1f; //!< thickness of halo in vertical screen units, 0 to disable - float haloRadius = 0.4f; //!< radius of halo in vertical screen units [0, 0.5] - float haloThreshold = 10.0f; //!< hdr threshold for the halo - }; - - /** - * Options to control fog in the scene - */ - struct FogOptions { - float distance = 0.0f; //!< distance in world units from the camera where the fog starts ( >= 0.0 ) - float maximumOpacity = 1.0f; //!< fog's maximum opacity between 0 and 1 - float height = 0.0f; //!< fog's floor in world units - float heightFalloff = 1.0f; //!< how fast fog dissipates with altitude - LinearColor color{0.5f}; //!< fog's color (linear), see fogColorFromIbl - float density = 0.1f; //!< fog's density at altitude given by 'height' - float inScatteringStart = 0.0f; //!< distance in world units from the camera where in-scattering starts - float inScatteringSize = -1.0f; //!< size of in-scattering (>0 to activate). Good values are >> 1 (e.g. ~10 - 100). - bool fogColorFromIbl = false; //!< Fog color will be modulated by the IBL color in the view direction. - bool enabled = false; //!< enable or disable fog - }; - - /** - * Options to control Depth of Field (DoF) effect in the scene. - * - * cocScale can be used to set the depth of field blur independently from the camera - * aperture, e.g. for artistic reasons. This can be achieved by setting: - * cocScale = cameraAperture / desiredDoFAperture - * - * @see Camera - */ - struct DepthOfFieldOptions { - enum class Filter : uint8_t { - NONE = 0, - MEDIAN = 2 - }; - float cocScale = 1.0f; //!< circle of confusion scale factor (amount of blur) - 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; - }; - - /** - * Options to control the vignetting effect. - */ - struct VignetteOptions { - float midPoint = 0.5f; //!< high values restrict the vignette closer to the corners, between 0 and 1 - float roundness = 0.5f; //!< controls the shape of the vignette, from a rounded rectangle (0.0), to an oval (0.5), to a circle (1.0) - float feather = 0.5f; //!< softening amount of the vignette effect, between 0 and 1 - LinearColorA color{0.0f, 0.0f, 0.0f, 1.0f}; //!< color of the vignette effect, alpha is currently ignored - bool enabled = false; //!< enables or disables the vignette effect - }; - - /** - * Structure used to set the precision of the color buffer and related quality settings. - * - * @see setRenderQuality, getRenderQuality - */ - struct RenderQuality { - /** - * Sets the quality of the HDR color buffer. - * - * A quality of HIGH or ULTRA means using an RGB16F or RGBA16F color buffer. This means - * colors in the LDR range (0..1) have a 10 bit precision. A quality of LOW or MEDIUM means - * using an R11G11B10F opaque color buffer or an RGBA16F transparent color buffer. With - * R11G11B10F colors in the LDR range have a precision of either 6 bits (red and green - * channels) or 5 bits (blue channel). - */ - QualityLevel hdrColorBuffer = QualityLevel::HIGH; - }; - - /** - * Options for screen space Ambient Occlusion (SSAO) and Screen Space Cone Tracing (SSCT) - * @see setAmbientOcclusionOptions() - */ - struct AmbientOcclusionOptions { - float radius = 0.3f; //!< Ambient Occlusion radius in meters, between 0 and ~10. - float power = 1.0f; //!< Controls ambient occlusion's contrast. Must be positive. - float bias = 0.0005f; //!< Self-occlusion bias in meters. Use to avoid self-occlusion. Between 0 and a few mm. - float resolution = 0.5f;//!< How each dimension of the AO buffer is scaled. Must be either 0.5 or 1.0. - float intensity = 1.0f; //!< Strength of the Ambient Occlusion effect. - float bilateralThreshold = 0.05f; //!< depth distance that constitute an edge for filtering - QualityLevel quality = QualityLevel::LOW; //!< affects # of samples used for AO. - QualityLevel lowPassFilter = QualityLevel::MEDIUM; //!< affects AO smoothness - QualityLevel upsampling = QualityLevel::LOW; //!< affects AO buffer upsampling quality - bool enabled = false; //!< enables or disables screen-space ambient occlusion - bool bentNormals = false; //!< enables bent normals computation from AO, and specular AO - float minHorizonAngleRad = 0.0f; //!< min angle in radian to consider - /** - * Screen Space Cone Tracing (SSCT) options - * Ambient shadows from dominant light - */ - struct Ssct { - float lightConeRad = 1.0f; //!< full cone angle in radian, between 0 and pi/2 - float shadowDistance = 0.3f; //!< how far shadows can be cast - float contactDistanceMax = 1.0f; //!< max distance for contact - float intensity = 0.8f; //!< intensity - math::float3 lightDirection{ 0, -1, 0 }; //!< light direction - float depthBias = 0.01f; //!< depth bias in world units (mitigate self shadowing) - float depthSlopeBias = 0.01f; //!< depth slope bias (mitigate self shadowing) - uint8_t sampleCount = 4; //!< tracing sample count, between 1 and 255 - uint8_t rayCount = 1; //!< # of rays to trace, between 1 and 255 - bool enabled = false; //!< enables or disables SSCT - } ssct; - }; - - /** - * Options for Temporal Anti-aliasing (TAA) - * @see setTemporalAntiAliasingOptions() - */ - struct TemporalAntiAliasingOptions { - float filterWidth = 1.0f; //!< reconstruction filter width typically between 0 (sharper, aliased) and 1 (smoother) - float feedback = 0.04f; //!< history feedback, between 0 (maximum temporal AA) and 1 (no temporal AA). - bool enabled = false; //!< enables or disables temporal anti-aliasing - }; - - /** - * List of available post-processing anti-aliasing techniques. - * @see setAntiAliasing, getAntiAliasing, setSampleCount - */ - enum class AntiAliasing : uint8_t { - NONE = 0, //!< no anti aliasing performed as part of post-processing - FXAA = 1 //!< FXAA is a low-quality but very efficient type of anti-aliasing. (default). - }; - - /** - * List of available post-processing dithering techniques. - */ - enum class Dithering : uint8_t { - NONE = 0, //!< No dithering - TEMPORAL = 1 //!< Temporal dithering (default) - }; - - /** - * List of available shadow mapping techniques. - * @see setShadowType - */ - enum class ShadowType : uint8_t { - PCF, //!< percentage-closer filtered shadows (default) - VSM //!< variance shadows - }; - - /** - * View-level options for VSM Shadowing. - * @see setVsmShadowOptions() - * @warning This API is still experimental and subject to change. - */ - struct VsmShadowOptions { - /** - * Sets the number of anisotropic samples to use when sampling a VSM shadow map. If greater - * than 0, mipmaps will automatically be generated each frame for all lights. - * - * The number of anisotropic samples = 2 ^ vsmAnisotropy. - */ - uint8_t anisotropy = 0; - - /** - * Whether to generate mipmaps for all VSM shadow maps. - */ - bool mipmapping = false; - - /** - * EVSM exponent. - * The maximum value permissible is 5.54 for a shadow map in fp16, or 42.0 for a - * shadow map in fp32. Currently the shadow map bit depth is always fp16. - */ - float exponent = 5.54f; - - /** - * VSM minimum variance scale, must be positive. - */ - float minVarianceScale = 0.5f; - - /** - * VSM light bleeding reduction amount, between 0 and 1. - */ - float lightBleedReduction = 0.15f; - }; + using DynamicResolutionOptions = DynamicResolutionOptions; + using BloomOptions = BloomOptions; + using FogOptions = FogOptions; + using DepthOfFieldOptions = DepthOfFieldOptions; + using VignetteOptions = VignetteOptions; + using RenderQuality = RenderQuality; + using AmbientOcclusionOptions = AmbientOcclusionOptions; + using TemporalAntiAliasingOptions = TemporalAntiAliasingOptions; + using VsmShadowOptions = VsmShadowOptions; /** * Sets the View's name. Only useful for debugging. @@ -875,6 +572,116 @@ public: //! debugging: returns a Camera from the point of view of *the* dominant directional light used for shadowing. Camera const* getDirectionalLightCamera() const noexcept; + + /** Result of a picking query */ + struct PickingQueryResult { + utils::Entity renderable{}; //! RenderableManager Entity at the queried coordinates + float depth{}; //! Depth buffer value (1 (near plane) to 0 (infinity)) + uint32_t reserved1{}; + uint32_t reserved2{}; + /** + * screen space coordinates in GL convention, this can be used to compute the view or + * world space position of the picking hit. For e.g.: + * clip_space_position = (fragCoords.xy / viewport.wh, fragCoords.z) * 2.0 - 1.0 + * view_space_position = inverse(projection) * clip_space_position + * world_space_position = model * view_space_position + * + * The viewport, projection and model matrices can be obtained from Camera. Because + * pick() has some latency, it might be more accurate to obtain these values at the + * time the View::pick() call is made. + */ + math::float3 fragCoords; //! screen space coordinates in GL convention + }; + + /** User data for PickingQueryResultCallback */ + struct PickingQuery { + // note: this is enough to store a std::function<> -- just saying... + void* storage[4]; + }; + + /** callback type used for picking queries. */ + using PickingQueryResultCallback = void(*)(PickingQueryResult const& result, PickingQuery* pq); + + /** + * Helper for creating a picking query from Foo::method, by pointer. + * e.g.: pick(x, y, &foo); + * + * @tparam T Class of the method to call (e.g.: Foo) + * @tparam method Method to call on T (e.g.: &Foo::bar) + * @param x Horizontal coordinate to query in the viewport with origin on the left. + * @param y Vertical coordinate to query on the viewport with origin at the bottom. + * @param data A pointer to an instance of T + */ + template + void pick(uint32_t x, uint32_t y, T* instance) noexcept { + PickingQuery& query = pick(x, y, [](PickingQueryResult const& result, PickingQuery* pq) { + void* user = pq->storage; + (*static_cast(user)->*method)(result); + }); + query.storage[0] = instance; + } + + /** + * Helper for creating a picking query from Foo::method, by copy for a small object + * e.g.: pick(x, y, foo); + * + * @tparam T Class of the method to call (e.g.: Foo) + * @tparam method Method to call on T (e.g.: &Foo::bar) + * @param x Horizontal coordinate to query in the viewport with origin on the left. + * @param y Vertical coordinate to query on the viewport with origin at the bottom. + * @param data An instance of T + */ + template + void pick(uint32_t x, uint32_t y, T instance) noexcept { + static_assert(sizeof(instance) <= sizeof(PickingQuery::storage), "user data too large"); + PickingQuery& query = pick(x, y, [](PickingQueryResult const& result, PickingQuery* pq) { + void* user = pq->storage; + T* that = static_cast(user); + (that->*method)(result); + that->~T(); + }); + new(query.storage) T(std::move(instance)); + } + + /** + * Helper for creating a picking query from a small functor + * e.g.: pick(x, y, [](PickingQueryResult const& result){}); + * + * @param x Horizontal coordinate to query in the viewport with origin on the left. + * @param y Vertical coordinate to query on the viewport with origin at the bottom. + * @param functor A functor, typically a lambda function. + */ + template + void pick(uint32_t x, uint32_t y, T functor) noexcept { + static_assert(sizeof(functor) <= sizeof(PickingQuery::storage), "functor too large"); + PickingQuery& query = pick(x, y, + (PickingQueryResultCallback)[](PickingQueryResult const& result, PickingQuery* pq) { + void* user = pq->storage; + T& that = *static_cast(user); + that(result); + that.~T(); + }); + new(query.storage) T(std::move(functor)); + } + + /** + * Creates a picking query. Multiple queries can be created (e.g.: multi-touch). + * Picking queries are all executed when Renderer::render() is called on this View. + * The provided callback is guaranteed to be called at some point in the future. + * + * Typically it takes a couple frames to receive the result of a picking query. + * + * @param x Horizontal coordinate to query in the viewport with origin on the left. + * @param y Vertical coordinate to query on the viewport with origin at the bottom. + * @param callback User callback, called when the picking query result is available. + * @return A reference to a PickingQuery structure, which can be used to store up to + * 8*sizeof(void*) bytes of user data. This user data is later accessible + * in the PickingQueryResultCallback callback 3rd parameter. + */ + PickingQuery& pick(uint32_t x, uint32_t y, + PickingQueryResultCallback callback) noexcept; + + /** * List of available ambient occlusion techniques * @deprecated use AmbientOcclusionOptions::enabled instead @@ -905,7 +712,6 @@ public: AmbientOcclusion getAmbientOcclusion() const noexcept; }; - } // namespace filament #endif // TNT_FILAMENT_VIEW_H diff --git a/ios/src/FilamentViewer.cpp b/ios/src/FilamentViewer.cpp index dcd7f2ba..c422205e 100644 --- a/ios/src/FilamentViewer.cpp +++ b/ios/src/FilamentViewer.cpp @@ -63,6 +63,9 @@ using namespace gltfio; using namespace utils; using namespace std::chrono; +namespace foo { + MaterialProvider* createUbershaderLoader(filament::Engine* engine); +} namespace filament { class IndirectLight; @@ -70,7 +73,12 @@ namespace filament { } namespace gltfio { - MaterialProvider* createGPUMorphShaderLoader(const void* data, uint64_t size, Engine* engine); + MaterialProvider* createGPUMorphShaderLoader( + const void* opaqueData, + uint64_t opaqueDataSize, + const void* fadeData, + uint64_t fadeDataSize, + Engine* engine); void decomposeMatrix(const filament::math::mat4f& mat, filament::math::float3* translation, filament::math::quatf* rotation, filament::math::float3* scale); } @@ -113,12 +121,14 @@ filament::math::mat4f composeMatrix(const filament::math::float3& translation, FilamentViewer::FilamentViewer( void* layer, - const char* shaderPath, + const char* opaqueShaderPath, + const char* fadeShaderPath, LoadResource loadResource, FreeResource freeResource) : _layer(layer), _loadResource(loadResource), _freeResource(freeResource), - materialProviderResources(nullptr, 0) { + opaqueShaderResources(nullptr, 0), + fadeShaderResources(nullptr, 0) { _engine = Engine::create(Engine::Backend::OPENGL); _renderer = _engine->createRenderer(); @@ -134,13 +144,19 @@ FilamentViewer::FilamentViewer( _swapChain = _engine->createSwapChain(_layer); - if(shaderPath) { - materialProviderResources = _loadResource(shaderPath); - _materialProvider = createGPUMorphShaderLoader(materialProviderResources.data, materialProviderResources.size, _engine); + // if(shaderPath) { + opaqueShaderResources = _loadResource(opaqueShaderPath); + fadeShaderResources = _loadResource(fadeShaderPath); + _materialProvider = createGPUMorphShaderLoader( + opaqueShaderResources.data, + opaqueShaderResources.size, + fadeShaderResources.data, + fadeShaderResources.size, + _engine); // _freeResource((void*)rb.data, rb.size, nullptr); <- TODO this is being freed too early, need to pass to callback? - } else { - _materialProvider = createUbershaderLoader(_engine); - } + // } else { + // _materialProvider = foo::createUbershaderLoader(_engine); + // } EntityManager& em = EntityManager::get(); _ncm = new NameComponentManager(em); _assetLoader = AssetLoader::create({_engine, _materialProvider, _ncm, &em}); @@ -191,7 +207,8 @@ void FilamentViewer::loadResources(string relativeResourcePath) { void FilamentViewer::releaseSourceAssets() { std::cout << "Releasing source data" << std::endl; _asset->releaseSourceData(); - _freeResource((void*)materialProviderResources.data, materialProviderResources.size, nullptr); + _freeResource((void*)opaqueShaderResources.data, opaqueShaderResources.size, nullptr); + _freeResource((void*)fadeShaderResources.data, fadeShaderResources.size, nullptr); } @@ -200,6 +217,44 @@ void FilamentViewer::animateWeights(float* data, int numWeights, int length, flo morphAnimationBuffer = std::make_unique(data, numWeights, length / numWeights, 1000 / frameRate ); } +void FilamentViewer::loadGlb(const char* const uri) { + if(_asset) { + _resourceLoader->evictResourceData(); + _scene->removeEntities(_asset->getEntities(), _asset->getEntityCount()); + _assetLoader->destroyAsset(_asset); + } + _asset = nullptr; + _animator = nullptr; + + ResourceBuffer rbuf = _loadResource(uri); + + // Parse the glTF file and create Filament entities. + _asset = _assetLoader->createAssetFromJson((uint8_t*)rbuf.data, rbuf.size); + + if (!_asset) { + std::cerr << "Unable to parse asset" << std::endl; + exit(1); + } + + _resourceLoader->loadResources(_asset); + const Entity* entities = _asset->getEntities(); + RenderableManager& rm = _engine->getRenderableManager(); + for(int i =0; i< _asset->getEntityCount(); i++) { + Entity e = entities[i]; + auto inst = rm.getInstance(e); + rm.setCulling(inst, false); + } + + _animator = _asset->getAnimator(); + + _scene->addEntities(_asset->getEntities(), _asset->getEntityCount()); + + + _freeResource((void*)rbuf.data, rbuf.size, nullptr); + + transformToUnitCube(); +} + void FilamentViewer::loadGltf(const char* const uri, const char* const relativeResourcePath) { if(_asset) { _resourceLoader->evictResourceData(); @@ -280,16 +335,23 @@ void FilamentViewer::playAnimation(int index) { } void FilamentViewer::loadSkybox(const char* const skyboxPath, const char* const iblPath) { + + std::cout << "Loading skybox from " << skyboxPath << std::endl; + ResourceBuffer skyboxBuffer = _loadResource(skyboxPath); + + std::cout << "Loaded skybox resource buffer of size " << skyboxBuffer.size << std::endl; image::KtxBundle* skyboxBundle = new image::KtxBundle(static_cast(skyboxBuffer.data), static_cast(skyboxBuffer.size)); - _skyboxTexture = image::ktx::createTexture(_engine, skyboxBundle, false); + _skyboxTexture = image::ktx::createTexture(_engine, skyboxBundle, true); _skybox = filament::Skybox::Builder().environment(_skyboxTexture).build(*_engine); _scene->setSkybox(_skybox); _freeResource((void*)skyboxBuffer.data, skyboxBuffer.size, nullptr); + std::cout << "Loading IBL from " << iblPath << std::endl; + // Load IBL. ResourceBuffer iblBuffer = _loadResource(iblPath); diff --git a/ios/src/FilamentViewer.hpp b/ios/src/FilamentViewer.hpp index eda37026..e6a972ce 100644 --- a/ios/src/FilamentViewer.hpp +++ b/ios/src/FilamentViewer.hpp @@ -94,8 +94,9 @@ namespace holovox { class FilamentViewer { public: - FilamentViewer(void* layer, const char* shaderPath, LoadResource loadResource, FreeResource freeResource); + FilamentViewer(void* layer, const char* opaqueShaderPath, const char* fadeShaderPath, LoadResource loadResource, FreeResource freeResource); ~FilamentViewer(); + void loadGlb(const char* const uri); void loadGltf(const char* const uri, const char* relativeResourcePath); void loadSkybox(const char* const skyboxUri, const char* const iblUri); void updateViewportAndCameraProjection(int height, int width, float scaleFactor); @@ -127,7 +128,8 @@ namespace holovox { LoadResource _loadResource; FreeResource _freeResource; - ResourceBuffer materialProviderResources; + ResourceBuffer opaqueShaderResources; + ResourceBuffer fadeShaderResources; Scene* _scene; View* _view; diff --git a/ios/src/morph/GPUMorphHelper.cpp b/ios/src/morph/GPUMorphHelper.cpp index d3d4ece4..0b68a846 100644 --- a/ios/src/morph/GPUMorphHelper.cpp +++ b/ios/src/morph/GPUMorphHelper.cpp @@ -35,6 +35,16 @@ using namespace filament; using namespace filamat; using namespace filament::math; using namespace utils; + +#include "upcast.h" + +#include + +#include + +#include + + namespace gltfio { static constexpr uint8_t kUnused = 0xff; @@ -62,6 +72,7 @@ namespace gltfio { targetMesh = mesh; for(int i = 0; i < numPrimitives; i++) { int primitiveIndex = primitiveIndices[i]; + //for(int primitiveIndex = 0; primitiveIndex < targetMesh->primitives_count; primitiveIndex++) { std::cout << "Adding primitive at index " << primitiveIndex << " to morpher " << std::endl; addPrimitive(mesh, primitiveIndex); } @@ -106,7 +117,6 @@ namespace gltfio { auto textureSize = textureWidth * 3 * sizeof(float) * prim->numTargets; auto textureBuffer = (float *const) malloc(textureSize); - if(!textureBuffer) { std::cout << "Error allocating texture buffer" << std::endl; exit(-1); @@ -117,7 +127,7 @@ namespace gltfio { uint32_t offset = 0; // assume the primitive morph target source buffer is laid out like: - // |target0_v0_pos * 3|target0_v0_norm * 3|target0_v1_pos * 3|target0_v1_norm * 3|...|target1_v0_pos * 3|target1_v0_norm * 3|target1_v1_pos * 3|target1_v1_norm * 3|... + // |target0_v0_pos * 3|target0_v1_pos * 3|...|target0_v0_norm * 3|target0_v1_norm * 3|...|target1_v0_pos * 3|target1_v1_pos * 3|...|target1_v0_norm * 3|target1_v1_norm * 3|... // where: // - target0/target1/etc is the first/second/etc morph target // - v0/v1/etc is the first/second/etc vertex @@ -126,7 +136,7 @@ namespace gltfio { if(target.type == cgltf_attribute_type_position || (numAttributes > 1 && target.type == cgltf_attribute_type_normal) ) { - + float attr = (float)textureBuffer[offset]; memcpy(textureBuffer+offset, target.bufferObject, target.bufferSize); offset += int(target.bufferSize / sizeof(float)); } @@ -137,7 +147,7 @@ namespace gltfio { .height(1) .depth(prim->numTargets) .sampler(Texture::Sampler::SAMPLER_2D_ARRAY) - .format(Texture::InternalFormat::RGB32F) + .format(backend::TextureFormat::RGB32F) .levels(0x01) .build(engine); @@ -146,8 +156,8 @@ namespace gltfio { Texture::PixelBufferDescriptor descriptor( textureBuffer, textureSize, - Texture::Format::RGB, - Texture::Type::FLOAT, + backend::PixelDataFormat::RGB, + backend::PixelDataType::FLOAT, FREE_CALLBACK, nullptr); prim->texture->setImage(engine, 0, 0,0, 0, textureWidth, 1, prim->numTargets, std::move(descriptor)); @@ -155,7 +165,8 @@ namespace gltfio { for(int i = 0; i < mAsset->getMaterialInstanceCount(); i++) { const char* name = materialInstances[i]->getName(); if(strcmp(name, prim->materialName) == 0) { - std::cout << "Found material instance for primitive under name : " << name << std::endl; + const char* m = materialInstances[i]->getMaterial()->getName(); + std::cout << "Found material instance for material " << m << " and primitive under name : " << name << std::endl; prim->materialInstance = materialInstances[i]; //std::unique_ptr(materialInstances[i]); break; } @@ -165,7 +176,7 @@ namespace gltfio { exit(-1); } - float dimensions[] = { (float(prim->numVertices) * float(numAttributes)), float(numAttributes), float(prim->numTargets) }; + float dimensions[] = { float(prim->numVertices), float(numAttributes), float(prim->numTargets) }; prim->materialInstance->setParameter("dimensions", dimensions, 3); // TextureSampler sampler(filament::backend::SamplerMagFilter::NEAREST, filament::TextureSampler::WrapMode::REPEAT); @@ -214,12 +225,7 @@ namespace gltfio { if (atype == cgltf_attribute_type_tangent) { continue; } - if ( - atype == cgltf_attribute_type_position || (numAttributes > 1 && atype == cgltf_attribute_type_normal) - ) { - - - // All position & normal attributes must have the same data type. + if (atype == cgltf_attribute_type_position || numAttributes > 1 && atype == cgltf_attribute_type_normal) { assert_invariant( !previous || previous->component_type == accessor->component_type); assert_invariant(!previous || previous->type == accessor->type); @@ -234,9 +240,122 @@ namespace gltfio { animatedPrimitive->targets.push_back({data, size, targetIndex, atype}); } - } + } } } animatablePrimitives.push_back(std::move(animatedPrimitive)); } } + + +// assert( +// FTexture::validatePixelFormatAndType( +// backend::TextureFormat::RGB32F, +// backend::PixelDataFormat::RGB, +// backend::PixelDataType::FLOAT)); + +// namespace filament { + +// class FEngine; +// class FStream; + +// class FTexture : public Texture { +// public: +// FTexture(FEngine& engine, const Builder& builder); + +// // frees driver resources, object becomes invalid +// void terminate(FEngine& engine); + +// backend::Handle getHwHandle() const noexcept { return mHandle; } + +// size_t getWidth(size_t level = 0) const noexcept; +// size_t getHeight(size_t level = 0) const noexcept; +// size_t getDepth(size_t level = 0) const noexcept; +// size_t getLevelCount() const noexcept { return mLevelCount; } +// size_t getMaxLevelCount() const noexcept { return FTexture::maxLevelCount(mWidth, mHeight); } +// Sampler getTarget() const noexcept { return mTarget; } +// InternalFormat getFormat() const noexcept { return mFormat; } +// Usage getUsage() const noexcept { return mUsage; } + +// void setImage(FEngine& engine, size_t level, +// uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, +// PixelBufferDescriptor&& buffer) const; + +// void setImage(FEngine& engine, size_t level, +// uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, +// uint32_t width, uint32_t height, uint32_t depth, +// PixelBufferDescriptor&& buffer) const; + +// void setImage(FEngine& engine, size_t level, +// PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets) const; + +// void generatePrefilterMipmap(FEngine& engine, +// PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets, +// PrefilterOptions const* options); + +// void setExternalImage(FEngine& engine, void* image) noexcept; +// void setExternalImage(FEngine& engine, void* image, size_t plane) noexcept; +// void setExternalStream(FEngine& engine, FStream* stream) noexcept; + +// void generateMipmaps(FEngine& engine) const noexcept; + +// void setSampleCount(size_t sampleCount) noexcept { mSampleCount = uint8_t(sampleCount); } +// size_t getSampleCount() const noexcept { return mSampleCount; } +// bool isMultisample() const noexcept { return mSampleCount > 1; } +// bool isCompressed() const noexcept { return backend::isCompressedFormat(mFormat); } + +// bool isCubemap() const noexcept { return mTarget == Sampler::SAMPLER_CUBEMAP; } + +// FStream const* getStream() const noexcept { return mStream; } + +// /* +// * Utilities +// */ + +// // 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; + +// // Size a of a pixel in bytes for the given format +// static size_t getFormatSize(InternalFormat format) noexcept; + +// // Returns the with or height for a given mipmap level from the base value. +// static inline size_t valueForLevel(uint8_t level, size_t baseLevelValue) { +// return std::max(size_t(1), baseLevelValue >> level); +// } + +// // Returns the max number of levels for a texture of given max dimensions +// static inline uint8_t maxLevelCount(uint32_t maxDimension) noexcept { +// return std::max(1, std::ilogbf(maxDimension) + 1); +// } + +// // Returns the max number of levels for a texture of given dimensions +// static inline uint8_t maxLevelCount(uint32_t width, uint32_t height) noexcept { +// return std::max(1, std::ilogbf(std::max(width, height)) + 1); +// } + +// static bool validatePixelFormatAndType(backend::TextureFormat internalFormat, +// backend::PixelDataFormat format, backend::PixelDataType type) noexcept; + +// private: +// friend class Texture; +// FStream* mStream = nullptr; +// backend::Handle mHandle; +// uint32_t mWidth = 1; +// uint32_t mHeight = 1; +// uint32_t mDepth = 1; +// InternalFormat mFormat = InternalFormat::RGBA8; +// Sampler mTarget = Sampler::SAMPLER_2D; +// uint8_t mLevelCount = 1; +// uint8_t mSampleCount = 1; +// Usage mUsage = Usage::DEFAULT; +// }; + + +// } // namespace filament diff --git a/ios/src/morph/GPUMorphHelper.h b/ios/src/morph/GPUMorphHelper.h index 065d4062..2b058fd9 100644 --- a/ios/src/morph/GPUMorphHelper.h +++ b/ios/src/morph/GPUMorphHelper.h @@ -67,7 +67,7 @@ namespace gltfio { MaterialInstance* materialInstance; }; - int numAttributes = 1; // just position for now - normals not working with indexing inside shader? byte offset seems not calculated correctly + int numAttributes = 2; void addPrimitive(cgltf_mesh const *mesh, int primitiveIndex); diff --git a/ios/src/morph/GPUMorphShaderLoader.cpp b/ios/src/morph/GPUMorphShaderLoader.cpp index e7ec448a..c3f803eb 100644 --- a/ios/src/morph/GPUMorphShaderLoader.cpp +++ b/ios/src/morph/GPUMorphShaderLoader.cpp @@ -8,6 +8,7 @@ #include #include +#include #include "gltfio/resources/gltfresources_lite.h" @@ -22,7 +23,12 @@ namespace { class GPUMorphShaderLoader : public MaterialProvider { public: - GPUMorphShaderLoader(const void* mData, uint64_t size, filament::Engine* engine); + GPUMorphShaderLoader( + const void* opaqueMaterial, + uint64_t opaqueMaterialSize, + const void* fadeMaterial, + uint64_t fadeMaterialSize, + filament::Engine* engine); ~GPUMorphShaderLoader() {} MaterialInstance* createMaterialInstance(MaterialKey* config, UvMap* uvmap, @@ -42,8 +48,10 @@ namespace { return false; } } - const void* mData; - const size_t mSize; + const void* opaqueData; + const size_t opaqueDataSize; + const void* fadeData; + const size_t fadeDataSize; Material* getMaterial(const MaterialKey& config) const; @@ -59,18 +67,41 @@ namespace { Engine* mEngine; }; - GPUMorphShaderLoader::GPUMorphShaderLoader(const void* data, uint64_t size, Engine* engine) : mData(data), mSize(size), mEngine(engine) { - unsigned char texels[4] = {}; - mDummyTexture = Texture::Builder() - .width(1).height(1) - .format(Texture::InternalFormat::RGBA8) - .build(*mEngine); - Texture::PixelBufferDescriptor pbd(texels, sizeof(texels), Texture::Format::RGBA, - Texture::Type::UBYTE); - mDummyTexture->setImage(*mEngine, 0, std::move(pbd)); +#define MATINDEX(shading, alpha, sheen, transmit, volume) (volume ? 11 : (transmit ? 10 : (sheen ? 9 : (int(shading) + 3 * int(alpha))))) + + + GPUMorphShaderLoader::GPUMorphShaderLoader(const void* opaqueData, + uint64_t opaqueDataSize, + const void* fadeData, + uint64_t fadeDataSize, + Engine* engine) : opaqueData(opaqueData), opaqueDataSize(opaqueDataSize), fadeData(fadeData), fadeDataSize(fadeDataSize), mEngine(engine) { + +// unsigned char texels[4] = {}; +// mDummyTexture = Texture::Builder() +// .width(1) +// .height(1) +// .format(backend::TextureFormat::RGBA8) +// .sampler(backend::SamplerType::SAMPLER_2D_ARRAY) +// .build(*mEngine); +// Texture::PixelBufferDescriptor pbd( +// texels, +// sizeof(texels), +// backend::PixelDataFormat::RGBA, +// backend::PixelDataType::UBYTE, +// nullptr); +// mDummyTexture->setImage(*mEngine, 0,0,0,0,0,0,0,std::move(pbd)); + unsigned char texels[4] = {}; + mDummyTexture = Texture::Builder() + .width(1).height(1) + .format(Texture::InternalFormat::RGBA8) + .build(*mEngine); + Texture::PixelBufferDescriptor pbd(texels, sizeof(texels), Texture::Format::RGBA, + Texture::Type::UBYTE); + mDummyTexture->setImage(*mEngine, 0, std::move(pbd)); } + size_t GPUMorphShaderLoader::getMaterialsCount() const noexcept { return sizeof(mMaterials) / sizeof(mMaterials[0]); } @@ -90,13 +121,33 @@ namespace { Material* GPUMorphShaderLoader::getMaterial(const MaterialKey& config) const { const ShadingMode shading = config.unlit ? UNLIT : (config.useSpecularGlossiness ? SPECULAR_GLOSSINESS : LIT); - const int matindex = 0; + + const int matindex = MATINDEX(shading, config.alphaMode, config.hasSheen, config.hasTransmission, config.hasVolume); if (mMaterials[matindex] != nullptr) { return mMaterials[matindex]; } + switch (matindex) { + case MATINDEX(LIT, AlphaMode::OPAQUE, false, false, false): + { + filamat::Package pkg = filamat::Package(opaqueData, opaqueDataSize); + mMaterials[matindex] = Material::Builder().package(pkg.getData(), pkg.getSize()).build(*mEngine); + } + break; + case MATINDEX(LIT, AlphaMode::BLEND, false, false, false): + { + filamat::Package pkg = filamat::Package(fadeData, fadeDataSize); + mMaterials[matindex] = Material::Builder().package(pkg.getData(), pkg.getSize()).build(*mEngine); + } + break; + default: + { + filamat::Package pkg = filamat::Package(fadeData, fadeDataSize); + mMaterials[matindex] = Material::Builder().package(pkg.getData(), pkg.getSize()).build(*mEngine); + } + break; + } - filamat::Package pkg = filamat::Package(mData, mSize); - return Material::Builder().package(pkg.getData(), pkg.getSize()).build(*mEngine); + return mMaterials[matindex]; } MaterialInstance* GPUMorphShaderLoader::createMaterialInstance(MaterialKey* config, UvMap* uvmap, @@ -145,7 +196,9 @@ namespace { mi->setDoubleSided(config->doubleSided); mi->setCullingMode(config->doubleSided ? CullingMode::NONE : CullingMode::BACK); - + mi->setTransparencyMode(config->doubleSided ? + MaterialInstance::TransparencyMode::TWO_PASSES_TWO_SIDES : + MaterialInstance::TransparencyMode::DEFAULT); // Initially, assume that the clear coat texture can be honored. This is changed to false when // running into a sampler count limitation. TODO: check if these constraints can now be relaxed. bool clearCoatNeedsTexture = true; @@ -176,7 +229,6 @@ namespace { getUvIndex(config->sheenRoughnessUV, config->hasSheenRoughnessTexture)); mi->setParameter("sheenColorUvMatrix", identity); mi->setParameter("sheenRoughnessUvMatrix", identity); - } if (config->hasVolume) { clearCoatNeedsTexture = false; @@ -196,6 +248,8 @@ namespace { mi->setParameter("normalMap", mDummyTexture, sampler); mi->setParameter("baseColorMap", mDummyTexture, sampler); mi->setParameter("metallicRoughnessMap", mDummyTexture, sampler); +// mi->setParameter("roughnessFactor", mDummyTexture, sampler); + mi->setParameter("occlusionMap", mDummyTexture, sampler); mi->setParameter("emissiveMap", mDummyTexture, sampler); if (clearCoatNeedsTexture) { @@ -227,8 +281,18 @@ namespace { namespace gltfio { - MaterialProvider* createGPUMorphShaderLoader(const void* data, uint64_t size, filament::Engine* engine) { - return new GPUMorphShaderLoader(data, size,engine); + MaterialProvider* createGPUMorphShaderLoader( + const void* opaqueData, + uint64_t opaqueDataSize, + const void* fadeData, + uint64_t fadeDataSize, + filament::Engine* engine) { + return new GPUMorphShaderLoader( + opaqueData, + opaqueDataSize, + fadeData, + fadeDataSize, + engine); } } // namespace gltfio diff --git a/ios/src/morph/UbershaderLoader.cpp b/ios/src/morph/UbershaderLoader.cpp new file mode 100644 index 00000000..c8627b29 --- /dev/null +++ b/ios/src/morph/UbershaderLoader.cpp @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include + +#include + +#include + +#include "gltfio/resources/gltfresources.h" + +using namespace filament; +using namespace filament::math; +using namespace gltfio; +using namespace utils; + +namespace { + +using CullingMode = MaterialInstance::CullingMode; + +class UbershaderLoader : public MaterialProvider { +public: + UbershaderLoader(filament::Engine* engine); + ~UbershaderLoader() {} + + MaterialInstance* createMaterialInstance(MaterialKey* config, UvMap* uvmap, + const char* label) override; + + size_t getMaterialsCount() const noexcept override; + const Material* const* getMaterials() const noexcept override; + void destroyMaterials() override; + + bool needsDummyData(VertexAttribute attrib) const noexcept override { + switch (attrib) { + case VertexAttribute::UV0: + case VertexAttribute::UV1: + case VertexAttribute::COLOR: + return true; + default: + return false; + } + } + + Material* getMaterial(const MaterialKey& config) const; + + enum ShadingMode { + UNLIT = 0, + LIT = 1, + SPECULAR_GLOSSINESS = 2, + }; + + mutable Material* mMaterials[12] = {}; + Texture* mDummyTexture = nullptr; + + Engine* mEngine; +}; + +#if GLTFIO_LITE + +#define CREATE_MATERIAL(name) Material::Builder() \ + .package(GLTFRESOURCES_LITE_ ## name ## _DATA, GLTFRESOURCES_LITE_ ## name ## _SIZE) \ + .build(*mEngine); + +#else + +#define CREATE_MATERIAL(name) Material::Builder() \ + .package(GLTFRESOURCES_ ## name ## _DATA, GLTFRESOURCES_ ## name ## _SIZE) \ + .build(*mEngine); + +#endif + +#define MATINDEX(shading, alpha, sheen, transmit, volume) (volume ? 11 : (transmit ? 10 : (sheen ? 9 : (int(shading) + 3 * int(alpha))))) + +UbershaderLoader::UbershaderLoader(Engine* engine) : mEngine(engine) { + unsigned char texels[4] = {}; + mDummyTexture = Texture::Builder() + .width(1).height(1) + .format(Texture::InternalFormat::RGBA8) + .build(*mEngine); + Texture::PixelBufferDescriptor pbd(texels, sizeof(texels), Texture::Format::RGBA, + Texture::Type::UBYTE); + mDummyTexture->setImage(*mEngine, 0, std::move(pbd)); +} + +size_t UbershaderLoader::getMaterialsCount() const noexcept { + return sizeof(mMaterials) / sizeof(mMaterials[0]); +} + +const Material* const* UbershaderLoader::getMaterials() const noexcept { + return &mMaterials[0]; +} + +void UbershaderLoader::destroyMaterials() { + for (auto& material : mMaterials) { + mEngine->destroy(material); + material = nullptr; + } + mEngine->destroy(mDummyTexture); +} + +Material* UbershaderLoader::getMaterial(const MaterialKey& config) const { + const ShadingMode shading = config.unlit ? UNLIT : + (config.useSpecularGlossiness ? SPECULAR_GLOSSINESS : LIT); + const int matindex = MATINDEX(shading, config.alphaMode, config.hasSheen, config.hasTransmission, config.hasVolume); + if (mMaterials[matindex] != nullptr) { + return mMaterials[matindex]; + } + switch (matindex) { + + case MATINDEX(LIT, AlphaMode::OPAQUE, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(LIT_OPAQUE); break; + + + + case MATINDEX(LIT, AlphaMode::BLEND, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(LIT_FADE); break; + + + + case MATINDEX(LIT, AlphaMode::MASK, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(LIT_MASKED); break; + case MATINDEX(UNLIT, AlphaMode::OPAQUE, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(UNLIT_OPAQUE); break; + case MATINDEX(UNLIT, AlphaMode::MASK, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(UNLIT_MASKED); break; + case MATINDEX(UNLIT, AlphaMode::BLEND, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(UNLIT_FADE); break; + case MATINDEX(SPECULAR_GLOSSINESS, AlphaMode::OPAQUE, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(SPECULARGLOSSINESS_OPAQUE); break; + case MATINDEX(SPECULAR_GLOSSINESS, AlphaMode::MASK, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(SPECULARGLOSSINESS_MASKED); break; + case MATINDEX(SPECULAR_GLOSSINESS, AlphaMode::BLEND, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(SPECULARGLOSSINESS_FADE); break; + case MATINDEX(0, 0, false, true, false): mMaterials[matindex] = CREATE_MATERIAL(LIT_TRANSMISSION); break; + case MATINDEX(0, 0, true, false, false): mMaterials[matindex] = CREATE_MATERIAL(LIT_SHEEN); break; + case MATINDEX(0, 0, false, false, true): mMaterials[matindex] = CREATE_MATERIAL(LIT_VOLUME); break; + + } + if (mMaterials[matindex] == nullptr) { + slog.w << "Unsupported glTF material configuration; falling back to LIT_OPAQUE." << io::endl; + MaterialKey litOpaque = config; + litOpaque.alphaMode = AlphaMode::OPAQUE; + litOpaque.hasTransmission = false; + litOpaque.hasVolume = false; + litOpaque.hasSheen = false; + litOpaque.useSpecularGlossiness = false; + litOpaque.unlit = false; + return getMaterial(litOpaque); + } + + return mMaterials[matindex]; +} + +MaterialInstance* UbershaderLoader::createMaterialInstance(MaterialKey* config, UvMap* uvmap, + const char* label) { + // Diagnostics are not supported with LOAD_UBERSHADERS, please use GENERATE_SHADERS instead. + if (config->enableDiagnostics) { + return nullptr; + } + + if (config->hasVolume && config->hasSheen) { + slog.w << "Volume and sheen are not supported together in ubershader mode," + " removing sheen (" << label << ")." << io::endl; + config->hasSheen = false; + } + + if (config->hasTransmission && config->hasSheen) { + slog.w << "Transmission and sheen are not supported together in ubershader mode," + " removing sheen (" << label << ")." << io::endl; + config->hasSheen = false; + } + + const bool clearCoatConflict = config->hasVolume || config->hasTransmission || config->hasSheen; + + // Due to sampler overload, disable transmission if necessary and print a friendly warning. + if (config->hasClearCoat && clearCoatConflict) { + slog.w << "Volume, transmission and sheen are not supported in ubershader mode for clearcoat" + " materials (" << label << ")." << io::endl; + config->hasVolume = false; + config->hasTransmission = false; + config->hasSheen = false; + } + + constrainMaterial(config, uvmap); + auto getUvIndex = [uvmap](uint8_t srcIndex, bool hasTexture) -> int { + return hasTexture ? int(uvmap->at(srcIndex)) - 1 : -1; + }; + Material* material = getMaterial(*config); + MaterialInstance* mi = material->createInstance(label); + mi->setParameter("baseColorIndex", + getUvIndex(config->baseColorUV, config->hasBaseColorTexture)); + mi->setParameter("normalIndex", getUvIndex(config->normalUV, config->hasNormalTexture)); + mi->setParameter("metallicRoughnessIndex", + getUvIndex(config->metallicRoughnessUV, config->hasMetallicRoughnessTexture)); + mi->setParameter("aoIndex", getUvIndex(config->aoUV, config->hasOcclusionTexture)); + mi->setParameter("emissiveIndex", getUvIndex(config->emissiveUV, config->hasEmissiveTexture)); + + mi->setDoubleSided(config->doubleSided); + mi->setCullingMode(config->doubleSided ? CullingMode::NONE : CullingMode::BACK); + mi->setTransparencyMode(config->doubleSided ? + MaterialInstance::TransparencyMode::TWO_PASSES_TWO_SIDES : + MaterialInstance::TransparencyMode::DEFAULT); + + #if !GLTFIO_LITE + + // Initially, assume that the clear coat texture can be honored. This is changed to false when + // running into a sampler count limitation. TODO: check if these constraints can now be relaxed. + bool clearCoatNeedsTexture = true; + + mat3f identity; + mi->setParameter("baseColorUvMatrix", identity); + mi->setParameter("metallicRoughnessUvMatrix", identity); + mi->setParameter("normalUvMatrix", identity); + mi->setParameter("occlusionUvMatrix", identity); + mi->setParameter("emissiveUvMatrix", identity); + + if (config->hasClearCoat) { + mi->setParameter("clearCoatIndex", + getUvIndex(config->clearCoatUV, config->hasClearCoatTexture)); + mi->setParameter("clearCoatRoughnessIndex", + getUvIndex(config->clearCoatRoughnessUV, config->hasClearCoatRoughnessTexture)); + mi->setParameter("clearCoatNormalIndex", + getUvIndex(config->clearCoatNormalUV, config->hasClearCoatNormalTexture)); + mi->setParameter("clearCoatUvMatrix", identity); + mi->setParameter("clearCoatRoughnessUvMatrix", identity); + mi->setParameter("clearCoatNormalUvMatrix", identity); + } else { + if (config->hasSheen) { + clearCoatNeedsTexture = false; + mi->setParameter("sheenColorIndex", + getUvIndex(config->sheenColorUV, config->hasSheenColorTexture)); + mi->setParameter("sheenRoughnessIndex", + getUvIndex(config->sheenRoughnessUV, config->hasSheenRoughnessTexture)); + mi->setParameter("sheenColorUvMatrix", identity); + mi->setParameter("sheenRoughnessUvMatrix", identity); + + } + if (config->hasVolume) { + clearCoatNeedsTexture = false; + mi->setParameter("volumeThicknessUvMatrix", identity); + mi->setParameter("volumeThicknessIndex", + getUvIndex(config->transmissionUV, config->hasVolumeThicknessTexture)); + } + if (config->hasTransmission) { + clearCoatNeedsTexture = false; + mi->setParameter("transmissionUvMatrix", identity); + mi->setParameter("transmissionIndex", + getUvIndex(config->transmissionUV, config->hasTransmissionTexture)); + } + } + #else + + // In the GLTFIO_LITE configuration we do not support UV matrices, clear coat, sheen, specular + // glossiness, or transmission. For more details, see `gltflite.mat.in`. To configure a custom + // set of features, create your own MaterialProvider class, perhaps using UbershaderLoader as a + // starting point. + const bool clearCoatNeedsTexture = false; + + #endif + + TextureSampler sampler; + mi->setParameter("normalMap", mDummyTexture, sampler); + mi->setParameter("baseColorMap", mDummyTexture, sampler); + mi->setParameter("metallicRoughnessMap", mDummyTexture, sampler); + mi->setParameter("occlusionMap", mDummyTexture, sampler); + mi->setParameter("emissiveMap", mDummyTexture, sampler); + if (clearCoatNeedsTexture) { + mi->setParameter("clearCoatMap", mDummyTexture, sampler); + mi->setParameter("clearCoatRoughnessMap", mDummyTexture, sampler); + mi->setParameter("clearCoatNormalMap", mDummyTexture, sampler); + } + if (!config->hasClearCoat) { + if (config->hasTransmission) { + mi->setParameter("transmissionMap", mDummyTexture, sampler); + } + if (config->hasSheen) { + mi->setParameter("sheenColorMap", mDummyTexture, sampler); + mi->setParameter("sheenRoughnessMap", mDummyTexture, sampler); + } + } + + if (mi->getMaterial()->hasParameter("ior")) { + mi->setParameter("ior", 1.5f); + } + if (mi->getMaterial()->hasParameter("reflectance")) { + mi->setParameter("reflectance", 0.5f); + } + + return mi; +} + +} // anonymous namespace + +namespace foo { + +MaterialProvider* createUbershaderLoader(filament::Engine* engine) { + return new UbershaderLoader(engine); +} + +} // namespace gltfio diff --git a/lib/filament_controller.dart b/lib/filament_controller.dart index 0e6548c7..d287917a 100644 --- a/lib/filament_controller.dart +++ b/lib/filament_controller.dart @@ -19,7 +19,12 @@ abstract class FilamentController { Future releaseSourceAssets(); Future playAnimation(int index); - // Weights is expected to be a contiguous sequence of floats of size W*F, where W is the number of weights and F is the number of frames + /// + /// Set the weights of all morph targets in the mesh to the specified weights at successive frames (where [framerate] is the number of times per second the weights should be updated). + /// Accepts a list of doubles representing a sequence of "frames", stacked end-to-end. + /// Each frame is [numWeights] in length, where each entry is the weight to be applied to the morph target located at that index in the mesh primitive at that frame. + /// In other words, weights is a contiguous sequence of floats of size W*F, where W is the number of weights and F is the number of frames + /// Future animate(List weights, int numWeights, double frameRate); Future createMorpher(String meshName, List primitives); Future zoom(double z); @@ -28,12 +33,10 @@ abstract class FilamentController { class HolovoxFilamentController extends FilamentController { late int _id; late MethodChannel _channel; - final String materialPath; + final Function(int id)? onFilamentViewCreatedHandler; - HolovoxFilamentController( - {this.materialPath = "packages/holovox_filament/assets/compiled.mat", - this.onFilamentViewCreatedHandler}); + HolovoxFilamentController({this.onFilamentViewCreatedHandler}); @override void onFilamentViewCreated(int id) async { @@ -51,7 +54,10 @@ class HolovoxFilamentController extends FilamentController { @override Future _initialize() async { - await _channel.invokeMethod("initialize", materialPath); + await _channel.invokeMethod("initialize", [ + "packages/holovox_filament/assets/lit_opaque.filamat", + "packages/holovox_filament/assets/lit_fade.filamat" + ]); } @override @@ -59,8 +65,9 @@ class HolovoxFilamentController extends FilamentController { await _channel.invokeMethod("loadSkybox", [skyboxPath, lightingPath]); } - Future loadGlb(String path) { - throw Exception(); + Future loadGlb(String path) async { + print("Loading GLB at $path "); + await _channel.invokeMethod("loadGlb", path); } Future loadGltf(String path, String relativeResourcePath) async {