diff --git a/assets-src/playermodel1.blend b/assets-src/playermodel1.blend index d9449fb..1f49949 100644 Binary files a/assets-src/playermodel1.blend and b/assets-src/playermodel1.blend differ diff --git a/assets/playermodel1.obj b/assets/playermodel1.obj index 7831938..34c1973 100644 --- a/assets/playermodel1.obj +++ b/assets/playermodel1.obj @@ -1,24 +1,24 @@ # Blender 4.0.0 Beta # www.blender.org o Cube -v 0.666667 0.708333 -0.500000 -v 0.666667 -0.291667 -0.500000 -v 0.666667 0.708333 0.500000 -v 0.666667 -0.291667 0.500000 -v -0.333333 0.708333 -0.500000 -v -0.333333 -0.291667 -0.500000 -v -0.333333 0.708333 0.500000 -v -0.333333 -0.291667 0.500000 -v 0.666667 0.958333 -0.500000 -v 0.666667 0.958333 0.500000 -v 0.666667 0.708333 -0.166667 -v 0.666667 0.708333 0.166667 +v -0.500000 0.708333 -0.666667 +v -0.500000 -0.291667 -0.666667 +v 0.500000 0.708333 -0.666667 +v 0.500000 -0.291667 -0.666667 +v -0.500000 0.708333 0.333333 +v -0.500000 -0.291667 0.333333 +v 0.500000 0.708333 0.333333 +v 0.500000 -0.291667 0.333333 +v -0.500000 0.958333 -0.666667 +v 0.500000 0.958333 -0.666667 +v -0.166667 0.708333 -0.666667 +v 0.166667 0.708333 -0.666667 vn -0.0000 1.0000 -0.0000 -vn -0.0000 -0.0000 1.0000 -vn -1.0000 -0.0000 -0.0000 -vn -0.0000 -1.0000 -0.0000 vn 1.0000 -0.0000 -0.0000 +vn -0.0000 -0.0000 1.0000 +vn -0.0000 -1.0000 -0.0000 vn -0.0000 -0.0000 -1.0000 +vn -1.0000 -0.0000 -0.0000 vt 0.204555 0.291387 vt 0.043204 0.462923 vt 0.043204 0.291387 diff --git a/kubi/shaders/entities.wgsl b/kubi/shaders/entities.wgsl index 83eb27e..2a0526f 100644 --- a/kubi/shaders/entities.wgsl +++ b/kubi/shaders/entities.wgsl @@ -9,6 +9,10 @@ struct VertexInput { @location(0) uv: vec2, @location(1) position: vec3, @location(2) normal: vec3, + @location(3) mat_row0: vec4, + @location(4) mat_row1: vec4, + @location(5) mat_row2: vec4, + @location(6) mat_row3: vec4, } struct VertexOutput { @@ -21,8 +25,14 @@ struct VertexOutput { fn vs_main( in: VertexInput, ) -> VertexOutput { + let inst_mat = mat4x4( + in.mat_row0, + in.mat_row1, + in.mat_row2, + in.mat_row3, + ); var out: VertexOutput; - out.clip_position = camera.view_proj * vec4(in.position, 1.0); + out.clip_position = camera.view_proj * (inst_mat * vec4(in.position, 1.0)); out.uv = in.uv; out.normal = in.normal; return out; diff --git a/kubi/src/rendering.rs b/kubi/src/rendering.rs index 4b8c2f9..7c5736e 100644 --- a/kubi/src/rendering.rs +++ b/kubi/src/rendering.rs @@ -54,6 +54,7 @@ pub fn update_rendering_late() -> Workload { ( camera_uniform::update_camera_uniform_buffer, selection_box::update_selection_box_render_state.run_if(is_ingame), + entities::update_entities_render_state.run_if(is_ingame), ).into_workload() } diff --git a/kubi/src/rendering/entities.rs b/kubi/src/rendering/entities.rs index a91e2bb..84865cf 100644 --- a/kubi/src/rendering/entities.rs +++ b/kubi/src/rendering/entities.rs @@ -6,19 +6,24 @@ use crate::{ use super::{camera_uniform::CameraUniformBuffer, depth::DepthTexture, RenderCtx}; +mod instance; mod pipeline; #[derive(Unique)] pub struct EntitiesRenderState { pub pipeline: wgpu::RenderPipeline, + pub instance_buffer: instance::InstanceBuffer, } pub fn init_entities_render_state(storages: AllStoragesView) { storages.add_unique(EntitiesRenderState { pipeline: storages.run(pipeline::init_entities_pipeline), + instance_buffer: storages.run(instance::create_instance_buffer), }); } +pub use instance::update_instance_buffer as update_entities_render_state; + // TODO: entity models pub fn render_entities( ctx: &mut RenderCtx, @@ -26,11 +31,11 @@ pub fn render_entities( depth: UniqueView, prefabs: UniqueView, camera_ubo: UniqueView, - camera: View, - settings: UniqueView, - entities: View, - transform: View, ) { + if state.instance_buffer.count == 0 { + return + } + let mut rpass = ctx.encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: Some("rpass_draw_entities"), color_attachments: &[Some(wgpu::RenderPassColorAttachment { @@ -56,14 +61,7 @@ pub fn render_entities( rpass.set_bind_group(0, &prefabs.player_model_diffuse_bind_group, &[]); rpass.set_bind_group(1, &camera_ubo.camera_bind_group, &[]); rpass.set_vertex_buffer(0, prefabs.player_model.vertex.slice(..)); + rpass.set_vertex_buffer(1, state.instance_buffer.buffer.slice(..)); rpass.set_index_buffer(prefabs.player_model.index.slice(..), wgpu::IndexFormat::Uint32); - rpass.draw_indexed(0..prefabs.player_model.index_len, 0, 0..1); - - // let (camera_id, _camera) = camera.iter().with_id().next().expect("No cameras in the scene"); - - // for (entity_id, (_, trans)) in (&entities, &transform).iter().with_id() { - // //skip rendering camera holder (as the entity would block the view) - // if entity_id == camera_id { continue } - - // } + rpass.draw_indexed(0..prefabs.player_model.index_len, 0, 0..state.instance_buffer.count); } diff --git a/kubi/src/rendering/entities/instance.rs b/kubi/src/rendering/entities/instance.rs new file mode 100644 index 0000000..271949a --- /dev/null +++ b/kubi/src/rendering/entities/instance.rs @@ -0,0 +1,77 @@ +use bytemuck::{Pod, Zeroable}; +use kubi_shared::{entity::Entity, transform::Transform}; +use renderer::Renderer; +use shipyard::{EntityId, IntoIter, IntoWithId, UniqueView, UniqueViewMut, View}; + +use crate::{camera::Camera, rendering::renderer}; + +use super::EntitiesRenderState; + +#[derive(Clone, Copy, Pod, Zeroable)] +#[repr(C, packed)] +pub struct InstanceData { + pub mat: [f32; 4 * 4], +} + +impl InstanceData { + pub const LAYOUT: wgpu::VertexBufferLayout<'static> = wgpu::VertexBufferLayout { + array_stride: std::mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Instance, + attributes: &wgpu::vertex_attr_array![ + 3 => Float32x4, + 4 => Float32x4, + 5 => Float32x4, + 6 => Float32x4, + ], + }; +} + +pub struct InstanceBuffer { + pub count: u32, + pub buffer: wgpu::Buffer, +} + +pub fn create_instance_buffer( + renderer: UniqueView, +) -> InstanceBuffer { + let buffer = renderer.device().create_buffer(&wgpu::BufferDescriptor { + label: Some("instance_buffer"), + size: 255 * std::mem::size_of::() as u64, + usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + InstanceBuffer { count: 0, buffer } +} + +pub fn update_instance_buffer( + renderer: UniqueView, + mut state: UniqueViewMut, + entities: View, + transforms: View, + camera: View, +) { + //Get id of the camera entity (this assumes a single camera entity) + let cam_id = (&camera) + .iter().with_id().next() + .map(|(x, _)| x) + .unwrap_or(EntityId::dead()); + + // Create a list of instance data for all entities except ones that have camera attached + let mut instances = Vec::with_capacity(entities.len() - 1); + for (id, (_, trans)) in (&entities, &transforms).iter().with_id() { + if id == cam_id { continue } + instances.push(InstanceData { + mat: trans.0.to_cols_array(), + }); + } + + state.instance_buffer.count = instances.len() as u32; + + if !instances.is_empty() { + renderer.queue().write_buffer( + &state.instance_buffer.buffer, + 0, + bytemuck::cast_slice(&instances) + ); + } +} diff --git a/kubi/src/rendering/entities/pipeline.rs b/kubi/src/rendering/entities/pipeline.rs index 40f61a8..b7e8e42 100644 --- a/kubi/src/rendering/entities/pipeline.rs +++ b/kubi/src/rendering/entities/pipeline.rs @@ -2,6 +2,8 @@ use shipyard::UniqueView; use wgpu::include_wgsl; use crate::{prefabs::{GpuPrefabs, ModelVertex}, rendering::{camera_uniform::CameraUniformBuffer, Renderer}}; +use super::instance::InstanceData; + pub fn init_entities_pipeline( renderer: UniqueView, prefabs: UniqueView, @@ -27,6 +29,7 @@ pub fn init_entities_pipeline( entry_point: "vs_main", buffers: &[ ModelVertex::LAYOUT, + InstanceData::LAYOUT, ], }, fragment: Some(wgpu::FragmentState {