Bevy 3D场景中添加2D文本标注坐标轴的实现方法
Bevy 3D场景中添加2D文本标注坐标轴的实现方法
嘿,我来帮你搞定这个3D坐标轴标签的问题!你当前的代码已经成功画出了彩色坐标轴,但要让文本真正存在于3D空间中(而非固定在屏幕UI层),核心是用Bevy的Text3dBundle替代你之前尝试的Text2dBundle——前者是3D场景中的实体,会跟随相机视角变化,完美匹配你的需求。
关键修改思路
- 替换UI文本为3D文本:
Text3dBundle是专门为3D空间设计的文本组件,能像其他3D实体一样被相机拍摄、受视角影响 - 文本位置偏移:把标签放在轴的末端外侧一点(比如
Vec3::X * 1.1),避免和轴线重叠 - 样式匹配:保持文本颜色和对应轴的颜色一致,提升视觉一致性
修改后的完整代码
use bevy::prelude::*; use bevy::color::palettes::css; use bevy_fly_camera::{FlyCamera, FlyCameraPlugin}; use bevy_polyline::prelude::*; fn main() { App::new() .add_plugins((DefaultPlugins, PolylinePlugin, FlyCameraPlugin)) .add_systems(Startup, spawn_axis) .run(); } fn spawn_axis( mut commands: Commands, mut polyline_materials: ResMut<Assets<PolylineMaterial>>, mut polylines: ResMut<Assets<Polyline>>, asset_server: Res<AssetServer>, // 用于获取自定义字体,可选 ) { // 定义粗线材质的生成函数 let mut thick_line = |color: Srgba| { PolylineMaterialHandle(polyline_materials.add(PolylineMaterial { width: 2.5, color: color.into(), perspective: false, ..Default::default() })) }; // 坐标轴线段定义 let axis_lines = [ (vec![Vec3::ZERO, Vec3::X], css::RED), (vec![Vec3::ZERO, Vec3::Y], css::GREEN), (vec![Vec3::ZERO, Vec3::Z], css::BLUE), ]; // 生成线段Bundle的函数 let line_bundle = move |vertices, material, polylines: &mut ResMut<Assets<Polyline>>| PolylineBundle { polyline: PolylineHandle(polylines.add(Polyline { vertices })), material, ..Default::default() }; // 生成坐标轴 for (line, color) in axis_lines { commands.spawn(line_bundle(line, thick_line(color), &mut polylines)); } // --- 新增:生成3D轴标签 --- // 定义轴标签的位置、文本、颜色 let axis_labels = [ (Vec3::X * 1.1, "X", css::RED), (Vec3::Y * 1.1, "Y", css::GREEN), (Vec3::Z * 1.1, "Z", css::BLUE), ]; // 定义3D文本的样式 let text_style = |color: Srgba| TextStyle { font_size: 0.2, // 3D空间中的字体大小,单位为世界空间单位 color: color.into(), // 没有自定义字体的话,可替换为 font: Default::default() 使用Bevy内置字体 font: asset_server.load("fonts/FiraSans-Bold.ttf"), ..Default::default() }; // 生成每个轴的标签 for (pos, label, color) in axis_labels { commands.spawn(Text3dBundle { text: Text::from_section(label, text_style(color)), transform: Transform::from_translation(pos), ..Default::default() }); } // 相机设置(保持你的原有代码) commands .spawn(( Camera3d::default(), Camera { hdr: true, ..default() }, Msaa::Sample4, Transform::from_xyz(1.0, 1.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y), )) .insert(FlyCamera::default()); }
代码关键细节说明
- Text3dBundle vs Text2dBundle:
Text3dBundle是3D场景中的实体,它的位置、旋转、缩放都遵循世界空间规则,会随着相机的移动和旋转正确显示;而Text2dBundle是固定在屏幕UI层的,不会受3D视角影响。 - 文本位置偏移:我们把标签放在
Vec3::X * 1.1这样的位置,比轴的末端(Vec3::X)稍微向外一点,避免和轴线的末端重叠,提升可读性。 - 3D字体大小:Text3d的
font_size单位是世界空间单位,所以设置0.2左右比较合适(如果设置太大,文本会在3D空间里显得巨幅)。 - 字体加载:如果你没有自定义字体,可以把
font: asset_server.load(...)换成font: Default::default(),Bevy会使用内置的默认字体。
Cargo.toml 保持不变
你的依赖配置已经是正确的,不需要修改:
[dependencies] bevy = {version = "0.16", features = ["wayland"] } bevy_polyline = "0.12" bevy_fly_camera = "0.16"
这样修改后,运行代码就能看到每个轴的末端有对应的彩色标签,而且你可以用飞行相机自由移动视角,标签会一直正确显示在3D空间的轴末端~
内容来源于stack exchange
相关产品推荐
相关产品推荐

