@ -33,70 +33,81 @@ camera_system::camera_system(entt::registry& registry):
camera ( nullptr ) ,
viewport { 0 , 0 , 0 , 0 } ,
mouse_position { 0 , 0 }
{ }
{
// Init azimuth spring constraint
azimuth_spring . v = 0.0f ;
azimuth_spring . z = 1.0f ;
azimuth_spring . w = 2.0f * math : : two_pi < float > ;
// Init elevation spring constraint
elevation_spring . v = 0.0f ;
elevation_spring . z = 1.0f ;
elevation_spring . w = 2.0f * math : : two_pi < float > ;
// Init focal distance spring constraint
focal_distance_spring . v = 0.0f ;
focal_distance_spring . z = 1.0f ;
focal_distance_spring . w = 5.0f * math : : two_pi < float > ;
// Init fov spring constraint
fov_spring . v = 0.0f ;
fov_spring . z = 1.0f ;
fov_spring . w = 5.0f * math : : two_pi < float > ;
}
void camera_system : : update ( double t , double dt )
{
if ( ! camera )
return ;
// Determine focal point
// Determine target focal point
int subject_count = 0 ;
float3 focal_point = { 0 , 0 , 0 } ;
float3 target_ focal_point = { 0 , 0 , 0 } ;
registry . view < camera_subject_component , transform_component > ( ) . each (
[ & ] ( auto entity , auto & subject , auto & transform )
{
focal_point + = transform . transform . translation ;
target_ focal_point + = transform . transform . translation ;
+ + subject_count ;
} ) ;
if ( subject_count > 1 )
focal_point / = static_cast < float > ( subject_count ) ;
target_ 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
// Get source 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 ;
// Solve azimuth spring
float2 xz_direction = math : : normalize ( math : : swizzle < 0 , 2 > ( target_focal_point ) - math : : swizzle < 0 , 2 > ( source_transform . translation ) ) ;
azimuth_spring . x0 = math : : wrap_radians ( std : : atan2 ( - xz_direction . y , xz_direction . x ) - math : : half_pi < float > ) ;
azimuth_spring . x1 = azimuth_spring . x0 + math : : wrap_radians ( azimuth_spring . x1 - azimuth_spring . x0 ) ;
solve_spring_constraint < float , float > ( azimuth_spring , dt ) ;
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 ;
// Sovle elevation spring
elevation_spring . x0 = elevation ;
elevation_spring . x1 = elevation_spring . x0 + math : : wrap_radians ( elevation_spring . x1 - elevation_spring . x0 ) ;
solve_spring_constraint < float , float > ( elevation_spring , dt ) ;
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 ) ;
// Solve focal distance spring
focal_distance_spring . x0 = math : : length ( source_transform . translation - target_focal_point ) ;
solve_spring_constraint < float , float > ( focal_distance_spring , dt ) ;
// Solve FOV spring
fov_spring . x0 = camera - > get_fov ( ) ;
solve_spring_constraint < float , float > ( fov_spring , dt ) ;
smooth_azimuth = source_azimuth ;
float shortest_angle = math : : wrap_radians ( azimuth - source_azimuth ) ;
static float velocity = 0.0f ;
spring < float , float > ( smooth_azimuth , velocity , smooth_azimuth + shortest_angle , 1.0f , 2.0f * math : : two_pi < float > , dt ) ;
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 } ) ;
// Determine camera rotation
quaternion_type smooth_azimuth_rotation = math : : angle_axis ( azimuth_spring . x0 , float3 { 0.0f , 1.0f , 0.0f } ) ;
quaternion_type smooth_elevation_rotation = math : : angle_axis ( elevation_spring . x0 , 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 } ;
// Determine camera view point
float3 smooth_view_point = target_focal_point + smooth_rotation * float3 { 0.0f , 0.0f , focal_distance_spring . x0 } ;
// Update camera transform
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 ) ;
smooth_transform . scale = source_transform . scale ;
camera - > set_transform ( smooth_transform ) ;
// Determine FOV
float fov = math : : log_lerp < float > ( fov_far , fov_near , zoom_factor ) ;
// Determine aspect ratio
float aspect_ratio = viewport [ 2 ] / viewport [ 3 ] ;
@ -106,7 +117,7 @@ void camera_system::update(double t, double dt)
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 ) ;
camera - > set_perspective ( fov_spring . x0 , aspect_ratio , clip_near , clip_far ) ;
}
void camera_system : : rotate ( float angle )
@ -117,12 +128,11 @@ void camera_system::rotate(float angle)
void camera_system : : tilt ( float angle )
{
set_elevation ( elevation + angle ) ;
}
void camera_system : : zoom ( float factor )
{
set_zoom ( std : : max < float > ( 0.0f , std : : min < float > ( 1.0f , zoom_factor + factor ) ) ) ;
set_zoom ( zoom_factor + factor ) ;
}
void camera_system : : set_camera ( : : camera * camera )
@ -139,29 +149,35 @@ 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 } ) ;
azimuth_spring . x1 = azimuth ;
}
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 } ) ;
elevation_spring . x1 = elevation ;
}
void camera_system : : set_zoom ( float factor )
{
this - > zoom_factor = factor ;
this - > zoom_factor = std : : max < float > ( 0.0f , std : : min < float > ( 1.0f , factor ) ) ;
update_focal_distance ( ) ;
update_fov ( ) ;
}
void camera_system : : set_focal_distance ( float distance_near , float distance_far )
{
focal_distance_near = distance_near ;
focal_distance_far = distance_far ;
update_focal_distance ( ) ;
}
void camera_system : : set_fov ( float angle_near , float angle_far )
{
fov_near = angle_near ;
fov_far = angle_far ;
update_fov ( ) ;
}
void camera_system : : set_clip_near ( float distance_near , float distance_far )
@ -186,3 +202,15 @@ 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 ) } ) ;
}
void camera_system : : update_focal_distance ( )
{
focal_distance = math : : log_lerp < float > ( focal_distance_far , focal_distance_near , zoom_factor ) ;
focal_distance_spring . x1 = focal_distance ;
}
void camera_system : : update_fov ( )
{
fov = math : : log_lerp < float > ( fov_far , fov_near , zoom_factor ) ;
fov_spring . x1 = fov ;
}