Compare commits

...

5 Commits

Author SHA1 Message Date
6ba9add6ea a bit better ui 2025-11-16 20:18:05 +03:00
12bc173fb2 use Lambertian scattering 2025-11-16 19:39:36 +03:00
64925f9640 update defaults 2025-11-16 18:05:14 +03:00
198dc06d02 nicer hit rendering 2025-11-16 18:05:00 +03:00
bb8373fad5 optimize summation 2025-11-16 18:04:18 +03:00
4 changed files with 53 additions and 25 deletions

View File

@ -9,7 +9,7 @@ use crate::{
camera::OrbitalCamera, camera::OrbitalCamera,
ray::Ray, ray::Ray,
render::lines::{LookParams, Mesh, Pipeline, Vertex}, render::lines::{LookParams, Mesh, Pipeline, Vertex},
trace::{Scene, Source, Sphere}, trace::{Hit, Scene, Source, Sphere},
}; };
mod camera; mod camera;
@ -156,12 +156,7 @@ impl Core {
depth_slice: None, depth_slice: None,
resolve_target: None, resolve_target: None,
ops: wgpu::Operations { ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color { load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
r: 0.1,
g: 0.2,
b: 0.8,
a: 1.0,
}),
store: wgpu::StoreOp::Store, store: wgpu::StoreOp::Store,
}, },
})], })],
@ -210,9 +205,9 @@ impl Core {
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();
let camera_rays: Vec<Ray> = (0..1024).map(|_| camera.make_ray(&mut prng)).collect(); let camera_rays: Vec<Ray> = (0..10240).map(|_| camera.make_ray(&mut prng)).collect();
let mut source_ray_display: Vec<Vertex> = Vec::with_capacity(source_rays.len()); let mut source_ray_display: Vec<Vertex> = Vec::with_capacity(source_rays.len());
let mut hits: Vec<Ray> = Vec::with_capacity(source_rays.len()); let mut hits: Vec<Hit> = Vec::with_capacity(source_rays.len());
for ray in source_rays { for ray in source_rays {
if let Some(hit) = scene.trace_ray(ray) { if let Some(hit) = scene.trace_ray(ray) {
hits.push(hit); hits.push(hit);
@ -226,11 +221,11 @@ impl Core {
color: vec3(0., 1., 0.), color: vec3(0., 1., 0.),
}, },
Vertex { Vertex {
pos: hit.base - 0.02 * hit.dir, pos: hit.incident.base - 0.02 * hit.incident.dir,
color: vec3(0., 0., 1.), color: vec3(0., 0., 1.),
}, },
Vertex { Vertex {
pos: hit.base, pos: hit.incident.base,
color: vec3(1., 1., 1.), color: vec3(1., 1., 1.),
}, },
]); ]);
@ -256,15 +251,21 @@ impl Core {
}; };
let mut value = 0.0f32; let mut value = 0.0f32;
for light_hit in &hits { for light_hit in &hits {
let d2 = hit.base.distance_squared(light_hit.base); let d2 = hit.incident.base.distance_squared(light_hit.incident.base);
if d2 > 3. * sigma2 {
continue;
}
assert!(hit.incident.dir.is_normalized());
let radiance = hit.normal.dot(-hit.incident.dir);
let w = (-0.5 * d2 / sigma2).exp(); let w = (-0.5 * d2 / sigma2).exp();
value += w; value += w * radiance;
} }
value *= weight; value *= weight;
let r = 0.01; value = 3. * (1. - (1. + value).recip());
let r = args.accum_sigma;
let color = vec3(value, value - 1., value - 2.).clamp(Vec3::splat(0.), Vec3::splat(1.)); let color = vec3(value, value - 1., value - 2.).clamp(Vec3::splat(0.), Vec3::splat(1.));
let vertex = |off: Vec3| Vertex { let vertex = |off: Vec3| Vertex {
pos: hit.base + r * off, pos: hit.incident.base + r * off,
color, color,
}; };
camera_ray_display.extend([ camera_ray_display.extend([

View File

@ -78,8 +78,14 @@ pub struct Sphere {
pub radius: f32, pub radius: f32,
} }
struct Hit1 {
pos: Vec3,
dist: f32,
normal: Vec3,
}
impl Sphere { impl Sphere {
fn trace_ray(&self, ray: Ray) -> Option<f32> { fn trace_ray(&self, ray: Ray) -> Option<Hit1> {
// let t: f32; // let t: f32;
// let hit = ray.base + t * ray.dir; // let hit = ray.base + t * ray.dir;
// (hit - self.position).length() == self.radius; // (hit - self.position).length() == self.radius;
@ -94,7 +100,10 @@ impl Sphere {
if d4 < 0. { if d4 < 0. {
return None; return None;
} }
Some((-b2 - d4.sqrt()) / a) let dist = (-b2 - d4.sqrt()) / a;
let pos = ray.advance(dist).base;
let normal = (pos - self.position).normalize();
Some(Hit1 { pos, dist, normal })
} }
} }
@ -103,13 +112,25 @@ pub struct Scene {
pub objects: Vec<Sphere>, pub objects: Vec<Sphere>,
} }
#[derive(Debug, Clone, Copy)]
pub struct Hit {
pub incident: Ray,
pub normal: Vec3,
}
impl Scene { impl Scene {
pub fn trace_ray(&self, ray: Ray) -> Option<Ray> { pub fn trace_ray(&self, ray: Ray) -> Option<Hit> {
let dist = self let hit = self
.objects .objects
.iter() .iter()
.filter_map(|obj| obj.trace_ray(ray)) .filter_map(|obj| obj.trace_ray(ray))
.min_by(f32::total_cmp); .min_by(|a, b| f32::total_cmp(&a.dist, &b.dist))?;
Some(ray.advance(dist?)) Some(Hit {
incident: Ray {
base: hit.pos,
dir: ray.dir,
},
normal: hit.normal,
})
} }
} }

View File

@ -36,8 +36,8 @@ void PhotonLight::updateView() {
m_ui->cameraPitchLabel->setText(tr("Pitch: %1 deg").arg(QString::number(qRadiansToDegrees(args.camera_position.pitch)))); 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->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->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->accumSigmaLabel->setText(tr("Sigma: %1").arg(QString::number(args.accum_sigma, 'f', 3)));
m_ui->accumScaleLabel->setText(tr("Scale: %1").arg(QString::number(args.accum_scale))); m_ui->accumScaleLabel->setText(tr("Scale: %1").arg(QString::number(args.accum_scale, 'f', 3)));
m_ui->viewport->setView(args); m_ui->viewport->setView(args);
} }

View File

@ -181,7 +181,10 @@
<number>-100</number> <number>-100</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<number>100</number> <number>0</number>
</property>
<property name="value">
<number>-40</number>
</property> </property>
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
@ -201,7 +204,10 @@
<number>-100</number> <number>-100</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<number>100</number> <number>0</number>
</property>
<property name="value">
<number>-50</number>
</property> </property>
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>