use std::cell::Cell;
use glamx::{Mat3, Mat4, Pose3, Vec3, Vec4};
use crate::camera::Camera3d;
use crate::context::Context;
use crate::event::WindowEvent;
use crate::window::Canvas;
fn householder(n: Vec3, d: f32) -> Mat4 {
let (a, b, c) = (n.x, n.y, n.z);
Mat4::from_cols(
Vec4::new(1.0 - 2.0 * a * a, -2.0 * a * b, -2.0 * a * c, 0.0),
Vec4::new(-2.0 * a * b, 1.0 - 2.0 * b * b, -2.0 * b * c, 0.0),
Vec4::new(-2.0 * a * c, -2.0 * b * c, 1.0 - 2.0 * c * c, 0.0),
Vec4::new(-2.0 * a * d, -2.0 * b * d, -2.0 * c * d, 1.0),
)
}
pub struct MirrorCamera {
view: Pose3,
proj: Mat4,
eye: Vec3,
znear: f32,
zfar: f32,
}
impl MirrorCamera {
pub fn new(
view: Pose3,
proj: Mat4,
eye: Vec3,
znear: f32,
zfar: f32,
plane_point: Vec3,
plane_normal: Vec3,
) -> Self {
let view_mat = view.to_mat4();
let m3 = Mat3::from_cols(
view_mat.x_axis.truncate(),
view_mat.y_axis.truncate(),
view_mat.z_axis.truncate(),
);
let n = (m3 * plane_normal).normalize();
let p_view = (view_mat * plane_point.extend(1.0)).truncate();
let d = -n.dot(p_view);
let reflect = householder(n, d);
let nn = plane_normal.normalize();
let eye_refl = eye - 2.0 * (nn.dot(eye - plane_point)) * nn;
MirrorCamera {
view,
proj: proj * reflect,
eye: eye_refl,
znear,
zfar,
}
}
pub fn reflector_view_proj(&self) -> Mat4 {
self.proj * self.view.to_mat4()
}
}
impl Camera3d for MirrorCamera {
fn handle_event(&mut self, _: &Canvas, _: &WindowEvent) {}
fn update(&mut self, _: &Canvas) {}
fn eye(&self) -> Vec3 {
self.eye
}
fn view_transform(&self) -> Pose3 {
self.view
}
fn transformation(&self) -> Mat4 {
self.proj * self.view.to_mat4()
}
fn inverse_transformation(&self) -> Mat4 {
self.transformation().inverse()
}
fn clip_planes(&self) -> (f32, f32) {
(self.znear, self.zfar)
}
fn view_transform_pair(&self, _pass: usize) -> (Pose3, Mat4) {
(self.view, self.proj)
}
}
pub struct Reflector {
width: u32,
height: u32,
_color: wgpu::Texture,
color_view: wgpu::TextureView,
_depth: wgpu::Texture,
depth_view: wgpu::TextureView,
local_normal: Vec3,
intensity: f32,
normal_falloff: f32,
view_proj: Cell<Mat4>,
generation: u64,
}
impl Default for Reflector {
fn default() -> Self {
Self::new()
}
}
impl Reflector {
pub fn new() -> Reflector {
let (color, color_view, depth, depth_view) = Self::make_targets(1, 1);
Reflector {
width: 1,
height: 1,
_color: color,
color_view,
_depth: depth,
depth_view,
local_normal: Vec3::Z,
intensity: 1.0,
normal_falloff: 0.0,
view_proj: Cell::new(Mat4::IDENTITY),
generation: 1,
}
}
pub fn with_local_normal(mut self, normal: Vec3) -> Reflector {
self.local_normal = normal.normalize();
self
}
pub fn with_intensity(mut self, intensity: f32) -> Reflector {
self.intensity = intensity.clamp(0.0, 1.0);
self
}
pub fn with_normal_falloff(mut self, falloff: f32) -> Reflector {
self.normal_falloff = falloff.max(0.0);
self
}
fn make_targets(
w: u32,
h: u32,
) -> (
wgpu::Texture,
wgpu::TextureView,
wgpu::Texture,
wgpu::TextureView,
) {
let ctxt = Context::get();
let color = ctxt.create_texture(&wgpu::TextureDescriptor {
label: Some("reflector_color"),
size: wgpu::Extent3d {
width: w,
height: h,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: crate::post_processing::HDR_FORMAT,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
view_formats: &[],
});
let color_view = color.create_view(&wgpu::TextureViewDescriptor::default());
let depth = ctxt.create_texture(&wgpu::TextureDescriptor {
label: Some("reflector_depth"),
size: wgpu::Extent3d {
width: w,
height: h,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: Context::depth_format(),
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
});
let depth_view = depth.create_view(&wgpu::TextureViewDescriptor::default());
(color, color_view, depth, depth_view)
}
pub fn resize(&mut self, width: u32, height: u32) {
let (w, h) = (width.max(1), height.max(1));
if self.width == w && self.height == h {
return;
}
let (color, color_view, depth, depth_view) = Self::make_targets(w, h);
self._color = color;
self.color_view = color_view;
self._depth = depth;
self.depth_view = depth_view;
self.width = w;
self.height = h;
self.generation += 1;
}
pub fn generation(&self) -> u64 {
self.generation
}
pub fn color_view(&self) -> &wgpu::TextureView {
&self.color_view
}
pub fn depth_view(&self) -> &wgpu::TextureView {
&self.depth_view
}
pub fn local_normal(&self) -> Vec3 {
self.local_normal
}
pub fn set_local_normal(&mut self, normal: Vec3) {
self.local_normal = normal.normalize();
}
pub fn intensity(&self) -> f32 {
self.intensity
}
pub fn set_intensity(&mut self, intensity: f32) {
self.intensity = intensity.clamp(0.0, 1.0);
}
pub fn normal_falloff(&self) -> f32 {
self.normal_falloff
}
pub fn set_normal_falloff(&mut self, falloff: f32) {
self.normal_falloff = falloff.max(0.0);
}
pub fn view_proj(&self) -> Mat4 {
self.view_proj.get()
}
pub fn set_view_proj(&self, vp: Mat4) {
self.view_proj.set(vp);
}
}