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:
parent
efe98454d9
commit
3231ed9190
10 changed files with 1829 additions and 1449 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
|
@ -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
BIN
game.core
Normal file
Binary file not shown.
87
src/app.rs
87
src/app.rs
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
BIN
src/assets/cube.glb
Normal file
Binary file not shown.
BIN
src/assets/skybox1.png
Normal file
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 |
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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()));
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue