مرحبا يا هبر! أقدم إليكم ترجمة المقال "JavaScript in 3D: مقدمة إلى Three.js" للمخرج بريت كاميرون.مقدمة
Three.js هي أداة قوية. إنه يساعد على استخدام التصميم ثلاثي الأبعاد في متصفح بأداء مقبول. يمكن أن تكون لعبة Three.js صعبة ، خاصة إذا لم تغوص مطلقًا في عالم البرمجة ثلاثية الأبعاد من قبل.
لديّ بعض الخبرة الأساسية مع محرك اللعبة Unity و C # ، لكن لا يزال ، العديد من المفاهيم جديدة بالنسبة لي. توصلت إلى استنتاج مفاده أن هناك الآن موارد قليلة جدًا للمطورين المبتدئين ، لذلك قررت أن أكتب هذا المقال. في ذلك ، سننظر في العناصر الأساسية لمشاهد Three.js بدءًا من شبكات المضلع والمواد إلى الهندسة والمحمل وغير ذلك الكثير.
في نهاية هذه المقالة ، سيكون لديك فهم قوي للجوانب الأساسية اللازمة لإضافة بعد إضافي لمشروع الويب الخاص بك في المستقبل.
Three.js أمثلة من
بن هيوستن وتوماس دايفالد وسترايكر دوز أنيمشن .
ناقلات وحاويات - اللبنات الأساسية
في كثير من الأحيان هناك فئتان رئيسيتان في Three.js -
Vector3 و
Box3 . إذا كنت جديدًا في تطبيق ثلاثي الأبعاد ، فقد يبدو هذا مجردة بعض الشيء ، لكنك ستقابلهم عدة مرات.
Vector3
الفئة ثلاثية الأبعاد الأساسية التي تحتوي على ثلاثة أرقام:
x و y و z . الأرقام هي إحداثيات نقطة في الفضاء ثلاثي الأبعاد أو الاتجاه والطول. على سبيل المثال:
const vect = new THREE.Vector3(1, 1, 1);
تقبل معظم المُنشئات في Three.js كائنات من النوع
Vector3 كوسائط إدخال ، على سبيل المثال
Box3Box3
تمثل هذه الفئة مكعبة (حاوية ثلاثية الأبعاد). وتتمثل مهمتها الرئيسية في إنشاء حاوية حول كائنات أخرى - وهذا كل شيء ، هو أصغر مكعبة يمكن تركيب كائن ثلاثي الأبعاد فيها.
يتم محاذاة كل
Box3 حول محاور
x و y و z. مثال عن كيفية إنشاء حاوية باستخدام
Vector3 :
const vect = new THREE.Vector3(1, 1, 1); const box = new THREE.Box3(vect);
مثال عن كيفية إنشاء حاوية حول كائن ثلاثي الأبعاد موجود:
const box = new THREE.Box3(); box.setFromObject(object);
يمكنك إنشاء شبكات دون هذه المعرفة المتعمقة ، ولكن بمجرد أن تبدأ في الوصول إلى النماذج الخاصة بك أو تغييرها ، ستكون هذه الفئات في متناول يدي بالتأكيد. سننتقل الآن من التجريد إلى أشياء أكثر وضوحًا.
شبكة المضلع
في Three.js ، العنصر المرئي الرئيسي على المسرح هو
Mesh . هذا كائن ثلاثي الأبعاد يتكون من مستطيلات مثلثة (شبكة مضلعة). بنيت باستخدام كائنين:
الهندسة - تحدد شكلها ،
المادة - تحدد المظهر.
قد تبدو تعاريفها مربكة بعض الشيء (على سبيل المثال ، قد تحتوي فئة
الهندسة على معلومات حول اللون) ، لكن الفرق الرئيسي هو ذلك بالضبط.
علم الهندسة
بناءً على المهمة التي تريد تحقيقها ، قد ترغب في تحديد الشكل الهندسي داخل Three.js أو استيراد ملف آخر من ملف.
باستخدام وظائف مثل
THREE.TorusKnotGeometry ، يمكننا إنشاء كائنات معقدة مع سطر واحد من التعليمات البرمجية. سنتطرق إلى ذلك قريبًا ، لكن أولاً لننظر في أشكال أكثر بساطة.
يمكن تحديد أبسط شكل ثلاثي الأبعاد ، مكعبة أو حاوية ، من خلال معلمات
العرض والطول والعمق .
const geometry = new THREE.BoxGeometry( 20, 20, 20 );
بالنسبة إلى كرة ما ، تكون قيمة
نصف القطر ومعلمات widthSegments و
heightSegments ضئيلة . يشير المتغيران الأخيران إلى عدد المثلثات التي يجب أن يستخدمها النموذج لتمثيل الكرة: كلما زاد العدد ، زاد مظهره.
const geometry = new THREE.SphereGeometry( 20, 64, 64 );
إذا أردنا عمل أشكال حادة أو ثلاثية ، فيمكننا استخدام مخروط. حججه هي مزيج من الحجج من الرقمين السابقين. أدناه ، نحن
نصف دائرة نصف قطرها ،
widthSegments و
radialSegments .
const geometry = new THREE.ConeBufferGeometry( 5, 20, 32 );
هذا ليس سوى جزء من الأرقام الأكثر شيوعًا. Three.js لديه الكثير من الأشكال داخل المربع ، والتي يمكن العثور عليها في الوثائق. في هذه المقالة ، سننظر في أشكال أكثر إثارة للاهتمام تم إنشاؤها على أساس طريقة
TorusKnotGeometry .
لماذا تبدو هذه الأشكال بالطريقة التي تبدو بها بالضبط؟ هذا السؤال خارج عن نطاق هذه المقالة ، لكنني أحثك على تجربة قيم المعلمات ، لأنه يمكنك الحصول على أشكال مثيرة جدًا للاهتمام بسطر واحد من التعليمات البرمجية!
const geometry = new THREE.TorusKnotGeometry(10, 1.3, 500, 6, 6, 20);
https://codepen.io/BretCameron/pen/gOYqORgالمواد
تحدد الهندسة شكل كائناتنا ثلاثية الأبعاد ، ولكن ليس مظهرها. لإصلاح هذا ، نحتاج إلى مواد.
يوفر Three.js 10 مواد خارج الصندوق ، لكل منها مزاياه الخاصة والمعلمات القابلة للتخصيص. سوف ننظر فقط جزء من الأكثر فائدة.

