From 35456c299b91a8765422e184895e45377fd439b4 Mon Sep 17 00:00:00 2001 From: pommicket Date: Sun, 11 Dec 2022 19:21:19 -0500 Subject: rotation , but it looks weird --- Cargo.lock | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/main.rs | 132 +++++++++++++++++++++++++++++++++++++++++-- src/sdf.rs | 82 +++++++++++++++++++++++++++ src/win.rs | 78 +++++++++++++++++++++++++- 5 files changed, 468 insertions(+), 7 deletions(-) create mode 100644 src/sdf.rs diff --git a/Cargo.lock b/Cargo.lock index 2f5d73f..ad36445 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,13 +2,35 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "autosdf" version = "0.1.0" dependencies = [ "gl", + "nalgebra", ] +[[package]] +name = "bytemuck" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f" + [[package]] name = "cfg-if" version = "1.0.0" @@ -50,6 +72,166 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "matrixmultiply" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add85d4dd35074e6fedc608f8c8f513a3548619a9024b751949ef0e8e45a4d84" +dependencies = [ + "rawpointer", +] + +[[package]] +name = "nalgebra" +version = "0.31.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20bd243ab3dbb395b39ee730402d2e5405e448c75133ec49cc977762c4cba3d1" +dependencies = [ + "approx", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01fcc0b8149b4632adc89ac3b7b31a12fb6099a0317a4eb2ebff574ef7de7218" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-complex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "paste" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" + +[[package]] +name = "proc-macro2" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "safe_arch" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "794821e4ccb0d9f979512f9c1973480123f9bd62a90d74ab0f9426fcf8f4a529" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "simba" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f3fd720c48c53cace224ae62bef1bbff363a70c68c4802a78b5cc6159618176" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + +[[package]] +name = "syn" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "wide" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae41ecad2489a1655c8ef8489444b0b113c0a0c795944a3572a0931cf7d2525c" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "xml-rs" version = "0.8.4" diff --git a/Cargo.toml b/Cargo.toml index e351af7..afac22e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,4 @@ edition = "2021" [dependencies] gl = "0.14.0" +nalgebra = "0.31.4" diff --git a/src/main.rs b/src/main.rs index fdd2f54..dc29e2b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,134 @@ +extern crate nalgebra; + mod sdl; pub mod win; +pub mod sdf; + +use nalgebra::{Vector3, Matrix3, Rotation3}; +type Vec3 = Vector3; +type Mat3 = Matrix3; +type Rot3 = Rotation3; + +struct View { + pos: Vec3, + yaw: f32, + pitch: f32 +} + +impl Default for View { + fn default() -> Self { + Self { + pos: Vec3::zeros(), + yaw: 0.0, + pitch: 0.0 + } + } +} + +impl View { + /// `camera_rotation() * vec3(0, 0, -1)` is the direction the camera is pointing + fn camera_rotation(&self) -> Mat3 { + *Rot3::from_euler_angles(self.pitch, self.yaw, 0.0).matrix() + } +} + fn try_main() -> Result<(), String> { + let my_sdf = sdf::Sdf::sphere(); + let mut window = win::Window::new("AutoSDF", 1280, 720, true) .map_err(|e| format!("Error creating window: {e}"))?; + let mut fshader_source = String::new(); + fshader_source.push_str(" +IN vec2 pos; +uniform vec3 u_camera_position; +uniform mat3 u_camera_rotation; +"); + my_sdf.to_glsl(&mut fshader_source); + fshader_source.push_str(" +#define ITERATIONS 30 +#define AA_X 2 +#define AA_Y 2 + + + +float fbm(vec3 p) { + float t = 0.0; + float freq = 24.0; + mat3 m = mat3(cos(1.),sin(1.),0, + -sin(1.),cos(1.),0, + 0, 0, 1) * mat3( + 1, 0, 0, + 0, cos(1.),sin(1.), + 0, -sin(1.),cos(1.) + ); + for(int i = 0; i < 5; i++) + { + p = m * p; + t += pow(0.6, float(i)) * sin(freq*p.x)*sin(freq*p.y)*sin(freq*p.z); + freq *= 2.0; + } + return t; +} + +vec3 normal(vec3 p) +{ +// thanks to https://iquilezles.org/articles/normalsSDF/ + float h = 0.0001; + vec2 k = vec2(1.,-1.); + vec3 sdf_normal = k.xyy*sdf(p + k.xyy*h) + + k.yyx*sdf(p + k.yyx*h) + + k.yxy*sdf(p + k.yxy*h) + + k.xxx*sdf(p + k.xxx*h); + vec3 noise_normal = k.xyy*fbm(p + k.xyy*h) + + k.yyx*fbm(p + k.yyx*h) + + k.yxy*fbm(p + k.yxy*h) + + k.xxx*fbm(p + k.xxx*h); + return normalize(sdf_normal + 0.003 * noise_normal); +} + +void main() { + float focal_length = 0.3; + float min_dist = 10.; + vec2 inv_screen_size = 1.0 / vec2(1280.0, 720.0); // @TODO + vec2 aa_delta = inv_screen_size / vec2(AA_X, AA_Y); + vec3 final_color = vec3(0); + for (int m = 0; m < AA_X; m++) { + for (int n = 0; n < AA_Y; n++) { + vec3 p = u_camera_position; + vec2 aa_offset = vec2(float(m), float(n)) * aa_delta; + vec3 delta = normalize(u_camera_rotation * vec3(pos + aa_offset, -focal_length)); + int i; + for (i = 0; i < ITERATIONS; i++) { + float dist = sdf(p); + min_dist = min(min_dist, dist); + if (dist <= 0.01) { + float L = 0.3 + max(0., dot(normal(p), normalize(vec3(.8,1,.6)))); + final_color += L * vec3(1.0, 0.0, 0.0); + + break; + } + p += dist * delta; + } + } + } + final_color *= 1.0 / (AA_X * AA_Y); + o_color = vec4(final_color, 1.0); +}"); + + println!("{fshader_source}"); + let program = window.create_program( "attribute vec2 v_pos; + OUT vec2 pos; + uniform float u_aspect_ratio; + void main() { + pos = v_pos * vec2(u_aspect_ratio, 1.0); gl_Position = vec4(v_pos, 0.0, 1.0); }", - "void main() { - o_color = vec4(1.0, 0.0, 0.0, 1.0); - }" + &fshader_source ).map_err(|e| format!("Error compiling shader:\n{e}"))?; let mut buffer = window.create_buffer(); @@ -28,6 +144,8 @@ fn try_main() -> Result<(), String> { let mut array = window.create_vertex_array(buffer, &program); window.array_attrib2f(&mut array, "v_pos", 0); + let mut view = View::default(); + 'mainloop: loop { while let Some(event) = window.next_event() { use win::Event::*; @@ -35,11 +153,17 @@ fn try_main() -> Result<(), String> { Quit => break 'mainloop, _ => {}, } - println!("{event:?}"); } + window.viewport_full_screen(); + + view.yaw += 0.002; + window.clear_screen(win::ColorF32::BLACK); window.use_program(&program); + window.uniform1f("u_aspect_ratio", window.aspect_ratio()); + window.uniform3f("u_camera_position", view.pos.x, view.pos.y, view.pos.z); + window.uniform3x3f("u_camera_rotation", view.camera_rotation().as_slice()); window.draw_array(&array); diff --git a/src/sdf.rs b/src/sdf.rs new file mode 100644 index 0000000..51d85cc --- /dev/null +++ b/src/sdf.rs @@ -0,0 +1,82 @@ +#![allow(dead_code)] // @TODO @TEMPORARY + +use std::fmt::Write; + +// we're only writing numbers and strings so write! should never fail. +macro_rules! write_str { + ($( $arg:tt )*) => { write!($($arg)*).unwrap() } +} + +enum R3ToR3 { + Identity, + Translate([f32; 3]) +} + +enum RToR { + Identity, + Add(f32) +} + +pub struct Sdf { + pre: R3ToR3, + post: RToR +} + +impl RToR { + /// treats `v<*initial value of var_idx>` as the input, and puts the output in `v`. + fn to_glsl(&self, code: &mut String, var_idx: &mut u32) { + use RToR::*; + let input = *var_idx; + + match self { + Identity => {}, // no code + Add(x) => { + *var_idx += 1; + let output = *var_idx; + write_str!(code, "float v{output} = v{input} + {x};\n"); + } + } + } +} + +impl R3ToR3 { + /// treats `v<*initial value of var_idx>` as the input, and puts the output in `v`. + fn to_glsl(&self, code: &mut String, var_idx: &mut u32) { + use R3ToR3::*; + let input = *var_idx; + + match self { + Identity => {}, // no code + Translate([x, y, z]) => { + *var_idx += 1; + let output = *var_idx; + write_str!(code, "vec3 v{output} = v{input} + vec3({x}, {y}, {z});\n"); + }, + } + } +} + +impl Sdf { + /// test sphere + pub fn sphere() -> Self { + Self { + pre: R3ToR3::Identity, + post: RToR::Identity + } + } + + /// appends some glsl code including a function `float sdf(vec3 p) { ... }` + pub fn to_glsl(&self, code: &mut String) { + code.push_str("float sdf(vec3 p) {\n"); + // don't start out right next to the origin, since weird stuff might be happening there + let origin_dist: f32 = 2.0; + write_str!(code, "vec3 v0 = p - vec3(0,0,-{}.);\n", origin_dist); + let mut var_idx = 0; + self.pre.to_glsl(code, &mut var_idx); + write_str!(code, "float v{} = length(v{}) - 1.0;\n", var_idx + 1, var_idx); + var_idx += 1; + self.post.to_glsl(code, &mut var_idx); + write_str!(code, "return v{var_idx};\n"); + code.push('}'); + } +} diff --git a/src/win.rs b/src/win.rs index 781156d..65437d8 100644 --- a/src/win.rs +++ b/src/win.rs @@ -664,16 +664,26 @@ impl Window { self.array_attribnf(array, 4, name, offset) } - pub fn size(&mut self) -> (i32, i32) { + pub fn size(&self) -> (i32, i32) { let mut x = 0; let mut y = 0; unsafe { sdl::get_window_size(self.sdlwin, &mut x, &mut y) }; (x, y) } + + pub fn aspect_ratio(&self) -> f32 { + let (w, h) = self.size(); + return w as f32 / h as f32; + } pub fn viewport(&mut self, x: i32, y: i32, w: i32, h: i32) { unsafe { gl::Viewport(x, y, w, h) }; } + + pub fn viewport_full_screen(&mut self) { + let (w, h) = self.size(); + self.viewport(0, 0, w, h); + } pub fn next_event(&mut self) -> Option { loop { @@ -831,13 +841,75 @@ impl Window { } } - pub fn uniform_texture(&mut self, name: &str, slot: u32) { + pub fn uniform1i(&mut self, name: &str, x: i32) { + let loc = self.get_uniform_location(name).unwrap_or(-1); + unsafe { + gl::Uniform1i(loc, x); + } + } + + pub fn uniform2i(&mut self, name: &str, x: i32, y: i32) { + let loc = self.get_uniform_location(name).unwrap_or(-1); + unsafe { + gl::Uniform2i(loc, x, y); + } + } + + pub fn uniform3i(&mut self, name: &str, x: i32, y: i32, z: i32) { + let loc = self.get_uniform_location(name).unwrap_or(-1); + unsafe { + gl::Uniform3i(loc, x, y, z); + } + } + + pub fn uniform4i(&mut self, name: &str, x: i32, y: i32, z: i32, w: i32) { + let loc = self.get_uniform_location(name).unwrap_or(-1); + unsafe { + gl::Uniform4i(loc, x, y, z, w); + } + } + + pub fn uniform1f(&mut self, name: &str, x: f32) { let loc = self.get_uniform_location(name).unwrap_or(-1); unsafe { - gl::Uniform1i(loc, slot as i32); + gl::Uniform1f(loc, x); } } + pub fn uniform2f(&mut self, name: &str, x: f32, y: f32) { + let loc = self.get_uniform_location(name).unwrap_or(-1); + unsafe { + gl::Uniform2f(loc, x, y); + } + } + + pub fn uniform3f(&mut self, name: &str, x: f32, y: f32, z: f32) { + let loc = self.get_uniform_location(name).unwrap_or(-1); + unsafe { + gl::Uniform3f(loc, x, y, z); + } + } + + pub fn uniform4f(&mut self, name: &str, x: f32, y: f32, z: f32, w: f32) { + let loc = self.get_uniform_location(name).unwrap_or(-1); + unsafe { + gl::Uniform4f(loc, x, y, z, w); + } + } + + pub fn uniform3x3f(&mut self, name: &str, matrix: &[f32]) { + assert_eq!(matrix.len(), 9); + let loc = self.get_uniform_location(name).unwrap_or(-1); + unsafe { + gl::UniformMatrix3fv(loc, 1, 0, matrix.as_ptr()); + } + } + + + pub fn uniform_texture(&mut self, name: &str, slot: u32) { + self.uniform1i(name, slot as i32); + } + pub fn draw_array(&mut self, array: &VertexArray) { array.draw(); } -- cgit v1.2.3