Bevy Rust中如何在Mesh创建后逐帧修改网格数据
问题根源
报错核心是资源访问权限声明错误:update_planets系统中Assets<Mesh>资源被声明为只读访问的Res<Assets<Mesh>>,Res类型仅提供资源的不可变引用,未实现可变解引用所需的DerefMut trait,因此无法调用需要&mut self的get_mut方法。
另外原代码还存在几处笔误和类型不匹配问题,会在修复后一并解决。
修复方案
- 将系统参数中的
assets: Res<Assets<Mesh>>修改为mut assets: ResMut<Assets<Mesh>>,ResMut会为资源获取写锁,提供可变访问权限,支持调用get_mut等修改方法。 - 修正代码中的笔误:删除无意义的
handle.id调用(get_mut可直接传入Handle引用),替换未定义的temp、thingy变量为实际的有效变量。 - 修正类型匹配问题:
Mesh::ATTRIBUTE_POSITION属性接收的是Vec<[f32; 3]>类型数据,不要直接传入Vec<Vec3>,需将顶点坐标转为三元数组后再写入。 - 优化匹配逻辑:直接对
get_mut返回的Option做匹配,避免重复unwrap引发的运行时panic。
修正后的可运行代码
use bevy::{prelude::*, render::mesh::VertexAttributeValues}; fn setup ( mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>, mut materials: ResMut<Assets<StandardMaterial>>, ) { let mesh = Mesh::from(shape::Icosphere { radius: 0.5, subdivisions: 10 }); let colour = Color::srgb(0.2, 0.5, 0.8); commands.spawn(PbrBundle { mesh: meshes.add(mesh), material: materials.add(colour.into()), transform: Transform::from_xyz(0.0, 0.0, 0.0), ..Default::default() }); } fn update_planets ( mut query: Query<(&Transform, &Handle<Mesh>)>, mut assets: ResMut<Assets<Mesh>> ) { let (_transform, handle) = query.single().expect("场景中存在且仅存在一个行星实体"); if let Some(mesh) = assets.get_mut(handle) { let positions = mesh.attribute(Mesh::ATTRIBUTE_POSITION).expect("Mesh缺少POSITION顶点属性"); if let VertexAttributeValues::Float32x3(pos_data) = positions { let mut new_positions = Vec::with_capacity(pos_data.len()); for pos in pos_data { let mut vertex_pos = Vec3::new(pos[0], pos[1], pos[2]); // 在此处编写自定义顶点修改逻辑,例如噪声形变、顶点动画等 new_positions.push(vertex_pos.to_array()); } mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, new_positions); } } }
优化提示
- Bevy 0.8及以上版本会自动检测Mesh资源的变更,自动将修改后的数据上传到GPU,无需手动添加变更标记。
- 若多个实体共用同一个Mesh Handle,修改该Mesh会同步影响所有关联实体的显示效果;如果需要每个行星独立形变,生成实体时要为每个实体创建独立的Mesh副本,不要共用Handle。
- 若查询中不需要修改
Transform,不要使用get_single_mut,用single()获取只读查询结果即可,减少不必要的锁开销,提升系统调度效率。 - 大顶点量的Mesh逐帧全量更新会产生较高的CPU-GPU传输开销,复杂形变逻辑建议迁移到GPU端用Compute Shader实现。
内容的提问来源于stack exchange,提问作者Xzenotrex
相关产品推荐
相关产品推荐

