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:
parent
3231ed9190
commit
6685277e29
10 changed files with 1438 additions and 1818 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
|
@ -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
BIN
game.core
Binary file not shown.
531
src/app.rs
531
src/app.rs
|
|
@ -1,345 +1,312 @@
|
||||||
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;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use winit::platform::web::EventLoopExtWebSys;
|
use winit::platform::web::EventLoopExtWebSys;
|
||||||
use winit::{
|
use winit::{
|
||||||
application::ApplicationHandler,
|
application::ApplicationHandler,
|
||||||
event::*,
|
event::*,
|
||||||
event_loop::{ActiveEventLoop, EventLoop},
|
event_loop::{ActiveEventLoop, EventLoop},
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Controller {
|
impl Controller {
|
||||||
fn new() -> Controller {
|
fn new() -> 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),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
world: World,
|
world: World,
|
||||||
controller: Controller,
|
controller: Controller,
|
||||||
window: Arc<Window>,
|
window: Arc<Window>,
|
||||||
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 mut world = World::new();
|
let size = window.inner_size();
|
||||||
world.add_renderer(Renderer::new(&window).await?);
|
let mut world = World::new();
|
||||||
let mut clients = Vec::new();
|
world.add_renderer(Renderer::new(&window).await?);
|
||||||
{
|
let mut clients = Vec::new();
|
||||||
let file = world
|
{
|
||||||
.renderer
|
let file = world.renderer.as_mut().unwrap().load_from_gltf( include_bytes!("assets/cube.glb"));
|
||||||
.as_mut()
|
let block = file.first_object().unwrap();
|
||||||
.unwrap()
|
//let color = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/color.png"));
|
||||||
.load_from_gltf(include_bytes!("assets/cube.glb"));
|
//let normal = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/normal.png"));
|
||||||
let block = file.first_object().unwrap();
|
//let roughness = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/roughness.png"));
|
||||||
let skybox = world.renderer.as_mut().unwrap().load_texture_from_bytes(
|
//let mat = renderer.new_material(color,normal,roughness);
|
||||||
include_bytes!("assets/skybox1.png"),
|
for x in -BLOCKS..BLOCKS {
|
||||||
Some(image::ImageFormat::Png),
|
for y in -BLOCKS..BLOCKS {
|
||||||
);
|
let block = block.hard_clone();
|
||||||
world.renderer.as_mut().unwrap().set_skybox(skybox);
|
world.add_object(block.clone());
|
||||||
//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 mut model = block.0.borrow_mut();
|
||||||
//let roughness = &renderer.load_texture_from_bytes(include_bytes!("assets/plank/roughness.png"));
|
model.model.as_mut().unwrap().instance.transform = Mat4::from_translation(Vec3::new(-x as f32 * 3.0,0.0,-y as f32 * 3.0))
|
||||||
//let mat = renderer.new_material(color,normal,roughness);
|
* Mat4::from_rotation_z((x * y) as f32 / 1.23);
|
||||||
for x in -BLOCKS..BLOCKS {
|
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);
|
||||||
for y in -BLOCKS..BLOCKS {
|
}
|
||||||
let block = block.hard_clone();
|
clients.push(block)
|
||||||
world.add_object(block.clone());
|
|
||||||
{
|
|
||||||
let mut model = block.0.borrow_mut();
|
|
||||||
model.model.as_mut().unwrap().instance.transform = Mat4::from_translation(
|
|
||||||
Vec3::new(-x as f32 * 3.0, -8.0, -y as f32 * 3.0),
|
|
||||||
)
|
|
||||||
* 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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
clients.push(block)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(Self {
|
}
|
||||||
world,
|
|
||||||
clients,
|
|
||||||
controller: Controller::new(),
|
|
||||||
window,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
Ok(Self {
|
||||||
|
world,
|
||||||
|
clients,
|
||||||
|
controller: Controller::new(),
|
||||||
|
window,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
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 {
|
||||||
self.world.renderer.as_mut().unwrap().resize(width, height);
|
let max = 2048;
|
||||||
}
|
self.world.renderer.as_mut().unwrap().resize(width,height);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn update(&mut self) {
|
fn update(&mut self) {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
|
||||||
self.controller.keys.insert(code, is_pressed);
|
|
||||||
}
|
}
|
||||||
|
self.controller.keys.insert(code, is_pressed);
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
proxy: Option<winit::event_loop::EventLoopProxy<AppState>>,
|
proxy: Option<winit::event_loop::EventLoopProxy<AppState>>,
|
||||||
state: Option<AppState>,
|
state: Option<AppState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn new(#[cfg(target_arch = "wasm32")] event_loop: &EventLoop<AppState>) -> Self {
|
pub fn new(#[cfg(target_arch = "wasm32")] event_loop: &EventLoop<AppState>) -> Self {
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
let proxy = Some(event_loop.create_proxy());
|
let proxy = Some(event_loop.create_proxy());
|
||||||
Self {
|
Self {
|
||||||
state: None,
|
state: None,
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
proxy,
|
proxy,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApplicationHandler<AppState> for App {
|
impl ApplicationHandler<AppState> for App {
|
||||||
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
#[allow(unused_mut)]
|
|
||||||
let mut window_attributes = Window::default_attributes();
|
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
{
|
|
||||||
use wasm_bindgen::JsCast;
|
|
||||||
use winit::platform::web::WindowAttributesExtWebSys;
|
|
||||||
|
|
||||||
const CANVAS_ID: &str = "canvas";
|
|
||||||
|
|
||||||
let window = wgpu::web_sys::window().unwrap_throw();
|
|
||||||
let document = window.document().unwrap_throw();
|
|
||||||
let canvas = document.get_element_by_id(CANVAS_ID).unwrap_throw();
|
|
||||||
let html_canvas_element = canvas.unchecked_into();
|
|
||||||
window_attributes = window_attributes.with_canvas(Some(html_canvas_element));
|
|
||||||
}
|
|
||||||
|
|
||||||
let window = Arc::new(event_loop.create_window(window_attributes).unwrap());
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
{
|
|
||||||
// If we are not on web we can use pollster to
|
|
||||||
// await the window creation
|
|
||||||
self.state = Some(pollster::block_on(AppState::new(window)).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
{
|
|
||||||
// Run the future asynchronously and use the
|
|
||||||
// proxy to send the results to the event loop
|
|
||||||
if let Some(proxy) = self.proxy.take() {
|
|
||||||
wasm_bindgen_futures::spawn_local(async move {
|
|
||||||
assert!(
|
|
||||||
proxy
|
|
||||||
.send_event(
|
|
||||||
AppState::new(window)
|
|
||||||
.await
|
|
||||||
.expect("Unable to create canvas!!!")
|
|
||||||
)
|
|
||||||
.is_ok()
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
fn user_event(&mut self, _event_loop: &ActiveEventLoop, mut event: AppState) {
|
let mut window_attributes = Window::default_attributes();
|
||||||
// This is where proxy.send_event() ends up
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
{
|
{
|
||||||
event.window.request_redraw();
|
use wasm_bindgen::JsCast;
|
||||||
event.resize(
|
use winit::platform::web::WindowAttributesExtWebSys;
|
||||||
event.window.inner_size().width,
|
|
||||||
event.window.inner_size().height,
|
const CANVAS_ID: &str = "canvas";
|
||||||
);
|
|
||||||
}
|
let window = wgpu::web_sys::window().unwrap_throw();
|
||||||
self.state = Some(event);
|
let document = window.document().unwrap_throw();
|
||||||
|
let canvas = document.get_element_by_id(CANVAS_ID).unwrap_throw();
|
||||||
|
let html_canvas_element = canvas.unchecked_into();
|
||||||
|
window_attributes = window_attributes.with_canvas(Some(html_canvas_element));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window_event(
|
let window = Arc::new(event_loop.create_window(window_attributes).unwrap());
|
||||||
&mut self,
|
|
||||||
event_loop: &ActiveEventLoop,
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
_window_id: winit::window::WindowId,
|
{
|
||||||
event: WindowEvent,
|
// If we are not on web we can use pollster to
|
||||||
) {
|
// await the window creation
|
||||||
let state = match &mut self.state {
|
self.state = Some(pollster::block_on(AppState::new(window)).unwrap());
|
||||||
Some(canvas) => canvas,
|
}
|
||||||
None => return,
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
{
|
||||||
|
// Run the future asynchronously and use the
|
||||||
|
// proxy to send the results to the event loop
|
||||||
|
if let Some(proxy) = self.proxy.take() {
|
||||||
|
wasm_bindgen_futures::spawn_local(async move {
|
||||||
|
assert!(
|
||||||
|
proxy
|
||||||
|
.send_event(
|
||||||
|
AppState::new(window)
|
||||||
|
.await
|
||||||
|
.expect("Unable to create canvas!!!")
|
||||||
|
)
|
||||||
|
.is_ok()
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
fn user_event(&mut self, _event_loop: &ActiveEventLoop, mut event: AppState) {
|
||||||
|
// This is where proxy.send_event() ends up
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
{
|
||||||
|
event.window.request_redraw();
|
||||||
|
event.resize(
|
||||||
|
event.window.inner_size().width,
|
||||||
|
event.window.inner_size().height,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.state = Some(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn window_event(
|
||||||
|
&mut self,
|
||||||
|
event_loop: &ActiveEventLoop,
|
||||||
|
_window_id: winit::window::WindowId,
|
||||||
|
event: WindowEvent,
|
||||||
|
) {
|
||||||
|
let state = match &mut self.state {
|
||||||
|
Some(canvas) => canvas,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
match event {
|
||||||
|
WindowEvent::CloseRequested => event_loop.exit(),
|
||||||
|
WindowEvent::Resized(size) => state.resize(size.width, size.height),
|
||||||
|
WindowEvent::RedrawRequested => {
|
||||||
|
state.update();
|
||||||
|
let mut movement = Vec3::new(0.0,0.0,0.0);
|
||||||
|
|
||||||
|
let pressed = |keycode: KeyCode| {
|
||||||
|
if let Some(true) = state.controller.keys.get(&keycode) {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match event {
|
if pressed(KeyCode::KeyA) {
|
||||||
WindowEvent::CloseRequested => event_loop.exit(),
|
movement.x -= 1.0;
|
||||||
WindowEvent::Resized(size) => state.resize(size.width, size.height),
|
|
||||||
WindowEvent::RedrawRequested => {
|
|
||||||
state.update();
|
|
||||||
let mut movement = Vec3::new(0.0, 0.0, 0.0);
|
|
||||||
|
|
||||||
let pressed = |keycode: KeyCode| {
|
|
||||||
if let Some(true) = state.controller.keys.get(&keycode) {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if pressed(KeyCode::KeyA) {
|
|
||||||
movement.x -= 1.0;
|
|
||||||
}
|
|
||||||
if pressed(KeyCode::KeyD) {
|
|
||||||
movement.x += 1.0;
|
|
||||||
}
|
|
||||||
if pressed(KeyCode::KeyW) {
|
|
||||||
movement.z += 1.0;
|
|
||||||
}
|
|
||||||
if pressed(KeyCode::KeyS) {
|
|
||||||
movement.z -= 1.0;
|
|
||||||
}
|
|
||||||
if pressed(KeyCode::KeyE) {
|
|
||||||
movement.y += 1.0;
|
|
||||||
}
|
|
||||||
if pressed(KeyCode::KeyQ) {
|
|
||||||
movement.y -= 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
state
|
|
||||||
.world
|
|
||||||
.renderer
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.eye
|
|
||||||
.control(movement * 0.1);
|
|
||||||
match state.world.renderer.as_mut().unwrap().render(&state.window) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(e) => {
|
|
||||||
// Log the error and exit gracefully
|
|
||||||
log::error!("{e}");
|
|
||||||
event_loop.exit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for object in state.clients.iter() {
|
|
||||||
object
|
|
||||||
.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::CursorMoved { position: pos, .. } => state.handle_mouse_moved(pos),
|
|
||||||
WindowEvent::KeyboardInput {
|
|
||||||
event:
|
|
||||||
KeyEvent {
|
|
||||||
physical_key: PhysicalKey::Code(code),
|
|
||||||
state: key_state,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
} => state.handle_key(event_loop, code, key_state.is_pressed()),
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
if pressed(KeyCode::KeyD) {
|
||||||
|
movement.x += 1.0;
|
||||||
|
}
|
||||||
|
if pressed(KeyCode::KeyW) {
|
||||||
|
movement.z += 1.0;
|
||||||
|
}
|
||||||
|
if pressed(KeyCode::KeyS) {
|
||||||
|
movement.z -= 1.0;
|
||||||
|
}
|
||||||
|
if pressed(KeyCode::KeyE) {
|
||||||
|
movement.y += 1.0;
|
||||||
|
}
|
||||||
|
if pressed(KeyCode::KeyQ) {
|
||||||
|
movement.y -= 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.world.renderer.as_mut().unwrap().eye.control(movement * 0.1);
|
||||||
|
match state.world.renderer.as_mut().unwrap().render(&state.window) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
// Log the error and exit gracefully
|
||||||
|
log::error!("{e}");
|
||||||
|
event_loop.exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for object in state.clients.iter() {
|
||||||
|
object.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::CursorMoved { position: pos, .. } => state.handle_mouse_moved(pos),
|
||||||
|
WindowEvent::KeyboardInput {
|
||||||
|
event:
|
||||||
|
KeyEvent {
|
||||||
|
physical_key: PhysicalKey::Code(code),
|
||||||
|
state: key_state,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
} => state.handle_key(event_loop, code, key_state.is_pressed()),
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run() -> anyhow::Result<()> {
|
pub fn run() -> anyhow::Result<()> {
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
{
|
{
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
}
|
}
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
{
|
{
|
||||||
console_log::init_with_level(log::Level::Info).unwrap_throw();
|
console_log::init_with_level(log::Level::Info).unwrap_throw();
|
||||||
}
|
}
|
||||||
|
|
||||||
let event_loop = EventLoop::with_user_event().build()?;
|
let event_loop = EventLoop::with_user_event().build()?;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
{
|
{
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
event_loop.run_app(&mut app)?;
|
event_loop.run_app(&mut app)?;
|
||||||
}
|
}
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
{
|
{
|
||||||
let app = App::new(&event_loop);
|
let app = App::new(&event_loop);
|
||||||
event_loop.spawn_app(app);
|
event_loop.spawn_app(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
#[wasm_bindgen(start)]
|
#[wasm_bindgen(start)]
|
||||||
pub fn run_web() -> Result<(), wasm_bindgen::JsValue> {
|
pub fn run_web() -> Result<(), wasm_bindgen::JsValue> {
|
||||||
console_error_panic_hook::set_once();
|
console_error_panic_hook::set_once();
|
||||||
run().unwrap_throw();
|
run().unwrap_throw();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
BIN
src/assets/test.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 254 KiB |
|
|
@ -1,187 +1,131 @@
|
||||||
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,
|
||||||
pub(crate) environment: Environment,
|
pub(crate) environment: Environment,
|
||||||
aspect_ratio: f32,
|
aspect_ratio: f32,
|
||||||
z_near: f32,
|
z_near: f32,
|
||||||
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(
|
let projection = perspective(self.fov_y, self.aspect_ratio, self.z_near, self.z_far);
|
||||||
self.frame.matrix3.into(),
|
projection * self.frame.inverse()
|
||||||
Vec3::from(self.frame.translation),
|
}
|
||||||
);
|
pub(crate) fn write(&mut self, queue: &Queue) {
|
||||||
let projection = perspective(self.fov_y, self.aspect_ratio, self.z_near, self.z_far);
|
queue.write_buffer(&self.buffer,0,bytemuck::cast_slice(&[
|
||||||
queue.write_buffer(
|
self.view(),
|
||||||
&self.camera_buffer,
|
Mat4::from_mat3_translation(self.frame.matrix3.into(), Vec3::from(self.frame.translation))
|
||||||
0,
|
]));
|
||||||
bytemuck::cast_slice(&[
|
queue.write_buffer(&self.environment_buffer,0,bytemuck::cast_slice(&[self.environment]));
|
||||||
projection,
|
}
|
||||||
camera * projection.inverse(),
|
pub(crate) fn new(device: &Device, width: u32, height: u32) -> Eye {
|
||||||
camera.inverse(),
|
let buffer = device.create_buffer_init(
|
||||||
camera,
|
&wgpu::util::BufferInitDescriptor {
|
||||||
]),
|
label: Some("Camera Buffer"),
|
||||||
);
|
contents: bytemuck::cast_slice(&[Mat4::from_translation(Vec3::new(0.0,2.0,-8.0)),Mat4::IDENTITY]),
|
||||||
queue.write_buffer(
|
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||||
&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(&wgpu::util::BufferInitDescriptor {
|
let environment_buffer = device.create_buffer_init(
|
||||||
label: Some(""),
|
&wgpu::util::BufferInitDescriptor {
|
||||||
contents: bytemuck::cast_slice(&[environment]),
|
label: Some(""),
|
||||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
contents: bytemuck::cast_slice(&[environment]),
|
||||||
});
|
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: &[
|
||||||
wgpu::BindGroupLayoutEntry {
|
wgpu::BindGroupLayoutEntry {
|
||||||
binding: 0,
|
binding: 0,
|
||||||
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
|
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
|
||||||
ty: wgpu::BindingType::Buffer {
|
ty: wgpu::BindingType::Buffer {
|
||||||
ty: wgpu::BufferBindingType::Uniform,
|
ty: wgpu::BufferBindingType::Uniform,
|
||||||
has_dynamic_offset: false,
|
has_dynamic_offset: false,
|
||||||
min_binding_size: None,
|
min_binding_size: None,
|
||||||
},
|
},
|
||||||
count: None,
|
count: None,
|
||||||
},
|
},
|
||||||
wgpu::BindGroupLayoutEntry {
|
wgpu::BindGroupLayoutEntry {
|
||||||
binding: 1,
|
binding: 1,
|
||||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
ty: wgpu::BindingType::Buffer {
|
ty: wgpu::BindingType::Buffer {
|
||||||
ty: wgpu::BufferBindingType::Uniform,
|
ty: wgpu::BufferBindingType::Uniform,
|
||||||
has_dynamic_offset: false,
|
has_dynamic_offset: false,
|
||||||
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"),
|
|
||||||
});
|
|
||||||
|
|
||||||
let group = Eye::bind_group(&layout, device, &camera_buffer, &environment_buffer, skybox);
|
|
||||||
|
|
||||||
Eye {
|
|
||||||
aspect_ratio: width as f32 / height as f32,
|
|
||||||
frame: Affine3A::IDENTITY,
|
|
||||||
fov_y: 90.0,
|
|
||||||
z_near: 0.1,
|
|
||||||
z_far: 1000.0,
|
|
||||||
camera_buffer,
|
|
||||||
group,
|
|
||||||
layout,
|
|
||||||
environment,
|
|
||||||
environment_buffer,
|
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
label: Some("eye_bind_group_layout"),
|
||||||
|
});
|
||||||
|
|
||||||
|
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 {
|
||||||
|
aspect_ratio: width as f32 / height as f32,
|
||||||
|
frame: Affine3A::IDENTITY,
|
||||||
|
fov_y: 90.0,
|
||||||
|
z_near: 0.1,
|
||||||
|
z_far: 1000.0,
|
||||||
|
buffer,
|
||||||
|
group,
|
||||||
|
layout,
|
||||||
|
environment,
|
||||||
|
environment_buffer,
|
||||||
}
|
}
|
||||||
fn bind_group(
|
}
|
||||||
layout: &wgpu::BindGroupLayout,
|
pub(crate) fn resize(&mut self, width: u32, height: u32) {
|
||||||
device: &wgpu::Device,
|
self.aspect_ratio = width as f32 / height as f32
|
||||||
camera: &wgpu::Buffer,
|
}
|
||||||
environment: &wgpu::Buffer,
|
pub(crate) fn control(&mut self, delta: Vec3) {
|
||||||
skybox: SimpleTexture,
|
self.frame *= Affine3A::from_translation(delta);
|
||||||
) -> wgpu::BindGroup {
|
}
|
||||||
device.create_bind_group(&wgpu::BindGroupDescriptor {
|
pub(crate) fn rotate(&mut self, yaw: f32, pitch: f32) {
|
||||||
layout: &layout,
|
let (mut y,mut x,z) = self.frame.matrix3.to_euler(EulerRot::YXZ);
|
||||||
entries: &[
|
x = (x + pitch * 0.005).clamp(-1.4,1.4);
|
||||||
wgpu::BindGroupEntry {
|
y += yaw * 0.005;
|
||||||
binding: 0,
|
self.frame.matrix3 = Mat3A::from_euler(EulerRot::YXZ,y,x,z);
|
||||||
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) {
|
|
||||||
self.aspect_ratio = width as f32 / height as f32
|
|
||||||
}
|
|
||||||
pub(crate) fn control(&mut self, delta: Vec3) {
|
|
||||||
self.frame *= Affine3A::from_translation(delta);
|
|
||||||
}
|
|
||||||
pub(crate) fn rotate(&mut self, yaw: f32, pitch: f32) {
|
|
||||||
let (mut y, mut x, z) = self.frame.matrix3.to_euler(EulerRot::YXZ);
|
|
||||||
x = (x + pitch * 0.005).clamp(-1.4, 1.4);
|
|
||||||
y += yaw * 0.005;
|
|
||||||
self.frame.matrix3 = Mat3A::from_euler(EulerRot::YXZ, y, x, z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2018
src/render/mod.rs
2018
src/render/mod.rs
File diff suppressed because it is too large
Load diff
319
src/world/mod.rs
319
src/world/mod.rs
|
|
@ -1,228 +1,223 @@
|
||||||
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 {
|
||||||
Block(Vec3),
|
Block(Vec3),
|
||||||
Sphere(f32),
|
Sphere(f32),
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SimpleColliderData {
|
pub struct SimpleColliderData {
|
||||||
pub transform: Mat4,
|
pub transform: Mat4,
|
||||||
pub shape: Shape,
|
pub shape: Shape,
|
||||||
pub radius: f32,
|
pub radius: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SimpleObjectData {
|
pub struct SimpleObjectData {
|
||||||
pub model: Option<SimpleModelData>,
|
pub model: Option<SimpleModelData>,
|
||||||
pub collider: SimpleColliderData,
|
pub collider: SimpleColliderData,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SimpleLight(pub Rc<RefCell<SimpleLightData>>);
|
pub struct SimpleLight(pub Rc<RefCell<SimpleLightData>>);
|
||||||
|
|
||||||
impl PartialEq for SimpleLight {
|
impl PartialEq for SimpleLight {
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for SimpleLight {}
|
impl Eq for SimpleLight {}
|
||||||
|
|
||||||
impl Hash for SimpleLight {
|
impl Hash for SimpleLight {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
(self.0.as_ptr() as *const RefCell<SimpleLight>).hash(state)
|
(self.0.as_ptr() as *const RefCell<SimpleLight>).hash(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SimpleObject(pub Rc<RefCell<SimpleObjectData>>);
|
pub struct SimpleObject(pub Rc<RefCell<SimpleObjectData>>);
|
||||||
|
|
||||||
impl SimpleObject {
|
impl SimpleObject {
|
||||||
pub(crate) fn hard_clone(&self) -> SimpleObject {
|
pub(crate) fn hard_clone(&self) -> SimpleObject {
|
||||||
SimpleObject {
|
SimpleObject {
|
||||||
0: Rc::new(RefCell::new(SimpleObjectData {
|
0: Rc::new(RefCell::new(SimpleObjectData {
|
||||||
model: self.0.borrow().model.clone(),
|
model: self.0.borrow().model.clone(),
|
||||||
collider: self.0.borrow().collider.clone(),
|
collider: self.0.borrow().collider.clone(),
|
||||||
})),
|
})),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for SimpleObject {}
|
impl Eq for SimpleObject {}
|
||||||
|
|
||||||
impl Hash for SimpleObject {
|
impl Hash for SimpleObject {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
(self.0.as_ptr() as *const RefCell<SimpleModelData>).hash(state);
|
(self.0.as_ptr() as *const RefCell<SimpleModelData>).hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Eq, Hash, PartialEq, Clone)]
|
#[derive(Eq, Hash, PartialEq, Clone)]
|
||||||
enum Interest {
|
enum Interest {
|
||||||
Light(SimpleLight),
|
Light(SimpleLight),
|
||||||
Object(SimpleObject),
|
Object(SimpleObject),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Block {
|
struct Block {
|
||||||
debug: Option<SimpleObject>,
|
debug: Option<SimpleObject>,
|
||||||
volume: u8,
|
volume: u8,
|
||||||
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;
|
||||||
const TREE_FLOOR: usize = 4;
|
const TREE_FLOOR: usize = 4;
|
||||||
impl Block {
|
impl Block {
|
||||||
fn new() -> Block {
|
fn new() -> Block {
|
||||||
Block {
|
Block {
|
||||||
debug: None,
|
debug: None,
|
||||||
volume: 0,
|
volume: 0,
|
||||||
velocity: Vec3::ZERO,
|
velocity: Vec3::ZERO,
|
||||||
material: 0,
|
material: 0,
|
||||||
interests: FastHashSet::with_hasher(BuildHasherDefault::default()),
|
interests: FastHashSet::with_hasher(BuildHasherDefault::default()),
|
||||||
blocks: [const { None }; const { TREE_ATTACK * TREE_ATTACK * TREE_ATTACK }],
|
blocks: [const { None }; const { TREE_ATTACK * TREE_ATTACK * TREE_ATTACK }],
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fn place_pos(&mut self, interest: Interest, pos: Vec3, rad: f32, block_size: f32) {
|
}
|
||||||
let cs = block_size / const { TREE_ATTACK as f32 };
|
fn place_pos(&mut self, interest: Interest, pos: Vec3, rad: f32, block_size: f32) {
|
||||||
if rad < cs || block_size >= TREE_FLOOR as f32 {
|
let cs = block_size / const { TREE_ATTACK as f32 };
|
||||||
let rel = ((pos + block_size / 2.0) / cs).round().as_uvec3();
|
if rad < cs || block_size >= TREE_FLOOR as f32 {
|
||||||
let new_pos = pos - (rel.as_vec3() + cs / 2.0);
|
let rel = ((pos + block_size / 2.0) / cs).round().as_uvec3();
|
||||||
let index = (rel.x + rel.y * 4 + rel.z * 16) as usize;
|
let new_pos = pos - (rel.as_vec3() + cs / 2.0);
|
||||||
match self.blocks[index] {
|
let index = (rel.x + rel.y * 4 + rel.z * 16) as usize;
|
||||||
Some(ref mut block) => {
|
match self.blocks[index] {
|
||||||
block.place_pos(interest, new_pos, rad, cs);
|
Some(ref mut block) => {
|
||||||
}
|
block.place_pos(interest,new_pos,rad,cs);
|
||||||
None => {
|
},
|
||||||
let mut block = Box::new(Block::new());
|
None => {
|
||||||
block.place_pos(interest, new_pos, rad, cs);
|
let mut block = Box::new(Block::new());
|
||||||
self.blocks[index] = Some(block);
|
block.place_pos(interest,new_pos,rad,cs);
|
||||||
}
|
self.blocks[index] = Some(block);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.interests.insert(interest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn debug_step(&mut self, value: bool) {
|
||||||
|
match self.debug {
|
||||||
|
Some(ref mut debug) => {
|
||||||
|
if value {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
self.interests.insert(interest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn debug_step(&mut self, value: bool) {
|
|
||||||
match self.debug {
|
|
||||||
Some(ref mut debug) => {
|
|
||||||
if value {
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
if value {
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for maybe_block in self.blocks.iter_mut() {
|
|
||||||
if let Some(block) = maybe_block {
|
|
||||||
block.debug_step(value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
if value {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl World {
|
impl World {
|
||||||
pub fn new() -> World {
|
pub fn new() -> World {
|
||||||
World {
|
World {
|
||||||
chunk_size: 512,
|
chunk_size: 512,
|
||||||
map: FastHashMap::with_hasher(BuildHasherDefault::default()),
|
map: FastHashMap::with_hasher(BuildHasherDefault::default()),
|
||||||
renderer: None,
|
renderer: None,
|
||||||
debug_world_map: false,
|
debug_world_map: false,
|
||||||
debug_world_map_object: None,
|
debug_world_map_object: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn add_renderer(&mut self, renderer: Renderer) {
|
||||||
|
self.renderer = Some(renderer);
|
||||||
|
self.debug_world_map_object = self.renderer.as_mut().unwrap().load_from_gltf(include_bytes!("../assets/debug.glb")).first_object()
|
||||||
|
}
|
||||||
|
pub fn add_object(&mut self, object: SimpleObject) {
|
||||||
|
self.place(Interest::Object(object.clone()));
|
||||||
|
if let Some(ref mut renderer) = self.renderer {
|
||||||
|
renderer.instances.add_object(object)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn set_debug(&mut self, value: bool) {
|
||||||
|
self.debug_world_map = value;
|
||||||
|
}
|
||||||
|
pub fn light_step(&mut self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
pub fn object_step(&mut self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
pub fn debug_step(&mut self) {
|
||||||
|
self.light_step();
|
||||||
|
self.object_step();
|
||||||
|
for (index, item) in self.map.iter_mut() {
|
||||||
|
item.debug_step(self.debug_world_map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn place_pos(&mut self, interest: Interest, pos: Vec3, rad: f32) {
|
||||||
|
let cs = self.chunk_size as f32;
|
||||||
|
let c_rad = ((cs / 2.0) * (cs / 2.0)) * 3.0;
|
||||||
|
for x in (pos.x - rad).div(cs) as i32..=(pos.x + rad).div(cs).ceil() as i32 {
|
||||||
|
for y in (pos.y - rad).div(cs) as i32..=(pos.y + rad).div(cs).ceil() as i32 {
|
||||||
|
for z in (pos.z - rad).div(cs) as i32..=(pos.z + rad).div(cs).ceil() as i32 {
|
||||||
|
let block_pos = IVec3::new(x,y,z);
|
||||||
|
let block_pos_f32 = block_pos.as_vec3();
|
||||||
|
if block_pos_f32.distance_squared(pos) < rad + c_rad {
|
||||||
|
self.map.entry(block_pos).or_insert_with(|| {
|
||||||
|
let mut block = Block::new();
|
||||||
|
block.place_pos(
|
||||||
|
interest.clone(),
|
||||||
|
pos - block_pos_f32,
|
||||||
|
rad,
|
||||||
|
self.chunk_size as f32,
|
||||||
|
);
|
||||||
|
block
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn add_renderer(&mut self, renderer: Renderer) {
|
}
|
||||||
self.renderer = Some(renderer);
|
fn place(&mut self, interest: Interest) {
|
||||||
self.debug_world_map_object = self
|
let (pos,rad) = match &interest {
|
||||||
.renderer
|
Interest::Light(light) => {
|
||||||
.as_mut()
|
let light = light.0.borrow();
|
||||||
.unwrap()
|
(light.instance.location.xyz(),light.instance.color.length())
|
||||||
.load_from_gltf(include_bytes!("../assets/cube.glb"))
|
},
|
||||||
.first_object()
|
Interest::Object(object) => {
|
||||||
}
|
let collider = &object.0.borrow().collider;
|
||||||
pub fn add_object(&mut self, object: SimpleObject) {
|
(collider.transform.to_scale_rotation_translation().2,collider.radius)
|
||||||
self.place(Interest::Object(object.clone()));
|
},
|
||||||
if let Some(ref mut renderer) = self.renderer {
|
};
|
||||||
renderer.instances.add_object(object)
|
self.place_pos(interest,pos,rad);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn set_debug(&mut self, value: bool) {
|
|
||||||
self.debug_world_map = value;
|
|
||||||
}
|
|
||||||
pub fn light_step(&mut self) {}
|
|
||||||
pub fn object_step(&mut self) {}
|
|
||||||
pub fn debug_step(&mut self) {
|
|
||||||
self.light_step();
|
|
||||||
self.object_step();
|
|
||||||
for (index, item) in self.map.iter_mut() {
|
|
||||||
item.debug_step(self.debug_world_map);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn place_pos(&mut self, interest: Interest, pos: Vec3, rad: f32) {
|
|
||||||
let cs = self.chunk_size as f32;
|
|
||||||
let c_rad = ((cs / 2.0) * (cs / 2.0)) * 3.0;
|
|
||||||
for x in (pos.x - rad).div(cs) as i32..=(pos.x + rad).div(cs).ceil() as i32 {
|
|
||||||
for y in (pos.y - rad).div(cs) as i32..=(pos.y + rad).div(cs).ceil() as i32 {
|
|
||||||
for z in (pos.z - rad).div(cs) as i32..=(pos.z + rad).div(cs).ceil() as i32 {
|
|
||||||
let block_pos = IVec3::new(x, y, z);
|
|
||||||
let block_pos_f32 = block_pos.as_vec3();
|
|
||||||
if block_pos_f32.distance_squared(pos) < rad + c_rad {
|
|
||||||
self.map.entry(block_pos).or_insert_with(|| {
|
|
||||||
let mut block = Block::new();
|
|
||||||
block.place_pos(
|
|
||||||
interest.clone(),
|
|
||||||
pos - block_pos_f32,
|
|
||||||
rad,
|
|
||||||
self.chunk_size as f32,
|
|
||||||
);
|
|
||||||
block
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn place(&mut self, interest: Interest) {
|
|
||||||
let (pos, rad) = match &interest {
|
|
||||||
Interest::Light(light) => {
|
|
||||||
let light = light.0.borrow();
|
|
||||||
(light.instance.location.xyz(), light.instance.color.length())
|
|
||||||
}
|
|
||||||
Interest::Object(object) => {
|
|
||||||
let collider = &object.0.borrow().collider;
|
|
||||||
(
|
|
||||||
collider.transform.to_scale_rotation_translation().2,
|
|
||||||
collider.radius,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.place_pos(interest, pos, rad);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue