add flag for affectsCollidingTransform, add setParent method for transforms

This commit is contained in:
Nick Fisher
2024-02-15 14:50:14 +08:00
parent 023900bb99
commit 935b876ce9
7 changed files with 87 additions and 46 deletions

View File

@@ -103,7 +103,9 @@ namespace polyvox
const char *entityName); const char *entityName);
int getEntityCount(EntityId entity, bool renderableOnly); int getEntityCount(EntityId entity, bool renderableOnly);
const char* getEntityNameAt(EntityId entity, int index, bool renderableOnly); const char* getEntityNameAt(EntityId entity, int index, bool renderableOnly);
void addCollisionComponent(EntityId entity, void (*onCollisionCallback)(EntityId entityId)); void addCollisionComponent(EntityId entity, void (*onCollisionCallback)(EntityId entityId), bool affectsCollidingTransform);
void removeCollisionComponent(EntityId entityId);
void setParent(EntityId child, EntityId parent);
private: private:
AssetLoader *_assetLoader = nullptr; AssetLoader *_assetLoader = nullptr;

View File

@@ -185,8 +185,9 @@ extern "C"
FLUTTER_PLUGIN_EXPORT void set_recording_output_directory(void *const viewer, const char* outputDirectory); FLUTTER_PLUGIN_EXPORT void set_recording_output_directory(void *const viewer, const char* outputDirectory);
FLUTTER_PLUGIN_EXPORT void ios_dummy(); FLUTTER_PLUGIN_EXPORT void ios_dummy();
FLUTTER_PLUGIN_EXPORT void flutter_filament_free(void *ptr); 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)); FLUTTER_PLUGIN_EXPORT void add_collision_component(void *const assetManager, EntityId entityId, void (*callback)(const EntityId entityId), bool affectsCollidingTransform);
FLUTTER_PLUGIN_EXPORT EntityId create_geometry(void *const viewer, float* vertices, int numVertices, uint16_t* indices, int numIndices, const char* materialPath); 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);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -13,57 +13,63 @@ namespace polyvox
{ {
typedef void(*CollisionCallback)(int32_t entityId) ; typedef void(*CollisionCallback)(int32_t entityId) ;
class CollisionComponentManager : public utils::SingleInstanceComponentManager<filament::Aabb, CollisionCallback> { class CollisionComponentManager : public utils::SingleInstanceComponentManager<filament::Aabb, CollisionCallback, bool> {
const filament::TransformManager& _transformManager; const filament::TransformManager& _transformManager;
public: public:
CollisionComponentManager(const filament::TransformManager& transformManager) : _transformManager(transformManager) {} CollisionComponentManager(const filament::TransformManager& transformManager) : _transformManager(transformManager) {}
std::vector<filament::math::float3> collides(filament::Aabb sourceBox, filament::math::float3 direction) { std::vector<filament::math::float3> collides(filament::Aabb sourceBox) {
auto sourceCorners = sourceBox.getCorners(); auto sourceCorners = sourceBox.getCorners();
std::vector<filament::math::float3> collision_axes; std::vector<filament::math::float3> collisionAxes;
for(auto it = begin(); it < end(); it++) { for(auto it = begin(); it < end(); it++) {
auto entity = getEntity(it); auto entity = getEntity(it);
auto targetXformInstance = _transformManager.getInstance(entity); auto targetXformInstance = _transformManager.getInstance(entity);
auto targetXform = _transformManager.getWorldTransform(targetXformInstance); auto targetXform = _transformManager.getWorldTransform(targetXformInstance);
auto targetBox = elementAt<0>(it).transform(targetXform); auto targetBox = elementAt<0>(it).transform(targetXform);
bool collided = false;
// iterate over every vertex in the source AABB // iterate over every vertex in the source AABB
for(int i = 0; i < 8; i++) { for(int i = 0; i < 8; i++) {
// if the vertex has insersected with the target AABB // if the vertex has insersected with the target AABB
if(targetBox.contains(sourceCorners.vertices[i]) < 0) { 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;
auto intersecting = sourceCorners.vertices[i]; float xmin = min.x - intersecting.x;
auto min = targetBox.min; float ymin = min.y - intersecting.y;
auto max = targetBox.max; float zmin = min.z - intersecting.z;
float xmax = intersecting.x - max.x;
float ymax = intersecting.y - max.y;
float zmax = intersecting.z - max.z;
float xmin = min.x - intersecting.x; auto maxD = std::max(xmin,std::max(ymin,std::max(zmin,std::max(xmax,std::max(ymax,zmax)))));
float ymin = min.y - intersecting.y; filament::math::float3 axis;
float zmin = min.z - intersecting.z; if(maxD == xmin) {
float xmax = intersecting.x - max.x; axis = {-1.0f,0.0f, 0.0f};
float ymax = intersecting.y - max.y; } else if(maxD == ymin) {
float zmax = intersecting.z - max.z; axis = {0.0f,-1.0f, 0.0f};
} else if(maxD == zmin) {
auto maxD = std::max(xmin,std::max(ymin,std::max(zmin,std::max(xmax,std::max(ymax,zmax))))); axis = {0.0f,0.0f, -1.0f};
filament::math::float3 axis; } else if(maxD == xmax) {
if(maxD == xmin) { axis = {1.0f,0.0f, 0.0f};
axis = {-1.0f,0.0f, 0.0f}; } else if(maxD == ymax) {
} else if(maxD == ymin) { axis = {0.0f,1.0f, 0.0f};
axis = {0.0f,-1.0f, 0.0f}; } else {
} else if(maxD == zmin) { axis = { 0.0f, 0.0f, 1.0f};
axis = {0.0f,0.0f, -1.0f}; }
} else if(maxD == xmax) { collisionAxes.push_back(axis);
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};
} }
collision_axes.push_back(axis);
break; break;
} }
} }
if(collision_axes.size() > 0) { if(collided) {
auto callback = elementAt<1>(it); auto callback = elementAt<1>(it);
if(callback) { if(callback) {
callback(utils::Entity::smuggle(entity)); callback(utils::Entity::smuggle(entity));
@@ -71,7 +77,7 @@ class CollisionComponentManager : public utils::SingleInstanceComponentManager<f
} }
} }
return collision_axes; return collisionAxes;
} }
}; };

View File

@@ -1163,7 +1163,19 @@ namespace polyvox
tm.setTransform(tm.getInstance(inst->getRoot()), transform); tm.setTransform(tm.getInstance(inst->getRoot()), transform);
} }
void AssetManager::addCollisionComponent(EntityId entityId, void(*onCollisionCallback)(EntityId entityId)) { void AssetManager::setParent(EntityId childEntityId, EntityId parentEntityId) {
auto& tm = _engine->getTransformManager();
const auto child = Entity::import(childEntityId);
const auto parent = Entity::import(parentEntityId);
const auto& parentInstance = tm.getInstance(parent);
const auto& childInstance = tm.getInstance(child);
tm.setParent(childInstance, parentInstance);
}
void AssetManager::addCollisionComponent(EntityId entityId, void(*onCollisionCallback)(EntityId entityId), bool affectsCollidingTransform) {
std::lock_guard lock(_mutex); std::lock_guard lock(_mutex);
const auto &pos = _entityIdLookup.find(entityId); const auto &pos = _entityIdLookup.find(entityId);
if (pos == _entityIdLookup.end()) if (pos == _entityIdLookup.end())
@@ -1176,6 +1188,7 @@ namespace polyvox
auto collisionInstance = _collisionComponentManager->addComponent(asset.asset->getRoot()); auto collisionInstance = _collisionComponentManager->addComponent(asset.asset->getRoot());
_collisionComponentManager->elementAt<0>(collisionInstance) = asset.asset->getInstance()->getBoundingBox(); _collisionComponentManager->elementAt<0>(collisionInstance) = asset.asset->getInstance()->getBoundingBox();
_collisionComponentManager->elementAt<1>(collisionInstance) = onCollisionCallback; _collisionComponentManager->elementAt<1>(collisionInstance) = onCollisionCallback;
_collisionComponentManager->elementAt<2>(collisionInstance) = affectsCollidingTransform;
} }
@@ -1227,18 +1240,16 @@ namespace polyvox
auto bb = asset.asset->getBoundingBox(); auto bb = asset.asset->getBoundingBox();
auto transformedBB = bb.transform(transform); auto transformedBB = bb.transform(transform);
auto collisions = _collisionComponentManager->collides(transformedBB, relativeTranslation); auto collisionAxes = _collisionComponentManager->collides(transformedBB);
Log("%d collisions", collisions.size()); if(collisionAxes.size() == 1) {
if(collisions.size() == 1) { auto globalAxis = collisionAxes[0];
auto globalAxis = collisions[0];
globalAxis *= norm(relativeTranslation); globalAxis *= norm(relativeTranslation);
auto newRelativeTranslation = relativeTranslation + globalAxis; auto newRelativeTranslation = relativeTranslation + globalAxis;
// Log("Collision axis global : %f %f %f relativeTranslation %f %f %f relativeTranslation (after subtracting global collision vector) %f %f %f", globalAxis.x, globalAxis.y, globalAxis.z, relativeTranslation.x, relativeTranslation.y, relativeTranslation.z, newRelativeTranslation.x, newRelativeTranslation.y, newRelativeTranslation.z);
translation -= relativeTranslation; translation -= relativeTranslation;
translation += newRelativeTranslation; translation += newRelativeTranslation;
transform = composeMatrix(translation, rotation, scale); transform = composeMatrix(translation, rotation, scale);
} else if(collisions.size() > 1) { } else if(collisionAxes.size() > 1) {
translation -= relativeTranslation; translation -= relativeTranslation;
transform = composeMatrix(translation, rotation, scale); transform = composeMatrix(translation, rotation, scale);
} }

