تتبعات
دعونا نستكشف عالم التتبعات! التتبعات هي وسيلة رائعة لإضافة إحساس بالحركة إلى المشهد الخاص بك. يمكن استخدامها لإنشاء مجموعة متنوعة من التأثيرات، مثل تتبعات الضوء، أو تتبعات الدخان، أو حتى تتبع جسم متحرك.
ها هو المشروع النهائي الذي سنقوم ببنائه معًا:
سنبدأ بإنشاء تأثير تتبع بسيط باستخدام مؤشر تتبع مخصص. ثم سنستكشف مكون التتبع من drei لعمل الكواكب التي رأيتها في المعاينة.
مشروع البداية
يحتوي مشروع البداية على العديد من الأشياء التي قمنا بتغطيتها بالفعل في الدروس السابقة:
- مكون ScrollControls للتعامل مع التمرير وحركة الكاميرا والرسوم المتحركة المرتبطة بها. إذا كنت بحاجة إلى تحديث، يمكنك الاطلاع على درس التمرير المخصص.
- تأثيرات ما بعد المعالجة مثل Bloom وVignette، مع إضافة جميلة لتأثير GodRays. تحقق من درس المعالجة اللاحقة إذا كنت بحاجة إلى تحديث.
<StarrySky />
الذي بنيناه في درس الجسيمات مع ضبط المعايير.
بالإضافة إلى ذلك، استخدمت Tailwind CSS لتصميم واجهة المستخدم بسرعة. إذا لم تكن متمرسًا في Tailwind CSS، يمكنك تخطي جزء واجهة المستخدم والتركيز على جزء Threejs.
النماذج WawaCoin وWawaCard مصنوعة داخل المؤسسة ومتاحة في مشروع البداية. استخدمت MeshTransmissionMaterial من drei لإنشاء هذا المظهر المستقبلي.
لا تتردد في تحويل المشهد كما تشاء. يمكنك إعادة استخدام أي جزء من المشروع بحرية في مشاريعك الخاصة.
نسيت أن أذكر، لكن المحتوى الموجود على الموقع هو خيالي بحت. أنا لا أطلق عملة مشفرة جديدة. (بعد؟ 👀)
المؤشر بتأثير المحاكاة المخصصة
لنبدأ بإنشاء تأثير محاكاة بسيطة تتبع المؤشر.
قم بإنشاء ملف جديد 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 controls.
في الوقت الحالي نستخدم حركة ثابتة، ستبسط عرض المسار. سنستبدلها بموقع الماوس لاحقًا.
أضف مكون Cursor
إلى مكون Experience
:
// ... import { Cursor } from "./Cursor"; export const Experience = () => { // ... return ( <> <Cursor /> {/* ... */} </> ); }; // ...
يمكننا رؤية كرة متحركة، ستصبح هدف المسار الخاص بنا.
SimpleTrail component
المجموعة هي الهدف الذي سيتبعه أثرنا. سنقوم بإنشاء مكون جديد 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: مرجع الهدف المراد اتباعه.
- color: لون الأثر.
- intensity: شدة الإضاءة للأثر.
- numPoints: عدد المواقع التي سنخزنها في الأثر. (كلما زاد الرقم، كلما كان الأثر أطول).
- height: ارتفاع الأثر.
- minDistance: الحد الأدنى للمسافة بين نقطتين.
- opacity: شفافية الأثر.
- duration: الوقت قبل أن يبدأ الأثر في التلاشي من نهايته.
لا تقلق إذا لم تفهم جميع المعلمات بعد. سنشرحها أثناء تنفيذنا للأثر.
قم باستيراد مكون SimpleTrail
في مكون Cursor
:
// ... 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، يمكننا رؤية مربع، ولكن بسبب عدد الأقسام، سنكون قادرين على تحريك الرؤوس لإنشاء تأثير الأثر.
لنرى جنبًا إلى جنب طائرة بمقطع واحد وطائرة بـ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>
هذا الكود لغرض التصور فقط. يمكنك إزالته بعد فهم المفهوم.
نقوم بتكبيرها على المحور ص لرؤية الفرق في عدد الأقسام.
يمكنك رؤية الطائرة اليسرى تحتوي فقط على 4 رؤوس بينما الطائرة اليمنى تحتوي على العديد منها. سنقوم بتحريك هذه الرؤوس لبناء تأثير الأثر.
يمكننا استخدام خط بدلاً من طائرة لإنشاء الأثر، ولكن استخدام طائرة يسمح لنا بإنشاء تأثير مثير للاهتمام (يعمل بشكل أفضل للرياح على سبيل المثال).
يستخدم مكون Trail من drei خطًا ، ونحن لا نريد إعادة ترميز نفس الشيء.
التلاعب برؤوس المضلعات
سنقوم بتحديث موضع رؤوس المضلعات للطائرة لتتبع الهدف بمرور الوقت.
أولاً، سنحتاج إلى تخزين جميع مواقع الهدف في مصفوفة. سنستخدم 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 hook لتحديث موضع الرؤوس.
// ... 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.