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

This reverts commit 3231ed9190.
This commit is contained in:
Christian Lincoln 2026-09-03 22:55:16 +01:00
parent 3231ed9190
commit 6685277e29
10 changed files with 1438 additions and 1818 deletions

12
Cargo.lock generated
View file

@ -349,15 +349,6 @@ 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"
@ -1105,9 +1096,6 @@ 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

Binary file not shown.

View file

@ -1,9 +1,7 @@
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;
@ -16,6 +14,9 @@ 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>,
@ -40,27 +41,19 @@ pub struct AppState {
clients: Vec<SimpleObject>, clients: Vec<SimpleObject>,
} }
const BLOCKS: i32 = 1; const BLOCKS: i32 = 50;
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 let file = world.renderer.as_mut().unwrap().load_from_gltf( include_bytes!("assets/cube.glb"));
.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"));
@ -71,16 +64,9 @@ 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( model.model.as_mut().unwrap().instance.transform = Mat4::from_translation(Vec3::new(-x as f32 * 3.0,0.0,-y as f32 * 3.0))
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( 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);
0.3,
(x + BLOCKS) as f32 / BLOCKS as f32,
(y + BLOCKS) as f32 / BLOCKS as f32,
1.0,
);
} }
clients.push(block) clients.push(block)
} }
@ -101,6 +87,7 @@ impl AppState {
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);
} }
} }
@ -112,7 +99,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
} }
@ -123,10 +110,7 @@ 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( self.world.renderer.as_mut().unwrap().eye.rotate(position.x as f32 - self.controller.mouse.x, position.y as f32 - self.controller.mouse.y);
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);
} }
@ -261,13 +245,7 @@ impl ApplicationHandler<AppState> for App {
movement.y -= 1.0; movement.y -= 1.0;
} }
state state.world.renderer.as_mut().unwrap().eye.control(movement * 0.1);
.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) => {
@ -277,24 +255,13 @@ impl ApplicationHandler<AppState> for App {
} }
} }
for object in state.clients.iter() { for object in state.clients.iter() {
object object.0.borrow_mut().model.as_mut().unwrap().instance.transform *= Mat4::from_rotation_translation(
.0
.borrow_mut()
.model
.as_mut()
.unwrap()
.instance
.transform *= Mat4::from_rotation_translation(
Quat::from_euler(EulerRot::XYZ,0.001,-0.001,0.001), Quat::from_euler(EulerRot::XYZ,0.001,-0.001,0.001),
Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0,0.0,0.0)
); );
} }
} }
WindowEvent::MouseInput { WindowEvent::MouseInput { button, state: element, .. } => state.handle_mouse_button(button,element),
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,26 +4,16 @@ struct Environment {
dir: vec4<f32>, dir: vec4<f32>,
} }
struct Eye { struct View {
// 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> eye: Eye; var<uniform> view: View;
@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>,
@ -70,7 +60,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 = eye.proj * eye.view * world_position; out.clip_position = view.view * world_position;
return out; return out;
} }
@ -85,79 +75,23 @@ 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 diffuse_color = object_color.xyz; let tangent_normal = object_normal.xyz * 2.0 - 1.0;
let specular_color = vec3<f32>(0.0,0.0,0.0); let light_dir = normalize(environment.dir.xyz);
let reflection = sky_aspect(reflect(normalize(in.world_position-translation(eye.frame).xyz),normalize(in.world_normal))); let view_dir = normalize(view.frame[3].xyz - in.world_position);
let half_dir = normalize(view_dir + light_dir);
//let result = (environment.ambient.xyz + diffuse_color + specular_color) * object_color.xyz; let diffuse_strength = max(dot(tangent_normal, light_dir), 0.0);
let diffuse_color = environment.light.xyz * diffuse_strength;
//let light_dir = normalize(environment.dir.xyz); let specular_strength = pow(max(dot(tangent_normal, half_dir), 0.0), 32.0);
//let view_dir = normalize(eye.frame[3].xyz - in.world_position); let specular_color = specular_strength * environment.light.xyz;
//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>(reflection.xyz,object_color.a); return vec4<f32>(result.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);
} }

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

