From 00803c35ab8cd779ada3e9b81c2c04484d00e1ca Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Sun, 18 Feb 2024 15:22:47 +0800 Subject: [PATCH] rename AssetManager to SceneManager, add camera FOV/antialiasing methods, do symmetric AABB checking for collisions --- ios/include/FilamentViewer.hpp | 12 +- ios/include/FlutterFilamentApi.h | 69 ++--- .../{AssetManager.hpp => SceneManager.hpp} | 12 +- ios/include/components/StandardComponents.h | 85 +++--- ios/src/FilamentViewer.cpp | 58 ++-- .../{AssetManager.cpp => SceneManager.cpp} | 265 +++++++++++++----- lib/filament_controller.dart | 49 +++- lib/filament_controller_ffi.dart | 130 ++++++--- 8 files changed, 450 insertions(+), 230 deletions(-) rename ios/include/{AssetManager.hpp => SceneManager.hpp} (92%) rename ios/src/{AssetManager.cpp => SceneManager.cpp} (84%) diff --git a/ios/include/FilamentViewer.hpp b/ios/include/FilamentViewer.hpp index 297bd176..8324e1e8 100644 --- a/ios/include/FilamentViewer.hpp +++ b/ios/include/FilamentViewer.hpp @@ -32,7 +32,7 @@ #include #include -#include "AssetManager.hpp" +#include "SceneManager.hpp" #include "ThreadPool.hpp" using namespace std; @@ -82,6 +82,8 @@ namespace polyvox void setFrameInterval(float interval); bool setCamera(EntityId asset, const char *nodeName); + void setMainCamera(); + void setCameraFov(double fovDegrees, double aspect); void createSwapChain(const void *surface, uint32_t width, uint32_t height); void destroySwapChain(); @@ -131,11 +133,13 @@ namespace polyvox void setRecording(bool recording); void setRecordingOutputDirectory(const char* path); + void setAntiAliasing(bool msaaEnabled, bool fxaaEnabled, bool taaEnabled); + EntityId createGeometry(float* vertices, uint32_t numVertices, uint16_t* indices, uint32_t numIndices, const char* materialPath); - AssetManager *const getAssetManager() + SceneManager *const getSceneManager() { - return (AssetManager *const)_assetManager; + return (SceneManager *const)_sceneManager; } private: @@ -152,7 +156,7 @@ namespace polyvox SwapChain *_swapChain = nullptr; - AssetManager *_assetManager = nullptr; + SceneManager *_sceneManager = nullptr; NameComponentManager *_ncm = nullptr; diff --git a/ios/include/FlutterFilamentApi.h b/ios/include/FlutterFilamentApi.h index 170f79d8..e5ded8e0 100644 --- a/ios/include/FlutterFilamentApi.h +++ b/ios/include/FlutterFilamentApi.h @@ -57,7 +57,7 @@ extern "C" FLUTTER_PLUGIN_EXPORT const void *create_filament_viewer(const void *const context, const ResourceLoaderWrapper *const loader, void *const platform, const char *uberArchivePath); FLUTTER_PLUGIN_EXPORT void destroy_filament_viewer(const void *const viewer); FLUTTER_PLUGIN_EXPORT ResourceLoaderWrapper *make_resource_loader(LoadFilamentResourceFromOwner loadFn, FreeFilamentResourceFromOwner freeFn, void *owner); - FLUTTER_PLUGIN_EXPORT void *get_asset_manager(const void *const viewer); + FLUTTER_PLUGIN_EXPORT void *get_scene_manager(const void *const viewer); FLUTTER_PLUGIN_EXPORT void create_render_target(const void *const viewer, intptr_t texture, uint32_t width, uint32_t height); FLUTTER_PLUGIN_EXPORT void clear_background_image(const void *const viewer); FLUTTER_PLUGIN_EXPORT void set_background_image(const void *const viewer, const char *path, bool fillHeight); @@ -73,8 +73,9 @@ extern "C" FLUTTER_PLUGIN_EXPORT EntityId add_light(const void *const viewer, uint8_t type, float colour, float intensity, float posX, float posY, float posZ, float dirX, float dirY, float dirZ, bool shadows); FLUTTER_PLUGIN_EXPORT void remove_light(const void *const viewer, EntityId entityId); FLUTTER_PLUGIN_EXPORT void clear_lights(const void *const viewer); - FLUTTER_PLUGIN_EXPORT EntityId load_glb(void *assetManager, const char *assetPath, bool unlit); - FLUTTER_PLUGIN_EXPORT EntityId load_gltf(void *assetManager, const char *assetPath, const char *relativePath); + FLUTTER_PLUGIN_EXPORT EntityId load_glb(void *sceneManager, const char *assetPath, bool unlit); + FLUTTER_PLUGIN_EXPORT EntityId load_gltf(void *sceneManager, const char *assetPath, const char *relativePath); + FLUTTER_PLUGIN_EXPORT void set_main_camera(const void *const viewer); FLUTTER_PLUGIN_EXPORT bool set_camera(const void *const viewer, EntityId asset, const char *nodeName); FLUTTER_PLUGIN_EXPORT void set_view_frustum_culling(const void *const viewer, bool enabled); FLUTTER_PLUGIN_EXPORT void render( @@ -94,19 +95,19 @@ extern "C" FLUTTER_PLUGIN_EXPORT void grab_update(const void *const viewer, float x, float y); FLUTTER_PLUGIN_EXPORT void grab_end(const void *const viewer); FLUTTER_PLUGIN_EXPORT void apply_weights( - void *assetManager, + void *sceneManager, EntityId asset, const char *const entityName, float *const weights, int count); FLUTTER_PLUGIN_EXPORT void set_morph_target_weights( - void *assetManager, + void *sceneManager, EntityId asset, const char *const entityName, const float *const morphData, int numWeights); FLUTTER_PLUGIN_EXPORT bool set_morph_animation( - void *assetManager, + void *sceneManager, EntityId asset, const char *const entityName, const float *const morphData, @@ -116,10 +117,10 @@ extern "C" float frameLengthInMs); FLUTTER_PLUGIN_EXPORT void reset_to_rest_pose( - void *assetManager, + void *sceneManager, EntityId asset); FLUTTER_PLUGIN_EXPORT void add_bone_animation( - void *assetManager, + void *sceneManager, EntityId asset, const float *const frameData, int numFrames, @@ -129,28 +130,28 @@ extern "C" float frameLengthInMs, bool isModelSpace); FLUTTER_PLUGIN_EXPORT bool set_bone_transform( - void *assetManager, + void *sceneManager, EntityId asset, const char *entityName, const float *const transform, const char *boneName); - FLUTTER_PLUGIN_EXPORT void play_animation(void *assetManager, EntityId asset, int index, bool loop, bool reverse, bool replaceActive, float crossfade); - FLUTTER_PLUGIN_EXPORT void set_animation_frame(void *assetManager, EntityId asset, int animationIndex, int animationFrame); - FLUTTER_PLUGIN_EXPORT void stop_animation(void *assetManager, EntityId asset, int index); - FLUTTER_PLUGIN_EXPORT int get_animation_count(void *assetManager, EntityId asset); - FLUTTER_PLUGIN_EXPORT void get_animation_name(void *assetManager, EntityId asset, char *const outPtr, int index); - FLUTTER_PLUGIN_EXPORT float get_animation_duration(void *assetManager, EntityId asset, int index); - FLUTTER_PLUGIN_EXPORT void get_morph_target_name(void *assetManager, EntityId asset, const char *meshName, char *const outPtr, int index); - FLUTTER_PLUGIN_EXPORT int get_morph_target_name_count(void *assetManager, EntityId asset, const char *meshName); + FLUTTER_PLUGIN_EXPORT void play_animation(void *sceneManager, EntityId asset, int index, bool loop, bool reverse, bool replaceActive, float crossfade); + FLUTTER_PLUGIN_EXPORT void set_animation_frame(void *sceneManager, EntityId asset, int animationIndex, int animationFrame); + FLUTTER_PLUGIN_EXPORT void stop_animation(void *sceneManager, EntityId asset, int index); + FLUTTER_PLUGIN_EXPORT int get_animation_count(void *sceneManager, EntityId asset); + FLUTTER_PLUGIN_EXPORT void get_animation_name(void *sceneManager, EntityId asset, char *const outPtr, int index); + FLUTTER_PLUGIN_EXPORT float get_animation_duration(void *sceneManager, EntityId asset, int index); + FLUTTER_PLUGIN_EXPORT void get_morph_target_name(void *sceneManager, EntityId asset, const char *meshName, char *const outPtr, int index); + FLUTTER_PLUGIN_EXPORT int get_morph_target_name_count(void *sceneManager, EntityId asset, const char *meshName); FLUTTER_PLUGIN_EXPORT void remove_entity(const void *const viewer, EntityId asset); FLUTTER_PLUGIN_EXPORT void clear_entities(const void *const viewer); - FLUTTER_PLUGIN_EXPORT bool set_material_color(void *assetManager, EntityId asset, const char *meshName, int materialIndex, const float r, const float g, const float b, const float a); - FLUTTER_PLUGIN_EXPORT void transform_to_unit_cube(void *assetManager, EntityId asset); - FLUTTER_PLUGIN_EXPORT void queue_position_update(void *assetManager, EntityId asset, float x, float y, float z, bool relative); - FLUTTER_PLUGIN_EXPORT void queue_rotation_update(void *assetManager, EntityId asset, float rads, float x, float y, float z, float w, bool relative); - FLUTTER_PLUGIN_EXPORT void set_position(void *assetManager, EntityId asset, float x, float y, float z); - FLUTTER_PLUGIN_EXPORT void set_rotation(void *assetManager, EntityId asset, float rads, float x, float y, float z, float w); - FLUTTER_PLUGIN_EXPORT void set_scale(void *assetManager, EntityId asset, float scale); + FLUTTER_PLUGIN_EXPORT bool set_material_color(void *sceneManager, EntityId asset, const char *meshName, int materialIndex, const float r, const float g, const float b, const float a); + FLUTTER_PLUGIN_EXPORT void transform_to_unit_cube(void *sceneManager, EntityId asset); + FLUTTER_PLUGIN_EXPORT void queue_position_update(void *sceneManager, EntityId asset, float x, float y, float z, bool relative); + FLUTTER_PLUGIN_EXPORT void queue_rotation_update(void *sceneManager, EntityId asset, float rads, float x, float y, float z, float w, bool relative); + FLUTTER_PLUGIN_EXPORT void set_position(void *sceneManager, EntityId asset, float x, float y, float z); + FLUTTER_PLUGIN_EXPORT void set_rotation(void *sceneManager, EntityId asset, float rads, float x, float y, float z, float w); + FLUTTER_PLUGIN_EXPORT void set_scale(void *sceneManager, EntityId asset, float scale); // Camera methods FLUTTER_PLUGIN_EXPORT void move_camera_to_asset(const void *const viewer, EntityId asset); @@ -169,25 +170,29 @@ extern "C" FLUTTER_PLUGIN_EXPORT double get_camera_culling_far(const void *const viewer); FLUTTER_PLUGIN_EXPORT const double *const get_camera_culling_projection_matrix(const void *const viewer); FLUTTER_PLUGIN_EXPORT const double *const get_camera_frustum(const void *const viewer); + FLUTTER_PLUGIN_EXPORT void set_camera_fov(const void *const viewer, float fovInDegrees, float aspect); FLUTTER_PLUGIN_EXPORT void set_camera_focal_length(const void *const viewer, float focalLength); FLUTTER_PLUGIN_EXPORT void set_camera_focus_distance(const void *const viewer, float focusDistance); FLUTTER_PLUGIN_EXPORT void set_camera_manipulator_options(const void *const viewer, _ManipulatorMode mode, double orbitSpeedX, double orbitSpeedY, double zoomSpeed); - FLUTTER_PLUGIN_EXPORT int hide_mesh(void *assetManager, EntityId asset, const char *meshName); - FLUTTER_PLUGIN_EXPORT int reveal_mesh(void *assetManager, EntityId asset, const char *meshName); + FLUTTER_PLUGIN_EXPORT int hide_mesh(void *sceneManager, EntityId asset, const char *meshName); + FLUTTER_PLUGIN_EXPORT int reveal_mesh(void *sceneManager, EntityId asset, const char *meshName); FLUTTER_PLUGIN_EXPORT void set_post_processing(void *const viewer, bool enabled); + FLUTTER_PLUGIN_EXPORT void set_antialiasing(void *const viewer, bool msaa, bool fxaa, bool taa); FLUTTER_PLUGIN_EXPORT void pick(void *const viewer, int x, int y, EntityId *entityId); - FLUTTER_PLUGIN_EXPORT const char *get_name_for_entity(void *const assetManager, const EntityId entityId); - FLUTTER_PLUGIN_EXPORT EntityId find_child_entity_by_name(void *const assetManager, const EntityId parent, const char* name); - FLUTTER_PLUGIN_EXPORT int get_entity_count(void *const assetManager, const EntityId target, bool renderableOnly); - FLUTTER_PLUGIN_EXPORT const char* get_entity_name_at(void *const assetManager, const EntityId target, int index, bool renderableOnly); + FLUTTER_PLUGIN_EXPORT const char *get_name_for_entity(void *const sceneManager, const EntityId entityId); + FLUTTER_PLUGIN_EXPORT EntityId find_child_entity_by_name(void *const sceneManager, const EntityId parent, const char* name); + FLUTTER_PLUGIN_EXPORT int get_entity_count(void *const sceneManager, const EntityId target, bool renderableOnly); + FLUTTER_PLUGIN_EXPORT const char* get_entity_name_at(void *const sceneManager, const EntityId target, int index, bool renderableOnly); FLUTTER_PLUGIN_EXPORT void set_recording(void *const viewer, bool recording); FLUTTER_PLUGIN_EXPORT void set_recording_output_directory(void *const viewer, const char* outputDirectory); FLUTTER_PLUGIN_EXPORT void ios_dummy(); FLUTTER_PLUGIN_EXPORT void flutter_filament_free(void *ptr); - FLUTTER_PLUGIN_EXPORT void add_collision_component(void *const assetManager, EntityId entityId, void (*callback)(const EntityId entityId), bool affectsCollidingTransform); + FLUTTER_PLUGIN_EXPORT void add_collision_component(void *const sceneManager, EntityId entityId, void (*callback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform); + FLUTTER_PLUGIN_EXPORT void mark_nontransformable_collidable(void *const sceneManager, EntityId entityId); + FLUTTER_PLUGIN_EXPORT void unmark_nontransformable_collidable(void *const sceneManager, EntityId entityId); FLUTTER_PLUGIN_EXPORT EntityId create_geometry(void *const viewer, float* vertices, int numVertices, uint16_t* indices, int numIndices, const char* materialPath); - FLUTTER_PLUGIN_EXPORT void set_parent(void *const assetManager, EntityId child, EntityId parent); + FLUTTER_PLUGIN_EXPORT void set_parent(void *const sceneManager, EntityId child, EntityId parent); #ifdef __cplusplus } diff --git a/ios/include/AssetManager.hpp b/ios/include/SceneManager.hpp similarity index 92% rename from ios/include/AssetManager.hpp rename to ios/include/SceneManager.hpp index 56d0c1c9..c72af09c 100644 --- a/ios/include/AssetManager.hpp +++ b/ios/include/SceneManager.hpp @@ -19,15 +19,15 @@ namespace polyvox using namespace filament; using namespace filament::gltfio; - class AssetManager + class SceneManager { public: - AssetManager(const ResourceLoaderWrapper *const loader, + SceneManager(const ResourceLoaderWrapper *const loader, NameComponentManager *ncm, Engine *engine, Scene *scene, const char *uberArchivePath); - ~AssetManager(); + ~SceneManager(); EntityId loadGltf(const char *uri, const char *relativeResourcePath); EntityId loadGlb(const char *uri, bool unlit); FilamentAsset *getAssetByEntityId(EntityId entityId); @@ -103,8 +103,11 @@ namespace polyvox const char *entityName); int getEntityCount(EntityId entity, bool renderableOnly); const char* getEntityNameAt(EntityId entity, int index, bool renderableOnly); - void addCollisionComponent(EntityId entity, void (*onCollisionCallback)(EntityId entityId), bool affectsCollidingTransform); + void addCollisionComponent(EntityId entity, void (*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform); void removeCollisionComponent(EntityId entityId); + void markNonTransformableCollidable(EntityId entity); + void unmarkNonTransformableCollidable(EntityId entity); + void checkNonTransformableCollisions(); void setParent(EntityId child, EntityId parent); private: @@ -122,6 +125,7 @@ namespace polyvox vector _assets; tsl::robin_map _entityIdLookup; tsl::robin_map> _transformUpdates; + std::vector _nonTransformableCollidableEntities; CollisionComponentManager* _collisionComponentManager = nullptr; diff --git a/ios/include/components/StandardComponents.h b/ios/include/components/StandardComponents.h index cf16261e..31da4ab4 100644 --- a/ios/include/components/StandardComponents.h +++ b/ios/include/components/StandardComponents.h @@ -12,14 +12,14 @@ namespace polyvox { -typedef void(*CollisionCallback)(int32_t entityId) ; +typedef void(*CollisionCallback)(int32_t entityId1, int32_t entityId2) ; class CollisionComponentManager : public utils::SingleInstanceComponentManager { const filament::TransformManager& _transformManager; public: CollisionComponentManager(const filament::TransformManager& transformManager) : _transformManager(transformManager) {} - std::vector collides(filament::Aabb sourceBox) { + std::vector collides(EntityId transformingEntityId, filament::Aabb sourceBox) { auto sourceCorners = sourceBox.getCorners(); std::vector collisionAxes; for(auto it = begin(); it < end(); it++) { @@ -27,52 +27,63 @@ class CollisionComponentManager : public utils::SingleInstanceComponentManager(it).transform(targetXform); + auto targetCorners = targetBox.getCorners(); + + // Log("Checking collision for entity %d with aabb extent %f %f %f against source entity %d with aabb extent %f %f %f", entity, targetBox.extent().x, targetBox.extent().y, targetBox.extent().z, transformingEntityId, sourceBox.extent().x, sourceBox.extent().y, sourceBox.extent().z); bool collided = false; - // iterate over every vertex in the source AABB + // iterate over every vertex in the source/target AABB for(int i = 0; i < 8; i++) { - // if the vertex has insersected with the target AABB + auto intersecting = sourceCorners.vertices[i]; + auto min = targetBox.min; + auto max = targetBox.max; + + // if the vertex has insersected with the target/source AABB if(targetBox.contains(sourceCorners.vertices[i]) < 0) { - collided = true; - auto affectsCollidingTransform = elementAt<2>(it); - if(affectsCollidingTransform) { - auto intersecting = sourceCorners.vertices[i]; - auto min = targetBox.min; - auto max = targetBox.max; - - float xmin = min.x - intersecting.x; - float ymin = min.y - intersecting.y; - float zmin = min.z - intersecting.z; - float xmax = intersecting.x - max.x; - float ymax = intersecting.y - max.y; - float zmax = intersecting.z - max.z; - - auto maxD = std::max(xmin,std::max(ymin,std::max(zmin,std::max(xmax,std::max(ymax,zmax))))); - filament::math::float3 axis; - if(maxD == xmin) { - axis = {-1.0f,0.0f, 0.0f}; - } else if(maxD == ymin) { - axis = {0.0f,-1.0f, 0.0f}; - } else if(maxD == zmin) { - axis = {0.0f,0.0f, -1.0f}; - } else if(maxD == xmax) { - axis = {1.0f,0.0f, 0.0f}; - } else if(maxD == ymax) { - axis = {0.0f,1.0f, 0.0f}; - } else { - axis = { 0.0f, 0.0f, 1.0f}; - } - collisionAxes.push_back(axis); - } - break; + // Log("targetBox %f %f %f contains source vertex %f %f %f", targetBox.extent().x, targetBox.extent().y, targetBox.extent().z, sourceCorners.vertices[i].x, sourceCorners.vertices[i].y, sourceCorners.vertices[i].z); + } else if(sourceBox.contains(targetCorners.vertices[i]) < 0) { + // Log("sourceBox %f %f %f contains target vertex %f %f %f", sourceBox.extent().x, sourceBox.extent().y, sourceBox.extent().z, targetCorners.vertices[i].x, targetCorners.vertices[i].y, targetCorners.vertices[i].z); + collided = true; + intersecting = targetCorners.vertices[i]; + min = sourceBox.min; + max = sourceBox.max; + } else { + continue; } + auto affectsTransform = elementAt<2>(it); + if(affectsTransform) { + float xmin = min.x - intersecting.x; + float ymin = min.y - intersecting.y; + float zmin = min.z - intersecting.z; + float xmax = intersecting.x - max.x; + float ymax = intersecting.y - max.y; + float zmax = intersecting.z - max.z; + + auto maxD = std::max(xmin,std::max(ymin,std::max(zmin,std::max(xmax,std::max(ymax,zmax))))); + filament::math::float3 axis; + if(maxD == xmin) { + axis = {-1.0f,0.0f, 0.0f}; + } else if(maxD == ymin) { + axis = {0.0f,-1.0f, 0.0f}; + } else if(maxD == zmin) { + axis = {0.0f,0.0f, -1.0f}; + } else if(maxD == xmax) { + axis = {1.0f,0.0f, 0.0f}; + } else if(maxD == ymax) { + axis = {0.0f,1.0f, 0.0f}; + } else { + axis = { 0.0f, 0.0f, 1.0f}; + } + collisionAxes.push_back(axis); + } + break; } if(collided) { auto callback = elementAt<1>(it); if(callback) { - callback(utils::Entity::smuggle(entity)); + callback(utils::Entity::smuggle(entity), transformingEntityId); } } } diff --git a/ios/src/FilamentViewer.cpp b/ios/src/FilamentViewer.cpp index baded416..009b1484 100644 --- a/ios/src/FilamentViewer.cpp +++ b/ios/src/FilamentViewer.cpp @@ -199,18 +199,14 @@ namespace polyvox // options.quality = View::QualityLevel::ULTRA; _view->setDynamicResolutionOptions(options); - View::MultiSampleAntiAliasingOptions multiSampleAntiAliasingOptions; - multiSampleAntiAliasingOptions.enabled = true; - - _view->setMultiSampleAntiAliasingOptions(multiSampleAntiAliasingOptions); - - _view->setAntiAliasing(AntiAliasing::NONE); + setAntiAliasing(false, true, false); + EntityManager &em = EntityManager::get(); _ncm = new NameComponentManager(em); - _assetManager = new AssetManager( + _sceneManager = new SceneManager( _resourceLoaderWrapper, _ncm, _engine, @@ -271,7 +267,18 @@ namespace polyvox .culling(false) .build(*_engine, imageEntity); _imageEntity = &imageEntity; - // _scene->addEntity(imageEntity); + _scene->addEntity(imageEntity); + } + + void FilamentViewer::setAntiAliasing(bool msaa, bool fxaa, bool taa) { + View::MultiSampleAntiAliasingOptions multiSampleAntiAliasingOptions; + multiSampleAntiAliasingOptions.enabled = msaa; + + _view->setMultiSampleAntiAliasingOptions(multiSampleAntiAliasingOptions); + TemporalAntiAliasingOptions taaOpts; + taaOpts.enabled = taa; + _view->setTemporalAntiAliasingOptions(taaOpts); + _view->setAntiAliasing(fxaa ? AntiAliasing::FXAA : AntiAliasing::NONE); } void FilamentViewer::setPostProcessing(bool enabled) @@ -640,7 +647,7 @@ namespace polyvox FilamentViewer::~FilamentViewer() { clearEntities(); - delete _assetManager; + delete _sceneManager; for (auto it : _lights) { @@ -727,15 +734,8 @@ namespace polyvox void FilamentViewer::clearEntities() { - Log("Clearing all assets"); - if (_mainCamera) - { - _view->setCamera(_mainCamera); - } - - _assetManager->destroyAll(); - - Log("Cleared all assets"); + _view->setCamera(_mainCamera); + _sceneManager->destroyAll(); } void FilamentViewer::removeEntity(EntityId asset) @@ -744,8 +744,7 @@ namespace polyvox mtx.lock(); // todo - what if we are using a camera from this asset? - _view->setCamera(_mainCamera); - _assetManager->remove(asset); + _sceneManager->remove(asset); mtx.unlock(); } @@ -803,6 +802,10 @@ namespace polyvox cam.setFocusDistance(_cameraFocusDistance); } + void FilamentViewer::setMainCamera() { + _view->setCamera(_mainCamera); + } + /// /// Sets the active camera to the GLTF camera node specified by [name] (or if null, the first camera found under that node). /// N.B. Blender will generally export a three-node hierarchy - @@ -811,7 +814,7 @@ namespace polyvox bool FilamentViewer::setCamera(EntityId entityId, const char *cameraName) { - auto asset = _assetManager->getAssetByEntityId(entityId); + auto asset = _sceneManager->getAssetByEntityId(entityId); if (!asset) { Log("Failed to find asset under entity id %d.", entityId); @@ -1037,8 +1040,9 @@ namespace polyvox Timer tmr; - _assetManager->updateTransforms(); - _assetManager->updateAnimations(); + _sceneManager->updateTransforms(); + _sceneManager->updateAnimations(); + _sceneManager->checkNonTransformableCollisions(); _cumulativeAnimationUpdateTime += tmr.elapsed(); @@ -1214,6 +1218,12 @@ namespace polyvox _view->setFrustumCullingEnabled(enabled); } + void FilamentViewer::setCameraFov(double fovInDegrees, double aspect) { + Camera &cam = _view->getCamera(); + cam.setProjection(fovInDegrees, aspect, _near, _far, Camera::Fov::HORIZONTAL); + Log("Set camera projection fov to %f", fovInDegrees); + } + void FilamentViewer::setCameraPosition(float x, float y, float z) { Camera &cam = _view->getCamera(); @@ -1224,7 +1234,7 @@ namespace polyvox void FilamentViewer::moveCameraToAsset(EntityId entityId) { - auto asset = _assetManager->getAssetByEntityId(entityId); + auto asset = _sceneManager->getAssetByEntityId(entityId); if (!asset) { Log("Failed to find asset attached to specified entity id."); diff --git a/ios/src/AssetManager.cpp b/ios/src/SceneManager.cpp similarity index 84% rename from ios/src/AssetManager.cpp rename to ios/src/SceneManager.cpp index 616c00e0..db6023ca 100644 --- a/ios/src/AssetManager.cpp +++ b/ios/src/SceneManager.cpp @@ -20,7 +20,7 @@ #include "StreamBufferAdapter.hpp" #include "SceneAsset.hpp" #include "Log.hpp" -#include "AssetManager.hpp" +#include "SceneManager.hpp" #include "material/FileMaterialProvider.hpp" #include "gltfio/materials/uberarchive.h" @@ -40,7 +40,7 @@ namespace polyvox using namespace filament; using namespace filament::gltfio; - AssetManager::AssetManager(const ResourceLoaderWrapper *const resourceLoaderWrapper, + SceneManager::SceneManager(const ResourceLoaderWrapper *const resourceLoaderWrapper, NameComponentManager *ncm, Engine *engine, Scene *scene, @@ -86,7 +86,7 @@ namespace polyvox _collisionComponentManager = new CollisionComponentManager(tm); } - AssetManager::~AssetManager() + SceneManager::~SceneManager() { _gltfResourceLoader->asyncCancelLoad(); _ubershaderProvider->destroyMaterials(); @@ -94,7 +94,7 @@ namespace polyvox AssetLoader::destroy(&_assetLoader); } - EntityId AssetManager::loadGltf(const char *uri, + EntityId SceneManager::loadGltf(const char *uri, const char *relativeResourcePath) { ResourceBuffer rbuf = _resourceLoaderWrapper->load(uri); @@ -188,7 +188,7 @@ namespace polyvox return eid; } - EntityId AssetManager::loadGlb(const char *uri, bool unlit) + EntityId SceneManager::loadGlb(const char *uri, bool unlit) { ResourceBuffer rbuf = _resourceLoaderWrapper->load(uri); @@ -263,7 +263,7 @@ namespace polyvox return eid; } - bool AssetManager::hide(EntityId entityId, const char *meshName) + bool SceneManager::hide(EntityId entityId, const char *meshName) { auto asset = getAssetByEntityId(entityId); @@ -272,18 +272,29 @@ namespace polyvox return false; } - auto entity = findEntityByName(asset, meshName); + utils::Entity entity; - if (entity.isNull()) - { - Log("Mesh %s could not be found", meshName); - return false; + if(meshName) { + entity = findEntityByName(asset, meshName); + Log("Hiding child entity under name %s ", meshName); + if (entity.isNull()) { + Log("Failed to hide entity; specified mesh name does not exist under the target entity, or the target entity itself is no longer valid."); + return false; + } + _scene->remove(entity); + } else { + Log("Hiding all child entities"); + auto* entities = asset->getEntities(); + for(int i =0; i < asset->getEntityCount(); i++) { + auto entity = entities[i]; + _scene->remove(entity); + } } - _scene->remove(entity); + return true; } - bool AssetManager::reveal(EntityId entityId, const char *meshName) + bool SceneManager::reveal(EntityId entityId, const char *meshName) { auto asset = getAssetByEntityId(entityId); if (!asset) @@ -292,19 +303,30 @@ namespace polyvox return false; } - auto entity = findEntityByName(asset, meshName); + utils::Entity entity; - - if (entity.isNull()) - { - Log("Mesh %s could not be found", meshName); - return false; + if(meshName) { + entity = findEntityByName(asset, meshName); + if (entity.isNull()) + { + Log("Failed to reveal entity; specified mesh name does not exist under the target entity, or the target entity itself is no longer valid."); + return false; + } + _scene->addEntity(entity); + } else { + Log("Revealing all child entities"); + auto* entities = asset->getEntities(); + for(int i =0; i < asset->getEntityCount(); i++) { + auto entity = entities[i]; + _scene->addEntity(entity); + } } - _scene->addEntity(entity); + + return true; } - void AssetManager::destroyAll() + void SceneManager::destroyAll() { for (auto &asset : _assets) { @@ -317,7 +339,7 @@ namespace polyvox _assets.clear(); } - FilamentAsset *AssetManager::getAssetByEntityId(EntityId entityId) + FilamentAsset *SceneManager::getAssetByEntityId(EntityId entityId) { const auto &pos = _entityIdLookup.find(entityId); if (pos == _entityIdLookup.end()) @@ -327,7 +349,7 @@ namespace polyvox return _assets[pos->second].asset; } - void AssetManager::updateAnimations() + void SceneManager::updateAnimations() { std::lock_guard lock(_mutex); RenderableManager &rm = _engine->getRenderableManager(); @@ -459,7 +481,7 @@ namespace polyvox // TODO - we really don't want to be looking up the bone index/entity by name every single frame // - could use findChildEntityByName // - or is it better to add an option for "streaming" mode where we can just return a reference to a mat4 and then update the values directly? - bool AssetManager::setBoneTransform(EntityId entityId, const char *entityName, int32_t skinIndex, const char* boneName, math::mat4f localTransform) + bool SceneManager::setBoneTransform(EntityId entityId, const char *entityName, int32_t skinIndex, const char* boneName, math::mat4f localTransform) { std::lock_guard lock(_mutex); @@ -545,7 +567,7 @@ namespace polyvox return true; } - void AssetManager::remove(EntityId entityId) + void SceneManager::remove(EntityId entityId) { std::lock_guard lock(_mutex); const auto &pos = _entityIdLookup.find(entityId); @@ -567,13 +589,38 @@ namespace polyvox _entityIdLookup.erase(entityId); + auto entityCount = sceneAsset.asset->getEntityCount(); + const auto* entities = sceneAsset.asset->getEntities(); - _scene->removeEntities(sceneAsset.asset->getEntities(), - sceneAsset.asset->getEntityCount()); + auto entity = Entity::import(entityId); + + if(_collisionComponentManager->hasComponent(entity)) { + _collisionComponentManager->removeComponent(entity); + } + + for(int i = 0; i < entityCount; i++) { + auto entity = entities[i]; + if(_collisionComponentManager->hasComponent(entity)) { + _collisionComponentManager->removeComponent(entity); + } + } + auto root = sceneAsset.asset->getRoot(); + if(_collisionComponentManager->hasComponent(root)) { + _collisionComponentManager->removeComponent(root); + } + _nonTransformableCollidableEntities.erase(std::remove_if(_nonTransformableCollidableEntities.begin(), _nonTransformableCollidableEntities.end(), + [=](EntityId entityId2) + { return entityId == entityId2; }), + _nonTransformableCollidableEntities.end()); + + _scene->removeEntities(entities, entityCount); + auto lightCount =sceneAsset.asset->getLightEntityCount(); - if(lightCount > 0) { _scene->removeEntities(sceneAsset.asset->getLightEntities(), + if(lightCount > 0) { + _scene->removeEntities(sceneAsset.asset->getLightEntities(), sceneAsset.asset->getLightEntityCount()); } + _scene->remove(entity); _assetLoader->destroyAsset(sceneAsset.asset); @@ -582,14 +629,14 @@ namespace polyvox _engine->destroy(sceneAsset.texture); } EntityManager &em = EntityManager::get(); - em.destroy(Entity::import(entityId)); + em.destroy(entity); _assets.erase(std::remove_if(_assets.begin(), _assets.end(), [=](SceneAsset &asset) { return asset.asset == sceneAsset.asset; }), _assets.end()); } - void AssetManager::setMorphTargetWeights(EntityId entityId, const char *const entityName, const float *const weights, const int count) + void SceneManager::setMorphTargetWeights(EntityId entityId, const char *const entityName, const float *const weights, const int count) { const auto &pos = _entityIdLookup.find(entityId); if (pos == _entityIdLookup.end()) @@ -622,7 +669,7 @@ namespace polyvox count); } - utils::Entity AssetManager::findChildEntityByName(EntityId entityId, const char *entityName) { + utils::Entity SceneManager::findChildEntityByName(EntityId entityId, const char *entityName) { std::lock_guard lock(_mutex); const auto &pos = _entityIdLookup.find(entityId); @@ -644,7 +691,7 @@ namespace polyvox } - utils::Entity AssetManager::findEntityByName(SceneAsset asset, const char *entityName) + utils::Entity SceneManager::findEntityByName(SceneAsset asset, const char *entityName) { utils::Entity entity; for (size_t i = 0, c = asset.asset->getEntityCount(); i != c; ++i) @@ -668,7 +715,7 @@ namespace polyvox return entity; } - bool AssetManager::setMorphAnimationBuffer( + bool SceneManager::setMorphAnimationBuffer( EntityId entityId, const char *entityName, const float *const morphData, @@ -718,7 +765,7 @@ namespace polyvox return true; } - bool AssetManager::setMaterialColor(EntityId entityId, const char *meshName, int materialIndex, const float r, const float g, const float b, const float a) + bool SceneManager::setMaterialColor(EntityId entityId, const char *meshName, int materialIndex, const float r, const float g, const float b, const float a) { const auto &pos = _entityIdLookup.find(entityId); @@ -753,7 +800,7 @@ namespace polyvox return true; } - void AssetManager::resetBones(EntityId entityId) { + void SceneManager::resetBones(EntityId entityId) { std::lock_guard lock(_mutex); const auto &pos = _entityIdLookup.find(entityId); @@ -784,7 +831,7 @@ namespace polyvox } - bool AssetManager::addBoneAnimation(EntityId entityId, + bool SceneManager::addBoneAnimation(EntityId entityId, const float *const frameData, int numFrames, const char *const boneName, @@ -846,10 +893,7 @@ namespace polyvox math::quatf brot; math::float3 bscale; decomposeMatrix(bindMatrix, &btrans, &brot, &bscale); - // Log("Bind matrix for bone %s is \n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n", boneName, bindMatrix[0][0],bindMatrix[1][0],bindMatrix[2][0],bindMatrix[3][0], - // bindMatrix[0][1],bindMatrix[1][1],bindMatrix[2][1],bindMatrix[3][1], - // bindMatrix[0][2],bindMatrix[1][2],bindMatrix[2][2],bindMatrix[3][2], - // bindMatrix[0][3],bindMatrix[1][3],bindMatrix[2][3],bindMatrix[3][3]); + for(int i = 0; i < numFrames; i++) { math::mat4f frame( frameData[i*16], @@ -906,7 +950,7 @@ namespace polyvox return true; } - void AssetManager::playAnimation(EntityId e, int index, bool loop, bool reverse, bool replaceActive, float crossfade) + void SceneManager::playAnimation(EntityId e, int index, bool loop, bool reverse, bool replaceActive, float crossfade) { std::lock_guard lock(_mutex); @@ -963,7 +1007,7 @@ namespace polyvox } - void AssetManager::stopAnimation(EntityId entityId, int index) + void SceneManager::stopAnimation(EntityId entityId, int index) { std::lock_guard lock(_mutex); @@ -982,7 +1026,7 @@ namespace polyvox asset.gltfAnimations.end()); } - void AssetManager::loadTexture(EntityId entity, const char *resourcePath, int renderableIndex) + void SceneManager::loadTexture(EntityId entity, const char *resourcePath, int renderableIndex) { const auto &pos = _entityIdLookup.find(entity); @@ -1056,7 +1100,7 @@ namespace polyvox _resourceLoaderWrapper->free(imageResource); } - void AssetManager::setAnimationFrame(EntityId entity, int animationIndex, int animationFrame) + void SceneManager::setAnimationFrame(EntityId entity, int animationIndex, int animationFrame) { const auto &pos = _entityIdLookup.find(entity); if (pos == _entityIdLookup.end()) @@ -1070,7 +1114,7 @@ namespace polyvox asset.asset->getInstance()->getAnimator()->updateBoneMatrices(); } - float AssetManager::getAnimationDuration(EntityId entity, int animationIndex) + float SceneManager::getAnimationDuration(EntityId entity, int animationIndex) { const auto &pos = _entityIdLookup.find(entity); @@ -1086,7 +1130,7 @@ namespace polyvox return asset.asset->getInstance()->getAnimator()->getAnimationDuration(animationIndex); } - unique_ptr> AssetManager::getAnimationNames(EntityId entity) + unique_ptr> SceneManager::getAnimationNames(EntityId entity) { const auto &pos = _entityIdLookup.find(entity); @@ -1110,7 +1154,7 @@ namespace polyvox return names; } - unique_ptr> AssetManager::getMorphTargetNames(EntityId entity, const char *meshName) + unique_ptr> SceneManager::getMorphTargetNames(EntityId entity, const char *meshName) { unique_ptr> names = make_unique>(); @@ -1145,7 +1189,7 @@ namespace polyvox return names; } - void AssetManager::transformToUnitCube(EntityId entity) + void SceneManager::transformToUnitCube(EntityId entity) { const auto &pos = _entityIdLookup.find(entity); if (pos == _entityIdLookup.end()) @@ -1166,7 +1210,8 @@ namespace polyvox tm.setTransform(tm.getInstance(inst->getRoot()), transform); } - void AssetManager::setParent(EntityId childEntityId, EntityId parentEntityId) { + void SceneManager::setParent(EntityId childEntityId, EntityId parentEntityId) { + Log("Parenting child %d to %d", childEntityId, parentEntityId); auto& tm = _engine->getTransformManager(); const auto child = Entity::import(childEntityId); const auto parent = Entity::import(parentEntityId); @@ -1178,7 +1223,7 @@ namespace polyvox } - void AssetManager::addCollisionComponent(EntityId entityId, void(*onCollisionCallback)(EntityId entityId), bool affectsCollidingTransform) { + void SceneManager::addCollisionComponent(EntityId entityId, void(*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsTransform) { std::lock_guard lock(_mutex); const auto &pos = _entityIdLookup.find(entityId); if (pos == _entityIdLookup.end()) @@ -1191,11 +1236,72 @@ namespace polyvox auto collisionInstance = _collisionComponentManager->addComponent(asset.asset->getRoot()); _collisionComponentManager->elementAt<0>(collisionInstance) = asset.asset->getInstance()->getBoundingBox(); _collisionComponentManager->elementAt<1>(collisionInstance) = onCollisionCallback; - _collisionComponentManager->elementAt<2>(collisionInstance) = affectsCollidingTransform; + _collisionComponentManager->elementAt<2>(collisionInstance) = affectsTransform; } - void AssetManager::updateTransforms() { + void SceneManager::markNonTransformableCollidable(EntityId entityId) { + // Log("Marking entity %d as non-transforming collidable", entityId); + std::lock_guard lock(_mutex); + for(auto& existing : _nonTransformableCollidableEntities) { + if(existing == entityId) { + Log("Collision already exists"); + return; + } + } + _nonTransformableCollidableEntities.push_back(entityId); + Log("Mark complete."); + } + void SceneManager::unmarkNonTransformableCollidable(EntityId entityId) { + // Log("Removing non-transformable collidable from entity %d", entityId); + + std::lock_guard lock(_mutex); + auto begin = _nonTransformableCollidableEntities.begin(); + auto end = _nonTransformableCollidableEntities.end(); + auto removed = std::remove_if(begin, end, [=](EntityId id) { return id == entityId; }); + _nonTransformableCollidableEntities.erase(removed); + } + + void SceneManager::checkNonTransformableCollisions() { + // Log("checkNonTransformableCollisions %d ", _nonTransformableCollidableEntities.size()); + std::lock_guard lock(_mutex); + const auto& tm = _engine->getTransformManager(); + for(const auto& entityId : _nonTransformableCollidableEntities) { + + const auto &pos = _entityIdLookup.find(entityId); + if (pos == _entityIdLookup.end()) + { + Log("ERROR: asset not found for entity."); + continue; + } + auto &asset = _assets[pos->second]; + auto root = asset.asset->getRoot(); + auto rootId = Entity::smuggle(root); + + auto transformInstance = tm.getInstance(root); + + if(!transformInstance.isValid()) { + Log("Invalid transform, skipping."); + continue; + } + auto parent = tm.getParent(transformInstance); + + if(!parent.isNull()) { + transformInstance = tm.getInstance(parent); + } + auto transform = tm.getTransform(transformInstance); + auto worldTransform = tm.getWorldTransform(transformInstance); + + Log("Entity id %d, Local Transform : %f %f %f World transform %f %f %f", rootId, transform[3][0],transform[3][1],transform[3][2], worldTransform[0], worldTransform[1], worldTransform[2]); + auto boundingBox = asset.asset->getInstance()->getBoundingBox(); + auto worldBoundingBox = boundingBox.transform(worldTransform); + Log("Checking bounding box at center %f %f %f (world transformed centger %f %f %f)", boundingBox.center().x,boundingBox.center().y, boundingBox.center().z, worldBoundingBox.center().x, worldBoundingBox.center().y, worldBoundingBox.center().z); + _collisionComponentManager->collides(entityId, worldBoundingBox); + } + } + + + void SceneManager::updateTransforms() { std::lock_guard lock(_mutex); auto &tm = _engine->getTransformManager(); @@ -1243,7 +1349,7 @@ namespace polyvox auto bb = asset.asset->getBoundingBox(); auto transformedBB = bb.transform(transform); - auto collisionAxes = _collisionComponentManager->collides(transformedBB); + auto collisionAxes = _collisionComponentManager->collides(entityId, transformedBB); if(collisionAxes.size() == 1) { auto globalAxis = collisionAxes[0]; @@ -1261,21 +1367,29 @@ namespace polyvox _transformUpdates.clear(); } - void AssetManager::setScale(EntityId entity, float newScale) + void SceneManager::setScale(EntityId entityId, float newScale) { std::lock_guard lock(_mutex); - const auto &pos = _transformUpdates.find(entity); - if (pos == _transformUpdates.end()) - { - _transformUpdates[entity] = make_tuple(math::float3(), true, math::quatf(1.0f), true, newScale); - } - auto curr = _transformUpdates[entity]; - auto& scale = get<4>(curr); - scale = newScale; - _transformUpdates[entity] = curr; + + auto entity = Entity::import(entityId); + if(entity.isNull()) { + Log("Failed to find entity under ID %d", entityId); + return; + } + auto &tm = _engine->getTransformManager(); + + auto transformInstance = tm.getInstance(entity); + auto transform = tm.getTransform(transformInstance); + math::float3 translation; + math::quatf rotation; + math::float3 scale; + + decomposeMatrix(transform, &translation, &rotation, &scale); + auto newTransform = composeMatrix(translation, rotation, newScale); + tm.setTransform(transformInstance, newTransform); } - void AssetManager::setPosition(EntityId entityId, float x, float y, float z) + void SceneManager::setPosition(EntityId entityId, float x, float y, float z) { std::lock_guard lock(_mutex); @@ -1298,7 +1412,7 @@ namespace polyvox tm.setTransform(transformInstance, newTransform); } - void AssetManager::setRotation(EntityId entityId, float rads, float x, float y, float z, float w) + void SceneManager::setRotation(EntityId entityId, float rads, float x, float y, float z, float w) { std::lock_guard lock(_mutex); @@ -1321,13 +1435,10 @@ namespace polyvox tm.setTransform(transformInstance, newTransform); } - void AssetManager::queuePositionUpdate(EntityId entity, float x, float y, float z, bool relative) + void SceneManager::queuePositionUpdate(EntityId entity, float x, float y, float z, bool relative) { std::lock_guard lock(_mutex); - if(!relative) { - - } const auto &pos = _transformUpdates.find(entity); if (pos == _transformUpdates.end()) { @@ -1344,7 +1455,7 @@ namespace polyvox _transformUpdates[entity] = curr; } - void AssetManager::queueRotationUpdate(EntityId entity, float rads, float x, float y, float z, float w, bool relative) + void SceneManager::queueRotationUpdate(EntityId entity, float rads, float x, float y, float z, float w, bool relative) { std::lock_guard lock(_mutex); const auto &pos = _transformUpdates.find(entity); @@ -1363,7 +1474,7 @@ namespace polyvox _transformUpdates[entity] = curr; } - const utils::Entity *AssetManager::getCameraEntities(EntityId entity) + const utils::Entity *SceneManager::getCameraEntities(EntityId entity) { const auto &pos = _entityIdLookup.find(entity); if (pos == _entityIdLookup.end()) @@ -1375,7 +1486,7 @@ namespace polyvox return asset.asset->getCameraEntities(); } - size_t AssetManager::getCameraEntityCount(EntityId entity) + size_t SceneManager::getCameraEntityCount(EntityId entity) { const auto &pos = _entityIdLookup.find(entity); if (pos == _entityIdLookup.end()) @@ -1387,7 +1498,7 @@ namespace polyvox return asset.asset->getCameraEntityCount(); } - const utils::Entity *AssetManager::getLightEntities(EntityId entity) const noexcept + const utils::Entity *SceneManager::getLightEntities(EntityId entity) const noexcept { const auto &pos = _entityIdLookup.find(entity); if (pos == _entityIdLookup.end()) @@ -1399,7 +1510,7 @@ namespace polyvox return asset.asset->getLightEntities(); } - size_t AssetManager::getLightEntityCount(EntityId entity) const noexcept + size_t SceneManager::getLightEntityCount(EntityId entity) const noexcept { const auto &pos = _entityIdLookup.find(entity); if (pos == _entityIdLookup.end()) @@ -1411,7 +1522,7 @@ namespace polyvox return asset.asset->getLightEntityCount(); } - const char *AssetManager::getNameForEntity(EntityId entityId) + const char *SceneManager::getNameForEntity(EntityId entityId) { const auto &entity = Entity::import(entityId); auto nameInstance = _ncm->getInstance(entity); @@ -1423,7 +1534,7 @@ namespace polyvox return _ncm->getName(nameInstance); } - int AssetManager::getEntityCount(EntityId entityId, bool renderableOnly) { + int SceneManager::getEntityCount(EntityId entityId, bool renderableOnly) { const auto &pos = _entityIdLookup.find(entityId); if (pos == _entityIdLookup.end()) { @@ -1445,7 +1556,7 @@ namespace polyvox return asset.asset->getEntityCount(); } - const char* AssetManager::getEntityNameAt(EntityId entityId, int index, bool renderableOnly) { + const char* SceneManager::getEntityNameAt(EntityId entityId, int index, bool renderableOnly) { const auto &pos = _entityIdLookup.find(entityId); if (pos == _entityIdLookup.end()) { diff --git a/lib/filament_controller.dart b/lib/filament_controller.dart index 8fc36574..4e90b58c 100644 --- a/lib/filament_controller.dart +++ b/lib/filament_controller.dart @@ -326,6 +326,15 @@ abstract class FilamentController { bool replaceActive = true, double crossfade = 0.0}); + /// + /// Schedules the glTF animation at [index] in [entity] to start playing on the next frame. + /// + Future playAnimationByName(FilamentEntity entity, String name, + {bool loop = false, + bool reverse = false, + bool replaceActive = true, + double crossfade = 0.0}); + Future setAnimationFrame( FilamentEntity entity, int index, int animationFrame); Future stopAnimation(FilamentEntity entity, int animationIndex); @@ -335,6 +344,16 @@ abstract class FilamentController { /// Future setCamera(FilamentEntity entity, String? name); + /// + /// Sets the current scene camera to the main camera (which is always available and added to every scene by default). + /// + Future setMainCamera(); + + /// + /// Sets the current scene camera to the glTF camera under [name] in [entity]. + /// + Future setCameraFov(double degrees); + /// /// Sets the tone mapping (requires postprocessing). /// @@ -491,6 +510,11 @@ abstract class FilamentController { /// Future setPostProcessing(bool enabled); + /// + /// Set antialiasing options. + /// + Future setAntiAliasing(bool msaa, bool fxaa, bool taa); + /// /// Sets the rotation for [entity] to the specified quaternion. /// @@ -502,9 +526,10 @@ abstract class FilamentController { Future reveal(FilamentEntity entity, String meshName); /// - /// Hide the node [meshName] under [entity]. The node is still loaded, but is no longer being rendered into the scene. Call [reveal] to re-commence rendering. + /// If [meshName] is provided, hide the node [meshName] under [entity], otherwise hide the root node for [entity]. + /// The entity still exists in memory, but is no longer being rendered into the scene. Call [reveal] to re-commence rendering. /// - Future hide(FilamentEntity entity, String meshName); + Future hide(FilamentEntity entity, String? meshName); /// /// Used to select the entity in the scene at the given viewport coordinates. @@ -559,14 +584,26 @@ abstract class FilamentController { {double? translationSpeed, String? forwardAnimation}); /// - /// Make [collidableEntity] collidable. - /// At the moment, this is only relevant when controlling a different entity's transform. - /// If there is a collision between the controlled entity and [collidableEntity], the transform will not be updated. + /// Makes [collidableEntity] collidable with + /// (a) any entity whose transform is being controlled (via [control]) or + /// (b) any entity that has been marked as non-transformable but collidable (via [markNonTransformableCollidable]) + /// These are differentiated because a collision will affect the transform for controlled entities + /// (e.g. if a controlled entity collides with a wall, we ignore the control update to the transform so it doesn't go through the wall) /// Future addCollisionComponent(FilamentEntity collidableEntity, - {void Function(int entityId)? callback, + {void Function(int entityId1, int entityId2)? callback, bool affectsCollingTransform = false}); + /// + /// Make [entity] collidable, without affecting its transform. + /// + Future markNonTransformableCollidable(FilamentEntity entity); + + /// + /// Make [entity] no longer collidable. + /// + Future unmarkNonTransformableCollidable(FilamentEntity entity); + /// /// Creates a (renderable) entity with the specified geometry and adds to the scene. /// diff --git a/lib/filament_controller_ffi.dart b/lib/filament_controller_ffi.dart index 8aa75715..61477f2b 100644 --- a/lib/filament_controller_ffi.dart +++ b/lib/filament_controller_ffi.dart @@ -36,7 +36,7 @@ class FilamentControllerFFI extends FilamentController { double _pixelRatio = 1.0; - late Pointer? _assetManager; + late Pointer? _sceneManager; Pointer? _viewer; @@ -169,7 +169,7 @@ class FilamentControllerFFI extends FilamentController { _viewer = null; - _assetManager = null; + _sceneManager = null; destroy_filament_viewer_ffi(viewer!); hasViewer.value = false; } @@ -250,7 +250,7 @@ class FilamentControllerFFI extends FilamentController { throw Exception("Failed to create viewer. Check logs for details"); } - _assetManager = get_asset_manager(_viewer!); + _sceneManager = get_scene_manager(_viewer!); create_swap_chain_ffi(_viewer!, renderingSurface.surface, _rect.value!.width.toInt(), _rect.value!.height.toInt()); @@ -387,8 +387,6 @@ class FilamentControllerFFI extends FilamentController { throw Exception("Failed to create viewer. Check logs for details"); } - _assetManager = get_asset_manager(_viewer!); - if (!_usesBackingWindow) { create_swap_chain_ffi(_viewer!, renderingSurface.surface, _rect.value!.width.toInt(), _rect.value!.height.toInt()); @@ -556,7 +554,7 @@ class FilamentControllerFFI extends FilamentController { throw Exception("Not yet implemented"); } final pathPtr = path.toNativeUtf8().cast(); - var entity = load_glb_ffi(_assetManager!, pathPtr, unlit); + var entity = load_glb_ffi(_sceneManager!, pathPtr, unlit); allocator.free(pathPtr); if (entity == _FILAMENT_ASSET_ERROR) { throw Exception("An error occurred loading the asset at $path"); @@ -580,7 +578,7 @@ class FilamentControllerFFI extends FilamentController { final relativeResourcePathPtr = relativeResourcePath.toNativeUtf8().cast(); var entity = - load_gltf_ffi(_assetManager!, pathPtr, relativeResourcePathPtr); + load_gltf_ffi(_sceneManager!, pathPtr, relativeResourcePathPtr); allocator.free(pathPtr); allocator.free(relativeResourcePathPtr); if (entity == _FILAMENT_ASSET_ERROR) { @@ -652,7 +650,7 @@ class FilamentControllerFFI extends FilamentController { } var meshNamePtr = meshName.toNativeUtf8(allocator: allocator).cast(); set_morph_target_weights_ffi( - _assetManager!, entity, meshNamePtr, weightsPtr, weights.length); + _sceneManager!, entity, meshNamePtr, weightsPtr, weights.length); allocator.free(weightsPtr); allocator.free(meshNamePtr); } @@ -666,10 +664,10 @@ class FilamentControllerFFI extends FilamentController { var names = []; var meshNamePtr = meshName.toNativeUtf8().cast(); var count = - get_morph_target_name_count_ffi(_assetManager!, entity, meshNamePtr); + get_morph_target_name_count_ffi(_sceneManager!, entity, meshNamePtr); var outPtr = allocator(255); for (int i = 0; i < count; i++) { - get_morph_target_name(_assetManager!, entity, meshNamePtr, outPtr, i); + get_morph_target_name(_sceneManager!, entity, meshNamePtr, outPtr, i); names.add(outPtr.cast().toDartString()); } allocator.free(outPtr); @@ -682,11 +680,11 @@ class FilamentControllerFFI extends FilamentController { if (_viewer == null) { throw Exception("No viewer available, ignoring"); } - var animationCount = get_animation_count(_assetManager!, entity); + var animationCount = get_animation_count(_sceneManager!, entity); var names = []; var outPtr = allocator(255); for (int i = 0; i < animationCount; i++) { - get_animation_name_ffi(_assetManager!, entity, outPtr, i); + get_animation_name_ffi(_sceneManager!, entity, outPtr, i); names.add(outPtr.cast().toDartString()); } @@ -700,7 +698,7 @@ class FilamentControllerFFI extends FilamentController { throw Exception("No viewer available, ignoring"); } var duration = - get_animation_duration(_assetManager!, entity, animationIndex); + get_animation_duration(_sceneManager!, entity, animationIndex); return duration; } @@ -740,7 +738,7 @@ class FilamentControllerFFI extends FilamentController { meshName.toNativeUtf8(allocator: allocator).cast(); set_morph_animation( - _assetManager!, + _sceneManager!, entity, meshNamePtr, dataPtr, @@ -789,7 +787,7 @@ class FilamentControllerFFI extends FilamentController { } add_bone_animation_ffi( - _assetManager!, + _sceneManager!, entity, data, numFrames, @@ -813,7 +811,7 @@ class FilamentControllerFFI extends FilamentController { if (_viewer == nullptr) { throw Exception("No viewer available, ignoring"); } - reset_to_rest_pose_ffi(_assetManager!, entity); + reset_to_rest_pose_ffi(_sceneManager!, entity); } @override @@ -873,7 +871,21 @@ class FilamentControllerFFI extends FilamentController { throw Exception("No viewer available, ignoring"); } play_animation_ffi( - _assetManager!, entity, index, loop, reverse, replaceActive, crossfade); + _sceneManager!, entity, index, loop, reverse, replaceActive, crossfade); + } + + @override + Future playAnimationByName(FilamentEntity entity, String name, + {bool loop = false, + bool reverse = false, + bool replaceActive = true, + double crossfade = 0.0}) async { + var animations = await getAnimationNames(entity); + await playAnimation(entity, animations.indexOf(name), + loop: loop, + reverse: reverse, + replaceActive: replaceActive, + crossfade: crossfade); } @override @@ -882,7 +894,7 @@ class FilamentControllerFFI extends FilamentController { if (_viewer == null) { throw Exception("No viewer available, ignoring"); } - set_animation_frame(_assetManager!, entity, index, animationFrame); + set_animation_frame(_sceneManager!, entity, index, animationFrame); } @override @@ -890,7 +902,12 @@ class FilamentControllerFFI extends FilamentController { if (_viewer == null) { throw Exception("No viewer available, ignoring"); } - stop_animation(_assetManager!, entity, animationIndex); + stop_animation(_sceneManager!, entity, animationIndex); + } + + @override + Future setMainCamera() async { + set_main_camera(_viewer!); } @override @@ -924,6 +941,11 @@ class FilamentControllerFFI extends FilamentController { set_post_processing_ffi(_viewer!, enabled); } + @override + Future setAntiAliasing(bool msaa, bool fxaa, bool taa) async { + set_antialiasing(_viewer!, msaa, fxaa, taa); + } + @override Future setBloom(double bloom) async { if (_viewer == null) { @@ -940,6 +962,11 @@ class FilamentControllerFFI extends FilamentController { set_camera_focal_length(_viewer!, focalLength); } + @override + Future setCameraFov(double degrees) async { + set_camera_fov(_viewer!, degrees, _rect.value!.width / _rect.value!.height); + } + @override Future setCameraCulling(double near, double far) async { if (_viewer == null) { @@ -1029,7 +1056,7 @@ class FilamentControllerFFI extends FilamentController { } var meshNamePtr = meshName.toNativeUtf8().cast(); var result = set_material_color( - _assetManager!, + _sceneManager!, entity, meshNamePtr, materialIndex, @@ -1048,7 +1075,7 @@ class FilamentControllerFFI extends FilamentController { if (_viewer == null) { throw Exception("No viewer available, ignoring"); } - transform_to_unit_cube(_assetManager!, entity); + transform_to_unit_cube(_sceneManager!, entity); } @override @@ -1058,7 +1085,7 @@ class FilamentControllerFFI extends FilamentController { throw Exception("No viewer available, ignoring"); } - set_position(_assetManager!, entity, x, y, z); + set_position(_sceneManager!, entity, x, y, z); } @override @@ -1077,7 +1104,7 @@ class FilamentControllerFFI extends FilamentController { if (_viewer == null) { throw Exception("No viewer available, ignoring"); } - set_rotation(_assetManager!, entity, rotation.radians, rotation.x, + set_rotation(_sceneManager!, entity, rotation.radians, rotation.x, rotation.y, rotation.z, rotation.w); } @@ -1086,7 +1113,7 @@ class FilamentControllerFFI extends FilamentController { if (_viewer == null) { throw Exception("No viewer available, ignoring"); } - set_scale(_assetManager!, entity, scale); + set_scale(_sceneManager!, entity, scale); } @override @@ -1097,7 +1124,7 @@ class FilamentControllerFFI extends FilamentController { throw Exception("No viewer available, ignoring"); } - queue_position_update(_assetManager!, entity, x, y, z, relative); + queue_position_update(_sceneManager!, entity, x, y, z, relative); } @override @@ -1116,17 +1143,17 @@ class FilamentControllerFFI extends FilamentController { if (_viewer == null) { throw Exception("No viewer available, ignoring"); } - queue_rotation_update(_assetManager!, entity, rotation.radians, rotation.x, + queue_rotation_update(_sceneManager!, entity, rotation.radians, rotation.x, rotation.y, rotation.z, rotation.w, relative); } @override - Future hide(FilamentEntity entity, String meshName) async { + Future hide(FilamentEntity entity, String? meshName) async { if (_viewer == null) { throw Exception("No viewer available, ignoring"); } - final meshNamePtr = meshName.toNativeUtf8().cast(); - if (hide_mesh(_assetManager!, entity, meshNamePtr) != 1) {} + final meshNamePtr = meshName?.toNativeUtf8().cast() ?? nullptr; + if (hide_mesh(_sceneManager!, entity, meshNamePtr) != 1) {} allocator.free(meshNamePtr); } @@ -1137,7 +1164,7 @@ class FilamentControllerFFI extends FilamentController { } final meshNamePtr = meshName.toNativeUtf8().cast(); - final result = reveal_mesh(_assetManager!, entity, meshNamePtr) != 1; + final result = reveal_mesh(_sceneManager!, entity, meshNamePtr) != 1; allocator.free(meshNamePtr); if (!result) { throw Exception("Failed to reveal mesh $meshName"); @@ -1146,7 +1173,7 @@ class FilamentControllerFFI extends FilamentController { @override String? getNameForEntity(FilamentEntity entity) { - final result = get_name_for_entity(_assetManager!, entity); + final result = get_name_for_entity(_sceneManager!, entity); if (result == nullptr) { return null; } @@ -1316,7 +1343,7 @@ class FilamentControllerFFI extends FilamentController { var boneNamePtr = boneName.toNativeUtf8(allocator: allocator).cast(); var result = set_bone_transform_ffi( - _assetManager!, entity, meshNamePtr, ptr, boneNamePtr); + _sceneManager!, entity, meshNamePtr, ptr, boneNamePtr); allocator.free(ptr); allocator.free(meshNamePtr); @@ -1333,7 +1360,7 @@ class FilamentControllerFFI extends FilamentController { childName.toNativeUtf8(allocator: allocator).cast(); var childEntity = - find_child_entity_by_name(_assetManager!, parent, childNamePtr); + find_child_entity_by_name(_sceneManager!, parent, childNamePtr); allocator.free(childNamePtr); if (childEntity == _FILAMENT_ASSET_ERROR) { throw Exception( @@ -1344,10 +1371,10 @@ class FilamentControllerFFI extends FilamentController { Future> getMeshNames(FilamentEntity entity, {bool async = false}) async { - var count = get_entity_count(_assetManager!, entity, true); + var count = get_entity_count(_sceneManager!, entity, true); var names = []; for (int i = 0; i < count; i++) { - var name = get_entity_name_at(_assetManager!, entity, i, true); + var name = get_entity_name_at(_sceneManager!, entity, i, true); if (name == nullptr) { throw Exception("Failed to find mesh at index $i"); } @@ -1369,6 +1396,7 @@ class FilamentControllerFFI extends FilamentController { } HardwareKeyboardListener? _keyboardListener; + @override Future control(FilamentEntity entity, {double? translationSpeed, String? forwardAnimation}) async { int? forwardAnimationIndex; @@ -1390,25 +1418,35 @@ class FilamentControllerFFI extends FilamentController { } @override - Future addCollisionComponent(FilamentEntity entity, - {void Function(int entityId)? callback, + Future addCollisionComponent(FilamentEntity collidableEntity, + {void Function(int entityId1, int entityId2)? callback, bool affectsCollingTransform = false}) async { - if (_assetManager == null) { - throw Exception("AssetManager must be non-null"); + if (_sceneManager == null) { + throw Exception("SceneManager must be non-null"); } // ignore: sdk_version_since if (callback != null) { - var ptr = - NativeCallable.listener(callback); - add_collision_component( - _assetManager!, entity, ptr.nativeFunction, affectsCollingTransform); + var ptr = NativeCallable< + Void Function(Int32 entityId1, Int32 entityId2)>.listener(callback); + add_collision_component(_sceneManager!, collidableEntity, + ptr.nativeFunction, affectsCollingTransform); } else { add_collision_component( - _assetManager!, entity, nullptr, affectsCollingTransform); + _sceneManager!, collidableEntity, nullptr, affectsCollingTransform); } } + @override + Future markNonTransformableCollidable(FilamentEntity entity) async { + mark_nontransformable_collidable(_sceneManager!, entity); + } + + @override + Future unmarkNonTransformableCollidable(FilamentEntity entity) async { + unmark_nontransformable_collidable(_sceneManager!, entity); + } + @override Future createGeometry( List vertices, List indices, String? materialPath) async { @@ -1446,9 +1484,9 @@ class FilamentControllerFFI extends FilamentController { @override Future setParent(FilamentEntity child, FilamentEntity parent) async { - if (_assetManager == null) { + if (_sceneManager == null) { throw Exception("Asset manager must be non-null"); } - set_parent(_assetManager!, child, parent); + set_parent(_sceneManager!, child, parent); } }