support collisions & restructure transforms to only update once per frame
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "SceneAsset.hpp"
|
#include "SceneAsset.hpp"
|
||||||
#include "ResourceBuffer.hpp"
|
#include "ResourceBuffer.hpp"
|
||||||
|
#include "components/StandardComponents.h"
|
||||||
|
|
||||||
typedef int32_t EntityId;
|
typedef int32_t EntityId;
|
||||||
|
|
||||||
@@ -45,6 +46,7 @@ namespace polyvox
|
|||||||
const utils::Entity *getLightEntities(EntityId e) const noexcept;
|
const utils::Entity *getLightEntities(EntityId e) const noexcept;
|
||||||
size_t getLightEntityCount(EntityId e) const noexcept;
|
size_t getLightEntityCount(EntityId e) const noexcept;
|
||||||
void updateAnimations();
|
void updateAnimations();
|
||||||
|
void updateTransforms();
|
||||||
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(
|
||||||
@@ -99,6 +101,7 @@ 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);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AssetLoader *_assetLoader = nullptr;
|
AssetLoader *_assetLoader = nullptr;
|
||||||
@@ -110,10 +113,13 @@ namespace polyvox
|
|||||||
gltfio::ResourceLoader *_gltfResourceLoader = nullptr;
|
gltfio::ResourceLoader *_gltfResourceLoader = nullptr;
|
||||||
gltfio::TextureProvider *_stbDecoder = nullptr;
|
gltfio::TextureProvider *_stbDecoder = nullptr;
|
||||||
gltfio::TextureProvider *_ktxDecoder = nullptr;
|
gltfio::TextureProvider *_ktxDecoder = nullptr;
|
||||||
std::mutex _animationMutex;
|
std::mutex _mutex;
|
||||||
|
|
||||||
vector<SceneAsset> _assets;
|
vector<SceneAsset> _assets;
|
||||||
tsl::robin_map<EntityId, int> _entityIdLookup;
|
tsl::robin_map<EntityId, int> _entityIdLookup;
|
||||||
|
tsl::robin_map<EntityId, std::tuple<math::float3,bool,math::quatf,bool,float>> _transformUpdates;
|
||||||
|
|
||||||
|
CollisionComponentManager* _collisionComponentManager = nullptr;
|
||||||
|
|
||||||
utils::Entity findEntityByName(
|
utils::Entity findEntityByName(
|
||||||
SceneAsset asset,
|
SceneAsset asset,
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ 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);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -80,6 +80,10 @@ namespace polyvox
|
|||||||
_gltfResourceLoader->addTextureProvider ("image/ktx2", _ktxDecoder);
|
_gltfResourceLoader->addTextureProvider ("image/ktx2", _ktxDecoder);
|
||||||
_gltfResourceLoader->addTextureProvider("image/png", _stbDecoder);
|
_gltfResourceLoader->addTextureProvider("image/png", _stbDecoder);
|
||||||
_gltfResourceLoader->addTextureProvider("image/jpeg", _stbDecoder);
|
_gltfResourceLoader->addTextureProvider("image/jpeg", _stbDecoder);
|
||||||
|
|
||||||
|
const auto& tm = _engine->getTransformManager();
|
||||||
|
|
||||||
|
_collisionComponentManager = new CollisionComponentManager(tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetManager::~AssetManager()
|
AssetManager::~AssetManager()
|
||||||
@@ -325,7 +329,7 @@ namespace polyvox
|
|||||||
|
|
||||||
void AssetManager::updateAnimations()
|
void AssetManager::updateAnimations()
|
||||||
{
|
{
|
||||||
std::lock_guard lock(_animationMutex);
|
std::lock_guard lock(_mutex);
|
||||||
RenderableManager &rm = _engine->getRenderableManager();
|
RenderableManager &rm = _engine->getRenderableManager();
|
||||||
|
|
||||||
auto now = high_resolution_clock::now();
|
auto now = high_resolution_clock::now();
|
||||||
@@ -456,7 +460,7 @@ namespace polyvox
|
|||||||
// - 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?
|
// - 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 AssetManager::setBoneTransform(EntityId entityId, const char *entityName, int32_t skinIndex, const char* boneName, math::mat4f localTransform)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(_animationMutex);
|
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())
|
||||||
@@ -542,7 +546,7 @@ namespace polyvox
|
|||||||
|
|
||||||
void AssetManager::remove(EntityId entityId)
|
void AssetManager::remove(EntityId entityId)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(_animationMutex);
|
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())
|
||||||
{
|
{
|
||||||
@@ -618,7 +622,7 @@ namespace polyvox
|
|||||||
}
|
}
|
||||||
|
|
||||||
utils::Entity AssetManager::findChildEntityByName(EntityId entityId, const char *entityName) {
|
utils::Entity AssetManager::findChildEntityByName(EntityId entityId, const char *entityName) {
|
||||||
std::lock_guard lock(_animationMutex);
|
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())
|
||||||
@@ -672,7 +676,7 @@ namespace polyvox
|
|||||||
int numFrames,
|
int numFrames,
|
||||||
float frameLengthInMs)
|
float frameLengthInMs)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(_animationMutex);
|
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())
|
||||||
@@ -749,7 +753,7 @@ namespace polyvox
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AssetManager::resetBones(EntityId entityId) {
|
void AssetManager::resetBones(EntityId entityId) {
|
||||||
std::lock_guard lock(_animationMutex);
|
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())
|
||||||
@@ -788,7 +792,7 @@ namespace polyvox
|
|||||||
float frameLengthInMs,
|
float frameLengthInMs,
|
||||||
bool isModelSpace)
|
bool isModelSpace)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(_animationMutex);
|
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())
|
||||||
@@ -903,7 +907,7 @@ namespace polyvox
|
|||||||
|
|
||||||
void AssetManager::playAnimation(EntityId e, int index, bool loop, bool reverse, bool replaceActive, float crossfade)
|
void AssetManager::playAnimation(EntityId e, int index, bool loop, bool reverse, bool replaceActive, float crossfade)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(_animationMutex);
|
std::lock_guard lock(_mutex);
|
||||||
|
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
{
|
{
|
||||||
@@ -960,7 +964,7 @@ namespace polyvox
|
|||||||
|
|
||||||
void AssetManager::stopAnimation(EntityId entityId, int index)
|
void AssetManager::stopAnimation(EntityId entityId, int index)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(_animationMutex);
|
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())
|
||||||
@@ -1149,8 +1153,6 @@ namespace polyvox
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto &asset = _assets[pos->second];
|
auto &asset = _assets[pos->second];
|
||||||
|
|
||||||
Log("Transforming asset to unit cube.");
|
|
||||||
auto &tm = _engine->getTransformManager();
|
auto &tm = _engine->getTransformManager();
|
||||||
FilamentInstance *inst = asset.asset->getInstance();
|
FilamentInstance *inst = asset.asset->getInstance();
|
||||||
auto aabb = inst->getBoundingBox();
|
auto aabb = inst->getBoundingBox();
|
||||||
@@ -1163,97 +1165,120 @@ namespace polyvox
|
|||||||
tm.setTransform(tm.getInstance(inst->getRoot()), transform);
|
tm.setTransform(tm.getInstance(inst->getRoot()), transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetManager::setScale(EntityId entity, float newScale)
|
void AssetManager::addCollisionComponent(EntityId entityId) {
|
||||||
{
|
std::lock_guard lock(_mutex);
|
||||||
const auto &pos = _entityIdLookup.find(entity);
|
const auto &pos = _entityIdLookup.find(entityId);
|
||||||
if (pos == _entityIdLookup.end())
|
if (pos == _entityIdLookup.end())
|
||||||
{
|
{
|
||||||
Log("ERROR: asset not found for entity.");
|
Log("ERROR: asset not found for entity.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto &asset = _assets[pos->second];
|
auto &asset = _assets[pos->second];
|
||||||
|
auto collisionInstance = _collisionComponentManager->addComponent(asset.asset->getRoot());
|
||||||
|
_collisionComponentManager->elementAt<0>(collisionInstance) = asset.asset->getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetManager::updateTransforms() {
|
||||||
|
std::lock_guard lock(_mutex);
|
||||||
|
|
||||||
auto &tm = _engine->getTransformManager();
|
auto &tm = _engine->getTransformManager();
|
||||||
|
for ( const auto &[entityId, transformUpdate]: _transformUpdates ) {
|
||||||
|
const auto &pos = _entityIdLookup.find(entityId);
|
||||||
|
if (pos == _entityIdLookup.end())
|
||||||
|
{
|
||||||
|
Log("ERROR: asset not found for entity.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto &asset = _assets[pos->second];
|
||||||
auto transformInstance = tm.getInstance(asset.asset->getRoot());
|
auto transformInstance = tm.getInstance(asset.asset->getRoot());
|
||||||
|
|
||||||
auto transform = tm.getTransform(transformInstance);
|
auto transform = tm.getTransform(transformInstance);
|
||||||
|
|
||||||
|
math::float3 newTranslation = std::get<0>(transformUpdate);
|
||||||
|
bool newTranslationRelative = std::get<1>(transformUpdate);
|
||||||
|
math::quatf newRotation = std::get<2>(transformUpdate);
|
||||||
|
bool newRotationRelative = std::get<3>(transformUpdate);
|
||||||
|
float newScale = std::get<4>(transformUpdate);
|
||||||
|
|
||||||
math::float3 translation;
|
math::float3 translation;
|
||||||
math::quatf rotation;
|
math::quatf rotation;
|
||||||
math::float3 scale;
|
math::float3 scale;
|
||||||
|
|
||||||
decomposeMatrix(transform, &translation, &rotation, &scale);
|
decomposeMatrix(transform, &translation, &rotation, &scale);
|
||||||
scale = { newScale, newScale, newScale};
|
|
||||||
|
if(newRotationRelative) {
|
||||||
|
rotation = normalize(rotation * newRotation);
|
||||||
|
} else {
|
||||||
|
rotation = newRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(newTranslationRelative) {
|
||||||
|
math::mat3f rotationMatrix(rotation);
|
||||||
|
math::float3 relativeTranslation = rotationMatrix * newTranslation;
|
||||||
|
translation += relativeTranslation;
|
||||||
|
} else {
|
||||||
|
translation = newTranslation;
|
||||||
|
}
|
||||||
|
|
||||||
transform = composeMatrix(translation, rotation, scale);
|
transform = composeMatrix(translation, rotation, scale);
|
||||||
|
auto bb = asset.asset->getBoundingBox();
|
||||||
|
auto transformedBB = bb.transform(transform);
|
||||||
|
if(!_collisionComponentManager->collides(transformedBB)) {
|
||||||
tm.setTransform(transformInstance, transform);
|
tm.setTransform(transformInstance, transform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_transformUpdates.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetManager::setScale(EntityId entity, 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetManager::setPosition(EntityId entity, float x, float y, float z, bool relative)
|
void AssetManager::setPosition(EntityId entity, float x, float y, float z, bool relative)
|
||||||
{
|
{
|
||||||
const auto &pos = _entityIdLookup.find(entity);
|
std::lock_guard lock(_mutex);
|
||||||
if (pos == _entityIdLookup.end())
|
const auto &pos = _transformUpdates.find(entity);
|
||||||
|
if (pos == _transformUpdates.end())
|
||||||
{
|
{
|
||||||
Log("ERROR: asset not found for entity.");
|
_transformUpdates.emplace(entity, make_tuple(math::float3(), true, math::quatf(1.0f), true, 1.0f));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
auto &asset = _assets[pos->second];
|
auto curr = _transformUpdates[entity];
|
||||||
|
auto& trans = get<0>(curr);
|
||||||
auto &tm = _engine->getTransformManager();
|
trans.x = x;
|
||||||
auto transformInstance = tm.getInstance(asset.asset->getRoot());
|
trans.y = y;
|
||||||
|
trans.z = z;
|
||||||
auto transform = tm.getTransform(transformInstance);
|
|
||||||
|
|
||||||
math::float3 translation;
|
|
||||||
math::quatf rotation;
|
|
||||||
math::float3 scale;
|
|
||||||
|
|
||||||
decomposeMatrix(transform, &translation, &rotation, &scale);
|
|
||||||
if(relative) {
|
|
||||||
math::mat3f rotationMatrix(rotation);
|
|
||||||
math::float3 relativeTranslation = rotationMatrix * math::float3( x, y, z );
|
|
||||||
translation += relativeTranslation;
|
|
||||||
} else {
|
|
||||||
translation = math::float3(x,y,z);
|
|
||||||
}
|
|
||||||
|
|
||||||
transform = composeMatrix(translation, rotation, scale);
|
|
||||||
tm.setTransform(transformInstance, transform);
|
|
||||||
|
|
||||||
|
auto& isRelative = get<1>(curr);
|
||||||
|
isRelative = relative;
|
||||||
|
_transformUpdates[entity] = curr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetManager::setRotation(EntityId entity, float rads, float x, float y, float z, float w, bool relative)
|
void AssetManager::setRotation(EntityId entity, float rads, float x, float y, float z, float w, bool relative)
|
||||||
{
|
{
|
||||||
const auto &pos = _entityIdLookup.find(entity);
|
std::lock_guard lock(_mutex);
|
||||||
if (pos == _entityIdLookup.end())
|
const auto &pos = _transformUpdates.find(entity);
|
||||||
|
if (pos == _transformUpdates.end())
|
||||||
{
|
{
|
||||||
Log("ERROR: asset not found for entity.");
|
_transformUpdates.emplace(entity, make_tuple(math::float3(), true, math::quatf(1.0f), true, 1.0f));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
auto &asset = _assets[pos->second];
|
auto curr = _transformUpdates[entity];
|
||||||
|
auto& rot = std::get<2>(curr);
|
||||||
auto &tm = _engine->getTransformManager();
|
rot.w = w;
|
||||||
auto transformInstance = tm.getInstance(asset.asset->getRoot());
|
rot.x = x;
|
||||||
|
rot.y = y;
|
||||||
auto transform = tm.getTransform(transformInstance);
|
rot.z = z;
|
||||||
|
auto& isRelative = get<3>(curr);
|
||||||
math::float3 translation;
|
isRelative = relative;
|
||||||
math::quatf rotation;
|
_transformUpdates[entity] = curr;
|
||||||
math::float3 scale;
|
|
||||||
|
|
||||||
decomposeMatrix(transform, &translation, &rotation, &scale);
|
|
||||||
|
|
||||||
if(relative) {
|
|
||||||
rotation = normalize(rotation * math::quatf(w,x,y,z));
|
|
||||||
} else {
|
|
||||||
rotation = math::quatf(w,x,y,z);
|
|
||||||
}
|
|
||||||
|
|
||||||
transform = composeMatrix(translation, rotation, scale);
|
|
||||||
tm.setTransform(transformInstance, transform);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const utils::Entity *AssetManager::getCameraEntities(EntityId entity)
|
const utils::Entity *AssetManager::getCameraEntities(EntityId entity)
|
||||||
|
|||||||
@@ -1040,6 +1040,7 @@ namespace polyvox
|
|||||||
|
|
||||||
Timer tmr;
|
Timer tmr;
|
||||||
|
|
||||||
|
_assetManager->updateTransforms();
|
||||||
_assetManager->updateAnimations();
|
_assetManager->updateAnimations();
|
||||||
|
|
||||||
_cumulativeAnimationUpdateTime += tmr.elapsed();
|
_cumulativeAnimationUpdateTime += tmr.elapsed();
|
||||||
|
|||||||
@@ -536,4 +536,8 @@ extern "C"
|
|||||||
{
|
{
|
||||||
free(ptr);
|
free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FLUTTER_PLUGIN_EXPORT void add_collision_component(void *const assetManager, EntityId entityId) {
|
||||||
|
((AssetManager*)assetManager)->addCollisionComponent(entityId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -538,4 +538,11 @@ abstract class FilamentController {
|
|||||||
|
|
||||||
Future<EntityTransformController> control(FilamentEntity entity,
|
Future<EntityTransformController> control(FilamentEntity entity,
|
||||||
{double? translationSpeed, String? forwardAnimation});
|
{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.
|
||||||
|
///
|
||||||
|
Future addCollisionComponent(FilamentEntity collidableEntity);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1358,4 +1358,13 @@ class FilamentControllerFFI extends FilamentController {
|
|||||||
_keyboardListener = HardwareKeyboardListener(transformController);
|
_keyboardListener = HardwareKeyboardListener(transformController);
|
||||||
return transformController;
|
return transformController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future addCollisionComponent(FilamentEntity entity) async {
|
||||||
|
if (_assetManager == null) {
|
||||||
|
throw Exception("AssetManager must be non-null");
|
||||||
|
}
|
||||||
|
|
||||||
|
add_collision_component(_assetManager!, entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -828,6 +828,13 @@ external void flutter_filament_free(
|
|||||||
ffi.Pointer<ffi.Void> ptr,
|
ffi.Pointer<ffi.Void> ptr,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ffi.Native<ffi.Void Function(ffi.Pointer<ffi.Void>, EntityId)>(
|
||||||
|
symbol: 'add_collision_component', assetId: 'flutter_filament_plugin')
|
||||||
|
external void add_collision_component(
|
||||||
|
ffi.Pointer<ffi.Void> assetManager,
|
||||||
|
int entityId,
|
||||||
|
);
|
||||||
|
|
||||||
@ffi.Native<
|
@ffi.Native<
|
||||||
ffi.Pointer<ffi.Void> Function(
|
ffi.Pointer<ffi.Void> Function(
|
||||||
ffi.Pointer<ffi.Void>,
|
ffi.Pointer<ffi.Void>,
|
||||||
|
|||||||
Reference in New Issue
Block a user