diff --git a/src/app.rs b/src/app.rs index 0907c8e..0fb8a80 100644 --- a/src/app.rs +++ b/src/app.rs @@ -40,7 +40,7 @@ pub struct AppState { clients: Vec, } -const BLOCKS: i32 = 1; +const BLOCKS: i32 = 4; impl AppState { // We don't need this to be async right now, @@ -54,17 +54,24 @@ impl AppState { .renderer .as_mut() .unwrap() - .load_from_gltf(include_bytes!("assets/cube.glb")); + .load_from_gltf(include_bytes!("assets/sphere.glb")); let block = file.first_object().unwrap(); let skybox = world.renderer.as_mut().unwrap().load_texture_from_bytes( - include_bytes!("assets/skybox1.png"), + include_bytes!("assets/skybox2.png"), Some(image::ImageFormat::Png), ); - world.renderer.as_mut().unwrap().set_skybox(skybox); - //let color = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/color.png")); - //let normal = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/normal.png")); - //let roughness = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/roughness.png")); - //let mat = renderer.new_material(color,normal,roughness); + world.renderer().set_skybox(skybox); + let color = world + .renderer() + .load_texture_from_bytes(include_bytes!("assets/plank/color.png"), None); + let normal = world + .renderer() + .load_texture_from_bytes(include_bytes!("assets/plank/normal.png"), None); + let roughness = world + .renderer() + .load_texture_from_bytes(include_bytes!("assets/plank/roughness.png"), None); + let mat = world.renderer().new_material(&color, &normal, &roughness); + block.0.borrow_mut().model.as_mut().unwrap().material = mat; for x in -BLOCKS..BLOCKS { for y in -BLOCKS..BLOCKS { let block = block.hard_clone(); @@ -72,7 +79,7 @@ impl AppState { { let mut model = block.0.borrow_mut(); model.model.as_mut().unwrap().instance.transform = Mat4::from_translation( - Vec3::new(-x as f32 * 3.0, -8.0, -y as f32 * 3.0), + Vec3::new(-x as f32 * 3.0, -2.0, -y as f32 * 3.0), ) * Mat4::from_rotation_z((x * y) as f32 / 1.23); model.model.as_mut().unwrap().instance.color = Vec4::new( diff --git a/src/assets/SimpleShader.wgsl b/src/assets/SimpleShader.wgsl index 7a9a592..f8c7b12 100644 --- a/src/assets/SimpleShader.wgsl +++ b/src/assets/SimpleShader.wgsl @@ -88,9 +88,9 @@ var t_rough: texture_2d; fn sky_aspect(look: vec3) -> vec4 { var pi = 3.14159; let u_angle = atan2(look.x,look.z); - let u = (u_angle/pi) + 0.5; // from -pi/2 -> pi/2 into 0 -> 1 + let u = (u_angle/pi) * 0.5 + 0.5; // from -pi/2 -> pi/2 into 0 -> 1 let v_angle = atan2(-look.y,sqrt(look.x * look.x + look.z * look.z)); - let v = (v_angle/pi) + 0.5;//(v_angle/pi) + 0.5; // from -pi/2 -> pi/2 into 0 -> 1 + let v = (v_angle/pi) - 0.5;//(v_angle/pi) + 0.5; // from -pi/2 -> pi/2 into 0 -> 1 let uv = vec2(u,v); // Get UV on skybox return textureSample(sky_texture, sky_sampler, uv); } @@ -112,7 +112,9 @@ fn translation(mat: mat4x4) -> vec4 { fn fs_main(in: VertexOutput) -> @location(0) vec4 { let object_color: vec4 = textureSample(t_diffuse, s_diffuse, in.tex_coords); let object_normal: vec4 = textureSample(t_normal, s_diffuse, in.tex_coords); + let object_rough: vec4 = textureSample(t_rough, s_diffuse, in.tex_coords); + let diffuse_result = object_color.xyz * environment.ambient.xyz; let diffuse_color = object_color.xyz; let specular_color = vec3(0.0,0.0,0.0); let reflection = sky_aspect(reflect(normalize(in.world_position-translation(eye.frame).xyz),normalize(in.world_normal))); @@ -129,9 +131,15 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4 { //let specular_strength = pow(max(dot(tangent_normal, half_dir), 0.0), 32.0); //let specular_color = specular_strength * environment.light.xyz; - let result = (environment.ambient.xyz + diffuse_color.xyz + specular_color.xyz) * object_color.xyz; + let reflect_factor = max(object_rough.x * 0.5,object_rough.y); - return vec4(reflection.xyz,object_color.a); + let diffuse_brightness = length(diffuse_color); + + let diffuse_effect = (diffuse_result * (1 - reflect_factor)) + reflection.xyz * reflect_factor * diffuse_brightness; + + let result = (diffuse_effect.xyz + specular_color.xyz); + + return vec4(result.xyz,object_color.a); } struct SkyOutput { diff --git a/src/assets/skybox2.png b/src/assets/skybox2.png new file mode 100644 index 0000000..e828de1 Binary files /dev/null and b/src/assets/skybox2.png differ diff --git a/src/render/eye.rs b/src/render/eye.rs index 11b7112..21fd621 100644 --- a/src/render/eye.rs +++ b/src/render/eye.rs @@ -63,7 +63,7 @@ impl Eye { let dir = Vec3::new(1.0, 0.5, 1.0).normalize(); let environment = Environment { - ambient: Vec4::new(0.15, 0.15, 0.15, 0.0), + ambient: Vec4::new(0.1, 0.1, 0.1, 0.0), light: Vec4::new(1.0, 1.0, 1.0, 0.0), dir: Vec4::new(dir.x, dir.y, dir.z, 0.0), }; diff --git a/src/render/mod.rs b/src/render/mod.rs index 68977e7..f6d2761 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -826,7 +826,6 @@ impl Renderer { collider: SimpleColliderData { transform: Mat4::default(), shape: Shape::None, - radius: 0.0, }, }))); if len == 1 { diff --git a/src/world/mod.rs b/src/world/mod.rs index 3802219..0cdfdad 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -1,8 +1,7 @@ use crate::render::{Renderer, SimpleLightData, SimpleModelData}; -use glam::{DVec3, IVec3, Mat4, UVec3, Vec3, Vec4Swizzles}; +use glam::{IVec3, Mat4, Vec3}; use std::cell::RefCell; use std::hash::{BuildHasherDefault, Hash, Hasher}; -use std::ops::{Div, Mul}; use std::rc::Rc; use wgpu::naga::{FastHashMap, FastHashSet}; @@ -17,7 +16,29 @@ pub enum Shape { pub struct SimpleColliderData { pub transform: Mat4, pub shape: Shape, - pub radius: f32, +} + +impl SimpleColliderData { + fn aabb(&self) -> Option { + let (_scale, _rotation, translation) = self.transform.to_scale_rotation_translation(); + match self.shape { + Shape::Block(size) => { + let radius_offset = Vec3::splat(size.length()); + Some(AABB( + translation - radius_offset, + translation + radius_offset, + )) + } + Shape::Sphere(radius) => { + let radius_offset = Vec3::splat(radius); + Some(AABB( + translation - radius_offset, + translation + radius_offset, + )) + } + Shape::None => None, + } + } } #[derive(Clone)] @@ -72,157 +93,220 @@ impl Hash for SimpleObject { } #[derive(Eq, Hash, PartialEq, Clone)] -enum Interest { +pub enum Interest { Light(SimpleLight), Object(SimpleObject), } -struct Block { - debug: Option, +impl Interest { + fn aabb(&self) -> Option { + match self { + Interest::Light(light) => { + let data = light.0.borrow(); + Some(AABB::new( + data.transform.to_scale_rotation_translation().2, + Vec3::splat(data.instance.color.length()), + )) + } + Interest::Object(object) => object.0.borrow().collider.aabb(), + } + } +} + +#[derive(Copy, Clone)] +struct Material { volume: u8, velocity: Vec3, material: u8, - interests: FastHashSet, - blocks: [Option>; 64], } -const TREE_ATTACK: usize = 4; -const TREE_FLOOR: usize = 4; -impl Block { - fn new() -> Block { - Block { - debug: None, +impl Material { + const fn new() -> Material { + Material { volume: 0, velocity: Vec3::ZERO, material: 0, - interests: FastHashSet::with_hasher(BuildHasherDefault::default()), - blocks: [const { None }; const { TREE_ATTACK * TREE_ATTACK * TREE_ATTACK }], } } - fn place_pos(&mut self, interest: Interest, pos: Vec3, rad: f32, block_size: f32) { - let cs = block_size / const { TREE_ATTACK as f32 }; - if rad < cs || block_size >= TREE_FLOOR as f32 { - let rel = ((pos + block_size / 2.0) / cs).round().as_uvec3(); - let new_pos = pos - (rel.as_vec3() + cs / 2.0); - let index = (rel.x + rel.y * 4 + rel.z * 16) as usize; - match self.blocks[index] { - Some(ref mut block) => { - block.place_pos(interest, new_pos, rad, cs); - } - None => { - let mut block = Box::new(Block::new()); - block.place_pos(interest, new_pos, rad, cs); - self.blocks[index] = Some(block); - } - } - } else { - self.interests.insert(interest); - } +} + +#[derive(Clone, Copy)] +struct AABB(Vec3, Vec3); + +impl AABB { + fn new(translation: Vec3, size: Vec3) -> AABB { + AABB(translation - size, translation + size) } - fn debug_step(&mut self, value: bool) { - match self.debug { - Some(ref mut debug) => { - if value { - } else { - } - } - None => { - if value { - } else { - } - } - } - for maybe_block in self.blocks.iter_mut() { - if let Some(block) = maybe_block { - block.debug_step(value) - } - } + fn bounded_by(&self, aabb: AABB) -> AABB { + AABB(self.0.max(aabb.0), self.1.min(aabb.1)) + } + fn offset(&self) -> Vec3 { + self.1 - self.0 } } pub struct World { - chunk_size: u32, - map: FastHashMap, + map: HashedMap, pub renderer: Option, - debug_world_map: bool, - debug_world_map_object: Option, } impl World { pub fn new() -> World { World { - chunk_size: 512, - map: FastHashMap::with_hasher(BuildHasherDefault::default()), + map: HashedMap::new(), renderer: None, - debug_world_map: false, - debug_world_map_object: None, } } + pub fn renderer(&mut self) -> &mut Renderer { + self.renderer.as_mut().unwrap() + } pub fn add_renderer(&mut self, renderer: Renderer) { self.renderer = Some(renderer); - self.debug_world_map_object = self - .renderer - .as_mut() - .unwrap() - .load_from_gltf(include_bytes!("../assets/cube.glb")) - .first_object() } pub fn add_object(&mut self, object: SimpleObject) { - self.place(Interest::Object(object.clone())); - if let Some(ref mut renderer) = self.renderer { - renderer.instances.add_object(object) + if let Some(aabb) = object.0.borrow().collider.aabb() { + self.map + .place_with_aabb(Interest::Object(object.clone()), aabb); + } + if let Some(ref mut renderer) = self.renderer + && object.0.borrow().model.is_some() + { + renderer.instances.add_object(object.clone()) } } - pub fn set_debug(&mut self, value: bool) { - self.debug_world_map = value; + pub fn remove_object(&mut self, object: SimpleObject) {} + pub fn set_debug(&mut self, value: Option) { + for (index, item) in self.map.it.iter_mut() {} } - pub fn light_step(&mut self) {} - pub fn object_step(&mut self) {} - pub fn debug_step(&mut self) { - self.light_step(); - self.object_step(); - for (index, item) in self.map.iter_mut() { - item.debug_step(self.debug_world_map); + fn step(&mut self) {} + fn sync(&mut self) {} +} + +type VecMap = FastHashMap; + +struct Level { + sub_level: + entries: T +} + +struct MatterLevel { + blocks: Option> +} + +struct InterestLevel { + blocks: Option> +} + +struct HashedMap { + matter: +} + +impl HashedMap { + fn new() -> HashedMap { + HashedMap { + it: FastHashMap::default() } } - fn place_pos(&mut self, interest: Interest, pos: Vec3, rad: f32) { - let cs = self.chunk_size as f32; - let c_rad = ((cs / 2.0) * (cs / 2.0)) * 3.0; - for x in (pos.x - rad).div(cs) as i32..=(pos.x + rad).div(cs).ceil() as i32 { - for y in (pos.y - rad).div(cs) as i32..=(pos.y + rad).div(cs).ceil() as i32 { - for z in (pos.z - rad).div(cs) as i32..=(pos.z + rad).div(cs).ceil() as i32 { - let block_pos = IVec3::new(x, y, z); - let block_pos_f32 = block_pos.as_vec3(); - if block_pos_f32.distance_squared(pos) < rad + c_rad { - self.map.entry(block_pos).or_insert_with(|| { - let mut block = Block::new(); - block.place_pos( - interest.clone(), - pos - block_pos_f32, - rad, - self.chunk_size as f32, - ); - block - }); - } +} + +/*impl Block { + const FLOOR: i32 = 4; + const CHUNK_SIZE: i32 = Block::FLOOR * 64; + const MAX_IDEAL_INTEREST: usize = 4; + fn new() -> Block { + Block { + debug: None, + material: Material::new(), + interests: FastHashSet::default(), + blocks: None, + } + } +} + +type Blocks = Box<[Block; 8]>; + +struct Block { + debug: Option, + interests: FastHashSet, + material: Material, + blocks: Option, +} + +impl Block { + pub fn set_debug(&mut self, value: Option, pos: Vec3, size: f32) {} +} + +pub trait WorldMap { + fn new() -> Self; + fn place_with_aabb(&mut self, interest: Interest, aabb: AABB); +} + +struct OctreeMap { + it: FastHashMap, +} + +impl OctreeMap { + fn place_with_index(&mut self, interest: Interest, mut index: IVec3) { + let chunk_index = (index + IVec3::splat(Block::CHUNK_SIZE / 2)) / Block::CHUNK_SIZE; + let mut block = self.it.entry(chunk_index).or_insert_with(|| Block::new()); + let mut offset_size = Block::CHUNK_SIZE / 4; + index = index - chunk_index * Block::CHUNK_SIZE; + while index != IVec3::ZERO { + let blocks = if let Some(ref mut blocks) = block.blocks { + blocks + } else if block.interests.len() < Block::MAX_IDEAL_INTEREST { + block.interests.insert(interest.clone()); + return; + } else { + block.blocks = Some(Box::new(core::array::from_fn(|_| Block::new()))); + block.blocks.as_mut().unwrap() + }; + let mut block_index = 0; + if index.x < 0 { + index.x += offset_size; + } else { + index.x -= offset_size; + block_index += 1; + } + if index.y < 0 { + index.y += offset_size; + } else { + index.y -= offset_size; + block_index += 2; + } + if index.z < 0 { + index.z += offset_size; + } else { + index.z -= offset_size; + block_index += 4; + } + block = &mut blocks[block_index]; + offset_size /= 2; + } + block.interests.insert(interest.clone()); + } +} + +impl WorldMap for OctreeMap { + fn place_with_aabb(&mut self, interest: Interest, aabb: AABB) { + let mut d = 4; + let offset = aabb.1 - aabb.0; + while offset.element_sum() > (d * 2) as f32 { + d *= 2 + } + let iaabb0 = (aabb.0 / d as f32).floor().as_ivec3(); + let iaabb1 = (aabb.1 / d as f32).ceil().as_ivec3(); + for x in iaabb0.x..iaabb1.x { + for y in iaabb0.y..iaabb1.y { + for z in iaabb0.z..iaabb1.z { + self.place_with_index(interest.clone(), IVec3::new(x, y, z) * d as i32); } } } } - fn place(&mut self, interest: Interest) { - let (pos, rad) = match &interest { - Interest::Light(light) => { - let light = light.0.borrow(); - (light.instance.location.xyz(), light.instance.color.length()) - } - Interest::Object(object) => { - let collider = &object.0.borrow().collider; - ( - collider.transform.to_scale_rotation_translation().2, - collider.radius, - ) - } - }; - self.place_pos(interest, pos, rad); + fn new() -> OctreeMap { + OctreeMap { + it: FastHashMap::with_hasher(BuildHasherDefault::default()), + } } -} +}*/