Added skybox to renderer and reflections to shader. Builds and runs. Flickering with many objects in scene, assuming swap chain issue.

This commit is contained in:
Christian Lincoln 2026-09-03 22:18:48 +01:00
parent efe98454d9
commit 3231ed9190
10 changed files with 1829 additions and 1449 deletions

12
Cargo.lock generated
View file

@ -349,6 +349,15 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
[[package]]
name = "colored"
version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
dependencies = [
"windows-sys 0.61.2",
]
[[package]] [[package]]
name = "combine" name = "combine"
version = "4.6.7" version = "4.6.7"
@ -1096,6 +1105,9 @@ checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
[[package]] [[package]]
name = "mars" name = "mars"
version = "0.1.0" version = "0.1.0"
dependencies = [
"colored",
]
[[package]] [[package]]
name = "memchr" name = "memchr"

BIN
game.core Normal file

Binary file not shown.

View file

@ -1,7 +1,9 @@
use std::collections::HashMap; use std::collections::HashMap;
// Credit of most code to https://sotrh.github.io/learn-wgpu/ since I'm not familiar with wgpu // Credit of most code to https://sotrh.github.io/learn-wgpu/ since I'm not familiar with wgpu
use crate::render::Renderer;
use crate::world::{SimpleObject, World};
use glam::{Affine3A, EulerRot, Mat4, Quat, Vec2, Vec3, Vec4};
use std::sync::Arc; use std::sync::Arc;
use glam::{Vec2, Affine3A, Vec3, Vec4, Mat4, EulerRot, Quat};
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use winit::dpi::PhysicalPosition; use winit::dpi::PhysicalPosition;
@ -14,13 +16,10 @@ use winit::{
keyboard::{KeyCode, PhysicalKey}, keyboard::{KeyCode, PhysicalKey},
window::Window, window::Window,
}; };
use crate::render;
use crate::render::{Renderer, SimpleTexture};
use crate::world::{SimpleObject, World};
struct Controller { struct Controller {
buttons: HashMap<MouseButton,bool>, buttons: HashMap<MouseButton, bool>,
keys: HashMap<KeyCode,bool>, keys: HashMap<KeyCode, bool>,
mouse: Vec2, mouse: Vec2,
} }
@ -29,7 +28,7 @@ impl Controller {
Controller { Controller {
buttons: Default::default(), buttons: Default::default(),
keys: HashMap::new(), keys: HashMap::new(),
mouse: Vec2::new(0.0,0.0), mouse: Vec2::new(0.0, 0.0),
} }
} }
} }
@ -41,19 +40,27 @@ pub struct AppState {
clients: Vec<SimpleObject>, clients: Vec<SimpleObject>,
} }
const BLOCKS: i32 = 50; const BLOCKS: i32 = 1;
impl AppState { impl AppState {
// We don't need this to be async right now, // We don't need this to be async right now,
// but we will in the next tutorial // but we will in the next tutorial
pub async fn new(window: Arc<Window>) -> Result<AppState,Box<dyn std::error::Error>> { pub async fn new(window: Arc<Window>) -> Result<AppState, Box<dyn std::error::Error>> {
let size = window.inner_size();
let mut world = World::new(); let mut world = World::new();
world.add_renderer(Renderer::new(&window).await?); world.add_renderer(Renderer::new(&window).await?);
let mut clients = Vec::new(); let mut clients = Vec::new();
{ {
let file = world.renderer.as_mut().unwrap().load_from_gltf( include_bytes!("assets/cube.glb")); let file = world
.renderer
.as_mut()
.unwrap()
.load_from_gltf(include_bytes!("assets/cube.glb"));
let block = file.first_object().unwrap(); let block = file.first_object().unwrap();
let skybox = world.renderer.as_mut().unwrap().load_texture_from_bytes(
include_bytes!("assets/skybox1.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 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 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 roughness = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/roughness.png"));
@ -64,9 +71,16 @@ impl AppState {
world.add_object(block.clone()); world.add_object(block.clone());
{ {
let mut model = block.0.borrow_mut(); let mut model = block.0.borrow_mut();
model.model.as_mut().unwrap().instance.transform = Mat4::from_translation(Vec3::new(-x as f32 * 3.0,0.0,-y as f32 * 3.0)) model.model.as_mut().unwrap().instance.transform = Mat4::from_translation(
Vec3::new(-x as f32 * 3.0, -8.0, -y as f32 * 3.0),
)
* Mat4::from_rotation_z((x * y) as f32 / 1.23); * Mat4::from_rotation_z((x * y) as f32 / 1.23);
model.model.as_mut().unwrap().instance.color = Vec4::new(0.3,(x + BLOCKS) as f32 / BLOCKS as f32,(y + BLOCKS) as f32 / BLOCKS as f32,1.0); model.model.as_mut().unwrap().instance.color = Vec4::new(
0.3,
(x + BLOCKS) as f32 / BLOCKS as f32,
(y + BLOCKS) as f32 / BLOCKS as f32,
1.0,
);
} }
clients.push(block) clients.push(block)
} }
@ -80,15 +94,14 @@ impl AppState {
}) })
} }
pub fn bounds(&self) -> (u32,u32) { pub fn bounds(&self) -> (u32, u32) {
let size = self.window.inner_size(); let size = self.window.inner_size();
(size.width,size.height) (size.width, size.height)
} }
pub fn resize(&mut self, width: u32, height: u32) { pub fn resize(&mut self, width: u32, height: u32) {
if width > 0 && height > 0 { if width > 0 && height > 0 {
let max = 2048; self.world.renderer.as_mut().unwrap().resize(width, height);
self.world.renderer.as_mut().unwrap().resize(width,height);
} }
} }
@ -99,7 +112,7 @@ impl AppState {
fn handle_key(&mut self, event_loop: &ActiveEventLoop, code: KeyCode, is_pressed: bool) { fn handle_key(&mut self, event_loop: &ActiveEventLoop, code: KeyCode, is_pressed: bool) {
match (code, is_pressed) { match (code, is_pressed) {
(KeyCode::Escape, true) => event_loop.exit(), (KeyCode::Escape, true) => event_loop.exit(),
(KeyCode::Space, true) => {}, (KeyCode::Space, true) => {}
(KeyCode::KeyR, true) => { (KeyCode::KeyR, true) => {
self.world.renderer.as_mut().unwrap().eye.frame = Affine3A::IDENTITY self.world.renderer.as_mut().unwrap().eye.frame = Affine3A::IDENTITY
} }
@ -110,13 +123,16 @@ impl AppState {
fn handle_mouse_moved(&mut self, position: PhysicalPosition<f64>) { fn handle_mouse_moved(&mut self, position: PhysicalPosition<f64>) {
if let Some(true) = self.controller.buttons.get(&MouseButton::Right) { if let Some(true) = self.controller.buttons.get(&MouseButton::Right) {
self.world.renderer.as_mut().unwrap().eye.rotate(position.x as f32 - self.controller.mouse.x, position.y as f32 - self.controller.mouse.y); self.world.renderer.as_mut().unwrap().eye.rotate(
position.x as f32 - self.controller.mouse.x,
position.y as f32 - self.controller.mouse.y,
);
} }
self.controller.mouse = Vec2::new(position.x as f32, position.y as f32); self.controller.mouse = Vec2::new(position.x as f32, position.y as f32);
} }
fn handle_mouse_button(&mut self, button: MouseButton, state: ElementState ) { fn handle_mouse_button(&mut self, button: MouseButton, state: ElementState) {
self.controller.buttons.insert(button,state.is_pressed()); self.controller.buttons.insert(button, state.is_pressed());
} }
} }
@ -216,7 +232,7 @@ impl ApplicationHandler<AppState> for App {
WindowEvent::Resized(size) => state.resize(size.width, size.height), WindowEvent::Resized(size) => state.resize(size.width, size.height),
WindowEvent::RedrawRequested => { WindowEvent::RedrawRequested => {
state.update(); state.update();
let mut movement = Vec3::new(0.0,0.0,0.0); let mut movement = Vec3::new(0.0, 0.0, 0.0);
let pressed = |keycode: KeyCode| { let pressed = |keycode: KeyCode| {
if let Some(true) = state.controller.keys.get(&keycode) { if let Some(true) = state.controller.keys.get(&keycode) {
@ -245,7 +261,13 @@ impl ApplicationHandler<AppState> for App {
movement.y -= 1.0; movement.y -= 1.0;
} }
state.world.renderer.as_mut().unwrap().eye.control(movement * 0.1); state
.world
.renderer
.as_mut()
.unwrap()
.eye
.control(movement * 0.1);
match state.world.renderer.as_mut().unwrap().render(&state.window) { match state.world.renderer.as_mut().unwrap().render(&state.window) {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
@ -255,13 +277,24 @@ impl ApplicationHandler<AppState> for App {
} }
} }
for object in state.clients.iter() { for object in state.clients.iter() {
object.0.borrow_mut().model.as_mut().unwrap().instance.transform *= Mat4::from_rotation_translation( object
Quat::from_euler(EulerRot::XYZ,0.001,-0.001,0.001), .0
Vec3::new(0.0,0.0,0.0) .borrow_mut()
.model
.as_mut()
.unwrap()
.instance
.transform *= Mat4::from_rotation_translation(
Quat::from_euler(EulerRot::XYZ, 0.001, -0.001, 0.001),
Vec3::new(0.0, 0.0, 0.0),
); );
} }
} }
WindowEvent::MouseInput { button, state: element, .. } => state.handle_mouse_button(button,element), WindowEvent::MouseInput {
button,
state: element,
..
} => state.handle_mouse_button(button, element),
WindowEvent::CursorMoved { position: pos, .. } => state.handle_mouse_moved(pos), WindowEvent::CursorMoved { position: pos, .. } => state.handle_mouse_moved(pos),
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
event: event:

View file

@ -4,16 +4,26 @@ struct Environment {
dir: vec4<f32>, dir: vec4<f32>,
} }
struct View { struct Eye {
// from camera to screen
proj: mat4x4<f32>,
// from screen to camera
inv: mat4x4<f32>,
// world to camera
view: mat4x4<f32>, view: mat4x4<f32>,
// camera transform
frame: mat4x4<f32>, frame: mat4x4<f32>,
} }
// Vertex shader // Vertex shader
@group(0) @binding(0) @group(0) @binding(0)
var<uniform> view: View; var<uniform> eye: Eye;
@group(0) @binding(1) @group(0) @binding(1)
var<uniform> environment: Environment; var<uniform> environment: Environment;
@group(0) @binding(2)
var sky_sampler: sampler;
@group(0) @binding(3)
var sky_texture: texture_2d<f32>;
struct VertexInput { struct VertexInput {
@location(0) position: vec3<f32>, @location(0) position: vec3<f32>,
@ -60,7 +70,7 @@ fn vs_main(
out.world_normal = model_rot_matrix * model.normal; out.world_normal = model_rot_matrix * model.normal;
var world_position: vec4<f32> = model_matrix * vec4<f32>(model.position, 1.0); var world_position: vec4<f32> = model_matrix * vec4<f32>(model.position, 1.0);
out.world_position = world_position.xyz; out.world_position = world_position.xyz;
out.clip_position = view.view * world_position; out.clip_position = eye.proj * eye.view * world_position;
return out; return out;
} }
@ -75,23 +85,79 @@ var t_normal: texture_2d<f32>;
@group(1) @binding(3) @group(1) @binding(3)
var t_rough: texture_2d<f32>; var t_rough: texture_2d<f32>;
fn sky_aspect(look: vec3<f32>) -> vec4<f32> {
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 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 uv = vec2<f32>(u,v); // Get UV on skybox
return textureSample(sky_texture, sky_sampler, uv);
}
fn rotation(mat: mat4x4<f32>) -> mat3x3<f32> {
return mat3x3<f32>(
mat[0].xyz,
mat[1].xyz,
mat[2].xyz,
);
}
fn translation(mat: mat4x4<f32>) -> vec4<f32> {
//return vec4<f32>(mat[0][3],mat[1][3],mat[2][3],mat[3][3]);
return mat[3];
}
@fragment @fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
let object_color: vec4<f32> = textureSample(t_diffuse, s_diffuse, in.tex_coords); let object_color: vec4<f32> = textureSample(t_diffuse, s_diffuse, in.tex_coords);
let object_normal: vec4<f32> = textureSample(t_normal, s_diffuse, in.tex_coords); let object_normal: vec4<f32> = textureSample(t_normal, s_diffuse, in.tex_coords);
let tangent_normal = object_normal.xyz * 2.0 - 1.0; let diffuse_color = object_color.xyz;
let light_dir = normalize(environment.dir.xyz); let specular_color = vec3<f32>(0.0,0.0,0.0);
let view_dir = normalize(view.frame[3].xyz - in.world_position); let reflection = sky_aspect(reflect(normalize(in.world_position-translation(eye.frame).xyz),normalize(in.world_normal)));
let half_dir = normalize(view_dir + light_dir);
let diffuse_strength = max(dot(tangent_normal, light_dir), 0.0); //let result = (environment.ambient.xyz + diffuse_color + specular_color) * object_color.xyz;
let diffuse_color = environment.light.xyz * diffuse_strength;
let specular_strength = pow(max(dot(tangent_normal, half_dir), 0.0), 32.0); //let light_dir = normalize(environment.dir.xyz);
let specular_color = specular_strength * environment.light.xyz; //let view_dir = normalize(eye.frame[3].xyz - in.world_position);
//let half_dir = normalize(view_dir + light_dir);
//let diffuse_strength = max(dot(tangent_normal, light_dir), 0.0);
//let diffuse_color = environment.light.xyz * diffuse_strength;
//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 result = (environment.ambient.xyz + diffuse_color.xyz + specular_color.xyz) * object_color.xyz;
return vec4<f32>(result.xyz,object_color.a); return vec4<f32>(reflection.xyz,object_color.a);
}
struct SkyOutput {
@builtin(position) position: vec4<f32>,
@location(0) pos: vec4<f32> // unadulterated by WGSL
}
const TRI_VERTICES = array(
vec4(-1.0, -1.0, 1.0, 1.0),
vec4(-1.0, 1.0, 1.0, 1.0),
vec4( 1.0, -1.0, 1.0, 1.0),
vec4( 1.0, 1.0, 1.0, 1.0),
vec4(-1.0, 1.0, 1.0, 1.0),
vec4( 1.0, -1.0, 1.0, 1.0),
);
@vertex
fn vs_sky(@builtin(vertex_index) index: u32) -> SkyOutput {
var out: SkyOutput;
out.position = TRI_VERTICES[index];
out.pos = out.position;
return out;
}
@fragment
fn fs_sky(in: SkyOutput) -> @location(0) vec4<f32> {
let look = rotation(eye.frame) * in.pos.xyz;
return sky_aspect(look);
} }

BIN
src/assets/cube.glb Normal file

Binary file not shown.

BIN
src/assets/skybox1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 254 KiB

View file

@ -1,9 +1,9 @@
use crate::render::{MaterialProperties, SimpleTexture};
use bytemuck::{Pod, Zeroable}; use bytemuck::{Pod, Zeroable};
use env_logger::Env;
use glam::{Affine3A, EulerRot, Mat3A, Mat4, Vec3, Vec4};
use glam::camera::lh::proj::directx::perspective; use glam::camera::lh::proj::directx::perspective;
use wgpu::{Device, Queue}; use glam::{Affine3A, EulerRot, Mat3A, Mat4, Vec3, Vec4};
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
use wgpu::{Device, Queue};
pub(crate) struct Eye { pub(crate) struct Eye {
pub(crate) frame: Affine3A, pub(crate) frame: Affine3A,
@ -13,54 +13,66 @@ pub(crate) struct Eye {
z_far: f32, z_far: f32,
fov_y: f32, fov_y: f32,
pub(crate) environment_buffer: wgpu::Buffer, pub(crate) environment_buffer: wgpu::Buffer,
pub(crate) buffer: wgpu::Buffer, pub(crate) camera_buffer: wgpu::Buffer,
pub(crate) layout: wgpu::BindGroupLayout, pub(crate) layout: wgpu::BindGroupLayout,
pub(crate) group: wgpu::BindGroup, pub(crate) group: wgpu::BindGroup,
} }
#[repr(C)] #[repr(C)]
#[derive(Pod, Copy, Clone, Zeroable)] #[derive(Pod, Copy, Clone, Zeroable)]
struct Environment { pub struct Environment {
ambient: Vec4, ambient: Vec4,
light: Vec4, light: Vec4,
dir: Vec4, dir: Vec4,
} }
impl Eye { impl Eye {
pub(crate) fn view(&self) -> Mat4 {
let projection = perspective(self.fov_y, self.aspect_ratio, self.z_near, self.z_far);
projection * self.frame.inverse()
}
pub(crate) fn write(&mut self, queue: &Queue) { pub(crate) fn write(&mut self, queue: &Queue) {
queue.write_buffer(&self.buffer,0,bytemuck::cast_slice(&[ let camera = Mat4::from_mat3_translation(
self.view(), self.frame.matrix3.into(),
Mat4::from_mat3_translation(self.frame.matrix3.into(), Vec3::from(self.frame.translation)) Vec3::from(self.frame.translation),
]));
queue.write_buffer(&self.environment_buffer,0,bytemuck::cast_slice(&[self.environment]));
}
pub(crate) fn new(device: &Device, width: u32, height: u32) -> Eye {
let buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Camera Buffer"),
contents: bytemuck::cast_slice(&[Mat4::from_translation(Vec3::new(0.0,2.0,-8.0)),Mat4::IDENTITY]),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
}
); );
let projection = perspective(self.fov_y, self.aspect_ratio, self.z_near, self.z_far);
queue.write_buffer(
&self.camera_buffer,
0,
bytemuck::cast_slice(&[
projection,
camera * projection.inverse(),
camera.inverse(),
camera,
]),
);
queue.write_buffer(
&self.environment_buffer,
0,
bytemuck::cast_slice(&[self.environment]),
);
}
pub(crate) fn new(device: &Device, width: u32, height: u32, skybox: SimpleTexture) -> Eye {
let camera_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Camera Buffer"),
contents: bytemuck::cast_slice(&[
Mat4::from_translation(Vec3::new(0.0, 2.0, -8.0)),
Mat4::IDENTITY,
Mat4::IDENTITY,
Mat4::IDENTITY,
]),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
});
let dir = Vec3::new(1.0,0.5,1.0).normalize(); let dir = Vec3::new(1.0, 0.5, 1.0).normalize();
let environment = Environment { let environment = Environment {
ambient: Vec4::new(0.15,0.15,0.15, 0.0), ambient: Vec4::new(0.15, 0.15, 0.15, 0.0),
light: Vec4::new(1.0,1.0,1.0, 0.0), light: Vec4::new(1.0, 1.0, 1.0, 0.0),
dir: Vec4::new(dir.x,dir.y,dir.z,0.0), dir: Vec4::new(dir.x, dir.y, dir.z, 0.0),
}; };
let environment_buffer = device.create_buffer_init( let environment_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
&wgpu::util::BufferInitDescriptor {
label: Some(""), label: Some(""),
contents: bytemuck::cast_slice(&[environment]), contents: bytemuck::cast_slice(&[environment]),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
} });
);
let layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { let layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[ entries: &[
@ -83,25 +95,28 @@ impl Eye {
min_binding_size: None, min_binding_size: None,
}, },
count: None, count: None,
} },
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 3,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
multisampled: false,
view_dimension: wgpu::TextureViewDimension::D2,
sample_type: wgpu::TextureSampleType::Float { filterable: true },
},
count: None,
},
], ],
label: Some("eye_bind_group_layout"), label: Some("eye_bind_group_layout"),
}); });
let group = device.create_bind_group(&wgpu::BindGroupDescriptor { let group = Eye::bind_group(&layout, device, &camera_buffer, &environment_buffer, skybox);
layout: &layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 1,
resource: environment_buffer.as_entire_binding(),
}
],
label: Some("eye_bind_group"),
});
Eye { Eye {
aspect_ratio: width as f32 / height as f32, aspect_ratio: width as f32 / height as f32,
@ -109,13 +124,54 @@ impl Eye {
fov_y: 90.0, fov_y: 90.0,
z_near: 0.1, z_near: 0.1,
z_far: 1000.0, z_far: 1000.0,
buffer, camera_buffer,
group, group,
layout, layout,
environment, environment,
environment_buffer, environment_buffer,
} }
} }
fn bind_group(
layout: &wgpu::BindGroupLayout,
device: &wgpu::Device,
camera: &wgpu::Buffer,
environment: &wgpu::Buffer,
skybox: SimpleTexture,
) -> wgpu::BindGroup {
device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: camera.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 1,
resource: environment.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 2,
resource: wgpu::BindingResource::Sampler(
&MaterialProperties::default().sampler(device),
),
},
wgpu::BindGroupEntry {
binding: 3,
resource: wgpu::BindingResource::TextureView(&skybox.view),
},
],
label: Some("eye_bind_group"),
})
}
pub fn skybox(&mut self, device: &wgpu::Device, texture: SimpleTexture) {
self.group = Eye::bind_group(
&self.layout,
device,
&self.camera_buffer,
&self.environment_buffer,
texture,
)
}
pub(crate) fn resize(&mut self, width: u32, height: u32) { pub(crate) fn resize(&mut self, width: u32, height: u32) {
self.aspect_ratio = width as f32 / height as f32 self.aspect_ratio = width as f32 / height as f32
} }
@ -123,9 +179,9 @@ impl Eye {
self.frame *= Affine3A::from_translation(delta); self.frame *= Affine3A::from_translation(delta);
} }
pub(crate) fn rotate(&mut self, yaw: f32, pitch: f32) { pub(crate) fn rotate(&mut self, yaw: f32, pitch: f32) {
let (mut y,mut x,z) = self.frame.matrix3.to_euler(EulerRot::YXZ); let (mut y, mut x, z) = self.frame.matrix3.to_euler(EulerRot::YXZ);
x = (x + pitch * 0.005).clamp(-1.4,1.4); x = (x + pitch * 0.005).clamp(-1.4, 1.4);
y += yaw * 0.005; y += yaw * 0.005;
self.frame.matrix3 = Mat3A::from_euler(EulerRot::YXZ,y,x,z); self.frame.matrix3 = Mat3A::from_euler(EulerRot::YXZ, y, x, z);
} }
} }

