Skip to content

Instantly share code, notes, and snippets.

@10maurycy10
Created December 12, 2020 01:36
Show Gist options
  • Save 10maurycy10/3dd642e4a1033cb1ee300a29bccdc7f0 to your computer and use it in GitHub Desktop.
Save 10maurycy10/3dd642e4a1033cb1ee300a29bccdc7f0 to your computer and use it in GitHub Desktop.
shading by ray matching steps
#![feature(trait_alias)]
mod line_noise {
pub use core::time::Duration;
pub extern crate nalgebra as na;
pub use na::{Vector3,Vector2};
pub use nalgebra::max;
pub use nalgebra::Rotation3;
pub use nalgebra::Isometry3;
pub use nalgebra::Point;
pub use sdl2::rect::Rect as SRect;
pub use sdl2::keyboard::PressedScancodeIterator;
pub use sdl2::keyboard::Scancode;
pub use sdl2::rect::Point as SPoint;
pub use sdl2::video::Window;
pub use sdl2::pixels::Color;
pub use sdl2::render::Canvas;
pub use sdl2::event::Event;
}
use self::line_noise::*;
type Sdfr = (f32,Vector3<f32>);
fn op_twist(p :&Vector3<f32>, apu:f32, sdf:fn(&Vector3<f32>) -> Sdfr) -> Sdfr {
sdf(&(Rotation3::new(Vector3::z() * (apu*p.z))*p))
}
fn op_rep(p :&Vector3<f32>, c: &Vector3<f32>, sdf:fn(&Vector3<f32>) -> Sdfr) -> Sdfr {
fn r(c: f32,r: f32) -> f32 {
((c+r/2.0).abs())%r-(r/2.0)
}
sdf(&Vector3::new(r(p.x,c.x),r(p.y,c.y),r(p.z,c.z)))
}
fn op_disp(p: &Vector3<f32>, disp:fn(&Vector3<f32>) -> f32, sdf:fn(&Vector3<f32>) -> Sdfr) -> Sdfr {
let s = sdf(&p);
(s.0+disp(&p),s.1)
}
fn sdf_torus(p :&Vector3<f32>, size: &Vector2<f32>) -> Sdfr {
let q: Vector2<f32> = Vector2::new(p.xz().norm()-size.x,p.y);
(q.norm()-size.y,Vector3::new(1.0,1.0,1.0))//*p)
}
fn get_dist_col(pos: &Vector3<f32>) -> (f32,Vector3<f32>) {
op_rep(
pos,
&Vector3::new(10.0,10.0,10.0),
|p| sdf_torus(
p,
&Vector2::new(2.0,1.0)
)
)
}
const SCALE: u32 = 4;
const PLAIN: f32 = 1.0;
const SKY: f32 = 30.0;
const HIT_TOLERANCE: f32 = 0.0001;
const CAMERA_SPEED: f32 = 2.0; //u per second
const GLOW_END: f32 = 0.3;
fn compute_sky_color(p: Vector3<f32>, mindist: f32) -> Vector3<f32> {
let glow_intensity: f32 = 0.0_f32.max(((GLOW_END-mindist))/GLOW_END);
Vector3::new(0.0,0.0,glow_intensity)/2.0
}
fn raymarch(dir: Vector2<f32>,is: Isometry3<f32>) -> Color {
let v = Vector3::new(dir.x,PLAIN,dir.y).normalize();
let mut pos = Point::from(Vector3::new(0.0,0.0,0.0));
let mut step_count:f32 = 1.0;
let mut mindist:f32 = 0.2;
loop {
let sp = (is*pos).coords;
let dist = get_dist_col(&sp).0;
pos += v * dist;
mindist = mindist.min(dist);
let mag = pos.coords.norm();
if mag > SKY {
let x = compute_sky_color(sp,mindist);
return Color::RGB(
(x.x*255.0) as u8,
(x.y*255.0) as u8,
(x.z*255.0) as u8
);
}
if dist < HIT_TOLERANCE {
let c = get_dist_col(&sp).1/(step_count/10.0);
return Color::RGB(
((c.x*-50.0)+127.0) as u8,
((c.y*-50.0)+127.0) as u8,
((c.z*-50.0)+127.0) as u8
);
}
step_count += 1.0;
}
}
fn draw(dest: &mut Canvas<Window>,is: Isometry3<f32>) {
let size = dest.output_size().unwrap();
let end: Vector2<f32> = Vector2::new(size.0 as f32,size.1 as f32);
let center = end/2.0;
for x in 0..(size.0/SCALE) {
for y in 0..(size.1/SCALE) {
let pos = (Vector2::new(x as f32, y as f32)-center/(SCALE as f32)).component_div(&(end/(SCALE as f32)));
dest.set_draw_color(raymarch(pos,is));
let r = SRect::new((x*SCALE) as i32,(y*SCALE) as i32,SCALE,SCALE);
dest.fill_rect(r).unwrap();
}
}
}
fn move_camera(camera: &mut Isometry3<f32>, timestep :f32, keys: PressedScancodeIterator) {
for key in keys {
let mut movement = Vector3::new(0.0,0.0,0.0);
let mut rot:f32 = 0.0;
let mut rot2:f32 = 0.0;
match key {
Scancode::W => movement.y += CAMERA_SPEED,
Scancode::S => movement.y -= CAMERA_SPEED,
Scancode::A => movement.x -= CAMERA_SPEED,
Scancode::D => movement.x += CAMERA_SPEED,
Scancode::K => rot2 += 0.3,
Scancode::I => rot2 -= 0.3,
Scancode::J => rot += 0.3,
Scancode::L => rot -= 0.3,
_ => (),
}
*camera = *camera*Isometry3::new(
movement*timestep,
Vector3::new(rot2, 0.0 , rot)*timestep
)
}
}
fn main() {
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let mut timer = sdl_context.timer().unwrap();
let window = video_subsystem.window("sdf", 900, 900)
.position_centered()
.build()
.unwrap();
let mut event_pump = sdl_context.event_pump().unwrap();
let mut canvas = window.into_canvas() //make software renderer
.software()
.build()
.unwrap();
let mut is = Isometry3::new(
Vector3::new(0.0,-10.0,0.0),
Vector3::new(0.5,0.0,-0.4)
);
let mut last_start_time = timer.ticks();
'running: loop {
let change = timer.ticks() - last_start_time;
last_start_time = timer.ticks();
canvas.set_draw_color(Color::RGB(255,255,255));
canvas.clear();
for event in event_pump.poll_iter() {
match event {
Event::Quit {timestamp: _} => {
break 'running
},
_ => {}
}
}
move_camera(&mut is,(change as f32)/1000.0,event_pump.keyboard_state().pressed_scancodes());
draw(&mut canvas,is);
canvas.present();
//std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment