diff --git a/thermion_dart/native/src/SceneManager.cpp b/thermion_dart/native/src/SceneManager.cpp index 1f4da40a..73924817 100644 --- a/thermion_dart/native/src/SceneManager.cpp +++ b/thermion_dart/native/src/SceneManager.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -91,7 +92,15 @@ namespace thermion_filament _collisionComponentManager = new CollisionComponentManager(tm); _animationComponentManager = new AnimationComponentManager(tm, _engine->getRenderableManager()); - _gizmo = new Gizmo(_engine); + gizmo = new Gizmo(*_engine); + _gridOverlay = new GridOverlay(*_engine); + + _scene->addEntity(_gridOverlay->sphere()); + _scene->addEntity(_gridOverlay->grid()); + + _view->setLayerEnabled(0, true); // scene assets + _view->setLayerEnabled(1, true); // gizmo + _view->setLayerEnabled(2, false); // world grid } SceneManager::~SceneManager() @@ -99,7 +108,8 @@ namespace thermion_filament destroyAll(); - _gizmo->destroy(_engine); + gizmo->destroy(); + _gridOverlay->destroy(); _gltfResourceLoader->asyncCancelLoad(); _ubershaderProvider->destroyMaterials(); @@ -1628,16 +1638,12 @@ namespace thermion_filament _animationComponentManager->update(); } - - void SceneManager::updateTransforms() { std::lock_guard lock(_mutex); auto &tm = _engine->getTransformManager(); - _gizmo->updateTransform(); - for (const auto &[entityId, transformUpdate] : _transformUpdates) { const auto &pos = _instances.find(entityId); @@ -1723,6 +1729,7 @@ namespace thermion_filament tm.setTransform(transformInstance, transform); } _transformUpdates.clear(); + gizmo->updateTransform(_view->getCamera(), _view->getViewport()); } void SceneManager::setScale(EntityId entityId, float newScale) @@ -1796,77 +1803,222 @@ namespace thermion_filament tm.setTransform(transformInstance, newTransform); } - void SceneManager::queuePositionUpdate(EntityId entity, float x, float y, float z, bool relative) -{ - std::lock_guard lock(_mutex); - const auto &pos = _transformUpdates.find(entity); - if (pos == _transformUpdates.end()) + // Log("view matrix %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f", + // viewMatrix[0][0], viewMatrix[0][1], viewMatrix[0][2], viewMatrix[0][3], + // viewMatrix[1][0], viewMatrix[1][1], viewMatrix[1][2], viewMatrix[1][3], + // viewMatrix[2][0], viewMatrix[2][1], viewMatrix[2][2], viewMatrix[2][3], + // viewMatrix[3][0], viewMatrix[3][1], viewMatrix[3][2], viewMatrix[3][3]); + + + + // math::float4 worldspace = { 250.0f, 0.0f, 0.0f, 1.0f }; + // math::float4 viewSpace = viewMatrix * worldspace; + // Log("viewspace %f %f %f %f", viewSpace.x, viewSpace.y, viewSpace.z, viewSpace.w); + + // math::float4 clipSpace = camera.getProjectionMatrix() * viewSpace; + // Log("clip space %f %f %f %f", clipSpace.x, clipSpace.y, clipSpace.z, clipSpace.w); + + // math::float4 ndc = clipSpace / clipSpace.w; + // Log("ndc %f %f %f %f", ndc.x, ndc.y, ndc.z, ndc.w); + + // ndc.x = -1.0; + + // // Multiply by inverse view-projection matrix + // auto inverseProj = inverse(camera.getProjectionMatrix()); + // clipSpace = inverseProj * math::float4 { ndc.x, ndc.y, ndc.z, 1.0f }; + // viewSpace = clipSpace / clipSpace.w; + // Log("clip space %f %f %f %f", viewSpace.x, viewSpace.y, viewSpace.z, viewSpace.w); + + // auto inverseView = inverse(viewMatrix); + // worldspace = inverseView * viewSpace; + // Log("worldspace space %f %f %f %f", worldspace.x, worldspace.y, worldspace.z, worldspace.w); + + // return; + + void SceneManager::queueRelativePositionUpdateWorldAxis(EntityId entity, float viewportCoordX, float viewportCoordY, float x, float y, float z) { - _transformUpdates.emplace(entity, std::make_tuple(math::float3(), true, math::quatf(1.0f), true, 1.0f)); - } - auto curr = _transformUpdates[entity]; - auto &trans = std::get<0>(curr); - const auto &tm = _engine->getTransformManager(); - auto transformInstance = tm.getInstance(Entity::import(entity)); - auto transform = tm.getTransform(transformInstance); - math::double4 position { 0.0f, 0.0f, 0.0f, 1.0f}; - math::mat4 worldTransform = tm.getWorldTransformAccurate(transformInstance); - position = worldTransform * position; + auto worldAxis = math::float3 { x, y, z}; - // Get camera's view matrix and its inverse - const Camera &camera = _view->getCamera(); + // Get the camera + const auto &camera = _view->getCamera(); + const auto &vp = _view->getViewport(); + auto viewMatrix = camera.getViewMatrix(); + + // Scale the viewport movement to NDC coordinates view axis + math::float2 viewportMovementNDC(viewportCoordX / (vp.width / 2), viewportCoordY / (vp.height / 2)); - math::mat4 viewMatrix = camera.getViewMatrix(); - math::mat4 invViewMatrix = inverse(viewMatrix); + // First we need to get the orientation of the specified world axis in screen space + math::float4 viewAxis = viewMatrix * math::float4 { x, y, z, 1.0f }; + // Apply projection matrix to get clip space axis + math::float4 clipAxis = camera.getProjectionMatrix() * viewAxis; + // Perform perspective division to get normalized device coordinates (NDC) + math::float2 ndcAxis = (clipAxis.xyz / clipAxis.w).xy; - // Transform object position to view space - math::double4 viewSpacePos = viewMatrix * position; + // project viewportMovementNDC onto axis + float projectedMovement = dot(viewportMovementNDC, normalize(ndcAxis)); + auto translationNDC = projectedMovement * normalize(ndcAxis); - Log("viewSpacePos %f %f %f %f", viewSpacePos.x, viewSpacePos.y, viewSpacePos.z, viewSpacePos.w); + // Log("projectedMovement %f translationNDC %f %f", projectedMovement, translationNDC.x, translationNDC.y); - // Calculate plane distance from camera - float planeDistance = -viewSpacePos.z; + // Get the camera's field of view and aspect ratio + float fovY = camera.getFieldOfViewInDegrees(filament::Camera::Fov::VERTICAL); + float fovX = camera.getFieldOfViewInDegrees(filament::Camera::Fov::HORIZONTAL); - const auto &vp = _view->getViewport(); + // Convert to radians + fovY = (fovY / 180) * M_PI; + fovX = (fovX / 180) * M_PI; - // Calculate viewport to world scale at the object's distance - float viewportToWorldScale = planeDistance * std::tan(camera.getFieldOfViewInDegrees(Camera::Fov::VERTICAL) * 0.5f * M_PI / 180.0f) * 2.0f / vp.height; + // Log("Fov vertical %f horizontal %f", fovY, fovX); + float aspectRatio = static_cast(vp.width) / vp.height; - Log("viewportToWorldScale %f", viewportToWorldScale); + auto &transformManager = _engine->getTransformManager(); + auto transformInstance = transformManager.getInstance(Entity::import(entity)); + const auto &transform = transformManager.getWorldTransform(transformInstance); - // Calculate view space delta - math::float4 viewSpaceDelta( - x * viewportToWorldScale, - -y * viewportToWorldScale, // Invert y-axis - z * viewportToWorldScale, - 0.0f); // Use 0 for the w component as it's a direction, not a position + math::float3 translation; + math::quatf rotation; + math::float3 scale; - Log("viewSpaceDelta %f %f %f", viewSpaceDelta.x, viewSpaceDelta.y, viewSpaceDelta.z); + decomposeMatrix(transform, &translation, &rotation, &scale); - // Transform delta to world space - math::float4 worldDelta = invViewMatrix * viewSpaceDelta; + const auto entityWorldPosition = transform * math::float4{0.0f, 0.0f, 0.0f, 1.0f}; - Log("worldDelta %f %f %f", worldDelta.x, worldDelta.y, worldDelta.z); + // Log("entityWorldPosition %f %f %f", entityWorldPosition.x, entityWorldPosition.y, entityWorldPosition.z); - if (relative) - { - trans.x += worldDelta.x; - trans.y += worldDelta.y; - trans.z += worldDelta.z; - } - else - { - trans.x = worldDelta.x; - trans.y = worldDelta.y; - trans.z = worldDelta.z; + float distanceToCamera = length(entityWorldPosition.xyz - camera.getPosition()); + + // Calculate the height of the view frustum at the given distance + float frustumHeight = 2.0f * distanceToCamera * tan(fovY * 0.5f); + + // Calculate the width of the view frustum at the given distance + float frustumWidth = frustumHeight * aspectRatio; + + // Log("frustum %fx%f", frustumWidth, frustumHeight); + + // Convert projected viewport movement to world space distance + float worldDistance = length(math::float2 { (translationNDC /2) * math::float2 { frustumWidth, frustumHeight } }); + + if(projectedMovement < 0) { + worldDistance *= -1; + } + + // Log("%f units in world ", worldDistance); + + auto newWorldTranslation = worldAxis * worldDistance; + + queuePositionUpdate(entity, newWorldTranslation.x, newWorldTranslation.y, newWorldTranslation.z, true); + + // // Convert to local space + // math::mat4f newWorldTransform = transformManager.getWorldTransform(transformInstance) * math::mat4f::translation(worldAxis * worldDistance); + // const auto parent = transformManager.getParent(transformInstance); + // const auto parentTransformInstance = transformManager.getInstance(parent); + // const auto inverseParentWorldTransformInverse = inverse(transformManager.getWorldTransform(parentTransformInstance)); + // math::mat4f newLocalTransform = inverseParentWorldTransformInverse * newWorldTransform; + + // Log("newLocalTransform %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f", + // newLocalTransform[0][0], newLocalTransform[0][1], newLocalTransform[0][2], newLocalTransform[0][3], + // newLocalTransform[1][0], newLocalTransform[1][1], newLocalTransform[1][2], newLocalTransform[1][3], + // newLocalTransform[2][0], newLocalTransform[2][1], newLocalTransform[2][2], newLocalTransform[2][3], + // newLocalTransform[3][0], newLocalTransform[3][1], newLocalTransform[3][2], newLocalTransform[3][3]); + + + + // transformManager.setTransform(transformInstance, newLocalTransform); } - auto &isRelative = std::get<1>(curr); - isRelative = relative; - _transformUpdates[entity] = curr; -} + void SceneManager::queuePositionUpdate(EntityId entity, float x, float y, float z, bool relative) + { + std::lock_guard lock(_mutex); + + const auto &pos = _transformUpdates.find(entity); + if (pos == _transformUpdates.end()) + { + _transformUpdates.emplace(entity, std::make_tuple(math::float3(), true, math::quatf(1.0f), true, 1.0f)); + } + auto curr = _transformUpdates[entity]; + auto &trans = std::get<0>(curr); + trans.x = x; + trans.y = y; + trans.z = z; + + auto &isRelative = std::get<1>(curr); + isRelative = relative; + _transformUpdates[entity] = curr; + } + + // void SceneManager::queuePositionUpdate(EntityId entity, float x, float y, float z, bool relative) + // { + // std::lock_guard lock(_mutex); + + // const auto &pos = _transformUpdates.find(entity); + // if (pos == _transformUpdates.end()) + // { + // _transformUpdates.emplace(entity, std::make_tuple(math::float3(), true, math::quatf(1.0f), true, 1.0f)); + // } + // auto curr = _transformUpdates[entity]; + // auto &trans = std::get<0>(curr); + + // const auto &tm = _engine->getTransformManager(); + // auto transformInstance = tm.getInstance(Entity::import(entity)); + // auto transform = tm.getTransform(transformInstance); + // math::double4 position { 0.0f, 0.0f, 0.0f, 1.0f}; + // math::mat4 worldTransform = tm.getWorldTransformAccurate(transformInstance); + // position = worldTransform * position; + + // // Get camera's view matrix and its inverse + // const Camera &camera = _view->getCamera(); + + // math::mat4 viewMatrix = camera.getViewMatrix(); + // math::mat4 invViewMatrix = inverse(viewMatrix); + + // // Transform object position to view space + // math::double4 viewSpacePos = viewMatrix * position; + + // Log("viewSpacePos %f %f %f %f", viewSpacePos.x, viewSpacePos.y, viewSpacePos.z, viewSpacePos.w); + + // // Calculate plane distance from camera + // float planeDistance = -viewSpacePos.z; + + // const auto &vp = _view->getViewport(); + + // // Calculate viewport to world scale at the object's distance + // float viewportToWorldScale = planeDistance * std::tan(camera.getFieldOfViewInDegrees(Camera::Fov::VERTICAL) * 0.5f * M_PI / 180.0f) * 2.0f / vp.height; + + // // Log("viewportToWorldScale %f", viewportToWorldScale); + + // // Calculate view space delta + // math::float4 viewSpaceDelta( + // x * viewportToWorldScale, + // -y * viewportToWorldScale, // Invert y-axis + // z * viewportToWorldScale, + // 0.0f); // Use 0 for the w component as it's a direction, not a position + + // // Log("viewSpaceDelta %f %f %f", viewSpaceDelta.x, viewSpaceDelta.y, viewSpaceDelta.z); + + // // Transform delta to world space + // math::float4 worldDelta = invViewMatrix * viewSpaceDelta; + + // // Log("worldDelta %f %f %f", worldDelta.x, worldDelta.y, worldDelta.z); + + // if (relative) + // { + // trans.x += worldDelta.x; + // trans.y += worldDelta.y; + // trans.z += worldDelta.z; + // } + // else + // { + // trans.x = worldDelta.x; + // trans.y = worldDelta.y; + // trans.z = worldDelta.z; + // } + + // auto &isRelative = std::get<1>(curr); + // isRelative = relative; + // _transformUpdates[entity] = curr; + // } void SceneManager::queueRotationUpdate(EntityId entity, float rads, float x, float y, float z, float w, bool relative) { @@ -2132,8 +2284,6 @@ namespace thermion_filament auto min = aabb.getMin(); auto max = aabb.getMax(); - Log("min %f %f %f max %f %f %f", min.x, min.y, min.z, max.x, max.y, max.z); - // Transform the 8 corners of the AABB to clip space std::array corners = { worldTransform * math::float4(min.x, min.y, min.z, 1.0f), @@ -2182,12 +2332,10 @@ namespace thermion_filament return Aabb2{minX, minY, maxX, maxY}; } - void SceneManager::getGizmo(EntityId *out) - { - out[0] = Entity::smuggle(_gizmo->x()); - out[1] = Entity::smuggle(_gizmo->y()); - out[2] = Entity::smuggle(_gizmo->z()); - out[3] = Entity::smuggle(_gizmo->center()); + void SceneManager::setLayerEnabled(int layer, bool enabled) { + Log("Setting layer %d to %d", layer, enabled); + _view->setLayerEnabled(layer, enabled); } + } // namespace thermion_filament