View file

@ -1,32 +1,32 @@
pub mod eye; pub mod eye;
use std::cell::RefCell; use crate::render::eye::Eye;
use crate::world::{Shape, SimpleColliderData, SimpleLight, SimpleObject, SimpleObjectData};
use bytemuck::{Pod, Zeroable};
use glam::prelude::*; use glam::prelude::*;
use std::collections::{HashMap}; use gltf::Semantic;
use image::EncodableLayout;
use std::cell::RefCell;
use std::collections::HashMap;
use std::error::Error; use std::error::Error;
use std::fmt::{Debug, Display, Formatter}; use std::fmt::{Debug, Display, Formatter};
use std::hash::{BuildHasherDefault, Hash, Hasher}; use std::hash::{BuildHasherDefault, Hash, Hasher};
use std::ops::{Range}; use std::ops::Range;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use bytemuck::{Pod, Zeroable};
use gltf::{Gltf, Node, Semantic};
use image::EncodableLayout;
use wgpu::{Device, Queue};
use wgpu::naga::{FastHashMap, FastHashSet}; use wgpu::naga::{FastHashMap, FastHashSet};
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
use wgpu::{Device, Queue};
use winit::window::Window; use winit::window::Window;
use crate::render::eye::Eye;
use crate::world::{Shape, SimpleColliderData, SimpleLight, SimpleObject, SimpleObjectData};
const DEFAULT_VERTICES: [SimpleVertex;0] = []; const DEFAULT_VERTICES: [SimpleVertex; 0] = [];
#[repr(C)] #[repr(C)]
#[derive(Pod,Zeroable,Copy,Clone)] #[derive(Pod, Zeroable, Copy, Clone)]
pub struct SimpleModelInstance { pub struct SimpleModelInstance {
pub transform: Mat4, pub transform: Mat4,
pub color: Vec4, pub color: Vec4,
pub lights: [u16;16], pub lights: [u16; 16],
pub point_lights: u32, pub point_lights: u32,
pub spot_lights: u32, pub spot_lights: u32,
pub metal: f32, pub metal: f32,
@ -34,7 +34,7 @@ pub struct SimpleModelInstance {
} }
#[repr(C)] #[repr(C)]
#[derive(Pod,Copy,Clone,Zeroable)] #[derive(Pod, Copy, Clone, Zeroable)]
pub struct SimpleLightInstance { pub struct SimpleLightInstance {
pub location: Vec4, pub location: Vec4,
pub rotation: Vec4, pub rotation: Vec4,
@ -62,14 +62,15 @@ pub struct SimpleInstances {
instance_buffer: wgpu::Buffer, instance_buffer: wgpu::Buffer,
//light_ref_last: usize, //light_ref_last: usize,
//light_ref_buffer: wgpu::Buffer, //light_ref_buffer: wgpu::Buffer,
objects: FastHashMap<Id<SimpleMesh>,FastHashMap<Id<SimpleMaterial>,FastHashSet<SimpleObject>>>, objects:
lights: FastHashMap<SimpleLight,usize>, FastHashMap<Id<SimpleMesh>, FastHashMap<Id<SimpleMaterial>, FastHashSet<SimpleObject>>>,
lights: FastHashMap<SimpleLight, usize>,
} }
enum SimpleRenderCode { enum SimpleRenderCode {
Material(wgpu::BindGroup), Material(wgpu::BindGroup),
Mesh((wgpu::Buffer,u32),Option<(wgpu::Buffer,u32)>), Mesh((wgpu::Buffer, u32), Option<(wgpu::Buffer, u32)>),
Draw(Range<u32>) Draw(Range<u32>),
} }
struct SimpleRenderProgram(Vec<SimpleRenderCode>); struct SimpleRenderProgram(Vec<SimpleRenderCode>);
@ -86,13 +87,15 @@ impl SimpleRenderProgram {
let mut indexed = false; let mut indexed = false;
for code in self.0 { for code in self.0 {
match code { match code {
SimpleRenderCode::Material(material) => { SimpleRenderCode::Material(material) => pass.set_bind_group(
pass.set_bind_group(Renderer::SIMPLE_RENDER_TEXTURE_GROUP_POSITION,&material,&[]) Renderer::SIMPLE_RENDER_TEXTURE_GROUP_POSITION,
} &material,
SimpleRenderCode::Mesh(vertices,indices) => { &[],
),
SimpleRenderCode::Mesh(vertices, indices) => {
pass.set_vertex_buffer(0, vertices.0.slice(..)); pass.set_vertex_buffer(0, vertices.0.slice(..));
if let Some(indices) = indices { if let Some(indices) = indices {
pass.set_index_buffer(indices.0.slice(..),wgpu::IndexFormat::Uint32); pass.set_index_buffer(indices.0.slice(..), wgpu::IndexFormat::Uint32);
count = indices.1; count = indices.1;
indexed = true; indexed = true;
} else { } else {
@ -118,8 +121,10 @@ impl SimpleInstances {
if let Some(ref model) = object.0.borrow().model { if let Some(ref model) = object.0.borrow().model {
self.instance_count += 1; self.instance_count += 1;
self.objects self.objects
.entry(model.mesh.clone()).or_insert(FastHashMap::with_hasher(BuildHasherDefault::new())) .entry(model.mesh.clone())
.entry(model.material.clone()).or_insert(FastHashSet::with_hasher(BuildHasherDefault::new())) .or_insert(FastHashMap::with_hasher(BuildHasherDefault::new()))
.entry(model.material.clone())
.or_insert(FastHashSet::with_hasher(BuildHasherDefault::new()))
.insert(object.clone()); .insert(object.clone());
} }
} }
@ -128,15 +133,17 @@ impl SimpleInstances {
if let Some(ref model) = object.0.borrow().model { if let Some(ref model) = object.0.borrow().model {
self.instance_count -= 1; self.instance_count -= 1;
self.objects self.objects
.entry(model.mesh.clone()).or_insert(FastHashMap::with_hasher(BuildHasherDefault::new())) .entry(model.mesh.clone())
.entry(model.material.clone()).or_insert(FastHashSet::with_hasher(BuildHasherDefault::new())) .or_insert(FastHashMap::with_hasher(BuildHasherDefault::new()))
.entry(model.material.clone())
.or_insert(FastHashSet::with_hasher(BuildHasherDefault::new()))
.remove(&object); .remove(&object);
} }
} }
pub fn add_light(&mut self, light: SimpleLight) { pub fn add_light(&mut self, light: SimpleLight) {
self.light_count += 1; self.light_count += 1;
self.lights.insert(light,0); self.lights.insert(light, 0);
} }
pub fn remove_light(&mut self, light: &SimpleLight) { pub fn remove_light(&mut self, light: &SimpleLight) {
@ -144,7 +151,12 @@ impl SimpleInstances {
self.lights.remove(light); self.lights.remove(light);
} }
pub fn reallocate_buffer(device: &wgpu::Device, queue: &wgpu::Queue, buffer: &mut wgpu::Buffer, count: usize, item_size: usize) { pub fn reallocate_buffer(
device: &wgpu::Device,
buffer: &mut wgpu::Buffer,
count: usize,
item_size: usize,
) {
let size = buffer.size() / item_size as wgpu::BufferAddress; let size = buffer.size() / item_size as wgpu::BufferAddress;
if count > SimpleInstances::MIN_SIZE as usize { if count > SimpleInstances::MIN_SIZE as usize {
let mut reallocate: Option<usize> = None; let mut reallocate: Option<usize> = None;
@ -172,51 +184,82 @@ impl SimpleInstances {
wgpu::BufferSize::new(self.instance_buffer.size()).unwrap() wgpu::BufferSize::new(self.instance_buffer.size()).unwrap()
).unwrap(); ).unwrap();
*/ */
SimpleInstances::reallocate_buffer(device, queue, &mut self.light_buffer, self.light_count, size_of::<SimpleLight>()); SimpleInstances::reallocate_buffer(
let mut buffer = queue.write_buffer_with( device,
&mut self.light_buffer,
self.light_count,
size_of::<SimpleLight>(),
);
let mut buffer = queue
.write_buffer_with(
&self.light_buffer, &self.light_buffer,
0 as wgpu::BufferAddress, 0 as wgpu::BufferAddress,
wgpu::BufferSize::new(self.light_buffer.size()).unwrap(), wgpu::BufferSize::new(self.light_buffer.size()).unwrap(),
).unwrap(); )
.unwrap();
let stride = size_of::<SimpleLight>(); let stride = size_of::<SimpleLight>();
for (new_index,(light,index)) in self.lights.iter_mut().enumerate() { for (new_index, (light, index)) in self.lights.iter_mut().enumerate() {
*index = new_index + 1; *index = new_index + 1;
let begin = *index * stride; let begin = *index * stride;
buffer.slice(begin..begin + stride).copy_from_slice(bytemuck::cast_slice(&[light.0.borrow().instance])); buffer
.slice(begin..begin + stride)
.copy_from_slice(bytemuck::cast_slice(&[light.0.borrow().instance]));
} }
} }
pub fn write_instances(&mut self, device: &wgpu::Device, queue: &wgpu::Queue) -> SimpleRenderProgram { fn write_instances(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
) -> SimpleRenderProgram {
let mut program = SimpleRenderProgram::new(); let mut program = SimpleRenderProgram::new();
SimpleInstances::reallocate_buffer(device, queue, &mut self.instance_buffer, self.instance_count, size_of::<SimpleModelInstance>()); SimpleInstances::reallocate_buffer(
let mut buffer = queue.write_buffer_with( device,
&mut self.instance_buffer,
self.instance_count,
size_of::<SimpleModelInstance>(),
);
let mut buffer = queue
.write_buffer_with(
&self.instance_buffer, &self.instance_buffer,
0 as wgpu::BufferAddress, 0 as wgpu::BufferAddress,
wgpu::BufferSize::new(self.instance_buffer.size()).unwrap() wgpu::BufferSize::new(self.instance_buffer.size()).unwrap(),
).unwrap(); )
.unwrap();
let mut index: u32 = 0; let mut index: u32 = 0;
let stride = size_of::<SimpleModelInstance>(); let stride = size_of::<SimpleModelInstance>();
for (mesh,materials) in self.objects.iter() { for (mesh, materials) in self.objects.iter() {
program.push(SimpleRenderCode::Mesh(mesh.it.vertices.clone(), mesh.it.indices.clone())); program.push(SimpleRenderCode::Mesh(
mesh.it.vertices.clone(),
mesh.it.indices.clone(),
));
for (material, objects) in materials.iter() { for (material, objects) in materials.iter() {
program.push(SimpleRenderCode::Material(material.it.group.clone())); program.push(SimpleRenderCode::Material(material.it.group.clone()));
let before = index; let before = index;
for object in objects.iter() { for object in objects.iter() {
let begin = index as usize * stride; let begin = index as usize * stride;
buffer.slice(begin .. begin + stride).copy_from_slice(bytemuck::cast_slice(&[object.0.borrow().model.as_ref().unwrap().instance])); buffer
.slice(begin..begin + stride)
.copy_from_slice(bytemuck::cast_slice(&[object
.0
.borrow()
.model
.as_ref()
.unwrap()
.instance]));
index += 1; index += 1;
} }
program.push(SimpleRenderCode::Draw(Range::from(before..index))); program.push(SimpleRenderCode::Draw(Range::from(before..index)));
} }
}; }
program program
} }
fn desc() -> wgpu::VertexBufferLayout<'static> { fn desc() -> wgpu::VertexBufferLayout<'static> {
use std::mem;
wgpu::VertexBufferLayout { wgpu::VertexBufferLayout {
array_stride: size_of::<SimpleModelInstance>() as wgpu::BufferAddress, array_stride: size_of::<SimpleModelInstance>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Instance, step_mode: wgpu::VertexStepMode::Instance,
attributes: &[ // todo: is this too big? attributes: &[
// todo: is this too big?
wgpu::VertexAttribute { wgpu::VertexAttribute {
offset: 0, offset: 0,
shader_location: 4, shader_location: 4,
@ -261,25 +304,27 @@ impl SimpleInstances {
} }
} }
pub fn new(device: &wgpu::Device, queue: &wgpu::Queue) -> SimpleInstances { pub fn new(device: &wgpu::Device) -> SimpleInstances {
let instance_buffer = device.create_buffer(&wgpu::BufferDescriptor { let instance_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Instance Buffer"), label: Some("Instance Buffer"),
size: (size_of::<SimpleModelInstance>() * SimpleInstances::MIN_SIZE as usize) as wgpu::BufferAddress, size: (size_of::<SimpleModelInstance>() * SimpleInstances::MIN_SIZE as usize)
as wgpu::BufferAddress,
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false, mapped_at_creation: false,
}); });
let light_buffer = device.create_buffer(&wgpu::BufferDescriptor { let light_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Light Buffer"), label: Some("Light Buffer"),
size: (size_of::<SimpleLightInstance>() * SimpleInstances::MIN_SIZE as usize) as wgpu::BufferAddress, size: (size_of::<SimpleLightInstance>() * SimpleInstances::MIN_SIZE as usize)
as wgpu::BufferAddress,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false, mapped_at_creation: false,
}); });
let light_ref_buffer = device.create_buffer(&wgpu::BufferDescriptor { /*let light_ref_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Light Ref Buffer"), label: Some("Light Ref Buffer"),
size: (size_of::<u32>() * SimpleInstances::MIN_SIZE as usize) as wgpu::BufferAddress, size: (size_of::<u32>() * SimpleInstances::MIN_SIZE as usize) as wgpu::BufferAddress,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false mapped_at_creation: false,
}); });*/
SimpleInstances { SimpleInstances {
light_count: 0, light_count: 0,
//light_ref_last: 0, //light_ref_last: 0,
@ -302,7 +347,9 @@ pub struct Renderer {
pub(crate) eye: eye::Eye, pub(crate) eye: eye::Eye,
material_layout: wgpu::BindGroupLayout, material_layout: wgpu::BindGroupLayout,
default_texture: SimpleTexture, default_texture: SimpleTexture,
pipeline: wgpu::RenderPipeline, default_material: SimpleMaterial,
sky_pipeline: wgpu::RenderPipeline,
instance_pipeline: wgpu::RenderPipeline,
depth_texture: SimpleTexture, depth_texture: SimpleTexture,
pub(crate) instances: SimpleInstances, pub(crate) instances: SimpleInstances,
} }
@ -337,34 +384,39 @@ impl SimpleVertex {
offset: size_of::<[f32; 6]>() as wgpu::BufferAddress, offset: size_of::<[f32; 6]>() as wgpu::BufferAddress,
shader_location: 2, shader_location: 2,
format: wgpu::VertexFormat::Float32x2, format: wgpu::VertexFormat::Float32x2,
} },
] ],
} }
} }
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct SimpleMesh { pub struct SimpleMesh {
indices: Option<(wgpu::Buffer,u32)>, indices: Option<(wgpu::Buffer, u32)>,
vertices: (wgpu::Buffer, u32), vertices: (wgpu::Buffer, u32),
} }
#[derive(Debug, Clone, Hash, Eq, PartialEq)] #[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub(crate) struct SimpleTexture { pub struct SimpleTexture {
texture: wgpu::Texture, texture: wgpu::Texture,
view: wgpu::TextureView, view: wgpu::TextureView,
} }
struct TextureProperties { pub struct TextureProperties {
width: u32, width: u32,
height: u32, height: u32,
} }
// todo: use texture compression!
impl SimpleTexture { impl SimpleTexture {
pub fn load(device: &Device, queue: &Queue, slice: impl AsRef<[u8]>, properties: TextureProperties) -> SimpleTexture { pub fn load(
device: &Device,
queue: &Queue,
slice: impl AsRef<[u8]>,
properties: TextureProperties,
) -> SimpleTexture {
let size = wgpu::Extent3d { let size = wgpu::Extent3d {
width: properties.width, width: properties.width,
height: properties.height, height: properties.height,
depth_or_array_layers: 1, depth_or_array_layers: 1,
}; };
let diffuse_texture = device.create_texture( let diffuse_texture = device.create_texture(&wgpu::TextureDescriptor {
&wgpu::TextureDescriptor {
size, size,
mip_level_count: 1, mip_level_count: 1,
sample_count: 1, sample_count: 1,
@ -373,9 +425,9 @@ impl SimpleTexture {
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
label: Some("texture"), label: Some("texture"),
view_formats: &[], view_formats: &[],
} });
); let diffuse_texture_view =
let diffuse_texture_view = diffuse_texture.create_view(&wgpu::TextureViewDescriptor::default()); diffuse_texture.create_view(&wgpu::TextureViewDescriptor::default());
queue.write_texture( queue.write_texture(
wgpu::TexelCopyTextureInfo { wgpu::TexelCopyTextureInfo {
texture: &diffuse_texture, texture: &diffuse_texture,
@ -428,20 +480,41 @@ struct MaterialProperties {
filter: wgpu::FilterMode, filter: wgpu::FilterMode,
} }
impl SimpleMaterial { impl Default for MaterialProperties {
fn new(renderer: &Renderer, base: &SimpleTexture, normal: &SimpleTexture, reflect: &SimpleTexture, config: MaterialProperties) -> SimpleMaterial { fn default() -> MaterialProperties {
let sampler = renderer.device.create_sampler(&wgpu::SamplerDescriptor { MaterialProperties {
address_mode_u: config.edge, edge: wgpu::AddressMode::Repeat,
address_mode_v: config.edge, filter: wgpu::FilterMode::Linear,
address_mode_w: config.edge, }
mag_filter: config.filter, }
min_filter: config.filter, }
impl MaterialProperties {
fn sampler(&self, device: &wgpu::Device) -> wgpu::Sampler {
device.create_sampler(&wgpu::SamplerDescriptor {
address_mode_u: self.edge,
address_mode_v: self.edge,
address_mode_w: self.edge,
mag_filter: self.filter,
min_filter: self.filter,
mipmap_filter: wgpu::MipmapFilterMode::Nearest, mipmap_filter: wgpu::MipmapFilterMode::Nearest,
..Default::default() ..Default::default()
}); })
let group = renderer.device.create_bind_group( }
&wgpu::BindGroupDescriptor { }
layout: &renderer.material_layout,
impl SimpleMaterial {
fn new(
device: &wgpu::Device,
layout: &wgpu::BindGroupLayout,
base: &SimpleTexture,
normal: &SimpleTexture,
reflect: &SimpleTexture,
config: MaterialProperties,
) -> SimpleMaterial {
let sampler = config.sampler(&device);
let group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: layout,
entries: &[ entries: &[
wgpu::BindGroupEntry { wgpu::BindGroupEntry {
binding: 0, binding: 0,
@ -461,11 +534,8 @@ impl SimpleMaterial {
}, },
], ],
label: Some("diffuse_bind_group"), label: Some("diffuse_bind_group"),
} });
); SimpleMaterial { group }
SimpleMaterial {
group,
}
} }
} }
@ -474,7 +544,7 @@ struct PoolError(String);
impl Display for PoolError { impl Display for PoolError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f,"{}",self.0) write!(f, "{}", self.0)
} }
} }
@ -493,7 +563,7 @@ impl SimpleTreeNode {
} else { } else {
for child in self.children.iter() { for child in self.children.iter() {
if let Some(object) = child.first_object() { if let Some(object) = child.first_object() {
return Some(object) return Some(object);
} }
} }
None None
@ -501,7 +571,7 @@ impl SimpleTreeNode {
} }
} }
type GltfVertexBufferKey = (Option<usize>,Option<usize>,Option<usize>,Option<usize>); type GltfVertexBufferKey = (Option<usize>, Option<usize>, Option<usize>, Option<usize>);
impl Renderer { impl Renderer {
const SIMPLE_RENDER_EYE_GROUP_POSITION: u32 = 0; const SIMPLE_RENDER_EYE_GROUP_POSITION: u32 = 0;
@ -514,25 +584,55 @@ impl Renderer {
id: self.id_count, id: self.id_count,
} }
} }
pub fn load_texture_from_bytes(&mut self, slice: impl AsRef<[u8]>) -> SimpleTexture { pub fn load_texture_from_bytes(
let image = image::load_from_memory(slice.as_ref()); &mut self,
slice: impl AsRef<[u8]>,
format: Option<image::ImageFormat>,
) -> SimpleTexture {
let image = if let Some(format) = format {
image::load_from_memory_with_format(slice.as_ref(), format)
} else {
image::load_from_memory(slice.as_ref())
};
if let Ok(data) = image { if let Ok(data) = image {
let data = data.into_rgba8(); let data = data.into_rgba8();
SimpleTexture::load(&self.device, &self.queue, data.as_bytes(), TextureProperties { SimpleTexture::load(
&self.device,
&self.queue,
data.as_bytes(),
TextureProperties {
width: data.width(), width: data.width(),
height: data.height(), height: data.height(),
}) },
)
} else { } else {
println!("failed to load texture! error: {:?}", image.unwrap_err());
self.default_texture.clone() self.default_texture.clone()
} }
} }
pub fn new_material(&mut self, base: &SimpleTexture, normal: &SimpleTexture, reflect: &SimpleTexture) -> Id<SimpleMaterial> { pub fn new_material(
self.new_id(SimpleMaterial::new(self, base, normal, reflect, MaterialProperties { &mut self,
base: &SimpleTexture,
normal: &SimpleTexture,
reflect: &SimpleTexture,
) -> Id<SimpleMaterial> {
self.new_id(SimpleMaterial::new(
&self.device,
&self.material_layout,
base,
normal,
reflect,
MaterialProperties {
edge: wgpu::AddressMode::Repeat, edge: wgpu::AddressMode::Repeat,
filter: wgpu::FilterMode::Linear, filter: wgpu::FilterMode::Linear,
})) },
))
} }
pub fn new_texture_from_gltf(&mut self, info: &gltf::texture::Texture, images: &Vec<gltf::image::Data>) -> SimpleTexture { pub fn new_texture_from_gltf(
&mut self,
info: &gltf::texture::Texture,
images: &Vec<gltf::image::Data>,
) -> SimpleTexture {
if let Some(image) = images.get(info.source().index()) { if let Some(image) = images.get(info.source().index()) {
let mut new_pixels = Vec::new(); let mut new_pixels = Vec::new();
let pixels: &Vec<u8>; let pixels: &Vec<u8>;
@ -546,15 +646,18 @@ impl Renderer {
} }
pixels = &new_pixels; pixels = &new_pixels;
} }
gltf::image::Format::R8G8B8A8 => { gltf::image::Format::R8G8B8A8 => pixels = &image.pixels,
pixels = &image.pixels _ => return self.default_texture.clone(),
} }
_ => return self.default_texture.clone() SimpleTexture::load(
} &self.device,
SimpleTexture::load(&self.device, &self.queue, pixels.as_slice(), TextureProperties { &self.queue,
pixels.as_slice(),
TextureProperties {
width: image.width, width: image.width,
height: image.height, height: image.height,
}) },
)
} else { } else {
self.default_texture.clone() self.default_texture.clone()
} }
@ -563,22 +666,47 @@ impl Renderer {
&mut self, &mut self,
primitive: gltf::Primitive, primitive: gltf::Primitive,
meshes: &mut HashMap<GltfVertexBufferKey, SimpleMesh>, meshes: &mut HashMap<GltfVertexBufferKey, SimpleMesh>,
buffers: &[gltf::buffer::Data] buffers: &[gltf::buffer::Data],
) -> Id<SimpleMesh> { ) -> Id<SimpleMesh> {
let position_index = primitive.get(&Semantic::Positions).and_then(|it| it.view()).and_then(|it| Some(it.buffer().index())); let position_index = primitive
let normals_index = primitive.get(&Semantic::Normals).and_then(|it| it.view()).and_then(|it| Some(it.buffer().index())); .get(&Semantic::Positions)
let tex_coords_index = primitive.get(&Semantic::TexCoords(0)).and_then(|it| it.view()).and_then(|it| Some(it.buffer().index())); .and_then(|it| it.view())
let indices_index = primitive.indices().and_then(|it| it.view()).and_then(|it| Some(it.buffer().index())); .and_then(|it| Some(it.buffer().index()));
let tangent_index = primitive.get(&Semantic::Tangents).and_then(|it| it.view()).and_then(|it| Some(it.buffer().index())); let normals_index = primitive
let key = (position_index,normals_index,tex_coords_index,indices_index); .get(&Semantic::Normals)
self.new_id(meshes.entry(key).or_insert_with(|| { .and_then(|it| it.view())
.and_then(|it| Some(it.buffer().index()));
let tex_coords_index = primitive
.get(&Semantic::TexCoords(0))
.and_then(|it| it.view())
.and_then(|it| Some(it.buffer().index()));
let indices_index = primitive
.indices()
.and_then(|it| it.view())
.and_then(|it| Some(it.buffer().index()));
let tangent_index = primitive
.get(&Semantic::Tangents)
.and_then(|it| it.view())
.and_then(|it| Some(it.buffer().index()));
let key = (
position_index,
normals_index,
tex_coords_index,
indices_index,
);
self.new_id(
meshes
.entry(key)
.or_insert_with(|| {
let mut tangents = false; let mut tangents = false;
let reader = primitive.reader(|buffer| Some(&buffers[buffer.index()])); let reader = primitive.reader(|buffer| Some(&buffers[buffer.index()]));
let mut vertex_data: Vec<SimpleVertex>; let mut vertex_data: Vec<SimpleVertex>;
if let Some(positions) = reader.read_positions() { if let Some(positions) = reader.read_positions() {
vertex_data = Vec::with_capacity(positions.len()); vertex_data = Vec::with_capacity(positions.len());
let mut normal = reader.read_normals().map(|it| it.into_iter()); let mut normal = reader.read_normals().map(|it| it.into_iter());
let mut tex_coord = reader.read_tex_coords(0).map(|it| it.into_f32().into_iter()); let mut tex_coord = reader
.read_tex_coords(0)
.map(|it| it.into_f32().into_iter());
let mut tangent = reader.read_tangents().map(|it| it.into_iter()); let mut tangent = reader.read_tangents().map(|it| it.into_iter());
tangents = tangent.is_some(); tangents = tangent.is_some();
for position in positions { for position in positions {
@ -588,46 +716,53 @@ impl Renderer {
if let Some(normal) = normals.next() { if let Some(normal) = normals.next() {
normal normal
} else { } else {
[0.0;3] [0.0; 3]
} }
} else { } else {
[0.0;3] [0.0; 3]
}, },
tex_coord: if let Some(ref mut tex_coords) = tex_coord { tex_coord: if let Some(ref mut tex_coords) = tex_coord {
tex_coords.next() tex_coords.next()
} else { } else {
None None
}.unwrap_or([0.0;2]), }
tangent: [0.0;3], // todo: tangent from model .unwrap_or([0.0; 2]),
bitangent: [0.0;3], tangent: [0.0; 3], // todo: tangent from model
bitangent: [0.0; 3],
}) })
} }
} else { } else {
vertex_data = Vec::new(); vertex_data = Vec::new();
} }
let vertex_buffer = self.device.create_buffer_init( let vertex_buffer =
&wgpu::util::BufferInitDescriptor { self.device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Vertex Buffer"), label: Some("Vertex Buffer"),
contents: bytemuck::cast_slice(vertex_data.as_slice()), contents: bytemuck::cast_slice(vertex_data.as_slice()),
usage: wgpu::BufferUsages::VERTEX, usage: wgpu::BufferUsages::VERTEX,
} });
); let vertices_result = (vertex_buffer, vertex_data.len() as u32);
let vertices_result = (vertex_buffer,vertex_data.len() as u32);
let indices_result = if let Some(indices) = reader.read_indices() { let indices_result = if let Some(indices) = reader.read_indices() {
let index_data: Vec<u32> = indices.into_u32().collect(); let index_data: Vec<u32> = indices.into_u32().collect();
Some((self.device.create_buffer_init(&wgpu::util::BufferInitDescriptor { Some((
self.device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Index Buffer"), label: Some("Index Buffer"),
contents: bytemuck::cast_slice(index_data.as_slice()), contents: bytemuck::cast_slice(index_data.as_slice()),
usage: wgpu::BufferUsages::INDEX, usage: wgpu::BufferUsages::INDEX,
}), index_data.len() as u32)) }),
index_data.len() as u32,
))
} else { } else {
None None
}; };
SimpleMesh { SimpleMesh {
indices: indices_result, indices: indices_result,
vertices: vertices_result vertices: vertices_result,
} }
}).clone()) })
.clone(),
)
} }
pub fn load_node_from_gltf( pub fn load_node_from_gltf(
&mut self, &mut self,
@ -640,7 +775,7 @@ impl Renderer {
let mut tree_node = SimpleTreeNode { let mut tree_node = SimpleTreeNode {
object: None, object: None,
children: Vec::new(), children: Vec::new(),
name: node.name().unwrap_or("Node").to_string() name: node.name().unwrap_or("Node").to_string(),
}; };
if let Some(mesh) = node.mesh() { if let Some(mesh) = node.mesh() {
let len = mesh.primitives().len(); let len = mesh.primitives().len();
@ -652,25 +787,34 @@ impl Renderer {
let rough = pbr.roughness_factor(); let rough = pbr.roughness_factor();
let light = primitive.material().emissive_factor(); let light = primitive.material().emissive_factor();
let base = match pbr.base_color_texture() { let base = match pbr.base_color_texture() {
Some(info) => textures.entry(info.texture().source().index()).or_insert_with(|| self.new_texture_from_gltf(&info.texture(), &images)).clone(), Some(info) => textures
None => self.default_texture.clone() .entry(info.texture().source().index())
.or_insert_with(|| self.new_texture_from_gltf(&info.texture(), &images))
.clone(),
None => self.default_texture.clone(),
}; };
let reflect = match pbr.metallic_roughness_texture() { let reflect = match pbr.metallic_roughness_texture() {
Some(info) => textures.entry(info.texture().source().index()).or_insert_with(|| self.new_texture_from_gltf(&info.texture(), &images)).clone(), Some(info) => textures
None => self.default_texture.clone() .entry(info.texture().source().index())
.or_insert_with(|| self.new_texture_from_gltf(&info.texture(), &images))
.clone(),
None => self.default_texture.clone(),
}; };
let normal = match material.normal_texture() { let normal = match material.normal_texture() {
Some(info) => textures.entry(info.texture().source().index()).or_insert_with(|| self.new_texture_from_gltf(&info.texture(), &images)).clone(), Some(info) => textures
None => self.default_texture.clone() .entry(info.texture().source().index())
.or_insert_with(|| self.new_texture_from_gltf(&info.texture(), &images))
.clone(),
None => self.default_texture.clone(),
}; };
let material = self.new_material(&base, &normal, &reflect); let material = self.new_material(&base, &normal, &reflect);
let mesh = self.new_mesh_from_gltf(primitive,meshes,buffers); let mesh = self.new_mesh_from_gltf(primitive, meshes, buffers);
let object = SimpleObject(Rc::new(RefCell::new(SimpleObjectData { let object = SimpleObject(Rc::new(RefCell::new(SimpleObjectData {
model: Some(SimpleModelData { model: Some(SimpleModelData {
instance: SimpleModelInstance { instance: SimpleModelInstance {
transform: Mat4::default(), transform: Mat4::default(),
color: Vec4::from_array(color), color: Vec4::from_array(color),
lights: [0;16], lights: [0; 16],
point_lights: 0, point_lights: 0,
spot_lights: 0, spot_lights: 0,
metal, metal,
@ -691,13 +835,15 @@ impl Renderer {
tree_node.children.push(SimpleTreeNode { tree_node.children.push(SimpleTreeNode {
object: Some(object), object: Some(object),
children: Vec::new(), children: Vec::new(),
name: "Primitive".to_string() name: "Primitive".to_string(),
}) })
} }
} }
} }
for node in node.children() { for node in node.children() {
tree_node.children.push(self.load_node_from_gltf(node,meshes,textures,images,buffers)); tree_node
.children
.push(self.load_node_from_gltf(node, meshes, textures, images, buffers));
} }
tree_node tree_node
} }
@ -717,7 +863,13 @@ impl Renderer {
name: scene.name().unwrap_or("Scene").to_string(), name: scene.name().unwrap_or("Scene").to_string(),
}; };
for node in scene.nodes() { for node in scene.nodes() {
scene_node.children.push(self.load_node_from_gltf(node, &mut meshes, &mut textures, &images, &buffers)); scene_node.children.push(self.load_node_from_gltf(
node,
&mut meshes,
&mut textures,
&images,
&buffers,
));
} }
root.children.push(scene_node) root.children.push(scene_node)
} }
@ -728,6 +880,9 @@ impl Renderer {
self.surface.configure(&self.device, &self.config); self.surface.configure(&self.device, &self.config);
self.eye.resize(width, height); self.eye.resize(width, height);
} }
pub fn set_skybox(&mut self, skybox: SimpleTexture) {
self.eye.skybox(&self.device, skybox);
}
pub async fn new(window: &Arc<Window>) -> anyhow::Result<Self> { pub async fn new(window: &Arc<Window>) -> anyhow::Result<Self> {
let bounds = window.inner_size(); let bounds = window.inner_size();
let width = bounds.width; let width = bounds.width;
@ -793,16 +948,22 @@ impl Renderer {
desired_maximum_frame_latency: 2, desired_maximum_frame_latency: 2,
}; };
let eye = Eye::new(&device, width, height); let shader =
device.create_shader_module(wgpu::include_wgsl!("../assets/SimpleShader.wgsl"));
let shader = device.create_shader_module(wgpu::include_wgsl!("../assets/SimpleShader.wgsl")); let default_texture = SimpleTexture::load(
&device,
let texture = SimpleTexture::load(&device, &queue, [255,255,255,255], TextureProperties { &queue,
[0, 0, 255, 255],
TextureProperties {
width: 1, width: 1,
height: 1, height: 1,
}); },
);
let texture_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { let eye = Eye::new(&device, width, height, default_texture.clone());
let texture_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[ entries: &[
wgpu::BindGroupLayoutEntry { wgpu::BindGroupLayoutEntry {
binding: 0, binding: 0,
@ -839,30 +1000,24 @@ impl Renderer {
sample_type: wgpu::TextureSampleType::Float { filterable: true }, sample_type: wgpu::TextureSampleType::Float { filterable: true },
}, },
count: None, count: None,
} },
], ],
label: Some("texture_bind_group_layout"), label: Some("texture_bind_group_layout"),
}); });
let render_pipeline_layout = let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Render Pipeline Layout"), label: Some("Render Pipeline Layout"),
bind_group_layouts: &[ bind_group_layouts: &[Some(&eye.layout), Some(&texture_bind_group_layout)],
Some(&eye.layout),
Some(&texture_bind_group_layout),
],
immediate_size: 0, immediate_size: 0,
}); });
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { let instance_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Render Pipeline"), label: Some("Render Pipeline"),
layout: Some(&render_pipeline_layout), layout: Some(&pipeline_layout),
vertex: wgpu::VertexState { vertex: wgpu::VertexState {
module: &shader, module: &shader,
entry_point: Some("vs_main"), entry_point: Some("vs_main"),
buffers: &[ buffers: &[SimpleVertex::desc(), SimpleInstances::desc()],
SimpleVertex::desc(),SimpleInstances::desc(),
],
compilation_options: wgpu::PipelineCompilationOptions::default(), compilation_options: wgpu::PipelineCompilationOptions::default(),
}, },
fragment: Some(wgpu::FragmentState { fragment: Some(wgpu::FragmentState {
@ -877,7 +1032,7 @@ impl Renderer {
})], })],
compilation_options: wgpu::PipelineCompilationOptions::default(), compilation_options: wgpu::PipelineCompilationOptions::default(),
}), }),
primitive: wgpu::PrimitiveState { primitive: Default::default(), /*wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList, topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None, strip_index_format: None,
front_face: wgpu::FrontFace::Ccw, front_face: wgpu::FrontFace::Ccw,
@ -885,12 +1040,12 @@ impl Renderer {
polygon_mode: wgpu::PolygonMode::Fill, polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false, unclipped_depth: false,
conservative: false, conservative: false,
}, }*/
depth_stencil: Some(wgpu::DepthStencilState { depth_stencil: Some(wgpu::DepthStencilState {
stencil: wgpu::StencilState::default(),
format: wgpu::TextureFormat::Depth32Float, format: wgpu::TextureFormat::Depth32Float,
depth_write_enabled: Some(true), depth_write_enabled: Some(true),
depth_compare: Some(wgpu::CompareFunction::Less), depth_compare: Some(wgpu::CompareFunction::Less),
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(), bias: wgpu::DepthBiasState::default(),
}), }),
multisample: wgpu::MultisampleState { multisample: wgpu::MultisampleState {
@ -902,7 +1057,45 @@ impl Renderer {
cache: None, cache: None,
}); });
let size = wgpu::Extent3d { // 2. //todo: use a pipeline cache!
let sky_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Sky Pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_sky"),
compilation_options: Default::default(),
buffers: &[],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_sky"),
compilation_options: Default::default(),
targets: &[Some(wgpu::ColorTargetState {
// 4.
format: config.format,
blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrites::ALL,
})],
}),
primitive: wgpu::PrimitiveState {
front_face: wgpu::FrontFace::Cw,
..Default::default()
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth32Float,
depth_write_enabled: Some(false),
depth_compare: Some(wgpu::CompareFunction::LessEqual),
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
});
let size = wgpu::Extent3d {
// 2.
width: config.width.max(1), width: config.width.max(1),
height: config.height.max(1), height: config.height.max(1),
depth_or_array_layers: 1, depth_or_array_layers: 1,
@ -920,8 +1113,8 @@ impl Renderer {
}; };
let depth_texture = device.create_texture(&desc); let depth_texture = device.create_texture(&desc);
let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default()); let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
let depth_sampler = device.create_sampler( let depth_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
&wgpu::SamplerDescriptor { // 4. // 4.
address_mode_u: wgpu::AddressMode::ClampToEdge, address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge, address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge, address_mode_w: wgpu::AddressMode::ClampToEdge,
@ -932,31 +1125,37 @@ impl Renderer {
lod_min_clamp: 0.0, lod_min_clamp: 0.0,
lod_max_clamp: 100.0, lod_max_clamp: 100.0,
..Default::default() ..Default::default()
} });
);
let instances = SimpleInstances::new(&device,&queue); let instances = SimpleInstances::new(&device);
let staging_belt = wgpu::util::StagingBelt::new(device.clone(), 0x1024); let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
let buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Vertex Buffer"), label: Some("Vertex Buffer"),
contents: bytemuck::cast_slice(&DEFAULT_VERTICES), contents: bytemuck::cast_slice(&DEFAULT_VERTICES),
usage: wgpu::BufferUsages::VERTEX, usage: wgpu::BufferUsages::VERTEX,
} });
let default_material = SimpleMaterial::new(
&device,
&texture_bind_group_layout,
&default_texture,
&default_texture,
&default_texture,
MaterialProperties::default(),
); );
Ok(Renderer { Ok(Renderer {
id_count: 0, id_count: 0,
material_layout: texture_bind_group_layout, material_layout: texture_bind_group_layout,
default_texture: texture, default_texture,
default_material,
depth_texture: SimpleTexture { depth_texture: SimpleTexture {
texture: depth_texture, texture: depth_texture,
view: depth_view, view: depth_view,
}, },
instances, instances,
pipeline, sky_pipeline,
instance_pipeline,
surface, surface,
config, config,
device, device,
@ -966,7 +1165,6 @@ impl Renderer {
} }
pub(crate) fn render(&mut self, window: &Arc<Window>) -> anyhow::Result<()> { pub(crate) fn render(&mut self, window: &Arc<Window>) -> anyhow::Result<()> {
window.request_redraw(); window.request_redraw();
let output = match self.surface.get_current_texture() { let output = match self.surface.get_current_texture() {
wgpu::CurrentSurfaceTexture::Success(surface_texture) => surface_texture, wgpu::CurrentSurfaceTexture::Success(surface_texture) => surface_texture,
wgpu::CurrentSurfaceTexture::Suboptimal(surface_texture) => { wgpu::CurrentSurfaceTexture::Suboptimal(surface_texture) => {
@ -993,7 +1191,7 @@ impl Renderer {
.texture .texture
.create_view(&wgpu::TextureViewDescriptor::default()); .create_view(&wgpu::TextureViewDescriptor::default());
let program = self.instances.write_instances(&self.device,&self.queue); let program = self.instances.write_instances(&self.device, &self.queue);
let mut encoder = self let mut encoder = self
.device .device
@ -1009,7 +1207,12 @@ impl Renderer {
resolve_target: None, resolve_target: None,
depth_slice: None, depth_slice: None,
ops: wgpu::Operations { ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(Default::default()), load: wgpu::LoadOp::Clear(wgpu::Color {
r: 0.5,
g: 0.6,
b: 0.8,
a: 1.0,
}),
store: wgpu::StoreOp::Store, store: wgpu::StoreOp::Store,
}, },
})], })],
@ -1026,10 +1229,15 @@ impl Renderer {
multiview_mask: None, multiview_mask: None,
}); });
pass.set_pipeline(&self.pipeline); pass.set_pipeline(&self.instance_pipeline);
pass.set_bind_group(0, &self.eye.group, &[]); pass.set_bind_group(0, &self.eye.group, &[]);
pass.set_vertex_buffer(1, self.instances.instance_buffer.slice(..)); pass.set_vertex_buffer(1, self.instances.instance_buffer.slice(..));
program.render(&mut pass); program.render(&mut pass);
pass.set_bind_group(1, &self.default_material.group, &[]);
pass.set_pipeline(&self.sky_pipeline);
pass.draw(0..6, 0..1);
} }
self.queue.submit(Some(encoder.finish())); self.queue.submit(Some(encoder.finish()));

