add testCollisions method for manual collision checking

This commit is contained in:
Nick Fisher
2024-02-18 21:48:03 +08:00
parent 6c37368aea
commit a10fe6584d
9 changed files with 40 additions and 160 deletions

View File

@@ -189,10 +189,10 @@ extern "C"
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 sceneManager, EntityId entityId, void (*callback)(const EntityId entityId1, const EntityId entityId2), 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 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 sceneManager, EntityId child, EntityId parent); FLUTTER_PLUGIN_EXPORT void set_parent(void *const sceneManager, EntityId child, EntityId parent);
FLUTTER_PLUGIN_EXPORT void test_collisions(void *const sceneManager, EntityId entity);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -49,6 +49,7 @@ namespace polyvox
size_t getLightEntityCount(EntityId e) const noexcept; size_t getLightEntityCount(EntityId e) const noexcept;
void updateAnimations(); void updateAnimations();
void updateTransforms(); void updateTransforms();
void testCollisions(EntityId entity);
bool setMaterialColor(EntityId e, const char *meshName, int materialInstance, const float r, const float g, const float b, const float a); bool setMaterialColor(EntityId e, const char *meshName, int materialInstance, const float r, const float g, const float b, const float a);
bool setMorphAnimationBuffer( bool setMorphAnimationBuffer(
@@ -105,10 +106,8 @@ namespace polyvox
const char* getEntityNameAt(EntityId entity, int index, bool renderableOnly); const char* getEntityNameAt(EntityId entity, int index, bool renderableOnly);
void addCollisionComponent(EntityId entity, void (*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform); void addCollisionComponent(EntityId entity, void (*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform);
void removeCollisionComponent(EntityId entityId); void removeCollisionComponent(EntityId entityId);
void markNonTransformableCollidable(EntityId entity);
void unmarkNonTransformableCollidable(EntityId entity);
void checkNonTransformableCollisions();
void setParent(EntityId child, EntityId parent); void setParent(EntityId child, EntityId parent);
private: private:
AssetLoader *_assetLoader = nullptr; AssetLoader *_assetLoader = nullptr;

View File

@@ -1042,7 +1042,6 @@ namespace polyvox
_sceneManager->updateTransforms(); _sceneManager->updateTransforms();
_sceneManager->updateAnimations(); _sceneManager->updateAnimations();
_sceneManager->checkNonTransformableCollisions();
_cumulativeAnimationUpdateTime += tmr.elapsed(); _cumulativeAnimationUpdateTime += tmr.elapsed();

View File

@@ -566,15 +566,6 @@ extern "C"
((SceneManager*)sceneManager)->addCollisionComponent(entityId, onCollisionCallback, affectsCollidingTransform); ((SceneManager*)sceneManager)->addCollisionComponent(entityId, onCollisionCallback, affectsCollidingTransform);
} }
FLUTTER_PLUGIN_EXPORT void mark_nontransformable_collidable(void *const sceneManager, EntityId entityId) {
((SceneManager*)sceneManager)->markNonTransformableCollidable(entityId);
}
FLUTTER_PLUGIN_EXPORT void unmark_nontransformable_collidable(void *const sceneManager, EntityId entityId) {
((SceneManager*)sceneManager)->unmarkNonTransformableCollidable(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 EntityId create_geometry(void *const viewer, float* vertices, int numVertices, uint16_t* indices, int numIndices, const char* materialPath) {
return ((FilamentViewer*)viewer)->createGeometry(vertices, (size_t)numVertices, indices, numIndices, materialPath); return ((FilamentViewer*)viewer)->createGeometry(vertices, (size_t)numVertices, indices, numIndices, materialPath);
} }
@@ -588,4 +579,8 @@ extern "C"
((SceneManager*)sceneManager)->setParent(child, parent); ((SceneManager*)sceneManager)->setParent(child, parent);
} }
FLUTTER_PLUGIN_EXPORT void test_collisions(void *const sceneManager, EntityId entity) {
((SceneManager*)sceneManager)->testCollisions(entity);
}
} }

View File