View File

@@ -547,8 +547,8 @@ extern "C"
free(ptr); free(ptr);
} }
FLUTTER_PLUGIN_EXPORT void add_collision_component(void *const assetManager, EntityId entityId, void (*onCollisionCallback)(const EntityId entityId)) { FLUTTER_PLUGIN_EXPORT void add_collision_component(void *const assetManager, EntityId entityId, void (*onCollisionCallback)(const EntityId entityId), bool affectsCollidingTransform) {
((AssetManager*)assetManager)->addCollisionComponent(entityId, onCollisionCallback); ((AssetManager*)assetManager)->addCollisionComponent(entityId, onCollisionCallback, affectsCollidingTransform);
} }
FLUTTER_PLUGIN_EXPORT EntityId create_geometry(void *const viewer, float* vertices, int numVertices, uint16_t* indices, int numIndices, const char* materialPath) { FLUTTER_PLUGIN_EXPORT EntityId create_geometry(void *const viewer, float* vertices, int numVertices, uint16_t* indices, int numIndices, const char* materialPath) {
@@ -560,4 +560,8 @@ extern "C"
return Entity::smuggle(entity); return Entity::smuggle(entity);
} }
FLUTTER_PLUGIN_EXPORT void set_parent(void *const assetManager, EntityId child, EntityId parent) {
((AssetManager*)assetManager)->setParent(child, parent);
}
} }

