materials, brick and nodes structure, preparing for world generation
This commit is contained in:
+46
-3
@@ -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<Event<()>>) {
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -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();
|
||||
|
||||
@@ -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::<f32>()> 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
|
||||
}
|
||||
}
|
||||
@@ -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 }
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -12,3 +23,6 @@ pub use uniform_buffer::UniformValues;
|
||||
mod raster_buffer;
|
||||
pub use raster_buffer::RasterBuffer;
|
||||
pub use raster_buffer::Vertex;
|
||||
|
||||
mod material_buffer;
|
||||
pub use material_buffer::MaterialBuffer;
|
||||
@@ -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::<f32>()> 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(
|
||||
|
||||
+86
-13
@@ -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<usize>,
|
||||
}
|
||||
|
||||
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<usize> = 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<PhysicalSize<u32>>) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -1,28 +1,9 @@
|
||||
|
||||
/*
|
||||
point: Hit point
|
||||
view: View vector (camera ray)
|
||||
normal: Normal vector
|
||||
*/
|
||||
vec3 solve(vec3 hitPoint, vec3 view, vec3 normal)
|
||||
{
|
||||
// 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 = vec3(0.0, 0.1, 0.5);
|
||||
return (ambient + diffuse + specular) * object_color;
|
||||
}
|
||||
|
||||
/*
|
||||
* origin: Point hit on the node
|
||||
* dir: Camera view direction (ray direction)
|
||||
* addr: Number given by node, afaik brick offset in brick array
|
||||
* incAxis: Last axis that was used to increment position
|
||||
* addr: Number given by node, brick offset in brick array
|
||||
*/
|
||||
vec4 castBricks(vec3 origin, vec3 start, vec3 dir, vec3 incAxis, uint addr)
|
||||
{
|
||||
@@ -38,14 +19,12 @@ vec4 castBricks(vec3 origin, vec3 start, vec3 dir, vec3 incAxis, uint addr)
|
||||
vec3 rayInv = 1.0/dir;
|
||||
vec3 raySign = sign(dir);
|
||||
vec3 dist = (pos-origin+0.5 + raySign*0.5) * rayInv;
|
||||
|
||||
ivec3 offset = ivec3(0, 0, (addr-1)*32);
|
||||
|
||||
vec3 tmp = abs(raySign);
|
||||
for(int i=0;i<110;i++)
|
||||
{
|
||||
// Get brick
|
||||
uint brick = texelFetch(bricksTexture, offset+ivec3(pos), 0).r;
|
||||
uint brick = texelFetch(_BricksTexture, offset+ivec3(pos), 0).r;
|
||||
if(brick != 0)
|
||||
{
|
||||
// Hit point
|
||||
@@ -55,7 +34,7 @@ vec4 castBricks(vec3 origin, vec3 start, vec3 dir, vec3 incAxis, uint addr)
|
||||
|
||||
// Normal vector (negate previous increment axis and mult by sign)
|
||||
vec3 normal = -incAxis * raySign;
|
||||
return vec4(solve(hitPoint, dir, normal), 1.0);
|
||||
return vec4(solve(hitPoint, dir, normal, brick-1), 1.0);
|
||||
}
|
||||
|
||||
// Get new closest axis to increment
|
||||
@@ -68,7 +47,7 @@ vec4 castBricks(vec3 origin, vec3 start, vec3 dir, vec3 incAxis, uint addr)
|
||||
if(pos.x > 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);
|
||||
|
||||
@@ -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<MAX_STEPS;i++)
|
||||
{
|
||||
// Travel through map
|
||||
vec2 dist = map(ro + rd * depth);
|
||||
if(dist.x < EPSILON)
|
||||
{
|
||||
// Hit something
|
||||
return vec2(depth, dist.y);
|
||||
}
|
||||
|
||||
// Move further
|
||||
depth += dist.x;
|
||||
}
|
||||
|
||||
// Nothing found
|
||||
return vec2(0);
|
||||
}
|
||||
|
||||
vec3 estimateNormal(vec3 p)
|
||||
{
|
||||
return normalize(vec3(
|
||||
map(vec3(p.x + EPSILON, p.y, p.z)).x - map(vec3(p.x - EPSILON, p.y, p.z)).x,
|
||||
map(vec3(p.x, p.y + EPSILON, p.z)).x - map(vec3(p.x, p.y - EPSILON, p.z)).x,
|
||||
map(vec3(p.x, p.y, p.z + EPSILON)).x - map(vec3(p.x, p.y, p.z - EPSILON)).x
|
||||
));
|
||||
}
|
||||
|
||||
vec3 raymarch(in vec3 ro, in vec3 rd)
|
||||
{
|
||||
// Light dir
|
||||
vec3 ld = normalize(vec3(-0.5, 2.0, -0.2));
|
||||
|
||||
vec2 result = intersect(ro, rd);
|
||||
if(result.y > 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);
|
||||
}
|
||||
}
|
||||
+19
-16
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user