トレイル
トレイルの世界に飛び込んでみましょう!トレイルはシーンに動きを加えるための素晴らしい方法です。ライトトレイルや煙のトレイル、さらには動いているオブジェクトのトレイルを作成するために使用できます。
これが一緒に作成する最終プロジェクトです:
最初にカスタムトレイルカーソルを使って、シンプルなトレイルエフェクトを作成します。その後、プレビューで見た彗星を作成するために、dreiのTrail componentを探索します。
スタータープロジェクト
スタータープロジェクトには、以前のレッスンでカバーした多くの内容が含まれています:
- スクロールと関連するカメラの動きやアニメーションを処理するScrollControls component。復習が必要な場合は、専用のスクロールレッスンをチェックしてください。
- BloomとVignetteのようなポストプロセシングエフェクトに加えて、GodRaysエフェクトがあります。ポストプロセッシングについて復習が必要な場合は、ポストプロセッシングレッスンをチェックしてください。
- Particles lessonで作成した
<StarrySky />
、調整パラメータ付きです。
さらに、私はTailwind CSSを使用してUIを迅速にデザインしました。Tailwind CSSに馴染みがない場合は、UI部分をスキップしてThree.js部分に焦点を当てることができます。
WawaCoinとWawaCardのモデルは社内で作成され、スタータープロジェクトで利用可能です。この未来的な外観を作成するために、dreiのMeshTransmissionMaterialを使用しました。
シーンをお好みに合わせて変換してください。プロジェクトのどの部分も自由に再利用して、自分のプロジェクトに組み込むことができます。
言い忘れていましたが、ウェブサイトの内容は純粋にフィクションです。新しい暗号通貨を立ち上げるわけではありません。(まだ?👀)
カスタム トレイル カーソル
カーソルを追従するシンプルなトレイル効果を作成することから始めましょう。
新しい components/Cursor.jsx
ファイルを作成し、次のコードを追加します:
import { useFrame } from "@react-three/fiber"; import { useControls } from "leva"; import { useRef } from "react"; export const Cursor = () => { const { color, intensity, opacity, size } = useControls("Cursor", { size: { value: 0.2, min: 0.1, max: 3, step: 0.01 }, color: "#dfbcff", intensity: { value: 4.6, min: 1, max: 10, step: 0.1 }, opacity: { value: 0.5, min: 0, max: 1, step: 0.01 }, }); const target = useRef(); useFrame(({ clock }) => { if (target.current) { const elapsed = clock.getElapsedTime(); target.current.position.x = Math.sin(elapsed) * 5; target.current.position.y = Math.cos(elapsed * 2) * 4; target.current.position.z = Math.sin(elapsed * 4) * 10; } }); return ( <> <group ref={target}> <mesh> <sphereGeometry args={[size / 2, 32, 32]} /> <meshStandardMaterial color={color} transparent opacity={opacity} emissive={color} emissiveIntensity={intensity} /> </mesh> </group> </> ); };
これは、サイン波に従うシンプルな球です。カーソルのサイズ、色、強度、不透明度を Leva コントロール を使用して調整できます。
今のところ固定された動きを使用しており、トレイルの視覚化を簡単にしています。後でマウス位置に置き換えます。
Experience
コンポーネントに Cursor
コンポーネントを追加します:
// ... import { Cursor } from "./Cursor"; export const Experience = () => { // ... return ( <> <Cursor /> {/* ... */} </> ); }; // ...
動く球体が見えますが、これがトレイルのターゲットになります。
SimpleTrailコンポーネント
groupは、トレイルが追従するターゲットです。トレイルエフェクトを作成するために、新しいコンポーネント components/SimpleTrail.jsx
を作成します。
import { useRef } from "react"; import * as THREE from "three"; export function SimpleTrail({ target = null, color = "#ffffff", intensity = 6, numPoints = 20, height = 0.42, minDistance = 0.1, opacity = 0.5, duration = 20, }) { const mesh = useRef(); return ( <> <mesh ref={mesh}> <planeGeometry args={[1, 1, 1, numPoints - 1]} /> <meshBasicMaterial color={color} side={THREE.DoubleSide} transparent={true} opacity={opacity} depthWrite={false} /> </mesh> </> ); }
パラメータは以下の通りです。
- target: 追尾するターゲットのref。
- color: トレイルの色。
- intensity: トレイルの放射の強さ。
- numPoints: トレイルに記録する位置の数。(数が多いほどトレイルが長くなります)
- height: トレイルの高さ。
- minDistance: 2点間の最小距離。
- opacity: トレイルの透明度。
- duration: トレイルが端からフェードする前の時間。
パラメータがまだすべて理解できなくても心配しないでください。トレイルを実装しながら説明します。
Cursor
コンポーネントでSimpleTrail
コンポーネントをインポートします。
// ... import { SimpleTrail } from "./SimpleTrail"; export const Cursor = () => { // ... return ( <> <group ref={target}>{/* ... */}</group> <SimpleTrail target={target} color={color} intensity={intensity} opacity={opacity} height={size} /> </> ); };
meshは<planeGeometry />
とセグメントの数がnumPoints
と等しいものから成っています。ターゲットに従うために、各セグメントの位置を更新します。
視覚的には、プレーンのサイズが1x1のため正方形が見えますが、セグメントの数があるため、トレイルエフェクトを作成するために頂点を操作することが可能です。
セグメントが1つのプレーンと20セグメントのプレーンを並べて見てみましょう:
<group position-x={5}> <mesh position-x={4} scale-y={5}> <planeGeometry args={[1, 1, 1, numPoints - 1]} /> <meshBasicMaterial color={"red"} wireframe /> </mesh> <mesh position-x={2} scale-y={5}> <planeGeometry args={[1, 1, 1, 1]} /> <meshBasicMaterial color={"red"} wireframe /> </mesh> </group>
このコードは視覚化のためのものです。概念を理解した後で削除できます。
y軸上にスケールして、セグメントの差を確認します。
左のプレーンには4つの頂点しかありませんが、右のプレーンにははるかに多くあります。これらの頂点を操作してトレイルエフェクトを構築します。
lineを使用してトレイルを作成することもできますが、planeを使用することで興味深いエフェクトを作成できます(たとえば、風に対してより効果的です)。
dreiのTrailコンポーネントはlineを使用するため、同じものを再コーディングすることはしません。
頂点の操作
プレーンの頂点の位置を時間とともにターゲットに追従するように更新します。
まず、ターゲットのすべての位置を配列に保存する必要があります。位置を保存するために ref を使用します。
// ... import * as THREE from "three"; export function SimpleTrail( { // ... } ) { const mesh = useRef(); const positions = useRef( new Array(numPoints).fill(new THREE.Vector3(0, 0, 0)) ); // ... }
この配列は常に numPoints
の長さを持ち、ターゲットの位置を保存します。
ターゲットが移動すると、新しい位置を配列の最前部に追加し、他の位置を後ろに押し出します。
これを実現するために、頂点の位置を更新するために useFrame フックを使用します。
// ... import { useFrame } from "@react-three/fiber"; export function SimpleTrail( { // ... } ) { // ... useFrame(() => { if (!mesh.current || !target?.current) { return; } const curPoint = target.current.position; const lastPoint = positions.current[0]; const distanceToLastPoint = lastPoint.distanceTo(target.current.position); if (distanceToLastPoint > minDistance) { positions.current.unshift(curPoint.clone()); positions.current.pop(); } }); // ... }
まず、最後のポイントと現在のポイントとの距離を計算します。距離が minDistance
より大きい場合、現在のポイントを配列の最前部に unshift
で追加し、最後のポイントを pop
で削除します。
次に、ターゲットの位置に追従するようにプレーンの頂点の位置を更新する必要があります。
React Three Fiber: The Ultimate Guide to 3D Web Development
✨ You have reached the end of the preview ✨
Go to the next level with Three.js and React Three Fiber!
Get full access to this lesson and the complete course when you enroll:
- 🔓 Full lesson videos with no limits
- 💻 Access to the final source code
- 🎓 Course progress tracking & completion
- 💬 Invite to our private Discord community
One-time payment. Lifetime updates included.