@@ -1237,67 +1237,24 @@ namespace polyvox
_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) = affectsTransform; _collisionComponentManager->elementAt<2>(collisionInstance) = affectsTransform;
} }
void SceneManager::markNonTransformableCollidable(EntityId entityId) { void SceneManager::testCollisions(EntityId entityId) {
// Log("Marking entity %d as non-transforming collidable", entityId); const auto &pos = _entityIdLookup.find(entityId);
std::lock_guard lock(_mutex); if (pos == _entityIdLookup.end())
for(auto& existing : _nonTransformableCollidableEntities) { {
if(existing == entityId) { Log("ERROR: asset not found for entity.");
Log("Collision already exists"); return;
return;
}
} }
_nonTransformableCollidableEntities.push_back(entityId); auto &asset = _assets[pos->second];
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(); const auto& tm = _engine->getTransformManager();
for(const auto& entityId : _nonTransformableCollidableEntities) {
const auto &pos = _entityIdLookup.find(entityId); auto transformInstance = tm.getInstance(asset.asset->getRoot());
if (pos == _entityIdLookup.end()) auto worldTransform = tm.getWorldTransform(transformInstance);
{ auto aabb = asset.asset->getInstance()->getBoundingBox();
Log("ERROR: asset not found for entity."); aabb = aabb.transform(worldTransform);
continue; _collisionComponentManager->collides(entityId, aabb);
}
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);
}
} }
@@ -1305,6 +1262,7 @@ namespace polyvox
std::lock_guard lock(_mutex); std::lock_guard lock(_mutex);
auto &tm = _engine->getTransformManager(); auto &tm = _engine->getTransformManager();
for ( const auto &[entityId, transformUpdate]: _transformUpdates ) { for ( const auto &[entityId, transformUpdate]: _transformUpdates ) {
const auto &pos = _entityIdLookup.find(entityId); const auto &pos = _entityIdLookup.find(entityId);
if (pos == _entityIdLookup.end()) if (pos == _entityIdLookup.end())

View File

@@ -1,54 +0,0 @@
// we know there's been a collision, but we want to adjust the direction vector to continue movement in the non-colliding direction
// first, we need to find the AABB plane that we have collided with
auto vertices = targetBox.getCorners().vertices;
// each entry here is a plane from the target bounding box
// (we drop the fourth vertex because it's mathematically not necessary to define the plane)
std::vector<std::vector<filament::math::float3>> planes = {
{
vertices[0],vertices[2],vertices[4] // bottom
},
{
vertices[1],vertices[3],vertices[5] // top
},
{
vertices[0],vertices[1],vertices[4] // back
},
{
vertices[0],vertices[1],vertices[2] // left
},
{
vertices[4],vertices[5],vertices[6] // right
},
{
vertices[2],vertices[3],vertices[6] //front
},
};
// now, iterate over each plane and project the intersecting source vertex onto it
// the smallest value will be the closest plane
auto sourceVertex = sourceCorners.vertices[i];
int planeIndex = -1;
int minDist = 999999.0f;
filament::math::float3 projection;
for(int j = 0; j < 6; j++) {
// translate the plane so the intersecting source vertex is at the origin
auto plane = std::vector<filament::math::float3>{ planes[j][0] - sourceVertex, planes[j][1] - sourceVertex, planes[j][2] - sourceVertex };
// cross product of the two known co-planar vectors to find the normal
auto normal = normalize(cross(plane[1] - plane[0], plane[2] - plane[1]));
// project the normal onto the original (untranslated) plane vector
auto dist = dot(planes[j][0], normal) / norm(planes[j][0]);
Log("Dist : %f", dist);
if(dist < minDist) {
minDist = dist;
planeIndex = j;
}
}
Log("Collision with plane index %d", planeIndex);
auto sourceNormal = normalize(cross(planes[planeIndex][1] - planes[planeIndex][0], planes[planeIndex][2] - planes[planeIndex][1]));
projection = direction - (sourceNormal * dot(sourceNormal, direction));

View File

@@ -6,6 +6,7 @@ import 'package:flutter/widgets.dart';
import 'package:flutter_filament/animations/animation_data.dart'; import 'package:flutter_filament/animations/animation_data.dart';
import 'package:flutter_filament/entities/entity_transform_controller.dart'; import 'package:flutter_filament/entities/entity_transform_controller.dart';
import 'package:flutter_filament/generated_bindings.dart';
import 'package:vector_math/vector_math_64.dart'; import 'package:vector_math/vector_math_64.dart';
// a handle that can be safely passed back to the rendering layer to manipulate an Entity // a handle that can be safely passed back to the rendering layer to manipulate an Entity
@@ -594,16 +595,6 @@ abstract class FilamentController {
{void Function(int entityId1, int entityId2)? callback, {void Function(int entityId1, int entityId2)? callback,
bool affectsCollingTransform = false}); 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. /// Creates a (renderable) entity with the specified geometry and adds to the scene.
/// ///
@@ -614,4 +605,10 @@ abstract class FilamentController {
/// Sets the parent transform of [child] to the transform of [parent]. /// Sets the parent transform of [child] to the transform of [parent].
/// ///
Future setParent(FilamentEntity child, FilamentEntity parent); Future setParent(FilamentEntity child, FilamentEntity parent);
///
/// Test all collidable entities against this entity to see if any have collided.
/// This method returns void; the relevant callback passed to [addCollisionComponent] will be fired if a collision is detected.
///
Future testCollisions(FilamentEntity entity);
} }

View File

@@ -1437,16 +1437,6 @@ class FilamentControllerFFI extends FilamentController {
} }
} }
@override
Future markNonTransformableCollidable(FilamentEntity entity) async {
mark_nontransformable_collidable(_sceneManager!, entity);
}
@override
Future unmarkNonTransformableCollidable(FilamentEntity entity) async {
unmark_nontransformable_collidable(_sceneManager!, entity);
}
@override @override
Future<FilamentEntity> createGeometry( Future<FilamentEntity> createGeometry(
List<double> vertices, List<int> indices, String? materialPath) async { List<double> vertices, List<int> indices, String? materialPath) async {
@@ -1489,4 +1479,9 @@ class FilamentControllerFFI extends FilamentController {
} }
set_parent(_sceneManager!, child, parent); set_parent(_sceneManager!, child, parent);
} }
@override
Future testCollisions(FilamentEntity entity) async {
test_collisions(_sceneManager!, entity);
}
} }

