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

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

12
Cargo.lock generated
View file

@ -349,6 +349,15 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "combine"
version = "4.6.7"
@ -1096,6 +1105,9 @@ checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
[[package]]
name = "mars"
version = "0.1.0"
dependencies = [
"colored",
]
[[package]]
name = "memchr"

BIN
game.core Normal file

Binary file not shown.

View file

@ -1,7 +1,9 @@
use std::collections::HashMap;
// 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 glam::{Vec2, Affine3A, Vec3, Vec4, Mat4, EulerRot, Quat};
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
use winit::dpi::PhysicalPosition;
@ -14,9 +16,6 @@ use winit::{
keyboard::{KeyCode, PhysicalKey},
window::Window,
};
use crate::render;
use crate::render::{Renderer, SimpleTexture};
use crate::world::{SimpleObject, World};
struct Controller {
buttons: HashMap<MouseButton, bool>,
@ -41,19 +40,27 @@ pub struct AppState {
clients: Vec<SimpleObject>,
}
const BLOCKS: i32 = 50;
const BLOCKS: i32 = 1;
impl AppState {
// We don't need this to be async right now,
// but we will in the next tutorial
pub async fn new(window: Arc<Window>) -> Result<AppState, Box<dyn std::error::Error>> {
let size = window.inner_size();
let mut world = World::new();
world.add_renderer(Renderer::new(&window).await?);
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 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 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"));
@ -64,9 +71,16 @@ impl AppState {
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,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);
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)
}
@ -87,7 +101,6 @@ impl AppState {
pub fn resize(&mut self, width: u32, height: u32) {
if width > 0 && height > 0 {
let max = 2048;
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) {
match (code, is_pressed) {
(KeyCode::Escape, true) => event_loop.exit(),
(KeyCode::Space, true) => {},
(KeyCode::Space, true) => {}
(KeyCode::KeyR, true) => {
self.world.renderer.as_mut().unwrap().eye.frame = Affine3A::IDENTITY
}
@ -110,7 +123,10 @@ impl AppState {
fn handle_mouse_moved(&mut self, position: PhysicalPosition<f64>) {
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);
}
@ -245,7 +261,13 @@ impl ApplicationHandler<AppState> for App {
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) {
Ok(_) => {}
Err(e) => {
@ -255,13 +277,24 @@ impl ApplicationHandler<AppState> for App {
}
}
for object in state.clients.iter() {
object.0.borrow_mut().model.as_mut().unwrap().instance.transform *= Mat4::from_rotation_translation(
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)
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::KeyboardInput {
event:

View file

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

BIN
src/assets/cube.glb Normal file

Binary file not shown.

BIN
src/assets/skybox1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 254 KiB

View file

@ -1,9 +1,9 @@
use crate::render::{MaterialProperties, SimpleTexture};
use bytemuck::{Pod, Zeroable};
use env_logger::Env;
use glam::{Affine3A, EulerRot, Mat3A, Mat4, Vec3, Vec4};
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::{Device, Queue};
pub(crate) struct Eye {
pub(crate) frame: Affine3A,
@ -13,39 +13,53 @@ pub(crate) struct Eye {
z_far: f32,
fov_y: f32,
pub(crate) environment_buffer: wgpu::Buffer,
pub(crate) buffer: wgpu::Buffer,
pub(crate) camera_buffer: wgpu::Buffer,
pub(crate) layout: wgpu::BindGroupLayout,
pub(crate) group: wgpu::BindGroup,
}
#[repr(C)]
#[derive(Pod, Copy, Clone, Zeroable)]
struct Environment {
pub struct Environment {
ambient: Vec4,
light: Vec4,
dir: Vec4,
}
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) {
queue.write_buffer(&self.buffer,0,bytemuck::cast_slice(&[
self.view(),
Mat4::from_mat3_translation(self.frame.matrix3.into(), Vec3::from(self.frame.translation))
]));
queue.write_buffer(&self.environment_buffer,0,bytemuck::cast_slice(&[self.environment]));
}
pub(crate) fn new(device: &Device, width: u32, height: u32) -> Eye {
let buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Camera Buffer"),
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 camera = Mat4::from_mat3_translation(
self.frame.matrix3.into(),
Vec3::from(self.frame.translation),
);
let projection = perspective(self.fov_y, self.aspect_ratio, self.z_near, self.z_far);
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 environment = Environment {
@ -54,13 +68,11 @@ impl Eye {
dir: Vec4::new(dir.x, dir.y, dir.z, 0.0),
};
let environment_buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
let environment_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(""),
contents: bytemuck::cast_slice(&[environment]),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
}
);
});
let layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[
@ -83,25 +95,28 @@ impl Eye {
min_binding_size: 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 = 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"),
});
let group = Eye::bind_group(&layout, device, &camera_buffer, &environment_buffer, skybox);
Eye {
aspect_ratio: width as f32 / height as f32,
@ -109,13 +124,54 @@ impl Eye {
fov_y: 90.0,
z_near: 0.1,
z_far: 1000.0,
buffer,
camera_buffer,
group,
layout,
environment,
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) {
self.aspect_ratio = width as f32 / height as f32
}

View file

@ -1,23 +1,23 @@
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 std::collections::{HashMap};
use gltf::Semantic;
use image::EncodableLayout;
use std::cell::RefCell;
use std::collections::HashMap;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::hash::{BuildHasherDefault, Hash, Hasher};
use std::ops::{Range};
use std::ops::Range;
use std::rc::Rc;
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::util::DeviceExt;
use wgpu::{Device, Queue};
use winit::window::Window;
use crate::render::eye::Eye;
use crate::world::{Shape, SimpleColliderData, SimpleLight, SimpleObject, SimpleObjectData};
const DEFAULT_VERTICES: [SimpleVertex; 0] = [];
@ -62,14 +62,15 @@ pub struct SimpleInstances {
instance_buffer: wgpu::Buffer,
//light_ref_last: usize,
//light_ref_buffer: wgpu::Buffer,
objects: FastHashMap<Id<SimpleMesh>,FastHashMap<Id<SimpleMaterial>,FastHashSet<SimpleObject>>>,
objects:
FastHashMap<Id<SimpleMesh>, FastHashMap<Id<SimpleMaterial>, FastHashSet<SimpleObject>>>,
lights: FastHashMap<SimpleLight, usize>,
}
enum SimpleRenderCode {
Material(wgpu::BindGroup),
Mesh((wgpu::Buffer, u32), Option<(wgpu::Buffer, u32)>),
Draw(Range<u32>)
Draw(Range<u32>),
}
struct SimpleRenderProgram(Vec<SimpleRenderCode>);
@ -86,9 +87,11 @@ impl SimpleRenderProgram {
let mut indexed = false;
for code in self.0 {
match code {
SimpleRenderCode::Material(material) => {
pass.set_bind_group(Renderer::SIMPLE_RENDER_TEXTURE_GROUP_POSITION,&material,&[])
}
SimpleRenderCode::Material(material) => pass.set_bind_group(
Renderer::SIMPLE_RENDER_TEXTURE_GROUP_POSITION,
&material,
&[],
),
SimpleRenderCode::Mesh(vertices, indices) => {
pass.set_vertex_buffer(0, vertices.0.slice(..));
if let Some(indices) = indices {
@ -118,8 +121,10 @@ impl SimpleInstances {
if let Some(ref model) = object.0.borrow().model {
self.instance_count += 1;
self.objects
.entry(model.mesh.clone()).or_insert(FastHashMap::with_hasher(BuildHasherDefault::new()))
.entry(model.material.clone()).or_insert(FastHashSet::with_hasher(BuildHasherDefault::new()))
.entry(model.mesh.clone())
.or_insert(FastHashMap::with_hasher(BuildHasherDefault::new()))
.entry(model.material.clone())
.or_insert(FastHashSet::with_hasher(BuildHasherDefault::new()))
.insert(object.clone());
}
}
@ -128,8 +133,10 @@ impl SimpleInstances {
if let Some(ref model) = object.0.borrow().model {
self.instance_count -= 1;
self.objects
.entry(model.mesh.clone()).or_insert(FastHashMap::with_hasher(BuildHasherDefault::new()))
.entry(model.material.clone()).or_insert(FastHashSet::with_hasher(BuildHasherDefault::new()))
.entry(model.mesh.clone())
.or_insert(FastHashMap::with_hasher(BuildHasherDefault::new()))
.entry(model.material.clone())
.or_insert(FastHashSet::with_hasher(BuildHasherDefault::new()))
.remove(&object);
}
}
@ -144,7 +151,12 @@ impl SimpleInstances {
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;
if count > SimpleInstances::MIN_SIZE as usize {
let mut reallocate: Option<usize> = None;
@ -172,51 +184,82 @@ impl SimpleInstances {
wgpu::BufferSize::new(self.instance_buffer.size()).unwrap()
).unwrap();
*/
SimpleInstances::reallocate_buffer(device, queue, &mut self.light_buffer, self.light_count, size_of::<SimpleLight>());
let mut buffer = queue.write_buffer_with(
SimpleInstances::reallocate_buffer(
device,
&mut self.light_buffer,
self.light_count,
size_of::<SimpleLight>(),
);
let mut buffer = queue
.write_buffer_with(
&self.light_buffer,
0 as wgpu::BufferAddress,
wgpu::BufferSize::new(self.light_buffer.size()).unwrap(),
).unwrap();
)
.unwrap();
let stride = size_of::<SimpleLight>();
for (new_index, (light, index)) in self.lights.iter_mut().enumerate() {
*index = new_index + 1;
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();
SimpleInstances::reallocate_buffer(device, queue, &mut self.instance_buffer, self.instance_count, size_of::<SimpleModelInstance>());
let mut buffer = queue.write_buffer_with(
SimpleInstances::reallocate_buffer(
device,
&mut self.instance_buffer,
self.instance_count,
size_of::<SimpleModelInstance>(),
);
let mut buffer = queue
.write_buffer_with(
&self.instance_buffer,
0 as wgpu::BufferAddress,
wgpu::BufferSize::new(self.instance_buffer.size()).unwrap()
).unwrap();
wgpu::BufferSize::new(self.instance_buffer.size()).unwrap(),
)
.unwrap();
let mut index: u32 = 0;
let stride = size_of::<SimpleModelInstance>();
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() {
program.push(SimpleRenderCode::Material(material.it.group.clone()));
let before = index;
for object in objects.iter() {
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;
}
program.push(SimpleRenderCode::Draw(Range::from(before..index)));
}
};
}
program
}
fn desc() -> wgpu::VertexBufferLayout<'static> {
use std::mem;
wgpu::VertexBufferLayout {
array_stride: size_of::<SimpleModelInstance>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Instance,
attributes: &[ // todo: is this too big?
attributes: &[
// todo: is this too big?
wgpu::VertexAttribute {
offset: 0,
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 {
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,
mapped_at_creation: false,
});
let light_buffer = device.create_buffer(&wgpu::BufferDescriptor {
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,
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"),
size: (size_of::<u32>() * SimpleInstances::MIN_SIZE as usize) as wgpu::BufferAddress,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false
});
mapped_at_creation: false,
});*/
SimpleInstances {
light_count: 0,
//light_ref_last: 0,
@ -302,7 +347,9 @@ pub struct Renderer {
pub(crate) eye: eye::Eye,
material_layout: wgpu::BindGroupLayout,
default_texture: SimpleTexture,
pipeline: wgpu::RenderPipeline,
default_material: SimpleMaterial,
sky_pipeline: wgpu::RenderPipeline,
instance_pipeline: wgpu::RenderPipeline,
depth_texture: SimpleTexture,
pub(crate) instances: SimpleInstances,
}
@ -337,8 +384,8 @@ impl SimpleVertex {
offset: size_of::<[f32; 6]>() as wgpu::BufferAddress,
shader_location: 2,
format: wgpu::VertexFormat::Float32x2,
}
]
},
],
}
}
}
@ -348,23 +395,28 @@ pub struct SimpleMesh {
vertices: (wgpu::Buffer, u32),
}
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub(crate) struct SimpleTexture {
pub struct SimpleTexture {
texture: wgpu::Texture,
view: wgpu::TextureView,
}
struct TextureProperties {
pub struct TextureProperties {
width: u32,
height: u32,
}
// todo: use texture compression!
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 {
width: properties.width,
height: properties.height,
depth_or_array_layers: 1,
};
let diffuse_texture = device.create_texture(
&wgpu::TextureDescriptor {
let diffuse_texture = device.create_texture(&wgpu::TextureDescriptor {
size,
mip_level_count: 1,
sample_count: 1,
@ -373,9 +425,9 @@ impl SimpleTexture {
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
label: Some("texture"),
view_formats: &[],
}
);
let diffuse_texture_view = diffuse_texture.create_view(&wgpu::TextureViewDescriptor::default());
});
let diffuse_texture_view =
diffuse_texture.create_view(&wgpu::TextureViewDescriptor::default());
queue.write_texture(
wgpu::TexelCopyTextureInfo {
texture: &diffuse_texture,
@ -428,20 +480,41 @@ struct MaterialProperties {
filter: wgpu::FilterMode,
}
impl SimpleMaterial {
fn new(renderer: &Renderer, base: &SimpleTexture, normal: &SimpleTexture, reflect: &SimpleTexture, config: MaterialProperties) -> SimpleMaterial {
let sampler = renderer.device.create_sampler(&wgpu::SamplerDescriptor {
address_mode_u: config.edge,
address_mode_v: config.edge,
address_mode_w: config.edge,
mag_filter: config.filter,
min_filter: config.filter,
impl Default for MaterialProperties {
fn default() -> MaterialProperties {
MaterialProperties {
edge: wgpu::AddressMode::Repeat,
filter: wgpu::FilterMode::Linear,
}
}
}
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,
..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: &[
wgpu::BindGroupEntry {
binding: 0,
@ -461,11 +534,8 @@ impl SimpleMaterial {
},
],
label: Some("diffuse_bind_group"),
}
);
SimpleMaterial {
group,
}
});
SimpleMaterial { group }
}
}
@ -493,7 +563,7 @@ impl SimpleTreeNode {
} else {
for child in self.children.iter() {
if let Some(object) = child.first_object() {
return Some(object)
return Some(object);
}
}
None
@ -514,25 +584,55 @@ impl Renderer {
id: self.id_count,
}
}
pub fn load_texture_from_bytes(&mut self, slice: impl AsRef<[u8]>) -> SimpleTexture {
let image = image::load_from_memory(slice.as_ref());
pub fn load_texture_from_bytes(
&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 {
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(),
height: data.height(),
})
},
)
} else {
println!("failed to load texture! error: {:?}", image.unwrap_err());
self.default_texture.clone()
}
}
pub fn new_material(&mut self, base: &SimpleTexture, normal: &SimpleTexture, reflect: &SimpleTexture) -> Id<SimpleMaterial> {
self.new_id(SimpleMaterial::new(self, base, normal, reflect, MaterialProperties {
pub fn new_material(
&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,
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()) {
let mut new_pixels = Vec::new();
let pixels: &Vec<u8>;
@ -546,15 +646,18 @@ impl Renderer {
}
pixels = &new_pixels;
}
gltf::image::Format::R8G8B8A8 => {
pixels = &image.pixels
gltf::image::Format::R8G8B8A8 => pixels = &image.pixels,
_ => return self.default_texture.clone(),
}
_ => return self.default_texture.clone()
}
SimpleTexture::load(&self.device, &self.queue, pixels.as_slice(), TextureProperties {
SimpleTexture::load(
&self.device,
&self.queue,
pixels.as_slice(),
TextureProperties {
width: image.width,
height: image.height,
})
},
)
} else {
self.default_texture.clone()
}
@ -563,22 +666,47 @@ impl Renderer {
&mut self,
primitive: gltf::Primitive,
meshes: &mut HashMap<GltfVertexBufferKey, SimpleMesh>,
buffers: &[gltf::buffer::Data]
buffers: &[gltf::buffer::Data],
) -> Id<SimpleMesh> {
let position_index = primitive.get(&Semantic::Positions).and_then(|it| it.view()).and_then(|it| Some(it.buffer().index()));
let normals_index = primitive.get(&Semantic::Normals).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 position_index = primitive
.get(&Semantic::Positions)
.and_then(|it| it.view())
.and_then(|it| Some(it.buffer().index()));
let normals_index = primitive
.get(&Semantic::Normals)
.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 reader = primitive.reader(|buffer| Some(&buffers[buffer.index()]));
let mut vertex_data: Vec<SimpleVertex>;
if let Some(positions) = reader.read_positions() {
vertex_data = Vec::with_capacity(positions.len());
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());
tangents = tangent.is_some();
for position in positions {
@ -597,7 +725,8 @@ impl Renderer {
tex_coords.next()
} else {
None
}.unwrap_or([0.0;2]),
}
.unwrap_or([0.0; 2]),
tangent: [0.0; 3], // todo: tangent from model
bitangent: [0.0; 3],
})
@ -605,29 +734,35 @@ impl Renderer {
} else {
vertex_data = Vec::new();
}
let vertex_buffer = self.device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
let vertex_buffer =
self.device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Vertex Buffer"),
contents: bytemuck::cast_slice(vertex_data.as_slice()),
usage: wgpu::BufferUsages::VERTEX,
}
);
});
let vertices_result = (vertex_buffer, vertex_data.len() as u32);
let indices_result = if let Some(indices) = reader.read_indices() {
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"),
contents: bytemuck::cast_slice(index_data.as_slice()),
usage: wgpu::BufferUsages::INDEX,
}), index_data.len() as u32))
}),
index_data.len() as u32,
))
} else {
None
};
SimpleMesh {
indices: indices_result,
vertices: vertices_result
vertices: vertices_result,
}
}).clone())
})
.clone(),
)
}
pub fn load_node_from_gltf(
&mut self,
@ -640,7 +775,7 @@ impl Renderer {
let mut tree_node = SimpleTreeNode {
object: None,
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() {
let len = mesh.primitives().len();
@ -652,16 +787,25 @@ impl Renderer {
let rough = pbr.roughness_factor();
let light = primitive.material().emissive_factor();
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(),
None => self.default_texture.clone()
Some(info) => textures
.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() {
Some(info) => textures.entry(info.texture().source().index()).or_insert_with(|| self.new_texture_from_gltf(&info.texture(), &images)).clone(),
None => self.default_texture.clone()
Some(info) => textures
.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() {
Some(info) => textures.entry(info.texture().source().index()).or_insert_with(|| self.new_texture_from_gltf(&info.texture(), &images)).clone(),
None => self.default_texture.clone()
Some(info) => textures
.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 mesh = self.new_mesh_from_gltf(primitive, meshes, buffers);
@ -691,13 +835,15 @@ impl Renderer {
tree_node.children.push(SimpleTreeNode {
object: Some(object),
children: Vec::new(),
name: "Primitive".to_string()
name: "Primitive".to_string(),
})
}
}
}
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
}
@ -717,7 +863,13 @@ impl Renderer {
name: scene.name().unwrap_or("Scene").to_string(),
};
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)
}
@ -728,6 +880,9 @@ impl Renderer {
self.surface.configure(&self.device, &self.config);
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> {
let bounds = window.inner_size();
let width = bounds.width;
@ -793,16 +948,22 @@ impl Renderer {
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 texture = SimpleTexture::load(&device, &queue, [255,255,255,255], TextureProperties {
let default_texture = SimpleTexture::load(
&device,
&queue,
[0, 0, 255, 255],
TextureProperties {
width: 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: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
@ -839,30 +1000,24 @@ impl Renderer {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
},
count: None,
}
},
],
label: Some("texture_bind_group_layout"),
});
let render_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Render Pipeline Layout"),
bind_group_layouts: &[
Some(&eye.layout),
Some(&texture_bind_group_layout),
],
bind_group_layouts: &[Some(&eye.layout), Some(&texture_bind_group_layout)],
immediate_size: 0,
});
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
let instance_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Render Pipeline"),
layout: Some(&render_pipeline_layout),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
buffers: &[
SimpleVertex::desc(),SimpleInstances::desc(),
],
buffers: &[SimpleVertex::desc(), SimpleInstances::desc()],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
@ -877,7 +1032,7 @@ impl Renderer {
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
primitive: Default::default(), /*wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
@ -885,12 +1040,12 @@ impl Renderer {
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
},
}*/
depth_stencil: Some(wgpu::DepthStencilState {
stencil: wgpu::StencilState::default(),
format: wgpu::TextureFormat::Depth32Float,
depth_write_enabled: Some(true),
depth_compare: Some(wgpu::CompareFunction::Less),
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
@ -902,7 +1057,45 @@ impl Renderer {
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),
height: config.height.max(1),
depth_or_array_layers: 1,
@ -920,8 +1113,8 @@ impl Renderer {
};
let depth_texture = device.create_texture(&desc);
let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
let depth_sampler = device.create_sampler(
&wgpu::SamplerDescriptor { // 4.
let depth_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
// 4.
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
@ -932,31 +1125,37 @@ impl Renderer {
lod_min_clamp: 0.0,
lod_max_clamp: 100.0,
..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"),
contents: bytemuck::cast_slice(&DEFAULT_VERTICES),
usage: wgpu::BufferUsages::VERTEX,
}
});
let default_material = SimpleMaterial::new(
&device,
&texture_bind_group_layout,
&default_texture,
&default_texture,
&default_texture,
MaterialProperties::default(),
);
Ok(Renderer {
id_count: 0,
material_layout: texture_bind_group_layout,
default_texture: texture,
default_texture,
default_material,
depth_texture: SimpleTexture {
texture: depth_texture,
view: depth_view,
},
instances,
pipeline,
sky_pipeline,
instance_pipeline,
surface,
config,
device,
@ -966,7 +1165,6 @@ impl Renderer {
}
pub(crate) fn render(&mut self, window: &Arc<Window>) -> anyhow::Result<()> {
window.request_redraw();
let output = match self.surface.get_current_texture() {
wgpu::CurrentSurfaceTexture::Success(surface_texture) => surface_texture,
wgpu::CurrentSurfaceTexture::Suboptimal(surface_texture) => {
@ -1009,7 +1207,12 @@ impl Renderer {
resolve_target: None,
depth_slice: None,
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,
},
})],
@ -1026,10 +1229,15 @@ impl Renderer {
multiview_mask: None,
});
pass.set_pipeline(&self.pipeline);
pass.set_pipeline(&self.instance_pipeline);
pass.set_bind_group(0, &self.eye.group, &[]);
pass.set_vertex_buffer(1, self.instances.instance_buffer.slice(..));
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()));

View file

@ -1,10 +1,10 @@
use crate::render::{Renderer, SimpleLightData, SimpleModelData};
use glam::{DVec3, IVec3, Mat4, UVec3, Vec3, Vec4Swizzles};
use std::cell::RefCell;
use std::hash::{BuildHasherDefault, Hash, Hasher};
use std::ops::{Div, Mul};
use std::rc::Rc;
use glam::{DVec3, IVec3, Mat4, UVec3, Vec3, Vec4Swizzles};
use wgpu::naga::{FastHashMap, FastHashSet};
use crate::render::{SimpleModelData, SimpleLightData, Renderer};
#[derive(Clone)]
pub enum Shape {
@ -108,7 +108,7 @@ impl Block {
match self.blocks[index] {
Some(ref mut block) => {
block.place_pos(interest, new_pos, rad, cs);
},
}
None => {
let mut block = Box::new(Block::new());
block.place_pos(interest, new_pos, rad, cs);
@ -123,19 +123,20 @@ impl Block {
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)
}
}
}
}
@ -159,7 +160,12 @@ impl World {
}
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()
self.debug_world_map_object = self
.renderer
.as_mut()
.unwrap()
.load_from_gltf(include_bytes!("../assets/cube.glb"))
.first_object()
}
pub fn add_object(&mut self, object: SimpleObject) {
self.place(Interest::Object(object.clone()));
@ -170,12 +176,8 @@ impl World {
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 light_step(&mut self) {}
pub fn object_step(&mut self) {}
pub fn debug_step(&mut self) {
self.light_step();
self.object_step();
@ -212,11 +214,14 @@ impl World {
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)
},
(
collider.transform.to_scale_rotation_translation().2,
collider.radius,
)
}
};
self.place_pos(interest, pos, rad);
}