Added scene editor
This commit is contained in:
@@ -27,7 +27,7 @@ impl Camera {
|
||||
|
||||
/// Create a unit camera with default parameters
|
||||
pub fn unit() -> Self {
|
||||
let eye = Point3::new(0.0, 0.0, 1.0);
|
||||
let eye = Point3::new(0.0, 0.0, 2.0);
|
||||
let target = Point3::new(0.0, 0.0, 0.0);
|
||||
let up = Vector3::new(0.0, 1.0, 0.0);
|
||||
Camera::new(eye, target, up)
|
||||
|
||||
120
src/gui.rs
120
src/gui.rs
@@ -4,7 +4,6 @@ use crate::{
|
||||
primitive::*,
|
||||
scene::{Node, Scene},
|
||||
state::{INIT_FILE, SAVE_FILE},
|
||||
EPSILON,
|
||||
};
|
||||
use imgui::*;
|
||||
use nalgebra::{Point3, Vector3};
|
||||
@@ -12,16 +11,42 @@ use pixels::{wgpu, PixelsContext};
|
||||
use rhai::Engine;
|
||||
use std::time::Instant;
|
||||
|
||||
//BUFFER CONSTANTS
|
||||
const BUFFER_PROPORTION_INIT: f32 = 0.2;
|
||||
const BUFFER_PROPORTION_MIN: f32 = 0.1;
|
||||
const BUFFER_PROPORTION_MAX: f32 = 1.0;
|
||||
|
||||
//RAY CONSTANTS
|
||||
const RAYS_INIT: i32 = 7000;
|
||||
const RAYS_MIN: i32 = 100;
|
||||
const RAYS_MAX: i32 = 30000;
|
||||
|
||||
const CAMERA_MIN_FOV: f32 = 10.0;
|
||||
const CAMERA_MAX_FOV: f32 = 160.0;
|
||||
//MATERIAL CONSTANTS
|
||||
const MIN_D: f32 = 0.0;
|
||||
const MIN_S: f32 = 0.0;
|
||||
const MIN_SHINE: f32 = 0.0;
|
||||
const MAX_D: f32 = 1.0;
|
||||
const MAX_S: f32 = 1.0;
|
||||
const MAX_SHINE: f32 = 50.0;
|
||||
|
||||
//TRANSFORMATION CONSTANTS
|
||||
const MIN_COLOUR: f32 = 0.0;
|
||||
const MIN_FALLOFF: f32 = 0.0;
|
||||
const MIN_SCALE: f64 = 0.0;
|
||||
const MIN_POSITION: f64 = -10.0;
|
||||
const MIN_ROTATION: f64 = -180.0;
|
||||
const MIN_TRANSLATE: f64 = -10.0;
|
||||
//--
|
||||
const MAX_COLOUR: f32 = 1.0;
|
||||
const MAX_FALLOFF: f32 = 1.0;
|
||||
const MAX_SCALE: f64 = 3.0;
|
||||
const MAX_POSITION: f64 = 10.0;
|
||||
const MAX_ROTATION: f64 = 180.0;
|
||||
const MAX_TRANSLATE: f64 = 10.0;
|
||||
|
||||
// CAMERA CONSTANTS
|
||||
const MIN_FOV: f32 = 10.0;
|
||||
const MAX_FOV: f32 = 160.0;
|
||||
const CAMERA_INIT: f32 = 5.0;
|
||||
|
||||
/// Manages all state required for rendering Dear ImGui over `Pixels`test.
|
||||
@@ -49,9 +74,7 @@ pub struct Gui {
|
||||
|
||||
buffer_proportion: f32,
|
||||
|
||||
camera_eye: [f32; 3],
|
||||
camera_target: [f32; 3],
|
||||
camera_up: [f32; 3],
|
||||
camera: Camera,
|
||||
camera_fov: f32,
|
||||
|
||||
image_filename: String,
|
||||
@@ -113,9 +136,7 @@ impl Gui {
|
||||
ray_num: RAYS_INIT,
|
||||
buffer_proportion: BUFFER_PROPORTION_INIT,
|
||||
|
||||
camera_eye: [CAMERA_INIT, CAMERA_INIT, CAMERA_INIT],
|
||||
camera_target: Vector3::zeros().into(),
|
||||
camera_up: Vector3::y().into(),
|
||||
camera: Camera::unit(),
|
||||
camera_fov: 110.0,
|
||||
|
||||
image_filename: String::from(SAVE_FILE),
|
||||
@@ -170,7 +191,7 @@ impl Gui {
|
||||
&mut self.buffer_proportion,
|
||||
);
|
||||
// Fov of the buffer
|
||||
ui.slider("fov", CAMERA_MIN_FOV, CAMERA_MAX_FOV, &mut self.camera_fov);
|
||||
ui.slider("fov", MIN_FOV, MAX_FOV, &mut self.camera_fov);
|
||||
// Apply stored changes
|
||||
if ui.button("Apply") {
|
||||
self.event = Some(GuiEvent::BufferResize(
|
||||
@@ -183,21 +204,15 @@ impl Gui {
|
||||
if CollapsingHeader::new("Camera").build(ui) {
|
||||
// Eye, target and up vector inputs
|
||||
ui.text("Camera options:");
|
||||
ui.input_float3("Eye", &mut self.camera_eye).build();
|
||||
ui.input_float3("Target", &mut self.camera_target).build();
|
||||
ui.input_float3("Up", &mut self.camera_up).build();
|
||||
ui.slider_config("Eye", MIN_TRANSLATE, MAX_TRANSLATE)
|
||||
.build_array(self.camera.eye.coords.as_mut_slice());
|
||||
ui.slider_config("Target", MIN_TRANSLATE, MAX_TRANSLATE)
|
||||
.build_array(self.camera.target.coords.as_mut_slice());
|
||||
ui.slider_config("Up", 0.0, 1.0)
|
||||
.build_array(self.camera.up.as_mut_slice());
|
||||
if ui.button("Apply Camera") {
|
||||
println!("Camera changed: {:?}", self.camera_eye);
|
||||
let (eye, target, up) = (&self.camera_eye, &self.camera_target, &self.camera_up);
|
||||
let (ex, ey, ez) = (eye[0] as f64, eye[1] as f64, eye[2] as f64);
|
||||
let (tx, ty, tz) = (target[0] as f64, target[1] as f64, target[2] as f64);
|
||||
let (ux, uy, uz) = (up[0] as f64, up[1] as f64, up[2] as f64);
|
||||
let camera = Camera::new(
|
||||
Point3::new(ex, ey, ez),
|
||||
Point3::new(tx, ty, tz),
|
||||
Vector3::new(ux, uy, uz),
|
||||
);
|
||||
self.event = Some(GuiEvent::CameraUpdate(camera, self.camera_fov));
|
||||
println!("Camera changed");
|
||||
self.event = Some(GuiEvent::CameraUpdate(self.camera.clone(), self.camera_fov));
|
||||
}
|
||||
}
|
||||
// SCRIPTING --------------------------------------------
|
||||
@@ -249,39 +264,58 @@ impl Gui {
|
||||
// SCENE --------------------------------------------
|
||||
if CollapsingHeader::new("Scene").build(ui) {
|
||||
if ui.button("Update Scene") {
|
||||
for node in &mut self.scene.nodes {
|
||||
for (_, node) in &mut self.scene.nodes {
|
||||
node.compute();
|
||||
}
|
||||
self.event = Some(GuiEvent::SceneLoad(self.scene.clone()));
|
||||
}
|
||||
// Edit transformation of nodes
|
||||
if let Some(_t) = ui.tree_node("Nodes") {
|
||||
for node in &mut self.scene.nodes {
|
||||
ui.text("node");
|
||||
ui.slider_config("Translation", -10.0, 10.0)
|
||||
.build_array(&mut node.translation);
|
||||
ui.slider_config("Rotation", -180.0, 180.0)
|
||||
.build_array(&mut node.rotation);
|
||||
ui.slider_config("Scale", -10.0, 10.0)
|
||||
.build_array(&mut node.scale);
|
||||
for (label, node) in &mut self.scene.nodes {
|
||||
if let Some(_t) = ui.tree_node(label) {
|
||||
ui.slider_config("Translation", MIN_TRANSLATE, MAX_TRANSLATE)
|
||||
.build_array(&mut node.translation);
|
||||
ui.slider_config("Rotation", MIN_ROTATION, MAX_ROTATION)
|
||||
.build_array(&mut node.rotation);
|
||||
ui.slider_config("Scale", MIN_SCALE, MAX_SCALE)
|
||||
.build_array(&mut node.scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Edit materials
|
||||
// if let Some(_t) = ui.tree_node("Materials") {
|
||||
// for (label, material) in &mut self.scene.materials {
|
||||
// if let Some(_t) = ui.tree_node(label) {
|
||||
// ui.slider_config("ks", MIN_D, MIN_D)
|
||||
// .build_array(material.ks.as_mut_slice());
|
||||
// ui.slider_config("kd", MIN_S, MAX_S)
|
||||
// .build_array(material.kd.as_mut_slice());
|
||||
// ui.slider("fov", MIN_SHINE, MAX_SHINE, &mut material.shininess);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//Edit color, position and falloff of lights
|
||||
if let Some(_t) = ui.tree_node("Lights") {
|
||||
for light in &mut self.scene.lights {
|
||||
ui.slider_config("Colour", 0.0, 1.0)
|
||||
.build_array(light.colour.as_mut_slice());
|
||||
ui.slider_config("Position", -10.0, 10.0)
|
||||
.build_array(light.position.coords.as_mut_slice());
|
||||
ui.slider_config("Falloff", 0.0, f32::MAX)
|
||||
.build_array(light.falloff.as_mut_slice());
|
||||
for (label, light) in &mut self.scene.lights {
|
||||
if let Some(_t) = ui.tree_node(label) {
|
||||
ui.slider_config("Colour", MIN_COLOUR, MAX_COLOUR)
|
||||
.build_array(light.colour.as_mut_slice());
|
||||
ui.slider_config("Position", MIN_TRANSLATE, MAX_TRANSLATE)
|
||||
.build_array(light.position.coords.as_mut_slice());
|
||||
ui.slider_config("Falloff", MIN_FALLOFF, MAX_FALLOFF)
|
||||
.build_array(light.falloff.as_mut_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
//Use different cameras in the scene
|
||||
if let Some(_t) = ui.tree_node("Cameras") {
|
||||
for camera in &self.scene.cameras {
|
||||
if ui.button("Use camera") {
|
||||
GuiEvent::CameraUpdate(camera.clone(), self.camera_fov);
|
||||
for (label, camera) in &self.scene.cameras {
|
||||
if let Some(_t) = ui.tree_node(label) {
|
||||
if ui.button("Use camera") {
|
||||
self.camera = camera.clone();
|
||||
self.event =
|
||||
Some(GuiEvent::CameraUpdate(camera.clone(), self.camera_fov));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ pub struct Light {
|
||||
}
|
||||
|
||||
impl Light {
|
||||
pub fn new(position: Point3<f64>, colour: Vector3<f64>, falloff: Vector3<f64>) -> Self {
|
||||
pub fn new(position: Point3<f64>, colour: Vector3<f64>, falloff: Vector3<f64>) -> Light {
|
||||
let colour = colour.cast();
|
||||
let falloff = falloff.cast();
|
||||
Light {
|
||||
@@ -19,7 +19,7 @@ impl Light {
|
||||
ambient: false,
|
||||
}
|
||||
}
|
||||
pub fn ambient(colour: Vector3<f64>) -> Self {
|
||||
pub fn ambient(colour: Vector3<f64>) -> Light {
|
||||
Light {
|
||||
position: Point3::new(0.0, 0.0, 0.0),
|
||||
colour: colour.cast(),
|
||||
|
||||
@@ -23,7 +23,6 @@ impl Material {
|
||||
}
|
||||
pub fn magenta() -> Arc<Self> {
|
||||
let kd = Vector3::new(1.0, 0.0, 1.0);
|
||||
|
||||
let ks = Vector3::new(1.0, 0.0, 1.0);
|
||||
let shininess = 0.5;
|
||||
Arc::new(Material { kd, ks, shininess })
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::{
|
||||
scene::{Node, Scene},
|
||||
};
|
||||
use nalgebra::{Matrix4, Point3, Vector3};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone)]
|
||||
// Ray struct represents a ray in 3D space with a starting point 'a' and a direction 'b'
|
||||
@@ -43,12 +44,12 @@ impl Ray {
|
||||
}
|
||||
|
||||
// Find the closest intersection
|
||||
pub fn get_closest_intersection(&self, nodes: &Vec<Node>) -> Option<Intersection> {
|
||||
pub fn get_closest_intersection(&self, nodes: &HashMap<String, Node>) -> Option<Intersection> {
|
||||
//Assign no intersection
|
||||
let mut closest_distance = f64::MAX;
|
||||
let mut closest_intersect: Option<Intersection> = None;
|
||||
|
||||
for node in nodes {
|
||||
for (_, node) in nodes {
|
||||
// Clone arc to primitive
|
||||
let primitive = node.primitive.clone();
|
||||
// Transform ray into local model cordinates
|
||||
|
||||
@@ -19,7 +19,7 @@ pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8>
|
||||
// Compute the ambient light component and set it as base colour
|
||||
let mut colour = Vector3::zeros();
|
||||
|
||||
for light in &scene.lights {
|
||||
for (_, light) in &scene.lights {
|
||||
let Light {
|
||||
position: light_position,
|
||||
colour: light_colour,
|
||||
@@ -73,7 +73,7 @@ pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8>
|
||||
}
|
||||
|
||||
fn light_blocked(scene: &Scene, ray: Ray) -> bool {
|
||||
for node in &scene.nodes {
|
||||
for (_, node) in &scene.nodes {
|
||||
let ray = ray.transform(&node.inv_model);
|
||||
if node.primitive.intersect_bounding_box(&ray).is_some() {
|
||||
if node.primitive.intersect_ray(&ray).is_some() {
|
||||
|
||||
57
src/scene.rs
57
src/scene.rs
@@ -2,15 +2,16 @@ use crate::camera::Camera;
|
||||
use crate::light::Light;
|
||||
use crate::primitive::*;
|
||||
use nalgebra::{Matrix4, Vector3};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
#[derive(Clone)]
|
||||
pub struct Node {
|
||||
//Primitive
|
||||
pub primitive: Arc<dyn Primitive>,
|
||||
//Transformations
|
||||
pub rotation: [f32; 3],
|
||||
pub scale: [f32; 3],
|
||||
pub translation: [f32; 3],
|
||||
pub rotation: [f64; 3],
|
||||
pub scale: [f64; 3],
|
||||
pub translation: [f64; 3],
|
||||
//Model matricies
|
||||
pub model: Matrix4<f64>,
|
||||
pub inv_model: Matrix4<f64>,
|
||||
@@ -43,27 +44,27 @@ impl Node {
|
||||
let yaw = yaw.to_radians();
|
||||
|
||||
// Add the roll, pitch, and yaw to the current rotation
|
||||
self.rotation[0] += roll as f32;
|
||||
self.rotation[1] += pitch as f32;
|
||||
self.rotation[2] += yaw as f32;
|
||||
self.rotation[0] += roll;
|
||||
self.rotation[1] += pitch;
|
||||
self.rotation[2] += yaw;
|
||||
|
||||
// Recompute the model and inverse model matrices
|
||||
self.compute();
|
||||
}
|
||||
// Translate a mesh by adding to its current position
|
||||
pub fn translate(&mut self, x: f64, y: f64, z: f64) {
|
||||
self.translation[0] += x as f32;
|
||||
self.translation[1] += y as f32;
|
||||
self.translation[2] += z as f32;
|
||||
self.translation[0] += x;
|
||||
self.translation[1] += y;
|
||||
self.translation[2] += z;
|
||||
|
||||
// Recompute the model and inverse model matrices
|
||||
self.compute();
|
||||
}
|
||||
// Scale a mesh by adding to its current scale
|
||||
pub fn scale(&mut self, x: f64, y: f64, z: f64) {
|
||||
self.scale[0] += x as f32;
|
||||
self.scale[1] += y as f32;
|
||||
self.scale[2] += z as f32;
|
||||
self.scale[0] += x;
|
||||
self.scale[1] += y;
|
||||
self.scale[2] += z;
|
||||
|
||||
// Recompute the model and inverse model matrices
|
||||
self.compute();
|
||||
@@ -88,36 +89,36 @@ impl Node {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Scene {
|
||||
pub nodes: Vec<Node>,
|
||||
pub materials: Vec<Material>,
|
||||
pub lights: Vec<Light>,
|
||||
pub cameras: Vec<Camera>,
|
||||
pub nodes: HashMap<String, Node>,
|
||||
pub materials: HashMap<String, Arc<Material>>,
|
||||
pub lights: HashMap<String, Light>,
|
||||
pub cameras: HashMap<String, Camera>,
|
||||
}
|
||||
|
||||
impl Scene {
|
||||
// Creates an emptry scene
|
||||
pub fn empty() -> Self {
|
||||
Scene {
|
||||
nodes: Vec::new(),
|
||||
materials: Vec::new(),
|
||||
lights: Vec::new(),
|
||||
cameras: Vec::new(),
|
||||
nodes: HashMap::new(),
|
||||
materials: HashMap::new(),
|
||||
lights: HashMap::new(),
|
||||
cameras: HashMap::new(),
|
||||
}
|
||||
}
|
||||
// Adds a node to the scene
|
||||
pub fn add_node(&mut self, node: Node) {
|
||||
self.nodes.push(node);
|
||||
pub fn add_node(&mut self, label: String, node: Node) {
|
||||
self.nodes.insert(label, node);
|
||||
}
|
||||
// Adds a material to the scene
|
||||
pub fn add_material(&mut self, material: Material) {
|
||||
self.materials.push(material);
|
||||
pub fn add_material(&mut self, label: String, material: Arc<Material>) {
|
||||
self.materials.insert(label, material);
|
||||
}
|
||||
// Adds a light to the scene
|
||||
pub fn add_light(&mut self, light: Light) {
|
||||
self.lights.push(light);
|
||||
pub fn add_light(&mut self, label: String, light: Light) {
|
||||
self.lights.insert(label, light);
|
||||
}
|
||||
// Adds a camera to the scene
|
||||
pub fn add_camera(&mut self, camera: Camera) {
|
||||
self.cameras.push(camera);
|
||||
pub fn add_camera(&mut self, label: String, camera: Camera) {
|
||||
self.cameras.insert(label, camera);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ use crate::{gui::Gui, scene::Scene};
|
||||
use crate::{gui::GuiEvent, log_error};
|
||||
use std::path::Path;
|
||||
|
||||
use nalgebra::{Point3, Vector3};
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
|
||||
@@ -20,7 +19,7 @@ use winit::event_loop::{ControlFlow, EventLoop};
|
||||
use winit::window::{Window, WindowBuilder};
|
||||
|
||||
const START_WIDTH: i32 = 1200;
|
||||
const START_HEIGHT: i32 = 1200;
|
||||
const START_HEIGHT: i32 = 700;
|
||||
const COLOUR_CLEAR: [u8; 4] = [0x22, 0x00, 0x11, 0xff];
|
||||
const PIXEL_CLEAR: [u8; 4] = [0x55, 0x00, 0x22, 0xff];
|
||||
|
||||
@@ -46,7 +45,7 @@ impl State {
|
||||
pub fn new(window: Window, pixels: Pixels, gui: Gui) -> Self {
|
||||
let scene = Scene::empty();
|
||||
let window_size = window.inner_size();
|
||||
let camera = Camera::new(Point3::new(2.0, 2.0, 2.0), Point3::origin(), Vector3::y());
|
||||
let camera = Camera::unit();
|
||||
let rays = Vec::new();
|
||||
|
||||
Self {
|
||||
|
||||
Reference in New Issue
Block a user