diff --git a/example/assets/shapes/shapes.bin b/example/assets/shapes/shapes.bin index e159dcdd..ee8296ff 100644 --- a/example/assets/shapes/shapes.bin +++ b/example/assets/shapes/shapes.bin @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9cd37bd5152ca0d7bde93663e188a537b2ac2bad58eaf69fbac00d9bc2da9f43 -size 93896 +oid sha256:1a28d8328f7881c6bfc57d18c55b5f347058e9c3a8ff69202e528eecb4728ac0 +size 100960 diff --git a/example/assets/shapes/shapes.glb b/example/assets/shapes/shapes.glb index 31340700..7be024c3 100644 --- a/example/assets/shapes/shapes.glb +++ b/example/assets/shapes/shapes.glb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3fa9367e8955a1e47e704e56f267854019f0135199a06d8e25f62cec503d67d6 -size 136160 +oid sha256:b728c8fe0ce9eb06290dc37034404a952df8ea360b014b76c82fe8b9d695e85a +size 113124 diff --git a/example/assets/shapes/shapes.gltf b/example/assets/shapes/shapes.gltf index e87aacbd..0a90df1f 100644 --- a/example/assets/shapes/shapes.gltf +++ b/example/assets/shapes/shapes.gltf @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cf4bf82fd77a54fd6573cded79d1d4db0d0e000c4200c0eadee9ce29425449de -size 32690 +oid sha256:ab3dc6ca4dcfcd660b3a4dce20347ad1154844fe95fc7b47781288a22b0cd75b +size 32437 diff --git a/example/lib/main.dart b/example/lib/main.dart index 249cede9..da2500fb 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -93,8 +93,12 @@ class ExampleWidgetState extends State { await _filamentController!.createViewer(); await _filamentController! .loadSkybox("assets/default_env/default_env_skybox.ktx"); + await _filamentController!.setRendering(true); - await _filamentController!.loadGlb("assets/shapes/shapes.glb"); + shapes = + await _filamentController!.loadGlb("assets/shapes/shapes.glb"); + hasSkybox = true; + rendering = true; }); }); } diff --git a/example/lib/menus/asset_submenu.dart b/example/lib/menus/asset_submenu.dart index 31e73d35..5eaa68b3 100644 --- a/example/lib/menus/asset_submenu.dart +++ b/example/lib/menus/asset_submenu.dart @@ -55,6 +55,17 @@ class _AssetSubmenuState extends State { .transformToUnitCube(ExampleWidgetState.shapes!); }, child: const Text('Transform to unit cube')), + MenuItemButton( + onPressed: ExampleWidgetState.shapes == null + ? null + : () async { + await widget.controller.setBoneTransform( + ExampleWidgetState.shapes!, + "Cylinder", + 0, + Matrix4.rotationX(pi / 2)); + }, + child: const Text('Set bone tranform to identity for Cylinder')), MenuItemButton( onPressed: () async { var names = await widget.controller diff --git a/ios/include/AssetManager.hpp b/ios/include/AssetManager.hpp index fe2c76f5..14e70ab6 100644 --- a/ios/include/AssetManager.hpp +++ b/ios/include/AssetManager.hpp @@ -73,6 +73,8 @@ namespace polyvox { bool hide(EntityId entity, const char* meshName); bool reveal(EntityId entity, const char* meshName); const char* getNameForEntity(EntityId entityId); + + bool setBoneTransform(EntityId entityId, const char* entityName, int skinIndex, int boneIndex, math::mat4f transform); private: AssetLoader* _assetLoader = nullptr; @@ -96,9 +98,7 @@ namespace polyvox { inline void updateTransform(SceneAsset& asset); - inline void setBoneTransform(SceneAsset& asset, int frameNumber); - - + inline void setBoneTransformFromAnimation(SceneAsset& asset, int frameNumber); }; } diff --git a/ios/include/FlutterFilamentApi.h b/ios/include/FlutterFilamentApi.h index 2e2629f6..ea2a71ac 100644 --- a/ios/include/FlutterFilamentApi.h +++ b/ios/include/FlutterFilamentApi.h @@ -125,6 +125,13 @@ FLUTTER_PLUGIN_EXPORT void set_bone_animation( const char** const meshName, int numMeshTargets, float frameLengthInMs); +FLUTTER_PLUGIN_EXPORT bool set_bone_transform( + void* assetManager, + EntityId asset, + const char* entityName, + const float* const transform, + int boneIndex + ); 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); diff --git a/ios/src/AssetManager.cpp b/ios/src/AssetManager.cpp index 1a70f45d..3db9c65d 100644 --- a/ios/src/AssetManager.cpp +++ b/ios/src/AssetManager.cpp @@ -318,7 +318,7 @@ void AssetManager::updateAnimations() { if(anim.mReverse) { frameNumber = lengthInFrames - frameNumber; } - setBoneTransform( + setBoneTransformFromAnimation( asset, frameNumber ); @@ -343,7 +343,73 @@ void AssetManager::updateAnimations() { } } -void AssetManager::setBoneTransform(SceneAsset& asset, int frameNumber) { +bool AssetManager::setBoneTransform(EntityId entityId, const char* entityName, int32_t skinIndex, int32_t boneIndex, math::mat4f localTransform) { + + Log("Setting transform for bone %d/skin %d for mesh target %s", boneIndex, skinIndex, entityName); + + const auto& pos = _entityIdLookup.find(entityId); + if(pos == _entityIdLookup.end()) { + Log("Couldn't find asset under specified entity id."); + return false; + } + SceneAsset& sceneAsset = _assets[pos->second]; + + const auto& entity = findEntityByName(sceneAsset, entityName); + + RenderableManager& rm = _engine->getRenderableManager(); + + const auto& renderableInstance = rm.getInstance(entity); + + TransformManager &transformManager = _engine->getTransformManager(); + + const auto& filamentInstance = sceneAsset.mAsset->getInstance(); + utils::Entity joint = filamentInstance->getJointsAt(skinIndex)[boneIndex]; + + if(joint.isNull()) { + Log("ERROR : joint not found"); + return false; + } + + rm.setBones( + renderableInstance, + &localTransform, + 1, + boneIndex + ); + + return true; + + // auto& inverseBindMatrix = filamentInstance->getInverseBindMatricesAt(skinIndex)[boneIndex]; + + // auto jointInstance = transformManager.getInstance(joint); + + // auto globalJointTransform = transformManager.getWorldTransform(jointInstance); + + // transformManager.setTransform(jointInstance, xform * localTransform); + + // auto inverseGlobalTransform = inverse( + // transformManager.getWorldTransform( + // transformManager.getInstance(target) + // ) + // ); + + // auto boneTransform = inverseGlobalTransform * globalJointTransform * localTransform * inverseBindMatrix; + // auto renderable = rm.getInstance(target); + + // 1.0f, 0.0f, 0.0f, 0.0f, + // 0.0f, 0.0f, 1.0f, 0.0f, + // 0.0f, -1.0f, 0.0f, 0.0f, + // 0.0f, 0.0f, 0.0f, 1.0f + // }; + // Log("TRANSFORM"); + // Log("%f %f %f %f", localTransform[0][0], localTransform[1][0], localTransform[2][0], localTransform[3][0] ) ; + // Log("%f %f %f %f", localTransform[0][1], localTransform[1][1], localTransform[2][1], localTransform[3][1] ) ; + // Log("%f %f %f %f", localTransform[0][2], localTransform[1][2], localTransform[2][2], localTransform[3][2] ) ; + // Log("%f %f %f %f", localTransform[0][3], localTransform[1][3], localTransform[2][3], localTransform[3][3] ) ; + // } +} + +void AssetManager::setBoneTransformFromAnimation(SceneAsset& asset, int frameNumber) { RenderableManager& rm = _engine->getRenderableManager(); @@ -969,39 +1035,3 @@ const char* AssetManager::getNameForEntity(EntityId entityId) { } // namespace polyvox - -// auto& inverseBindMatrix = filamentInstance->getInverseBindMatricesAt(skinIndex)[mBoneIndex]; - -// auto globalJointTransform = transformManager.getWorldTransform(jointInstance); - -// for(auto& target : asset.mBoneAnimationBuffer.mMeshTargets) { - -// auto inverseGlobalTransform = inverse( -// transformManager.getWorldTransform( -// transformManager.getInstance(target) -// ) -// ); - -// auto boneTransform = inverseGlobalTransform * globalJointTransform * localTransform * inverseBindMatrix; -// auto renderable = rm.getInstance(target); -// rm.setBones( -// renderable, -// &boneTransform, -// 1, -// mBoneIndex -// ); -// } - - - -// 1.0f, 0.0f, 0.0f, 0.0f, -// 0.0f, 0.0f, 1.0f, 0.0f, -// 0.0f, -1.0f, 0.0f, 0.0f, -// 0.0f, 0.0f, 0.0f, 1.0f -// }; -// Log("TRANSFORM"); -// Log("%f %f %f %f", localTransform[0][0], localTransform[1][0], localTransform[2][0], localTransform[3][0] ) ; -// Log("%f %f %f %f", localTransform[0][1], localTransform[1][1], localTransform[2][1], localTransform[3][1] ) ; -// Log("%f %f %f %f", localTransform[0][2], localTransform[1][2], localTransform[2][2], localTransform[3][2] ) ; -// Log("%f %f %f %f", localTransform[0][3], localTransform[1][3], localTransform[2][3], localTransform[3][3] ) ; -// transformManager.getTransform(jointInstance); diff --git a/ios/src/FlutterFilamentApi.cpp b/ios/src/FlutterFilamentApi.cpp index 3d9f3cbf..47f0244e 100644 --- a/ios/src/FlutterFilamentApi.cpp +++ b/ios/src/FlutterFilamentApi.cpp @@ -148,7 +148,7 @@ extern "C" return array; } - void set_camera_projection_matrix(const void *const viewer, const double* const matrix, double near, double far) + void set_camera_projection_matrix(const void *const viewer, const double *const matrix, double near, double far) { ((FilamentViewer *)viewer)->setCameraProjectionMatrix(matrix, near, far); } @@ -157,19 +157,20 @@ extern "C" { ((FilamentViewer *)viewer)->setCameraCulling(near, far); } - + const double *const get_camera_frustum(const void *const viewer) { const auto frustum = ((FilamentViewer *)viewer)->getCameraFrustum(); - const math::float4* planes = frustum.getNormalizedPlanes(); + const math::float4 *planes = frustum.getNormalizedPlanes(); double *array = (double *)calloc(24, sizeof(double)); - for(int i =0; i < 6; i++) { - array[i*4] = planes[i].x; - array[i*4+1] = planes[i].y; - array[i*4+2] = planes[i].z; - array[i*4+3] = planes[i].w; + for (int i = 0; i < 6; i++) + { + array[i * 4] = planes[i].x; + array[i * 4 + 1] = planes[i].y; + array[i * 4 + 2] = planes[i].z; + array[i * 4 + 3] = planes[i].w; } - + return array; } @@ -339,6 +340,32 @@ extern "C" ((FilamentViewer *)viewer)->setPostProcessing(enabled); } + FLUTTER_PLUGIN_EXPORT bool set_bone_transform( + void *assetManager, + EntityId entityId, + const char *entityName, + const float *const transform, + int boneIndex) + { + + auto matrix = math::mat4f( + transform[0], transform[1], transform[2], + transform[3], + transform[4], + transform[5], + transform[6], + transform[7], + transform[8], + transform[9], + transform[10], + transform[11], + transform[12], + transform[13], + transform[14], + transform[15]); + return ((AssetManager *)assetManager)->setBoneTransform(entityId, entityName, 0, boneIndex, matrix); + } + // void set_bone_transform( // EntityId asset, // const char* boneName, @@ -489,10 +516,8 @@ extern "C" Log("Dummy called"); } - FLUTTER_PLUGIN_EXPORT void flutter_filament_free(void* ptr) + FLUTTER_PLUGIN_EXPORT void flutter_filament_free(void *ptr) { free(ptr); } - - } diff --git a/lib/filament_controller.dart b/lib/filament_controller.dart index 7f159eb8..1f9dc4ea 100644 --- a/lib/filament_controller.dart +++ b/lib/filament_controller.dart @@ -279,6 +279,12 @@ abstract class FilamentController { /// Future setBoneAnimation(FilamentEntity entity, BoneAnimationData animation); + /// + /// Sets the local joint transform for the bone at the given index in [entity] for the mesh under [meshName]. + /// + Future setBoneTransform( + FilamentEntity entity, String meshName, int boneIndex, Matrix4 data); + /// /// Removes/destroys the specified entity from the scene. /// [entity] will no longer be a valid handle after this method is called; ensure you immediately discard all references once this method is complete. diff --git a/lib/filament_controller_ffi.dart b/lib/filament_controller_ffi.dart index 053c0358..5d8ffd22 100644 --- a/lib/filament_controller_ffi.dart +++ b/lib/filament_controller_ffi.dart @@ -1160,4 +1160,18 @@ class FilamentControllerFFI extends FilamentController { return frustum; } + + @override + Future setBoneTransform(FilamentEntity entity, String meshName, int boneIndex, + Matrix4 data) async { + var ptr = calloc(16); + for (int i = 0; i < 16; i++) { + ptr.elementAt(i).value = data.storage[i]; + } + + set_bone_transform(_assetManager!, entity, + meshName.toNativeUtf8().cast(), ptr, boneIndex); + + calloc.free(ptr); + } } diff --git a/lib/generated_bindings.dart b/lib/generated_bindings.dart index d961686d..f1ea54da 100644 --- a/lib/generated_bindings.dart +++ b/lib/generated_bindings.dart @@ -388,6 +388,18 @@ external void set_bone_animation( double frameLengthInMs, ); +@ffi.Native< + ffi.Bool Function(ffi.Pointer, EntityId, + ffi.Pointer, ffi.Pointer, ffi.Int)>( + symbol: 'set_bone_transform', assetId: 'flutter_filament_plugin') +external bool set_bone_transform( + ffi.Pointer assetManager, + int asset, + ffi.Pointer entityName, + ffi.Pointer transform, + int boneIndex, +); + @ffi.Native< ffi.Void Function(ffi.Pointer, EntityId, ffi.Int, ffi.Bool, ffi.Bool, ffi.Bool, ffi.Float)>( diff --git a/lib/widgets/filament_widget.dart b/lib/widgets/filament_widget.dart index 890d8616..20fa071a 100644 --- a/lib/widgets/filament_widget.dart +++ b/lib/widgets/filament_widget.dart @@ -139,18 +139,18 @@ class _SizedFilamentWidgetState extends State<_SizedFilamentWidget> { ); WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { - try { - widget.controller.setDimensions(_rect, MediaQuery.of(context).devicePixelRatio); + try { + widget.controller + .setDimensions(_rect, MediaQuery.of(context).devicePixelRatio); } catch (err) { dev.log("Fatal error : $err"); _error = err.toString(); } - }); + }); super.initState(); } - Timer? _resizeTimer; bool _resizing = false; @@ -162,26 +162,29 @@ class _SizedFilamentWidgetState extends State<_SizedFilamentWidget> { // any subsequent widget resizes will cancel the timer and replace with a new one. // debug mode does need a longer timeout. _resizeTimer?.cancel(); - _resizeTimer = Timer(Duration(milliseconds: (kReleaseMode || Platform.isWindows) ? 10 : 100), () async { + await widget.controller + .setDimensions(_rect, MediaQuery.of(context).devicePixelRatio); + _resizeTimer = Timer( + Duration(milliseconds: (kReleaseMode || Platform.isWindows) ? 10 : 100), + () async { try { - - while(_resizing) { + while (_resizing) { await Future.delayed(const Duration(milliseconds: 20)); } _resizing = true; - await widget.controller.setDimensions(_rect, MediaQuery.of(context).devicePixelRatio); + await widget.controller + .setDimensions(_rect, MediaQuery.of(context).devicePixelRatio); await widget.controller.resize(); _resizeTimer = null; setState(() {}); } catch (err) { dev.log("Error resizing FilamentWidget: $err"); - } finally { + } finally { _resizing = false; completer.complete(); } }); return completer.future; - } @override