44//! `Handle<Material>` and `Handle<Mesh>` for all of your instances.
55//!
66//! This example is intended for advanced users and shows how to make a custom instancing
7- //! implementation using bevy 's low level rendering api .
7+ //! implementation using Bevy 's low level rendering API .
88//! It's generally recommended to try the built-in instancing before going with this approach.
99
1010use bevy:: {
@@ -36,11 +36,13 @@ use bevy::{
3636} ;
3737use bytemuck:: { Pod , Zeroable } ;
3838
39- /// This example uses a shader source file from the assets subdirectory
39+ /// Path to the WGSL shader asset used for custom instancing rendering.
4040const SHADER_ASSET_PATH : & str = "shaders/instancing.wgsl" ;
4141
42+ /// Component holding per-instance data for custom rendering.
4243#[ derive( Component ) ]
4344pub struct InstanceMaterialData {
45+ /// A list of per-instance transform and color data.
4446 pub instances : Vec < InstanceData > ,
4547}
4648
@@ -56,6 +58,7 @@ impl ExtractComponent for InstanceMaterialData {
5658 }
5759}
5860
61+ /// Plugin that sets up the custom voxel material pipeline.
5962pub struct VoxelMaterialPlugin ;
6063
6164impl Plugin for VoxelMaterialPlugin {
@@ -78,13 +81,17 @@ impl Plugin for VoxelMaterialPlugin {
7881 }
7982}
8083
84+ /// Single instance data containing position, scale and color.
8185#[ derive( Clone , Copy , Pod , Zeroable ) ]
8286#[ repr( C ) ]
8387pub struct InstanceData {
84- pub pos_scale : [ f32 ; 4 ] , // x, y, z, scale
88+ /// (x, y, z) position and uniform scale.
89+ pub pos_scale : [ f32 ; 4 ] ,
90+ /// RGBA color.
8591 pub color : [ f32 ; 4 ] ,
8692}
8793
94+ /// Queues custom rendering commands for entities with `InstanceMaterialData`.
8895#[ allow( clippy:: too_many_arguments) ]
8996fn queue_custom (
9097 transparent_3d_draw_functions : Res < DrawFunctions < Transparent3d > > ,
@@ -105,9 +112,9 @@ fn queue_custom(
105112 } ;
106113
107114 let msaa_key = MeshPipelineKey :: from_msaa_samples ( msaa. samples ( ) ) ;
108-
109115 let view_key = msaa_key | MeshPipelineKey :: from_hdr ( view. hdr ) ;
110116 let rangefinder = view. rangefinder3d ( ) ;
117+
111118 for ( entity, main_entity) in & material_meshes {
112119 let Some ( mesh_instance) = render_mesh_instances. render_mesh_queue_data ( * main_entity)
113120 else {
@@ -116,6 +123,7 @@ fn queue_custom(
116123 let Some ( mesh) = meshes. get ( mesh_instance. mesh_asset_id ) else {
117124 continue ;
118125 } ;
126+
119127 let key =
120128 view_key | MeshPipelineKey :: from_primitive_topology ( mesh. primitive_topology ( ) ) ;
121129 let pipeline = pipelines
@@ -133,12 +141,14 @@ fn queue_custom(
133141 }
134142}
135143
144+ /// GPU buffer holding instance data ready for rendering.
136145#[ derive( Component ) ]
137146struct InstanceBuffer {
138147 buffer : Buffer ,
139148 length : usize ,
140149}
141150
151+ /// Prepares instance buffers each frame, sorting instances by distance to camera.
142152fn prepare_instance_buffers (
143153 mut commands : Commands ,
144154 query : Query < ( Entity , & InstanceMaterialData ) > ,
@@ -148,23 +158,20 @@ fn prepare_instance_buffers(
148158 let Some ( camera) = cameras. iter ( ) . next ( ) else {
149159 return ;
150160 } ;
151-
152161 let cam_pos = camera. world_from_view . transform_point ( Vec3 :: ZERO ) ;
153162
154163 for ( entity, instance_data) in & query {
155164 let mut sorted_instances = instance_data. instances . clone ( ) ;
156165
157166 if sorted_instances. is_empty ( ) {
158- // No instances, remove any existing buffer or do nothing
159167 commands. entity ( entity) . remove :: < InstanceBuffer > ( ) ;
160168 continue ;
161169 }
162170
163- // Sort instances by distance from camera ( back-to-front)
171+ // Sort back-to-front for proper alpha blending
164172 sorted_instances. sort_by ( |a, b| {
165173 let a_pos = Vec3 :: new ( a. pos_scale [ 0 ] , a. pos_scale [ 1 ] , a. pos_scale [ 2 ] ) ;
166174 let b_pos = Vec3 :: new ( b. pos_scale [ 0 ] , b. pos_scale [ 1 ] , b. pos_scale [ 2 ] ) ;
167-
168175 let a_dist = cam_pos. distance_squared ( a_pos) ;
169176 let b_dist = cam_pos. distance_squared ( b_pos) ;
170177
@@ -186,9 +193,12 @@ fn prepare_instance_buffers(
186193 }
187194}
188195
196+ /// Custom pipeline for instanced mesh rendering.
189197#[ derive( Resource ) ]
190198struct CustomPipeline {
199+ /// The custom shader handle.
191200 shader : Handle < Shader > ,
201+ /// Reference to Bevy's default mesh pipeline.
192202 mesh_pipeline : MeshPipeline ,
193203}
194204
@@ -215,22 +225,12 @@ impl SpecializedMeshPipeline for CustomPipeline {
215225
216226 let color_format = TextureFormat :: Rgba8UnormSrgb ;
217227
218- // Custom depth stencil settings
219228 descriptor. depth_stencil = Some ( DepthStencilState {
220229 format : TextureFormat :: Depth32Float ,
221230 depth_compare : CompareFunction :: Always ,
222- stencil : StencilState {
223- front : Default :: default ( ) ,
224- back : Default :: default ( ) ,
225- read_mask : 0 ,
226- write_mask : 0 ,
227- } , // Use default stencil state
231+ stencil : StencilState :: default ( ) ,
228232 depth_write_enabled : false ,
229- bias : DepthBiasState {
230- constant : 0 ,
231- slope_scale : 0.0 ,
232- clamp : 0.0 ,
233- } ,
233+ bias : DepthBiasState :: default ( ) ,
234234 } ) ;
235235
236236 descriptor. fragment . as_mut ( ) . unwrap ( ) . targets [ 0 ] = Some ( ColorTargetState {
@@ -247,7 +247,7 @@ impl SpecializedMeshPipeline for CustomPipeline {
247247 VertexAttribute {
248248 format: VertexFormat :: Float32x4 ,
249249 offset: 0 ,
250- shader_location: 3 , // shader locations 0-2 are taken up by Position, Normal and UV attributes
250+ shader_location: 3 ,
251251 } ,
252252 VertexAttribute {
253253 format: VertexFormat :: Float32x4 ,
@@ -262,13 +262,15 @@ impl SpecializedMeshPipeline for CustomPipeline {
262262 }
263263}
264264
265+ /// The custom draw command for rendering instances.
265266type DrawCustom = (
266267 SetItemPipeline ,
267268 SetMeshViewBindGroup < 0 > ,
268269 SetMeshBindGroup < 1 > ,
269270 DrawMeshInstanced ,
270271) ;
271272
273+ /// Draws a mesh multiple times using instance buffers.
272274struct DrawMeshInstanced ;
273275
274276impl < P : PhaseItem > RenderCommand < P > for DrawMeshInstanced {
@@ -288,7 +290,6 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMeshInstanced {
288290 ( meshes, render_mesh_instances, mesh_allocator) : SystemParamItem < ' w , ' _ , Self :: Param > ,
289291 pass : & mut TrackedRenderPass < ' w > ,
290292 ) -> RenderCommandResult {
291- // A borrow check workaround.
292293 let mesh_allocator = mesh_allocator. into_inner ( ) ;
293294
294295 let Some ( mesh_instance) = render_mesh_instances. render_mesh_queue_data ( item. main_entity ( ) )
0 commit comments