Add normal matrix for lighting, fix render multiple entities that use same model
This commit is contained in:
parent
a288c9b26c
commit
65467c5032
|
@ -77,10 +77,10 @@ async fn main() {
|
|||
TransformComponent::from(Transform::from_xyz(3.0, 0.5, -2.2)),
|
||||
)); */
|
||||
|
||||
world.spawn((
|
||||
/* world.spawn((
|
||||
ModelComponent(antique_camera_model),
|
||||
TransformComponent::from(Transform::from_xyz(0.0, -5.0, -10.0)),
|
||||
));
|
||||
)); */
|
||||
|
||||
/* let light = PointLight {
|
||||
color: Vec3::new(1.0, 1.0, 1.0),
|
||||
|
@ -90,18 +90,22 @@ async fn main() {
|
|||
quadratic: 0.032,
|
||||
};
|
||||
world.spawn((light,)); */
|
||||
let mut cube_tran = Transform::from_xyz(-3.5, 0.0, -7.0);
|
||||
cube_tran.rotate_y(math::Angle::Degrees(180.0));
|
||||
world.spawn((
|
||||
PointLight {
|
||||
/* PointLight {
|
||||
color: Vec3::new(1.0, 1.0, 1.0),
|
||||
intensity: 1.0,
|
||||
constant: 1.0,
|
||||
linear: 0.045,
|
||||
quadratic: 0.0075,
|
||||
},
|
||||
TransformComponent::from(Transform::from_xyz(-2.5, 0.0, -10.0)),
|
||||
}, */
|
||||
TransformComponent::from(cube_tran),
|
||||
ModelComponent(cube_model.clone()),
|
||||
));
|
||||
|
||||
let mut light_tran = Transform::from_xyz(3.5, 0.0, -7.0);
|
||||
light_tran.scale = Vec3::new(0.5, 0.5, 0.5);
|
||||
world.spawn((
|
||||
PointLight {
|
||||
color: Vec3::new(0.361, 0.984, 0.0),
|
||||
|
@ -110,7 +114,7 @@ async fn main() {
|
|||
linear: 0.045,
|
||||
quadratic: 0.0075,
|
||||
},
|
||||
TransformComponent::from(Transform::from_xyz(2.5, 0.0, -10.0)),
|
||||
TransformComponent::from(light_tran),
|
||||
ModelComponent(cube_model),
|
||||
));
|
||||
|
||||
|
@ -154,7 +158,7 @@ async fn main() {
|
|||
|
||||
let mut sys = BatchedSystem::new();
|
||||
sys.with_criteria(FixedTimestep::new(45));
|
||||
sys.with_system(spin_system);
|
||||
//sys.with_system(spin_system);
|
||||
sys.with_system(fps_system);
|
||||
|
||||
game.with_system("fixed", sys, &[]);
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"rdocCaptureSettings": 1,
|
||||
"settings": {
|
||||
"autoStart": true,
|
||||
"commandLine": "",
|
||||
"environment": [
|
||||
],
|
||||
"executable": "/media/data_drive/Development/Rust/lyra-test/engine/target/debug/testbed",
|
||||
"inject": false,
|
||||
"numQueuedFrames": 1,
|
||||
"options": {
|
||||
"allowFullscreen": true,
|
||||
"allowVSync": true,
|
||||
"apiValidation": false,
|
||||
"captureAllCmdLists": false,
|
||||
"captureCallstacks": false,
|
||||
"captureCallstacksOnlyDraws": false,
|
||||
"debugOutputMute": true,
|
||||
"delayForDebugger": 0,
|
||||
"hookIntoChildren": false,
|
||||
"refAllResources": false,
|
||||
"softMemoryLimit": 0,
|
||||
"verifyBufferAccess": false
|
||||
},
|
||||
"queuedFrameCap": 5,
|
||||
"workingDir": "/media/data_drive/Development/Rust/lyra-test/engine/examples/testbed"
|
||||
}
|
||||
}
|
|
@ -2,25 +2,21 @@ use edict::EntityId;
|
|||
|
||||
use crate::math::Transform;
|
||||
|
||||
use super::renderer::CachedTransform;
|
||||
|
||||
pub struct RenderJob {
|
||||
pub entity: EntityId,
|
||||
pub shader_id: u64,
|
||||
pub mesh_buffer_id: uuid::Uuid,
|
||||
|
||||
pub transform: Transform,
|
||||
pub last_transform: Option<CachedTransform>, // TODO: render interpolation
|
||||
}
|
||||
|
||||
impl RenderJob {
|
||||
pub fn new(entity: EntityId, shader_id: u64, mesh_buffer_id: uuid::Uuid, transform: Transform, last_transform: Option<CachedTransform>) -> Self {
|
||||
pub fn new(entity: EntityId, shader_id: u64, mesh_buffer_id: uuid::Uuid, transform: Transform) -> Self {
|
||||
Self {
|
||||
entity,
|
||||
shader_id,
|
||||
mesh_buffer_id,
|
||||
transform,
|
||||
last_transform,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -47,9 +47,9 @@ struct MeshBufferStorage {
|
|||
render_texture: Option<RenderTexture>,
|
||||
texture_bindgroup: Option<BindGroup>,
|
||||
|
||||
/// The index of the transform for this entity.
|
||||
/// The tuple is structured like this: (transform index, index of transform inside the buffer)
|
||||
transform_index: TransformBufferIndices,
|
||||
// The index of the transform for this entity.
|
||||
// The tuple is structured like this: (transform index, index of transform inside the buffer)
|
||||
//transform_index: TransformBufferIndices,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -78,8 +78,6 @@ pub struct BasicRenderer {
|
|||
entity_last_transforms: HashMap<EntityId, CachedTransform>,
|
||||
|
||||
transform_buffers: TransformBuffers,
|
||||
transform_bind_group_layout: BindGroupLayout,
|
||||
//transform_bind_group: wgpu::BindGroup,
|
||||
|
||||
render_limits: Limits,
|
||||
|
||||
|
@ -187,59 +185,7 @@ impl BasicRenderer {
|
|||
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(shader_src)),
|
||||
});
|
||||
|
||||
let transform_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
entries: &[
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStages::VERTEX,
|
||||
ty: wgpu::BindingType::Buffer {
|
||||
ty: wgpu::BufferBindingType::Uniform,
|
||||
has_dynamic_offset: true,
|
||||
min_binding_size: None,
|
||||
},
|
||||
count: None,
|
||||
}
|
||||
],
|
||||
label: Some("transform_bind_group_layout"),
|
||||
});
|
||||
|
||||
let transform_buffer = device.create_buffer(
|
||||
&wgpu::BufferDescriptor {
|
||||
label: Some("Transform Buffer 0"),
|
||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||
size: render_limits.max_uniform_buffer_binding_size as u64,
|
||||
mapped_at_creation: false,
|
||||
}
|
||||
);
|
||||
|
||||
let stride = render_limits.min_uniform_buffer_offset_alignment as usize + mem::size_of::<glam::Mat4>();
|
||||
let transform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &transform_bind_group_layout,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(
|
||||
wgpu::BufferBinding {
|
||||
buffer: &transform_buffer,
|
||||
offset: 0,
|
||||
size: Some(NonZeroU64::new(stride as u64).unwrap())
|
||||
}
|
||||
)
|
||||
}
|
||||
],
|
||||
label: Some("transform_bind_group"),
|
||||
});
|
||||
|
||||
// create create the transform buffer storage
|
||||
//let transforms = AVec::new(render_limits.min_uniform_buffer_offset_alignment as usize);
|
||||
let transform_buffers = TransformBuffers {
|
||||
max_transform_count: (render_limits.max_uniform_buffer_binding_size / mem::size_of::<glam::Mat4>() as u32) as usize,
|
||||
buffer_bindgroups: vec![( 0, transform_buffer, transform_bind_group )],
|
||||
just_updated: HashMap::new(),
|
||||
not_updated: HashMap::new(),
|
||||
dead_indices: VecDeque::new(),
|
||||
next_indices: TransformBufferIndices { buffer_index: 0, transform_index: 0 },
|
||||
};
|
||||
let transform_buffers = TransformBuffers::new(&device);
|
||||
|
||||
let camera_buffer = device.create_buffer_init(
|
||||
&wgpu::util::BufferInitDescriptor {
|
||||
|
@ -320,7 +266,6 @@ impl BasicRenderer {
|
|||
|
||||
render_limits,
|
||||
transform_buffers,
|
||||
transform_bind_group_layout,
|
||||
|
||||
inuse_camera: RenderCamera::new(size),
|
||||
camera_buffer,
|
||||
|
@ -338,7 +283,7 @@ impl BasicRenderer {
|
|||
let mut pipelines = HashMap::new();
|
||||
pipelines.insert(0, Arc::new(FullRenderPipeline::new(&s.device, &s.config, &shader,
|
||||
vec![super::vertex::Vertex::desc(),],
|
||||
vec![&s.texture_bind_group_layout, &s.transform_bind_group_layout, &camera_bind_group_layout,
|
||||
vec![&s.texture_bind_group_layout, &s.transform_buffers.bindgroup_layout, &camera_bind_group_layout,
|
||||
&s.light_buffers.bindgroup_layout])));
|
||||
s.render_pipelines = pipelines;
|
||||
|
||||
|
@ -465,58 +410,20 @@ impl BasicRenderer {
|
|||
buffer_indices,
|
||||
render_texture: None,
|
||||
texture_bindgroup: diffuse_bindgroup,
|
||||
transform_index: transform_indices
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_transform_buffers(&mut self) -> TransformBufferIndices {
|
||||
let buffers = &mut self.transform_buffers;
|
||||
|
||||
let transform_buffer = self.device.create_buffer(
|
||||
&wgpu::BufferDescriptor {
|
||||
label: Some(&format!("Transform Buffer {}", buffers.buffer_bindgroups.len())),
|
||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||
size: self.render_limits.max_uniform_buffer_binding_size as u64,
|
||||
mapped_at_creation: false,
|
||||
}
|
||||
);
|
||||
|
||||
let stride = self.render_limits.min_uniform_buffer_offset_alignment as usize + mem::size_of::<glam::Mat4>();
|
||||
let transform_bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &self.transform_bind_group_layout,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(
|
||||
wgpu::BufferBinding {
|
||||
buffer: &transform_buffer,
|
||||
offset: 0,
|
||||
size: Some(NonZeroU64::new(stride as u64).unwrap())
|
||||
}
|
||||
)
|
||||
}
|
||||
],
|
||||
label: Some("transform_bind_group"),
|
||||
});
|
||||
|
||||
let indices = TransformBufferIndices { buffer_index: buffers.buffer_bindgroups.len(), transform_index: 0 };
|
||||
buffers.buffer_bindgroups.push(( 0, transform_buffer, transform_bind_group ));
|
||||
buffers.next_indices = indices;
|
||||
indices
|
||||
}
|
||||
|
||||
/// Processes the mesh for the renderer, storing and creating buffers as needed. Returns true if a new mesh was processed.
|
||||
fn process_mesh(&mut self, entity: EntityId, transform: Transform, mesh: &Mesh) -> bool {
|
||||
if self.transform_buffers.should_expand() {
|
||||
self.transform_buffers.expand_buffers(&self.device);
|
||||
}
|
||||
|
||||
let indices = self.transform_buffers.update_or_insert(&self.queue, &self.render_limits,
|
||||
entity, || transform.calculate_mat4());
|
||||
entity, || ( transform.calculate_mat4(), glam::Mat3::from_quat(transform.rotation) ));
|
||||
|
||||
#[allow(clippy::map_entry)]
|
||||
if !self.mesh_buffers.contains_key(&mesh.uuid) {
|
||||
// check if the transform buffers need to be expanded
|
||||
if self.transform_buffers.should_expand() {
|
||||
self.expand_transform_buffers();
|
||||
}
|
||||
|
||||
// create the mesh's buffers
|
||||
let buffers = self.create_mesh_buffers(mesh, indices);
|
||||
self.mesh_buffers.insert(mesh.uuid, buffers);
|
||||
|
@ -530,7 +437,6 @@ impl BasicRenderer {
|
|||
impl Renderer for BasicRenderer {
|
||||
fn prepare(&mut self, main_world: &mut edict::World) {
|
||||
let last_epoch = main_world.epoch();
|
||||
debug!("Last epoch: {last_epoch:?}");
|
||||
|
||||
let mut alive_entities = HashSet::new();
|
||||
|
||||
|
@ -560,6 +466,7 @@ impl Renderer for BasicRenderer {
|
|||
cached
|
||||
}
|
||||
};
|
||||
//debug!("Transform: {:?}, comp: {:?}", cached.to_transform.translation, transform.transform.translation);
|
||||
|
||||
let fixed_time = match cached.last_updated_at {
|
||||
Some(last_updated_at) => cached.cached_at - last_updated_at,
|
||||
|
@ -577,7 +484,7 @@ impl Renderer for BasicRenderer {
|
|||
}
|
||||
|
||||
let shader = mesh.material().shader_uuid.unwrap_or(0);
|
||||
let job = RenderJob::new(entity, shader, mesh.uuid, transform_val, None);
|
||||
let job = RenderJob::new(entity, shader, mesh.uuid, transform_val);
|
||||
self.render_jobs.push_back(job);
|
||||
}
|
||||
}
|
||||
|
@ -654,7 +561,7 @@ impl Renderer for BasicRenderer {
|
|||
|
||||
// get the mesh (containing vertices) and the buffers from storage
|
||||
let buffers = self.mesh_buffers.get(&job.mesh_buffer_id).unwrap();
|
||||
|
||||
|
||||
// Bind the optional texture
|
||||
if let Some(tex) = buffers.texture_bindgroup.as_ref() {
|
||||
render_pass.set_bind_group(0, tex, &[]);
|
||||
|
@ -663,10 +570,11 @@ impl Renderer for BasicRenderer {
|
|||
}
|
||||
|
||||
// Get the bindgroup for job's transform and bind to it using an offset.
|
||||
let transform_indices = buffers.transform_index;
|
||||
let (_, _, bindgroup) = self.transform_buffers.buffer_bindgroups.get(transform_indices.buffer_index).unwrap();
|
||||
let offset = TransformBuffers::get_offset_for(&self.render_limits, transform_indices);
|
||||
render_pass.set_bind_group(1, bindgroup, &[ offset as u32, ]);
|
||||
let transform_indices = *self.transform_buffers.entity_indices(job.entity).unwrap();
|
||||
let bindgroup = self.transform_buffers.bind_group(transform_indices).unwrap();
|
||||
//let bindgroup = self.transform_buffers.entity_bind_group(job.entity).unwrap();
|
||||
let offset = TransformBuffers::index_offset(&self.render_limits, transform_indices) as u32;
|
||||
render_pass.set_bind_group(1, bindgroup, &[ offset, offset, ]);
|
||||
|
||||
// Bind camera
|
||||
render_pass.set_bind_group(2, &self.camera_bind_group, &[]);
|
||||
|
|
|
@ -36,6 +36,8 @@ struct Lights {
|
|||
|
||||
@group(1) @binding(0)
|
||||
var<uniform> u_model_transform: mat4x4<f32>;
|
||||
@group(1) @binding(1)
|
||||
var<uniform> u_model_normal_matrix: mat3x3<f32>;
|
||||
|
||||
@group(2) @binding(0)
|
||||
var<uniform> u_camera: CameraUniform;
|
||||
|
@ -52,9 +54,8 @@ fn vs_main(
|
|||
out.tex_coords = model.tex_coords;
|
||||
out.clip_position = u_camera.view_proj * u_model_transform * vec4<f32>(model.position, 1.0);
|
||||
|
||||
out.world_normal = (u_model_transform * vec4<f32>(model.normal, 0.0)).xyz;
|
||||
out.world_normal = u_model_normal_matrix * model.normal;
|
||||
|
||||
//out.world_normal = model.normal;
|
||||
var world_position: vec4<f32> = u_model_transform * vec4<f32>(model.position, 1.0);
|
||||
out.world_position = world_position.xyz;
|
||||
|
||||
|
|
|
@ -1,75 +1,129 @@
|
|||
use std::collections::{VecDeque, HashMap};
|
||||
use std::{collections::{VecDeque, HashMap}, num::NonZeroU64};
|
||||
|
||||
use edict::EntityId;
|
||||
use wgpu::Limits;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
use std::mem;
|
||||
|
||||
#[derive(Default, Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub(crate) struct TransformBufferIndices {
|
||||
pub buffer_index: usize,
|
||||
pub transform_index: usize,
|
||||
}
|
||||
|
||||
/// A struct representing a single transform buffer. There can be multiple of these
|
||||
pub(crate) struct TransformBufferEntry {
|
||||
pub len: usize,
|
||||
pub transform_buf: wgpu::Buffer,
|
||||
pub normal_mat_buf: wgpu::Buffer,
|
||||
pub bindgroup: wgpu::BindGroup,
|
||||
}
|
||||
|
||||
pub(crate) struct TransformBuffers {
|
||||
//transform_layout: wgpu::BindGroupLayout,
|
||||
pub bindgroup_layout: wgpu::BindGroupLayout,
|
||||
/// A vector storing the EntityId and
|
||||
pub just_updated: HashMap<EntityId, TransformBufferIndices>,
|
||||
pub not_updated: HashMap<EntityId, TransformBufferIndices>,
|
||||
pub dead_indices: VecDeque<TransformBufferIndices>,
|
||||
pub next_indices: TransformBufferIndices,
|
||||
/// (transform count, buffer, bindgroup)
|
||||
pub buffer_bindgroups: Vec<(usize, wgpu::Buffer, wgpu::BindGroup)>,
|
||||
pub buffer_bindgroups: Vec<TransformBufferEntry>,
|
||||
/// The max amount of transforms in a buffer
|
||||
pub max_transform_count: usize,
|
||||
}
|
||||
|
||||
impl TransformBuffers {
|
||||
pub fn new(device: &wgpu::Device) -> Self {
|
||||
let limits = device.limits();
|
||||
|
||||
let bindgroup_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
entries: &[
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStages::VERTEX,
|
||||
ty: wgpu::BindingType::Buffer {
|
||||
ty: wgpu::BufferBindingType::Uniform,
|
||||
has_dynamic_offset: true,
|
||||
min_binding_size: None,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStages::VERTEX,
|
||||
ty: wgpu::BindingType::Buffer {
|
||||
ty: wgpu::BufferBindingType::Uniform,
|
||||
has_dynamic_offset: true,
|
||||
min_binding_size: None,
|
||||
},
|
||||
count: None,
|
||||
}
|
||||
],
|
||||
label: Some("transform_bind_group_layout"),
|
||||
});
|
||||
|
||||
let mut s = Self {
|
||||
max_transform_count: limits.max_uniform_buffer_binding_size as usize / (mem::size_of::<glam::Mat4>() + mem::size_of::<glam::Mat3>()),
|
||||
buffer_bindgroups: Vec::new(),
|
||||
bindgroup_layout,
|
||||
just_updated: HashMap::new(),
|
||||
not_updated: HashMap::new(),
|
||||
dead_indices: VecDeque::new(),
|
||||
next_indices: TransformBufferIndices::default(),
|
||||
};
|
||||
|
||||
// create the first uniform buffer
|
||||
s.expand_buffers(device);
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
/// Update an entity's buffer with the new transform. Will panic if the entity isn't stored
|
||||
pub fn update_entity(&mut self, queue: &wgpu::Queue, limits: &Limits, entity: EntityId, transform: glam::Mat4) -> TransformBufferIndices {
|
||||
pub fn update_entity(&mut self, queue: &wgpu::Queue, limits: &Limits, entity: EntityId, transform: glam::Mat4, normal_matrix: glam::Mat3) -> TransformBufferIndices {
|
||||
let indices = self.not_updated.remove(&entity)
|
||||
.or_else(|| self.just_updated.remove(&entity))
|
||||
.expect("Use 'insert_entity' for new entities");
|
||||
self.just_updated.insert(entity, indices);
|
||||
|
||||
let (_, buffer, _) = self.buffer_bindgroups.get(indices.buffer_index).unwrap();
|
||||
queue.write_buffer(buffer, indices.transform_index as u64 * limits.min_uniform_buffer_offset_alignment as u64, bytemuck::bytes_of(&transform));
|
||||
let buffer = self.buffer_bindgroups.get(indices.buffer_index).unwrap();
|
||||
let offset = Self::index_offset(limits, indices);
|
||||
queue.write_buffer(&buffer.transform_buf, offset, bytemuck::bytes_of(&transform));
|
||||
queue.write_buffer(&buffer.normal_mat_buf, offset, bytemuck::bytes_of(&normal_matrix));
|
||||
indices
|
||||
}
|
||||
|
||||
/// Insert a new entity into the buffer, returns where it was stored.
|
||||
pub fn insert_entity(&mut self, queue: &wgpu::Queue, limits: &Limits, entity: EntityId, transform: glam::Mat4) -> TransformBufferIndices {
|
||||
// get a dead index, or create a new one
|
||||
let (indices, buffer) = if let Some(index) = self.dead_indices.pop_front() {
|
||||
let (_, buffer, _) = self.buffer_bindgroups.get(index.buffer_index).unwrap();
|
||||
(index, buffer)
|
||||
} else {
|
||||
let indices = &mut self.next_indices;
|
||||
let this_idx = *indices;
|
||||
let (count, buffer, _) = self.buffer_bindgroups.get_mut(indices.buffer_index).unwrap();
|
||||
pub fn insert_entity(&mut self, queue: &wgpu::Queue, limits: &Limits, entity: EntityId, transform: glam::Mat4, normal_matrix: glam::Mat3) -> TransformBufferIndices {
|
||||
let indices = match self.dead_indices.pop_front() {
|
||||
Some(indices) => indices,
|
||||
None => {
|
||||
let indices = &mut self.next_indices;
|
||||
let this_idx = *indices;
|
||||
let entry = self.buffer_bindgroups.get_mut(indices.buffer_index).unwrap();
|
||||
|
||||
if *count >= self.max_transform_count {
|
||||
panic!("Transform buffer is filled and 'next_indices' was not incremented! Was a new buffer created?");
|
||||
if entry.len >= self.max_transform_count {
|
||||
panic!("Transform buffer is filled and 'next_indices' was not incremented! Was a new buffer created?");
|
||||
}
|
||||
|
||||
entry.len += 1;
|
||||
indices.transform_index += 1;
|
||||
this_idx
|
||||
}
|
||||
|
||||
*count += 1;
|
||||
indices.transform_index += 1;
|
||||
|
||||
(this_idx, &*buffer)
|
||||
};
|
||||
|
||||
queue.write_buffer(buffer, Self::get_offset_for(limits, indices), bytemuck::bytes_of(&transform));
|
||||
|
||||
self.just_updated.insert(entity, indices);
|
||||
indices
|
||||
self.update_entity(queue, limits, entity, transform, normal_matrix)
|
||||
}
|
||||
|
||||
/// Update or insert an entities transform
|
||||
pub fn update_or_insert<TFn>(&mut self, queue: &wgpu::Queue, limits: &Limits, entity: EntityId, transform_fn: TFn) -> TransformBufferIndices
|
||||
where TFn: Fn() -> glam::Mat4
|
||||
{
|
||||
where TFn: Fn() -> (glam::Mat4, glam::Mat3)
|
||||
{
|
||||
let (tran, norm) = transform_fn();
|
||||
if self.contains(entity) {
|
||||
self.update_entity(queue, limits, entity, transform_fn())
|
||||
self.update_entity(queue, limits, entity, tran, norm)
|
||||
} else {
|
||||
self.insert_entity(queue, limits, entity, transform_fn())
|
||||
self.insert_entity(queue, limits, entity, tran, norm)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,16 +142,97 @@ impl TransformBuffers {
|
|||
self.just_updated.clear();
|
||||
}
|
||||
|
||||
pub fn get_offset_for(limits: &Limits, indices: TransformBufferIndices) -> u64 {
|
||||
/// Returns the offset for the transform index in the buffer
|
||||
pub fn index_offset(limits: &Limits, indices: TransformBufferIndices) -> u64 {
|
||||
indices.transform_index as u64 * limits.min_uniform_buffer_offset_alignment as u64
|
||||
}
|
||||
|
||||
/// Returns whether or not the transform buffers should be expanded
|
||||
pub fn should_expand(&self) -> bool {
|
||||
if let Some(( count, _, _ )) = self.buffer_bindgroups.last() {
|
||||
*count >= self.max_transform_count
|
||||
if let Some(entry) = self.buffer_bindgroups.last() {
|
||||
entry.len >= self.max_transform_count
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the bind group for the index
|
||||
pub fn bind_group(&self, index: TransformBufferIndices) -> Option<&wgpu::BindGroup> {
|
||||
self.buffer_bindgroups.get(index.buffer_index)
|
||||
.map(|entry| &entry.bindgroup)
|
||||
}
|
||||
|
||||
pub fn entity_bind_group(&self, entity: EntityId) -> Option<&wgpu::BindGroup> {
|
||||
self.entity_indices(entity).and_then(|i| self.bind_group(*i))
|
||||
}
|
||||
|
||||
/// Expand the Transform buffers by adding another uniform buffer binding
|
||||
pub fn expand_buffers(&mut self, device: &wgpu::Device) {
|
||||
let limits = device.limits();
|
||||
let max_buffer_sizes = (limits.max_uniform_buffer_binding_size as u64) / 2;
|
||||
|
||||
let transform_buffer = device.create_buffer(
|
||||
&wgpu::BufferDescriptor {
|
||||
label: Some(&format!("Transform Buffer {}", self.buffer_bindgroups.len())),
|
||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||
size: max_buffer_sizes,
|
||||
mapped_at_creation: false,
|
||||
}
|
||||
);
|
||||
|
||||
let normal_mat_buffer = device.create_buffer(
|
||||
&wgpu::BufferDescriptor {
|
||||
label: Some(&format!("Normal Matrix Buffer {}", self.buffer_bindgroups.len())),
|
||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||
size: max_buffer_sizes,
|
||||
mapped_at_creation: false,
|
||||
}
|
||||
);
|
||||
|
||||
/* let stride = limits.min_uniform_buffer_offset_alignment as u64
|
||||
+ mem::size_of::<glam::Mat4>() as u64 + mem::size_of::<glam::Mat3>() as u64; */
|
||||
let tran_stride = limits.min_uniform_buffer_offset_alignment as u64
|
||||
+ mem::size_of::<glam::Mat4>() as u64;
|
||||
let norm_stride = limits.min_uniform_buffer_offset_alignment as u64
|
||||
+ mem::size_of::<glam::Mat3>() as u64;
|
||||
|
||||
let transform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &self.bindgroup_layout,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(
|
||||
wgpu::BufferBinding {
|
||||
buffer: &transform_buffer,
|
||||
offset: 0,
|
||||
size: Some(NonZeroU64::new(tran_stride).unwrap())
|
||||
}
|
||||
)
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::Buffer(
|
||||
wgpu::BufferBinding {
|
||||
buffer: &normal_mat_buffer,
|
||||
offset: 0,
|
||||
size: Some(NonZeroU64::new(norm_stride).unwrap())
|
||||
}
|
||||
)
|
||||
}
|
||||
],
|
||||
label: Some("transform_bind_group"),
|
||||
});
|
||||
|
||||
let entry = TransformBufferEntry {
|
||||
bindgroup: transform_bind_group,
|
||||
transform_buf: transform_buffer,
|
||||
normal_mat_buf: normal_mat_buffer,
|
||||
len: 0,
|
||||
};
|
||||
self.buffer_bindgroups.push(entry);
|
||||
}
|
||||
|
||||
pub fn entity_indices(&self, entity: EntityId) -> Option<&TransformBufferIndices> {
|
||||
self.just_updated.get(&entity).or_else(|| self.not_updated.get(&entity))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue