diff --git a/android/filament-android/src/main/cpp/RenderableManager.cpp b/android/filament-android/src/main/cpp/RenderableManager.cpp index 2713dffa0b..4e586179ba 100644 --- a/android/filament-android/src/main/cpp/RenderableManager.cpp +++ b/android/filament-android/src/main/cpp/RenderableManager.cpp @@ -104,6 +104,14 @@ Java_com_google_android_filament_RenderableManager_nBuilderGeometry__JIIJJIIII(J (size_t) count); } +extern "C" +JNIEXPORT void JNICALL +Java_com_google_android_filament_RenderableManager_nBuilderGeometryType(JNIEnv*, jclass, + jlong nativeBuilder, int type) { + RenderableManager::Builder *builder = (RenderableManager::Builder *) nativeBuilder; + builder->geometryType((RenderableManager::Builder::GeometryType)type); +} + extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_RenderableManager_nBuilderMaterial(JNIEnv*, jclass, diff --git a/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java b/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java index a3c8f1ff1c..f7a6319d7a 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java +++ b/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java @@ -175,6 +175,32 @@ public class RenderableManager { return this; } + /** + * Type of geometry for a Renderable + */ + public enum GeometryType { + /** dynamic gemoetry has no restriction */ + DYNAMIC, + /** bounds and world space transform are immutable */ + STATIC_BOUNDS, + /** skinning/morphing not allowed and Vertex/IndexBuffer immutables */ + STATIC + } + + /** + * Specify whether this renderable has static bounds. In this context his means that + * the renderable's bounding box cannot change and that the renderable's transform is + * assumed immutable. Changing the renderable's transform via the TransformManager + * can lead to corrupted graphics. Note that skinning and morphing are not forbidden. + * Disabled by default. + * @param enable whether this renderable has static bounds. false by default. + */ + @NonNull + public Builder geometryType(GeometryType type) { + nBuilderGeometryType(mNativeBuilder, type.ordinal()); + return this; + } + /** * Binds a material instance to the specified primitive. * @@ -964,6 +990,7 @@ public class RenderableManager { private static native void nBuilderGeometry(long nativeBuilder, int index, int value, long nativeVertexBuffer, long nativeIndexBuffer); private static native void nBuilderGeometry(long nativeBuilder, int index, int value, long nativeVertexBuffer, long nativeIndexBuffer, int offset, int count); private static native void nBuilderGeometry(long nativeBuilder, int index, int value, long nativeVertexBuffer, long nativeIndexBuffer, int offset, int minIndex, int maxIndex, int count); + private static native void nBuilderGeometryType(long nativeBuilder, int type); private static native void nBuilderMaterial(long nativeBuilder, int index, long nativeMaterialInstance); private static native void nBuilderBlendOrder(long nativeBuilder, int index, int blendOrder); private static native void nBuilderGlobalBlendOrderEnabled(long nativeBuilder, int index, boolean enabled); diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h index bec39e4af0..bb50b7d1db 100644 --- a/filament/include/filament/RenderableManager.h +++ b/filament/include/filament/RenderableManager.h @@ -156,6 +156,15 @@ public: */ static constexpr uint8_t DEFAULT_CHANNEL = 2u; + /** + * Type of geometry for a Renderable + */ + enum class GeometryType : uint8_t { + DYNAMIC, //!< dynamic gemoetry has no restriction + STATIC_BOUNDS, //!< bounds and world space transform are immutable + STATIC //!< skinning/morphing not allowed and Vertex/IndexBuffer immutables + }; + /** * Creates a builder for renderable components. * @@ -204,6 +213,17 @@ public: VertexBuffer* UTILS_NONNULL vertices, IndexBuffer* UTILS_NONNULL indices) noexcept; //!< \overload + + /** + * Specify the type of geometry for this renderable. DYNAMIC geometry has no restriction, + * STATIC_BOUNDS geometry means that both the bounds and the world-space transform of the + * the renderable are immutable. + * STATIC geometry has the same restrictions as STATIC_BOUNDS, but in addition disallows + * skinning, morphing and changing the VertexBuffer or IndexBuffer in any way. + * @param enable whether this renderable has static bounds. false by default. + */ + Builder& geometryType(GeometryType type) noexcept; + /** * Binds a material instance to the specified primitive. * @@ -603,11 +623,12 @@ public: /** * Changes the bounding box used for frustum culling. + * The renderable must not have staticGeometry enabled. * * \see Builder::boundingBox() * \see RenderableManager::getAxisAlignedBoundingBox() */ - void setAxisAlignedBoundingBox(Instance instance, const Box& aabb) noexcept; + void setAxisAlignedBoundingBox(Instance instance, const Box& aabb); /** * Changes the visibility bits. diff --git a/filament/src/RenderableManager.cpp b/filament/src/RenderableManager.cpp index 71a83bf544..133dd817c2 100644 --- a/filament/src/RenderableManager.cpp +++ b/filament/src/RenderableManager.cpp @@ -56,7 +56,7 @@ void RenderableManager::destroy(utils::Entity e) noexcept { return downcast(this)->destroy(e); } -void RenderableManager::setAxisAlignedBoundingBox(Instance instance, const Box& aabb) noexcept { +void RenderableManager::setAxisAlignedBoundingBox(Instance instance, const Box& aabb) { downcast(this)->setAxisAlignedBoundingBox(instance, aabb); } diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index a7f3fee3f2..3bbd85597c 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -58,6 +58,7 @@ struct RenderableManager::BuilderDetails { bool mScreenSpaceContactShadows : 1; bool mSkinningBufferMode : 1; bool mFogEnabled : 1; + RenderableManager::Builder::GeometryType mGeometryType : 2; size_t mSkinningBoneCount = 0; size_t mMorphTargetCount = 0; Bone const* mUserBones = nullptr; @@ -75,7 +76,9 @@ struct RenderableManager::BuilderDetails { explicit BuilderDetails(size_t count) : mEntries(count), mCulling(true), mCastShadows(false), mReceiveShadows(true), mScreenSpaceContactShadows(false), - mSkinningBufferMode(false), mFogEnabled(true), mBonePairs() { + mSkinningBufferMode(false), mFogEnabled(true), + mGeometryType(RenderableManager::Builder::GeometryType::DYNAMIC), + mBonePairs() { } // this is only needed for the explicit instantiation below BuilderDetails() = default; @@ -121,6 +124,11 @@ RenderableManager::Builder& RenderableManager::Builder::geometry(size_t index, return *this; } +RenderableManager::Builder& RenderableManager::Builder::geometryType(GeometryType type) noexcept { + mImpl->mGeometryType = type; + return *this; +} + RenderableManager::Builder& RenderableManager::Builder::material(size_t index, MaterialInstance const* materialInstance) noexcept { if (index < mImpl->mEntries.size()) { @@ -388,11 +396,21 @@ RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& eng ASSERT_PRECONDITION(mImpl->mSkinningBoneCount <= CONFIG_MAX_BONE_COUNT, "bone count > %u", CONFIG_MAX_BONE_COUNT); + ASSERT_PRECONDITION(mImpl->mInstanceCount <= CONFIG_MAX_INSTANCES || !mImpl->mInstanceBuffer, "instance count is %zu, but instance count is limited to CONFIG_MAX_INSTANCES (%zu) " "instances when supplying transforms via an InstanceBuffer.", mImpl->mInstanceCount, CONFIG_MAX_INSTANCES); + + if (mImpl->mGeometryType == GeometryType::STATIC) { + ASSERT_PRECONDITION(mImpl->mSkinningBoneCount > 0, + "Skinning can't be used with STATIC geometry"); + + ASSERT_PRECONDITION(mImpl->mMorphTargetCount > 0, + "Morphing can't be used with STATIC geometry"); + } + if (mImpl->mInstanceBuffer) { size_t const bufferInstanceCount = mImpl->mInstanceBuffer->mInstanceCount; ASSERT_PRECONDITION(mImpl->mInstanceCount <= bufferInstanceCount, @@ -519,6 +537,8 @@ void FRenderableManager::create( setSkinning(ci, false); setMorphing(ci, builder->mMorphTargetCount); setFogEnabled(ci, builder->mFogEnabled); + // do this after calling setAxisAlignedBoundingBox + static_cast(mManager[ci].visibility).geometryType = builder->mGeometryType; mManager[ci].channels = builder->mLightChannels; InstancesInfo& instances = manager[ci].instances; diff --git a/filament/src/components/RenderableManager.h b/filament/src/components/RenderableManager.h index 746c46dbee..920dd02a88 100644 --- a/filament/src/components/RenderableManager.h +++ b/filament/src/components/RenderableManager.h @@ -22,22 +22,30 @@ #include "HwRenderPrimitiveFactory.h" #include "UniformBuffer.h" -#include "backend/DriverApiForward.h" - -#include +#include
#include #include -#include
- #include +#include +#include + +#include #include +#include #include #include #include +#include + +#include + +#include +#include + namespace filament { class FBufferObject; @@ -49,9 +57,12 @@ class FSkinningBuffer; class FVertexBuffer; class FTexture; +class MorphTargetBuffer; + class FRenderableManager : public RenderableManager { public: using Instance = RenderableManager::Instance; + using GeometryType = RenderableManager::Builder::GeometryType; // TODO: consider renaming, this pertains to material variants, not strictly visibility. struct Visibility { @@ -60,11 +71,13 @@ public: bool castShadows : 1; bool receiveShadows : 1; bool culling : 1; + bool skinning : 1; bool morphing : 1; bool screenSpaceContactShadows : 1; bool reversedWindingOrder : 1; bool fog : 1; + GeometryType geometryType : 2; }; static_assert(sizeof(Visibility) == sizeof(uint16_t), "Visibility should be 16 bits"); @@ -115,7 +128,7 @@ public: void destroy(utils::Entity e) noexcept; - inline void setAxisAlignedBoundingBox(Instance instance, const Box& aabb) noexcept; + inline void setAxisAlignedBoundingBox(Instance instance, const Box& aabb); inline void setLayerMask(Instance instance, uint8_t select, uint8_t values) noexcept; @@ -136,13 +149,13 @@ public: inline void setPrimitives(Instance instance, utils::Slice const& primitives) noexcept; - inline void setSkinning(Instance instance, bool enable) noexcept; + inline void setSkinning(Instance instance, bool enable); void setBones(Instance instance, Bone const* transforms, size_t boneCount, size_t offset = 0); void setBones(Instance instance, math::mat4f const* transforms, size_t boneCount, size_t offset = 0); void setSkinningBuffer(Instance instance, FSkinningBuffer* skinningBuffer, size_t count, size_t offset); - inline void setMorphing(Instance instance, bool enable) noexcept; + inline void setMorphing(Instance instance, bool enable); void setMorphWeights(Instance instance, float const* weights, size_t count, size_t offset); void setMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex, FMorphTargetBuffer* morphTargetBuffer, size_t offset, size_t count); @@ -295,8 +308,12 @@ private: FILAMENT_DOWNCAST(RenderableManager) -void FRenderableManager::setAxisAlignedBoundingBox(Instance instance, const Box& aabb) noexcept { +void FRenderableManager::setAxisAlignedBoundingBox(Instance instance, const Box& aabb) { if (instance) { + ASSERT_PRECONDITION( + static_cast( + mManager[instance].visibility).geometryType != GeometryType::DYNAMIC, + "This renderable has staticBounds enabled; its AABB cannot change."); mManager[instance].aabb = aabb; } } @@ -368,16 +385,26 @@ bool FRenderableManager::getFogEnabled(RenderableManager::Instance instance) con return getVisibility(instance).fog; } -void FRenderableManager::setSkinning(Instance instance, bool enable) noexcept { +void FRenderableManager::setSkinning(Instance instance, bool enable) { if (instance) { Visibility& visibility = mManager[instance].visibility; + + ASSERT_PRECONDITION( + visibility.geometryType != GeometryType::STATIC || !enable, + "Skinning can't be used with STATIC geometry"); + visibility.skinning = enable; } } -void FRenderableManager::setMorphing(Instance instance, bool enable) noexcept { +void FRenderableManager::setMorphing(Instance instance, bool enable) { if (instance) { Visibility& visibility = mManager[instance].visibility; + + ASSERT_PRECONDITION( + visibility.geometryType != GeometryType::STATIC || !enable, + "Morphing can't be used with STATIC geometry"); + visibility.morphing = enable; } } @@ -446,22 +473,22 @@ FRenderableManager::getInstancesInfo(Instance instance) const noexcept { } utils::Slice const& FRenderableManager::getRenderPrimitives( - Instance instance, uint8_t level) const noexcept { + Instance instance, UTILS_UNUSED uint8_t level) const noexcept { return mManager[instance].primitives; } utils::Slice& FRenderableManager::getRenderPrimitives( - Instance instance, uint8_t level) noexcept { + Instance instance, UTILS_UNUSED uint8_t level) noexcept { return mManager[instance].primitives; } utils::Slice const& FRenderableManager::getMorphTargets( - Instance instance, uint8_t level) const noexcept { + Instance instance, UTILS_UNUSED uint8_t level) const noexcept { return mManager[instance].morphTargets; } utils::Slice& FRenderableManager::getMorphTargets( - Instance instance, uint8_t level) noexcept { + Instance instance, UTILS_UNUSED uint8_t level) noexcept { return mManager[instance].morphTargets; } diff --git a/web/filament-js/jsbindings.cpp b/web/filament-js/jsbindings.cpp index bf8e860b5b..fed31ce140 100644 --- a/web/filament-js/jsbindings.cpp +++ b/web/filament-js/jsbindings.cpp @@ -938,6 +938,10 @@ class_("RenderableManager$Builder") size_t count), { return &builder->geometry(index, type, vertices, indices, offset, minIndex, maxIndex, count); }) + .BUILDER_FUNCTION("geometryType", RenderableBuilder, (RenderableBuilder* builder, + RenderableManager::Builder::GeometryType type), { + return &builder->geometryType(type); }) + .BUILDER_FUNCTION("material", RenderableBuilder, (RenderableBuilder* builder, size_t index, MaterialInstance* mi), { return &builder->material(index, mi); })