Three.js-硬要自学系列32之专项学习箭头辅助器

293 阅读4分钟

箭头辅助器是什么

想象一下我们在玩一个3D建造游戏或者看一个科学模拟动画。如果想直观地看到:

  1. 这个物体是朝哪边转的?  (比如一个陀螺的旋转轴)
  2. 这个力是往哪个方向推的?  (比如一阵风吹的方向)
  3. 这个灯光是照向哪里的?  (比如手电筒的光束方向)
  4. 摄像机是看向哪里的?  (比如你的第一人称视角方向)

three.js中提供了一个可视化工具 ArrowHelper ,专门用来在3D场景中绘制一个箭头,方便清楚地标出某个方向。

核心参数

  1. 方向 (dir):  这是最关键的!你需要用一个 THREE.Vector3 向量来表示箭头指向哪里。比如:

    • new THREE.Vector3(1, 0, 0) 表示指向 X 轴正方向 (右边)。
    • new THREE.Vector3(0, 1, 0) 表示指向 Y 轴正方向 (上边)。
    • new THREE.Vector3(0, 0, 1) 表示指向 Z 轴正方向 (屏幕外/前方)。
    • 也可以是 (0.5, 0.5, 0) 这样指向斜上方的向量。
  2. 起点 (origin):  箭头从 3D 空间的哪个位置开始画?也是用一个 THREE.Vector3 表示坐标点。默认通常是世界的中心 (0, 0, 0)

  3. 长度 (length):  箭头画多长?一个数字。太短看不清,太长可能穿模。默认值通常够用(比如 1)。

  4. 颜色 (color):  箭头涂成什么颜色?可以是 0xff0000 (红色), 0x00ff00 (绿色), 0x0000ff (蓝色) 等等。默认是红色。

主要作用

  • 直观调试:  这是它最主要的目的!让我们在开发 3D 应用时能 亲眼看到 抽象的方向信息。
  • 视觉参考:  在场景中提供清晰的方向标识,帮助用户理解朝向。
  • 标记位置和朝向:  可以附加到物体上,实时显示该物体的朝向(比如飞船的机头方向)。
  • 可视化向量:  物理模拟中的速度、力、加速度等向量,用箭头表示一目了然。

实时改变箭头指示方向的案例

效果如图

1.gif

需要了解的API

ArrowHelper

可视化方向工具,用于在 3D 场景中绘制带箭头的线段,直观展示 方向、力、旋转轴等抽象概念

参数类型作用默认值/示例
dirTHREE.Vector3箭头指向的方向new THREE.Vector3(1, 0, 0) (X轴)
originTHREE.Vector3箭头的起点坐标new THREE.Vector3(0, 0, 0) (场景原点)
lengthNumber箭头总长度(杆+锥头)1
colorNumber (十六进制)箭头颜色0xff0000 (红色)

典型问题解决方法

  • 箭头不可见?
    检查是否添加至场景:scene.add(arrowHelper)
    确认相机位置是否覆盖箭头区域。
  • 方向相反?
    向量定义错误:new THREE.Vector3(-1,0,0) 指向X轴负方向。
  • 箭头穿透物体?
    调整 length 参数或使用 Raycaster 检测碰撞点作为起点。

实现思路

const arrow = new THREE.ArrowHelper(new THREE.Vector3(0, 1, 0), new THREE.Vector3(0, 0, 0), 3, "deepskyblue");
scene.add(arrow);

这里在场景中添加了一个长度为3,指向(0,1,0)Y轴方向的蓝色箭头

let frame = 0;
const maxFrame = 500;
function animation() {
    const per = frame / maxFrame,
    rad = Math.PI * 2 * per, // 弧度制,0~2π
    x = Math.cos(rad),        // 0~1
    y = Math.sin(rad);  // 0~1
    const dir = new THREE.Vector3(x, y, 0).normalize();
    arrow.setDirection(dir);
    frame++;
    frame %= maxFrame;
    renderer.render( scene, camera );
    requestAnimationFrame( animation );  
}

通过arrow.setDirection(dir)设置方向,从而实现上图效果

沿指定方向移动

效果如图

2.gif

创建一个球体和箭头辅助器,如下

let V = new THREE.Vector3(1,1,0),
DIR = V.normalize(),
LENGTH = 5;

const arrow = new THREE.ArrowHelper(
    DIR, // 方向向量
    new THREE.Vector3(0, 0, 0), 
    LENGTH, 
    'deepskyblue' 
)
scene.add(arrow);

const sphere = new THREE.Mesh(
    new THREE.SphereGeometry(0.3, 32, 32),
    new THREE.MeshBasicMaterial({color: 'deeppink'})
)
scene.add(sphere);

image.png

要想使箭头做运动可参照上一个案例,这里创建一个update方法来更新状态

const update = secs => {
    const a1 = frame / maxFrame,
    a2 = 1 - Math.abs(0.5 - a1) / 0.5; // 0-1
    V.z = -5 + 10 * a2; 
    DIR = V.clone().normalize(); // 归一化
    arrow.setDirection(DIR); // 设置方向
}

接下来就是处理球体的运动,无非是不断更新小球的位置

const x = DIR.x * LENGTH * a2, // 计算x
y = DIR.y * LENGTH * a2, // 计算y
z = DIR.z * LENGTH * a2; // 计算z
sphere.position.set(x, y, z);
sphere.lookAt(0, 0, 0);
camera.position.z = z + 3;

最后在循环渲染函数中调用update方法,为了方便观察,这里动态的修改了相机的Z轴位置坐标

以上便是本篇的所有内容,自己动手练一练,感受一下实际效果