directional light

This commit is contained in:
zomseffen 2025-02-12 14:48:52 +01:00
parent da773cad56
commit b559bd5e08
8 changed files with 273 additions and 55 deletions

Binary file not shown.

View file

@ -149,11 +149,11 @@ uvec4 sample_color_from_scene_info(uint volume_start, uvec2 raster_pos, uint f)
}
vec3 get_light_position(uint light_index) {
return vec3(uintBitsToFloat(scene_info.infos[light_index]), uintBitsToFloat(scene_info.infos[light_index + 1]), uintBitsToFloat(scene_info.infos[light_index + 2]));
return vec3(uintBitsToFloat(scene_info.infos[light_index + 1]), uintBitsToFloat(scene_info.infos[light_index + 2]), uintBitsToFloat(scene_info.infos[light_index + 3]));
}
vec3 get_light_color(uint light_index) {
return vec3(float(scene_info.infos[light_index + 3]) / 255.0, float(scene_info.infos[light_index + 4]) / 255.0, float(scene_info.infos[light_index + 5]) / 255.0);
return vec3(float(scene_info.infos[light_index + 4]) / 255.0, float(scene_info.infos[light_index + 5]) / 255.0, float(scene_info.infos[light_index + 6]) / 255.0);
}
vec3 normal_for_facing(uint facing) {
@ -377,7 +377,7 @@ vec3 get_lighting_color(uint volume_start, vec3 starting_pos, vec4 orig_color_sa
uint light_num = 0;
// initialize color
vec3 color_sum = vec3(0.0, 0.0, 0.0) + (orig_color_sample.xyz * 0.01);
vec3 color_sum = vec3(0.0, 0.0, 0.0);// + (orig_color_sample.xyz * 0.01);
uint max_iterations = max_num_lights * max_iterations_per_light;
uint iteration = 0;
@ -388,10 +388,20 @@ vec3 get_lighting_color(uint volume_start, vec3 starting_pos, vec4 orig_color_sa
// abort if there is no new light
break;
}
vec3 light_direction = get_light_position(light_index) - starting_pos;
vec3 light_direction;
float max_factor;
if (scene_info.infos[light_index] == 0) {
//point light
light_direction = get_light_position(light_index) - starting_pos;
max_factor = 1.0;
} else if (scene_info.infos[light_index] == 1) {
// directional light
light_direction = -normalize(get_light_position(light_index));
max_factor = pos_infinity;
}
vec3 light_color = get_light_color(light_index);
Tracing result = trace_ray(volume_start, starting_pos, light_direction, 1.0, iteration, max_iterations, false);
Tracing result = trace_ray(volume_start, starting_pos, light_direction, max_factor, iteration, max_iterations, false);
// add result, if there is a hit the null vector will be added
color_sum += float(!result.has_hit) * result.color_mul * max(dot(normal, normalize(light_direction)), 0.0) * (orig_color_sample.xyz * light_color) / (length(light_direction) * length(light_direction));

View file

@ -190,7 +190,7 @@ impl App {
let entry = Entry::new(loader).map_err(|b| anyhow!("{}", b))?;
let mut data = app_data::AppData::default();
data.use_geometry_shader = false;
data.num_lights_per_volume = 2;
data.num_lights_per_volume = 5;
data.max_iterations_per_light = 20;
data.diffuse_raster_steps = 0;
data.diffuse_raster_size = 0.01;
@ -218,9 +218,9 @@ impl App {
create_framebuffers(&device, &mut data)?;
//image::create_texture_image(&instance, &device, &mut data)?;
//image::create_texture_image_view(&device, &mut data)?;
//image::create_texture_sampler(&device, &mut data)?;
image::create_texture_image(&instance, &device, &mut data)?;
image::create_texture_image_view(&device, &mut data)?;
image::create_texture_sampler(&device, &mut data)?;
scene_handler.prepare_data(&instance, &device, &mut data)?;

View file

@ -10,7 +10,12 @@ use crate::primitives::cube::Cube;
use crate::primitives::quad::Quad;
use crate::scene::oct_tree::OctTree;
use super::memorizable::Memorizable;
use super::light::LightSource;
use super::light::PointLight;
use super::AppData;
use super::LightsIter;
use super::Scene;
pub struct EmptyVolume {
pub memory_start: usize,
@ -863,12 +868,37 @@ impl EmptyVolume {
}
quads
}
pub fn select_lights(&self, lights: LightsIter, light_number: u32) -> Vec<u32> {
let center = self.position + Vector3{x: self.size_x / 2, y: self.size_y / 2, z: self.size_z / 2};
let mut weighted_indices = vec![];
for light in lights {
let weight = light.borrow().weighted_distance(center);
weighted_indices.push((weight, light.borrow().get_memory_start()));
}
weighted_indices.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
let mut out_index = vec![];
for index in 0..weighted_indices.len() {
out_index.push(weighted_indices[weighted_indices.len() - (index + 1)].1 as u32);
if out_index.len() == light_number as usize {
break;
}
}
while out_index.len() < light_number as usize {
out_index.push(0);
}
out_index
}
}
impl Memorizable for EmptyVolume {
// MARK: Get Buffer Mem Size
pub fn get_buffer_mem_size(&self, light_number: u32) -> u32 {
fn get_buffer_mem_size(&self, data: &AppData) -> u32 {
let mut mem_size: u32 = 0;
mem_size += 3; //pos
mem_size += 3; //max sizes
mem_size += light_number; // light references
mem_size += data.num_lights_per_volume; // light references
mem_size += 12; //color/roughness buffer sizes, 2 values each
mem_size += 12; //neighbor buffer sizes, 2 values each
@ -890,7 +920,7 @@ impl EmptyVolume {
mem_size
}
// MARK: insert into Memory
pub fn insert_into_memory(&self, mut v: Vec<u32>, light_number: u32, lights: &Vec<PointLight>) -> Vec<u32> {
fn insert_into_memory(&self, mut v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32> {
let mut mem_index = self.memory_start;
//pos
v[mem_index] = self.position.x as u32;
@ -907,7 +937,7 @@ impl EmptyVolume {
v[mem_index] = self.size_z as u32;
mem_index += 1;
//Todo: insert lights
let selected_lights = self.select_lights(lights, light_number);
let selected_lights = self.select_lights(scene.get_light_iter(), data.num_lights_per_volume);
for light in selected_lights {
v[mem_index] = light;
mem_index += 1;
@ -1207,26 +1237,12 @@ impl EmptyVolume {
v
}
pub fn select_lights(&self, lights: &Vec<PointLight>, light_number: u32) -> Vec<u32> {
let center = self.position + Vector3{x: self.size_x / 2, y: self.size_y / 2, z: self.size_z / 2};
let mut weighted_indices = vec![];
for light in lights {
let weight = light.weighted_distance(center);
weighted_indices.push((weight, light.memory_start));
}
weighted_indices.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
fn get_memory_start(&self) -> usize {
self.memory_start
}
let mut out_index = vec![];
for index in 0..weighted_indices.len() {
out_index.push(weighted_indices[weighted_indices.len() - (index + 1)].1 as u32);
if out_index.len() == light_number as usize {
break;
}
}
while out_index.len() < light_number as usize {
out_index.push(0);
}
out_index
fn set_memory_start(&mut self, memory_start: usize) {
self.memory_start = memory_start;
}
}

View file

@ -1,6 +1,22 @@
use cgmath::{InnerSpace, MetricSpace, Vector3};
use crate::vertex;
use super::memorizable::Memorizable;
use super::AppData;
use super::Scene;
pub enum LightType {
POINT,
DIRECTION
}
pub trait Light {
fn get_light_type(&self) -> LightType;
fn weighted_distance(&self, center: Vector3<usize>) -> f32;
}
pub trait LightSource: Light + Memorizable {}
#[derive(Clone, Debug, PartialEq)]
pub struct PointLight{
@ -9,26 +25,151 @@ pub struct PointLight{
pub memory_start: usize,
}
impl PointLight {
pub fn get_buffer_mem_size(&self) -> u32 {
3 + 3
impl Memorizable for PointLight {
fn get_buffer_mem_size(&self, data: &AppData) -> u32 {
1 + 3 + 3
}
pub fn insert_into_memory(&self, mut v: Vec<u32>) -> Vec<u32> {
v[self.memory_start] = u32::from_ne_bytes(self.pos.x.to_ne_bytes());
v[self.memory_start + 1] = u32::from_ne_bytes(self.pos.y.to_ne_bytes());
v[self.memory_start + 2] = u32::from_ne_bytes(self.pos.z.to_ne_bytes());
fn insert_into_memory(&self, mut v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32> {
v[self.memory_start] = LightType::POINT as u32;
v[self.memory_start + 3] = (self.color.x * 255.0) as u32;
v[self.memory_start + 4] = (self.color.y * 255.0) as u32;
v[self.memory_start + 5] = (self.color.z * 255.0) as u32;
v[self.memory_start + 1] = u32::from_ne_bytes(self.pos.x.to_ne_bytes());
v[self.memory_start + 2] = u32::from_ne_bytes(self.pos.y.to_ne_bytes());
v[self.memory_start + 3] = u32::from_ne_bytes(self.pos.z.to_ne_bytes());
v[self.memory_start + 4] = (self.color.x * 255.0) as u32;
v[self.memory_start + 5] = (self.color.y * 255.0) as u32;
v[self.memory_start + 6] = (self.color.z * 255.0) as u32;
v
}
pub fn weighted_distance(&self, center: Vector3<usize>) -> f32 {
fn get_memory_start(&self) -> usize {
self.memory_start
}
fn set_memory_start(&mut self, memory_start: usize) {
self.memory_start = memory_start;
}
}
impl Light for PointLight {
fn get_light_type(&self) -> LightType {
LightType::POINT
}
fn weighted_distance(&self, center: Vector3<usize>) -> f32 {
let distance = self.pos.distance(vertex::Vec3{x: center.x as f32, y: center.y as f32, z: center.z as f32});
let light_intensity = self.color.magnitude();
light_intensity / distance.powf(2.0)
}
}
impl LightSource for PointLight {}
#[derive(Clone, Debug, PartialEq)]
pub struct DirectionalLight{
pub direction: vertex::Vec3,
pub color: vertex::Vec3,
pub memory_start: usize,
}
impl Memorizable for DirectionalLight {
fn get_buffer_mem_size(&self, data: &AppData) -> u32 {
1 + 3 + 3
}
fn insert_into_memory(&self, mut v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32> {
v[self.memory_start] = LightType::DIRECTION as u32;
v[self.memory_start + 1] = u32::from_ne_bytes(self.direction.x.to_ne_bytes());
v[self.memory_start + 2] = u32::from_ne_bytes(self.direction.y.to_ne_bytes());
v[self.memory_start + 3] = u32::from_ne_bytes(self.direction.z.to_ne_bytes());
v[self.memory_start + 4] = (self.color.x * 255.0) as u32;
v[self.memory_start + 5] = (self.color.y * 255.0) as u32;
v[self.memory_start + 6] = (self.color.z * 255.0) as u32;
v
}
fn get_memory_start(&self) -> usize {
self.memory_start
}
fn set_memory_start(&mut self, memory_start: usize) {
self.memory_start = memory_start;
}
}
impl Light for DirectionalLight {
fn get_light_type(&self) -> LightType {
LightType::DIRECTION
}
fn weighted_distance(&self, center: Vector3<usize>) -> f32 {
let light_intensity = self.color.magnitude();
light_intensity
}
}
impl LightSource for DirectionalLight {}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_memorizable() {
let p = PointLight {pos: vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, color: vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0}, memory_start: 0};
let data= AppData::default();
let scene = Scene::default();
let mem_size = p.get_buffer_mem_size(&data);
assert!(mem_size == 7);
let mut memory = vec![0; 7];
p.insert_into_memory(memory, &data, &scene);
}
#[test]
#[should_panic]
fn test_mem_size() {
let p = PointLight {pos: vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, color: vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0}, memory_start: 0};
let data= AppData::default();
let scene = Scene::default();
let mem_size = p.get_buffer_mem_size(&data);
assert!(mem_size == 7);
let mut memory = vec![0; 6];
p.insert_into_memory(memory, &data, &scene);
}
#[test]
fn test_memorizable_directional_light() {
let p = DirectionalLight {direction: vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, color: vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0}, memory_start: 0};
let data= AppData::default();
let scene = Scene::default();
let mem_size = p.get_buffer_mem_size(&data);
assert!(mem_size == 7);
let mut memory = vec![0; 7];
p.insert_into_memory(memory, &data, &scene);
}
#[test]
#[should_panic]
fn test_mem_size_directional_light() {
let p = DirectionalLight {direction: vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, color: vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0}, memory_start: 0};
let data= AppData::default();
let scene = Scene::default();
let mem_size = p.get_buffer_mem_size(&data);
assert!(mem_size == 7);
let mut memory = vec![0; 6];
p.insert_into_memory(memory, &data, &scene);
}
}

10
src/scene/memorizable.rs Normal file
View file

@ -0,0 +1,10 @@
use super::light::LightSource;
use super::AppData;
use super::Scene;
pub trait Memorizable {
fn get_buffer_mem_size(&self, data: &AppData) -> u32;
fn insert_into_memory(&self, v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32>;
fn get_memory_start(&self) -> usize;
fn set_memory_start(&mut self, memory_start: usize);
}

View file

@ -1,8 +1,10 @@
mod oct_tree;
mod empty_volume;
mod light;
mod memorizable;
use anyhow::Ok;
use light::{DirectionalLight, LightSource};
use vulkanalia::prelude::v1_0::*;
use anyhow::Result;
@ -11,6 +13,7 @@ use cgmath::{vec2, vec3, Vector3};
use std::cell::RefCell;
use std::rc::Rc;
use crate::scene::memorizable::Memorizable;
use crate::app_data::AppData;
use crate::buffer;
use crate::primitives::rec_cuboid::Cuboid;
@ -54,7 +57,8 @@ pub struct Scene {
pub rt_memory: Vec<u32>,
pub point_lights: Vec<PointLight>,
point_lights: Vec<Rc<RefCell<PointLight>>>,
directional_lights: Vec<Rc<RefCell<DirectionalLight>>>,
}
impl Scene {
@ -99,8 +103,9 @@ impl Scene {
};
oct_tree.set_cube(cube.clone());
self.point_lights.push(PointLight { pos: vec3(11.0, 11.0, 11.0), color: vec3(1.0, 1.0, 1.0), memory_start: 0 });
self.point_lights.push(PointLight { pos: vec3(9.0, 9.0, 11.0), color: vec3(0.5, 0.5, 0.5), memory_start: 0 });
self.point_lights.push(Rc::new(RefCell::new(PointLight { pos: vec3(11.0, 11.0, 11.0), color: vec3(1.0, 1.0, 1.0), memory_start: 0 })));
self.point_lights.push(Rc::new(RefCell::new(PointLight { pos: vec3(9.0, 9.0, 11.0), color: vec3(0.5, 0.5, 0.5), memory_start: 0 })));
self.directional_lights.push(Rc::new(RefCell::new(DirectionalLight { direction: vec3(1.0, 1.0, -1.0), color: vec3(0.1, 0.1, 0.1), memory_start: 0 })));
let empty_volumes: Vec<Rc<RefCell<EmptyVolume>>>;
(empty_volumes, _) = EmptyVolume::from_oct_tree(&oct_tree);
@ -156,14 +161,14 @@ impl Scene {
// 3 - diffuse raster size
// 4 - max recursive rays
// 5 - diffuse rays per hit
for light in &mut self.point_lights {
light.memory_start = memory_index;
memory_index += light.get_buffer_mem_size() as usize;
for light in LightsIter::new(self) {
light.borrow_mut().set_memory_start(memory_index);
memory_index += light.borrow_mut().get_buffer_mem_size(data) as usize;
}
for volume in &empty_volumes {
volume.borrow_mut().memory_start = memory_index;
memory_index += volume.borrow().get_buffer_mem_size(data.num_lights_per_volume) as usize;
volume.borrow_mut().set_memory_start(memory_index);
memory_index += volume.borrow().get_buffer_mem_size(data) as usize;
}
for volume in &empty_volumes {
@ -181,10 +186,10 @@ impl Scene {
volume_vec[5] = data.diffuse_rays_per_hit;
for volume in &empty_volumes {
volume_vec = volume.borrow().insert_into_memory(volume_vec, data.num_lights_per_volume, &self.point_lights);
volume_vec = volume.borrow().insert_into_memory(volume_vec, data, &self);
}
for light in &self.point_lights {
volume_vec = light.insert_into_memory(volume_vec);
for light in LightsIter::new(self) {
volume_vec = light.borrow().insert_into_memory(volume_vec, data, &self);
}
//println!("volume_vec print {:?}", volume_vec);
@ -229,4 +234,40 @@ impl Scene {
device.destroy_buffer(self.vertex_buffer_quad, None);
device.free_memory(self.vertex_buffer_memory_quad, None);
}
fn get_light_iter(&self) -> LightsIter {
LightsIter::new(self)
}
}
pub struct LightsIter<'a> {
light_index: usize,
scene: &'a Scene,
}
impl<'a> LightsIter<'a> {
fn new(scene: &'a Scene) -> Self {
LightsIter {light_index: 0, scene: scene}
}
}
impl<'a> Iterator for LightsIter<'a> {
type Item = Rc<RefCell<dyn LightSource>>;
fn next(&mut self) -> Option<Self::Item> {
if self.light_index >= self.scene.point_lights.len() {
if self.light_index - self.scene.point_lights.len() >= self.scene.directional_lights.len() {
None
} else {
let result = self.scene.directional_lights[self.light_index - self.scene.point_lights.len()].clone();
self.light_index += 1;
Some(result)
}
} else {
let result = self.scene.point_lights[self.light_index].clone();
self.light_index += 1;
Some(result)
}
}
}

View file

@ -601,7 +601,7 @@ mod test {
#[test]
fn test_oct_tree(){
let mut test_tree: OctTree<Cube> = OctTree::create(512).unwrap();
let test_cube = Cube{color: Vector3 { x: 1.0, y: 0.0, z: 0.0 }, pos: Vector3 { x: 5.0, y: 2.0, z: 10.0 }, tex_coord: Vector2{x: 0.0, y: 0.0}, transparent: false};
let test_cube = Cube{color: Vector3 { x: 1.0, y: 0.0, z: 0.0 }, pos: Vector3 { x: 5.0, y: 2.0, z: 10.0 }, tex_coord: Vector2{x: 0.0, y: 0.0}, transparent: false, roughness: 128};
test_tree.set_cube(test_cube.clone());