View File

@@ -564,11 +564,17 @@ abstract class FilamentController {
/// If there is a collision between the controlled entity and [collidableEntity], the transform will not be updated. /// If there is a collision between the controlled entity and [collidableEntity], the transform will not be updated.
/// ///
Future addCollisionComponent(FilamentEntity collidableEntity, Future addCollisionComponent(FilamentEntity collidableEntity,
{void Function(int entityId)? callback}); {void Function(int entityId)? callback,
bool affectsCollingTransform = false});
/// ///
/// Creates a (renderable) entity with the specified geometry and adds to the scene. /// Creates a (renderable) entity with the specified geometry and adds to the scene.
/// ///
Future createGeometry( Future createGeometry(
List<double> vertices, List<int> indices, String? materialPath); List<double> vertices, List<int> indices, String? materialPath);
///
/// Sets the parent transform of [child] to the transform of [parent].
///
Future setParent(FilamentEntity child, FilamentEntity parent);
} }

View File

@@ -13,7 +13,7 @@ import 'package:flutter_filament/filament_controller.dart';
import 'package:flutter_filament/animations/animation_data.dart'; import 'package:flutter_filament/animations/animation_data.dart';
import 'package:flutter_filament/generated_bindings.dart'; import 'package:flutter_filament/generated_bindings.dart';
import 'package:flutter_filament/hardware/hardware_keyboard_listener.dart'; import 'package:flutter_filament/hardware/hardware_keyboard_listener.dart';
import 'package:flutter_filament/hardware/hardware_keyboard_poll.dart';
import 'package:flutter_filament/rendering_surface.dart'; import 'package:flutter_filament/rendering_surface.dart';
import 'package:vector_math/vector_math_64.dart'; import 'package:vector_math/vector_math_64.dart';
@@ -1391,7 +1391,8 @@ class FilamentControllerFFI extends FilamentController {
@override @override
Future addCollisionComponent(FilamentEntity entity, Future addCollisionComponent(FilamentEntity entity,
{void Function(int entityId)? callback}) async { {void Function(int entityId)? callback,
bool affectsCollingTransform = false}) async {
if (_assetManager == null) { if (_assetManager == null) {
throw Exception("AssetManager must be non-null"); throw Exception("AssetManager must be non-null");
} }
@@ -1400,9 +1401,11 @@ class FilamentControllerFFI extends FilamentController {
if (callback != null) { if (callback != null) {
var ptr = var ptr =
NativeCallable<Void Function(Int32 entityId)>.listener(callback); NativeCallable<Void Function(Int32 entityId)>.listener(callback);
add_collision_component(_assetManager!, entity, ptr.nativeFunction); add_collision_component(
_assetManager!, entity, ptr.nativeFunction, affectsCollingTransform);
} else { } else {
add_collision_component(_assetManager!, entity, nullptr); add_collision_component(
_assetManager!, entity, nullptr, affectsCollingTransform);
} }
} }
@@ -1440,4 +1443,12 @@ class FilamentControllerFFI extends FilamentController {
return entity; return entity;
} }
@override
Future setParent(FilamentEntity child, FilamentEntity parent) async {
if (_assetManager == null) {
throw Exception("Asset manager must be non-null");
}
set_parent(_assetManager!, child, parent);
}
} }