Compare commits
6 Commits
96e5c78a59
...
2995a830a2
| Author | SHA1 | Date | |
|---|---|---|---|
| 2995a830a2 | |||
| 77cab94a6e | |||
| 4b138deb34 | |||
| a51f46a038 | |||
| fb8ea92ce8 | |||
| 707bb6f66e |
52
src/lib.rs
52
src/lib.rs
|
|
@ -9,12 +9,13 @@ use crate::{
|
||||||
camera::OrbitalCamera,
|
camera::OrbitalCamera,
|
||||||
ray::Ray,
|
ray::Ray,
|
||||||
render::lines::{LookParams, Mesh, Pipeline, Vertex},
|
render::lines::{LookParams, Mesh, Pipeline, Vertex},
|
||||||
trace::{Hit, Lambertian, Reflector, Scene, Source, Sphere},
|
trace::{Hit, Lambertian, Reflective, Reflector, Scene, Source, Sphere},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod camera;
|
mod camera;
|
||||||
mod ray;
|
mod ray;
|
||||||
mod render;
|
mod render;
|
||||||
|
mod shape;
|
||||||
mod trace;
|
mod trace;
|
||||||
|
|
||||||
const OUTPUT_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Bgra8UnormSrgb;
|
const OUTPUT_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Bgra8UnormSrgb;
|
||||||
|
|
@ -27,6 +28,13 @@ pub struct SphericalPosition {
|
||||||
pub distance: f32,
|
pub distance: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum UseNormal {
|
||||||
|
Light,
|
||||||
|
Camera,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct RedrawArgs {
|
pub struct RedrawArgs {
|
||||||
|
|
@ -36,7 +44,8 @@ pub struct RedrawArgs {
|
||||||
pub light_spread: f32,
|
pub light_spread: f32,
|
||||||
pub accum_sigma: f32,
|
pub accum_sigma: f32,
|
||||||
pub accum_scale: f32,
|
pub accum_scale: f32,
|
||||||
pub reflections: u32,
|
pub reflections: u8,
|
||||||
|
pub use_normal: UseNormal,
|
||||||
pub show_axes: bool,
|
pub show_axes: bool,
|
||||||
pub show_shapes: bool,
|
pub show_shapes: bool,
|
||||||
pub show_hit_emission: bool,
|
pub show_hit_emission: bool,
|
||||||
|
|
@ -58,6 +67,7 @@ pub struct Core {
|
||||||
surface: wgpu::Surface<'static>,
|
surface: wgpu::Surface<'static>,
|
||||||
|
|
||||||
pipeline: Pipeline,
|
pipeline: Pipeline,
|
||||||
|
mesh_pipe: render::faces::Pipeline,
|
||||||
tripod: Mesh,
|
tripod: Mesh,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,6 +131,7 @@ impl Core {
|
||||||
} = gpu;
|
} = gpu;
|
||||||
|
|
||||||
let pipeline = Pipeline::new(&device, OUTPUT_FORMAT);
|
let pipeline = Pipeline::new(&device, OUTPUT_FORMAT);
|
||||||
|
let mesh_pipe = render::faces::Pipeline::new(&device, OUTPUT_FORMAT);
|
||||||
let tripod = new_tripod(&device);
|
let tripod = new_tripod(&device);
|
||||||
queue.submit([]); // flush buffer updates
|
queue.submit([]); // flush buffer updates
|
||||||
|
|
||||||
|
|
@ -130,6 +141,7 @@ impl Core {
|
||||||
surface,
|
surface,
|
||||||
pipeline,
|
pipeline,
|
||||||
tripod,
|
tripod,
|
||||||
|
mesh_pipe,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,6 +164,12 @@ impl Core {
|
||||||
m: perspective * camera.transform(),
|
m: perspective * camera.transform(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
self.mesh_pipe.set_look(
|
||||||
|
&self.queue,
|
||||||
|
render::faces::LookParams {
|
||||||
|
m: perspective * camera.transform(),
|
||||||
|
},
|
||||||
|
);
|
||||||
self.queue.submit([]); // flush buffer updates
|
self.queue.submit([]); // flush buffer updates
|
||||||
|
|
||||||
let view = output.create_view(&wgpu::TextureViewDescriptor::default());
|
let view = output.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
|
@ -214,6 +232,26 @@ impl Core {
|
||||||
sphere(vec3(0.1, 0.3, 0.1)),
|
sphere(vec3(0.1, 0.3, 0.1)),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
if args.show_shapes {
|
||||||
|
let mut meshes = Vec::new();
|
||||||
|
for obj in &scene.objects {
|
||||||
|
let mesh = shape::sphere((obj.radius * 15.) as usize + 7);
|
||||||
|
let obj_mesh = render::faces::Mesh::new(
|
||||||
|
&self.device,
|
||||||
|
&mesh
|
||||||
|
.vertices
|
||||||
|
.iter()
|
||||||
|
.map(|v| render::faces::Vertex {
|
||||||
|
pos: obj.position + obj.radius * v,
|
||||||
|
color: 0.5 * (v + 1.),
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
bytemuck::cast_slice(&mesh.indices),
|
||||||
|
);
|
||||||
|
meshes.push(obj_mesh);
|
||||||
|
}
|
||||||
|
self.mesh_pipe.render(&mut pass, &meshes);
|
||||||
|
}
|
||||||
|
|
||||||
let mut prng = rand_pcg::Pcg64::new(42, 0);
|
let mut prng = rand_pcg::Pcg64::new(42, 0);
|
||||||
let source_rays: Vec<Ray> = (0..10240).map(|_| source.make_ray(&mut prng)).collect();
|
let source_rays: Vec<Ray> = (0..10240).map(|_| source.make_ray(&mut prng)).collect();
|
||||||
|
|
@ -305,13 +343,15 @@ impl Core {
|
||||||
if d2 > 9. * sigma2 {
|
if d2 > 9. * sigma2 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
assert!(hit.normal.is_normalized());
|
let normal = match args.use_normal {
|
||||||
|
UseNormal::Light => light_hit.normal,
|
||||||
|
UseNormal::Camera => hit.normal,
|
||||||
|
};
|
||||||
|
assert!(normal.is_normalized());
|
||||||
assert!(hit.incident.dir.is_normalized());
|
assert!(hit.incident.dir.is_normalized());
|
||||||
let reflector = Lambertian;
|
let reflector = Lambertian;
|
||||||
let in_lm = 1.0;
|
let in_lm = 1.0;
|
||||||
let out_cd = in_lm
|
let out_cd = in_lm * reflector.brdf(normal, light_hit.incident.dir, -ray.dir);
|
||||||
* hit.normal.dot(-hit.incident.dir)
|
|
||||||
* reflector.brdf(hit.normal, hit.incident.dir, -ray.dir);
|
|
||||||
let weight = accum_normalizator * (-0.5 * d2 / sigma2).exp();
|
let weight = accum_normalizator * (-0.5 * d2 / sigma2).exp();
|
||||||
total_cd += weight * out_cd;
|
total_cd += weight * out_cd;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{f32::consts::PI, sync::Arc};
|
use std::{f32::consts::PI, sync::Arc};
|
||||||
|
|
||||||
use glam::uvec2;
|
use glam::uvec2;
|
||||||
use photon_light::{Core, RedrawArgs, SphericalPosition, init_gpu_inner};
|
use photon_light::{Core, RedrawArgs, SphericalPosition, UseNormal, init_gpu_inner};
|
||||||
use winit::{
|
use winit::{
|
||||||
application::ApplicationHandler,
|
application::ApplicationHandler,
|
||||||
event::WindowEvent,
|
event::WindowEvent,
|
||||||
|
|
@ -53,6 +53,7 @@ impl MainWindow {
|
||||||
accum_sigma: 0.025,
|
accum_sigma: 0.025,
|
||||||
accum_scale: 0.01,
|
accum_scale: 0.01,
|
||||||
reflections: 2,
|
reflections: 2,
|
||||||
|
use_normal: UseNormal::Light,
|
||||||
show_axes: true,
|
show_axes: true,
|
||||||
show_shapes: true,
|
show_shapes: true,
|
||||||
show_hit_emission: false,
|
show_hit_emission: false,
|
||||||
|
|
|
||||||
161
src/render/faces.rs
Normal file
161
src/render/faces.rs
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
use std::mem::offset_of;
|
||||||
|
|
||||||
|
use bytemuck::{Pod, Zeroable, bytes_of, cast_slice};
|
||||||
|
use glam::{Mat4, Vec3};
|
||||||
|
use wgpu::util::DeviceExt as _;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct LookParams {
|
||||||
|
pub m: Mat4,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Vertex {
|
||||||
|
pub pos: Vec3,
|
||||||
|
pub color: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vertex {
|
||||||
|
pub fn new(pos: Vec3, color: Vec3) -> Self {
|
||||||
|
Self { pos, color }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Mesh {
|
||||||
|
vertex_buffer: wgpu::Buffer,
|
||||||
|
index_buffer: wgpu::Buffer,
|
||||||
|
index_count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mesh {
|
||||||
|
pub fn new(device: &wgpu::Device, vertices: &[Vertex], indices: &[u16]) -> Self {
|
||||||
|
if vertices.len() >= 1 << 16 {
|
||||||
|
panic!("too many vertices");
|
||||||
|
}
|
||||||
|
for index in indices {
|
||||||
|
if *index as usize >= vertices.len() {
|
||||||
|
panic!(
|
||||||
|
"vertex index out of bounds: {index} out of {}",
|
||||||
|
vertices.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: None,
|
||||||
|
usage: wgpu::BufferUsages::VERTEX,
|
||||||
|
contents: cast_slice(vertices),
|
||||||
|
});
|
||||||
|
let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: None,
|
||||||
|
usage: wgpu::BufferUsages::INDEX,
|
||||||
|
contents: cast_slice(indices),
|
||||||
|
});
|
||||||
|
Self {
|
||||||
|
vertex_buffer,
|
||||||
|
index_buffer,
|
||||||
|
index_count: indices.len().try_into().expect("too many indices"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Pipeline {
|
||||||
|
look_buf: wgpu::Buffer,
|
||||||
|
bindings: wgpu::BindGroup,
|
||||||
|
pipeline: wgpu::RenderPipeline,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pipeline {
|
||||||
|
pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self {
|
||||||
|
let look_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
|
label: None,
|
||||||
|
size: size_of::<LookParams>() as u64,
|
||||||
|
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||||
|
mapped_at_creation: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
|
label: None,
|
||||||
|
source: wgpu::ShaderSource::Wgsl(super::SIMPLE_SHADER.into()),
|
||||||
|
});
|
||||||
|
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: None,
|
||||||
|
layout: None,
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: None,
|
||||||
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||||
|
buffers: &[wgpu::VertexBufferLayout {
|
||||||
|
array_stride: size_of::<Vertex>() as u64,
|
||||||
|
step_mode: wgpu::VertexStepMode::Vertex,
|
||||||
|
attributes: &[
|
||||||
|
wgpu::VertexAttribute {
|
||||||
|
shader_location: 0,
|
||||||
|
offset: offset_of!(Vertex, pos) as u64,
|
||||||
|
format: wgpu::VertexFormat::Float32x3,
|
||||||
|
},
|
||||||
|
wgpu::VertexAttribute {
|
||||||
|
shader_location: 1,
|
||||||
|
offset: offset_of!(Vertex, color) as u64,
|
||||||
|
format: wgpu::VertexFormat::Float32x3,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
primitive: wgpu::PrimitiveState {
|
||||||
|
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
depth_stencil: None,
|
||||||
|
multisample: wgpu::MultisampleState {
|
||||||
|
count: 1,
|
||||||
|
mask: !0,
|
||||||
|
alpha_to_coverage_enabled: false,
|
||||||
|
},
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: None,
|
||||||
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||||
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
|
format,
|
||||||
|
blend: Some(wgpu::BlendState::REPLACE),
|
||||||
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
|
})],
|
||||||
|
}),
|
||||||
|
multiview: None,
|
||||||
|
cache: None,
|
||||||
|
});
|
||||||
|
let bindings = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
label: None,
|
||||||
|
layout: &pipeline.get_bind_group_layout(0),
|
||||||
|
entries: &[wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: look_buf.as_entire_binding(),
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
Self {
|
||||||
|
look_buf,
|
||||||
|
bindings,
|
||||||
|
pipeline,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_look(&self, queue: &wgpu::Queue, look: LookParams) {
|
||||||
|
queue.write_buffer(&self.look_buf, 0, bytes_of(&look));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render<'a>(
|
||||||
|
&self,
|
||||||
|
pass: &mut wgpu::RenderPass,
|
||||||
|
meshes: impl IntoIterator<Item = &'a Mesh>,
|
||||||
|
) {
|
||||||
|
pass.set_pipeline(&self.pipeline);
|
||||||
|
pass.set_bind_group(0, &self.bindings, &[]);
|
||||||
|
for mesh in meshes {
|
||||||
|
pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..));
|
||||||
|
pass.set_index_buffer(mesh.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
|
||||||
|
pass.draw_indexed(0..mesh.index_count, 0, 0..1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -57,10 +57,9 @@ impl Pipeline {
|
||||||
mapped_at_creation: false,
|
mapped_at_creation: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
let shader = std::fs::read_to_string("shaders/line.wgsl").unwrap();
|
|
||||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
source: wgpu::ShaderSource::Wgsl(shader.into()),
|
source: wgpu::ShaderSource::Wgsl(super::SIMPLE_SHADER.into()),
|
||||||
});
|
});
|
||||||
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
|
|
|
||||||
|
|
@ -1 +1,4 @@
|
||||||
|
pub mod faces;
|
||||||
pub mod lines;
|
pub mod lines;
|
||||||
|
|
||||||
|
static SIMPLE_SHADER: &str = include_str!("simple.wgsl");
|
||||||
|
|
|
||||||
140
src/shape.rs
Normal file
140
src/shape.rs
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
|
use glam::{Vec3, vec3};
|
||||||
|
|
||||||
|
pub type Face = [u16; 3];
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Mesh {
|
||||||
|
pub vertices: Vec<Vec3>,
|
||||||
|
pub indices: Vec<Face>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sphere(subdiv: usize) -> Mesh {
|
||||||
|
assert!(subdiv >= 2);
|
||||||
|
assert!(2 * subdiv * (subdiv - 1) + 2 <= 1 << 16);
|
||||||
|
|
||||||
|
let mut vertices = Vec::new();
|
||||||
|
vertices.push(Vec3::Z);
|
||||||
|
for j in 1..subdiv {
|
||||||
|
let v = j as f32 / subdiv as f32;
|
||||||
|
let theta = PI * v;
|
||||||
|
let (xy, z) = theta.sin_cos();
|
||||||
|
for i in 0..2 * subdiv {
|
||||||
|
let u = i as f32 / (2 * subdiv) as f32;
|
||||||
|
let phi = 2. * PI * u;
|
||||||
|
let (y, x) = phi.sin_cos();
|
||||||
|
vertices.push(vec3(xy * x, xy * y, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vertices.push(-Vec3::Z);
|
||||||
|
assert_eq!(vertices.len(), 2 * subdiv * (subdiv - 1) + 2);
|
||||||
|
|
||||||
|
let mut indices = Vec::new();
|
||||||
|
let subdiv = subdiv as u16;
|
||||||
|
for i in 0..2 * subdiv - 1 {
|
||||||
|
indices.push([0, i + 1, i + 2]);
|
||||||
|
}
|
||||||
|
indices.push([0, 2 * subdiv, 1]);
|
||||||
|
for j in 0..subdiv - 2 {
|
||||||
|
let k1 = j * 2 * subdiv + 1;
|
||||||
|
let k2 = k1 + 2 * subdiv;
|
||||||
|
for i in 0..2 * subdiv - 1 {
|
||||||
|
let a = k1 + i;
|
||||||
|
let b = k2 + i;
|
||||||
|
indices.push([a, b, b + 1]);
|
||||||
|
indices.push([a, b + 1, a + 1]);
|
||||||
|
}
|
||||||
|
let a = k1 + 2 * subdiv - 1;
|
||||||
|
let b = k2 + 2 * subdiv - 1;
|
||||||
|
indices.push([a, b, k2]);
|
||||||
|
indices.push([a, k2, k1]);
|
||||||
|
}
|
||||||
|
let k1 = 2 * subdiv * (subdiv - 2) + 1;
|
||||||
|
let k2 = 2 * subdiv * (subdiv - 1) + 1;
|
||||||
|
for i in 0..2 * subdiv - 1 {
|
||||||
|
indices.push([k1 + i, k2, k1 + i + 1]);
|
||||||
|
}
|
||||||
|
indices.push([k1 + 2 * subdiv - 1, k2, k1]);
|
||||||
|
|
||||||
|
Mesh { vertices, indices }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use approx::abs_diff_eq;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sphere_2_topology() {
|
||||||
|
assert_eq!(
|
||||||
|
sphere(2).indices,
|
||||||
|
vec![
|
||||||
|
[0, 1, 2],
|
||||||
|
[0, 2, 3],
|
||||||
|
[0, 3, 4],
|
||||||
|
[0, 4, 1],
|
||||||
|
[1, 5, 2],
|
||||||
|
[2, 5, 3],
|
||||||
|
[3, 5, 4],
|
||||||
|
[4, 5, 1],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn are_equal_eps(left: &[Vec3], right: &[Vec3], eps: f32) -> bool {
|
||||||
|
if left.len() != right.len() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
left.iter()
|
||||||
|
.zip(right.iter())
|
||||||
|
.all(|(a, b)| abs_diff_eq!(a, b, epsilon = eps))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sphere_2_geometry() {
|
||||||
|
let left = sphere(2).vertices;
|
||||||
|
let right = [Vec3::Z, Vec3::X, Vec3::Y, -Vec3::X, -Vec3::Y, -Vec3::Z];
|
||||||
|
assert!(
|
||||||
|
are_equal_eps(&left, &right, 1e-6),
|
||||||
|
"assertion `left == right` failed\n left: {left:?}\n right: {right:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sphere_3_topology() {
|
||||||
|
assert_eq!(
|
||||||
|
sphere(3).indices,
|
||||||
|
vec![
|
||||||
|
// top
|
||||||
|
[0, 1, 2],
|
||||||
|
[0, 2, 3],
|
||||||
|
[0, 3, 4],
|
||||||
|
[0, 4, 5],
|
||||||
|
[0, 5, 6],
|
||||||
|
[0, 6, 1],
|
||||||
|
// belt
|
||||||
|
[1, 7, 8],
|
||||||
|
[1, 8, 2],
|
||||||
|
[2, 8, 9],
|
||||||
|
[2, 9, 3],
|
||||||
|
[3, 9, 10],
|
||||||
|
[3, 10, 4],
|
||||||
|
[4, 10, 11],
|
||||||
|
[4, 11, 5],
|
||||||
|
[5, 11, 12],
|
||||||
|
[5, 12, 6],
|
||||||
|
[6, 12, 7],
|
||||||
|
[6, 7, 1],
|
||||||
|
// bottom
|
||||||
|
[7, 13, 8],
|
||||||
|
[8, 13, 9],
|
||||||
|
[9, 13, 10],
|
||||||
|
[10, 13, 11],
|
||||||
|
[11, 13, 12],
|
||||||
|
[12, 13, 7],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,11 @@ struct SphericalPosition {
|
||||||
float distance = 1.;
|
float distance = 1.;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class UseNormal: std::uint8_t {
|
||||||
|
Light,
|
||||||
|
Camera,
|
||||||
|
};
|
||||||
|
|
||||||
struct RedrawArgs {
|
struct RedrawArgs {
|
||||||
SphericalPosition camera_position;
|
SphericalPosition camera_position;
|
||||||
SphericalPosition light_position;
|
SphericalPosition light_position;
|
||||||
|
|
@ -20,7 +25,8 @@ struct RedrawArgs {
|
||||||
float light_spread = 0.;
|
float light_spread = 0.;
|
||||||
float accum_sigma = 1.;
|
float accum_sigma = 1.;
|
||||||
float accum_scale = 1.;
|
float accum_scale = 1.;
|
||||||
std::uint32_t reflections = 0;
|
std::uint8_t reflections = 0;
|
||||||
|
UseNormal use_normal = UseNormal::Light;
|
||||||
bool show_axes = true;
|
bool show_axes = true;
|
||||||
bool show_shapes = true;
|
bool show_shapes = true;
|
||||||
bool show_hit_emission = true;
|
bool show_hit_emission = true;
|
||||||
|
|
@ -31,6 +37,7 @@ struct RedrawArgs {
|
||||||
};
|
};
|
||||||
} // namespace ffi
|
} // namespace ffi
|
||||||
|
|
||||||
|
using ffi::UseNormal;
|
||||||
using ffi::RedrawArgs;
|
using ffi::RedrawArgs;
|
||||||
using ffi::SphericalPosition;
|
using ffi::SphericalPosition;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,11 @@ float deg_to_rad(float val) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotonLight::updateView() {
|
void PhotonLight::updateView() {
|
||||||
|
UseNormal use_normal = {};
|
||||||
|
if (m_ui->normalFromLight->isChecked())
|
||||||
|
use_normal = UseNormal::Light;
|
||||||
|
else if (m_ui->normalFromCamera->isChecked())
|
||||||
|
use_normal = UseNormal::Camera;
|
||||||
RedrawArgs args{
|
RedrawArgs args{
|
||||||
.camera_position = SphericalPosition{
|
.camera_position = SphericalPosition{
|
||||||
.yaw = deg_to_rad(m_ui->cameraYaw->value()),
|
.yaw = deg_to_rad(m_ui->cameraYaw->value()),
|
||||||
|
|
@ -31,7 +36,8 @@ void PhotonLight::updateView() {
|
||||||
.light_spread = 0.125,
|
.light_spread = 0.125,
|
||||||
.accum_sigma = exp10f(m_ui->accumSigma->value() / 25.0),
|
.accum_sigma = exp10f(m_ui->accumSigma->value() / 25.0),
|
||||||
.accum_scale = exp10f(m_ui->accumScale->value() / 25.0),
|
.accum_scale = exp10f(m_ui->accumScale->value() / 25.0),
|
||||||
.reflections = std::uint32_t(m_ui->reflections->value()),
|
.reflections = std::uint8_t(m_ui->reflections->value()),
|
||||||
|
.use_normal = use_normal,
|
||||||
.show_axes = m_ui->displayAxes->isChecked(),
|
.show_axes = m_ui->displayAxes->isChecked(),
|
||||||
.show_shapes = m_ui->displayShapes->isChecked(),
|
.show_shapes = m_ui->displayShapes->isChecked(),
|
||||||
.show_hit_emission = m_ui->displayEmitted->isChecked(),
|
.show_hit_emission = m_ui->displayEmitted->isChecked(),
|
||||||
|
|
@ -51,4 +57,9 @@ void PhotonLight::updateView() {
|
||||||
m_ui->viewport->setView(args);
|
m_ui->viewport->setView(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PhotonLight::updateViewIf(bool update) {
|
||||||
|
if (update)
|
||||||
|
updateView();
|
||||||
|
}
|
||||||
|
|
||||||
#include "moc_main_window.cpp"
|
#include "moc_main_window.cpp"
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ public:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateView();
|
void updateView();
|
||||||
|
void updateViewIf(bool update); // for radio buttons
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::unique_ptr<Ui::MainWindow> m_ui;
|
const std::unique_ptr<Ui::MainWindow> m_ui;
|
||||||
|
|
|
||||||
|
|
@ -298,6 +298,30 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Use normal at</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="normalFromLight">
|
||||||
|
<property name="text">
|
||||||
|
<string>Hit position</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="normalFromCamera">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show position</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
@ -637,8 +661,41 @@
|
||||||
</hint>
|
</hint>
|
||||||
</hints>
|
</hints>
|
||||||
</connection>
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>normalFromLight</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>updateViewIf(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>1429</x>
|
||||||
|
<y>787</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>1381</x>
|
||||||
|
<y>783</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>normalFromCamera</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>updateViewIf(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>1932</x>
|
||||||
|
<y>816</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>1600</x>
|
||||||
|
<y>874</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
</connections>
|
</connections>
|
||||||
<slots>
|
<slots>
|
||||||
<slot>updateView()</slot>
|
<slot>updateView()</slot>
|
||||||
|
<slot>updateViewIf(bool)</slot>
|
||||||
</slots>
|
</slots>
|
||||||
</ui>
|
</ui>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user