MeshNormalMaterial
مفيدة لبداية سريعة وبدء.سنبدأ بـ
MeshNormalMaterial ، وهي المادة متعددة الألوان التي استخدمناها في الأمثلة أعلاه. يتوافق مع المتجهات العادية في لوحة RGB ، بمعنى آخر ، يتم استخدام الألوان لتحديد موضع المتجه في الفضاء ثلاثي الأبعاد.
const material = new THREE.MeshNormalMaterial();
لاحظ أنه إذا كنت ترغب في تغيير لون المادة ، يمكنك استخدام مرشح CSS وتغيير التشبع:
filter: hue-rotate(90deg) .
في تجربتي ، هذه المادة هي أكثر فائدة لطبقة سريعة والإطلاق. لمزيد من التحكم في الأشياء الخاصة بك ، من الأفضل استخدام شيء آخر.
MeshBasicMaterial
مفيد عند عرض الهيكل العظمي فقط.إذا كنت ترغب في إعطاء الشكل لونًا واحدًا ، فيمكنك استخدام
MeshBasicMaterial فقط في حالة عدم تطبيق الإضاءة. لقد وجدت أنه من المفيد استخدام هذه المواد في تقديم هيكل النموذج. لرسم الهيكل العظمي فقط ، تحتاج إلى تمرير
{wireframe: true} كمعلمة.
const material = new THREE.MeshBasicMaterial({ wireframe: true, color: 0xdaa520 });
العيب الرئيسي لهذه المادة هو أن المعلومات المتعلقة بعمق المادة تضيع تماما. كل مادة لديها خيار عرض الهيكل العظمي فقط ، لكن مادة واحدة فقط تحل مشكلة نقص العمق -
MeshDepthMaterialMeshLambertMaterial
مفيدة للأداء العالي ولكن دقة منخفضة.هذه هي المادة الأولى التي تأخذ الضوء في الاعتبار ، لذلك تحتاج إلى إضافة بعض الضوء إلى مشهدنا. في الكود أدناه ، نضيف الأضواء مع لون أصفر لخلق تأثير أكثر دفئا.
const scene = new THREE.Scene(); const frontSpot = new THREE.SpotLight(0xeeeece); frontSpot.position.set(1000, 1000, 1000); scene.add(frontSpot); const frontSpot2 = new THREE.SpotLight(0xddddce); frontSpot2.position.set(-500, -500, -500); scene.add(frontSpot2);
الآن إضافة المواد لدينا الرقم. بما أن الشكل لدينا يشبه الزخرفة ، أقترح إضافة لون ذهبي أكثر. معلمة أخرى ،
انبعاثية ، هي لون الكائن القادم من الكائن نفسه (بدون مصدر ضوء). غالبًا ما يعمل هذا بشكل أفضل بلون داكن - على سبيل المثال ، ظلال رمادية داكنة ، كما في المثال أدناه
const material = new THREE.MeshLambertMaterial({ color: 0xdaa520, emissive: 0x111111, });
كما ترى في المثال أدناه ، فإن اللون صحيح إلى حد ما ، لكن الطريقة التي يتفاعل بها مع الضوء لا تضيف الواقعية. لإصلاح ذلك ، نحتاج إلى استخدام
MeshPhongMaterial أو
MeshStandardMaterial.MeshPhongMaterial
مفيد للأداء المتوسط والدقة المتوسطة.توفر هذه المادة مفاضلة بين الأداء ودقة التجسيد ، وبالتالي فإن هذه المادة تعد خيارًا جيدًا للتطبيق الذي يحتاج إلى أن يكون منتجًا إلى جانب عرض أكثر دقة من
تطبيق MeshLambertMaterial.الآن يمكننا تغيير خاصية
براق التي تؤثر على سطوع ولون انعكاس السطح. إذا كانت الخاصية المنبعثة مظلمة ، فستكون
براقًا أفضل للألوان الفاتحة. أدناه نستخدم رمادي فاتح.
const material = new THREE.MeshPhongMaterial({ color: 0xdaa520, emissive: 0x000000, specular: 0xbcbcbc, });
بصريًا ، تعكس الصورة الواردة أعلاه الضوء بشكل أكثر إقناعًا ، لكنها لا تزال غير مثالية. الضوء الأبيض مشرق للغاية والمواد تبدو مضلعة أكثر من المعدن (ونحن نسعى جاهدين لذلك). يمكننا الحصول على نتيجة أفضل باستخدام
MeshStandardMaterial.MeshStandartMaterial
مفيدة للحصول على دقة عالية ولكن انخفاض الإنتاجية.هذه هي المادة الأكثر دقة على الإطلاق ، على الرغم من أن استخدامها يستلزم تكاليف استخدام المزيد من الطاقة.
يتم استخدام
MeshStandartMaterial مع معلمات
المعادن وخشونة إضافية ، كل منها يأخذ قيمة بين 0 و 1.
تؤثر المعلمة
المعدنية على كيفية انعكاس الكائن ، حيث تصبح أقرب إلى طبيعة المعدن. وذلك لأن المواد الموصلة مثل المعادن لها خصائص عاكسة مختلفة ، على عكس المواد العازلة مثل السيراميك.
يضيف
الخشونة طبقة إضافية للتخصيص. يمكنك أن تتخيل ذلك عكسًا لمعان: 0 - شديد اللمعان ، 1 - غير لامع جدًا.
const material = new THREE.MeshStandardMaterial({ color: 0xfcc742, emissive: 0x111111, specular: 0xffffff, metalness: 1, roughness: 0.55, });
هذه هي المادة الأكثر واقعية لجميع المقدمة في Three.js ، ولكن أيضا الأكثر استهلاكا للموارد
المواد التي ناقشناها أدناه هي تلك التي قابلتها كثيرًا ويمكنك مشاهدة جميع الخيارات في قفص الاتهام.
رافعات
كما ناقشنا أعلاه ، يمكنك تحديد هندسة الشبكات والشبكات المضلعة يدويًا. في الممارسة العملية ، غالبًا ما يقوم الأشخاص بتحميل الأشكال الهندسية الخاصة بهم من الملفات. لحسن الحظ ، يوجد في Three.js عدد قليل من برامج التنزيل المدعومة التي تدعم العديد من التنسيقات ثلاثية الأبعاد.
يقوم
ObjectLoader الرئيسي بتحميل ملف JSON باستخدام
تنسيق كائن / مشهد JSON . تحتاج معظم محمل الإقلاع إلى الاستيراد يدويًا. يمكنك العثور على قائمة كاملة بوادر التحميل المدعومة هنا واستيرادها. يوجد أدناه قائمة صغيرة بما يمكنك استيراده.
التنسيق الموصى به للعرض عبر الإنترنت هو GLTF ، لأن التنسيق "يهدف إلى تسليم الأصول في وقت التشغيل ، وصغير الحجم للنقل ، وسريع التنزيل".
بالطبع ، قد يكون هناك العديد من الأسباب لتفضيل نوع معين من الملفات (على سبيل المثال ، إذا كانت الجودة أولوية أو هناك حاجة للطباعة ثلاثية الأبعاد). سيكون أفضل أداء عبر الإنترنت عند استيراد GLTF.
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'; import model from '../models/sample.gltf'; let loader = new GLTFLoader(); loader.load(model, function (geometry) {
وضع كل ذلك معا
أحد الأسباب التي تجعل Three.js قد تبدو مرعبة هو أنه يمكنك إنشاء شيء ما من الصفر باستخدام بضعة أسطر من التعليمات البرمجية. في كل مثال أعلاه ، كنا بحاجة إلى إنشاء مشهد وكاميرا. لتبسيطًا ، أبقيت هذا الرمز خارج نطاق المراجعة ، لكن الآن سنرى كيف سيبدو معًا.
إن الطريقة التي تنظم بها الكود أمر متروك لك. في أمثلة أبسط ، كما في هذه المقالة ، من المنطقي أن تكتب كل الشفرة في مكان واحد. لكن من الناحية العملية ، من المفيد فصل العناصر الفردية عن إمكانية توسيع قاعدة الشفرة وإدارتها.
للبساطة ، سننظر في العناصر التي يتم رسمها ككائن واحد ، لذلك سنضع كل الشفرة في ملف واحد.
هل أحتاج إلى استخدام إطار عمل؟
أخيرًا ، لقد حان الوقت لمناقشة ما إذا كنت تريد استخدام Three.js مع إطار العمل المفضل لديك؟ في الوقت الحالي ، توجد حزمة رد
فعل ثلاثية الألياف جيدة لـ React. بالنسبة لمستخدمي React ، هناك مزايا واضحة لاستخدام حزمة مثل هذه - يمكنك الحفاظ على هيكل للعمل مع المكونات التي تسمح لك بإعادة استخدام التعليمات البرمجية.
بالنسبة للمبتدئين ، أنصحك أن تبدأ بـ
Vanila JS المعتادة ، لأن معظم المواد الموجودة على الإنترنت والتي كتبت عن Three.js تتعلق بـ Three.js على Vanila JS. بناءً على تجربتي التعليمية ، يمكن أن يكون هذا مربكًا وصعب التعلم من خلال حزمة - على سبيل المثال ، سيتعين عليك ترجمة كائنات وطرق Three.js إلى المكونات والدعائم. (بمجرد أن تتعلم Three.js يمكنك استخدام أي حزمة).
كيفية إضافة Three.js إلى الإطار
يوفر Three.js كائن HTML (يُسمى غالبًا renderer.domElement) يمكن إضافته إلى أي كائن HTML في التطبيق الخاص بك. على سبيل المثال ، إذا كان لديك
div بمعرف = "threejs" ، يمكنك ببساطة تضمين الكود التالي في كود Three.js الخاص بك:
document.getElementById('threejs').appendChild(renderer.domElement);
تفضل بعض الأُطُر مسارات الوصول إلى العقد DOM للشجرة. على سبيل المثال ،
المرجع في
React ، أو
$ ref في Vue أو
ngRef في Angular ، ويبدو أنه يمثل إضافة ضخمة على خلفية الوصول المباشر إلى عناصر DOM. كمثال ، دعنا ننظر إلى التنفيذ السريع لـ React.
استراتيجية رد الفعل
إذا كنت تستخدم React ، فهناك طريقة واحدة لتضمين ملفات Three.js في أحد مكوناتك. في الملف
ThreeEntryPoint.js ، سنكتب الكود التالي:
export default function ThreeEntryPoint(sceneRef) { let renderer = new THREE.WebGLRenderer();
نحن نصدر هذا كدالة تأخذ وسيطة واحدة: إشارة إلى عنصر في مكوننا. الآن يمكننا إنشاء مكون لدينا
import React, { Component } from 'react'; import ThreeEntryPoint from './threejs/ThreeEntryPoint'; export default class ThreeContainer extends Component { componentDidMount() { ThreeEntryPoint(this.scene); } render() { return ( <> <div ref={element => this.scene = element} /> </> ); } }
يجب استدعاء الدالة
ThreeEntryPoint المستوردة في طريقة
componentDidMount وتمرير
div الجديد كوسيطة باستخدام المراجع
كمثال على هذا النهج في العمل ، يمكنك استنساخ المستودع وتجربته بنفسك:
https://github.com/BretCameron/three-js-sample .
استنتاج
لا يزال هناك الكثير الذي يمكنني التحدث حول Three.js ، لكنني آمل أن يكون هذا المقال قد أعطاك معلومات كافية لبدء استخدام هذه التكنولوجيا القوية. عندما بدأت في تعلم Three.js ، لم أتمكن من العثور على مورد واحد مثل هذه المقالة ، لذلك آمل أن أكون ساعدت في جعل هذه التكنولوجيا أكثر سهولة للمبتدئين.