You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bevy 3D场景中添加2D文本标注坐标轴的实现方法

Bevy 3D场景中添加2D文本标注坐标轴的实现方法

嘿,我来帮你搞定这个3D坐标轴标签的问题!你当前的代码已经成功画出了彩色坐标轴,但要让文本真正存在于3D空间中(而非固定在屏幕UI层),核心是用Bevy的Text3dBundle替代你之前尝试的Text2dBundle——前者是3D场景中的实体,会跟随相机视角变化,完美匹配你的需求。

关键修改思路

  1. 替换UI文本为3D文本:Text3dBundle是专门为3D空间设计的文本组件,能像其他3D实体一样被相机拍摄、受视角影响
  2. 文本位置偏移:把标签放在轴的末端外侧一点(比如Vec3::X * 1.1),避免和轴线重叠
  3. 样式匹配:保持文本颜色和对应轴的颜色一致,提升视觉一致性

修改后的完整代码

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 10:50:26