View file

@ -1,10 +1,10 @@
use crate::render::{Renderer, SimpleLightData, SimpleModelData};
use glam::{DVec3, IVec3, Mat4, UVec3, Vec3, Vec4Swizzles};
use std::cell::RefCell; use std::cell::RefCell;
use std::hash::{BuildHasherDefault, Hash, Hasher}; use std::hash::{BuildHasherDefault, Hash, Hasher};
use std::ops::{Div, Mul}; use std::ops::{Div, Mul};
use std::rc::Rc; use std::rc::Rc;
use glam::{DVec3, IVec3, Mat4, UVec3, Vec3, Vec4Swizzles};
use wgpu::naga::{FastHashMap, FastHashSet}; use wgpu::naga::{FastHashMap, FastHashSet};
use crate::render::{SimpleModelData, SimpleLightData, Renderer};
#[derive(Clone)] #[derive(Clone)]
pub enum Shape { pub enum Shape {
@ -59,7 +59,7 @@ impl SimpleObject {
impl PartialEq for SimpleObject { impl PartialEq for SimpleObject {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.0,&other.0) Rc::ptr_eq(&self.0, &other.0)
} }
} }
@ -83,7 +83,7 @@ struct Block {
velocity: Vec3, velocity: Vec3,
material: u8, material: u8,
interests: FastHashSet<Interest>, interests: FastHashSet<Interest>,
blocks: [Option<Box<Block>>;64], blocks: [Option<Box<Block>>; 64],
} }
const TREE_ATTACK: usize = 4; const TREE_ATTACK: usize = 4;
@ -107,11 +107,11 @@ impl Block {
let index = (rel.x + rel.y * 4 + rel.z * 16) as usize; let index = (rel.x + rel.y * 4 + rel.z * 16) as usize;
match self.blocks[index] { match self.blocks[index] {
Some(ref mut block) => { Some(ref mut block) => {
block.place_pos(interest,new_pos,rad,cs); block.place_pos(interest, new_pos, rad, cs);
}, }
None => { None => {
let mut block = Box::new(Block::new()); let mut block = Box::new(Block::new());
block.place_pos(interest,new_pos,rad,cs); block.place_pos(interest, new_pos, rad, cs);
self.blocks[index] = Some(block); self.blocks[index] = Some(block);
} }
} }
@ -123,25 +123,26 @@ impl Block {
match self.debug { match self.debug {
Some(ref mut debug) => { Some(ref mut debug) => {
if value { if value {
} else { } else {
} }
}, }
None => { None => {
if value { if value {
} else { } else {
} }
} }
} }
for maybe_block in self.blocks.iter_mut() {
if let Some(block) = maybe_block {
block.debug_step(value)
}
}
} }
} }
pub struct World { pub struct World {
chunk_size: u32, chunk_size: u32,
map: FastHashMap<IVec3,Block>, map: FastHashMap<IVec3, Block>,
pub renderer: Option<Renderer>, pub renderer: Option<Renderer>,
debug_world_map: bool, debug_world_map: bool,
debug_world_map_object: Option<SimpleObject>, debug_world_map_object: Option<SimpleObject>,
@ -159,7 +160,12 @@ impl World {
} }
pub fn add_renderer(&mut self, renderer: Renderer) { pub fn add_renderer(&mut self, renderer: Renderer) {
self.renderer = Some(renderer); self.renderer = Some(renderer);
self.debug_world_map_object = self.renderer.as_mut().unwrap().load_from_gltf(include_bytes!("../assets/debug.glb")).first_object() 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) { pub fn add_object(&mut self, object: SimpleObject) {
self.place(Interest::Object(object.clone())); self.place(Interest::Object(object.clone()));
@ -170,12 +176,8 @@ impl World {
pub fn set_debug(&mut self, value: bool) { pub fn set_debug(&mut self, value: bool) {
self.debug_world_map = value; self.debug_world_map = value;
} }
pub fn light_step(&mut self) { pub fn light_step(&mut self) {}
pub fn object_step(&mut self) {}
}
pub fn object_step(&mut self) {
}
pub fn debug_step(&mut self) { pub fn debug_step(&mut self) {
self.light_step(); self.light_step();
self.object_step(); self.object_step();
@ -189,7 +191,7 @@ impl World {
for x in (pos.x - rad).div(cs) as i32..=(pos.x + rad).div(cs).ceil() as i32 { 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 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 { 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 = IVec3::new(x, y, z);
let block_pos_f32 = block_pos.as_vec3(); let block_pos_f32 = block_pos.as_vec3();
if block_pos_f32.distance_squared(pos) < rad + c_rad { if block_pos_f32.distance_squared(pos) < rad + c_rad {
self.map.entry(block_pos).or_insert_with(|| { self.map.entry(block_pos).or_insert_with(|| {
@ -208,16 +210,19 @@ impl World {
} }
} }
fn place(&mut self, interest: Interest) { fn place(&mut self, interest: Interest) {
let (pos,rad) = match &interest { let (pos, rad) = match &interest {
Interest::Light(light) => { Interest::Light(light) => {
let light = light.0.borrow(); let light = light.0.borrow();
(light.instance.location.xyz(),light.instance.color.length()) (light.instance.location.xyz(), light.instance.color.length())
}, }
Interest::Object(object) => { Interest::Object(object) => {
let collider = &object.0.borrow().collider; let collider = &object.0.borrow().collider;
(collider.transform.to_scale_rotation_translation().2,collider.radius) (
}, collider.transform.to_scale_rotation_translation().2,
collider.radius,
)
}
}; };
self.place_pos(interest,pos,rad); self.place_pos(interest, pos, rad);
} }
} }