إن غرف الكمبيوتر ثلاثية الأبعاد التي تم تقديمها باستخدام WebGL ليست جديدة الآن، والغرض الرئيسي من هذه المقالة هو شرح مشكلة العين والمركز في غرف الكمبيوتر ثلاثية الأبعاد، والتي تم استخدامها في المشروع بعد التفكير فيها لفترة من الوقت أشعر أن هذا المثال يلبي متطلباتي بشكل أفضل، لذلك أستخدمه كسجل.
الاداءاتيعد العرض التوضيحي لغرفة الكمبيوتر ثلاثية الأبعاد جيدًا جدًا، وهو جميل، والتفاعلات الأساسية مرضية، فلنرى كيفية تنفيذه.
توليد الكود تحديد الطبقةأولاً، افتح ملف js المقابل واحدًا تلو الآخر من مسار js المسمى في ملف Index.html. يتم تخصيص فئة Editor.Server في server.js ويتم إنشاؤها بواسطة وظيفة ht.Default.def المغلفة بواسطة HT (لاحظ أن الفئة التي تم إنشاؤها الاسم هو Editor لا يمكن استبدال المحرر الموجود أمام .Server بـ E):
ht.Default.def('Editor.Server', Object, {// المعلمة الأولى هي اسم الفئة. إذا كانت سلسلة، فسيتم تسجيلها تلقائيًا في classMap الخاص بـ HT؛ المعلمة الثانية هي الفئة الأصلية المراد توريثها بواسطة هذه الفئة؛ المعلمة الثالثة هي إعلان الأساليب والمتغيرات addToDataModel: function(dm) { // أضف العقدة إلى حاوية البيانات dm.add(this._node); العقدة من خلال الإضافة تمت إضافة الطريقة إلى حاوية البيانات}, setHost: function() { // تعيين الامتزاز this._node.setHost.apply(this._node, الوسيطات }, s3: function() {// تعيين حجم العقدة this._node .s3.apply(this._node, الوسيطات }, setElevation: function()); {// التحكم في موضع المحور y لنظام الإحداثيات ثلاثي الأبعاد حيث يقع الموضع المركزي للعقدة البدائية this._node.setElevation.apply(this._node,حجج }});
إنشاء فئة Editor.Server
يمكن لهذه الفئة إنشاء عقدة ht.Node وتعيين لون العقدة والملمس الأمامي:
var S = E.Server = function(obj) {// مكون الخادم var color = obj.color, frontImg = obj.frontImg var العقدة = this._node = new ht.Node();// إنشاء عقدةNode.s ({// اضبط نمط العقدة على اختصار setStyle 'all.color': color،// اضبط لون الجوانب الستة للعقدة 'front.image': frontImg // قم بتعيين الصورة في مقدمة العقدة});};
بهذه الطريقة، يمكنني مباشرة إنشاء كائن مكون خادم جديد حيث أحتاج إلى إنشاء مكون الخادم، ويمكنني استدعاء setHost مباشرة والوظائف الأخرى التي ذكرناها أعلاه، والتي سنستخدمها قريبًا.
بعد ذلك، قم بإنشاء فئة الخزانة Editor.Cabinet. تشبه الطريقة طريقة تعريف فئة Editor.Server أعلاه:
ht.Default.def('Editor.Cabinet', Object, { addToDataModel: function(dm) { dm.add(this._door); dm.add(this._node); this._serverList.forEach(function(s) { s.addToDataModel(dm }); this._node.p3.apply(this._node,حجج);// قم بتعيين الإحداثيات ثلاثية الأبعاد للعقدة}});
إنشاء فئة Editor.Cabinet
هذه الفئة أكثر تعقيدًا نسبيًا من فئة مكون خادم Editor.Server السابقة، حيث تقوم هذه الفئة بإنشاء هيكل الخزانة وباب الخزانة ومكونات الخادم داخل الخزانة:
var C = E.Cabinet = function(obj) { var color = obj.color,doorFrontImg = obj.doorFrontImg,doorBackImg = obj.doorBackImg, s3 = obj.s3 var العقدة = this._node = new ht.Node(); ; // الخزانةnode.s3(s3);//اضبط حجم العقدة على setSize3d Node.a('cabinet', this);// تخصيص خصائص الخزانة Node.s({// اضبط نمط العقدة على setStyle 'all.color': color,// اضبط لون الجوانب الستة للعقدة 'front.visible': false// اضبط ما إذا كان الجزء الأمامي من العقدة مرئيًا}); ['icon thermometer'], // مصفوفة تحتوي على سلاسل متعددة، كل سلسلة تتوافق مع صورة أو متجه (مسجل من خلال ht.Default.setImage) الوجه: 'top'، // القيمة الافتراضية هي الأمامية، رمز الاتجاه ثلاثي الأبعاد ، القيم المتاحة هي اليسار|اليمين|الأعلى|الأسفل|الأمام|الخلف|الموضع المركزي: 17, // تحديد موضع الأيقونات للتدوير التلقائي: 'y', // القيمة الافتراضية خاطئة، سواء كان الرمز يواجه اتجاه العين تلقائيًا في ثلاثي الأبعاد t3: [0, 16, 0], // القيمة الافتراضية غير محددة، إزاحة الرمز ثلاثي الأبعاد، التنسيق هو [x ,y,z] العرض: 37,// حدد عرض كل رمز، الافتراضي يعتمد على العرض عند تسجيل ارتفاع الصورة: 32,// حدد ارتفاع كل رمز، الافتراضي هو بناءً على الارتفاع عند تسجيل حجم نسيج الصورة: 4, // القيمة الافتراضية هي 2. تمثل هذه القيمة مضاعفات الخريطة الفعلية التي تم إنشاؤها بواسطة الذاكرة. لا ينبغي تعيينها كبيرة جدًا وإلا فإنها ستؤثر على الأداء visual: { func: function() { return !! E.alarmVisible; }}// يشير إلى ما إذا كان سيتم عرضه }); ht.DoorWindow();// باب الخزانةdoor.setWidth(s3[0]);// اضبط طول العنصر الرسومي في اتجاه المحور السيني في الهيكل ثلاثي الأبعادdoor.setHeight(1);// اضبط عنصر رسومي في المحور z للطوبولوجيا ثلاثية الأبعاد الطولdoor.setTall(s3[1]);// التحكم في طول العقدة البدائية على المحور ydoor.setElevation(0);// تعيين الإحداثي y لمركز البدائية في باب نظام الإحداثيات ثلاثي الأبعاد .setY(s3[2] * 0.5)؛// اضبط موضع العقدة على المحور الصاديdoor.setHost(node);// اضبط باب الامتزاز ({// اضبط نمط العقدة setStyle 'all.color': color,/ / اضبط لون الجوانب الستة للعقدة "front.image":doorFrontImg، // اضبط الصورة الأمامية للعقدة "front.transparent": صحيح، // اضبط ما إذا كان الوجه الأمامي للعقدة شفافًا "للخلف" .image':doorBackImg, // قم بتعيين الصورة على الجزء الخلفي من العقدة 'back.uv': [1,0, 1,1, 0,1, 0,0],// قم بتخصيص خريطة الأشعة فوق البنفسجية خلف العقدة إذا كانت فارغة، فالقيمة الافتراضية [0,0, 0,1, 1,1, 1 ,0] ' dw.axis': 'right'// قم بتعيين محور الدوران لعمليات توسيع وإغلاق عنصر DoorWindow، والقيم المحتملة هي left|right|top|bottom|v|h }); var serverList = this ._serverList = []; max = 6, list = E.randomList(max, Math.floor(Math.random() * (max - 2)) + 2); // وظيفة للحصول على أرقام عشوائية معلنة في خادم global.js var, h = s3 [0] / 4; list.forEach(function(r) { var server = new E.Server({ // لون مكون الخادم: 'rgb(51,49,49)', frontImg: "مكون الخادم جيد" }); server.s3(s3[0] - 2, h, s3[2] - 4);// تعيين حجم العقدة server.setElevation((r - max * 0.5) * (h + 2 ));// تعيين إحداثيات النقطة المركزية للعقدة على المحور الصادي server.setHost(node);// تعيين امتزاز العقدة serverList.push(server);// إلى serverList أضف عقدة الخادم في });};
الشيء الوحيد الذي لم يتم ذكره في الكود أعلاه هو وظيفة Editor.randomList. تم الإعلان عن هذه الوظيفة في ملف global.js وتم تعريفها على النحو التالي:
var E = window.Editor = { leftWidth: 0, topHeight: 40, RandomList: function(max, size) { var list = [], run; while (list.length < size) { run = Math.floor(Math. Random() * max); if (list.indexOf(ran) >= 0) continue;
حسنًا، الآن بعد أن تم إنشاء الفئات لكل جزء من المشهد، يجب علينا إنشاء المشهد ثم تجميع هذه البدائيات فيه!
خلق المشهديجب على الطلاب الذين هم على دراية بها أن يعلموا أن استخدام HT لإنشاء مشهد ثلاثي الأبعاد يتطلب فقط مكونًا ثلاثي الأبعاد جديدًا، ثم يضيفون المشهد إلى النص من خلال وظيفة addToDOM:
var g3d = E.main = new ht.graph3d.Graph3dView(); // مشهد ثلاثي الأبعاد
يقوم ملف main.js بشكل أساسي ببعض العناصر الضرورية في المشهد ثلاثي الأبعاد، مثل الجدران والأرضيات والأبواب ومكيفات الهواء ومواضع التوليد والتفريغ لجميع الخزانات، بالإضافة إلى الأجزاء التفاعلية المهمة جدًا.
لن أقوم بنشر الكود الخاص بإنشاء الجدران والأرضيات والأبواب ومكيفات الهواء والخزائن. إذا كنت مهتمًا، فيرجى التحقق من الكود بنفسك. نتحدث هنا بشكل أساسي عن النقر المزدوج على الخزانة وأي كائنات متعلقة بالخزانة (. أبواب الخزانة، معدات الخادم) لإنشاء ثلاثي الأبعاد، سينتقل مركز خط رؤية الكاميرا إلى موضع معين أمام الخزانة التي تم النقر عليها نقرًا مزدوجًا، وهذه الحركة سلسة جدًا لم أكن أجيدها من قبل، لذلك اعتقدت لقد تحدثنا عن هذا الجزء لفترة طويلة، وأشرنا أخيرًا إلى طريقة تنفيذ هذا العرض التوضيحي.
لكي تتمكن من ضبط العين والمركز بشكل متكرر، يتم تغليف المحتوى المقابل لإعداد هاتين المعلمتين في طريقتي setEye وsetCenter، تشبه طريقة setCenter طريقة setEye ولن يتم تكرارها هنا:
// اضبط موضع العين var setEye = function(eye, Finish) { if (!eye) return var e = g3d.getEye().slice(0),// احصل على قيمة العين الحالية dx = eye[0] - e[0], dy = العين[1] - e[1], dz = العين[2] - e[2]; // بدء انتقال للرسوم المتحركة بمقدار 500 مللي ثانية ht.Default.startAnim({ المدة: 500، التخفيف: التخفيف، // وظيفة تخفيف الرسوم المتحركة FinishFunc: Finish || function() {}، // الوظيفة التي يتم استدعاؤها بعد انتهاء الحركة: function(v, t) {// قم بتعيين الرسوم المتحركة v لتمثيل تخفيف التمرير (t) القيمة بعد تشغيل الوظيفة، تمثل t تقدم الرسوم المتحركة الحالية [0~1]، وتستند تغييرات السمات العامة إلى المعلمة v g3d.setEye([ // اضبط العين في المشهد ثلاثي الأبعاد قيمة العين عبارة عن مصفوفة، تتوافق مع قيم المحاور x وy وz على التوالي e[0] + dx * v, e[1] + dy * v, e[2] + dz * v ]); } }) ;};
حقيقة أنني لم أعلن بشكل متكرر عن وظيفة setCenter لا تعني أن هذه الوظيفة ليست مهمة، بل على العكس من ذلك، فإن هذه الوظيفة تلعب دورًا حاسمًا في عملية تحريك خط البصر. وظيفة setEye المذكورة أعلاه تعادل رغبتي للمشي أمام الموضع المستهدف (على الأقل أحدد أنه يستخدم لهذا الغرض)، بينما sCenter التعريف هو تحريك بصري إلى موضع الهدف (على سبيل المثال، أستطيع أن أقف في وضعي الحالي وأنظر إلى الجسم الموجود خلفي على اليمين، أو أستطيع أن أذهب إلى الخلف على يميني وأقف أمامه) الشيء الذي يجب النظر إليه). إنه مهم جدًا، يرجى تذوقه.
يعد حدث النقر المزدوج بسيطًا، ما عليك سوى الاستماع إلى الحدث المغلف بواسطة HT وتحديد نوع الحدث واتخاذ الإجراءات المقابلة:
g3d.mi(function(e) {// addInteractorListener وظيفة الاستماع للحدث if (e.kind !== 'doubleClickData') // تحديد نوع الحدث ليكون عقدة نقر مزدوج return؛ var data = e.data, p3 ; if (data.a('cabinet')) //Body p3 = data.p3(); else { host = data.getHost(); // احصل على كائن الامتزاز للعقدة التي تم النقر عليها if (host &&) host.a('cabinet')) {// إذا كان كائن الامتزاز عبارة عن خزانة p3 = host.p3(); } } if (!p3) return; موضع الخزانة setEye([p3[0], 211, p3[2] + 247]); // اضبط الموضع الذي ستتحرك فيه العين});شريط التنقل العلوي
عندما رأيت هذا المثال لأول مرة، كنت أفكر، أن هذا الشخص رائع للغاية، لقد كنت أستخدم HT لفترة طويلة، لكنني ما زلت غير قادر على إنشاء مثل هذه التأثيرات الجميلة باستخدام ht.widget.Toolbar عندما نظرت عندها، أدركت أن هذا كان في الواقع يستخدم HT. إنه مصنوع بالشكل، إنه لأمر مدهش، أنا غبي جدًا.
var form = E.top = new ht.widget.FormPane(); // مكون النموذج العلوي form.setRowHeight(E.topHeight);// اضبط ارتفاع الصف form.setVGap(-E.topHeight);// اضبط التباعد الأفقي لمكون النموذج على قيمة سالبة لارتفاع الصف للاحتفاظ به صفوف متعددة في نفس الموضع Line form.setVPadding(0);// قم بتعيين الجزء العلوي من النموذج والتباعد بين الجزء العلوي ومحتوى المكونform.addRow([null, {// أضف صفًا من المكونات إلى النموذج. المعلمة الأولى هي مصفوفة من العناصر. يمكن أن تكون العناصر عبارة عن سلاسل، أو معلومات معلمات المكونات الموضحة بتنسيق json، أو عناصر html، أو صورة فارغة: { icon: './symbols/ inputBG.json '، امتداد: 'centerUniform' }}]، [40، 260]);// المعلمة الثانية عبارة عن مصفوفة من معلومات العرض لكل عنصر. تمثل قيمة العرض الأكبر من 1 قيمة مطلقة ثابتة، كما يمكن أن تكون قيمة العرض أقل من أو تساوي 1 قيمة نسبية مزيج من 80+0.3form.addRow([null, null , {id: 'searchInput', textField: {}}, { element: 'نظام الإدارة المرئية لغرفة الكمبيوتر'، اللون: 'أبيض'، الخط: '18px arial ، بلا الرقيق'}، خالية، { زر: { // التسمية: 'ViewChange'، الرمز: './symbols/viewChange.json'، الخلفية: خالية، حدد الخلفية: 'rgb(128,128,128)'، borderColor: 'rgba(0, 0, 0, 0 ) '، عند النقر: function() { E.focusTo() } }}, null, { Button: { // التسمية: 'تنبيه'، أيقونة: './symbols/alarm.json'، قابل للتبديل: صحيح، محدد: خطأ، الخلفية: خالية، حدد الخلفية: 'rgb(128,128,128)'، borderColor: 'rgba(0, 0, 0, 0)'، عند النقر: الوظيفة ( e) { E.setAlarmVisible(this.isSelected()); 42، 218، 300، 0.1، 50، 10، 50، 10])؛
ما ورد أعلاه ممكن فقط، ولكن لم يتم إضافته فعليًا إلى علامة html، مما يعني أنه لا يوجد شيء على الواجهة الآن! لا تنس إضافة مشهد ثلاثي الأبعاد إلى النص عند تحميل الصفحة، ولا تنس إضافة النموذج إلى النص عند تعيين حدث تغيير حجم النافذة، يحتاج النموذج أيضًا إلى التحديث في الوقت الفعلي:
window.addEventListener('load', function() { g3d.addToDOM(); // أضف المشهد ثلاثي الأبعاد إلى النص الأساسي document.body.appendChild(E.top.getView()); // أضف القسم الأساسي للعنصر مكون النموذج أضف إلى النص window.addEventListener('resize', function() {// استمع لأحداث تغيير حجم النافذة E.top.iv();// قم بتحديث القسم الأساسي للنموذج });});
فيما يلي شرح لوظيفة addToDOM، وهي مهمة جدًا لفهم آلية HT. يتم تضمين مكونات HT بشكل عام في حاويات مثل BorderPane وSplitView وTabView. ويتطلب مكون HT الخارجي من المستخدم إضافة عنصر div الأساسي الذي يتم إرجاعه بواسطة getView() يدويًا إلى عنصر DOM الخاص بالصفحة ، عندما يتغير حجم الحاوية الأصلية، إذا كانت الحاوية الأصلية عبارة عن مكونات حاوية محددة مسبقًا لـ HT، مثل BorderPane وSplitView، فستقوم حاوية HT تلقائيًا باستدعاء وظيفة الإبطال للمكون الفرعي بشكل متكرر لإعلام التحديث. ولكن إذا كانت الحاوية الأصلية عبارة عن عنصر html أصلي، فلا يمكن لمكون HT معرفة أنه يحتاج إلى التحديث، لذلك يحتاج مكون HT الأبعد عمومًا إلى الاستماع إلى حدث تغيير حجم النافذة الخاص بالنافذة واستدعاء وظيفة الإبطال للأبعد. المكون للتحديث.
من أجل تسهيل تحميل المكون الخارجي لملء النافذة، تحتوي جميع مكونات HT على وظيفة addToDOM، ومنطق تنفيذها كما يلي، حيث iv هو اختصار يبطل:
addToDOM = function(){ var self = this, view = self.getView(), style = view.style document.body.appendChild(view); // أضف القسم الأساسي للمشهد إلى الجسم style.left = ' 0';// HT يضبط موضع القسم الأساسي لجميع المكونات على style.right = '0'; window.addEventListener('resize', function () { self.iv(); }, false); // استمع إلى الأحداث لتغييرات حجم النافذة وإخطار بتغييرات المكونات وتحديثاتها}
بهذه الطريقة، تنتهي جميع التعليمات البرمجية، ويمكنك النقر بزر الماوس الأيمن للتحقق منها بنفسك، ويمكن الحصول على ملف json المقابل من الشبكة.
ما ورد أعلاه هو المحتوى الكامل لهذه المقالة وآمل أن يكون مفيدًا لدراسة الجميع وآمل أيضًا أن يدعم الجميع شبكة VeVb Wulin.