From 97ece7a823393b9a4ed39c5e400026be8c77dd03 Mon Sep 17 00:00:00 2001 From: Piotrek Date: Sat, 24 Apr 2021 17:06:44 +0200 Subject: [PATCH] materials, brick and nodes structure, preparing for world generation --- src/app/mod.rs | 49 +++++++++++- src/app/world_gen.rs | 16 ++++ src/main.rs | 3 +- src/renderer/buffers/brick_buffer.rs | 69 ++++++----------- src/renderer/buffers/material_buffer.rs | 74 ++++++++++++++++++ src/renderer/buffers/mod.rs | 18 ++++- src/renderer/buffers/node_buffer.rs | 46 ++--------- src/renderer/mod.rs | 99 ++++++++++++++++++++---- src/shaders/bin/shader.frag.spv | Bin 10240 -> 10648 bytes src/shaders/raycasting.cginc | 36 ++------- src/shaders/raymarching.cginc | 91 ---------------------- src/shaders/shader.frag | 35 +++++---- src/shaders/shading.cginc | 19 +++++ 13 files changed, 311 insertions(+), 244 deletions(-) create mode 100644 src/app/world_gen.rs create mode 100644 src/renderer/buffers/material_buffer.rs delete mode 100644 src/shaders/raymarching.cginc create mode 100644 src/shaders/shading.cginc diff --git a/src/app/mod.rs b/src/app/mod.rs index 633d2d2..c284826 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -5,19 +5,62 @@ use winit::{ use std::sync::Arc; mod camera_controller; use camera_controller::CameraController; +mod world_gen; use world_gen::WorldGen; use crate::renderer::Renderer; - +//use crate::renderer::BrickData; pub struct App { pub window: Window, pub renderer: Renderer, + world_gen: WorldGen, camera_controller: CameraController, } impl App { - pub fn new(window: Window, renderer: Renderer) -> Self { + pub fn new(window: Window) -> Self { + let mut renderer = futures::executor::block_on(Renderer::new(&window)); let camera_controller = CameraController::new(); - Self { window, renderer, camera_controller } + let mut world_gen = WorldGen::new(); + + + // let start = std::time::Instant::now(); + // for x in 0..128 { + // for z in 0..128 { + // // Dirt + // for y in 0..31 { + // renderer.set_voxel(x, y, z, 1); + // } + // // Grass + // renderer.set_voxel(x, 31, z, 2); + // } + // } + // println!("Generated in {}ms", start.elapsed().as_millis()); + + + let start = std::time::Instant::now(); + for bx in 0..4 { + for bz in 0..4 { + + let brick_id = renderer.brick_get_id(bx, 0, bz); + renderer.brick_mark_changed(brick_id); + for x in 0..32 { + for z in 0..32 { + // Dirt + for y in 0..31 { + renderer.brick_set_voxel(brick_id, x, y, z, 1); + } + // Grass + renderer.brick_set_voxel(brick_id, x, 31, z, 2); + } + } + + } + } + println!("Generated in {}ms", start.elapsed().as_millis()); + + + + Self { window, renderer, camera_controller, world_gen } } pub fn input(&mut self, event: Arc>) { diff --git a/src/app/world_gen.rs b/src/app/world_gen.rs new file mode 100644 index 0000000..9b147a2 --- /dev/null +++ b/src/app/world_gen.rs @@ -0,0 +1,16 @@ +use std::sync::Arc; +use crate::renderer::Renderer; + +pub struct WorldGen { + +} + +impl WorldGen { + + pub fn new() -> Self { + Self{} + } + + pub fn generate(&mut self, renderer: Renderer) { + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 2ace7f5..7c22c4f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,8 +20,7 @@ fn main() { .with_inner_size(LogicalSize::new(1280.0, 720.0)) .build(&events) .expect("Failed to create window"); - let _renderer = futures::executor::block_on(Renderer::new(&_window)); - let mut app = App::new(_window, _renderer); + let mut app = App::new(_window); // Stats let mut fps_timer = std::time::Instant::now(); diff --git a/src/renderer/buffers/brick_buffer.rs b/src/renderer/buffers/brick_buffer.rs index 202fe6a..bdba9ea 100644 --- a/src/renderer/buffers/brick_buffer.rs +++ b/src/renderer/buffers/brick_buffer.rs @@ -1,42 +1,22 @@ -use wgpu::util::DeviceExt; use std::convert::TryInto; -use rand::prelude::*; -const BRICK_SIZE : usize = 32; // 32x32x32 brick size -const BRICK_NUM : usize = 10000; // x bricks in texture - -const BRICK_LEN : usize = BRICK_SIZE*BRICK_SIZE*BRICK_SIZE; +use crate::renderer::buffers::{BRICK_SIZE, BRICK_NUM, BRICK_LEN}; const DATA_LEN : usize = BRICK_LEN * BRICK_NUM; -struct BrickData { - pub data: Box<[u8]> -} - -impl BrickData { - - pub fn new() -> Self { - let data = vec![0_u8; DATA_LEN].into_boxed_slice(); - Self { data } - } - - pub fn set(&mut self, brick: usize, x: usize, y: usize, z: usize, value: u8) - { - let local_idx = x + BRICK_SIZE * (y + BRICK_SIZE * z); - let offset = brick * BRICK_LEN; - self.data[offset + local_idx] = value; - } -} - pub struct BrickBuffer { - bricks: BrickData, + pub bricks: Box<[u8]>, + pub free_brick: usize, texture: wgpu::Texture, - size: wgpu::Extent3d, pub bind_layout: wgpu::BindGroupLayout, pub bind_group: wgpu::BindGroup } impl BrickBuffer { + + /* + * Create buffer in memory and gpu + */ pub fn new(device: &wgpu::Device) -> Self { // Create texture @@ -93,36 +73,24 @@ impl BrickBuffer { ); // Data - let mut bricks = BrickData::new(); + let mut bricks = vec![0_u8; DATA_LEN].into_boxed_slice(); + bricks[0] = 1; println!("Brick buffer size: {} MB", DATA_LEN as f32 / 1024.0 / 1024.0); - let mut rng = rand::thread_rng(); - for x in 0..32 { - for y in 0..32 { - for z in 0..32 { - let value = if rng.gen::()> 0.99 { 1 } else { 0 }; - bricks.set(0, x, y, z, value); - bricks.set(1, x, 0, z, 1); - } - } - } - bricks.set(1, 20, 5, 16, 1); - // Done - Self { bricks, texture, size, bind_layout, bind_group } + Self { bricks, texture, bind_layout, bind_group, free_brick: 0 } } /* Write brick data to gpu, should be called to apply changes offset: Brick index to copy */ - pub fn write(&mut self, queue: &wgpu::Queue, offset: usize) - { + pub fn write(&mut self, queue: &wgpu::Queue, brick: usize) { // Get first brick - let brick_offset = offset*BRICK_LEN; - let brick_bytes : [u8;BRICK_LEN] = self.bricks.data[brick_offset..brick_offset+BRICK_LEN].try_into().unwrap(); + let brick_offset = brick*BRICK_LEN; + let brick_bytes : [u8;BRICK_LEN] = self.bricks[brick_offset..brick_offset+BRICK_LEN].try_into().unwrap(); let brick_size = wgpu::Extent3d{ width: BRICK_SIZE as u32, height: BRICK_SIZE as u32, depth: BRICK_SIZE as u32 }; - let brick_origin = wgpu::Origin3d{ x:0, y:0, z: (offset*BRICK_SIZE) as u32 }; + let brick_origin = wgpu::Origin3d{ x:0, y:0, z: (brick*BRICK_SIZE) as u32 }; // Write queue.write_texture( @@ -132,4 +100,13 @@ impl BrickBuffer { brick_size ); } + + pub fn next_brick(&mut self) -> usize { + if self.free_brick >= self.bricks.len() { + panic!("No more free bricks! we should consider reusing bricks..."); + } + + self.free_brick += 1; + self.free_brick + } } \ No newline at end of file diff --git a/src/renderer/buffers/material_buffer.rs b/src/renderer/buffers/material_buffer.rs new file mode 100644 index 0000000..dee9124 --- /dev/null +++ b/src/renderer/buffers/material_buffer.rs @@ -0,0 +1,74 @@ +use wgpu::util::DeviceExt; + + +#[repr(C)] +#[derive(Default, Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +struct Material { + pub albedo: [f32; 4], +} + +impl Material { + pub fn set_albedo(&mut self, r: f32, g: f32, b:f32) + { + self.albedo[0] = r; + self.albedo[1] = g; + self.albedo[2] = b; + } +} + + +pub struct MaterialBuffer { + materials: [Material; 256], + pub buffer: wgpu::Buffer, + pub bind_layout: wgpu::BindGroupLayout, + pub bind_group: wgpu::BindGroup +} + +impl MaterialBuffer { + + pub fn new(device: &wgpu::Device) -> Self { + // Create values + let mut materials: [Material; 256] = [Default::default(); 256]; + materials[0].set_albedo(0.41,0.33,0.20); + materials[1].set_albedo(0.49,0.74,0.00); + + // Create buffer + let buffer = device.create_buffer_init( + &wgpu::util::BufferInitDescriptor { + label: Some("Materials buffer"), + contents: bytemuck::cast_slice(&materials), + usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + } + ); + + // Create bind group + let bind_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + } + ], + label: Some("Materials buffer layout"), + }); + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &bind_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: buffer.as_entire_binding(), + } + ], + label: Some("Materials buffer group"), + }); + + // Done + MaterialBuffer { buffer, materials, bind_layout, bind_group } + } +} \ No newline at end of file diff --git a/src/renderer/buffers/mod.rs b/src/renderer/buffers/mod.rs index 48992e7..9bf5c1e 100644 --- a/src/renderer/buffers/mod.rs +++ b/src/renderer/buffers/mod.rs @@ -1,9 +1,20 @@ +// Consts + +pub const WORLD_SIZE: usize = 32; +pub const NUM_NODES: usize = (WORLD_SIZE*WORLD_SIZE*WORLD_SIZE) as usize; + +pub const BRICK_SIZE : usize = 32; // 32x32x32 brick size +pub const BRICK_NUM : usize = 32768; // max bricks in texture +pub const BRICK_LEN : usize = BRICK_SIZE*BRICK_SIZE*BRICK_SIZE; + +// Import names + mod node_buffer; pub use node_buffer::NodeBuffer; mod brick_buffer; -pub use brick_buffer::BrickBuffer; +pub use brick_buffer::{BrickBuffer}; mod uniform_buffer; pub use uniform_buffer::UniformBuffer; @@ -11,4 +22,7 @@ pub use uniform_buffer::UniformValues; mod raster_buffer; pub use raster_buffer::RasterBuffer; -pub use raster_buffer::Vertex; \ No newline at end of file +pub use raster_buffer::Vertex; + +mod material_buffer; +pub use material_buffer::MaterialBuffer; \ No newline at end of file diff --git a/src/renderer/buffers/node_buffer.rs b/src/renderer/buffers/node_buffer.rs index e4249d2..11a415e 100644 --- a/src/renderer/buffers/node_buffer.rs +++ b/src/renderer/buffers/node_buffer.rs @@ -1,31 +1,10 @@ use byteorder::{ByteOrder, LittleEndian}; use rand::prelude::*; -// 4x4x4 nodes -const WORLD_SIZE: usize = 32; -const NUM_NODES: usize = (WORLD_SIZE*WORLD_SIZE*WORLD_SIZE) as usize; - -struct NodeData { - pub data: Box<[u32]> -} - -impl NodeData { - - pub fn new() -> Self { - let data = vec![0_u32; NUM_NODES].into_boxed_slice(); - Self { data } - } - - pub fn set(&mut self, x: usize, y: usize, z: usize, value: u32) - { - let idx = x + WORLD_SIZE * (y + WORLD_SIZE * z); - self.data[idx] = value; - } -} - +use crate::renderer::buffers::{WORLD_SIZE, NUM_NODES}; pub struct NodeBuffer { - nodes: NodeData, + pub nodes: Box<[u32]>, texture: wgpu::Texture, size: wgpu::Extent3d, pub bind_layout: wgpu::BindGroupLayout, @@ -90,23 +69,8 @@ impl NodeBuffer { ); // Data - let mut nodes = NodeData::new(); - - // let mut rng = rand::thread_rng(); - // for x in 0..WORLD_SIZE { - // for y in 0..WORLD_SIZE { - // for z in 0..WORLD_SIZE { - // let value = if rng.gen::()> 0.5 { 1 } else { 0 }; - // nodes.set(x, y, z, value); - // } - // } - // } - for i in 0..WORLD_SIZE { - nodes.set(i, 0, 0, 1); - nodes.set(0, i, 0, 1); - nodes.set(0, 0, i, 1); - } - nodes.set(0, 0, 0, 2); + let nodes = vec![0_u32; NUM_NODES].into_boxed_slice(); + println!("Node buffer size: {} MB", nodes.len() as f32 * 4.0 / 1024.0 / 1024.0); // Done Self { nodes, texture, size, bind_layout, bind_group } @@ -115,7 +79,7 @@ impl NodeBuffer { pub fn write(&mut self, queue: &wgpu::Queue) { // Convert 32 bit values to 8 bit let mut bytes = [0_u8; NUM_NODES*4]; - LittleEndian::write_u32_into(&self.nodes.data, &mut bytes); + LittleEndian::write_u32_into(&self.nodes, &mut bytes); // Write queue.write_texture( diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 6710d35..fb26e3b 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1,6 +1,8 @@ use winit::{window::Window, dpi::PhysicalSize}; -mod buffers; use buffers::{NodeBuffer, BrickBuffer, UniformBuffer, RasterBuffer, Vertex}; +mod buffers; +use buffers::{NodeBuffer, BrickBuffer, UniformBuffer, RasterBuffer, Vertex, MaterialBuffer}; + pub mod camera; use camera::Camera; @@ -16,9 +18,11 @@ pub struct Renderer { uniform_buffer: UniformBuffer, node_buffer: NodeBuffer, brick_buffer: BrickBuffer, + material_buffer: MaterialBuffer, // Other pub camera: Camera, - start: std::time::Instant + start: std::time::Instant, + changed_bricks: Vec, } impl Renderer { @@ -82,6 +86,9 @@ impl Renderer { }) } + /* + * Initializes renderer and all buffers + */ pub async fn new(window: &Window) -> Self { // Create surface and pick device @@ -107,24 +114,29 @@ impl Renderer { // Buffers let uniform_buffer = UniformBuffer::new(&device); let raster_buffer = RasterBuffer::new(&device); - - let mut node_buffer = NodeBuffer::new(&device); - node_buffer.write(&queue); - - let mut brick_buffer = BrickBuffer::new(&device); - brick_buffer.write(&queue, 0); - brick_buffer.write(&queue, 1); + let node_buffer = NodeBuffer::new(&device); + let brick_buffer = BrickBuffer::new(&device); + let material_buffer = MaterialBuffer::new(&device); // Pipeline - let pipeline = Self::create_pipeline(&device, &swapchain_desc, &[&uniform_buffer.bind_layout, &node_buffer.bind_layout, &brick_buffer.bind_layout]); - - let start = std::time::Instant::now(); + let bind_layouts = [ + &uniform_buffer.bind_layout, + &node_buffer.bind_layout, + &brick_buffer.bind_layout, + &material_buffer.bind_layout + ]; + let pipeline = Self::create_pipeline(&device, &swapchain_desc, &bind_layouts); // Save values in app println!("Initialized"); - Self { surface, device, queue, swapchain_desc, swapchain, pipeline, raster_buffer, uniform_buffer, node_buffer, brick_buffer, camera, start } + let start = std::time::Instant::now(); + let changed_bricks: Vec = Vec::new(); + Self { surface, device, queue, swapchain_desc, swapchain, pipeline, raster_buffer, uniform_buffer, node_buffer, brick_buffer, material_buffer, camera, start, changed_bricks } } + /* + * Recreates swapchain with new resolution + */ pub fn resize(&mut self, new_size: Option>) { if let Some(size) = new_size { // Minimized or manually resized to 0 @@ -139,12 +151,24 @@ impl Renderer { self.swapchain = self.device.create_swap_chain(&self.surface, &self.swapchain_desc); } + /* + * Actually renders the frame + */ pub fn render(&mut self) -> Result<(), wgpu::SwapChainError> { // Update uniform buffer self.uniform_buffer.values.update(&self.camera, self.start.elapsed().as_secs_f32()); self.queue.write_buffer(&self.uniform_buffer.buffer, 0, bytemuck::cast_slice(&[self.uniform_buffer.values])); + // Update changed nodes + if self.changed_bricks.len() > 0 { + self.node_buffer.write(&self.queue); + for node in &self.changed_bricks { + self.brick_buffer.write(&self.queue, *node); + } + self.changed_bricks.clear(); + } + // Get next frame to render to let frame = self.swapchain.get_current_frame()?.output; @@ -171,6 +195,7 @@ impl Renderer { render_pass.set_bind_group(0, &self.uniform_buffer.bind_group, &[]); render_pass.set_bind_group(1, &self.node_buffer.bind_group, &[]); render_pass.set_bind_group(2, &self.brick_buffer.bind_group, &[]); + render_pass.set_bind_group(3, &self.material_buffer.bind_group, &[]); // Vertices and indices render_pass.set_vertex_buffer(0, self.raster_buffer.vertex_buffer.slice(..)); render_pass.set_index_buffer(self.raster_buffer.index_buffer.slice(..), wgpu::IndexFormat::Uint16); @@ -183,4 +208,52 @@ impl Renderer { // Return ok Ok(()) } + + /* + * Create or update brick at given location + */ + #[allow(dead_code)] + pub fn set_voxel(&mut self, x: usize, y: usize, z:usize, value: u8) + { + let brick_id = self.brick_get_id(x/32, y/32, z/32 ); + self.brick_set_voxel(brick_id, x%32, y%32, z%32, value); + self.brick_mark_changed(brick_id); + } + + /* + * Create or update brick at given location + */ + pub fn brick_set_voxel(&mut self, brick_id:usize, x: usize, y: usize, z:usize, value: u8) + { + let voxel_id = x + buffers::BRICK_SIZE * (y + buffers::BRICK_SIZE * z); + let brick_offset = brick_id * buffers::BRICK_LEN; + self.brick_buffer.bricks[brick_offset + voxel_id] = value; + } + + /* + * Gets brick id + */ + pub fn brick_get_id(&mut self, x: usize, y: usize, z:usize) -> usize { + // Get node + let node_idx = x + buffers::WORLD_SIZE * (y + buffers::WORLD_SIZE * z); + let mut node_value = self.node_buffer.nodes[node_idx]; + + // Use new brick if neccesary + if node_value == 0 { + node_value = self.brick_buffer.next_brick() as u32; + self.node_buffer.nodes[node_idx] = node_value; + } + + // Get brick id from node value + (node_value - 1) as usize + } + + /* + * Marks brick as changed + */ + pub fn brick_mark_changed(&mut self, brick_id:usize) { + if !self.changed_bricks.contains(&brick_id) { + self.changed_bricks.push(brick_id); + } + } } \ No newline at end of file diff --git a/src/shaders/bin/shader.frag.spv b/src/shaders/bin/shader.frag.spv index 1889b6392e1e05d46c2ad90db28bd4e2d2449b15..608d6e37826e220d387ffae9bfbce11676e3a679 100644 GIT binary patch literal 10648 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 31 || pos.y > 31 || pos.z > 31) { break; } } - return vec4(0.5,0.5,0.5, 0.0); + return vec4(1.0,0.0,0.5,0.0); } /* @@ -93,16 +72,13 @@ vec3 castNodes(vec3 origin, vec3 dir) for(int i=0;i<110;i++) { // Get node - uint node = texelFetch(nodesTexture, ivec3(pos), 0).r; + uint node = texelFetch(_NodesTexture, ivec3(pos), 0).r; if(node != 0) { // Hit point vec3 mini = (pos-origin+0.5 - raySign*0.5) * rayInv; float len = max(0.0, max(mini.x, max(mini.y, mini.z))); vec3 hitPoint = origin + dir * len; - // Normal vector (negate previous increment axis and mult by sign) - //vec3 normal = -incAxis * raySign; - //return solve(hitPoint, dir, normal); // Cast brick vec4 result = castBricks(pos, hitPoint, dir, incAxis, node); diff --git a/src/shaders/raymarching.cginc b/src/shaders/raymarching.cginc deleted file mode 100644 index c853868..0000000 --- a/src/shaders/raymarching.cginc +++ /dev/null @@ -1,91 +0,0 @@ - -// Returns nearest distance to and object id from given point -vec2 map(in vec3 pos) -{ - vec2 d1 = vec2(sdPlane(pos), 1); - vec2 d2 = vec2(sdSphere(pos - vec3(0.0, 2.0, 5.0)), 2); - vec2 d3 = vec2(sdSphere(pos - vec3(0.0, 3.0, 3.0)), 3); - return sdUnion(sdUnion(d1, d2), d3); -} - -// Returns distance to and object id that has been intersected by ray -vec2 intersect(in vec3 ro, in vec3 rd) -{ - float depth = NEAR; - for(int i=0;i 0.0) - { - // Calculate intersection point, normal vector and reflection vector - vec3 pos = ro + rd * result.x; - vec3 nor = estimateNormal(pos); - vec3 ref = reflect(rd, nor); - - // Light - vec3 light = vec3(1); - - float dif = clamp( dot( nor, ld ), 0.0, 1.0 ); - light += 2.20*dif*vec3(1.30,1.00,0.70); - - vec3 hal = normalize( ld-rd ); - float spe = pow( clamp( dot( nor, hal ), 0.0, 1.0 ),16.0); - spe *= dif; - spe *= 0.04+0.96*pow(clamp(1.0-dot(hal,ld),0.0,1.0),5.0); - light += 5.00*spe*vec3(1.30,1.00,0.70); - - //float diffuse = max(dot(norm, -ld), 0); - //color *= diffuse; - - //vec3 ldr = normalize(reflect(-ld, norm)); - //float specular = max(dot(ldr, rd), 0.0); - //specular = pow(specular, 3); - //color += vec3(0.2) * specular; - - //float scatter = pow(1.0-dot(rd, -norm), 2); - - // Calculate color - vec3 color = vec3(0); - if(result.y == 1) color = vec3(0.0, 0.1, 0.01); - else if(result.y == 2) color = vec3(0.5, 0.7, 0.05); - else if(result.y == 3) color = vec3(0.0, 0.2, 0.7); - - // Return - color *= light; - return color; - } - else - { - return vec3(0); - } -} \ No newline at end of file diff --git a/src/shaders/shader.frag b/src/shaders/shader.frag index 553360b..a805a26 100644 --- a/src/shaders/shader.frag +++ b/src/shaders/shader.frag @@ -1,38 +1,41 @@ // shader.frag #version 450 +struct Material { + vec4 albedo; +}; + // Variables layout(location=0) in vec2 vert_uv; layout(location=0) out vec4 out_color; -layout(set=0, binding=0) uniform Uniforms -{ - mat4 _viewMatrix; - mat4 _projMatrixInv; +layout(set=0,binding=0) uniform Uniforms { + mat4 _ViewMatrix; + mat4 _ProjMatrixInv; vec3 _CamPos; float _Time; }; - -//layout(set = 1, binding = 0) uniform texture3D node_tex; -//layout(set = 1, binding = 1) uniform usampler3D node_sampl; -layout(set=1,binding=0) uniform usampler3D nodesTexture; -layout(set=2,binding=0) uniform usampler3D bricksTexture; +layout(set=1,binding=0) uniform usampler3D _NodesTexture; +layout(set=2,binding=0) uniform usampler3D _BricksTexture; +layout(set=3, binding=0) uniform Materials { + Material _Materials[256]; +}; // Defines -#define PI 3.141592 -#define EPSILON 0.01 -#define NEAR 0.01 -#define MAX_STEPS 200 +// #define PI 3.141592 +// #define EPSILON 0.01 +// #define NEAR 0.01 // Include -#include "shapes.cginc" +#include "shading.cginc" #include "raycasting.cginc" + void main() { // Calculate ray direction - vec3 view_dir = (_projMatrixInv * vec4(vert_uv, 0, 1)).xyz; - vec3 ray_dir = normalize(_viewMatrix * vec4(view_dir,0)).xyz; + vec3 view_dir = (_ProjMatrixInv * vec4(vert_uv, 0, 1)).xyz; + vec3 ray_dir = normalize(_ViewMatrix * vec4(view_dir,0)).xyz; // Raycast out_color = vec4(castNodes(_CamPos, ray_dir), 1.0); diff --git a/src/shaders/shading.cginc b/src/shaders/shading.cginc new file mode 100644 index 0000000..a72a36f --- /dev/null +++ b/src/shaders/shading.cginc @@ -0,0 +1,19 @@ +/* + point: Hit point + view: View vector (camera ray) + normal: Normal vector +*/ +vec3 solve(vec3 hitPoint, vec3 view, vec3 normal, uint brick) +{ + // Lighting + vec3 light_color = vec3(1.0, 1.0, 1.0); + vec3 light_dir = normalize(hitPoint-vec3(0.0, 1.5, 4.0)); + + vec3 ambient = light_color * 0.1; + vec3 diffuse = light_color * max(1.0-dot(normal, light_dir), 0.0); + vec3 specular = light_color * pow(max(dot(view, reflect(-light_dir, normal)), 0.0), 32); + + // Combine colors + vec3 object_color = _Materials[brick].albedo.rgb;//vec3(0.0, 0.1, 0.5); + return (ambient + diffuse + specular) * object_color; +} \ No newline at end of file