///|
pub(all) struct RollingShutter {
readout_seconds : Double
image_height : Int
} derive(Debug, Eq)
///|
pub fn RollingShutter::new(
readout_seconds~ : Double,
image_height~ : Int,
) -> RollingShutter raise @core.GeometryError {
if readout_seconds < 0.0 || image_height <= 0 {
raise @core.GeometryError::DegenerateInput(
"rolling shutter parameters are invalid",
)
}
{ readout_seconds, image_height }
}
///|
pub fn RollingShutter::row_time(model : RollingShutter, y : Double) -> Double {
let normalized = @core.clamp(
y,
lo=0.0,
hi=Double::from_int(model.image_height - 1),
) /
Double::from_int(model.image_height)
model.readout_seconds * normalized
}
///|
pub fn RollingShutter::midpoint_time(model : RollingShutter) -> Double {
model.readout_seconds / 2.0
}
///|
pub fn rolling_pose(
pose : CameraPose,
velocity : @core.Vec3,
time : Double,
) -> CameraPose {
let translation = pose.translation().add(velocity.scale(time))
CameraPose::from_rotation_translation(pose.rotation(), translation)
}
///|
pub fn rolling_project(
point : @core.Point3,
intrinsics : CameraIntrinsics,
pose : CameraPose,
model : RollingShutter,
velocity : @core.Vec3,
) -> @core.Point2 raise @core.GeometryError {
let first = project_point_with_pose(point, intrinsics, pose)
let updated = rolling_pose(pose, velocity, model.row_time(first.y))
project_point_with_pose(point, intrinsics, updated)
}
///|
pub fn motion_blur_displacement(
velocity : @core.Vec3,
depth~ : Double,
intrinsics : CameraIntrinsics,
exposure~ : Double,
) -> @core.Vec2 raise @core.GeometryError {
if depth <= 0.0 || exposure < 0.0 {
raise @core.GeometryError::DegenerateInput(
"motion blur parameters are invalid",
)
}
@core.Vec2::new(
x=intrinsics.fx * velocity.x / depth * exposure,
y=intrinsics.fy * velocity.y / depth * exposure,
)
}