+ [page:AnimationMixer mixer] هو *AnimationMixer* الذي يتحكم فيه هذا الإجراء.<br />
+ [page:AnimationClip clip] هو *AnimationClip* الذي يحتفظ ببيانات الرسوم المتحركة لهذا الإجراء.<br />
+ [page:Object3D localRoot] هو الكائن الجذر الذي يتم تنفيذ هذا الإجراء عليه.<br /><br />
+
+ ملاحظة: بدلاً من استدعاء هذا المُنشئ مباشرةً ، يجب إنشاء AnimationAction برقم [page:AnimationMixer.clipAction] نظرًا لأن هذه الطريقة توفر التخزين المؤقت للحصول على أداء أفضل.
+ </p>
+
+
+ <h2>الخصائص (Properties)</h2>
+
+
+ <h3>[property:Boolean clampWhenFinished]</h3>
+ <p>
+ إذا تم ضبط *clampWhenFinished* على true ، فسيتم تلقائيًا إيقاف [page:.paused paused] للرسوم المتحركة مؤقتًا في إطارها الأخير.<br /><br />
+
+ إذا تم ضبط *clampWhenFinished* على false ، فسيتم تحويل [page:.enabled enabled] تلقائيًا إلى false عند انتهاء آخر حلقة من الإجراء ، بحيث لا يكون لهذا الإجراء أي تأثير آخر.<br /><br />
+
+ القيمة الافتراضية هو خطأ (false).<br /><br />
+
+ ملاحظة: *clampWhenFinished* ليس له أي تأثير إذا تم مقاطعة الإجراء (يكون له تأثير فقط إذا انتهت الحلقة الأخيرة بالفعل).
+ </p>
+
+ <h3>[property:Boolean enabled]</h3>
+ <p>
+ يؤدي تعيين *enabled* إلى *false* إلى تعطيل هذا الإجراء ، بحيث لا يكون له أي تأثير. الافتراضي هو *true*.<br /><br />
+
+ عند إعادة تمكين الإجراء ، يستمر الرسم المتحرك من وقته الحالي [page:.time time] (الإعداد *enabled* إلى *false* لا يعيد تعيين الإجراء).<br /><br />
+
+ ملاحظة: لا يؤدي إعداد *enabled* إلى *true* إلى إعادة تشغيل الرسوم المتحركة تلقائيًا. سيؤدي ضبط *enabled* إلى *true* إلى إعادة تشغيل الرسوم المتحركة فورًا فقط إذا تم استيفاء الشرط التالي:
+ [page:.paused paused] تحتوي قيمة *false* ، لم يتم إلغاء تنشيط هذا الإجراء في هذه الأثناء (بتنفيذ أمر [page:.stop stop] أو [page:.reset reset]) ، وليس [page:.weight weight] أو [page:.timeScale timeScale] يساوي 0.
+ </p>
+
+ <h3>[property:Number loop]</h3>
+ <p>
+ وضع التكرار (يمكن تغييره بـ [page:.setLoop setLoop]). الافتراضي هو [page:Animation THREE.LoopRepeat] (مع عدد لا نهائي من [page:.repetitions repetitions])<br /><br />
+
+ يجب أن يكون أحد هذه الثوابت:<br /><br />
+ [page:Animation THREE.LoopOnce] - تشغيل المقطع مرة واحدة ،<br />
+ [page:Animation THREE.LoopRepeat] - تشغيل المقطع مع العدد المختار من *التكرارات* ،
+ في كل مرة تقفز من نهاية المقطع مباشرة إلى بدايته ،<br />
+ [page:Animation THREE.LoopPingPong] - تشغيل المقطع مع العدد المختار من *التكرارات* ، بدلاً من التشغيل للأمام والخلف.
+ </p>
+
+ <h3>[property:Boolean paused]</h3>
+ <p>
+ يؤدي تعيين *paused* إلى *true* إلى إيقاف تنفيذ الإجراء مؤقتًا عن طريق تعيين مقياس الوقت الفعال على 0. الافتراضي هو *false*.<br /><br />
+ </p>
+
+ <h3>[property:Number repetitions]</h3>
+ <p>
+ عدد التكرارات التي تم إجراؤها [page:AnimationClip] على مدار هذا الإجراء. يمكن تعيينه عبر [page:.setLoop setLoop]. الافتراضي هو *Infinity*.<br /><br />
+ ضبط هذا الرقم ليس له أي تأثير ، إذا تم ضبط [page:.loop loop mode] على [page:Animation THREE.LoopOnce].
+ </p>
+
+ <h3>[property:Number time]</h3>
+ <p>
+ the local time of this action (in seconds, starting with 0).<br /><br />
+
+ يتم تثبيت القيمة أو لفها إلى 0 ... مدة المقطع (وفقًا لحالة الحلقة).
+ يمكن تغير قيمتها بالنسبة إلى وقت لخالط الحركات الرئيسي عن طريق تغيير [page:.timeScale timeScale] (باستخدام [page:.setEffectiveTimeScale setEffectiveTimeScale] أو [page:.setDuration setDuration]).<br />
+ </p>
+
+ <h3>[property:Number timeScale]</h3>
+ <p>
+ Sعامل التحجيم للوقت [page:.time time]. تؤدي القيمة 0 إلى توقف الرسوم المتحركة مؤقتًا. تؤدي القيم السالبة إلى تشغيل الرسوم المتحركة بشكل عكسي. الافتراضي هو 1.<br /><br />
+ الخصائص / الطرق المتعلقة *timeScale* (على التوالي *time*) هم:
+ درجة تأثير هذا الإجراء (في المجال القائم بين [0 ، 1]). يمكن استخدام القيم بين 0 (بدون تأثير) و 1 (تأثير كامل) للمزج بين عدة إجراءات. الافتراضي هو 1. <br /><br />
+ الخصائص / الطرق المتعلقة *weight* هي:
+ [page:.crossFadeFrom crossFadeFrom],
+ [page:.crossFadeTo crossFadeTo],
+ [page:.enabled enabled],
+ [page:.fadeIn fadeIn],
+ [page:.fadeOut fadeOut],
+ [page:.getEffectiveWeight getEffectiveWeight],
+ [page:.setEffectiveWeight setEffectiveWeight],
+ [page:.stopFading stopFading].
+ </p>
+
+ <h3>[property:Boolean zeroSlopeAtEnd]</h3>
+ <p>
+ يتيح تشغيل السلس بدون مقاطع منفصلة للبداية والحلقة والنهاية. الافتراضي هو *true*.
+ </p>
+
+ <h3>[property:Boolean zeroSlopeAtStart]</h3>
+ <p>
+ يتيح تشغيل السلس بدون مقاطع منفصلة للبداية والحلقة والنهاية. الافتراضي هو *true*.
+ يؤدي هذا الإجراء إلى تلاشي [page:.fadeIn fade in] ، مما يؤدي إلى تلاشي إجراء آخر في نفس الوقت ، خلال الفترة الزمنية المنقضية. يمكن تقييد هذه الطريقة.<br /><br />
+
+ إذا كانت warpBoolean تحمل قيمة true ، فسيتم تطبيق [page:.warp warping] إضافيًا (تغييرات تدريجية في المقاييس الزمنية).<br /><br />
+
+ ملاحظة: كما هو الحال مع *fadeIn*/*fadeOut* ، يبدأ / ينتهي التلاشي بوزن 1.
+ يؤدي هذا الإجراء إلى تلاشي [page:.fadeOut fade out] ، يتلاشى في إجراء آخر في وقت واحد ، خلال الفترة الزمنية المنقضية. يمكن تقييد هذه الطريقة ضمن سلسلة.<br /><br />
+ إذا كانت warpBoolean صحيحة ، فسيتم تطبيق [page:.warp warping] إضافيًا (تغييرات تدريجية في المقاييس الزمنية).<br /><br />
+
+ ملاحظة: كما هو الحال مع *fadeIn*/*fadeOut* ، يبدأ / ينتهي التلاشي بوزن 1.
+ تعمل على إبطاء سرعة هذه الرسوم المتحركة إلى 0 من خلال إنقاص [page:.timeScale timeScale] تدريجيًا (بدءًا من قيمتها الحالية) ، خلال الفترة الزمنية المنقضية. يمكن تقييد هذه الطريقة ضمن سلسلة.
+ </p>
+
+ <h3>[method:Boolean isRunning]()</h3>
+ <p>
+ تُرجع true إذا كان الإجراء [page:.time time] قيد التشغيل حاليًا.<br /><br />
+
+ بالإضافة إلى تفعيله في الخالط (انظر [page:.isScheduled isScheduled]) ، يجب استيفاء الشروط التالية:
+ [page:.timeScale timeScale] يختلف عن 0 ، ولا توجد جدولة لبدء متأخر ([page:.startAt startAt]).<br /><br />
+
+ ملاحظة: لا يعني كون *isRunning* تحمل قيمة *true* أنه يمكن رؤية الرسوم المتحركة بالفعل. هذا هو الحال فقط ، إذا تم تعيين [page:.weight weight] بشكل إضافي على قيمة غير صفرية.
+ </p>
+
+ <h3>[method:Boolean isScheduled]()</h3>
+ <p>
+ تُرجع قيمة *true* ، إذا تم تنشيط هذا الإجراء في الخالط.<br /><br />
+ ملاحظة: هذا لا يعني بالضرورة أن الرسوم المتحركة تعمل بالفعل (قارن الشروط الإضافية لـ [page:.isRunning isRunning]).
+ </p>
+
+ <h3>[method:AnimationAction play]()</h3>
+ <p>
+ يعلم الخالط بضرورة البدء في تنشيط الحدث (action). يمكن تقييد هذه الطريقة ضمن سلسلة. <br /><br />
+
+ ملاحظة: لا يعني تنشيط هذا الإجراء بالضرورة أن الرسوم المتحركة تبدأ على الفور: إذا كان الإجراء قد انتهى بالفعل من قبل (من خلال الوصول إلى نهاية الحلقة الأخيرة) ، أو إذا تم تعيين وقت لبدء متأخر (عبر [page:.startAt startAt]) ،
+ يجب تنفيذ [page:.reset reset] أولاً. يمكن لبعض الإعدادات الأخرى ([page:.paused paused]=true, [page:.enabled enabled]=false,
+ [page:.weight weight]=0, [page:.timeScale timeScale]=0) منع تشغيل الرسوم المتحركة أيضًا.
+ </p>
+
+ <h3>[method:AnimationAction reset]()</h3>
+ <p>
+ يتم إعادة الحدث إلى وضع البداية. يمكن تقييد هذه الطريقة ضمن سلسلة.<br /><br />
+
+ تقوم هذه الطريقة بتعيين [page:.paused paused] إلى false ، و [page:.enabled enabled] إلى true ، ومن [page:.time time] إلى 0 ، وتقطع أي تزييف مجدول ، وتزيل عدد الحلقات الداخلية وجدولة البدء المتأخر.<br /><br />
+
+ ملاحظة: يتم استدعاء. *reset* دائمًا بواسطة [page:.stop stop] ، ولكن *reset* لا يتصل بـ *stop* نفسه.
+ هذا يعني: إذا كنت تريد كلاهما ، reset وstop ، لا تتصل بـ *reset* بل إتصل بـ *stop* بدلا من ذلك.
+ يزامن هذا الإجراء مع الإجراء الآخر الذي تم تمريره. يمكن تقييد هذه الوظيفة ضمن سلسلة. <br /><br />
+
+ تتم المزامنة عن طريق تعيين قيم [page:.time time] و [page:.timeScale timeScale] لهذا الإجراء على القيم المقابلة للإجراء الآخر (إيقاف أي التواء مجدول).<br /><br />
+
+ ملاحظة: لن يتم الكشف عن التغييرات المستقبلية في *time* و *timeScale* للإجراء الآخر.
+ يغير سرعة التشغيل ، خلال الفترة الزمنية المنقضية ، عن طريق تعديل [page:.timeScale timeScale] تدريجيًا من *startTimeScale* إلى *endTimeScale*.يمكن تقييد هذه الوظيفة ضمن سلسلة.
+ </p>
+
+
+ <h2>الأحداث (Events)</h2>
+
+
+ <p class="desc">
+ هناك حدثان يشيران عند انتهاء حلقة واحدة من الإجراء على التوالي. يمكنك الرد عليهم من خلال:
+ </p>
+ <code>
+ mixer.addEventListener( 'loop', function( e ) { …} ); // properties of e: type, action and loopDelta
+ mixer.addEventListener( 'finished', function( e ) { …} ); // properties of e: type, action and direction
+ [page:Number duration] - مدة هذا المقطع (بالثواني). إذا تم تمرير قيمة سالبة ، فسيتم حساب المدة من *tracks* التي تم تمريرها.<br />
+ [page:Array tracks] - مجموعة (جدول) من [page:KeyframeTrack KeyframeTracks].<br /><br />
+
+ ملاحظة: بدلاً من إنشاء AnimationClip مباشرةً مع المُنشئ ، يمكنك استخدام إحدى طرقه الثابتة لإنشاء AnimationClips: من JSON ([page:.parse parse]) ، من تسلسلات الهدف التحويلية ([page:.CreateFromMorphTargetSequence CreateFromMorphTargetSequence] ،
+ [page:.CreateClipsFromMorphTargetSequences CreateClipsFromMorphTargetSequences]) أو من التسلسلات الهرمية للرسوم المتحركة ([page:.parseAnimation parseAnimation]) - إذا كان النموذج الخاص بك لا يحتوي بالفعل على AnimationClips في مجموعة الرسوم المتحركة الخاصة بهندسة.
+ </p>
+
+
+ <h2>الخصائص (Properties)</h2>
+
+
+ <h3>[property:Number duration]</h3>
+ <p>
+ مدة هذا المقطع (بالثواني). يمكن حساب ذلك من مجموعة [page:.tracks tracks] عبر [page:.resetDuration resetDuration].
+ </p>
+
+ <h3>[property:String name]</h3>
+ <p>
+ اسم لهذا المقطع. يمكن البحث عن مقطع معين طريق بإستعمال [page:.findByName findByName].
+ </p>
+
+ <h3>[property:Array tracks]</h3>
+ <p>
+ جدول يحتوي على [page:KeyframeTrack] لكل خاصية يتم تحريكها بواسطة هذا المقطع.
+ </p>
+
+ <h3>[property:String uuid]</h3>
+ <p>
+ [link:http://en.wikipedia.org/wiki/Universally_unique_identifier UUID] لهذا المقطع. يتم تعيينه تلقائيًا ولا يجب تحريره.
+ </p>
+
+
+ <h2>الوظائف (Methods)</h2>
+
+
+ <h3>[method:AnimationClip clone]()</h3>
+ <p>
+ إرجاع نسخة من هذا المقطع.
+ </p>
+
+ <h3>[method:this optimize]()</h3>
+ <p>
+ يحسن من أداء كل مسار عن طريق إزالة المفاتيح المتسلسلة المتكررة (الشائعة في تسلسلات هدف التحويل - morph target sequences).
+ </p>
+
+ <h3>[method:this resetDuration]()</h3>
+ <p>
+ يضبط [page:.duration duration] للمقطع على أطول مدة [page:KeyframeTrack] ممكنة.
+ </p>
+
+ <h3>[method:this trim]()</h3>
+ <p>
+ اقتطاع كل المسارات حسب مدة المقطع.
+ </p>
+
+ <h3>[method:Boolean validate]()</h3>
+ <p>
+ يقوم بتأدية الحد الأدنى من التحقق من الصحة على كل مسار في المقطع. إرجاع *true* إذا كانت جميع المسارات صالحة.
+ تُرجع مصفوفة من AnimationClips الجديدة التي تم إنشاؤها من [page:Geometry.morphTargets morph target sequences] من الشكل الهندسي ، في محاولة لفرز أسماء الأهداف التحويلية إلى أنماط قائمة على مجموعة الرسوم المتحركة مثل "Walk_001 ، Walk_002 ، Run_001 ، Run_002 ...".
+ يُرجع مقطع رسوم متحركة جديدًا من [page:Geometry.morphTargets morph targets array] تم تمريره لشكل هندسي ، مع أخذ اسم وعدد الإطارات في الثانية.<br /><br />
+
+ ملاحظة: قيمة fps مطلوبة و ضرورية ، ولكن يمكن إعادة ضبظ سرعة الرسوم المتحركة في *AnimationAction* عبر [page:AnimationAction.setDuration animationAction.setDuration].
+ AnimationMixer هو مشغل للرسوم المتحركة على كائن معين في المشهد. عندما يتم تحريك كائنات متعددة في المشهد بشكل مستقل ، يمكن استخدام AnimationMixer واحد لكل كائن.<br /><br />
+
+ للحصول على نظرة عامة حول العناصر المختلفة لنظام الرسوم المتحركة three.js ، راجع مقالة "نظام الحركات" في قسم "الخطوات التالية" من الدليل.
+ </p>
+
+
+ <h2>المنشئ (Constructor)</h2>
+
+
+ <h3>[name]( [param:Object3D rootObject] )</h3>
+ <p>
+ [page:Object3D rootObject] - الكائن الذي سيتم تشغيل رسومه المتحركة بواسطة هذا الخالط.<br />
+ </p>
+
+
+ <h2>الخصائص (Properties)</h2>
+
+
+ <h3>[property:Number time]</h3>
+ <p>
+ وقت الخالط الكامل (بالثواني ؛ بدءًا من 0 عند إنشاء الخالط).
+ </p>
+
+ <h3>[property:Number timeScale]</h3>
+ <p>
+ عامل تحجيم لـ [page:.time mixer time].<br /><br />
+
+ ملاحظة: يأدي ضبط مقياس وقت الخلاط على 0 والعودة لاحقًا إلى 1 إلى إمكانية إيقاف / إلغاء إيقاف مؤقت لجميع الإجراءات التي يتحكم فيها هذا الخالط.
+ إرجاع [page:AnimationAction] للمقطع الذي تم تمريره ، اختيارياً باستخدام كائن جذر مختلف عن الجذر الافتراضي لجهاز المزج. يمكن أن تكون القيمة الأولى إما كائن [page:AnimationClip] أو اسم AnimationClip.<br /><br />
+
+ إذا لم يكن هناك إجراء يلائم المقطع ومعلمات الجذر ، فسيتم إنشاؤه بهذه الطريقة. استدعاء هذه الطريقة عدة مرات مع نفس المقطع ومعلمات الجذر يؤدي دائمًا إلى إرجاع نفس مثيل المقطع.
+ يضبط الخالط العام على وقت محدد ويقوم بتحديث الرسوم المتحركة وفقًا لذلك.<br /><br />
+
+ يكون هذا مفيدًا عندما تحتاج إلى الانتقال إلى وقت محدد في رسم متحرك. سيتم قياس القيمة المدخلة حسب مقياس الوقت لجهاز الخالط [page:.timeScale timeScale].
- If not null, sets the background used when rendering the scene, and is always rendered first. Can be set to a [page:Color] which sets the clear color, a [page:Texture] covering the canvas, or a cubemap as a [page:CubeTexture] or [page:WebGLCubeRenderTarget]. Default is null.
+ If not null, sets the background used when rendering the scene, and is always rendered first.
+ Can be set to a [page:Color] which sets the clear color, a [page:Texture] covering the canvas, a cubemap as a [page:CubeTexture] or [page:WebGLCubeRenderTarget] or an equirectangular as a [page:Texture] . Default is null.
+ This class can be used to automatically save the depth information of a rendering into a texture.
+ When using a WebGL 1 rendering context, [name] requires support for the [link:https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/ WEBGL_depth_texture] extension.
</p>
<h2>Examples</h2>
@@ -31,11 +31,11 @@
[page:Number height] -- height of the texture.<br />
- [page:Constant type] -- Default is [page:Textures THREE.UnsignedShortType].
+ [page:Constant type] -- Default is [page:Textures THREE.UnsignedShortType] when unsing [page:Textures DepthFormat] and [page:Textures THREE.UnsignedInt248Type] when using [page:Textures DepthStencilFormat].
See [page:Textures type constants] for other choices.<br />
[page:Constant mapping] --
- See [page:Textures type constants] for details.<br />
+ See [page:Textures mapping mode constants] for details.<br />
[page:Constant wrapS] -- The default is [page:Textures THREE.ClampToEdgeWrapping].
See [page:Textures wrap mode constants] for other choices.<br />
@@ -73,7 +73,7 @@
<h3>[page:Texture.type .type]</h3>
<p>
- Default is [page:Textures THREE.UnsignedShortType].
+ Default is [page:Textures THREE.UnsignedShortType] when unsing [page:Textures DepthFormat] and [page:Textures THREE.UnsignedInt248Type] when using [page:Textures DepthStencilFormat].
See [page:Textures format constants] for details.<br />
+ This class can be used to automatically save the depth information of a rendering into a texture.
+ When using a WebGL 1 rendering context, [name] requires support for the [link:https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/ WEBGL_depth_texture] extension.
+ [page:Constant type] -- Default is [page:Textures THREE.UnsignedShortType] when unsing [page:Textures DepthFormat] and [page:Textures THREE.UnsignedInt248Type] when using [page:Textures DepthStencilFormat].
请参阅[page:Textures type constants](类型常量)来了解其他选项。<br />
+ Default is [page:Textures THREE.UnsignedShortType] when unsing [page:Textures DepthFormat] and [page:Textures THREE.UnsignedInt248Type] when using [page:Textures DepthStencilFormat].
+ يوضح هذه المقال كيفية الحصول على three.js في بيئة [link:https://nodejs.org/en/ node.js] حتى تتمكن من تنفيذ الاختبارات الآلية. يمكن إجراء الاختبارات على سطر الأوامر ، أو بواسطة أدوات CI الآلية مثل [link:https://travis-ci.org/ Travis].
+ </p>
+
+ <h2>النسخة القصيرة</h2>
+
+ <p>
+ إذا كنت مرتاحًا مع node و npm ،
+ <code>
+ $ npm install three --save-dev
+ </code>
+ و من ثم قم بإضافة
+ <code>
+ var THREE = require('three');
+ </code>
+ للاختبار الخاص بك.
+ </p>
+
+ <h2>إنشاء مشروع قابلة للاختبار من الصفر</h2>
+ <p>
+ إذا لم تكن معتادًا على هذه الأدوات ، فإليك دليلًا سريعًا (بالنسبة لنظام التشغيل Linux ، ستكون عملية التثبيت مختلفة قليلاً باستخدام windows ، لكن أوامر NPM متطابقة).
+ </p>
+
+ <h3>الإعدادات الأساسية</h3>
+ <div>
+ <ol>
+ <li>
+ قم بتثبيت [link:https://www.npmjs.org/ npm] و nodejs. عادةً ما يبدو أقصر طريق كالأتي
+ <code>
+$ sudo apt-get install -y npm nodejs-legacy
+# fix any problems with SSL in the default registry URL
+$ npm config set registry http://registry.npmjs.org/
+ </code>
+ </li>
+
+ <li>
+ أنشئ دليل مشروع جديد
+ <code>
+ $ mkdir test-example; cd test-example
+ </code>
+ </li>
+
+ <li>
+ اطلب من npm إنشاء ملف مشروع جديد لك:
+ <code>
+ $ npm init
+ </code>
+ واقبل جميع الإعدادات الافتراضية عن طريق الضغط على Enter في جميع المطالبات ، سيؤدي هذا إلى إنشاء package.json.
+ </li><br />
+
+ <li>
+ جرب وابدأ اختبار الميزة بـ
+ <code>
+$ npm test
+ </code>
+ هذا سيفشل ، وهو أمر متوقع. إذا نظرت في package.json ، فإن تعريف البرنامج النصي للاختبار هو
+ <code>
+ "test": "echo \"Error: no test specified\" && exit 1"
+ لاحظ أنه تم إنشاء node_modules/ وتظهر تبعياتك هناك. لاحظ أيضًا أنه تم تحديث package.json: تمت إضافة خاصية devDependencies وتحديثها باستخدام --save-dev.
+ </li><br />
+
+ <li>
+ قم بتحرير package.json لاستخدام mocha للاختبار. عندما يتم استدعاء الاختبار ، نريد فقط تشغيل المخاوي وتحديد مراسل مطول. بشكل افتراضي ، سيؤدي هذا إلى تشغيل أي شيء في test (لا يمكن تشغيل الدليل test في npm ERR! ، قم بإنشائه عبر اختبار mkdir)
+ <code>
+ "test": "mocha --reporter list"
+ </code>
+ </li>
+
+ <li>
+ أعد الاختبار باستخدام
+ <code>
+ $ npm test
+ </code>
+
+ يجب أن ينجح هذا الآن ، حيث يتم الإبلاغ عن 0 تمرير (1 جزء من الثانية) أو ما شابه.
+ </li>
+
+ </ol>
+ </div>
+
+ <h2>أضف three.js</h2>
+ <div>
+ <ol>
+ <li>
+ دعنا نسحب تبعية three.js لدينا مع
+ <code>
+$ npm install three --save-dev
+ </code>
+ <ul>
+ <li>
+ إذا كنت بحاجة إلى إصدار مختلف ، فاستخدم
+ <code>
+ $ npm show three versions
+ </code>
+ لمعرفة ما هو متاح. لإخبار npm بالقيمة الصحيحة ، استخدم
+ (0.84.0 في هذا المثال). - حفظ يجعل هذا تبعية لهذا المشروع ، بدلاً من dev تبعية. انظر المستندات هنا [link:https://www.npmjs.org/doc/json.html here] لمزيد من المعلومات.
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ سيبحث Mocha عن الاختبارات في test/ ، لذلك دعونا
+ <code>
+ $ mkdir test
+ </code>
+ </li>
+
+ <li>
+ أخيرًا ، نحتاج بالفعل إلى اختبار JS للتشغيل. دعنا نضيف اختبارًا بسيطًا للتحقق من أن الكائن three.js متاح ويعمل. أنشئ test/verify-three.js تحتوي على:
+<code>
+var THREE = require('three');
+var assert = require("assert");
+
+describe('The THREE object', function() {
+ it('should have a defined BasicShadowMap constant', function() {
+ قم بتصدير الكود الوظيفي الخاص بك بطريقة يمكن للعقدة js رؤيتها ، لاستخدامها مع طلب.
+ شاهده هنا [link:https://github.com/air/encounter/blob/master/js/Physics.js here].
+ </li>
+
+ <li>
+ اطلب الكود الخاص بك في ملف الاختبار ، بنفس الطريقة التي فعلنا بها require('three') في المثال أعلاه.
+ </li>
+ </ol>
+
+ <p>
+ سيختلف البندان 2 و 3 بناءً على كيفية إدارتك للرمز. في مثال Physics.js الموضح أعلاه ، يكون جزء التصدير في النهاية. نقوم بتعيين كائن إلى module.exports:
+ إذا كنت تستخدم بالفعل شيئًا ذكيًا مثل request.js أو browserify فتخط هذا الجزء.
+ </p>
+ <p>
+ عادةً ما يتم تشغيل مشروع three.js في المتصفح. يتم تحميل الوحدة النمطية عن طريق المتصفح الذي يقوم بتنفيذ مجموعة من علامات البرنامج النصي. فبالنسبة لملفاتك الفردية فلا داعي للقلق بشأن التبعيات. ومع ذلك ، في سياق nodejs ، لا يوجد index.html يربط كل شيء معًا ، لذلك يجب أن تكون واضحًا.
+ </p>
+ <p>
+ إذا كنت تقوم بتصدير وحدة تعتمد على ملفات أخرى ، فسيتعين عليك إخبار العقدة بتحميلها.
+ إليك طريقة واحدة:
+ </p>
+ <ol>
+ <li>
+ في بداية الوحدة النمطية الخاصة بك ، تحقق لمعرفة ما إذا كنت في بيئة nodejs.
+ </li>
+ <li>
+ إذا كان هذا هو الحال، فيتوجب عليك أن تعلن عن التبعيات الخاصة بك.
+ </li>
+ <li>
+ إذا لم يكن الأمر كذلك ، فمن المحتمل أنك في متصفح لذلك لا تحتاج إلى القيام بأي شيء آخر.
+ يضمن نظام الرسوم المتحركة three.js ، إمكانية تحريك الخصائص المختلفة لنماذجك: عظام [page:SkinnedMesh skinned and rigged model] ، [page:Geometry.morphTargets morph targets] ، خصائص مادة مختلفة (ألوان ، عتامة ، منطقية) ، الرؤية والتحولات. يمكن أن تتلاشى الخصائص المتحركة، أو تتلاشى وتتشوه. يمكن تغيير مقاييس الوزن والوقت للرسوم المتحركة المتزامنة المختلفة على نفس الكائن وكذلك على كائنات مختلفة بشكل مستقل. يمكن مزامنة الرسوم المتحركة المختلفة على نفس الشيء وعلى كائنات مختلفة.
+ <br /><br />
+
+ لتحقيق كل هذا في نظام واحد متجانس ، نظام الرسوم المتحركة three.js شعد تغييرا هامًا في عام [link:https://github.com/mrdoob/three.js/issues/6881 2015] (احذر من المعلومات القديمة!) ، ولديه الآن بنية مشابهة لـ Unity / Unreal Engine 4. تقدم هذه الصفحة لمحة موجزة عن المكونات الرئيسية للنظام وكيف تعمل معًا.
+
+ </p>
+
+ <h3>مقاطع الحركات</h3>
+
+ <p class="desc">
+
+ إذا قمت باستيراد كائن ثلاثي الأبعاد متحرك بنجاح (لا يهم ما إذا كان يحتوي على عظام أو أهداف تشكيل أو كليهما) - على سبيل المثال تصديره من Blender مع [link:https://github.com/KhronosGroup/glTF-Blender-IO glTF Blender exporter] وتحميله في مشهد three.js باستخدام 333 - يضمن أن توجد مصفوفة تسمى "الرسوم المتحركة" ، تحتوي على 444 لهذا النموذج (انظر قائمة برامج التحميل المتوفرة أدناه).
+ <br /><br />
+
+ يحتفظ كل مقطع *AnimationClip* عادةً ببيانات نشاط معين للكائن. إذا كانت الشبكة عبارة عن شخصية ، على سبيل المثال ، فقد يكون هناك مقطع Animation واحد للمشي ، وثاني للقفز ، وثالث للتنقل وما إلى ذلك.
+
+ </p>
+
+ <h3>مسارات الإطار الأساسي (Keyframe tracks)</h3>
+
+ <p class="desc">
+
+ داخل ملف *AnimationClip* ، يتم تخزين البيانات الخاصة بكل خاصية متحركة في [page:KeyframeTrack]. بافتراض أن كائن حرف له هيكل عظمي [page:Skeleton skeleton] ، يمكن لمسار إطار رئيسي واحد تخزين البيانات لتغييرات موضع عظم الذراع السفلي بمرور الوقت ، وهو أمر مختلف تتبع البيانات الخاصة بتغييرات دوران نفس العظم ، وثلث موضع المسار ، دوران أو تحجيم عظم آخر ، وما إلى ذلك. يجب أن يكون واضحًا ، أن AnimationClip يمكن أن يتكون من الكثير من هذه المسارات.
+ <br /><br />
+
+ بافتراض أن النموذج يحتوي على [page:Geometry.morphTargets morph targets] (على سبيل المثال ، أحد أهداف التشكيل يظهر وجهًا ودودًا والآخر يظهر وجهًا غاضبًا) ، فإن كل مسار يحمل المعلومات المتعلقة بكيفية تغيير الرقم [page:Mesh.morphTargetInfluences influence] لهدف تشكيل معين أثناء أداء المقطع.
+
+ </p>
+
+ <h3>خالط الحركات (Animation Mixer)</h3>
+
+ <p class="desc">
+
+ تشكل البيانات المخزنة أساس الرسوم المتحركة فقط - يتم التحكم في التشغيل الفعلي بواسطة [page:AnimationMixer]. يمكنك تخيل هذا ليس فقط كمشغل للرسوم المتحركة ، ولكن ك كجهاز أو مثل وحدة التحكم في المزج الحقيقي ، والتي يمكنها التحكم في العديد من الرسوم المتحركة في وقت واحد ومزجها ودمجها.
+
+ </p>
+
+ <h3>أحداث الحركات (Animation Actions)</h3>
+
+ <p class="desc">
+
+ يحتوي *AnimationMixer* نفسه على عدد قليل جدًا من الخصائص والطرق (العامة) ، لأنه يمكن التحكم فيه بواسطة [page:AnimationAction AnimationActions]. من خلال تكوين *AnimationAction* يمكنك تحديد وقت تشغيل *AnimationClip* معين أو إيقافه مؤقتًا أو إيقاف تشغيله أحد الخلاطات ، إذا كان يجب تكرار المقطع وعدد مرات تكرارها ، سواء كان يجب إجراؤه بتلاشي أو مقياس زمني ، وبعض الأشياء الإضافية ، مثل التلاشي أو التزامن.
+
+ </p>
+
+ <h3>تحريك مجموعة من النماذج</h3>
+
+ <p class="desc">
+
+ إذا كنت تريد أن تطبق على مجموعة من الكائنات حالة حركة مشتركة ، يمكنك استخدام [page:AnimationObjectGroup]..
+
+ </p>
+
+ <h3>التنسيقات و عناصر التحميل المدعومة</h3>
+
+ <p class="desc">
+ لاحظ أنه لا تتضمن جميع تنسيقات النماذج الرسوم المتحركة (لا سيما OBJ) ، وأن بعض أدوات تحميل three.js فقط تدعم [page:AnimationClip AnimationClip] تسلسلًا. العديد منها يدعم هذا النوع من الرسوم المتحركة:
+ </p>
+
+ <ul>
+ <li>[page:ObjectLoader THREE.ObjectLoader]</li>
+ <li>THREE.BVHLoader</li>
+ <li>THREE.ColladaLoader</li>
+ <li>THREE.FBXLoader</li>
+ <li>[page:GLTFLoader THREE.GLTFLoader]</li>
+ <li>THREE.MMDLoader</li>
+ </ul>
+
+ <p class="desc">
+ لاحظ أن 3ds max و Maya لا يمكنهم حاليًا تصدير العديد من الرسوم المتحركة (بمعنى الرسوم المتحركة غير الموجودة في نفس المخطط الزمني) مباشرةً إلى ملف واحد.
+ </p>
+
+ <h2>مثال</h2>
+
+ <code>
+ var mesh;
+
+ // Create an AnimationMixer, and get the list of AnimationClip instances
+ var mixer = new THREE.AnimationMixer( mesh );
+ var clips = mesh.animations;
+
+ // Update the mixer on each frame
+ function update () {
+ mixer.update( deltaSeconds );
+ }
+
+ // Play a specific animation
+ var clip = THREE.AnimationClip.findByName( clips, 'dance' );
+ يمكن لـ Three.js استخدام WebGL لعرض المشاهد الخاصة بك على جميع المتصفحات الحديثة. بالنسبة إلى المتصفحات الأقدم ، وخاصة Internet Explorer 10 والإصدارات الأقدم ، قد تضطر إلى الرجوع إلى أحد المستعرضات الأخرى [link:https://github.com/mrdoob/three.js/tree/master/examples/jsm/renderers renderers] (CSS2DRenderer و CSS3DRenderer و SVGRenderer). بالإضافة إلى ذلك ، قد تضطر إلى تضمين بعض polyfills ، بالأخص إذا كنت تستخدم ملفات من المجلد [link:https://github.com/mrdoob/three.js/tree/master/examples /examples].
+ </p>
+ <p>
+ ملاحظة: إذا لم تكن بحاجة إلى دعم هذه المتصفحات القديمة ، فلا يوصى باستخدام برامج العارض الأخرى لأنها أبطأ وتدعم ميزات أقل من WebGLRenderer.
+ </p>
+ </div>
+
+ <h2>المتصفحات التي تدعم WebGL</h2>
+ <div>
+ <p>
+ Google Chrome 9+, Firefox 4+, Opera 15+, Safari 5.1+, Internet Explorer 11 و Microsoft Edge.<br/>
+ يمكنك العثور على المتصفحات التي تدعم WebGL في [link:https://caniuse.com/#feat=webgl Can I use WebGL].
+ </p>
+ </div>
+
+ <h2>ميزات لغة JavaScript أو واجهات الويب البرمجية المستخدمة في three.js</h2>
+ <div>
+ <p>
+ فيما يلي بعض الميزات المستخدمة في three.js. قد يتطلب بعض منهم polyfills إضافية.
+ <p>الهدف من هذا القسم هو تقديم لمحة وجيزة عن كيفية عمل المكتبة. سنبدأ بتحضير مشهد يتمثل في مكعب ثلاثي الأبعاد .الصفحة مرفوقة بمثال أسفلها في حالة واجهتك بعض المشاكل وإحتجت إلى المساعدة.</p>
+
+ <h2>قبل أن نبدأ</h2>
+
+ <p>
+ قبل أن يمكنك إستعمال المكتبة, يجب أن توفر مكان لإظهار المشهد. قم بإنشاء ملف HTML يحتوي الشفرة البرمجية التالية
+ بصحبة نسخة من المكتبة [link:https://threejs.org/build/three.js three.js] في مجلد سمه js و من ثم فم بفتح الصفحة في المتصفح.
+ </p>
+
+ <code>
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <meta charset="utf-8">
+ <title>My first three.js app</title>
+ <style>
+ body { margin: 0; }
+ canvas { display: block; }
+ </style>
+ </head>
+ <body>
+ <script src="js/three.js"></script>
+ <script>
+ // Our Javascript will go here.
+ </script>
+ </body>
+ </html>
+ </code>
+
+ <p>
+ هذا كل شيء. بقية الأوامر البرمجية ستكون محتوات في وسم <script> الفارغ حاليا.
+ </p>
+
+ <h2>إنشاء مشهد</h2>
+
+ <p>
+ لنتمكن من إظهار أي شيء بإستهمال three.js، نحتاج ثلاثة عناصر أساسية: المسرح (Scene)، الكاميرا (Camera)، و العارض
+ (Renderer).
+ </p>
+
+ <code>
+ var scene = new THREE.Scene();
+ var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
+ وإستخدم ترميز CSS لوضع موضع مطلق (position absolutely) في موضع فوق كل المواقع الأخرى باستخدام z-index بالأخاص إذا كنت تقوم بتشغيل على كامل الشاشة three.js.
+ </p>
+
+ <code>
+#info {
+ position: absolute;
+ top: 10px;
+ width: 100%;
+ text-align: center;
+ z-index: 100;
+ display:block;
+}
+ </code>
+
+ </div>
+
+
+
+ <h2>2. ارسم نصًا على (canvas) واستخدمه كـ [page:Texture]</h2>
+ <div>
+ <p>استخدم هذه الطريقة إذا كنت ترغب في رسم نص بسهولة على سطح في مشهد three.js.</p>
+ </div>
+
+
+ <h2>3. قم بإنشاء نموذج في التطبيق ثلاثي الأبعاد المفضل لديك وقم بتصديره إلى three.js</h2>
+ <div>
+ <p>إستخدم هذه الطريقة إذا كنت تفضل العمل مع تطبيقاتك ثلاثية الأبعاد وإستيراد النماذج إلى three.js</p>
+ </div>
+
+
+
+ <h2>4. هندسة النص الإجرائي (Procedural Text Geometry)</h2>
+ <div>
+ <p>
+ إذا كنت تفضل العمل فقط في THREE.js أو إنشاء أشكال هندسية إجرائية وديناميكية للنص ثلاثي الأبعاد ، فيمكنك إنشاء شبكة تعتبر هندستها مثيلًا لـ THREE.TextGeometry:
+ لكي يعمل هذا، ستحتاج Text Geometry إلى نموذج من THREE.Font لتعيينه لجعله إعداد "الخط" الخاصة به.
+
+ راجع صفحة [page:TextGeometry] للحصول على مزيد من المعلومات حول كيفية القيام بذلك ، و وصف كل الخيارات المتاحة ، وقائمة بخطوط JSON التي تأتي مع توزيع THREE.js نفسه.
+ إذا كان Typeface معطلاً ، أو كنت تريد استخدام خط غير موجود ، فهناك برنامج تعليمي مع برنامج نصي بايثون لـ bender يسمح لك بتصدير النص إلى Three.js بتنسيق JSON:
+ تسمح BMFonts (الخطوط النقطية) بدمج الصور الرمزية في BufferGeometry واحد. يدعم عرض BMFont التفاف الكلمات ، وتباعد الأحرف ، وتقنين الأحرف ، وحقول المسافة الموقعة مع المشتقات القياسية ، وحقول المسافة الموقعة متعددة القنوات ، والخطوط متعددة الأنسجة ، والمزيد.
+ انظر [link:https://github.com/Jam3/three-bmfont-text three-bmfont-text].
+ </p>
+ <p>
+ تتوفر الخطوط في مشاريع مثل [link:https://github.com/etiennepinchon/aframe-fonts A-Frame Fonts] ، أو يمكنك إنشاء خطوطك الخاصة من أي خط .TTF ، مع التحسين لتضمين الأحرف المطلوبة للمشروع.
+ </p>
+ <p>
+ بعض الأدوات المفيدة
+ </p>
+ <ul>
+ <li>[link:http://msdf-bmfont.donmccurdy.com/ msdf-bmfont-web] <i>(على شبكة الإنترنت)</i></li>
+ لنفترض أنك تريد رسم خط أو دائرة ، وليس إطارًا سلكيًا [page:Mesh]. نحتاج أولاً إلى إعداد العارض [page:WebGLRenderer renderer] ، المسرح [page:Scene scene] والكاميرا (انظر صفحة إنشاء مشهد).
+ <h2>ما هو أفضل تنسيق النموذج ثلاثي الأبعاد الذي تدعمه المكتبة؟</h2>
+ <div>
+ <p>
+ التنسيق الموصى به لاستيراد المجسمات وتصديرها هو glTF (GL Transmission Format). نظرًا لأن glTF يركز على تسليم أصول وقت التشغيل ، فهو مضغوط للإرسال وسريع التحميل.
+ </p>
+ <p>
+ توفر three.js أدوات تحميل للعديد من التنسيقات الشائعة الأخرى مثل FBX أو Collada أو OBJ أيضًا. ومع ذلك ، يجب أن تحاول دائمًا إنشاء سير عمل قائم على glTF في مشاريعك. لمزيد من المعلومات ، انظر [link:#manual/introduction/Loading-3D-models loading 3D models].
+ </p>
+ </div>
+
+ <h2>لماذا توجد علامات meta viewport في الأمثلة؟</h2>
+ <p>تتحكم هذه العلامات في حجم منفذ العرض ومقياسه لمتصفحات الجوال (حيث يمكن عرض محتوى الصفحة بحجم مختلف عن إطار العرض المرئي).</p>
+
+ <p>[link:https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/UsingtheViewport/UsingtheViewport.html Safari: Using the Viewport]</p>
+
+ <p>[link:https://developer.mozilla.org/en/Mobile/Viewport_meta_tag MDN: Using the viewport meta tag]</p>
+ </div>
+
+ <h2>كيف يمكن الحفاظ على مقياس المشهد عند تغيير الحجم؟</h2>
+ <p>
+ نريد أن تظهر جميع النماذج ، بغض النظر عن بعدها عن الكاميرا ، بالحجم نفسه ، حتى عندما يتم تغيير حجم النافذة.
+
+ المعادلة الأساسية لحل هذه المعادلة هي معادلة الارتفاع المرئي على مسافة معينة:
+ إذا قمنا بزيادة ارتفاع النافذة بنسبة معينة ، فإن ما نريده هو زيادة الارتفاع المرئي في جميع المسافات بنفس النسبة المئوية.
+
+ لا يمكن القيام بذلك عن طريق تغيير موضع الكاميرا. بل ما يجب أن تفعله هو تغيير مجال رؤية الكاميرا.
+ [link:http://jsfiddle.net/Q4Jpu/ Example].
+ </p>
+
+ <h2>لماذا جزء من نموذجي غير مرئي؟</h2>
+ <p>
+ يمكن أن يكون هدا بسبب إعدام الوجه, فالأوجه التي تبني النموذج لها إتجاه معين من خلاله يتم تقرير ما يتم إضهار. و هده الظاهرة تقوم بإلغاء الوجه الخلفي في الحالات العادية.
+ لمعرفة ما إذا كانت هذه هي مشكلتك ، قم بتغيير جانب المادة إلى THREE.DoubleSide.
+ يقدم هذا الدليل لمحة موجزة عن المكونات الأساسية لتطبيق VR مخصص للويب بإستعمال three.js.
+ </p>
+
+ <h2>سير العمل</h2>
+
+ <p>
+ أولاً ، عليك ضم [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/webxr/VRButton.js VRButton.js] في مشروعك.
+ </p>
+
+ <code>
+import { VRButton } from 'three/examples/jsm/webxr/VRButton.js';
+ </code>
+
+ <p>
+ *VRButton.createButton()* يقوم بأمرين مهمين: أولا يقوم بإنشاء زر يشير إلى توافق الواقع الافتراضي. إلى جانب ذلك ، يبدأ جلسة VR إذا قام المستخدم بتنشيط الزر. كل ما عليك فعله هو إضافة السطر التالي من التعليمات البرمجية إلى تطبيقك.
+ بعد ذلك ، عليك توجيه نموذج *WebGLRenderer* لتمكين عرض XR.
+ </p>
+
+ <code>
+renderer.xr.enabled = true;
+ </code>
+
+ <p>
+ أخيرًا ، يجب عليك ضبط حلقة الرسوم المتحركة لأننا لا نستطيع استخدام وظيفة *window.requestAnimationFrame()* المعروفة لدينا. بالنسبة لمشاريع الواقع الافتراضي ، نستخدم [page:WebGLRenderer.setAnimationLoop setAnimationLoop].
+ يبدو الحد الأدنى من الكود كما يلي:
+ </p>
+
+ <code>
+renderer.setAnimationLoop( function () {
+
+ renderer.render( scene, camera );
+
+} );
+ </code>
+
+ <h2>الخطوات التالية</h2>
+
+ <p>
+ ألق نظرة على أحد أمثلة WebVR الرسمية لرؤية سير العمل.<br /><br />
+ أحد الجوانب المهمة لتحسين الأداء وتجنب تسرب الذاكرة في تطبيقك هو التخلص من كيانات المكتبة غير المستخدمة. عندما تقوم بإنشاء مثيل من النوع * three.js * ، فإنك تخصص قدرًا معينًا من الذاكرة.
+ ومع ذلك ، يُنشئ * three.js * كائنات محددة مثل الأشكال الهندسية أو المواد ، كيانات ذات صلة بـ WebGL مثل المخازن المؤقتة أو برامج التظليل الضرورية للعرض. من المهم إبراز أن هذه الكائنات لا يتم تحريرها تلقائيًا ، وبدلاً من ذلك ، يجب أن يستخدم التطبيق واجهة برمجة تطبيقات خاصة لتحرير هذه الموارد. يقدم هذا الدليل نظرة عامة موجزة حول كيفية استخدام واجهة برمجة التطبيقات هذه وما هي الكائنات ذات الصلة في هذا السياق.
+ </p>
+
+ <h2>الهندسة (Geometries)</h2>
+
+ <p>
+ تمثل الهندسة عادةً معلومات قمة الرأس تُعرَّف على أنها مجموعة من السمات. تنشئ * three.js * داخليًا كائنًا من النوع [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLBuffer WebGLBuffer] لكل سمة. يتم حذف هذه الكيانات فقط إذا اتصلت بـ [page:BufferGeometry.dispose](). إذا أصبحت الهندسة قديمة في التطبيق الخاص بك ، فقم بتنفيذ الطريقة لتحرير جميع الموارد ذات الصلة.
+ </p>
+
+ <h2>المواد (Materials)</h2>
+
+ <p>
+ تحدد المادة كيفية تجسيد الكائنات. يستخدم * three.js * معلومات تعريف المادة لإنشاء برنامج تظليل للعرض.
+ لا يمكن حذف برامج Shader إلا إذا تم التخلص من المواد المعنية. لأسباب تتعلق بالأداء ، يحاول * three.js * إعادة استخدام القائمة برامج تظليل إن أمكن. لذلك يتم حذف برنامج shader فقط إذا تم التخلص من جميع المواد ذات الصلة. يمكنك الإشارة إلى التخلص من مادة عن طريق تنفيذ [page:Material.dispose] ().
+ </p>
+
+ <h2>الأنسجة (Textures)</h2>
+
+ <p>
+ التخلص من المواد ليس له أي تأثير على القوام. يتم التعامل معها بشكل منفصل حيث يمكن استخدام نسيج واحد بواسطة مواد متعددة في نفس الوقت.
+ عندما تقوم بإنشاء مثيل [page:Texture] ، فإن three.js داخليًا تنشئ مثيلًا من [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLTexture WebGLTexture].
+ على غرار المخازن المؤقتة ، لا يمكن حذف هذا الكائن إلا عن طريق استدعاء [page:Texture.dispose]().
+ </p>
+
+ <h2>أهداف العرض</h2>
+
+ <p>
+ لا تقوم الكائنات من النوع [page:WebGLRenderTarget] فقط بتخصيص مثيل لـ [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLTexture WebGLTexture] ولكن أيضًا [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLFramebuffer WebGLFramebuffer]s و [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderbuffer WebGLRenderbuffer]s لتحقيق وجهات العرض المخصصة. لا يتم تخصيص هذه الكائنات إلا بتنفيذ [page:WebGLRenderTarget.dispose]().
+ </p>
+
+ <h2>متفرقات (Miscellaneous)</h2>
+
+ <p>
+ هناك فئات أخرى من دليل الأمثلة مثل الضوابط أو ممرات المعالجة اللاحقة التي توفر طرق * dispose () * من أجل إزالة مستمعي الأحداث الداخلية أو تقديم الأهداف. بشكل عام ، يوصى بالتحقق من واجهة برمجة التطبيقات أو وثائق الفصل الدراسي ومراقبة * dispose () *. إذا كان موجودًا ، يجب استخدامه عند تنظيف الأشياء.
+ </p>
+
+ <h2>الأسئلة الشائعة (FAQ)</h2>
+
+ <h3>لماذا لا يمكن لـ * three.js * التخلص من الكائنات تلقائيًا؟</h3>
+
+ <p>
+ تم طرح هذا السؤال عدة مرات من قبل المجتمع ، لذا من المهم توضيح هذا الأمر. الحقيقة هي أن * three.js * لا تعرف عمر أو نطاق الكيانات التي أنشأها المستخدم مثل الأشكال الهندسية أو المواد. هذه هي مسؤولية التطبيق. على سبيل المثال ، حتى إذا لم يتم استخدام مادة حاليًا للعرض ، فقد تكون ضرورية للإطار التالي. لذلك إذا قرر التطبيق أنه يمكن حذف كائن معين ، فيجب عليه إخبار المحرك عن طريق استدعاء طريقة *dispose()* المعنية.
+ </p>
+
+ <h3>هل تؤدي إزالة الشبكة من المشهد إلى التخلص من هندستها ومادتها أيضًا؟</h3>
+
+ <p>
+ لا ، يجب عليك التخلص صراحة من الهندسة والمواد عبر *dispose()*. ضع في اعتبارك أنه يمكن مشاركة الأشكال الهندسية والمواد بين الكائنات ثلاثية الأبعاد مثل الشبكات.
+ </p>
+
+ <h3>هل توفر * three.js * معلومات حول كمية العناصر المخزنة مؤقتًا؟</h3>
+
+ <p>
+ نعم. من الممكن تقييم [page:WebGLRenderer.info] ، وهي خاصية خاصة للعارض مع سلسلة من المعلومات الإحصائية حول ذاكرة لوحة الرسومات وعملية العرض. من بين أشياء أخرى ، تخبرك أن لديك العديد من القوام والهندسة وبرامج التظليل مخزنة داخليًا. إذا لاحظت وجود مشاكل في الأداء في التطبيق الخاص بك ، فمن الأفضل تصحيح هذه الخاصية من أجل التعرف بسهولة على تسرب الذاكرة.
+ </p>
+
+ <h3>ماذا يحدث عندما تستدعي * dispose () * على نسيج لكن الصورة لم يتم تحميلها بعد؟</h3>
+
+ <p>
+ يتم تخصيص الموارد الداخلية للنسيج فقط إذا تم تحميل الصورة بالكامل. إذا تخلصت من نسيج قبل تحميل الصورة ، فلن يحدث شيء. لم يتم تخصيص أي موارد لذلك ليست هناك حاجة للتنظيف.
+ </p>
+
+ <h3>ماذا يحدث عندما تستدعي * dispose () * ثم أستخدم النموذج المعني في وقت لاحق؟</h3>
+
+ <p>
+ سيتم إنشاء الموارد الداخلية المحذوفة مرة أخرى بواسطة المحرك. لذلك لن يحدث أي خطأ في وقت التشغيل ولكن قد تلاحظ تأثيرًا سلبيًا على الأداء للإطار الحالي ، خاصةً عندما يتعين تجميع برامج shader.
+ </p>
+
+ <h3>كيف يمكنني إدارة كائنات * three.js * في تطبيقي؟ متى أعرف كيف أتخلص من الأشياء؟</h3>
+
+ <p>
+ بشكل عام ، لا توجد توصية محددة لهذا الغرض. يعتمد الأمر بشكل كبير على حالة الاستخدام المحددة عندما يكون الاتصال بالرقم *dispose()* مناسبًا. من المهم إبراز أنه ليس من الضروري دائمًا التخلص من الأشياء طوال الوقت. وخير مثال على ذلك هو اللعبة التي تتكون من مستويات متعددة. مكان جيد للتخلص من الأشياء عند تبديل المستوى. يمكن للتطبيق اجتياز المشهد القديم والتخلص من جميع المواد والأشكال الهندسية والقوام المتقادمة. كما هو مذكور في القسم السابق ، لا ينتج عنه خطأ في وقت التشغيل إذا تخلصت من كائن لا يزال قيد الاستخدام بالفعل. أسوأ شيء يمكن أن يحدث هو انخفاض الأداء لإطار واحد.
+ </p>
+
+ <h2>أمثلة توضح استخدام dispose()</h2>
+
+ <p>
+ [example:webgl_test_memory WebGL / test / memory]<br />
+ [example:webgl_test_memory2 WebGL / test / memory2]<br />
+ إذا كنت تستخدم الأشكال الهندسية الإجرائية فقط ولا تقوم بتحميل أي مواد ، فيجب أن تعمل صفحات الويب مباشرة من نظام الملفات ، فقط انقر نقرًا مزدوجًا فوق ملف HTML في مدير الملفات
+ يجب أن يعرض محتوى الصفحة في المتصفح (سترى <em>file:///yourFile.html</em> في شريط العناوين).
+ </p>
+
+ <h2>المحتوى الذي تم تحميله من ملفات خارجية</h2>
+ <div>
+ <p>
+ إذا قمت بتحميل نماذج وأنسجة من ملفات خارجية ، نظرًا لقيود أمان المتصفحات [link:http://en.wikipedia.org/wiki/Same_origin_policy same origin policy] ، فسيفشل التحميل من نظام الملفات مع استثناء أمان.
+ </p>
+
+ <p>هناك طريقتان لحل هذا:</p>
+
+ <ol>
+ <li>
+ قم بتغيير أمان الملفات المحلية في المستعرض. يتيح لك ذلك الوصول إلى صفحتك على النحو التالي: <code>file:///yourFile.html</code>
+ </li>
+ <li>
+ قم بتشغيل الملفات من خادم ويب محلي. يتيح لك هذا الوصول إلى صفحتك على النحو التالي: <code>http://localhost/yourFile.html</code>
+ </li>
+ </ol>
+
+ <p>
+ إذا كنت تستخدم الخيار 1 ، فاعلم أنك قد تفتح نفسك لبعض نقاط الضعف إذا كنت تستخدم نفس المتصفح لتصفح الويب. قد ترغب في إنشاء ملف تعريف / اختصار متصفح منفصل يستخدم فقط للتطور لتكون في مأمن. دعنا نمر إلى كل خيار على حدة.
+ </p>
+ </div>
+
+
+ <h2>قم بتشغيل خادم محلي</h2>
+ <div>
+ <p>
+ تحتوي العديد من لغات البرمجة على خوادم HTTP بسيطة مضمنة فيها. فهي ليست كاملة الميزات مثل خوادم الإنتاج مثل [link:https://www.apache.org/ Apache] أو [link:https://nginx.org NGINX] ، ولكن يجب أن تكون كافية لاختبار تطبيق three.js الخاص بك.
+ </p>
+
+ <h3>إضافات لمحررات الأكواد الأكثر إستعمالا</h3>
+ <div>
+ <p>تحتوي بعض برامج تحرير الأكواد على مكونات إضافية والتي ستنتج خادمًا بسيطًا عند الطلب.</p>
+ <ul>
+ <li>[link:https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer Live Server] لـ Visual Studio Code.</li>
+ <li>[link:https://atom.io/packages/atom-live-server Live Server] لـ Atom.</li>
+ </ul>
+ </div>
+
+ <h3>Servez</h3>
+ <div>
+ <p>
+ [link:https://greggman.github.io/servez Servez] هو خادم بسيط مع واجهة المستخدم.
+ </p>
+ </div>
+
+ <h3>Node.js http-server</h3>
+ <div>
+ <p>يحتوي Node.js على حزمة خادم HTTP بسيطة. لتثبيت:</p>
+ <code>npm install http-server -g</code>
+
+ <p>للتشغيل (من دليلك المحلي):</p>
+ <code>http-server . -p 8000</code>
+ </div>
+
+ <h3>خادم Python</h3>
+ <div>
+ <p>
+ إذا كان لديك [link:http://python.org/ Python] مثبتًا ، فيجب أن يكون كافيًا لتشغيل هذا من سطر أوامر (من دليل العمل الخاص بك):
+ </p>
+ <code>
+//Python 2.x
+python -m SimpleHTTPServer
+
+//Python 3.x
+python -m http.server
+ </code>
+
+ <p>سيخدم هذا الملفات من الدليل الحالي في المضيف المحلي تحت المنفذ 8000 ، كمثال في شريط العنوان اكتب:</p>
+
+ <code>http://localhost:8000/</code>
+ </div>
+
+ <h3>خادم Ruby</h3>
+ <div>
+ <p>إذا قمت بتثبيت Ruby ، فيمكنك الحصول على نفس النتيجة بتشغيل هذا بدلاً من ذلك:</p>
+ <p>تحتوي PHP أيضًا على خادم ويب مدمج ، بدءًا من php 5.4.0:</p>
+ <code>php -S localhost:8000</code>
+ </div>
+
+ <h3>Lighttpd</h3>
+ <div>
+ <p>
+ Lighttpd هو خادم ويب خفيف الوزن للغاية للأغراض العامة. سنغطي تثبيته على OSX مع HomeBrew هنا. على عكس الخوادم الأخرى التي تمت مناقشتها هنا ، فإن lighttpd هو خادم جاهز للإنتاج الكامل.
+ </p>
+
+ <ol>
+ <li>
+ تثبيته بواسطة homebrew
+ <code>brew install lighttpd</code>
+ </li>
+ <li>
+ قم بإنشاء ملف ترتيب (configuration) يسمى lighttpd.conf في المجلد حيث تريد تشغيل خادم الويب الخاص بك. يوجد نموذج [link:http://redmine.lighttpd.net/projects/lighttpd/wiki/TutorialConfiguration here].
+ </li>
+ <li>
+ في ملف conf ، قم بتغيير server.document-root إلى الدليل الذي تريد خدمة الملفات منه.
+ </li>
+ <li>
+ شغله من خلال الأمر التالي:
+ <code>lighttpd -f lighttpd.conf</code>
+ </li>
+ <li>
+ انتقل إلى http://localhost:3000 وسيخدم الملفات الثابتة من الدليل الذي تختاره.
+ </li>
+ </ol>
+ </div>
+ <h3>IIS</h3>
+ <div>
+ <p>إذا كنت تستخدم Microsoft IIS كخادم ويب. الرجاء إضافة إعدادات نوع MIME فيما يتعلق بامتداد .fbx قبل التحميل.</p>
+ <code>File name extension: fbx MIME Type: text/plain</code>
+ <p>بشكل تلقائي ، يقوم IIS بحظر تنزيل ملفات .fbx و .obj. يجب عليك تعديل IIS لتمكين تنزيل هذا النوع من الملفات.</p>
+ </div>
+ <p>
+ تمت مناقشة البدائل البسيطة الأخرى هنا [link:http://stackoverflow.com/q/12905426/24874 here] على Stack Overflow.
+ هذا يجعلها بشكل عام أسرع من الهندسة الأساسية (standard geometry) ، بحساب تكلفة العمل بها إلى حد ما.
+ </p>
+ <p>
+ فيما يتعلق بتحديث BufferGeometries ، فإن أهم شيء يجب فهمه هو أنه لا يمكنك تغيير حجم المخازن المؤقتة (هذا مكلف للغاية ، ويعادل بشكل أساسي إنشاء هندسة جديدة). ومع ذلك يمكنك تحديث محتوى المخازن المؤقتة.
+ </p>
+ <p>
+ هذا يعني أنك إذا كنت تعرف أن إحدى سمات BufferGeometry ستنمو ، لنقل عدد الرؤوس ، فيجب عليك تخصيص مخزن مؤقت كبير بما يكفي لاحتواء أي رؤوس جديدة قد يتم إنشاؤها. بالطبع ، هذا يعني أيضًا أنه سيكون هناك حد أقصى لحجم BufferGeometry - لا توجد طريقة لإنشاء BufferGeometry يمكن تمديده حجم غير محدود.
+ </p>
+ <p>
+ سنستخدم مثال السطر الذي سيتم تمديده في وقت العرض. سنخصص مساحة في المخزن المؤقت لـ 500 رأس لكننا نرسم اثنين فقط في البداية ، باستخدام [page:BufferGeometry.drawRange].
+ </p>
+ <code>
+var MAX_POINTS = 500;
+
+// geometry
+var geometry = new THREE.BufferGeometry();
+
+// attributes
+var positions = new Float32Array( MAX_POINTS * 3 ); // 3 vertices per point
+geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
+
+// draw range
+var drawCount = 2; // draw the first 2 points, only
+geometry.setDrawRange( 0, drawCount );
+
+// material
+var material = new THREE.LineBasicMaterial( { color: 0xff0000 } );
+
+// line
+var line = new THREE.Line( geometry, material );
+scene.add( line );
+ </code>
+ <p>
+ بعد ذلك سنضيف نقاطًا بشكل عشوائي إلى الخط باستخدام نمط مثل:
+ تتحكم العلامات التالية في تحديث سمات الهندسة المختلفة. قم بتعيين العلامات فقط للسمات التي تحتاج إلى تحديثها ، فالتحديثات مكلفة. بمجرد تغيير المخازن المؤقتة ، يتم إعادة تعيين هذه العلامات تلقائيًا إلى false. تحتاج إلى الاستمرار في ضبطها على true إذا كنت تريد الاستمرار في تحديث المخازن المؤقتة. لاحظ أن هذا ينطبق فقط على [page:Geometry] وليس [page:BufferGeometry].
+ </p>
+ <code>
+var geometry = new THREE.Geometry();
+geometry.verticesNeedUpdate = true;
+geometry.elementsNeedUpdate = true;
+geometry.morphTargetsNeedUpdate = true;
+geometry.uvsNeedUpdate = true;
+geometry.normalsNeedUpdate = true;
+geometry.colorsNeedUpdate = true;
+geometry.tangentsNeedUpdate = true;
+ </code>
+
+ <p>
+ في الإصدارات السابقة لـ [link:https://github.com/mrdoob/three.js/releases/tag/r66 r66] ، تحتاج الشبكات أيضًا إلى تمكين العلامة <em>الديناميكية</em> (للاحتفاظ بالمصفوفات المكتوبة داخليًا):
+ </p>
+
+ <code>
+ //removed after r66
+ geometry.dynamic = true;
+ </code>
+
+ </div>
+
+ <h2>المواد (Materials)</h2>
+ <div>
+ <p>يمكن تغيير جميع قيم الزي الرسمي بحرية (على سبيل المثال ، الألوان ، والأنسجة ، والعتامة ، وما إلى ذلك) ، ويتم إرسال القيم إلى الشادر (shader) في كل إطار.</p>
+
+ <p>يمكن أيضًا تغيير المعلمات ذات الصلة بـ GLstate في أي وقت (depthTest, blending, polygonOffset, etc).</p>
+
+ <p>لا يمكن تغيير الخصائص التالية بسهولة في وقت التشغيل (بمجرد تقديم المادة مرة واحدة على الأقل):</p>
+ <ul>
+ <li>numbers and types of uniforms</li>
+ <li>presence or not of
+ <ul>
+ <li>texture</li>
+ <li>fog</li>
+ <li>vertex colors</li>
+ <li>skinning</li>
+ <li>morphing</li>
+ <li>shadow map</li>
+ <li>alpha test</li>
+ </ul>
+ </li>
+ </ul>
+
+ <p>تتطلب التغييرات في هذه بناء برنامج شادر (shader) جديد. سوف تحتاج إلى ضبط</p>
+ <code>material.needsUpdate = true</code>
+
+ <p>ضع في اعتبارك أن هذا قد يكون بطيئًا للغاية ويؤدي إلى اهتزاز في معدل الإطارات (خاصة على Windows ، حيث أن التحويل البرمجي للشادر (shader) يكون أبطأ في DirectX منه في OpenGL).</p>
+
+ <p>للحصول على تجربة أكثر سلاسة ، يمكنك محاكاة التغييرات في هذه الميزات إلى حد ما من خلال الحصول على قيم "وهمية" مثل الأضواء صفر الكثافة أو الزخارف البيضاء أو الضباب الصفري.</p>
+
+ <p>يمكنك تغيير المواد المستخدمة في القطع الهندسية بحرية ، ولكن لا يمكنك تغيير كيفية تقسيم الكائن إلى أجزاء (وفقًا لمواد الوجه). </p>
+
+ <h3>إذا كنت بحاجة إلى تكوينات مختلفة من المواد أثناء وقت التشغيل:</h3>
+ <p>إذا كان عدد المواد / القطع الصغيرًة ، فيمكنك تقسيم الجسم مسبقًا (مثل الشعر / الوجه / الجسم / الملابس العلوية / السراويل للإنسان ، أمامي / جوانب / الجزء العلوي / الزجاج / الإطار / الجزء الداخلي للسيارة). </p>
+
+ <p>إذا كان الرقم كبيرًا (على سبيل المثال ، من المحتمل أن يكون كل وجه مختلفًا) ، ففكر في حل مختلف ، مثل استخدام السمات / القوام للحصول على مظهر مختلف لكل وجه.</p>
+ <h1>كيفية استخدام المعالجة اللاحقة<br/> (post-processing)</h1>
+
+ <p>
+ تعرض العديد من تطبيقات three.js كائناتها ثلاثية الأبعاد مباشرة على الشاشة. ومع ذلك ، في بعض الأحيان ، تريد تطبيق واحد أو أكثر من التأثيرات الرسومية مثل Depth-Of-Field أو Bloom أو Film Grain أو أنواع مختلفة من Anti-aliasing. المعالجة اللاحقة هي طريقة مستخدمة على نطاق واسع لتنفيذ مثل هذه التأثيرات. أولاً ، يتم تحويل المشهد إلى هدف عرض يمثل مخزنًا مؤقتًا في ذاكرة بطاقة الفيديو.
+ في الخطوة التالية ، تقوم واحدة أو أكثر من ممرات ما بعد المعالجة بتطبيق المرشحات والتأثيرات على المخزن المؤقت للصور قبل أن يتم عرضه في النهاية على الشاشة.
+ </p>
+ <p>
+ توفر three.js حلاً كاملاً لعملية المعالجة بتوفير [page:EffectComposer] الذي يتولى تنفيذ مثل هذه الأعمال.
+ </p>
+
+ <h2>سير العمل</h2>
+
+ <p>
+ الخطوة الأولى في العملية هي استيراد جميع الملفات الضرورية من دليل الأمثلة. يفترض الدليل أنك تستخدم الرقم الرسمي [link:https://www.npmjs.com/package/three npm package] من three.js. في العرض التوضيحي الأساسي في هذا الدليل ، نحتاج إلى الملفات التالية.
+ </p>
+
+ <code>
+ import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
+ import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
+ import { GlitchPass } from 'three/examples/jsm/postprocessing/GlitchPass.js';
+ </code>
+
+ <p>
+ بعد أن يتم استرداد جميع الملفات بنجاح ، يمكنك إنشاء الملحن الخاص بنا بتمرير نموذج من [page:WebGLRenderer].
+ </p>
+
+ <code>
+ var composer = new EffectComposer( renderer );
+ </code>
+
+ <p>
+ عند استخدام الملحن ، من الضروري تغيير حلقة الرسوم المتحركة للتطبيق. بدلاً من استدعاء طريقة العرض [page:WebGLRenderer] ، نستخدم الآن النظير الخاص بها [page:EffectComposer].
+ </p>
+
+ <code>
+ function animate() {
+
+ requestAnimationFrame( animate );
+
+ composer.render();
+
+ }
+ </code>
+
+ <p>
+ أصبح الملحن جاهزًا الآن ، لذا من الممكن تكوين سلسلة ممرات ما بعد المعالجة. هذه التمريرات مسؤولة عن إنشاء الإخراج المرئي النهائي للتطبيق. تتم معالجتها بترتيب الإضافة / الإدراج. في مثالنا ، تم تنفيذ *RenderPass* أولاً ثم *GlitchPass*. يتم عرض آخر تمرير تم تمكينه في السلسلة تلقائيًا على الشاشة. يبدو إعداد التصاريح كما يلي:
+ </p>
+
+ <code>
+ var renderPass = new RenderPass( scene, camera );
+ composer.addPass( renderPass );
+
+ var glitchPass = new GlitchPass();
+ composer.addPass( glitchPass );
+ </code>
+
+ <p>
+ يتم وضع *RenderPass* بشكل طبيعي في بداية السلسلة من أجل توفير المشهد الذي تم عرضه كمدخل لخطوة ما بعد المعالجة التالية. في حالتنا ، ستستخدم *GlitchPass* بيانات الصورة هذه لتطبيق تأثير خلل جامح. تحقق من هذا [link:https://threejs.org/examples/webgl_postprocessing_glitch live example] لتراها في العمل.
+ </p>
+
+ <h2>تصاريح مدمجة</h2>
+
+ <p>
+ يمكنك استخدام مجموعة واسعة من تصاريح ما بعد المعالجة التي يوفرها المحرك. يتم الاحتفاظ بها في الدليل [link:https://github.com/mrdoob/three.js/tree/dev/examples/jsm/postprocessing postprocessing].
+ </p>
+
+ <h2>تصاريح مخصصة</h2>
+
+ <p>
+ في بعض الأحيان تريد كتابة تظليل مخصص للمعالجة اللاحقة وإدراجه في سلسلة ممرات ما بعد المعالجة. في هذا السيناريو ، يمكنك استخدام *ShaderPass*. بعد استيراد الملف والتظليل المخصص الخاص بك ، يمكنك استخدام الكود التالي لإعداد المرور.
+ </p>
+
+ <code>
+ import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
+ import { LuminosityShader } from 'three/examples/jsm/shaders/LuminosityShader.js';
+
+ // later in your init routine
+
+ var luminosityPass = new ShaderPass( LuminosityShader );
+ composer.addPass( luminosityPass );
+ </code>
+
+ <p>
+ يوفر المستودع ملفًا يسمى [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/shaders/CopyShader.js CopyShader] وهو رمز بداية جيد للتظليل المخصص الخاص بك. *CopyShader* فقط ينسخ محتويات الصورة من مخزن قراءة [page:EffectComposer] إلى مخزن الكتابة المؤقت الخاص به دون تطبيق أي تأثيرات.
+ قم بزيارة [link:https://eloquentjavascript.net/20_node.html#h_J6hW/SmL/a Eloquent JavaScript: Installing with npm].
+ </p>
+
+ <h2>التثبيت من CDN أو استضافة ثابتة</h2>
+
+ <p>
+ يمكن إستعمال مكتبة three.js دون الحاجة إلى نظام بناء، سواءا عبر تحميل الملفات إلى خادم الويب الخاص بك أو باستخدام CDN موجود. بسبب أن المكتبة تعتمد على وحدات ES (modules) يجب على أي شفرة برمجية تشير إليها أن تستخدام <em>type="module"</em> كما هو موضح أسفله:
+ </p>
+
+ <code>
+ <script type="module">
+
+ // Find the latest version by visiting https://unpkg.com/three. The URL will
+ // redirect to the newest stable release.
+ import * as THREE from 'https://unpkg.com/three@<VERSION>/build/three.module.js';
+
+ const scene = new THREE.Scene();
+
+ </script>
+ </code>
+
+ <p>
+ ليست كل المزايا يمكن الوصول لها عبر وحدة <em>build/three.module.js</em>. بعض المكونات الأخرى من المكتبة - مثل الضوابط (controls) وعناصر التحميل (loaders) وتأثيرات ما بعد المعالجة (post-processing effects) - يجب إستدعائهم من الملفات الثانوية [link:https://github.com/mrdoob/three.js/tree/dev/examples/jsm examples/jsm].
+ </p>
+
+
+ <h2>أمثلة</h2>
+
+ <p>
+ يركز جوهر three.js على أهم المكونات المكونة لمحرك ثلاثي الأبعاد. العديد من المكونات المفيدة الأخرى - مثل الضوابط ، عناصر التحميل ، وتأثيرات ما بعد المعالجة - هي جزء من المجلد [link:https://github.com/mrdoob/three.js/tree/dev/examples/jsm examples/jsm]. .يشار إليها باسم "أمثلة" ، لأنه بينما يمكنك استخدامها ببساطة، من المفترض أيضًا إعادة دمجها وتخصيصها. هذه المكونات تضل متزامنة مع المكتبة الأساسية
+ بينما يتم الاحتفاظ بحزم الجهات الخارجية المماثلة على npm بواسطة أشخاص مختلفين وقد لا تكون محدثة.
+ </p>
+
+ <p>
+ لا يلزم تثبيت الأمثلة بشكل منفصل ، ولكن يجب استيرادها بشكل منفصل. إذا تم تثبيت three.js بواسطة npm ، يمكنك إستدعاء مكون OrbitControls كالأتي:
+ </p>
+
+ <code>
+ import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
+
+ const controls = new OrbitControls();
+ </code>
+
+ <p>
+ إذا تم تثبيت three.js من CDN ، فمن المستحسن إستخدم نفس CDN لتثبيت المكونات الأخرى:
+ </p>
+
+ <code>
+ <script type="module">
+
+ // Find the latest version by visiting https://unpkg.com/three. The URL will
+ // redirect to the newest stable release.
+ import { OrbitControls } from 'https://unpkg.com/three@<VERSION>/examples/jsm/controls/OrbitControls.js';
+
+ const controls = new OrbitControls();
+
+ </script>
+ </code>
+
+ <p>
+ من المهم أن تستخدم جميع الملفات نفس الإصدار. لا تستورد أمثلة مختلفة من إصدارات مختلفة، أو تستخدم أمثلة من إصدارات مختلفة عن مكتبة three.js نفسها.
+ </p>
+
+ <h2>التوافق</h2>
+
+ <h3>واردات CommonJS</h3>
+
+ <p>
+ في حين أن معظم حِزم JavaScript الحديثة تدعم الآن وحدات ES افتراضيًا ، فقد لا تدعم بعض أدوات البناء القديمة.
+ في مثل هذه الحالات بإستطاعتك تعديل المجمع لفهم وحدات ES: <br/>
+ [link:http://browserify.org/ Browserify] يحتاج فقط إلى إضافة [link:https://github.com/babel/babelify babelify] على سبيل المثال.
+ </p>
+
+ <h3>خرائط الإستيراد</h3>
+
+ <p>
+ تختلف المسارات المستوردة عند التثبيت من npm ، مقارنة بالتثبيت من استضافة ثابتة أو CDN. نحن ندرك أن هذه مشكلة مريحة لكلا مجموعتي المستخدمين.
+ يفضل المطورون الذين لديهم أدوات إنشاء وحزم محددات الحزم المجردة (على سبيل المثال "three") بدلاً من المسارات النسبية ، وتستخدم الملفات في المجلد <em>examples/</em> مراجع نسبية إلى <em> three.module.js </em > التي لا تتبع هذا التوقع.
+ أولئك الذين لا يستخدمون أدوات الإنشاء - للنماذج الأولية السريعة أو التعلم أو التفضيل الشخصي - قد يكرهون بالمثل تلك الواردات النسبية ، والتي تتطلب هياكل مجلدات معينة وتكون أقل تسامحًا من مساحة الاسم <em> THREE. * </em> العام.
+ </p>
+
+ <p>
+ نأمل في إزالة هذه المسارات النسبية عندما يصبح [link:https://github.com/WICG/import-maps import maps] متاحًا على نطاق واسع ، واستبدالها بمحددات الحزمة المجردة إلى اسم الحزمة npm ، 'three'. يتطابق هذا مع توقعات أداة الإنشاء لحزم npm بشكل وثيق ، ويسمح لمجموعتي المستخدمين بكتابة نفس الرمز تمامًا عند استيراد ملف. بالنسبة للمستخدمين الذين يفضلون تجنب أدوات الإنشاء ، يمكن أن يوجه تعيين JSON البسيط جميع الواردات إلى CDN أو مجلد ملف ثابت. من الناحية التجريبية ، يمكنك محاولة استخدام عمليات استيراد أبسط اليوم مع تعبئة خريطة الاستيراد ، كما هو موضح في [link:https://glitch.com/edit/#!/three-import-map?path=index.html import map example].
+ </p>
+
+ <h3>Node.js</h3>
+
+ <p>
+ قد يكون استخدام three.js في Node.js أمرًا صعبًا ، وذلك لسببين:
+ </p>
+
+ <p>
+ أولاً ، نظرًا لأن three.js مصممة للويب ، فإنها تعتمد على المتصفح وواجهات برمجة تطبيقات DOM التي لا تتواجد دائمًا في Node.js. يمكن حل بعض هذه المشكلات باستخدام (shims) مثل [link:https://github.com/stackgl/headless-gl headless-gl]، أو عن طريق استبدال مكونات مثل [page: TextureLoader] ببدائل مخصصة. قد تتشابك واجهات برمجة تطبيقات DOM الأخرى بعمق مع الكود الذي يستخدمها ، وسيكون من الصعب حلها. نرحب بطلبات السحب البسيطة والقابلة للصيانة لتحسين دعم Node.js ، لكننا نوصي بفتح مشكلة لمناقشة التحسينات التي أجريتها أولاً.
+ </p>
+
+ <p>
+ ثانيًا ، دعم Node.js لوحدات ES ... معقد. بدءًا من الإصدار 12 من Node.js ، يمكن استيراد المكتبة الأساسية كوحدة نمطية CommonJS ، مع <em>require('three')</em>. ومع ذلك ، فإن معظم أمثلة المكونات في <em>examples/jsm</em> لا يمكنها ذلك.
+ قد تحل الإصدارات المستقبلية من Node.js هذه المشكلة ، ولكن في هذه الأثناء قد تحتاج إلى استخدام حلول بديلة مثل [link:https://github.com/standard-things/esm esm] لتمكين تطبيق Node.js الخاص بك من التعرف على وحدات ES.
+ مكتبة three.js توفر العديد من عناصر التحميل</a>، فإن اختيار التنسيق المناسب وسير العمل سيوفر الوقت والإحباط لاحقًا. يصعب العمل مع بعض التنسيقات ، أو أنها غير فعالة في تجارب الوقت الفعلي ، أو ببساطة غير مدعومة بالكامل في هذا الوقت.
+ </p>
+
+ <p>
+ يوفر هذا الدليل سير عمل موصى به لمعظم المستخدمين ، واقتراحات لما يجب تجربته إذا لم تسير الأمور كما هو متوقع.
+ </p>
+
+ <h2>قبل أن نبدأ</h2>
+
+ <p>
+ إذا كنت جديدًا في تشغيل خادم محلي ، فابدأ بكيفية إدارة الأشياء محليًا [link:#manual/introduction/How-to-run-things-locally how to run things locally] أولاً. يمكن تجنب العديد من الأخطاء الشائعة أثناء عرض النماذج ثلاثية الأبعاد عن طريق استضافة الملفات بشكل صحيح.
+ </p>
+
+ <h2>سير العمل الموصى به</h2>
+
+ <p>
+ حيثما أمكن ، نوصي باستخدام glTF (تنسيق نقل GL). كلا النسختين <small> .GLB </small> و <small> .GLTF </small> من التنسيق مدعومة بشكل جيد. نظرًا لأن glTF يركز على تسليم أصول وقت التشغيل ، فهو مضغوط للإرسال وسريع التحميل. تتضمن الميزات الشبكات والمواد والأنسجة والجلود والهياكل العظمية والأهداف المتحولة والرسوم المتحركة والأضواء والكاميرات.
+ عندما لا يكون glTF خيارًا ، تتوفر أيضًا التنسيقات الشائعة مثل FBX أو OBJ أو COLLADA ويتم صيانتها بانتظام.
+ </p>
+
+ <h2>التحميل</h2>
+
+ <p>
+ يتم تضمين عدد قليل فقط من عناصر التحميل (على سبيل المثال [page:ObjectLoader]) بشكل ألي مع
+ three.js - يجب عليك إضافة الآخرين إلى تطبيقك بشكل فردي.
+ </p>
+
+ <code>
+ import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
+ </code>
+
+ <p>
+ بمجرد قيامك باستيراد عنصر التحميل ، فأنت جاهز لإضافة نموذج إلى المشهد الخاص بك. يختلف بناء الجملة باختلاف عناصر التحميل - عند استخدام تنسيق آخر ، تحقق من الأمثلة والوثائق الخاصة بهذا المُحمل. بالنسبة إلى glTF ، سيكون الاستخدام مع البرامج النصية العامة:
+ </p>
+
+ <code>
+ var loader = new GLTFLoader();
+
+ loader.load( 'path/to/model.glb', function ( gltf ) {
+
+ scene.add( gltf.scene );
+
+ }, undefined, function ( error ) {
+
+ console.error( error );
+
+ } );
+ </code>
+
+ <p>
+ انظر [page:GLTFLoader GLTFLoader documentation] لمزيد من التفاصيل.
+ </p>
+
+ <h2>إستكشاف الأخطاء وإصلاحها</h2>
+
+ <p>
+ إن كنت قد أمضيت ساعات في تصميم تحفة فنية ، وقمت بتحميلها في صفحة الويب ، و- لا! 😭 إنه مشوه أو مفقود تمامًا. ابدأ بالخطوات التالية لاستكشاف الأخطاء وإصلاحها:
+ </p>
+
+ <ol>
+ <li>
+ تحقق من وحدة تحكم جافا سكريبت بحثًا عن أخطاء ، وتأكد من استخدام رد اتصال <em> onError </em> عند استدعاء <em> .load () </em> لتسجيل النتيجة.
+ </li>
+ <li>
+ اعرض النموذج في تطبيق آخر. بالنسبة إلى glTF ، تتوفر عارضات السحب والإفلات لـ
+ <a href="https://gltf-viewer.donmccurdy.com/" target="_blank" rel="noopener">three.js</a> و
+ <a href="http://sandbox.babylonjs.com/" target="_blank" rel="noopener">babylon.js</a>. إذا ظهر النموذج بشكل صحيح في تطبيق واحد أو أكثر ،
+ <a href="https://github.com/mrdoob/three.js/issues/new" target="_blank" rel="noopener">إرفع إعلان وجود خطأ ضد المكتبة</a>.
+ إذا تعذر عرض النموذج في أي تطبيق ، فإننا نشجع بشدة على تسجيل خطأ في التطبيق المستخدم لإنشاء النموذج.
+ </li>
+ <li>
+ حاول تكبير النموذج لأعلى أو لأسفل بعامل 1000. يتم قياس العديد من الأمثلة بشكل مختلف ، وقد لا تظهر الأمثلة الكبيرة إذا كانت الكاميرا داخل النموذج.
+ </li>
+ <li>
+ حاول إضافة مصدر ضوء وتحديد موضعه. قد يكون النموذج مخفيًا في الظلام.
+ </li>
+ <li>
+ ابحث عن طلبات النسيج الفاشلة في علامة تبويب الشبكة ، مثل <em>C:\\Path\To\Model\texture.jpg</em>. استخدم المسارات المتعلقة بنموذجك بدلاً من ذلك ، مثل <em> images/texture.jpg</em> - قد يتطلب ذلك تعديل ملف النموذج في محرر نصي.
+ </li>
+ </ol>
+
+ <h2>طلب المساعدة</h2>
+
+ <p>
+ إذا مررت بعملية استكشاف الأخطاء وإصلاحها أعلاه ولا يزال نموذجك لا يعمل ، فإن الطريقة الصحيحة لطلب المساعدة ستوصلك إلى حل بشكل أسرع. انشر سؤالاً على منتدى المكتبة
+ <a href="https://discourse.threejs.org/" target="_blank" rel="noopener">three.js forum</a> وحيثما أمكن ، قم بتضمين النموذج الخاص بك (أو نموذج أبسط بنفس المشكلة) بأي تنسيقات متوفرة لديك. قم بتضمين معلومات كافية لشخص آخر لإعادة إنتاج المشكلة بسرعة - من الناحية المثالية ، عرض توضيحي مباشر.
+ يستخدم *Three.js* المصفوفات لتشفير عمليات التحويل ثلاثية الأبعاد --- الترجمات (الموضع) والتدوير والقياس. يحتوي كل مثيل [page:Object3D] على [page:Object3D.matrix matrix] يخزن موضع هذا الكائن وتدويره ومقياسه. تصف هذه الصفحة كيفية تحديث تحول الكائن.
+ </p>
+
+ <h2>خصائص الراحة و *matrixAutoUpdate*</h2>
+
+ <p>
+ هناك طريقتان لتحديث تحول الكائن(object):
+ </p>
+ <ol>
+ <li>
+ عدّل خصائص *position* و *quaternion* و *scale* الخاصة بالكائن ، واسمح لـ three.js بإعادة حساب مصفوفة الكائن من هذه الخصائص:
+ <code>
+object.position.copy( start_position );
+object.quaternion.copy( quaternion );
+ </code>
+ بشكل افتراضي ، يتم تعيين الخاصية *matrixAutoUpdate* على "true" ، وستتم إعادة حساب المصفوفة تلقائيًا. إذا كان الكائن ثابتًا ، أو كنت ترغب في التحكم يدويًا عند حدوث إعادة الحساب ، فيمكن الحصول على أداء أفضل من خلال تعيين الخاصية false:
+ <code>
+object.matrixAutoUpdate = false;
+ </code>
+ وبعد تغيير أي خصائص ، قم بتحديث المصفوفة يدويًا:
+ <code>
+object.updateMatrix();
+ </code>
+ </li>
+ <li>
+ قم بتعديل مصفوفة الكائن مباشرة. تحتوي فئة [page:Matrix4] على طرق مختلفة لتعديل المصفوفة:
+ لاحظ أنه <em>يجب</em> ضبط *matrixAutoUpdate* على *false* في هذه الحالة ، ويجب عليك التأكد من <em>عدم</em> استدعاء *updateMatrix*. سيؤدي استدعاء *updateMatrix* إلى إعاقة التغييرات اليدوية التي تم إجراؤها على المصفوفة ، وإعادة حساب المصفوفة من *position* ، *scale* ، وما إلى ذلك.
+ </li>
+ </ol>
+
+ <h2>مصفوفات وعالم الكائن</h2>
+ <p>
+ يخزن [page:Object3D.matrix matrix] كائن تحويل الكائن <em>بالنسبة</em> إلى [page:Object3D.parent parent] الكائن ؛ للحصول على تحول الكائن في إحداثيات <em>العالم</em> ، يجب عليك الوصول إلى [page:Object3D.matrixWorld] الكائن.
+ </p>
+ <p>
+ عندما تتغير حالة الكائن الأصل أو الكائن الفرعي ، يمكنك طلب تحديث [page:Object3D.matrixWorld matrixWorld] الكائن الفرعي عن طريق استدعاء [page:Object3D.updateMatrixWorld updateMatrixWorld]().
+ </p>
+
+ <h2>الدوران و Quaternion</h2>
+ <p>
+ يوفر Three.js طريقتين لتمثيل التدوير ثلاثي الأبعاد: [page:Euler Euler angles] و [page:Quaternion Quaternions] ، بالإضافة إلى طرق التحويل بين الاثنين. تخضع زوايا أويلر لمشكلة تسمى "gimballock" ، حيث يمكن أن تفقد بعض التكوينات درجة من الحرية (تمنع تدوير الكائن حول محور واحد). لهذا السبب ، يتم تخزين استدارة الكائن <em>دائمًا</em> في [page:Object3D.quaternion quaternion].
+ </p>
+ <p>
+ تضمنت الإصدارات السابقة من المكتبة خاصية *useQuaternion* والتي ، عند ضبطها على false ، ستؤدي إلى حساب [page:Object3D.matrix matrix] للكائن من زاوية أويلر. تم إيقاف هذه الممارسة - بدلاً من ذلك ، يجب عليك استخدام طريقة [page:Object3D.setRotationFromEuler setRotationFromEuler] ، والتي ستعمل على تحديث الرباعية.
+ three.js هي مكتبة قائمة على JavaScript. ومع ذلك ، من الممكن استخدامه في مشروع TypeScript ، حيث تعرض المكتبة [link:https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html Declaration Files] ملفات التصريح (ملفات * d.ts *).
+ </p>
+
+ <p>
+ الحد الأدنى من التكوين المطلوب لكي يتمكن برنامج التحويل البرمجي TypeScript من
+ اكتشف أنواع three.js.
+ <br>
+ ستحتاج إلى ضبط الخيار [link:https://www.typescriptlang.org/docs/handbook/module-resolution.html moduleResolution] على *node* ، وخيار [link:https://www.typescriptlang.org/docs/handbook/compiler-options.html target] على *es6* أو ما هو أحدث.
+ </p>
+
+ <code>
+ // Example of minimal `tsconfig.json` file
+ {
+ "compilerOptions": {
+ "target": "es6",
+ "moduleResolution": "node",
+ },
+ "include": [ "./src/**/*.ts" ],
+ }
+ </code>
+
+ <p>
+ ملاحظة: اعتبارًا من اليوم ، ليس من الممكن استخدام كتابة three.js بدون استخدام هذين الخيارين.
+ </p>
+
+ <p>
+ ملاحظة: يحدث أن بعض التصريحات غير صحيحة و / أو مفقودة. تُعد المساهمة في ملفات التصريح مفيدة حقًا للمجتمع ، مما يجعل كتابات three.js أفضل وأكثر دقة.
+ فيما يلي مجموعة من الروابط التي قد تجدها مفيدة عند تعلم three.js.<br />
+ إذا وجدت شيئًا ما ترغب في إضافته هنا ، أو تعتقد أن أحد الروابط أدناه لم يعد مناسبًا أو يعمل ، فلا تتردد في النقر فوق الزر "تحرير" في الجزء السفلي الأيسر وإجراء بعض التغييرات!<br /><br />
+
+ لاحظ أيضًا أنه نظرًا لأن موقع three.js قيد التطوير السريع ، فإن الكثير من هذه الروابط سيحتوي على معلومات قديمة - إذا كان هناك شيء لا يعمل كما تتوقع أو كما يقول أحد هذه الروابط ، تحقق من وحدة تحكم المتصفح للتحذيرات أو الأخطاء. تحقق أيضًا من صفحات المستندات ذات الصلة.
+ </p>
+
+ <h2>منتديات المساعدة</h2>
+ <p>
+ يستخدم Three.js رسميًا [link:https://discourse.threejs.org/ forum] و [link:http://stackoverflow.com/tags/three.js/info Stack Overflow] لطلبات المساعدة. إذا كنت بحاجة إلى مساعدة في شيء ما ، فهذا هو المكان المناسب لك. لا تفتح مشكلة على Github لطلبات المساعدة.
+ [link:https://codepen.io/rachsmith/post/beginning-with-3d-webgl-pt-1-the-scene Beginning with 3D WebGL] بواسطة [link:https://codepen.io/rachsmith/ Rachel Smith].
+ </li>
+ <li>
+ [link:https://www.august.com.au/blog/animating-scenes-with-webgl-three-js/ Animating scenes with WebGL and three.js]
+ [link:http://blog.cjgammon.com/ Collection of tutorials] by [link:http://www.cjgammon.com/ CJ Gammon].
+ </li>
+ <li>
+ [link:https://medium.com/soffritti.pierfrancesco/glossy-spheres-in-three-js-bfd2785d4857 Glossy spheres in three.js].
+ </li>
+ <li>
+ [link:https://www.udacity.com/course/cs291 Interactive 3D Graphics] - دورة مجانية على Udacity تُعلِّم أساسيات الرسومات ثلاثية الأبعاد ، وتستخدم three.js كأداة تشفير لها.
+ </li>
+ <li>
+ [Link:https://aerotwist.com/tutorials/ Aerotwist] tutorials by [link:https://github.com/paullewis/ Paul Lewis].
+ </li>
+ <li>
+ [link:http://learningthreejs.com/ Learning Three.js] – مدونة تحتوي على مقالات مخصصة لتدريس three.js
+ </li>
+ <li>
+ [link:https://discourse.threejs.org/t/three-js-bookshelf/2468 Three.js Bookshelf] - هل تبحث عن مزيد من الموارد حول three.js أو رسومات الكمبيوتر بشكل عام؟ تحقق من اختيار الأدبيات التي أوصى بها مجتمع المكتبة.
+ </li>
+ </ul>
+
+ <h2>الأخبار والتحديثات</h2>
+ <ul>
+ <li>
+ [link:https://twitter.com/hashtag/threejs Three.js on Twitter]
+ </li>
+ <li>
+ [link:http://www.reddit.com/r/threejs/ Three.js on reddit]
+ </li>
+ <li>
+ [link:http://www.reddit.com/r/webgl/ WebGL on reddit]
+ </li>
+ <li>
+ [link:http://learningwebgl.com/blog/ Learning WebGL Blog] – مصدر الأخبار الموثوق لـ WebGL.
+ </li>
+ </ul>
+
+ <h2>أمثلة</h2>
+ <ul>
+ <li>
+ [link:https://github.com/edwinwebb/three-seed/ three-seed] - three.js starter مع ES6 و Webpack
+ </li>
+ <li>
+ [link:http://stemkoski.github.io/Three.js/index.html Professor Stemkoskis Examples] - مجموعة من الأمثلة الصديقة للمبتدئين التي تم إنشاؤها باستخدام three.js r60.
+ </li>
+ <li>
+ [link:https://threejs.org/examples/ Official three.js examples] - يتم الاحتفاظ بهذه الأمثلة كجزء من مستودع three.js ، ودائمًا ما تستخدم أحدث إصدار من three.js.
+ </li>
+ <li>
+ [link:https://raw.githack.com/mrdoob/three.js/dev/examples/ Official three.js dev branch examples] -
+ كما هو مذكور أعلاه ، باستثناء هذه تستخدم فرع dev من three.js ، وتُستخدم للتحقق من أن كل شيء يعمل كما تم تطوير three.js.
+ </li>
+ </ul>
+
+ <h2>أدوات</h2>
+ <ul>
+ <li>
+ [link:http://www.physgl.org/ physgl.org] - واجهة JavaScript الأمامية مع أغلفة لـ three.js ، لجلب رسومات WebGL للطلاب الذين يتعلمون الفيزياء والرياضيات.
+ </li>
+ <li>
+ [link:https://whs.io/ Whitestorm.js] – إطار عمل modular three.js مع البرنامج المساعد AmmoNext للفيزياء.
+ [link:https://www.khronos.org/files/webgl/webgl-reference-card-1_0.pdf webgl-reference-card.pdf] - مراجع لجميع الكلمات الرئيسية والمصطلحات والنحو والتعريفات في WebGL و GLSL.
+ </li>
+ </ul>
+
+ <h2>الروابط القديمة</h2>
+ <p>
+ يتم الاحتفاظ بهذه الروابط لأغراض تاريخية - قد لا تزال تجدها مفيدة ، ولكن حذر من أنها قد تحتوي على معلومات تتعلق بالإصدارات القديمة جدًا من three.js.
+ </p>
+
+ <ul>
+ <li>
+ <a href="https://www.youtube.com/watch?v=Dir4KO9RdhM" target="_blank">AlterQualia at WebGL Camp 3</a>
+ </li>
+ <li>
+ [link:http://yomotsu.github.io/threejs-examples/ Yomotsus Examples] - مجموعة من الأمثلة باستخدام three.js r45.
+ </li>
+ <li>
+ [link:http://fhtr.org/BasicsOfThreeJS/#1 Introduction to Three.js] بواسطة [link:http://github.com/kig/ Ilmari Heikkinen] (slideshow).
+ </li>
+ <li>
+ [link:http://www.slideshare.net/yomotsu/webgl-and-threejs WebGL and Three.js] بواسطة [link:http://github.com/yomotsu Akihiro Oyamada] (slideshow).
+ </li>
+ <li>
+ [link:http://bkcore.com/blog/general/adobe-user-group-nl-talk-video-hexgl.html Fast HTML5 game development using three.js] بواسطة [link:https://github.com/BKcore BKcore] (video).
+ </li>
+ <li>
+ <a href="https://www.youtube.com/watch?v=VdQnOaolrPA" target="_blank">Trigger Rally</a> بواسطة [link:https://github.com/jareiko jareiko] (video).
+ </li>
+ <li>
+ [link:http://blackjk3.github.io/threefab/ ThreeFab] - محرر مشاهد ، تم دعم إصداراته حتى حوالي three.js r50.
+ </li>
+ <li>
+ [link:http://bkcore.com/blog/3d/webgl-three-js-workflow-tips.html Max to Three.js workflow tips and tricks] بواسطة [link:https://github.com/BKcore BKcore]
+ </li>
+ <li>
+ [link:http://12devsofxmas.co.uk/2012/01/webgl-and-three-js/ A whirlwind look at Three.js]
+ بواسطة [link:http://github.com/nrocy Paul King]
+ </li>
+ <li>
+ [link:http://bkcore.com/blog/3d/webgl-three-js-animated-selective-glow.html Animated selective glow in Three.js]
+ بواسطة [link:https://github.com/BKcore BKcore]
+ </li>
+ <li>
+ [link:http://www.natural-science.or.jp/article/20120220155529.php Building A Physics Simulation Environment] - أمثلة تعليمية باللغة اليابانية
-e=[],d=0;d<f.length;d++)f[d]!==a&&(e.push(f[d]),a=f[d]);switch(e.length){case 0:f="end of input";break a;case 1:f=e[0];break a;default:f=e.slice(0,e.length-1).join(", ")+" or "+e[e.length-1]}}a=Math.max(b,ta);a=a<c.length?n(c.charAt(a)):"end of input";return"Expected "+f+" but "+a+" found."}function Lc(){for(var f=1,a=1,e=!1,d=0;d<Math.max(b,ta);d++){var g=c.charAt(d);"\n"===g?(e||f++,a=1,e=!1):"\r"===g||"\u2028"===g||"\u2029"===g?(f++,a=1,e=!0):(a++,e=!1)}return{ka:f,Da:a}}function y(b){this.id=
-Ic++;this.ka=Lc().ka;for(var a in b)b.hasOwnProperty(a)&&(this[a]=b[a])}function X(b,a){for(var c=b,d=0;d<a.length;d++)c=new y({type:"binary",j:a[d][1],left:c,right:a[d][3]});return c}function jc(b,a,c){c&&(a=a.concat([c]));c=b[0];c.ia=b[1].C;b=c;for(var d=0;d<a.length;d++)b.M=a[d][0],b.M.ia=a[d][1].C,b=b.M;return c}var Mc={EOF:B,_:q,additive_expression:$a,additive_operator:Nb,assignment_expression:S,attribute_qualifier:Ib,attribute_type:rc,bitwise_and_expression:db,bitwise_and_operator:Rb,bitwise_or_expression:fb,
-function Ja(c,f){for(var k in f){var n=f[k];if("array"==ea(n))Ka(c,n);else{var g=typeof n;("object"==g&&null!=n||"function"==g)&&n.type&&E(c,n)}}};function F(c,f){this.c=c||"\n";this.h=!!f;this.a="";this.f=0}v(F,Ia);ka("glslunit.Generator",F);function G(c,f,k){this.a=c;this.c=f||0;this.f=k||2}
-R.prototype.getOriginalFragmentSource=R.prototype.v;R.prototype.D=function(c){return"".replace(/\n/g,c||"\\n").replace(/'/g,"\\'")};R.prototype.getOriginalVertexSource=R.prototype.D;R.prototype.m=function(){var c=[],f;for(f in this.L)c.push(this.L[f]);0<c.length&&(c[c.length-1].last=!0);return c};R.prototype.getAttributes=R.prototype.m;R.prototype.O=function(){var c=[],f;for(f in this.R)c.push(this.R[f]);0<c.length&&(c[c.length-1].last=!0);return c};R.prototype.getUniforms=R.prototype.O;
-function Vc(c){D(c.f,function(c){""==c.s&&(c.s=c.a)});var f={},k;for(k in c.L){var n=c.L[k];f[n.s]=n}k={};for(var g in c.R)n=c.R[g],k[n.s]=n;Wc(c,c.c,f,k);Wc(c,c.a,f,k)}
-U.prototype.transformForStatement=U.prototype.i;U.prototype.f=function(){return"BraceReducer"};U.prototype.g=function(){return[]};U.prototype.u=function(c,f){var k=new U;f.c=P(new U,f.c);f.a=P(k,f.a);return[]};function V(){this.c=[];this.a={}}v(V,N);V.prototype.h=function(c){var f=new K;E(f,c);c=f.a;this.a={};for(var k in c)this.a[k]=!1;$c(this,"main",c);$c(this,bc,c)};V.prototype.beforeTransformRoot=V.prototype.h;function $c(c,f,k){f in c.a&&!c.a[f]&&(c.a[f]=!0,D(k[f],function(c){$c(this,c,k)},c))}V.prototype.i=function(c){return this.a[c.name]?c:null};V.prototype.transformFunctionDeclaration=V.prototype.i;V.prototype.m=V.prototype.i;V.prototype.transformFunctionPrototype=V.prototype.m;V.prototype.f=function(){return"DeadFunctionRemover"};
-W.prototype.afterTransformPreprocessor=W.prototype.K;function ad(c,f,k){var n=I(f.w),g=null;0<c.a.length&&(g=c.a.slice(-1)[0][n]);return null!=f&&(c.i||"attribute"!=f.w.qualifier)&&"const"!=f.w.qualifier&&(!g||1<g.length)&&!(f.id in c.o)&&!(f.id in c.v)&&!(k&&!sa(f.A,function(c){return!da(c.H)}))}W.prototype.Z=function(c){return ad(this,this.h,1==this.a.length)?c.H?{id:Pc--,type:"expression",N:{id:Pc--,type:"binary",j:{id:Pc--,type:"operator",j:"="},left:c.name,right:c.H}}:null:c};
-W.prototype.transformDeclaratorItem=W.prototype.Z;W.prototype.Y=function(c){if(!ad(this,c,1==this.a.length))return c;var f=[],k=I(c.w),n=this.a.slice(-1)[0],g=n[k];g&&(f=O(c),f.A=g,f=[f],delete n[k]);c.A&&0!=c.A.length&&Array.prototype.push.apply(f,c.A);return f};W.prototype.transformDeclarator=W.prototype.Y;W.prototype.f=function(){return"DeclarationConsolidation"};W.prototype.g=function(){return[]};W.prototype.u=function(c,f){var k=new W(this.i);f.c=P(new W(this.i),f.c);f.a=P(k,f.a);return[]};function bd(c){this.a={};this.i=c;this.f={};this.c={};D(cd,function(c){this.a[c]=[]},this)}var cd=[0,1];function dd(c,f){c.c[f.f()]=f;c.a[1].push(f)}function ed(c){D(cd,function(c){D(this.a[c],function(c){fd(this,c,[])},this)},c);return c.i}function fd(c,f,k){var n=f.f(),g=k.concat(n);if(-1!=k.indexOf(n))throw"Circular dependcy in compiler steps. "+g.join("->");n in c.f||(D(f.g(),function(c){c in this.c&&fd(this,this.c[c],g)},c),c.f[n]=f.u(c.f,c.i))};function gd(){this.c={};this.g={};this.f=this.a=0}function hd(c){var f="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"[c%52];for(c=Math.floor(c/52);0<c;)--c,f+="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"[c%62],c=Math.floor(c/62);return f}function id(c){return"_"+hd(c)}function jd(c,f){if(c.c[f])return c.c[f];for(var k=null;!k||k in c.g;)k=hd(c.a++);c.g[k]=!0;return c.c[f]=k}function kd(c,f){return c.c[f]||f}
-gd.prototype.clone=function(){var c=new gd;c.c=M(this.c);c.g=M(this.g);c.a=this.a;c.f=this.f;return c};function Y(c){this.c=[];this.K=[];this.a=new gd;this.h=null;this.m=0;this.D=c;this.J=[]}v(Y,N);function ld(c,f){if(!f)return!1;var k=f.w.qualifier;return(c.D||"uniform"!=k&&"attribute"!=k)&&!(f.id in c.J)}Y.prototype.ea=function(c){this.J=Oc(c);var f=[];c=Zb(c,c);for(var k in c){var n=c[k];ld(this,n)&&(n=n.w.qualifier,"varying"==n||"uniform"==n?jd(this.a,k):f.push(k))}this.v();D(f,function(c){jd(this.a,c)},this)};Y.prototype.beforeTransformRoot=Y.prototype.ea;Y.prototype.ba=function(c){this.h=c};
-function wd(c,f,k){if(c in k)return c;var n=f[c],g=c;if(da(n))if(n.a)g=n.a.s||n.name;else if(!n.arguments){var u=M(k);u[c]=!0;g=n.c.map(function(c){return wd(c,f,u)}).join("")}return g}
-function xd(c,f,k,n){for(var g in c){var u=f[c[g]];if(da(u)&&u.arguments){var B=c.slice(g).join(""),B=z(B,"macro_call_line");if(B.aa&&B.aa.l.length==u.arguments.length&&!(B.aa.oa.name in n)){var q=B.aa,x=M(n);x[B.aa.oa.name]=!0;var q=q.l.map(function(c){return sd(I(c),f,k,x)}),ha={},C;for(C in u.arguments)ha[u.arguments[C]]=q[C];u=sd(u.c.join(""),f,ha,x);B=sd(B.Ja,f,k,n);return sd(c.slice(0,g).join("")+u+B,f,k,n)}}}return c.join("")}
-c;c=!1;if(0!=g.slice(-2,-1)[0].status){A=z(k,"preprocessor_else_if");C=rd(A.value,n);if(!C.ja)throw"Invalid "+A.B+": "+k;k="#elif "+C.na;A=0==C.value;f.G&&!f.V?(f=!0,C.G?(C=2,A=!1):A?(C=0,A=!1):(k="#else",C=1,A=!0)):f.V?(C=0,A=f.V,f=f.G):C.G?(k=k.replace(/^#elif/,"#if"),C=2,A=!1,c=f=!0):(C=A?0:1,A=!A,f=f.G);g[g.length-1]=new yd(C,A,f);f&&0!=C&&B.push(k)}u+=c}else 0==c.search("#endif")?(g.pop(),f.G&&(u--,B.push(c))):k||(f=sd(c,n),B.push(f));else{if(0<u)throw"Definitions can not be changed inside of Modes: "+
-c;f=z(c,"preprocessor_operator");delete n[f.value]}else{if(0<u)throw"Definitions can not be changed inside of Modes: "+c;f=z(c,"preprocessor_define");f=new vd(f);n[f.name]=f}});return z(B.join("\n"),k)}od.prototype.f=function(){return"Preprocessor"};od.prototype.g=function(){return["VariableMinifier"]};function Ad(c,f){var k="statements";for(k in c)if(c[k]===c.C)break;return P(new Rc(c,k,0,0,f.C),c)}
-od.prototype.u=function(c,f){var k=this.a,n=new gd;if(this.h)for(var g in f.g){var u=id(n.f++);f.g[g].s=u}if(this.i)for(g in f.f)u=id(n.f++),k.push(f.f[g].a+" "+u),f.f[g].s=u;n=this.c.map(function(c){var f=new Sc;f.a=c;return f}).concat(f.g);k=z(k.map(function(c){return"#define "+c}).join("\n"));f.c=zd(Ad(f.c,k),n,"vertex_start");f.a=zd(Ad(f.a,k),n,"fragment_start");return[]};var Bd={};ka("glslprep.SyntaxError",la.SyntaxError);ka("glslprep.Shader",Bd);Bd.VERTEX=0;Bd.FRAGMENT=1;ka("glslprep.parseGlsl",function(c,f){return z(c,0===f?"vertex_start":"fragment_start")});
+function La(){var a=b.preRun.shift();Ga.unshift(a)}var Ma=0,Na=null,Oa=null;b.preloadedImages={};b.preloadedAudios={};function oa(a){if(b.onAbort)b.onAbort(a);a+="";pa(a);qa(a);va=!0;throw new WebAssembly.RuntimeError("abort("+a+"). Build with -s ASSERTIONS=1 for more info.");}function Pa(a){var c=Qa;return String.prototype.startsWith?c.startsWith(a):0===c.indexOf(a)}function Ra(){return Pa("data:application/octet-stream;base64,")}var Qa="ammo.wasm.wasm";
+if(!Ra()){var Sa=Qa;Qa=b.locateFile?b.locateFile(Sa,ja):ja+Sa}function Ta(){try{if(ra)return new Uint8Array(ra);if(la)return la(Qa);throw"both async and sync fetching of the wasm failed";}catch(a){oa(a)}}function Ua(){return ra||!ea&&!fa||"function"!==typeof fetch||Pa("file://")?new Promise(function(a){a(Ta())}):fetch(Qa,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+Qa+"'";return a.arrayBuffer()}).catch(function(){return Ta()})}
+var Va={1960:function(a,c,d,e,g,n,F,aa){a=b.getCache(b.ConcreteContactResultCallback)[a];if(!a.hasOwnProperty("addSingleResult"))throw"a JSImplementation must implement all functions, you forgot ConcreteContactResultCallback::addSingleResult.";return a.addSingleResult(c,d,e,g,n,F,aa)},2520:function(a,c,d,e){a=b.getCache(b.DebugDrawer)[a];if(!a.hasOwnProperty("drawLine"))throw"a JSImplementation must implement all functions, you forgot DebugDrawer::drawLine.";a.drawLine(c,d,e)},2745:function(a,c,d,
+e,g,n){a=b.getCache(b.DebugDrawer)[a];if(!a.hasOwnProperty("drawContactPoint"))throw"a JSImplementation must implement all functions, you forgot DebugDrawer::drawContactPoint.";a.drawContactPoint(c,d,e,g,n)},3002:function(a,c){a=b.getCache(b.DebugDrawer)[a];if(!a.hasOwnProperty("reportErrorWarning"))throw"a JSImplementation must implement all functions, you forgot DebugDrawer::reportErrorWarning.";a.reportErrorWarning(c)},3249:function(a,c,d){a=b.getCache(b.DebugDrawer)[a];if(!a.hasOwnProperty("draw3dText"))throw"a JSImplementation must implement all functions, you forgot DebugDrawer::draw3dText.";
+a.draw3dText(c,d)},3476:function(a,c){a=b.getCache(b.DebugDrawer)[a];if(!a.hasOwnProperty("setDebugMode"))throw"a JSImplementation must implement all functions, you forgot DebugDrawer::setDebugMode.";a.setDebugMode(c)},3705:function(a){a=b.getCache(b.DebugDrawer)[a];if(!a.hasOwnProperty("getDebugMode"))throw"a JSImplementation must implement all functions, you forgot DebugDrawer::getDebugMode.";return a.getDebugMode()}};Ha.push({Xy:function(){Wa()}});var Xa=[];
+NA.prototype.debugDrawObject=function(a,c,d){var e=this.hy;a&&"object"===typeof a&&(a=a.hy);c&&"object"===typeof c&&(c=c.hy);d&&"object"===typeof d&&(d=d.hy);pb(e,a,c,d)};NA.prototype.__destroy__=function(){qb(this.hy)};function m(){throw"cannot construct a btCollisionShape, no constructor in IDL";}m.prototype=Object.create(f.prototype);m.prototype.constructor=m;m.prototype.iy=m;m.jy={};b.btCollisionShape=m;
+function q(){throw"cannot construct a btCollisionObject, no constructor in IDL";}q.prototype=Object.create(f.prototype);q.prototype.constructor=q;q.prototype.iy=q;q.jy={};b.btCollisionObject=q;q.prototype.setAnisotropicFriction=function(a,c){var d=this.hy;a&&"object"===typeof a&&(a=a.hy);c&&"object"===typeof c&&(c=c.hy);xb(d,a,c)};q.prototype.getCollisionShape=function(){return k(yb(this.hy),m)};
+q.prototype.getUserPointer=function(){return k(Yb(this.hy),SA)};q.prototype.setUserPointer=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);Zb(c,a)};q.prototype.getBroadphaseHandle=function(){return k($b(this.hy),t)};q.prototype.__destroy__=function(){ac(this.hy)};function u(){throw"cannot construct a btDynamicsWorld, no constructor in IDL";}u.prototype=Object.create(NA.prototype);u.prototype.constructor=u;u.prototype.iy=u;u.jy={};b.btDynamicsWorld=u;
+u.prototype.debugDrawObject=function(a,c,d){var e=this.hy;a&&"object"===typeof a&&(a=a.hy);c&&"object"===typeof c&&(c=c.hy);d&&"object"===typeof d&&(d=d.hy);yc(e,a,c,d)};u.prototype.__destroy__=function(){zc(this.hy)};function TA(){throw"cannot construct a btTypedConstraint, no constructor in IDL";}TA.prototype=Object.create(f.prototype);TA.prototype.constructor=TA;TA.prototype.iy=TA;TA.jy={};b.btTypedConstraint=TA;
+TA.prototype.setParam=function(a,c,d){var e=this.hy;a&&"object"===typeof a&&(a=a.hy);c&&"object"===typeof c&&(c=c.hy);d&&"object"===typeof d&&(d=d.hy);Ec(e,a,c,d)};TA.prototype.__destroy__=function(){Fc(this.hy)};function UA(){throw"cannot construct a btConcaveShape, no constructor in IDL";}UA.prototype=Object.create(m.prototype);UA.prototype.constructor=UA;UA.prototype.iy=UA;UA.jy={};b.btConcaveShape=UA;
+VA.prototype.getLocalScaling=function(){return k(Rc(this.hy),p)};VA.prototype.calculateLocalInertia=function(a,c){var d=this.hy;a&&"object"===typeof a&&(a=a.hy);c&&"object"===typeof c&&(c=c.hy);Sc(d,a,c)};VA.prototype.__destroy__=function(){Tc(this.hy)};function RA(){throw"cannot construct a btIDebugDraw, no constructor in IDL";}RA.prototype=Object.create(f.prototype);RA.prototype.constructor=RA;RA.prototype.iy=RA;RA.jy={};b.btIDebugDraw=RA;
+function WA(a){a&&"object"===typeof a&&(a=a.hy);this.hy=void 0===a?ad():bd(a);h(WA)[this.hy]=this}WA.prototype=Object.create(f.prototype);WA.prototype.constructor=WA;WA.prototype.iy=WA;WA.jy={};b.btDefaultCollisionConfiguration=WA;WA.prototype.__destroy__=function(){cd(this.hy)};function XA(){throw"cannot construct a btTriangleMeshShape, no constructor in IDL";}XA.prototype=Object.create(UA.prototype);XA.prototype.constructor=XA;XA.prototype.iy=XA;XA.jy={};b.btTriangleMeshShape=XA;
+b.btConeShape=YA;YA.prototype.setLocalScaling=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);Pd(c,a)};YA.prototype.getLocalScaling=function(){return k(Qd(this.hy),p)};YA.prototype.calculateLocalInertia=function(a,c){var d=this.hy;a&&"object"===typeof a&&(a=a.hy);c&&"object"===typeof c&&(c=c.hy);Rd(d,a,c)};YA.prototype.__destroy__=function(){Sd(this.hy)};function ZA(){throw"cannot construct a btActionInterface, no constructor in IDL";}ZA.prototype=Object.create(f.prototype);
+p.prototype.op_mul=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);return k(he(c,a),p)};p.prototype.op_add=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);return k(ie(c,a),p)};p.prototype.op_sub=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);return k(je(c,a),p)};p.prototype.__destroy__=function(){ke(this.hy)};function $A(){throw"cannot construct a btVehicleRaycaster, no constructor in IDL";}$A.prototype=Object.create(f.prototype);$A.prototype.constructor=$A;
+$A.prototype.iy=$A;$A.jy={};b.btVehicleRaycaster=$A;$A.prototype.castRay=function(a,c,d){var e=this.hy;a&&"object"===typeof a&&(a=a.hy);c&&"object"===typeof c&&(c=c.hy);d&&"object"===typeof d&&(d=d.hy);le(e,a,c,d)};$A.prototype.__destroy__=function(){me(this.hy)};function aB(){throw"cannot construct a btQuadWord, no constructor in IDL";}aB.prototype=Object.create(f.prototype);aB.prototype.constructor=aB;aB.prototype.iy=aB;aB.jy={};b.btQuadWord=aB;aB.prototype.x=aB.prototype.x=function(){return ne(this.hy)};
+function OA(){throw"cannot construct a btDispatcher, no constructor in IDL";}OA.prototype=Object.create(f.prototype);OA.prototype.constructor=OA;OA.prototype.iy=OA;OA.jy={};b.btDispatcher=OA;OA.prototype.getNumManifolds=function(){return wf(this.hy)};OA.prototype.getManifoldByIndexInternal=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);return k(xf(c,a),dB)};OA.prototype.__destroy__=function(){yf(this.hy)};
+eB.prototype.setParam=function(a,c,d){var e=this.hy;a&&"object"===typeof a&&(a=a.hy);c&&"object"===typeof c&&(c=c.hy);d&&"object"===typeof d&&(d=d.hy);Kf(e,a,c,d)};eB.prototype.__destroy__=function(){Lf(this.hy)};function fB(){throw"cannot construct a btStridingMeshInterface, no constructor in IDL";}fB.prototype=Object.create(f.prototype);fB.prototype.constructor=fB;fB.prototype.iy=fB;fB.jy={};b.btStridingMeshInterface=fB;
+fB.prototype.setScaling=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);Mf(c,a)};fB.prototype.__destroy__=function(){Nf(this.hy)};function gB(){throw"cannot construct a btMotionState, no constructor in IDL";}gB.prototype=Object.create(f.prototype);gB.prototype.constructor=gB;gB.prototype.iy=gB;gB.jy={};b.btMotionState=gB;gB.prototype.getWorldTransform=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);Of(c,a)};
+gB.prototype.setWorldTransform=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);Pf(c,a)};gB.prototype.__destroy__=function(){Qf(this.hy)};function y(){throw"cannot construct a ConvexResultCallback, no constructor in IDL";}y.prototype=Object.create(f.prototype);y.prototype.constructor=y;y.prototype.iy=y;y.jy={};b.ConvexResultCallback=y;y.prototype.hasHit=function(){return!!Rf(this.hy)};y.prototype.get_m_collisionFilterGroup=y.prototype.ky=function(){return Sf(this.hy)};
+function hB(){throw"cannot construct a ContactResultCallback, no constructor in IDL";}hB.prototype=Object.create(f.prototype);hB.prototype.constructor=hB;hB.prototype.iy=hB;hB.jy={};b.ContactResultCallback=hB;
+hB.prototype.addSingleResult=function(a,c,d,e,g,n,F){var aa=this.hy;a&&"object"===typeof a&&(a=a.hy);c&&"object"===typeof c&&(c=c.hy);d&&"object"===typeof d&&(d=d.hy);e&&"object"===typeof e&&(e=e.hy);g&&"object"===typeof g&&(g=g.hy);n&&"object"===typeof n&&(n=n.hy);F&&"object"===typeof F&&(F=F.hy);return Zf(aa,a,c,d,e,g,n,F)};hB.prototype.__destroy__=function(){$f(this.hy)};function iB(){throw"cannot construct a btSoftBodySolver, no constructor in IDL";}iB.prototype=Object.create(f.prototype);
+iB.prototype.constructor=iB;iB.prototype.iy=iB;iB.jy={};b.btSoftBodySolver=iB;iB.prototype.__destroy__=function(){ag(this.hy)};function z(){throw"cannot construct a RayResultCallback, no constructor in IDL";}z.prototype=Object.create(f.prototype);z.prototype.constructor=z;z.prototype.iy=z;z.jy={};b.RayResultCallback=z;z.prototype.hasHit=function(){return!!bg(this.hy)};z.prototype.get_m_collisionFilterGroup=z.prototype.ky=function(){return cg(this.hy)};
+z.prototype.set_m_collisionObject=z.prototype.xy=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);jg(c,a)};Object.defineProperty(z.prototype,"m_collisionObject",{get:z.prototype.qy,set:z.prototype.xy});z.prototype.__destroy__=function(){kg(this.hy)};function jB(){throw"cannot construct a btMatrix3x3, no constructor in IDL";}jB.prototype=Object.create(f.prototype);jB.prototype.constructor=jB;jB.prototype.iy=jB;jB.jy={};b.btMatrix3x3=jB;
+jB.prototype.setEulerZYX=function(a,c,d){var e=this.hy;a&&"object"===typeof a&&(a=a.hy);c&&"object"===typeof c&&(c=c.hy);d&&"object"===typeof d&&(d=d.hy);lg(e,a,c,d)};jB.prototype.getRotation=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);mg(c,a)};jB.prototype.getRow=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);return k(ng(c,a),p)};jB.prototype.__destroy__=function(){og(this.hy)};function kB(){throw"cannot construct a btScalarArray, no constructor in IDL";}kB.prototype=Object.create(f.prototype);
+kB.prototype.constructor=kB;kB.prototype.iy=kB;kB.jy={};b.btScalarArray=kB;kB.prototype.size=kB.prototype.size=function(){return pg(this.hy)};kB.prototype.at=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);return qg(c,a)};kB.prototype.__destroy__=function(){rg(this.hy)};function A(){throw"cannot construct a Material, no constructor in IDL";}A.prototype=Object.create(f.prototype);A.prototype.constructor=A;A.prototype.iy=A;A.jy={};b.Material=A;A.prototype.get_m_kLST=A.prototype.vA=function(){return sg(this.hy)};
+function l(){throw"cannot construct a btDispatcherInfo, no constructor in IDL";}l.prototype=Object.create(f.prototype);l.prototype.constructor=l;l.prototype.iy=l;l.jy={};b.btDispatcherInfo=l;l.prototype.get_m_timeStep=l.prototype.jB=function(){return Bg(this.hy)};l.prototype.set_m_timeStep=l.prototype.QD=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);Cg(c,a)};Object.defineProperty(l.prototype,"m_timeStep",{get:l.prototype.jB,set:l.prototype.QD});
+Object.defineProperty(l.prototype,"m_convexConservativeDistanceThreshold",{get:l.prototype.Rz,set:l.prototype.xC});l.prototype.__destroy__=function(){Xg(this.hy)};function B(){throw"cannot construct a btWheelInfoConstructionInfo, no constructor in IDL";}B.prototype=Object.create(f.prototype);B.prototype.constructor=B;B.prototype.iy=B;B.jy={};b.btWheelInfoConstructionInfo=B;B.prototype.get_m_chassisConnectionCS=B.prototype.Lz=function(){return k(Yg(this.hy),p)};
+function mB(){throw"cannot construct a btCollisionConfiguration, no constructor in IDL";}mB.prototype=Object.create(f.prototype);mB.prototype.constructor=mB;mB.prototype.iy=mB;mB.jy={};b.btCollisionConfiguration=mB;mB.prototype.__destroy__=function(){gi(this.hy)};function dB(){this.hy=hi();h(dB)[this.hy]=this}dB.prototype=Object.create(f.prototype);dB.prototype.constructor=dB;dB.prototype.iy=dB;dB.jy={};b.btPersistentManifold=dB;dB.prototype.getBody0=function(){return k(ii(this.hy),q)};
+G.prototype.set_m_collisionObject=G.prototype.xy=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);nj(c,a)};Object.defineProperty(G.prototype,"m_collisionObject",{get:G.prototype.qy,set:G.prototype.xy});G.prototype.__destroy__=function(){oj(this.hy)};function qB(){throw"cannot construct a tMaterialArray, no constructor in IDL";}qB.prototype=Object.create(f.prototype);qB.prototype.constructor=qB;qB.prototype.iy=qB;qB.jy={};b.tMaterialArray=qB;qB.prototype.size=qB.prototype.size=function(){return pj(this.hy)};
+H.prototype.get_m_impulseClamp=H.prototype.qA=function(){return Fj(this.hy)};H.prototype.set_m_impulseClamp=H.prototype.XC=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);Gj(c,a)};Object.defineProperty(H.prototype,"m_impulseClamp",{get:H.prototype.qA,set:H.prototype.XC});H.prototype.__destroy__=function(){Hj(this.hy)};function tB(){throw"cannot construct a LocalShapeInfo, no constructor in IDL";}tB.prototype=Object.create(f.prototype);tB.prototype.constructor=tB;tB.prototype.iy=tB;
+I.prototype.getUserPointer=function(){return k(Vk(this.hy),SA)};I.prototype.setUserPointer=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);Wk(c,a)};I.prototype.getBroadphaseHandle=function(){return k(Xk(this.hy),t)};I.prototype.__destroy__=function(){Yk(this.hy)};function uB(){throw"cannot construct a btIndexedMeshArray, no constructor in IDL";}uB.prototype=Object.create(f.prototype);uB.prototype.constructor=uB;uB.prototype.iy=uB;uB.jy={};b.btIndexedMeshArray=uB;
+function SA(){throw"cannot construct a VoidPtr, no constructor in IDL";}SA.prototype=Object.create(f.prototype);SA.prototype.constructor=SA;SA.prototype.iy=SA;SA.jy={};b.VoidPtr=SA;SA.prototype.__destroy__=function(){vl(this.hy)};function J(){this.hy=wl();h(J)[this.hy]=this}J.prototype=Object.create(f.prototype);J.prototype.constructor=J;J.prototype.iy=J;J.jy={};b.btSoftBodyWorldInfo=J;J.prototype.get_air_density=J.prototype.Yy=function(){return xl(this.hy)};
+function IB(){throw"cannot construct a btCollisionObjectWrapper, no constructor in IDL";}IB.prototype=Object.create(f.prototype);IB.prototype.constructor=IB;IB.prototype.iy=IB;IB.jy={};b.btCollisionObjectWrapper=IB;IB.prototype.getWorldTransform=function(){return k(tn(this.hy),r)};IB.prototype.getCollisionObject=function(){return k(un(this.hy),q)};IB.prototype.getCollisionShape=function(){return k(vn(this.hy),m)};function JB(a){a&&"object"===typeof a&&(a=a.hy);this.hy=wn(a);h(JB)[this.hy]=this}
+LB.prototype.constructor=LB;LB.prototype.iy=LB;LB.jy={};b.btDefaultCollisionConstructionInfo=LB;LB.prototype.__destroy__=function(){bp(this.hy)};function O(){throw"cannot construct a Anchor, no constructor in IDL";}O.prototype=Object.create(f.prototype);O.prototype.constructor=O;O.prototype.iy=O;O.jy={};b.Anchor=O;O.prototype.get_m_node=O.prototype.FA=function(){return k(cp(this.hy),Node)};O.prototype.set_m_node=O.prototype.lD=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);dp(c,a)};
+O.prototype.get_m_c2=O.prototype.Jz=function(){return op(this.hy)};O.prototype.set_m_c2=O.prototype.pC=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);pp(c,a)};Object.defineProperty(O.prototype,"m_c2",{get:O.prototype.Jz,set:O.prototype.pC});O.prototype.__destroy__=function(){qp(this.hy)};function P(){throw"cannot construct a btVehicleRaycasterResult, no constructor in IDL";}P.prototype=Object.create(f.prototype);P.prototype.constructor=P;P.prototype.iy=P;P.jy={};
+P.prototype.__destroy__=function(){xp(this.hy)};function pB(){throw"cannot construct a btVector3Array, no constructor in IDL";}pB.prototype=Object.create(f.prototype);pB.prototype.constructor=pB;pB.prototype.iy=pB;pB.jy={};b.btVector3Array=pB;pB.prototype.size=pB.prototype.size=function(){return yp(this.hy)};pB.prototype.at=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);return k(zp(c,a),p)};pB.prototype.__destroy__=function(){Ap(this.hy)};
+function MB(){throw"cannot construct a btConstraintSolver, no constructor in IDL";}MB.prototype=Object.create(f.prototype);MB.prototype.constructor=MB;MB.prototype.iy=MB;MB.jy={};b.btConstraintSolver=MB;MB.prototype.__destroy__=function(){Bp(this.hy)};function Q(a,c,d){a&&"object"===typeof a&&(a=a.hy);c&&"object"===typeof c&&(c=c.hy);d&&"object"===typeof d&&(d=d.hy);this.hy=Cp(a,c,d);h(Q)[this.hy]=this}Q.prototype=Object.create(ZA.prototype);Q.prototype.constructor=Q;Q.prototype.iy=Q;Q.jy={};
+OB.prototype.__destroy__=function(){uq(this.hy)};function HB(){throw"cannot construct a btConvexPolyhedron, no constructor in IDL";}HB.prototype=Object.create(f.prototype);HB.prototype.constructor=HB;HB.prototype.iy=HB;HB.jy={};b.btConvexPolyhedron=HB;HB.prototype.get_m_vertices=HB.prototype.qB=function(){return k(vq(this.hy),pB)};HB.prototype.set_m_vertices=HB.prototype.XD=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);wq(c,a)};
+QB.prototype.constructor=QB;QB.prototype.iy=QB;QB.jy={};b.btSequentialImpulseConstraintSolver=QB;QB.prototype.__destroy__=function(){Bq(this.hy)};function RB(){throw"cannot construct a tAnchorArray, no constructor in IDL";}RB.prototype=Object.create(f.prototype);RB.prototype.constructor=RB;RB.prototype.iy=RB;RB.jy={};b.tAnchorArray=RB;RB.prototype.size=RB.prototype.size=function(){return Cq(this.hy)};RB.prototype.at=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);return k(Dq(c,a),O)};
+RB.prototype.clear=RB.prototype.clear=function(){Eq(this.hy)};RB.prototype.push_back=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);Fq(c,a)};RB.prototype.pop_back=function(){Gq(this.hy)};RB.prototype.__destroy__=function(){Hq(this.hy)};function M(){throw"cannot construct a RaycastInfo, no constructor in IDL";}M.prototype=Object.create(f.prototype);M.prototype.constructor=M;M.prototype.iy=M;M.jy={};b.RaycastInfo=M;
+R.prototype.set_m_anchors=R.prototype.gC=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);ms(c,a)};Object.defineProperty(R.prototype,"m_anchors",{get:R.prototype.Az,set:R.prototype.gC});R.prototype.__destroy__=function(){ns(this.hy)};function VB(){throw"cannot construct a btIntArray, no constructor in IDL";}VB.prototype=Object.create(f.prototype);VB.prototype.constructor=VB;VB.prototype.iy=VB;VB.jy={};b.btIntArray=VB;VB.prototype.size=VB.prototype.size=function(){return ps(this.hy)};
+VB.prototype.at=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);return qs(c,a)};VB.prototype.__destroy__=function(){rs(this.hy)};function S(){throw"cannot construct a Config, no constructor in IDL";}S.prototype=Object.create(f.prototype);S.prototype.constructor=S;S.prototype.iy=S;S.jy={};b.Config=S;S.prototype.get_kVCF=S.prototype.sz=function(){return ss(this.hy)};S.prototype.set_kVCF=S.prototype.$B=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);ts(c,a)};
+S.prototype.set_collisions=S.prototype.HB=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);pt(c,a)};Object.defineProperty(S.prototype,"collisions",{get:S.prototype.$y,set:S.prototype.HB});S.prototype.__destroy__=function(){qt(this.hy)};function Node(){throw"cannot construct a Node, no constructor in IDL";}Node.prototype=Object.create(f.prototype);Node.prototype.constructor=Node;Node.prototype.iy=Node;Node.jy={};b.Node=Node;
+Object.defineProperty(Node.prototype,"m_area",{get:Node.prototype.Dz,set:Node.prototype.jC});Node.prototype.__destroy__=function(){Ft(this.hy)};function WB(){this.hy=Gt();h(WB)[this.hy]=this}WB.prototype=Object.create(f.prototype);WB.prototype.constructor=WB;WB.prototype.iy=WB;WB.jy={};b.btGhostPairCallback=WB;WB.prototype.__destroy__=function(){Ht(this.hy)};function XB(){throw"cannot construct a btOverlappingPairCallback, no constructor in IDL";}XB.prototype=Object.create(f.prototype);
+T.prototype.setUpInterpolate=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);cu(c,a)};T.prototype.updateAction=function(a,c){var d=this.hy;a&&"object"===typeof a&&(a=a.hy);c&&"object"===typeof c&&(c=c.hy);du(d,a,c)};T.prototype.__destroy__=function(){eu(this.hy)};function YB(){throw"cannot construct a btSoftBodyArray, no constructor in IDL";}YB.prototype=Object.create(f.prototype);YB.prototype.constructor=YB;YB.prototype.iy=YB;YB.jy={};b.btSoftBodyArray=YB;
+YB.prototype.size=YB.prototype.size=function(){return fu(this.hy)};YB.prototype.at=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);return k(gu(c,a),R)};YB.prototype.__destroy__=function(){hu(this.hy)};function PB(){throw"cannot construct a btFaceArray, no constructor in IDL";}PB.prototype=Object.create(f.prototype);PB.prototype.constructor=PB;PB.prototype.iy=PB;PB.jy={};b.btFaceArray=PB;PB.prototype.size=PB.prototype.size=function(){return iu(this.hy)};
+$B.prototype.getLocalScaling=function(){return k(nu(this.hy),p)};$B.prototype.calculateLocalInertia=function(a,c){var d=this.hy;a&&"object"===typeof a&&(a=a.hy);c&&"object"===typeof c&&(c=c.hy);ou(d,a,c)};$B.prototype.__destroy__=function(){pu(this.hy)};function PA(){throw"cannot construct a btOverlappingPairCache, no constructor in IDL";}PA.prototype=Object.create(f.prototype);PA.prototype.constructor=PA;PA.prototype.iy=PA;PA.jy={};b.btOverlappingPairCache=PA;
+PA.prototype.setInternalGhostPairCallback=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);qu(c,a)};PA.prototype.getNumOverlappingPairs=function(){return ru(this.hy)};PA.prototype.__destroy__=function(){su(this.hy)};function vB(){throw"cannot construct a btIndexedMesh, no constructor in IDL";}vB.prototype=Object.create(f.prototype);vB.prototype.constructor=vB;vB.prototype.iy=vB;vB.jy={};b.btIndexedMesh=vB;vB.prototype.get_m_numTriangles=vB.prototype.KA=function(){return tu(this.hy)};
+dC.prototype.calculateLocalInertia=function(a,c){var d=this.hy;a&&"object"===typeof a&&(a=a.hy);c&&"object"===typeof c&&(c=c.hy);hw(d,a,c)};dC.prototype.__destroy__=function(){iw(this.hy)};function oB(){throw"cannot construct a btConstCollisionObjectArray, no constructor in IDL";}oB.prototype=Object.create(f.prototype);oB.prototype.constructor=oB;oB.prototype.iy=oB;oB.jy={};b.btConstCollisionObjectArray=oB;oB.prototype.size=oB.prototype.size=function(){return jw(this.hy)};
+U.prototype.getOverlappingObject=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);return k(cx(c,a),q)};U.prototype.__destroy__=function(){dx(this.hy)};function D(){throw"cannot construct a btManifoldPoint, no constructor in IDL";}D.prototype=Object.create(f.prototype);D.prototype.constructor=D;D.prototype.iy=D;D.jy={};b.btManifoldPoint=D;D.prototype.getPositionWorldOnA=function(){return k(ex(this.hy),p)};D.prototype.getPositionWorldOnB=function(){return k(fx(this.hy),p)};
+gC.prototype.CreateFromConvexHull=function(a,c,d,e){var g=this.hy;a&&"object"===typeof a&&(a=a.hy);c&&"object"===typeof c&&(c=c.hy);d&&"object"===typeof d&&(d=d.hy);e&&"object"===typeof e&&(e=e.hy);return k(Px(g,a,c,d,e),R)};gC.prototype.__destroy__=function(){Qx(this.hy)};function t(){throw"cannot construct a btBroadphaseProxy, no constructor in IDL";}t.prototype=Object.create(f.prototype);t.prototype.constructor=t;t.prototype.iy=t;t.jy={};b.btBroadphaseProxy=t;
+t.prototype.set_m_collisionFilterMask=t.prototype.ny=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);Ux(c,a)};Object.defineProperty(t.prototype,"m_collisionFilterMask",{get:t.prototype.ly,set:t.prototype.ny});t.prototype.__destroy__=function(){Vx(this.hy)};function TB(){throw"cannot construct a tNodeArray, no constructor in IDL";}TB.prototype=Object.create(f.prototype);TB.prototype.constructor=TB;TB.prototype.iy=TB;TB.jy={};b.tNodeArray=TB;TB.prototype.size=TB.prototype.size=function(){return Wx(this.hy)};
+hC.prototype.setLocalScaling=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);by(c,a)};hC.prototype.getLocalScaling=function(){return k(cy(this.hy),p)};hC.prototype.calculateLocalInertia=function(a,c){var d=this.hy;a&&"object"===typeof a&&(a=a.hy);c&&"object"===typeof c&&(c=c.hy);dy(d,a,c)};hC.prototype.__destroy__=function(){ey(this.hy)};function ZB(){throw"cannot construct a btFace, no constructor in IDL";}ZB.prototype=Object.create(f.prototype);ZB.prototype.constructor=ZB;
+mC.prototype.getLocalScaling=function(){return k(Sz(this.hy),p)};mC.prototype.calculateLocalInertia=function(a,c){var d=this.hy;a&&"object"===typeof a&&(a=a.hy);c&&"object"===typeof c&&(c=c.hy);Tz(d,a,c)};mC.prototype.__destroy__=function(){Uz(this.hy)};function Y(){throw"cannot construct a Face, no constructor in IDL";}Y.prototype=Object.create(f.prototype);Y.prototype.constructor=Y;Y.prototype.iy=Y;Y.jy={};b.Face=Y;
+function UB(){throw"cannot construct a tFaceArray, no constructor in IDL";}UB.prototype=Object.create(f.prototype);UB.prototype.constructor=UB;UB.prototype.iy=UB;UB.jy={};b.tFaceArray=UB;UB.prototype.size=UB.prototype.size=function(){return bA(this.hy)};UB.prototype.at=function(a){var c=this.hy;a&&"object"===typeof a&&(a=a.hy);return k(cA(c,a),Y)};UB.prototype.__destroy__=function(){dA(this.hy)};
- * @param {Vec3} pivotA The point relative to the center of mass of bodyA which bodyA is constrained to.
- * @param {Body} bodyB Body that will be constrained in a similar way to the same point as bodyA. We will therefore get a link between bodyA and bodyB. If not specified, bodyA will be constrained to a static point.
- * @param {Vec3} pivotB See pivotA.
- * @param {Number} maxForce The maximum force that should be applied to constrain the bodies.
- *
- * @example
- * var bodyA = new Body({ mass: 1 });
- * var bodyB = new Body({ mass: 1 });
- * bodyA.position.set(-1, 0, 0);
- * bodyB.position.set(1, 0, 0);
- * bodyA.addShape(shapeA);
- * bodyB.addShape(shapeB);
- * world.addBody(bodyA);
- * world.addBody(bodyB);
- * var localPivotA = new Vec3(1, 0, 0);
- * var localPivotB = new Vec3(-1, 0, 0);
- * var constraint = new PointToPointConstraint(bodyA, localPivotA, bodyB, localPivotB);
- * Friction for this material. If non-negative, it will be used instead of the friction given by ContactMaterials. If there's no matching ContactMaterial, the value from .defaultContactMaterial in the World will be used.
- * Restitution for this material. If non-negative, it will be used instead of the restitution given by ContactMaterials. If there's no matching ContactMaterial, the value from .defaultContactMaterial in the World will be used.
- * A Quaternion describes a rotation in 3D space. The Quaternion is mathematically defined as Q = x*i + y*j + z*k + w, where (i,j,k) are imaginary basis vectors. (x,y,z) can be seen as a vector related to the axis of rotation, while the real multiplier, w, is related to the amount of rotation.
- * @class Quaternion
- * @constructor
- * @param {Number} x Multiplier of the imaginary basis vector i.
- * @param {Number} y Multiplier of the imaginary basis vector j.
- * @param {Number} z Multiplier of the imaginary basis vector k.
- * @param {Number} w Multiplier of the real part.
- * @see http://en.wikipedia.org/wiki/Quaternion
- */
-function Quaternion(x,y,z,w){
- /**
- * @property {Number} x
- */
- this.x = x!==undefined ? x : 0;
-
- /**
- * @property {Number} y
- */
- this.y = y!==undefined ? y : 0;
-
- /**
- * @property {Number} z
- */
- this.z = z!==undefined ? z : 0;
-
- /**
- * The multiplier of the real quaternion basis vector.
- * @property {Number} w
- */
- this.w = w!==undefined ? w : 1;
-}
-
-/**
- * Set the value of the quaternion.
- * @method set
- * @param {Number} x
- * @param {Number} y
- * @param {Number} z
- * @param {Number} w
- */
-Quaternion.prototype.set = function(x,y,z,w){
- this.x = x;
- this.y = y;
- this.z = z;
- this.w = w;
-};
-
-/**
- * Convert to a readable format
- * @method toString
- * @return string
- */
-Quaternion.prototype.toString = function(){
- return this.x+","+this.y+","+this.z+","+this.w;
-};
-
-/**
- * Convert to an Array
- * @method toArray
- * @return Array
- */
-Quaternion.prototype.toArray = function(){
- return [this.x, this.y, this.z, this.w];
-};
-
-/**
- * Set the quaternion components given an axis and an angle.
- bank = Math.atan2(2*x*w - 2*y*z , 1 - 2*sqx - 2*sqz); // bank
- }
- break;
- default:
- throw new Error("Euler order "+order+" not supported yet.");
- }
-
- target.y = heading;
- target.z = attitude;
- target.x = bank;
-};
-
-/**
- * See http://www.mathworks.com/matlabcentral/fileexchange/20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/content/SpinCalc.m
- * @method setFromEuler
- * @param {Number} x
- * @param {Number} y
- * @param {Number} z
- * @param {String} order The order to apply angles: 'XYZ' or 'YXZ' or any other combination
- */
-Quaternion.prototype.setFromEuler = function ( x, y, z, order ) {
- order = order || "XYZ";
-
- var c1 = Math.cos( x / 2 );
- var c2 = Math.cos( y / 2 );
- var c3 = Math.cos( z / 2 );
- var s1 = Math.sin( x / 2 );
- var s2 = Math.sin( y / 2 );
- var s3 = Math.sin( z / 2 );
-
- if ( order === 'XYZ' ) {
-
- this.x = s1 * c2 * c3 + c1 * s2 * s3;
- this.y = c1 * s2 * c3 - s1 * c2 * s3;
- this.z = c1 * c2 * s3 + s1 * s2 * c3;
- this.w = c1 * c2 * c3 - s1 * s2 * s3;
-
- } else if ( order === 'YXZ' ) {
-
- this.x = s1 * c2 * c3 + c1 * s2 * s3;
- this.y = c1 * s2 * c3 - s1 * c2 * s3;
- this.z = c1 * c2 * s3 - s1 * s2 * c3;
- this.w = c1 * c2 * c3 + s1 * s2 * s3;
-
- } else if ( order === 'ZXY' ) {
-
- this.x = s1 * c2 * c3 - c1 * s2 * s3;
- this.y = c1 * s2 * c3 + s1 * c2 * s3;
- this.z = c1 * c2 * s3 + s1 * s2 * c3;
- this.w = c1 * c2 * c3 - s1 * s2 * s3;
-
- } else if ( order === 'ZYX' ) {
-
- this.x = s1 * c2 * c3 - c1 * s2 * s3;
- this.y = c1 * s2 * c3 + s1 * c2 * s3;
- this.z = c1 * c2 * s3 - s1 * s2 * c3;
- this.w = c1 * c2 * c3 + s1 * s2 * s3;
-
- } else if ( order === 'YZX' ) {
-
- this.x = s1 * c2 * c3 + c1 * s2 * s3;
- this.y = c1 * s2 * c3 + s1 * c2 * s3;
- this.z = c1 * c2 * s3 - s1 * s2 * c3;
- this.w = c1 * c2 * c3 - s1 * s2 * s3;
-
- } else if ( order === 'XZY' ) {
-
- this.x = s1 * c2 * c3 - c1 * s2 * s3;
- this.y = c1 * s2 * c3 - s1 * c2 * s3;
- this.z = c1 * c2 * s3 + s1 * s2 * c3;
- this.w = c1 * c2 * c3 + s1 * s2 * s3;
-
- }
-
- return this;
-
-};
-
-Quaternion.prototype.clone = function(){
- return new Quaternion(this.x, this.y, this.z, this.w);
- * Make the vector point in the opposite direction.
- * @method negate
- * @param {Vec3} target Optional target to save in
- * @return {Vec3}
- */
-Vec3.prototype.negate = function(target){
- target = target || new Vec3();
- target.x = -this.x;
- target.y = -this.y;
- target.z = -this.z;
- return target;
-};
-
-/**
- * Compute two artificial tangents to the vector
- * @method tangents
- * @param {Vec3} t1 Vector object to save the first tangent in
- * @param {Vec3} t2 Vector object to save the second tangent in
- */
-var Vec3_tangents_n = new Vec3();
-var Vec3_tangents_randVec = new Vec3();
-Vec3.prototype.tangents = function(t1,t2){
- var norm = this.norm();
- if(norm>0.0){
- var n = Vec3_tangents_n;
- var inorm = 1/norm;
- n.set(this.x*inorm,this.y*inorm,this.z*inorm);
- var randVec = Vec3_tangents_randVec;
- if(Math.abs(n.x) < 0.9){
- randVec.set(1,0,0);
- n.cross(randVec,t1);
- } else {
- randVec.set(0,1,0);
- n.cross(randVec,t1);
- }
- n.cross(t1,t2);
- } else {
- // The normal length is zero, make something up
- t1.set(1, 0, 0);
- t2.set(0, 1, 0);
- }
-};
-
-/**
- * Converts to a more readable format
- * @method toString
- * @return string
- */
-Vec3.prototype.toString = function(){
- return this.x+","+this.y+","+this.z;
-};
-
-/**
- * Converts to an array
- * @method toArray
- * @return Array
- */
-Vec3.prototype.toArray = function(){
- return [this.x, this.y, this.z];
-};
-
-/**
- * Copies value of source to this vector.
- * @method copy
- * @param {Vec3} source
- * @return {Vec3} this
- */
-Vec3.prototype.copy = function(source){
- this.x = source.x;
- this.y = source.y;
- this.z = source.z;
- return this;
-};
-
-
-/**
- * Do a linear interpolation between two vectors
- * @method lerp
- * @param {Vec3} v
- * @param {Number} t A number between 0 and 1. 0 will make this function return u, and 1 will make it return v. Numbers in between will generate a vector in between them.
- * @param {Vec3} target
- */
-Vec3.prototype.lerp = function(v,t,target){
- var x=this.x, y=this.y, z=this.z;
- target.x = x + (v.x-x)*t;
- target.y = y + (v.y-y)*t;
- target.z = z + (v.z-z)*t;
-};
-
-/**
- * Check if a vector equals is almost equal to another one.
- * Callback function that is used BEFORE stepping the system. Use it to apply forces, for example. Inside the function, "this" will refer to this Body object.
- * @property preStep
- * @type {Function}
- * @deprecated Use World events instead
- */
- this.preStep = null;
-
- /**
- * Callback function that is used AFTER stepping the system. Inside the function, "this" will refer to this Body object.
- * Indicates if the AABB needs to be updated before use.
- * @property aabbNeedsUpdate
- * @type {Boolean}
- */
- this.aabbNeedsUpdate = true;
-
- this.wlambda = new Vec3();
-
- if(options.shape){
- this.addShape(options.shape);
- }
-
- this.updateMassProperties();
-}
-Body.prototype = new EventTarget();
-Body.prototype.constructor = Body;
-
-/**
- * A dynamic body is fully simulated. Can be moved manually by the user, but normally they move according to forces. A dynamic body can collide with all body types. A dynamic body always has finite, non-zero mass.
- * @static
- * @property DYNAMIC
- * @type {Number}
- */
-Body.DYNAMIC = 1;
-
-/**
- * A static body does not move during simulation and behaves as if it has infinite mass. Static bodies can be moved manually by setting the position of the body. The velocity of a static body is always zero. Static bodies do not collide with other static or kinematic bodies.
- * @static
- * @property STATIC
- * @type {Number}
- */
-Body.STATIC = 2;
-
-/**
- * A kinematic body moves under simulation according to its velocity. They do not respond to forces. They can be moved manually, but normally a kinematic body is moved by setting its velocity. A kinematic body behaves as if it has infinite mass. Kinematic bodies do not collide with other static or kinematic bodies.
- * @static
- * @property KINEMATIC
- * @type {Number}
- */
-Body.KINEMATIC = 4;
-
-
-
-/**
- * @static
- * @property AWAKE
- * @type {number}
- */
-Body.AWAKE = 0;
-
-/**
- * @static
- * @property SLEEPY
- * @type {number}
- */
-Body.SLEEPY = 1;
-
-/**
- * @static
- * @property SLEEPING
- * @type {number}
- */
-Body.SLEEPING = 2;
-
-Body.idCounter = 0;
-
-/**
- * Wake the body up.
- * @method wakeUp
- */
-Body.prototype.wakeUp = function(){
- var s = this.sleepState;
- this.sleepState = 0;
- if(s === Body.SLEEPING){
- this.dispatchEvent({type:"wakeup"});
- }
-};
-
-/**
- * Force body sleep
- * @method sleep
- */
-Body.prototype.sleep = function(){
- this.sleepState = Body.SLEEPING;
- this.velocity.set(0,0,0);
- this.angularVelocity.set(0,0,0);
-};
-
-Body.sleepyEvent = {
- type: "sleepy"
-};
-
-Body.sleepEvent = {
- type: "sleep"
-};
-
-/**
- * Called every timestep to update internal sleep timer and change sleep state if needed.
- * @method sleepTick
- * @param {Number} time The world time in seconds
- */
-Body.prototype.sleepTick = function(time){
- if(this.allowSleep){
- var sleepState = this.sleepState;
- var speedSquared = this.velocity.norm2() + this.angularVelocity.norm2();
- var speedLimitSquared = Math.pow(this.sleepSpeedLimit,2);
- * Apply force to a world point. This could for example be a point on the Body surface. Applying force this way will add to Body.force and Body.torque.
- * @method applyForce
- * @param {Vec3} force The amount of force to add.
- * @param {Vec3} worldPoint A world point to apply the force on.
- * Apply impulse to a world point. This could for example be a point on the Body surface. An impulse is a force added to a body during a short period of time (impulse = force * time). Impulses will be added to Body.velocity and Body.angularVelocity.
- * @method applyImpulse
- * @param {Vec3} impulse The amount of impulse to add.
- * @param {Vec3} worldPoint A world point to apply the force on.
- * Note when rendering wheels: during each step, wheel transforms are updated BEFORE the chassis; ie. their position becomes invalid after the step. Thus when you render wheels, you must update wheel transforms before rendering them. See raycastVehicle demo for an example.
- * @method updateWheelTransform
- * @param {integer} wheelIndex The wheel index to update.
- // Scale the relative position in the up direction with rollInfluence.
- // If rollInfluence is 1, the impulse will be applied on the hitPoint (easy to roll over), if it is zero it will be applied in the same plane as the center of mass (not easy to roll over).
- throw new Error("Vertex "+this.faces[i][j]+" not found!");
- }
- }
-
- var n = this.faceNormals[i] || new Vec3();
- this.getFaceNormal(i,n);
- n.negate(n);
- this.faceNormals[i] = n;
- var vertex = this.vertices[this.faces[i][0]];
- if(n.dot(vertex) < 0){
- console.error(".faceNormals[" + i + "] = Vec3("+n.toString()+") looks like it points into the shape? The vertices follow. Make sure they are ordered CCW around the normal, using the right hand rule.");
- * @param {Array} worldVertsB1 An array of Vec3 with vertices in the world frame.
- * @param {Number} minDist Distance clamping
- * @param {Number} maxDist
- * @param Array result Array to store resulting contact points in. Will be objects with properties: point, depth, normal. These are represented in world coordinates.
- // console.log("--- did not find any closest face... ---");
- return;
- }
- //console.log("closest A: ",closestFaceA);
- // Get the face and construct connected faces
- var polyA = hullA.faces[closestFaceA];
- polyA.connectedFaces = [];
- for(var i=0; i<hullA.faces.length; i++){
- for(var j=0; j<hullA.faces[i].length; j++){
- if(polyA.indexOf(hullA.faces[i][j])!==-1 /* Sharing a vertex*/ && i!==closestFaceA /* Not the one we are looking for connections from */ && polyA.connectedFaces.indexOf(i)===-1 /* Not already added */ ){
- polyA.connectedFaces.push(i);
- }
- }
- }
- // Clip the polygon to the back of the planes of all faces of hull A, that are adjacent to the witness face
- var numContacts = pVtxIn.length;
- var numVerticesA = polyA.length;
- var res = [];
- for(var e0=0; e0<numVerticesA; e0++){
- var a = hullA.vertices[polyA[e0]];
- var b = hullA.vertices[polyA[(e0+1)%numVerticesA]];
- * Checks whether p is inside the polyhedra. Must be in local coords. The point lies outside of the convex hull of the other points if and only if the direction of all the vectors from it to those other points are on less than one half of a sphere around it.
- * @method pointIsInside
- * @param {Vec3} p A point given in local coordinates
- * @return {Boolean}
- */
-var ConvexPolyhedron_pointIsInside = new Vec3();
-var ConvexPolyhedron_vToP = new Vec3();
-var ConvexPolyhedron_vToPointInside = new Vec3();
- this.clearCachedConvexTrianglePillar(xi, yi - 1, true);
- this.clearCachedConvexTrianglePillar(xi, yi - 1, false);
- }
- if(yi > 0 && xi > 0){
- this.clearCachedConvexTrianglePillar(xi - 1, yi - 1, true);
- }
-};
-
-/**
- * Get max/min in a rectangle in the matrix data
- * @method getRectMinMax
- * @param {integer} iMinX
- * @param {integer} iMinY
- * @param {integer} iMaxX
- * @param {integer} iMaxY
- * @param {array} [result] An array to store the results in.
- * @return {array} The result array, if it was passed in. Minimum will be at position 0 and max at 1.
- */
-Heightfield.prototype.getRectMinMax = function (iMinX, iMinY, iMaxX, iMaxY, result) {
- result = result || [];
-
- // Get max and min of the data
- var data = this.data,
- max = this.minValue; // Set first value
- for(var i = iMinX; i <= iMaxX; i++){
- for(var j = iMinY; j <= iMaxY; j++){
- var height = data[i][j];
- if(height > max){
- max = height;
- }
- }
- }
-
- result[0] = this.minValue;
- result[1] = max;
-};
-
-/**
- * Get the index of a local position on the heightfield. The indexes indicate the rectangles, so if your terrain is made of N x N height data points, you will have rectangle indexes ranging from 0 to N-1.
- * @method getIndexOfPosition
- * @param {number} x
- * @param {number} y
- * @param {array} result Two-element array
- * @param {boolean} clamp If the position should be clamped to the heightfield edge.
- * @return {boolean}
- */
-Heightfield.prototype.getIndexOfPosition = function (x, y, result, clamp) {
-
- // Get the index of the data points to test against
- * A plane, facing in the Z direction. The plane has its surface at z=0 and everything below z=0 is assumed to be solid plane. To make the plane face in some other direction than z, you must put it inside a RigidBody and rotate that body. See the demos.
- * The number of solver iterations determines quality of the constraints in the world. The more iterations, the more correct simulation. More iterations need more computations though. If you have a large gravity force in your world, you will need more iterations.
- * @property iterations
- * @type {Number}
- * @todo write more about solver and iterations in the wiki
- */
- this.iterations = 10;
-
- /**
- * When tolerance is reached, the system is assumed to be converged.
- * @property tolerance
- * @type {Number}
- */
- this.tolerance = 1e-7;
-}
-GSSolver.prototype = new Solver();
-
-var GSSolver_solve_lambda = []; // Just temporary number holders that we want to reuse each solve.
-var GSSolver_solve_invCs = [];
-var GSSolver_solve_Bs = [];
-GSSolver.prototype.solve = function(dt,world){
- var iter = 0,
- maxIter = this.iterations,
- tolSquared = this.tolerance*this.tolerance,
- equations = this.equations,
- Neq = equations.length,
- bodies = world.bodies,
- Nbodies = bodies.length,
- h = dt,
- q, B, invC, deltalambda, deltalambdaTot, GWlambda, lambdaj;
-
- // Update solve mass
- if(Neq !== 0){
- for(var i=0; i!==Nbodies; i++){
- bodies[i].updateSolveMassProperties();
- }
- }
-
- // Things that does not change during iteration can be computed once
- var invCs = GSSolver_solve_invCs,
- Bs = GSSolver_solve_Bs,
- lambda = GSSolver_solve_lambda;
- invCs.length = Neq;
- Bs.length = Neq;
- lambda.length = Neq;
- for(var i=0; i!==Neq; i++){
- var c = equations[i];
- lambda[i] = 0.0;
- Bs[i] = c.computeB(h);
- invCs[i] = 1.0 / c.computeC();
- }
-
- if(Neq !== 0){
-
- // Reset vlambda
- for(var i=0; i!==Nbodies; i++){
- var b=bodies[i],
- vlambda=b.vlambda,
- wlambda=b.wlambda;
- vlambda.set(0,0,0);
- if(wlambda){
- wlambda.set(0,0,0);
- }
- }
-
- // Iterate over equations
- for(iter=0; iter!==maxIter; iter++){
-
- // Accumulate the total error for each iteration.
- * Currently / last used timestep. Is set to -1 if not available. This value is updated before each internal step, which means that it is "fresh" inside event callbacks.
- * @property {Number} dt
- */
- this.dt = -1;
-
- /**
- * Makes bodies go to sleep when they've been inactive
- * @property allowSleep
- * @type {Boolean}
- */
- this.allowSleep = false;
-
- /**
- * All the current contacts (instances of ContactEquation) in the world.
- * @property contacts
- * @type {Array}
- */
- this.contacts = [];
- this.frictionEquations = [];
-
- /**
- * How often to normalize quaternions. Set to 0 for every step, 1 for every second etc.. A larger value increases performance. If bodies tend to explode, set to a smaller value (zero to be sure nothing can go wrong).
- * @property quatNormalizeSkip
- * @type {Number}
- */
- this.quatNormalizeSkip = 0;
-
- /**
- * Set to true to use fast quaternion normalization. It is often enough accurate to use. If bodies tend to explode, set to false.
- if (performance.timing && performance.timing.navigationStart){
- nowOffset = performance.timing.navigationStart;
- }
- performance.now = function(){
- return Date.now() - nowOffset;
- };
-}
-
-var step_tmp1 = new Vec3();
-
-/**
- * Step the physics world forward in time.
- *
- * There are two modes. The simple mode is fixed timestepping without interpolation. In this case you only use the first argument. The second case uses interpolation. In that you also provide the time since the function was last used, as well as the maximum fixed timesteps to take.
- *
- * @method step
- * @param {Number} dt The fixed time step size to use.
- * @param {Number} [timeSinceLastCalled] The time elapsed since the function was last called.
- * @param {Number} [maxSubSteps=10] Maximum number of fixed steps to take per function call.