Appearance
Curve 绘制曲线
本片实现一个CatmullRomCurve3曲线,然后让一个小球在这条线上移动
使用Catmull-Rom算法, 从一系列的点创建一条平滑的三维样条曲线。
思路
首先创造一系列点,然后将他们连接成线
js
const curve = new THREE.CatmullRomCurve3(
[
new THREE.Vector3(-10, 0, 10),
new THREE.Vector3(-5, 5, 5),
new THREE.Vector3(0, 10, 0),
new THREE.Vector3(15, -15, 15),
new THREE.Vector3(20, 0, -20)
],
true // 表示曲线是否闭合
);
const points = curve.getPoints(50);
const geometry = new THREE.BufferGeometry().setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0xff0000 });
const line = new THREE.Line(geometry, material);
scene.add(line);然后创建一个小球,关键如何在这个线上移动呢,通过getPoint方法,传入一个0-1的数值,返回一个点,然后将这个点赋值给小球的position属性,就可以实现小球在这条线上移动了
js
const t = (Date.now() * 0.001) / 10; // 控制小球移动的速度
const position = curve.getPointAt(t % 1); // t % 1 保证 t 在 0-1 之间循环
sphere.position.copy(position);效果
代码实现
html
<template>
<div id="canvas"></div>
</template>
<script setup>
import { onMounted } from 'vue';
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import Stats from 'three/addons/libs/stats.module.js';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
onMounted(() => {
let scene = new THREE.Scene();
scene.add(new THREE.AmbientLight(0xffffff));
const light = new THREE.DirectionalLight(0xffffff, 1.5);
light.position.set(0, 0, 1);
scene.add(light);
const curve = new THREE.CatmullRomCurve3(
[
new THREE.Vector3(-10, 0, 10),
new THREE.Vector3(-5, 5, 5),
new THREE.Vector3(0, 10, 0),
new THREE.Vector3(15, -15, 15),
new THREE.Vector3(20, 0, -20)
],
true // 表示曲线是否闭合
);
const points = curve.getPoints(50);
const geometry = new THREE.BufferGeometry().setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0xff0000 });
const line = new THREE.Line(geometry, material);
scene.add(line);
// 来个小球放在原点
const geometry2 = new THREE.SphereGeometry(1);
const material2 = new THREE.MeshBasicMaterial({ color: 0x0000ff });
const sphere = new THREE.Mesh(geometry2, material2);
scene.add(sphere);
let camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 10000);
camera.position.set(40, 40, 40);
camera.lookAt(0, 0, 0);
// 坐标系
const axesHelper = new THREE.AxesHelper(100);
scene.add(axesHelper);
let renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById('canvas').appendChild(renderer.domElement);
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
// 让小球在那一根线上移动
const t = (Date.now() * 0.001) / 10;
const position = curve.getPointAt(t % 1);
sphere.position.copy(position);
// 让相机视角跟随小球
camera.position.copy(sphere.position);
// 根据移动方向决定相机的朝向
camera.position.add(new THREE.Vector3(20, 0, 0));
camera.lookAt(sphere.position);
}
animate();
});
</script>