BIN
src/assets/test.png Executable file

Binary file not shown.

After

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 glam::camera::lh::proj::directx::perspective; use env_logger::Env;
use glam::{Affine3A, EulerRot, Mat3A, Mat4, Vec3, Vec4}; use glam::{Affine3A, EulerRot, Mat3A, Mat4, Vec3, Vec4};
use wgpu::util::DeviceExt; use glam::camera::lh::proj::directx::perspective;
use wgpu::{Device, Queue}; use wgpu::{Device, Queue};
use wgpu::util::DeviceExt;
pub(crate) struct Eye { pub(crate) struct Eye {
pub(crate) frame: Affine3A, pub(crate) frame: Affine3A,
@ -13,53 +13,39 @@ 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) camera_buffer: wgpu::Buffer, pub(crate) 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)]
pub struct Environment { struct Environment {
ambient: Vec4, ambient: Vec4,
light: Vec4, light: Vec4,
dir: Vec4, dir: Vec4,
} }
impl Eye { impl Eye {
pub(crate) fn write(&mut self, queue: &Queue) { pub(crate) fn view(&self) -> Mat4 {
let camera = Mat4::from_mat3_translation(
self.frame.matrix3.into(),
Vec3::from(self.frame.translation),
);
let projection = perspective(self.fov_y, self.aspect_ratio, self.z_near, self.z_far); let projection = perspective(self.fov_y, self.aspect_ratio, self.z_near, self.z_far);
queue.write_buffer( projection * self.frame.inverse()
&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 { pub(crate) fn write(&mut self, queue: &Queue) {
let camera_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { queue.write_buffer(&self.buffer,0,bytemuck::cast_slice(&[
self.view(),
Mat4::from_mat3_translation(self.frame.matrix3.into(), 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"), label: Some("Camera Buffer"),
contents: bytemuck::cast_slice(&[ contents: bytemuck::cast_slice(&[Mat4::from_translation(Vec3::new(0.0,2.0,-8.0)),Mat4::IDENTITY]),
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, 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 {
@ -68,11 +54,13 @@ impl Eye {
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(&wgpu::util::BufferInitDescriptor { let environment_buffer = device.create_buffer_init(
&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: &[
@ -95,28 +83,25 @@ 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 = Eye::bind_group(&layout, device, &camera_buffer, &environment_buffer, skybox); let group = device.create_bind_group(&wgpu::BindGroupDescriptor {
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,
@ -124,54 +109,13 @@ 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,
camera_buffer, 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
} }

View file

@ -1,23 +1,23 @@
pub mod eye; pub mod eye;
use crate::render::eye::Eye;
use crate::world::{Shape, SimpleColliderData, SimpleLight, SimpleObject, SimpleObjectData};
use bytemuck::{Pod, Zeroable};
use glam::prelude::*;
use gltf::Semantic;
use image::EncodableLayout;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use glam::prelude::*;
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] = [];
@ -62,15 +62,14 @@ 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: objects: FastHashMap<Id<SimpleMesh>,FastHashMap<Id<SimpleMaterial>,FastHashSet<SimpleObject>>>,
FastHashMap<Id<SimpleMesh>, FastHashMap<Id<SimpleMaterial>, FastHashSet<SimpleObject>>>,
lights: FastHashMap<SimpleLight,usize>, 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>);
@ -87,11 +86,9 @@ 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) => pass.set_bind_group( SimpleRenderCode::Material(material) => {
Renderer::SIMPLE_RENDER_TEXTURE_GROUP_POSITION, pass.set_bind_group(Renderer::SIMPLE_RENDER_TEXTURE_GROUP_POSITION,&material,&[])
&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 {
@ -121,10 +118,8 @@ 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()) .entry(model.mesh.clone()).or_insert(FastHashMap::with_hasher(BuildHasherDefault::new()))
.or_insert(FastHashMap::with_hasher(BuildHasherDefault::new())) .entry(model.material.clone()).or_insert(FastHashSet::with_hasher(BuildHasherDefault::new()))
.entry(model.material.clone())
.or_insert(FastHashSet::with_hasher(BuildHasherDefault::new()))
.insert(object.clone()); .insert(object.clone());
} }
} }
@ -133,10 +128,8 @@ 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()) .entry(model.mesh.clone()).or_insert(FastHashMap::with_hasher(BuildHasherDefault::new()))
.or_insert(FastHashMap::with_hasher(BuildHasherDefault::new())) .entry(model.material.clone()).or_insert(FastHashSet::with_hasher(BuildHasherDefault::new()))
.entry(model.material.clone())
.or_insert(FastHashSet::with_hasher(BuildHasherDefault::new()))
.remove(&object); .remove(&object);
} }
} }
@ -151,12 +144,7 @@ impl SimpleInstances {
self.lights.remove(light); self.lights.remove(light);
} }
pub fn reallocate_buffer( pub fn reallocate_buffer(device: &wgpu::Device, queue: &wgpu::Queue, buffer: &mut wgpu::Buffer, count: usize, item_size: usize) {
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;
@ -184,82 +172,51 @@ impl SimpleInstances {
wgpu::BufferSize::new(self.instance_buffer.size()).unwrap() wgpu::BufferSize::new(self.instance_buffer.size()).unwrap()
).unwrap(); ).unwrap();
*/ */
SimpleInstances::reallocate_buffer( SimpleInstances::reallocate_buffer(device, queue, &mut self.light_buffer, self.light_count, size_of::<SimpleLight>());
device, let mut buffer = queue.write_buffer_with(
&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 buffer.slice(begin..begin + stride).copy_from_slice(bytemuck::cast_slice(&[light.0.borrow().instance]));
.slice(begin..begin + stride)
.copy_from_slice(bytemuck::cast_slice(&[light.0.borrow().instance]));
} }
} }
fn write_instances( pub fn write_instances(&mut self, device: &wgpu::Device, queue: &wgpu::Queue) -> SimpleRenderProgram {
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
) -> SimpleRenderProgram {
let mut program = SimpleRenderProgram::new(); let mut program = SimpleRenderProgram::new();
SimpleInstances::reallocate_buffer( SimpleInstances::reallocate_buffer(device, queue, &mut self.instance_buffer, self.instance_count, size_of::<SimpleModelInstance>());
device, let mut buffer = queue.write_buffer_with(
&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( program.push(SimpleRenderCode::Mesh(mesh.it.vertices.clone(), mesh.it.indices.clone()));
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 buffer.slice(begin .. begin + stride).copy_from_slice(bytemuck::cast_slice(&[object.0.borrow().model.as_ref().unwrap().instance]));
.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: &[ attributes: &[ // todo: is this too big?
// todo: is this too big?
wgpu::VertexAttribute { wgpu::VertexAttribute {
offset: 0, offset: 0,
shader_location: 4, shader_location: 4,
@ -304,27 +261,25 @@ impl SimpleInstances {
} }
} }
pub fn new(device: &wgpu::Device) -> SimpleInstances { pub fn new(device: &wgpu::Device, queue: &wgpu::Queue) -> 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) size: (size_of::<SimpleModelInstance>() * SimpleInstances::MIN_SIZE as usize) as wgpu::BufferAddress,
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) size: (size_of::<SimpleLightInstance>() * SimpleInstances::MIN_SIZE as usize) as wgpu::BufferAddress,
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,
@ -347,9 +302,7 @@ 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,
default_material: SimpleMaterial, pipeline: wgpu::RenderPipeline,
sky_pipeline: wgpu::RenderPipeline,
instance_pipeline: wgpu::RenderPipeline,
depth_texture: SimpleTexture, depth_texture: SimpleTexture,
pub(crate) instances: SimpleInstances, pub(crate) instances: SimpleInstances,
} }
@ -384,8 +337,8 @@ 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,
}, }
], ]
} }
} }
} }
@ -395,28 +348,23 @@ pub struct SimpleMesh {
vertices: (wgpu::Buffer, u32), vertices: (wgpu::Buffer, u32),
} }
#[derive(Debug, Clone, Hash, Eq, PartialEq)] #[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct SimpleTexture { pub(crate) struct SimpleTexture {
texture: wgpu::Texture, texture: wgpu::Texture,
view: wgpu::TextureView, view: wgpu::TextureView,
} }
pub struct TextureProperties { struct TextureProperties {
width: u32, width: u32,
height: u32, height: u32,
} }
// todo: use texture compression!
impl SimpleTexture { impl SimpleTexture {
pub fn load( pub fn load(device: &Device, queue: &Queue, slice: impl AsRef<[u8]>, properties: TextureProperties) -> SimpleTexture {
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(&wgpu::TextureDescriptor { let diffuse_texture = device.create_texture(
&wgpu::TextureDescriptor {
size, size,
mip_level_count: 1, mip_level_count: 1,
sample_count: 1, sample_count: 1,
@ -425,9 +373,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 = );
diffuse_texture.create_view(&wgpu::TextureViewDescriptor::default()); let diffuse_texture_view = diffuse_texture.create_view(&wgpu::TextureViewDescriptor::default());
queue.write_texture( queue.write_texture(
wgpu::TexelCopyTextureInfo { wgpu::TexelCopyTextureInfo {
texture: &diffuse_texture, texture: &diffuse_texture,
@ -480,41 +428,20 @@ struct MaterialProperties {
filter: wgpu::FilterMode, filter: wgpu::FilterMode,
} }
impl Default for MaterialProperties { impl SimpleMaterial {
fn default() -> MaterialProperties { fn new(renderer: &Renderer, base: &SimpleTexture, normal: &SimpleTexture, reflect: &SimpleTexture, config: MaterialProperties) -> SimpleMaterial {
MaterialProperties { let sampler = renderer.device.create_sampler(&wgpu::SamplerDescriptor {
edge: wgpu::AddressMode::Repeat, address_mode_u: config.edge,
filter: wgpu::FilterMode::Linear, address_mode_v: config.edge,
} 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,
@ -534,8 +461,11 @@ impl SimpleMaterial {
}, },
], ],
label: Some("diffuse_bind_group"), label: Some("diffuse_bind_group"),
}); }
SimpleMaterial { group } );
SimpleMaterial {
group,
}
} }
} }
@ -563,7 +493,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
@ -584,55 +514,25 @@ impl Renderer {
id: self.id_count, id: self.id_count,
} }
} }
pub fn load_texture_from_bytes( pub fn load_texture_from_bytes(&mut self, slice: impl AsRef<[u8]>) -> SimpleTexture {
&mut self, let image = image::load_from_memory(slice.as_ref());
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( SimpleTexture::load(&self.device, &self.queue, data.as_bytes(), TextureProperties {
&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( pub fn new_material(&mut self, base: &SimpleTexture, normal: &SimpleTexture, reflect: &SimpleTexture) -> Id<SimpleMaterial> {
&mut self, self.new_id(SimpleMaterial::new(self, base, normal, reflect, MaterialProperties {
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( pub fn new_texture_from_gltf(&mut self, info: &gltf::texture::Texture, images: &Vec<gltf::image::Data>) -> SimpleTexture {
&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>;
@ -646,18 +546,15 @@ impl Renderer {
} }
pixels = &new_pixels; pixels = &new_pixels;
} }
gltf::image::Format::R8G8B8A8 => pixels = &image.pixels, gltf::image::Format::R8G8B8A8 => {
_ => return self.default_texture.clone(), pixels = &image.pixels
} }
SimpleTexture::load( _ => return self.default_texture.clone()
&self.device, }
&self.queue, SimpleTexture::load(&self.device, &self.queue, pixels.as_slice(), TextureProperties {
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()
} }
@ -666,47 +563,22 @@ 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 let position_index = primitive.get(&Semantic::Positions).and_then(|it| it.view()).and_then(|it| Some(it.buffer().index()));
.get(&Semantic::Positions) let normals_index = primitive.get(&Semantic::Normals).and_then(|it| it.view()).and_then(|it| Some(it.buffer().index()));
.and_then(|it| it.view()) let tex_coords_index = primitive.get(&Semantic::TexCoords(0)).and_then(|it| it.view()).and_then(|it| Some(it.buffer().index()));
.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 normals_index = primitive let tangent_index = primitive.get(&Semantic::Tangents).and_then(|it| it.view()).and_then(|it| Some(it.buffer().index()));
.get(&Semantic::Normals) let key = (position_index,normals_index,tex_coords_index,indices_index);
.and_then(|it| it.view()) self.new_id(meshes.entry(key).or_insert_with(|| {
.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 let mut tex_coord = reader.read_tex_coords(0).map(|it| it.into_f32().into_iter());
.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 {
@ -725,8 +597,7 @@ impl Renderer {
tex_coords.next() tex_coords.next()
} else { } else {
None None
} }.unwrap_or([0.0;2]),
.unwrap_or([0.0; 2]),
tangent: [0.0;3], // todo: tangent from model tangent: [0.0;3], // todo: tangent from model
bitangent: [0.0;3], bitangent: [0.0;3],
}) })
@ -734,35 +605,29 @@ impl Renderer {
} else { } else {
vertex_data = Vec::new(); vertex_data = Vec::new();
} }
let vertex_buffer = let vertex_buffer = self.device.create_buffer_init(
self.device &wgpu::util::BufferInitDescriptor {
.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(( Some((self.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
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,
@ -775,7 +640,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();
@ -787,25 +652,16 @@ 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 Some(info) => textures.entry(info.texture().source().index()).or_insert_with(|| self.new_texture_from_gltf(&info.texture(), &images)).clone(),
.entry(info.texture().source().index()) None => self.default_texture.clone()
.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 Some(info) => textures.entry(info.texture().source().index()).or_insert_with(|| self.new_texture_from_gltf(&info.texture(), &images)).clone(),
.entry(info.texture().source().index()) None => self.default_texture.clone()
.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 Some(info) => textures.entry(info.texture().source().index()).or_insert_with(|| self.new_texture_from_gltf(&info.texture(), &images)).clone(),
.entry(info.texture().source().index()) None => self.default_texture.clone()
.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);
@ -835,15 +691,13 @@ 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 tree_node.children.push(self.load_node_from_gltf(node,meshes,textures,images,buffers));
.children
.push(self.load_node_from_gltf(node, meshes, textures, images, buffers));
} }
tree_node tree_node
} }
@ -863,13 +717,7 @@ 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( scene_node.children.push(self.load_node_from_gltf(node, &mut meshes, &mut textures, &images, &buffers));
node,
&mut meshes,
&mut textures,
&images,
&buffers,
));
} }
root.children.push(scene_node) root.children.push(scene_node)
} }
@ -880,9 +728,6 @@ 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;
@ -948,22 +793,16 @@ impl Renderer {
desired_maximum_frame_latency: 2, desired_maximum_frame_latency: 2,
}; };
let shader = let eye = Eye::new(&device, width, height);
device.create_shader_module(wgpu::include_wgsl!("../assets/SimpleShader.wgsl"));
let default_texture = SimpleTexture::load( let shader = device.create_shader_module(wgpu::include_wgsl!("../assets/SimpleShader.wgsl"));
&device,
&queue, let texture = SimpleTexture::load(&device, &queue, [255,255,255,255], TextureProperties {
[0, 0, 255, 255],
TextureProperties {
width: 1, width: 1,
height: 1, height: 1,
}, });
);
let eye = Eye::new(&device, width, height, default_texture.clone()); let texture_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
let texture_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[ entries: &[
wgpu::BindGroupLayoutEntry { wgpu::BindGroupLayoutEntry {
binding: 0, binding: 0,
@ -1000,24 +839,30 @@ 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 pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { let render_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Render Pipeline Layout"), label: Some("Render Pipeline Layout"),
bind_group_layouts: &[Some(&eye.layout), Some(&texture_bind_group_layout)], bind_group_layouts: &[
Some(&eye.layout),
Some(&texture_bind_group_layout),
],
immediate_size: 0, immediate_size: 0,
}); });
let instance_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Render Pipeline"), label: Some("Render Pipeline"),
layout: Some(&pipeline_layout), layout: Some(&render_pipeline_layout),
vertex: wgpu::VertexState { vertex: wgpu::VertexState {
module: &shader, module: &shader,
entry_point: Some("vs_main"), entry_point: Some("vs_main"),
buffers: &[SimpleVertex::desc(), SimpleInstances::desc()], buffers: &[
SimpleVertex::desc(),SimpleInstances::desc(),
],
compilation_options: wgpu::PipelineCompilationOptions::default(), compilation_options: wgpu::PipelineCompilationOptions::default(),
}, },
fragment: Some(wgpu::FragmentState { fragment: Some(wgpu::FragmentState {
@ -1032,7 +877,7 @@ impl Renderer {
})], })],
compilation_options: wgpu::PipelineCompilationOptions::default(), compilation_options: wgpu::PipelineCompilationOptions::default(),
}), }),
primitive: Default::default(), /*wgpu::PrimitiveState { primitive: 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,
@ -1040,12 +885,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 {
@ -1057,45 +902,7 @@ impl Renderer {
cache: None, cache: None,
}); });
//todo: use a pipeline cache! let size = wgpu::Extent3d { // 2.
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,
@ -1113,8 +920,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(&wgpu::SamplerDescriptor { let depth_sampler = device.create_sampler(
// 4. &wgpu::SamplerDescriptor { // 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,
@ -1125,37 +932,31 @@ 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); let instances = SimpleInstances::new(&device,&queue);
let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { let staging_belt = wgpu::util::StagingBelt::new(device.clone(), 0x1024);
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, default_texture: texture,
default_material,
depth_texture: SimpleTexture { depth_texture: SimpleTexture {
texture: depth_texture, texture: depth_texture,
view: depth_view, view: depth_view,
}, },
instances, instances,
sky_pipeline, pipeline,
instance_pipeline,
surface, surface,
config, config,
device, device,
@ -1165,6 +966,7 @@ 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) => {
@ -1207,12 +1009,7 @@ impl Renderer {
resolve_target: None, resolve_target: None,
depth_slice: None, depth_slice: None,
ops: wgpu::Operations { ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color { load: wgpu::LoadOp::Clear(Default::default()),
r: 0.5,
g: 0.6,
b: 0.8,
a: 1.0,
}),
store: wgpu::StoreOp::Store, store: wgpu::StoreOp::Store,
}, },
})], })],
@ -1229,15 +1026,10 @@ impl Renderer {
multiview_mask: None, multiview_mask: None,
}); });
pass.set_pipeline(&self.instance_pipeline); pass.set_pipeline(&self.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 {
@ -108,7 +108,7 @@ impl Block {
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);
@ -123,20 +123,19 @@ 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)
}
}
} }
} }
@ -160,12 +159,7 @@ 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 self.debug_world_map_object = self.renderer.as_mut().unwrap().load_from_gltf(include_bytes!("../assets/debug.glb")).first_object()
.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()));
@ -176,8 +170,12 @@ 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();
@ -214,14 +212,11 @@ impl World {
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);
} }