Add instances support
This commit is contained in:
parent
f8b81f3269
commit
77c717f90b
7 changed files with 158 additions and 31 deletions
40
Cargo.lock
generated
40
Cargo.lock
generated
|
@ -1929,8 +1929,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"rand_chacha",
|
"rand_chacha 0.3.1",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
||||||
|
dependencies = [
|
||||||
|
"rand_chacha 0.9.0",
|
||||||
|
"rand_core 0.9.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1940,7 +1950,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ppv-lite86",
|
"ppv-lite86",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core 0.9.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1952,6 +1972,15 @@ dependencies = [
|
||||||
"getrandom 0.2.16",
|
"getrandom 0.2.16",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.3.3",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rav1e"
|
name = "rav1e"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
@ -1978,8 +2007,8 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"paste",
|
"paste",
|
||||||
"profiling",
|
"profiling",
|
||||||
"rand",
|
"rand 0.8.5",
|
||||||
"rand_chacha",
|
"rand_chacha 0.3.1",
|
||||||
"simd_helpers",
|
"simd_helpers",
|
||||||
"system-deps",
|
"system-deps",
|
||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
|
@ -2112,6 +2141,7 @@ dependencies = [
|
||||||
"glam",
|
"glam",
|
||||||
"image",
|
"image",
|
||||||
"log",
|
"log",
|
||||||
|
"rand 0.9.1",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"vulkano",
|
"vulkano",
|
||||||
"vulkano-shaders",
|
"vulkano-shaders",
|
||||||
|
|
|
@ -23,3 +23,6 @@ glam = { version = "0.30" }
|
||||||
# Log and tracing
|
# Log and tracing
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
env_logger = "0.11"
|
env_logger = "0.11"
|
||||||
|
|
||||||
|
# Random
|
||||||
|
rand = "0.9"
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
layout (location = 0) in vec2 position;
|
layout (location = 0) in vec3 position;
|
||||||
layout (location = 1) in vec2 uv;
|
layout (location = 1) in vec2 uv;
|
||||||
|
layout (location = 2) in mat4 model;
|
||||||
|
|
||||||
layout (location = 0) out vec2 fragUv;
|
layout (location = 0) out vec2 fragUv;
|
||||||
|
|
||||||
|
@ -13,6 +14,7 @@ layout (set = 0, binding = 0) uniform MVP {
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
mat4 worldview = uniforms.view * uniforms.world;
|
mat4 worldview = uniforms.view * uniforms.world;
|
||||||
gl_Position = uniforms.projection * worldview * vec4(position, 0.0, 1.0);
|
vec4 modelPosition = model * vec4(position, 1.0);
|
||||||
|
gl_Position = uniforms.projection * worldview * modelPosition;
|
||||||
fragUv = uv;
|
fragUv = uv;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,26 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use glam::{Mat4, Quat, Vec3};
|
use glam::{Mat4, Quat, Vec3};
|
||||||
|
use vulkano::{
|
||||||
|
Validated,
|
||||||
|
buffer::{
|
||||||
|
AllocateBufferError, Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer,
|
||||||
|
},
|
||||||
|
memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator},
|
||||||
|
pipeline::graphics::vertex_input::Vertex,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct Transform {
|
pub struct Transform {
|
||||||
position: Vec3,
|
pub position: Vec3,
|
||||||
rotation: Quat,
|
pub rotation: Quat,
|
||||||
scale: Vec3,
|
pub scale: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BufferContents, Vertex)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct TransformRaw {
|
||||||
|
#[format(R32G32B32A32_SFLOAT)]
|
||||||
|
pub model: [[f32; 4]; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Transform {
|
impl Default for Transform {
|
||||||
|
@ -29,9 +46,35 @@ impl Transform {
|
||||||
self.scale *= scale;
|
self.scale *= scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mat4(&self) -> Mat4 {
|
pub fn into_raw(&self) -> TransformRaw {
|
||||||
Mat4::from_translation(self.position)
|
TransformRaw {
|
||||||
* Mat4::from_quat(self.rotation)
|
model: (Mat4::from_translation(self.position)
|
||||||
* Mat4::from_scale(self.scale)
|
* Mat4::from_quat(self.rotation)
|
||||||
|
* Mat4::from_scale(self.scale))
|
||||||
|
.to_cols_array_2d(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_buffer(
|
||||||
|
memory_allocator: &Arc<StandardMemoryAllocator>,
|
||||||
|
transforms: &[Transform],
|
||||||
|
) -> Result<Subbuffer<[TransformRaw]>, Validated<AllocateBufferError>> {
|
||||||
|
let transform_raws: Vec<TransformRaw> = transforms.iter().map(|t| t.into_raw()).collect();
|
||||||
|
|
||||||
|
let buffer = Buffer::from_iter(
|
||||||
|
memory_allocator.clone(),
|
||||||
|
BufferCreateInfo {
|
||||||
|
usage: BufferUsage::VERTEX_BUFFER,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
AllocationCreateInfo {
|
||||||
|
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
|
||||||
|
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
transform_raws,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,3 +10,13 @@ pub struct Vertex2D {
|
||||||
#[format(R32G32_SFLOAT)]
|
#[format(R32G32_SFLOAT)]
|
||||||
pub uv: [f32; 2],
|
pub uv: [f32; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(BufferContents, Vertex)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Vertex3D {
|
||||||
|
#[format(R32G32B32_SFLOAT)]
|
||||||
|
pub position: [f32; 3],
|
||||||
|
|
||||||
|
#[format(R32G32_SFLOAT)]
|
||||||
|
pub uv: [f32; 2],
|
||||||
|
}
|
||||||
|
|
|
@ -30,26 +30,26 @@ use vulkano::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::core::render::{
|
use crate::core::render::{
|
||||||
primitives::{mvp::MVP, vertex::Vertex2D},
|
primitives::{mvp::MVP, transform::TransformRaw, vertex::Vertex3D},
|
||||||
texture::Texture,
|
texture::Texture,
|
||||||
};
|
};
|
||||||
|
|
||||||
const VERTICES: [Vertex2D; 4] = [
|
const VERTICES: [Vertex3D; 4] = [
|
||||||
Vertex2D {
|
Vertex3D {
|
||||||
position: [0.0, 0.0],
|
position: [-0.5, -0.5, 0.0],
|
||||||
uv: [0.0, 0.0],
|
uv: [0.0, 0.0],
|
||||||
},
|
},
|
||||||
Vertex2D {
|
Vertex3D {
|
||||||
position: [0.0, 5.0],
|
position: [-0.5, 0.5, 0.0],
|
||||||
uv: [0.0, 0.5],
|
uv: [0.0, 1.0],
|
||||||
},
|
},
|
||||||
Vertex2D {
|
Vertex3D {
|
||||||
position: [10.0, 0.0],
|
position: [0.5, -0.5, 0.0],
|
||||||
uv: [1.0, 0.0],
|
uv: [1.0, 0.0],
|
||||||
},
|
},
|
||||||
Vertex2D {
|
Vertex3D {
|
||||||
position: [10.0, 5.0],
|
position: [0.5, 0.5, 0.0],
|
||||||
uv: [1.0, 0.5],
|
uv: [1.0, 1.0],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ pub mod shaders {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Square {
|
pub struct Square {
|
||||||
vertex_buffer: Subbuffer<[Vertex2D]>,
|
vertex_buffer: Subbuffer<[Vertex3D]>,
|
||||||
index_buffer: Subbuffer<[u32]>,
|
index_buffer: Subbuffer<[u32]>,
|
||||||
pipeline: Arc<GraphicsPipeline>,
|
pipeline: Arc<GraphicsPipeline>,
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,8 @@ impl Square {
|
||||||
.entry_point("main")
|
.entry_point("main")
|
||||||
.ok_or("Failed find main entry point of fragment shader".to_string())?;
|
.ok_or("Failed find main entry point of fragment shader".to_string())?;
|
||||||
|
|
||||||
let vertex_input_state = Vertex2D::per_vertex().definition(&vs)?;
|
let vertex_input_state =
|
||||||
|
[Vertex3D::per_vertex(), TransformRaw::per_instance()].definition(&vs)?;
|
||||||
|
|
||||||
let stages = [
|
let stages = [
|
||||||
PipelineShaderStageCreateInfo::new(vs),
|
PipelineShaderStageCreateInfo::new(vs),
|
||||||
|
@ -207,6 +208,7 @@ impl Square {
|
||||||
command_buffer: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
|
command_buffer: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
|
||||||
descriptor_set_allocator: &Arc<StandardDescriptorSetAllocator>,
|
descriptor_set_allocator: &Arc<StandardDescriptorSetAllocator>,
|
||||||
mvp_uniform: &Subbuffer<[MVP]>,
|
mvp_uniform: &Subbuffer<[MVP]>,
|
||||||
|
transform_uniform: &Subbuffer<[TransformRaw]>,
|
||||||
texture: &Texture,
|
texture: &Texture,
|
||||||
) -> Result<(), Box<dyn Error>> {
|
) -> Result<(), Box<dyn Error>> {
|
||||||
let layouts = self.pipeline.layout().set_layouts();
|
let layouts = self.pipeline.layout().set_layouts();
|
||||||
|
@ -235,11 +237,18 @@ impl Square {
|
||||||
0,
|
0,
|
||||||
vec![uniform_descriptor_set, texture_descriptor_set],
|
vec![uniform_descriptor_set, texture_descriptor_set],
|
||||||
)?;
|
)?;
|
||||||
command_buffer.bind_vertex_buffers(0, self.vertex_buffer.clone())?;
|
command_buffer
|
||||||
|
.bind_vertex_buffers(0, (self.vertex_buffer.clone(), transform_uniform.clone()))?;
|
||||||
command_buffer.bind_index_buffer(self.index_buffer.clone())?;
|
command_buffer.bind_index_buffer(self.index_buffer.clone())?;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
command_buffer.draw_indexed(INDICES.len() as u32, 1, 0, 0, 0)?;
|
command_buffer.draw_indexed(
|
||||||
|
INDICES.len() as u32,
|
||||||
|
transform_uniform.len() as u32,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
use std::{error::Error, sync::Arc};
|
use std::{error::Error, sync::Arc};
|
||||||
|
|
||||||
use crate::core::render::primitives::camera::Camera3D;
|
use crate::core::render::primitives::camera::Camera3D;
|
||||||
|
use crate::core::render::primitives::transform::Transform;
|
||||||
use crate::core::render::texture::Texture;
|
use crate::core::render::texture::Texture;
|
||||||
use crate::core::scene::Scene;
|
use crate::core::scene::Scene;
|
||||||
use crate::core::scene::SceneContext;
|
use crate::core::scene::SceneContext;
|
||||||
use egui_winit_vulkano::{Gui, egui};
|
use egui_winit_vulkano::{Gui, egui};
|
||||||
use glam::Mat4;
|
use glam::EulerRot;
|
||||||
|
use glam::Quat;
|
||||||
|
use glam::Vec3;
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
command_buffer::{
|
command_buffer::{
|
||||||
AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBufferAbstract,
|
AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBufferAbstract,
|
||||||
|
@ -21,6 +24,7 @@ use super::assets::square::Square;
|
||||||
|
|
||||||
pub struct MainSceneState {
|
pub struct MainSceneState {
|
||||||
square: Square,
|
square: Square,
|
||||||
|
instances: Vec<Transform>,
|
||||||
camera: Camera3D,
|
camera: Camera3D,
|
||||||
texture: Texture,
|
texture: Texture,
|
||||||
speed: f32,
|
speed: f32,
|
||||||
|
@ -43,6 +47,27 @@ impl Scene for MainScene {
|
||||||
scene_context.swapchain_format,
|
scene_context.swapchain_format,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
let num_instances = 100;
|
||||||
|
let instance_size = 10.0;
|
||||||
|
let instance_spacing = 10.0;
|
||||||
|
let num_instances_per_row = (num_instances as f32 / instance_spacing as f32).ceil() as u32;
|
||||||
|
let instances: Vec<Transform> = (0..num_instances)
|
||||||
|
.map(|i| Transform {
|
||||||
|
position: Vec3::new(
|
||||||
|
(i % num_instances_per_row) as f32 * (instance_spacing + instance_size),
|
||||||
|
0.0,
|
||||||
|
(i / num_instances_per_row) as f32 * (instance_spacing + instance_size),
|
||||||
|
),
|
||||||
|
rotation: Quat::from_euler(
|
||||||
|
EulerRot::XYZ,
|
||||||
|
0.0,
|
||||||
|
rand::random_range(0.0..=360.0),
|
||||||
|
0.0,
|
||||||
|
),
|
||||||
|
scale: Vec3::new(instance_size, instance_size, instance_size),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
let camera = Camera3D::new(
|
let camera = Camera3D::new(
|
||||||
scene_context.aspect_ratio,
|
scene_context.aspect_ratio,
|
||||||
std::f32::consts::FRAC_PI_2,
|
std::f32::consts::FRAC_PI_2,
|
||||||
|
@ -69,6 +94,7 @@ impl Scene for MainScene {
|
||||||
|
|
||||||
self.state = Some(MainSceneState {
|
self.state = Some(MainSceneState {
|
||||||
square,
|
square,
|
||||||
|
instances,
|
||||||
camera,
|
camera,
|
||||||
texture,
|
texture,
|
||||||
speed: 50.0,
|
speed: 50.0,
|
||||||
|
@ -129,12 +155,16 @@ impl Scene for MainScene {
|
||||||
.camera
|
.camera
|
||||||
.create_buffer(&scene_context.memory_allocator)?;
|
.create_buffer(&scene_context.memory_allocator)?;
|
||||||
|
|
||||||
|
let transform_uniform =
|
||||||
|
Transform::create_buffer(&scene_context.memory_allocator, &state.instances)?;
|
||||||
|
|
||||||
state
|
state
|
||||||
.square
|
.square
|
||||||
.render(
|
.render(
|
||||||
&mut builder,
|
&mut builder,
|
||||||
&scene_context.descriptor_set_allocator,
|
&scene_context.descriptor_set_allocator,
|
||||||
&camera_uniform,
|
&camera_uniform,
|
||||||
|
&transform_uniform,
|
||||||
&state.texture,
|
&state.texture,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue