ADD: planet camera fix
This commit is contained in:
BIN
Binary file not shown.
BIN
Binary file not shown.
LFS
BIN
Binary file not shown.
LFS
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+35
-3
@@ -835,8 +835,38 @@ namespace
|
|||||||
|
|
||||||
if (pick.ownerType == RenderObject::OwnerType::MeshInstance)
|
if (pick.ownerType == RenderObject::OwnerType::MeshInstance)
|
||||||
{
|
{
|
||||||
target.type = CameraTargetType::MeshInstance;
|
// Many procedural objects (planets etc.) tag draws as "MeshInstance" for picking,
|
||||||
target.name = pick.ownerName;
|
// but they don't exist in SceneManager::dynamicMeshInstances. Only use a
|
||||||
|
// MeshInstance camera target if it resolves.
|
||||||
|
WorldVec3 t{};
|
||||||
|
glm::quat r{};
|
||||||
|
glm::vec3 s{};
|
||||||
|
if (sceneMgr->getMeshInstanceTRSWorld(pick.ownerName, t, r, s))
|
||||||
|
{
|
||||||
|
target.type = CameraTargetType::MeshInstance;
|
||||||
|
target.name = pick.ownerName;
|
||||||
|
}
|
||||||
|
else if (PlanetSystem *planets = sceneMgr->get_planet_system())
|
||||||
|
{
|
||||||
|
if (PlanetSystem::PlanetBody *body = planets->find_body_by_name(pick.ownerName))
|
||||||
|
{
|
||||||
|
target.type = CameraTargetType::WorldPoint;
|
||||||
|
target.world_point = body->center_world;
|
||||||
|
target.name = body->name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
target.type = CameraTargetType::WorldPoint;
|
||||||
|
target.world_point = pick.worldPos;
|
||||||
|
target.name.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
target.type = CameraTargetType::WorldPoint;
|
||||||
|
target.world_point = pick.worldPos;
|
||||||
|
target.name.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (pick.ownerType == RenderObject::OwnerType::GLTFInstance)
|
else if (pick.ownerType == RenderObject::OwnerType::GLTFInstance)
|
||||||
{
|
{
|
||||||
@@ -920,7 +950,9 @@ namespace
|
|||||||
target_from_last_pick(s.target);
|
target_from_last_pick(s.target);
|
||||||
}
|
}
|
||||||
ImGui::InputDouble("Distance", &s.distance, 0.1, 1.0, "%.3f");
|
ImGui::InputDouble("Distance", &s.distance, 0.1, 1.0, "%.3f");
|
||||||
s.distance = std::clamp(s.distance, 0.2, 100000.0);
|
s.distance = std::clamp(s.distance,
|
||||||
|
OrbitCameraSettings::kMinDistance,
|
||||||
|
OrbitCameraSettings::kMaxDistance);
|
||||||
float yawDeg = glm::degrees(s.yaw);
|
float yawDeg = glm::degrees(s.yaw);
|
||||||
float pitchDeg = glm::degrees(s.pitch);
|
float pitchDeg = glm::degrees(s.pitch);
|
||||||
if (ImGui::SliderFloat("Yaw (deg)", &yawDeg, -180.0f, 180.0f))
|
if (ImGui::SliderFloat("Yaw (deg)", &yawDeg, -180.0f, 180.0f))
|
||||||
|
|||||||
+30
-2
@@ -14,6 +14,7 @@
|
|||||||
#include "scene/vk_scene.h"
|
#include "scene/vk_scene.h"
|
||||||
#include "scene/camera.h"
|
#include "scene/camera.h"
|
||||||
#include "scene/camera/camera_rig.h"
|
#include "scene/camera/camera_rig.h"
|
||||||
|
#include "scene/planet/planet_system.h"
|
||||||
|
|
||||||
#include <glm/gtx/matrix_decompose.hpp>
|
#include <glm/gtx/matrix_decompose.hpp>
|
||||||
#include <glm/gtx/quaternion.hpp>
|
#include <glm/gtx/quaternion.hpp>
|
||||||
@@ -1821,8 +1822,35 @@ bool Engine::set_camera_target_from_last_pick()
|
|||||||
::CameraTarget t;
|
::CameraTarget t;
|
||||||
if (pick.ownerType == RenderObject::OwnerType::MeshInstance)
|
if (pick.ownerType == RenderObject::OwnerType::MeshInstance)
|
||||||
{
|
{
|
||||||
t.type = ::CameraTargetType::MeshInstance;
|
// RenderObject::OwnerType::MeshInstance is also used for some procedural objects
|
||||||
t.name = pick.ownerName;
|
// (planets etc.) which don't exist in SceneManager::dynamicMeshInstances.
|
||||||
|
WorldVec3 inst_t{};
|
||||||
|
glm::quat inst_r{};
|
||||||
|
glm::vec3 inst_s{};
|
||||||
|
if (_engine->_sceneManager->getMeshInstanceTRSWorld(pick.ownerName, inst_t, inst_r, inst_s))
|
||||||
|
{
|
||||||
|
t.type = ::CameraTargetType::MeshInstance;
|
||||||
|
t.name = pick.ownerName;
|
||||||
|
}
|
||||||
|
else if (PlanetSystem *planets = _engine->_sceneManager->get_planet_system())
|
||||||
|
{
|
||||||
|
if (PlanetSystem::PlanetBody *body = planets->find_body_by_name(pick.ownerName))
|
||||||
|
{
|
||||||
|
t.type = ::CameraTargetType::WorldPoint;
|
||||||
|
t.name = body->name;
|
||||||
|
t.world_point = body->center_world;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
t.type = ::CameraTargetType::WorldPoint;
|
||||||
|
t.world_point = pick.worldPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
t.type = ::CameraTargetType::WorldPoint;
|
||||||
|
t.world_point = pick.worldPos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (pick.ownerType == RenderObject::OwnerType::GLTFInstance)
|
else if (pick.ownerType == RenderObject::OwnerType::GLTFInstance)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "core/device/images.h"
|
#include "core/device/images.h"
|
||||||
#include "core/device/swapchain.h"
|
#include "core/device/swapchain.h"
|
||||||
#include "render/graph/graph.h"
|
#include "render/graph/graph.h"
|
||||||
|
#include "scene/planet/planet_system.h"
|
||||||
|
|
||||||
#include "SDL2/SDL.h"
|
#include "SDL2/SDL.h"
|
||||||
#include "SDL2/SDL_vulkan.h"
|
#include "SDL2/SDL_vulkan.h"
|
||||||
@@ -12,6 +13,91 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool try_orbit_camera_to_planet(EngineContext *context, const PickingSystem::PickInfo &pick)
|
||||||
|
{
|
||||||
|
if (!context || !context->scene)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pick.ownerType != RenderObject::OwnerType::MeshInstance)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneManager &scene = *context->scene;
|
||||||
|
|
||||||
|
// If this is a real dynamic MeshInstance, leave it alone (user might want
|
||||||
|
// to orbit other things separately).
|
||||||
|
{
|
||||||
|
WorldVec3 t{};
|
||||||
|
glm::quat r{};
|
||||||
|
glm::vec3 s{};
|
||||||
|
if (scene.getMeshInstanceTRSWorld(pick.ownerName, t, r, s))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PlanetSystem *planets = scene.get_planet_system();
|
||||||
|
if (!planets || !planets->enabled())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlanetSystem::PlanetBody *body = planets->find_body_by_name(pick.ownerName);
|
||||||
|
if (!body || !body->visible)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CameraRig &rig = scene.getCameraRig();
|
||||||
|
Camera &cam = scene.getMainCamera();
|
||||||
|
|
||||||
|
CameraTarget target{};
|
||||||
|
target.type = CameraTargetType::WorldPoint;
|
||||||
|
target.name = body->name;
|
||||||
|
target.world_point = body->center_world;
|
||||||
|
|
||||||
|
rig.orbit_settings().target = target;
|
||||||
|
rig.follow_settings().target = target;
|
||||||
|
rig.chase_settings().target = target;
|
||||||
|
|
||||||
|
rig.set_mode(CameraMode::Orbit, scene, cam);
|
||||||
|
|
||||||
|
const WorldVec3 to_cam = cam.position_world - body->center_world;
|
||||||
|
double dist = glm::length(to_cam);
|
||||||
|
|
||||||
|
// If we're inside the planet (or very close), pop out to a sane viewing altitude.
|
||||||
|
// Clamp altitude to [10 km, 1000 km] and scale with body radius.
|
||||||
|
const double min_alt_m = std::clamp(body->radius_m * 0.05, 1.0e4, 1.0e6);
|
||||||
|
const double min_dist = body->radius_m + min_alt_m;
|
||||||
|
|
||||||
|
if (!std::isfinite(dist) || dist < min_dist)
|
||||||
|
{
|
||||||
|
dist = min_dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::dvec3 dir = glm::dvec3(to_cam);
|
||||||
|
if (glm::dot(dir, dir) < 1e-12)
|
||||||
|
{
|
||||||
|
dir = glm::dvec3(0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dir = glm::normalize(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
OrbitCameraSettings &orbit = rig.orbit_settings();
|
||||||
|
orbit.distance = std::clamp(dist, OrbitCameraSettings::kMinDistance, OrbitCameraSettings::kMaxDistance);
|
||||||
|
orbit.yaw = static_cast<float>(std::atan2(dir.x, dir.z));
|
||||||
|
orbit.pitch = static_cast<float>(std::asin(std::clamp(-dir.y, -1.0, 1.0)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void PickingSystem::init(EngineContext *context)
|
void PickingSystem::init(EngineContext *context)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
@@ -121,6 +207,7 @@ void PickingSystem::process_event(const SDL_Event &event, bool ui_want_capture_m
|
|||||||
{
|
{
|
||||||
set_pick_from_hit(hit_object, hit_pos, _last_pick);
|
set_pick_from_hit(hit_object, hit_pos, _last_pick);
|
||||||
_last_pick_object_id = hit_object.objectID;
|
_last_pick_object_id = hit_object.objectID;
|
||||||
|
try_orbit_camera_to_planet(_context, _last_pick);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -223,6 +310,7 @@ void PickingSystem::begin_frame()
|
|||||||
glm::vec3 fallback_local = glm::vec3(picked.transform[3]);
|
glm::vec3 fallback_local = glm::vec3(picked.transform[3]);
|
||||||
WorldVec3 fallback_pos = local_to_world(fallback_local, _context->scene->get_world_origin());
|
WorldVec3 fallback_pos = local_to_world(fallback_local, _context->scene->get_world_origin());
|
||||||
set_pick_from_hit(picked, fallback_pos, _last_pick);
|
set_pick_from_hit(picked, fallback_pos, _last_pick);
|
||||||
|
try_orbit_camera_to_planet(_context, _last_pick);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ struct FreeCameraSettings
|
|||||||
|
|
||||||
struct OrbitCameraSettings
|
struct OrbitCameraSettings
|
||||||
{
|
{
|
||||||
|
static constexpr double kMinDistance = 0.2;
|
||||||
|
static constexpr double kMaxDistance = 1.0e12;
|
||||||
|
|
||||||
CameraTarget target{};
|
CameraTarget target{};
|
||||||
double distance{10.0};
|
double distance{10.0};
|
||||||
float yaw{0.0f}; // radians
|
float yaw{0.0f}; // radians
|
||||||
|
|||||||
@@ -76,17 +76,18 @@ void FreeCameraMode::process_input(SceneManager & /*scene*/,
|
|||||||
float dx = e.mouse_delta.x * _settings.look_sensitivity;
|
float dx = e.mouse_delta.x * _settings.look_sensitivity;
|
||||||
float dy = e.mouse_delta.y * _settings.look_sensitivity;
|
float dy = e.mouse_delta.y * _settings.look_sensitivity;
|
||||||
|
|
||||||
// Mouse right (xrel > 0) turns view right with -Z-forward: yaw around +Y.
|
// Mouse right (xrel > 0) turns view right with -Z-forward: yaw around the
|
||||||
glm::quat yaw_rotation = glm::angleAxis(dx, glm::vec3{0.f, 1.f, 0.f});
|
// camera's local +Y (up) axis, so yaw remains intuitive when rolled.
|
||||||
|
glm::vec3 up = glm::rotate(camera.orientation, glm::vec3{0.f, 1.f, 0.f});
|
||||||
|
glm::quat yaw_rotation = glm::angleAxis(dx, glm::normalize(up));
|
||||||
|
camera.orientation = glm::normalize(yaw_rotation * camera.orientation);
|
||||||
|
|
||||||
// Mouse up (yrel < 0) looks up with -Z-forward: negative dy.
|
// Mouse up (yrel < 0) looks up with -Z-forward: negative dy.
|
||||||
float pitch_delta = -dy;
|
float pitch_delta = -dy;
|
||||||
// Pitch around the camera's local X (right) axis in world space.
|
// Pitch around the camera's local +X (right) axis (after yaw is applied).
|
||||||
glm::vec3 right = glm::rotate(camera.orientation, glm::vec3{1.f, 0.f, 0.f});
|
glm::vec3 right = glm::rotate(camera.orientation, glm::vec3{1.f, 0.f, 0.f});
|
||||||
glm::quat pitch_rotation = glm::angleAxis(pitch_delta, glm::vec3(right));
|
glm::quat pitch_rotation = glm::angleAxis(pitch_delta, glm::normalize(right));
|
||||||
|
camera.orientation = glm::normalize(pitch_rotation * camera.orientation);
|
||||||
// Apply yaw, then pitch, to the current orientation.
|
|
||||||
camera.orientation = glm::normalize(pitch_rotation * yaw_rotation * camera.orientation);
|
|
||||||
}
|
}
|
||||||
else if (e.type == InputEvent::Type::MouseWheel)
|
else if (e.type == InputEvent::Type::MouseWheel)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -102,7 +102,9 @@ void OrbitCameraMode::process_input(SceneManager & /*scene*/,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
const double factor = std::pow(1.15, -static_cast<double>(steps));
|
const double factor = std::pow(1.15, -static_cast<double>(steps));
|
||||||
_settings.distance = std::clamp(_settings.distance * factor, 0.2, 100000.0);
|
_settings.distance = std::clamp(_settings.distance * factor,
|
||||||
|
OrbitCameraSettings::kMinDistance,
|
||||||
|
OrbitCameraSettings::kMaxDistance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,7 +139,7 @@ void OrbitCameraMode::update(SceneManager &scene, Camera &camera, float /*dt*/)
|
|||||||
glm::half_pi<float>() - 0.01f);
|
glm::half_pi<float>() - 0.01f);
|
||||||
_settings.yaw = yaw;
|
_settings.yaw = yaw;
|
||||||
_settings.pitch = pitch;
|
_settings.pitch = pitch;
|
||||||
double dist = std::max(0.2, _settings.distance);
|
double dist = std::max(OrbitCameraSettings::kMinDistance, _settings.distance);
|
||||||
|
|
||||||
glm::quat yaw_q = glm::angleAxis(yaw, glm::vec3(0.0f, 1.0f, 0.0f));
|
glm::quat yaw_q = glm::angleAxis(yaw, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||||
glm::vec3 right = glm::rotate(yaw_q, glm::vec3(1.0f, 0.0f, 0.0f));
|
glm::vec3 right = glm::rotate(yaw_q, glm::vec3(1.0f, 0.0f, 0.0f));
|
||||||
|
|||||||
@@ -182,6 +182,19 @@ PlanetSystem::PlanetBody *PlanetSystem::get_body(BodyID id)
|
|||||||
return &_bodies[i];
|
return &_bodies[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PlanetSystem::PlanetBody *PlanetSystem::find_body_by_name(std::string_view name)
|
||||||
|
{
|
||||||
|
ensure_bodies_created();
|
||||||
|
for (PlanetBody &b : _bodies)
|
||||||
|
{
|
||||||
|
if (b.name == name)
|
||||||
|
{
|
||||||
|
return &b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void PlanetSystem::ensure_bodies_created()
|
void PlanetSystem::ensure_bodies_created()
|
||||||
{
|
{
|
||||||
if (!_bodies.empty())
|
if (!_bodies.empty())
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -61,6 +62,7 @@ public:
|
|||||||
|
|
||||||
const PlanetBody *get_body(BodyID id) const;
|
const PlanetBody *get_body(BodyID id) const;
|
||||||
PlanetBody *get_body(BodyID id);
|
PlanetBody *get_body(BodyID id);
|
||||||
|
PlanetBody *find_body_by_name(std::string_view name);
|
||||||
const std::vector<PlanetBody> &bodies() const { return _bodies; }
|
const std::vector<PlanetBody> &bodies() const { return _bodies; }
|
||||||
|
|
||||||
const planet::PlanetQuadtree::Settings &earth_quadtree_settings() const { return _earth_quadtree_settings; }
|
const planet::PlanetQuadtree::Settings &earth_quadtree_settings() const { return _earth_quadtree_settings; }
|
||||||
|
|||||||
Reference in New Issue
Block a user