@ -18,96 +18,111 @@
*/
# include "camera-system.hpp"
# include "game/components/collision-component.hpp"
# include "game/components/tool-component.hpp"
# include "game/components/camera-subject-component.hpp"
# include "game/components/transform-component.hpp"
# include "scene/camera.hpp"
# include "orbit-cam.hpp"
# include "geometry/mesh.hpp"
# include "geometry/intersection.hpp"
# include "math/math.hpp"
# include <cmath>
# include <iostream>
using namespace ecs ;
camera_system : : camera_system ( entt : : registry & registry ) :
entity_system ( registry ) ,
orbit_ cam( nullptr ) ,
camera ( nullptr ) ,
viewport { 0 , 0 , 0 , 0 } ,
mouse_position { 0 , 0 }
{ }
void camera_system : : update ( double t , double dt )
{
if ( ! orbit_cam )
return ;
const camera * camera = orbit_cam - > get_camera ( ) ;
if ( ! camera )
return ;
/*
registry . view < transform_component , tool_component > ( ) . each (
[ & ] ( auto entity , auto & transform , auto & tool )
// Determine focal point
int subject_count = 0 ;
float3 focal_point = { 0 , 0 , 0 } ;
registry . view < camera_subject_component , transform_component > ( ) . each (
[ & ] ( auto entity , auto & subject , auto & transform )
{
if ( ! tool . active )
return ;
focal_point + = transform . transform . translation ;
+ + subject_count ;
} ) ;
if ( subject_count > 1 )
focal_point / = static_cast < float > ( subject_count ) ;
// Determine focal distance
float focal_distance = math : : log_lerp < float > ( focal_distance_far , focal_distance_near , zoom_factor ) ;
// Determine view point
quaternion_type rotation = math : : normalize ( azimuth_rotation * elevation_rotation ) ;
float3 view_point = focal_point + rotation * float3 { 0.0f , 0.0f , focal_distance } ;
// Update camera transform
transform_type source_transform = camera - > get_transform ( ) ;
transform_type target_transform = math : : identity_transform < float > ;
target_transform . translation = view_point ;
target_transform . rotation = rotation ;
float2 xz_direction = math : : normalize ( math : : swizzle < 0 , 2 > ( focal_point ) - math : : swizzle < 0 , 2 > ( source_transform . translation ) ) ;
float source_azimuth = math : : wrap_radians ( std : : atan2 ( - xz_direction . y , xz_direction . x ) - math : : half_pi < float > ) ;
float source_elevation = elevation ;
std : : cout < < " azimuth: " < < math : : degrees ( azimuth ) < < " \n " ;
std : : cout < < " source azimuth: " < < math : : degrees ( source_azimuth ) < < " \n " ;
float smooth_factor = 0.1f ;
float smooth_azimuth = math : : lerp_angle ( source_azimuth , azimuth , smooth_factor ) ;
float smooth_elevation = math : : lerp_angle ( source_elevation , elevation , smooth_factor ) ;
quaternion_type smooth_azimuth_rotation = math : : angle_axis ( smooth_azimuth , float3 { 0.0f , 1.0f , 0.0f } ) ;
quaternion_type smooth_elevation_rotation = math : : angle_axis ( smooth_elevation , float3 { - 1.0f , 0.0f , 0.0f } ) ;
quaternion_type smooth_rotation = math : : normalize ( smooth_azimuth_rotation * smooth_elevation_rotation ) ;
float3 smooth_view_point = focal_point + smooth_rotation * float3 { 0.0f , 0.0f , focal_distance } ;
float3 screen_position = camera - > project ( transform . transform . translation , viewport ) ;
std : : cout < < screen_position < < std : : endl ;
transform_type smooth_transform ;
smooth_transform . translation = smooth_view_point ;
//smooth_transform.translation = math::lerp(source_transform.translation, target_transform.translation, smooth_factor);
//smooth_transform.rotation = math::slerp(source_transform.rotation, target_transform.rotation, smooth_factor);
smooth_transform . rotation = smooth_rotation ;
smooth_transform . scale = math : : lerp ( source_transform . scale , target_transform . scale , smooth_factor ) ;
camera - > set_transform ( smooth_transform ) ;
// Project tool position onto viewport
} ) ;
*/
// Cast a ray straight down from infinity at the focal point's lateral coordinates.
// std::numeric_limits<float>::infinity() actually doesn't work here
float3 focal_point = orbit_cam - > get_target_focal_point ( ) ;
float3 pick_origin = float3 { focal_point . x , focal_point . y + 500.0f , focal_point . z } ;
float3 pick_direction = float3 { 0 , - 1 , 0 } ;
ray < float > picking_ray = { pick_origin , pick_direction } ;
float a = std : : numeric_limits < float > : : infinity ( ) ;
bool intersection = false ;
float3 pick ;
registry . view < transform_component , collision_component > ( ) . each (
[ & ] ( auto entity , auto & transform , auto & collision )
{
math : : transform < float > inverse_transform = math : : inverse ( transform . transform ) ;
float3 origin = inverse_transform * pick_origin ;
float3 direction = math : : normalize ( math : : conjugate ( transform . transform . rotation ) * pick_direction ) ;
ray < float > transformed_ray = { origin , direction } ;
// Broad phase AABB test
auto aabb_result = ray_aabb_intersection ( transformed_ray , collision . bounds ) ;
if ( ! std : : get < 0 > ( aabb_result ) )
{
return ;
}
// Narrow phase mesh test
auto mesh_result = ray_mesh_intersection ( transformed_ray , * collision . mesh ) ;
if ( std : : get < 0 > ( mesh_result ) )
{
intersection = true ;
if ( std : : get < 1 > ( mesh_result ) < a )
{
a = std : : get < 1 > ( mesh_result ) ;
pick = picking_ray . extrapolate ( a ) ;
}
}
} ) ;
// Determine FOV
float fov = math : : log_lerp < float > ( fov_far , fov_near , zoom_factor ) ;
// Determine aspect ratio
float aspect_ratio = viewport [ 2 ] / viewport [ 3 ] ;
// Determine clipping planes
float clip_near = math : : log_lerp < float > ( near_clip_far , near_clip_near , zoom_factor ) ;
float clip_far = math : : log_lerp < float > ( far_clip_far , far_clip_near , zoom_factor ) ;
// Update camera projection
camera - > set_perspective ( fov , aspect_ratio , clip_near , clip_far ) ;
}
void camera_system : : rotate ( float angle )
{
set_azimuth ( azimuth + angle ) ;
}
void camera_system : : tilt ( float angle )
{
set_elevation ( elevation + angle ) ;
}
if ( intersection )
{
//orbit_cam->set_target_focal_point(pick);
}
void camera_system : : zoom ( float factor )
{
set_zoom ( std : : max < float > ( 0.0f , std : : min < float > ( 1.0f , zoom_factor + factor ) ) ) ;
}
void camera_system : : set_orbit_cam ( : : orbit_cam * orbit_cam )
void camera_system : : set_camera ( : : camera * camera )
{
this - > orbit_cam = orbit_cam ;
this - > camera = camera ;
}
void camera_system : : set_viewport ( const float4 & viewport )
@ -115,9 +130,54 @@ void camera_system::set_viewport(const float4& viewport)
this - > viewport = viewport ;
}
void camera_system : : set_azimuth ( float angle )
{
azimuth = math : : wrap_radians ( angle ) ;
azimuth_rotation = math : : angle_axis ( azimuth , float3 { 0.0f , 1.0f , 0.0f } ) ;
}
void camera_system : : set_elevation ( float angle )
{
elevation = math : : wrap_radians ( angle ) ;
elevation_rotation = math : : angle_axis ( elevation , float3 { - 1.0f , 0.0f , 0.0f } ) ;
}
void camera_system : : set_zoom ( float factor )
{
this - > zoom_factor = factor ;
}
void camera_system : : set_focal_distance ( float distance_near , float distance_far )
{
focal_distance_near = distance_near ;
focal_distance_far = distance_far ;
}
void camera_system : : set_fov ( float angle_near , float angle_far )
{
fov_near = angle_near ;
fov_far = angle_far ;
}
void camera_system : : set_clip_near ( float distance_near , float distance_far )
{
near_clip_near = distance_near ;
near_clip_far = distance_far ;
}
void camera_system : : set_clip_far ( float distance_near , float distance_far )
{
far_clip_near = distance_near ;
far_clip_far = distance_far ;
}
void camera_system : : handle_event ( const mouse_moved_event & event )
{
mouse_position [ 0 ] = event . x ;
mouse_position [ 1 ] = event . y ;
}
void camera_system : : handle_event ( const window_resized_event & event )
{
set_viewport ( { 0.0f , 0.0f , static_cast < float > ( event . w ) , static_cast < float > ( event . h ) } ) ;
}