Compare commits
3 Commits
413839ccb8
...
cd0c264c6e
| Author | SHA1 | Date | |
|---|---|---|---|
| cd0c264c6e | |||
| cf65929b99 | |||
| 8bed95f872 |
121
src/lib.rs
121
src/lib.rs
|
|
@ -2,10 +2,12 @@
|
||||||
|
|
||||||
use std::{convert::identity, error::Error, f32::consts::PI};
|
use std::{convert::identity, error::Error, f32::consts::PI};
|
||||||
|
|
||||||
use glam::{Mat4, UVec2, Vec3, vec3};
|
use glam::{Mat4, UVec2, Vec2, Vec3, vec3};
|
||||||
|
use rand_distr::Distribution as _;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
camera::OrbitalCamera,
|
camera::OrbitalCamera,
|
||||||
|
ray::Ray,
|
||||||
render::lines::{LookParams, Mesh, Pipeline, Vertex},
|
render::lines::{LookParams, Mesh, Pipeline, Vertex},
|
||||||
trace::{Scene, Source, Sphere},
|
trace::{Scene, Source, Sphere},
|
||||||
};
|
};
|
||||||
|
|
@ -32,6 +34,8 @@ pub struct RedrawArgs {
|
||||||
pub light_position: SphericalPosition,
|
pub light_position: SphericalPosition,
|
||||||
pub light_radius: f32,
|
pub light_radius: f32,
|
||||||
pub light_spread: f32,
|
pub light_spread: f32,
|
||||||
|
pub accum_sigma: f32,
|
||||||
|
pub accum_scale: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Gpu {
|
pub struct Gpu {
|
||||||
|
|
@ -84,6 +88,22 @@ fn loop_list_ex<T: Clone, U>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl OrbitalCamera {
|
||||||
|
fn make_ray(&self, rng: &mut impl rand::Rng) -> Ray {
|
||||||
|
let off: f32 = rand_distr::StandardUniform.sample(rng);
|
||||||
|
let side: Vec2 = rand_distr::UnitCircle.sample(rng).into();
|
||||||
|
|
||||||
|
let m = self.transform().inverse();
|
||||||
|
let fwd = 1. - 0.1 * off;
|
||||||
|
let side_scale = (1. - fwd.powi(2)).sqrt();
|
||||||
|
let dir = Vec3::from((side_scale * side, fwd));
|
||||||
|
Ray {
|
||||||
|
base: self.position(),
|
||||||
|
dir: m.transform_vector3(dir),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Core {
|
impl Core {
|
||||||
pub fn new(gpu: Gpu) -> Self {
|
pub fn new(gpu: Gpu) -> Self {
|
||||||
let Gpu {
|
let Gpu {
|
||||||
|
|
@ -189,36 +209,77 @@ impl Core {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut prng = rand_pcg::Pcg64::new(42, 0);
|
let mut prng = rand_pcg::Pcg64::new(42, 0);
|
||||||
let rays: Vec<Vertex> = (0..10000)
|
let source_rays: Vec<Ray> = (0..10240).map(|_| source.make_ray(&mut prng)).collect();
|
||||||
.flat_map(|_| {
|
let camera_rays: Vec<Ray> = (0..1024).map(|_| camera.make_ray(&mut prng)).collect();
|
||||||
let ray = source.make_ray(&mut prng);
|
let mut source_ray_display: Vec<Vertex> = Vec::with_capacity(source_rays.len());
|
||||||
if let Some(ray) = scene.trace_ray(ray) {
|
let mut hits: Vec<Ray> = Vec::with_capacity(source_rays.len());
|
||||||
[
|
for ray in source_rays {
|
||||||
Vertex {
|
if let Some(hit) = scene.trace_ray(ray) {
|
||||||
pos: ray.base - 0.02 * ray.dir,
|
hits.push(hit);
|
||||||
color: vec3(1., 1., 1.),
|
source_ray_display.extend([
|
||||||
},
|
Vertex {
|
||||||
Vertex {
|
pos: ray.base,
|
||||||
pos: ray.base,
|
color: vec3(1., 1., 1.),
|
||||||
color: vec3(0., 1., 0.),
|
},
|
||||||
},
|
Vertex {
|
||||||
]
|
pos: ray.base + 0.1 * ray.dir,
|
||||||
} else {
|
color: vec3(0., 1., 0.),
|
||||||
[
|
},
|
||||||
Vertex {
|
Vertex {
|
||||||
pos: ray.base,
|
pos: hit.base - 0.02 * hit.dir,
|
||||||
color: vec3(1., 1., 1.),
|
color: vec3(0., 0., 1.),
|
||||||
},
|
},
|
||||||
Vertex {
|
Vertex {
|
||||||
pos: ray.base + 0.1 * ray.dir,
|
pos: hit.base,
|
||||||
color: vec3(1., 0., 0.),
|
color: vec3(1., 1., 1.),
|
||||||
},
|
},
|
||||||
]
|
]);
|
||||||
}
|
} else {
|
||||||
})
|
source_ray_display.extend([
|
||||||
.collect();
|
Vertex {
|
||||||
|
pos: ray.base,
|
||||||
|
color: vec3(1., 1., 1.),
|
||||||
|
},
|
||||||
|
Vertex {
|
||||||
|
pos: ray.base + 0.1 * ray.dir,
|
||||||
|
color: vec3(1., 0., 0.),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut camera_ray_display: Vec<Vertex> = Vec::with_capacity(camera_rays.len());
|
||||||
|
let sigma2 = args.accum_sigma.powi(2);
|
||||||
|
let weight = (2. * PI * sigma2).sqrt().recip() * args.accum_scale;
|
||||||
|
for ray in camera_rays {
|
||||||
|
let Some(hit) = scene.trace_ray(ray) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let mut value = 0.0f32;
|
||||||
|
for light_hit in &hits {
|
||||||
|
let d2 = hit.base.distance_squared(light_hit.base);
|
||||||
|
let w = (-0.5 * d2 / sigma2).exp();
|
||||||
|
value += w;
|
||||||
|
}
|
||||||
|
value *= weight;
|
||||||
|
let r = 0.01;
|
||||||
|
let color = vec3(value, value - 1., value - 2.).clamp(Vec3::splat(0.), Vec3::splat(1.));
|
||||||
|
let vertex = |off: Vec3| Vertex {
|
||||||
|
pos: hit.base + r * off,
|
||||||
|
color,
|
||||||
|
};
|
||||||
|
camera_ray_display.extend([
|
||||||
|
vertex(-Vec3::X),
|
||||||
|
vertex(Vec3::X),
|
||||||
|
vertex(-Vec3::Y),
|
||||||
|
vertex(Vec3::Y),
|
||||||
|
vertex(-Vec3::Z),
|
||||||
|
vertex(Vec3::Z),
|
||||||
|
]);
|
||||||
|
}
|
||||||
self.pipeline
|
self.pipeline
|
||||||
.render(&mut pass, [&Mesh::new(&self.device, &rays)]);
|
.render(&mut pass, [&Mesh::new(&self.device, &source_ray_display)]);
|
||||||
|
self.pipeline
|
||||||
|
.render(&mut pass, [&Mesh::new(&self.device, &camera_ray_display)]);
|
||||||
|
|
||||||
drop(pass);
|
drop(pass);
|
||||||
self.queue.submit(std::iter::once(encoder.finish()));
|
self.queue.submit(std::iter::once(encoder.finish()));
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ struct RedrawArgs {
|
||||||
SphericalPosition light_position;
|
SphericalPosition light_position;
|
||||||
float light_radius;
|
float light_radius;
|
||||||
float light_spread;
|
float light_spread;
|
||||||
|
float accum_sigma;
|
||||||
|
float accum_scale;
|
||||||
};
|
};
|
||||||
} // namespace ffi
|
} // namespace ffi
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ float deg_to_rad(float val) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotonLight::updateView() {
|
void PhotonLight::updateView() {
|
||||||
m_ui->viewport->setView(RedrawArgs{
|
RedrawArgs args{
|
||||||
.camera_position = SphericalPosition{
|
.camera_position = SphericalPosition{
|
||||||
.yaw = deg_to_rad(m_ui->cameraYaw->value()),
|
.yaw = deg_to_rad(m_ui->cameraYaw->value()),
|
||||||
.pitch = deg_to_rad(m_ui->cameraPitch->value()),
|
.pitch = deg_to_rad(m_ui->cameraPitch->value()),
|
||||||
|
|
@ -29,7 +29,16 @@ void PhotonLight::updateView() {
|
||||||
},
|
},
|
||||||
.light_radius = 0.125,
|
.light_radius = 0.125,
|
||||||
.light_spread = 0.125,
|
.light_spread = 0.125,
|
||||||
});
|
.accum_sigma = exp10f(m_ui->accumSigma->value() / 25.0),
|
||||||
|
.accum_scale = exp10f(m_ui->accumScale->value() / 25.0),
|
||||||
|
};
|
||||||
|
m_ui->cameraYawLabel->setText(tr("Yaw: %1 deg").arg(QString::number(qRadiansToDegrees(args.camera_position.yaw))));
|
||||||
|
m_ui->cameraPitchLabel->setText(tr("Pitch: %1 deg").arg(QString::number(qRadiansToDegrees(args.camera_position.pitch))));
|
||||||
|
m_ui->lightYawLabel->setText(tr("Yaw: %1 deg").arg(QString::number(qRadiansToDegrees(args.light_position.yaw))));
|
||||||
|
m_ui->lightPitchLabel->setText(tr("Pitch: %1 deg").arg(QString::number(qRadiansToDegrees(args.light_position.pitch))));
|
||||||
|
m_ui->accumSigmaLabel->setText(tr("Sigma: %1").arg(QString::number(args.accum_sigma)));
|
||||||
|
m_ui->accumScaleLabel->setText(tr("Scale: %1").arg(QString::number(args.accum_scale)));
|
||||||
|
m_ui->viewport->setView(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "moc_main_window.cpp"
|
#include "moc_main_window.cpp"
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="cameraYawLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Yaw</string>
|
<string>Yaw</string>
|
||||||
</property>
|
</property>
|
||||||
|
|
@ -73,7 +73,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="cameraPitchLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Pitch</string>
|
<string>Pitch</string>
|
||||||
</property>
|
</property>
|
||||||
|
|
@ -108,7 +108,7 @@
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QLabel" name="lightYawLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Yaw</string>
|
<string>Yaw</string>
|
||||||
</property>
|
</property>
|
||||||
|
|
@ -131,7 +131,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_4">
|
<widget class="QLabel" name="lightPitchLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Pitch</string>
|
<string>Pitch</string>
|
||||||
</property>
|
</property>
|
||||||
|
|
@ -162,6 +162,55 @@
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_3">
|
||||||
|
<property name="title">
|
||||||
|
<string>Accumulating</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="accumSigmaLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Sigma</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSlider" name="accumSigma">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>-100</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="accumScaleLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Scale</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSlider" name="accumScale">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>-100</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="verticalSpacer">
|
<spacer name="verticalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
|
@ -253,6 +302,38 @@
|
||||||
</hint>
|
</hint>
|
||||||
</hints>
|
</hints>
|
||||||
</connection>
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>accumSigma</sender>
|
||||||
|
<signal>valueChanged(int)</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>updateView()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>729</x>
|
||||||
|
<y>479</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>399</x>
|
||||||
|
<y>299</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>accumScale</sender>
|
||||||
|
<signal>valueChanged(int)</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>updateView()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>729</x>
|
||||||
|
<y>535</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>399</x>
|
||||||
|
<y>299</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
</connections>
|
</connections>
|
||||||
<slots>
|
<slots>
|
||||||
<slot>updateView()</slot>
|
<slot>updateView()</slot>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user