View File

@@ -891,22 +891,6 @@ external void add_collision_component(
bool affectsCollidingTransform, bool affectsCollidingTransform,
); );
@ffi.Native<ffi.Void Function(ffi.Pointer<ffi.Void>, EntityId)>(
symbol: 'mark_nontransformable_collidable',
assetId: 'flutter_filament_plugin')
external void mark_nontransformable_collidable(
ffi.Pointer<ffi.Void> sceneManager,
int entityId,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<ffi.Void>, EntityId)>(
symbol: 'unmark_nontransformable_collidable',
assetId: 'flutter_filament_plugin')
external void unmark_nontransformable_collidable(
ffi.Pointer<ffi.Void> sceneManager,
int entityId,
);
@ffi.Native< @ffi.Native<
EntityId Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Float>, EntityId Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Float>,
ffi.Int, ffi.Pointer<ffi.Uint16>, ffi.Int, ffi.Pointer<ffi.Char>)>( ffi.Int, ffi.Pointer<ffi.Uint16>, ffi.Int, ffi.Pointer<ffi.Char>)>(
@@ -928,6 +912,13 @@ external void set_parent(
int parent, int parent,
); );
@ffi.Native<ffi.Void Function(ffi.Pointer<ffi.Void>, EntityId)>(
symbol: 'test_collisions', assetId: 'flutter_filament_plugin')
external void test_collisions(
ffi.Pointer<ffi.Void> sceneManager,
int entity,
);
@ffi.Native< @ffi.Native<
ffi.Pointer<ffi.Void> Function( ffi.Pointer<ffi.Void> Function(
ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>,