@@ -6,9 +6,9 @@ use bevy_asset::{
6
6
} ;
7
7
use bevy_math:: { Vec2 , Vec3 } ;
8
8
use bevy_reflect:: TypePath ;
9
+ use bevy_render:: render_resource:: ShaderType ;
9
10
use bevy_tasks:: block_on;
10
11
use bytemuck:: { Pod , Zeroable } ;
11
- use half:: f16;
12
12
use lz4_flex:: frame:: { FrameDecoder , FrameEncoder } ;
13
13
use std:: io:: { Read , Write } ;
14
14
use thiserror:: Error ;
@@ -17,7 +17,7 @@ use thiserror::Error;
17
17
const MESHLET_MESH_ASSET_MAGIC : u64 = 1717551717668 ;
18
18
19
19
/// The current version of the [`MeshletMesh`] asset format.
20
- pub const MESHLET_MESH_ASSET_VERSION : u64 = 1 ;
20
+ pub const MESHLET_MESH_ASSET_VERSION : u64 = 2 ;
21
21
22
22
/// A mesh that has been pre-processed into multiple small clusters of triangles called meshlets.
23
23
///
@@ -47,12 +47,32 @@ pub struct MeshletMesh {
47
47
pub ( crate ) vertex_uvs : Arc < [ Vec2 ] > ,
48
48
/// Triangle indices for meshlets.
49
49
pub ( crate ) indices : Arc < [ u8 ] > ,
50
+ /// The BVH8 used for culling and LOD selection of the meshlets. The root is at index 0.
51
+ pub ( crate ) bvh : Arc < [ BvhNode ] > ,
50
52
/// The list of meshlets making up this mesh.
51
53
pub ( crate ) meshlets : Arc < [ Meshlet ] > ,
52
54
/// Spherical bounding volumes.
53
- pub ( crate ) meshlet_bounding_spheres : Arc < [ MeshletBoundingSpheres ] > ,
54
- /// Meshlet group and parent group simplification errors.
55
- pub ( crate ) meshlet_simplification_errors : Arc < [ MeshletSimplificationError ] > ,
55
+ pub ( crate ) meshlet_cull_data : Arc < [ MeshletCullData ] > ,
56
+ /// The tight AABB of the meshlet mesh, used for frustum and occlusion culling at the instance
57
+ /// level.
58
+ pub ( crate ) aabb : MeshletAabb ,
59
+ /// The depth of the culling BVH, used to determine the number of dispatches at runtime.
60
+ pub ( crate ) bvh_depth : u32 ,
61
+ }
62
+
63
+ /// A single BVH8 node in the BVH used for culling and LOD selection of a [`MeshletMesh`].
64
+ #[ derive( Copy , Clone , Default , Pod , Zeroable ) ]
65
+ #[ repr( C ) ]
66
+ pub struct BvhNode {
67
+ /// The tight AABBs of this node's children, used for frustum and occlusion during BVH
68
+ /// traversal.
69
+ pub aabbs : [ MeshletAabbErrorOffset ; 8 ] ,
70
+ /// The LOD bounding spheres of this node's children, used for LOD selection during BVH
71
+ /// traversal.
72
+ pub lod_bounds : [ MeshletBoundingSphere ; 8 ] ,
73
+ /// If `u8::MAX`, it indicates that the child of each children is a BVH node, otherwise it is the number of meshlets in the group.
74
+ pub child_counts : [ u8 ; 8 ] ,
75
+ pub _padding : [ u32 ; 2 ] ,
56
76
}
57
77
58
78
/// A single meshlet within a [`MeshletMesh`].
@@ -91,31 +111,37 @@ pub struct Meshlet {
91
111
/// Bounding spheres used for culling and choosing level of detail for a [`Meshlet`].
92
112
#[ derive( Copy , Clone , Pod , Zeroable ) ]
93
113
#[ repr( C ) ]
94
- pub struct MeshletBoundingSpheres {
95
- /// Bounding sphere used for frustum and occlusion culling for this meshlet.
96
- pub culling_sphere : MeshletBoundingSphere ,
114
+ pub struct MeshletCullData {
115
+ /// Tight bounding box, used for frustum and occlusion culling for this meshlet.
116
+ pub aabb : MeshletAabbErrorOffset ,
97
117
/// Bounding sphere used for determining if this meshlet's group is at the correct level of detail for a given view.
98
118
pub lod_group_sphere : MeshletBoundingSphere ,
99
- /// Bounding sphere used for determining if this meshlet's parent group is at the correct level of detail for a given view.
100
- pub lod_parent_group_sphere : MeshletBoundingSphere ,
101
119
}
102
120
103
- /// A spherical bounding volume used for a [`Meshlet`].
104
- #[ derive( Copy , Clone , Pod , Zeroable ) ]
121
+ /// An axis-aligned bounding box used for a [`Meshlet`].
122
+ #[ derive( Copy , Clone , Default , Pod , Zeroable , ShaderType ) ]
105
123
#[ repr( C ) ]
106
- pub struct MeshletBoundingSphere {
124
+ pub struct MeshletAabb {
107
125
pub center : Vec3 ,
108
- pub radius : f32 ,
126
+ pub half_extent : Vec3 ,
109
127
}
110
128
111
- /// Simplification error used for choosing level of detail for a [`Meshlet`].
112
- #[ derive( Copy , Clone , Pod , Zeroable ) ]
129
+ // An axis-aligned bounding box used for a [`Meshlet`].
130
+ #[ derive( Copy , Clone , Default , Pod , Zeroable , ShaderType ) ]
131
+ #[ repr( C ) ]
132
+ pub struct MeshletAabbErrorOffset {
133
+ pub center : Vec3 ,
134
+ pub error : f32 ,
135
+ pub half_extent : Vec3 ,
136
+ pub child_offset : u32 ,
137
+ }
138
+
139
+ /// A spherical bounding volume used for a [`Meshlet`].
140
+ #[ derive( Copy , Clone , Default , Pod , Zeroable ) ]
113
141
#[ repr( C ) ]
114
- pub struct MeshletSimplificationError {
115
- /// Simplification error used for determining if this meshlet's group is at the correct level of detail for a given view.
116
- pub group_error : f16 ,
117
- /// Simplification error used for determining if this meshlet's parent group is at the correct level of detail for a given view.
118
- pub parent_group_error : f16 ,
142
+ pub struct MeshletBoundingSphere {
143
+ pub center : Vec3 ,
144
+ pub radius : f32 ,
119
145
}
120
146
121
147
/// An [`AssetSaver`] for `.meshlet_mesh` [`MeshletMesh`] assets.
@@ -143,15 +169,23 @@ impl AssetSaver for MeshletMeshSaver {
143
169
. write_all ( & MESHLET_MESH_ASSET_VERSION . to_le_bytes ( ) )
144
170
. await ?;
145
171
172
+ writer. write_all ( bytemuck:: bytes_of ( & asset. aabb ) ) . await ?;
173
+ writer
174
+ . write_all ( bytemuck:: bytes_of ( & asset. bvh_depth ) )
175
+ . await ?;
176
+
146
177
// Compress and write asset data
147
178
let mut writer = FrameEncoder :: new ( AsyncWriteSyncAdapter ( writer) ) ;
148
179
write_slice ( & asset. vertex_positions , & mut writer) ?;
149
180
write_slice ( & asset. vertex_normals , & mut writer) ?;
150
181
write_slice ( & asset. vertex_uvs , & mut writer) ?;
151
182
write_slice ( & asset. indices , & mut writer) ?;
183
+ write_slice ( & asset. bvh , & mut writer) ?;
152
184
write_slice ( & asset. meshlets , & mut writer) ?;
153
- write_slice ( & asset. meshlet_bounding_spheres , & mut writer) ?;
154
- write_slice ( & asset. meshlet_simplification_errors , & mut writer) ?;
185
+ write_slice ( & asset. meshlet_cull_data , & mut writer) ?;
186
+ // BUG: Flushing helps with an async_fs bug, but it still fails sometimes. https://github.com/smol-rs/async-fs/issues/45
187
+ // ERROR bevy_asset::server: Failed to load asset with asset loader MeshletMeshLoader: failed to fill whole buffer
188
+ writer. flush ( ) ?;
155
189
writer. finish ( ) ?;
156
190
157
191
Ok ( ( ) )
@@ -184,24 +218,33 @@ impl AssetLoader for MeshletMeshLoader {
184
218
return Err ( MeshletMeshSaveOrLoadError :: WrongVersion { found : version } ) ;
185
219
}
186
220
221
+ let mut bytes = [ 0u8 ; size_of :: < MeshletAabb > ( ) ] ;
222
+ reader. read_exact ( & mut bytes) . await ?;
223
+ let aabb = bytemuck:: cast ( bytes) ;
224
+ let mut bytes = [ 0u8 ; size_of :: < u32 > ( ) ] ;
225
+ reader. read_exact ( & mut bytes) . await ?;
226
+ let bvh_depth = u32:: from_le_bytes ( bytes) ;
227
+
187
228
// Load and decompress asset data
188
229
let reader = & mut FrameDecoder :: new ( AsyncReadSyncAdapter ( reader) ) ;
189
230
let vertex_positions = read_slice ( reader) ?;
190
231
let vertex_normals = read_slice ( reader) ?;
191
232
let vertex_uvs = read_slice ( reader) ?;
192
233
let indices = read_slice ( reader) ?;
234
+ let bvh = read_slice ( reader) ?;
193
235
let meshlets = read_slice ( reader) ?;
194
- let meshlet_bounding_spheres = read_slice ( reader) ?;
195
- let meshlet_simplification_errors = read_slice ( reader) ?;
236
+ let meshlet_cull_data = read_slice ( reader) ?;
196
237
197
238
Ok ( MeshletMesh {
198
239
vertex_positions,
199
240
vertex_normals,
200
241
vertex_uvs,
201
242
indices,
243
+ bvh,
202
244
meshlets,
203
- meshlet_bounding_spheres,
204
- meshlet_simplification_errors,
245
+ meshlet_cull_data,
246
+ aabb,
247
+ bvh_depth,
205
248
} )
206
249
}
207
250
@@ -218,7 +261,7 @@ pub enum MeshletMeshSaveOrLoadError {
218
261
WrongVersion { found : u64 } ,
219
262
#[ error( "failed to compress or decompress asset data" ) ]
220
263
CompressionOrDecompression ( #[ from] lz4_flex:: frame:: Error ) ,
221
- #[ error( "failed to read or write asset data" ) ]
264
+ #[ error( transparent ) ]
222
265
Io ( #[ from] std:: io:: Error ) ,
223
266
}
224
267
0 commit comments