هذه المادة لديها الكثير من الماء.

"لقد بدأنا في تطوير لعبة جديدة ، ونحن بحاجة إلى ماء بارد. هل يمكنك فعل هذا؟


- سألني. "نعم ، لا شك! أجبته بالطبع ، لكن صوتي ارتجف غادرًا. "وكذلك على الوحدة؟" - وأصبح من الواضح لي أنه كان هناك الكثير من العمل في المستقبل.

لذلك ، بعض الماء. حتى تلك اللحظة لم أرَ الوحدة ، تمامًا مثل C # ، لذلك قررت أن أقدم نموذجًا أوليًا على الأدوات التي أعرفها: C ++ و DX9. ما عرفته وتمكنت من ممارسته في ذلك الوقت كان القوام التمرير من القواعد الطبيعية لتشكيل السطح ، ورسم خرائط الإزاحة البدائية بناءً عليها. على الفور كان من الضروري تغيير كل شيء على الاطلاق. شكل الرسوم المتحركة واقعية من سطح الماء. معقد (بقوة) التظليل. جيل رغوة. نظام LOD تعلق على الكاميرا. بدأت في البحث عن معلومات على الإنترنت حول كيفية القيام بكل هذا.

النقطة الأولى ، بالطبع ، كانت فهم جيري تيسندورف لمحاكاة مياه المحيط .

لم يُعطِ لي الكثير من أجهزة الاستدعاء الأكاديمية التي تحتوي على مجموعة من الصيغ الشاذة ، لذا بعد بضع قراءات لم أفهم شيئًا يذكر. كانت المبادئ العامة واضحة: يتم إنشاء كل إطار بواسطة خريطة ارتفاع باستخدام Fast Fourier Transform ، والتي ، كدالة للوقت ، تغير شكلها بسلاسة لتشكل سطحًا مائيًا واقعيًا. ولكن كيف وماذا لحساب لم أكن أعرف. لقد بحثت ببطء في حكمة حساب FFT على التظليل في D3D9 ، والكود المصدري مع مقالة في مكان ما في براري الإنترنت ، والتي حاولت أن أجدها لمدة ساعة ، ولكن دون جدوى (لسوء الحظ) ، ساعدني حقًا. تم الحصول على النتيجة الأولى (مخيفة كحرب نووية):


بدء النجاحات سعيدة ، وبدأ نقل المياه إلى الوحدة مع الانتهاء منها.

تم طرح العديد من المتطلبات للمياه في اللعبة حول المعارك البحرية:

  • نظرة واقعية. جميلة مثل الأفرع القريبة والبعيدة ، رغوة ديناميكية ، مبعثر ، إلخ.
  • دعم لمختلف الظروف الجوية: الهدوء والعواصف والظروف المتوسطة. تغيير الوقت من اليوم.
  • فيزياء طفو السفن على سطح مقلد ، كائنات عائمة.
  • نظرًا لأن اللعبة متعددة اللاعبين ، يجب أن تكون المياه هي نفسها لجميع المشاركين في المعركة.
  • الرسم السطحي: المناطق المرسومة من رحلة النوى الطائرة ، ورغوة من دخول النوى في الماء.

علم الهندسة


تقرر بناء هيكل مشابه للربع ، مع مركز حول الكاميرا ، يتم إعادة بنائه على نحو متقن عندما يتحرك المراقب. لماذا منفصلة؟ إذا قمت بنقل الشبكة بسلاسة مع الكاميرا أو استخدام رفض مساحة الشاشة كما في المقالة تقديم المياه في الوقت الفعلي - تقديم مفهوم الشبكة المسقطة ، ثم في الخطط طويلة الأجل ، بسبب الدقة غير الكافية للشبكة الهندسية ، فإن المضلعات "ستقفز" للأعلى و إلى أسفل. هذا مذهل جدا. الصورة تموج. للتغلب على هذا ، يجب على المرء إما زيادة دقة مضلع شبكة المياه بشكل كبير ، أو "تسطيح" الهندسة على مسافات طويلة ، أو إنشاء المضلعات وتحريكها بحيث لا تكون هذه التحولات مرئية. مياهنا تقدمية (الكالينجيون) واخترت المسار الثالث. كما هو الحال في أي تقنية مماثلة (خاصة مألوفة لكل من أنشأ التضاريس في الألعاب) ، فأنت بحاجة إلى التخلص من تقاطعات T على حدود انتقالات مستويات التفاصيل. لحل هذه المشكلة ، في البداية يتم حساب 3 أنواع من الكواد مع معلمات التغطية بالفسيفساء المعينة:



النوع الأول هو تلك الكواد التي ليست انتقالات إلى تفاصيل أقل. لا يحتوي أي من الجانبين على عدد مخفض من القمم يبلغ ضعفين. النوع الثاني هو الحدود ، ولكن ليس الكواد الزاوي. النوع الثالث هو الكواد الحدود الزاوي. يتم إنشاء شبكة المياه النهائية عن طريق تدوير وتحجيم هذه الأنواع الثلاثة من الشبكات.

هذه هي الطريقة التي تظهر بها لون مختلف من مستويات المياه LOD.


تُظهر الإطارات الأولى اتصال مستويين مختلفين من التفاصيل.

الفيديو كإطار مليء بالكواد المياه:


اسمحوا لي أن أذكركم بأن الأمر كان منذ زمن طويل (وليس صحيحًا). الآن يمكن تحقيق المزيد من المرونة والمرونة على GPU (GPU Pro 5. Quadtrees على GPU). وسوف يتم السحب في مكالمة سحب واحدة ، ويمكن لفسيفساء التغطية رفع التفاصيل.

في وقت لاحق ، انتقل المشروع إلى D3D11 ، لكن الأيدي لم تصل إلى ترقية هذا الجزء من عرض المحيط.

الجيل الموجي


لهذا نحن بحاجة إلى تحويل فورييه السريع. من أجل الدقة المحددة (الضرورية) لنسيج الموجة (في الوقت الحالي ، دعنا نسميها ، سأشرح ما هي البيانات المخزنة هناك) ، ونحن نعد البيانات الأولية باستخدام المعلمات التي حددها الفنانون (القوة واتجاه الرياح واعتماد الموجة على اتجاه الرياح وغيرها). كل هذا يجب أن تغذي الصيغ ما يسمى. فيليبس الطيف نقوم بتعديل البيانات الأولية التي تم الحصول عليها لكل إطار مع الأخذ في الاعتبار الوقت وننفذ FFT عليها. في الخرج ، نحصل على تبليط نسيج في جميع الاتجاهات التي تحتوي على إزاحة رؤوس الشبكة المسطحة. لماذا ليس مجرد خريطة للارتفاع؟ إذا قمت بتخزين الإزاحة في الارتفاع فقط ، فستكون النتيجة كتلة "محتدمة" غير واقعية ، تشبه البحر عن بُعد فقط:


إذا أخذنا في الاعتبار عمليات التشريد للإحداثيات الثلاثة ، سيتم إنشاء موجات واقعية "حادة" جميلة:


واحد الملمس المتحركة ليست كافية. التجانب مرئي ، وليس تفاصيل كافية في المستقبل القريب. نحن نأخذ الخوارزمية الموصوفة ونصنع واحدة ، ولكننا ننتج 3 قوام متناسق. الأول هو الأمواج الكبيرة. يحدد الشكل الموجي الأساسي ويستخدم للفيزياء. والثاني هو موجات متوسطة. وأخيرا ، أصغر. 3 مولدات FFT (الخيار الرابع هو المزيج النهائي):


يتم تعيين المعلمات من الطبقات بشكل مستقل عن بعضها البعض ، ويتم خلط القوام الناتجة في تظليل المياه في الموجي النهائي. بالتوازي مع الإزاحة ، يتم أيضًا إنشاء خرائط طبيعية لكل طبقة.

يتم ضمان "توحيد" المياه في جميع المشاركين في القتال من خلال تزامن المعلمات المحيط في بداية المعركة. يتم نقل هذه المعلومات بواسطة الخادم إلى كل عميل.

نموذج الطفو الجسدي


لأنه كان من الضروري جعل ليس فقط صورة جميلة ، ولكن أيضا السلوك واقعية للسفن. ومع الأخذ في الاعتبار حقيقة أن البحر العاصف (الأمواج الكبيرة) يجب أن يكون حاضراً في اللعبة ، فإن المهمة الأخرى التي يتعين حلها تتمثل في ضمان ازدهار الأجسام على سطح البحر المتولد. أولاً ، حاولت أن أجعل GPU يعيد قراءة نسيج الموجة. ولكن ، بعد أن أصبح من الواضح أن جميع فيزياء القتال البحري يجب أن تتم على الخادم ، فإن البحر ، أو بالأحرى طبقته الأولى ، التي تحدد الشكل الموجي ، يجب أيضًا قراءتها على الخادم (وعلى الأرجح ، لا يوجد سريع و / أو GPU المتوافق) ، تقرر كتابة نسخة وظيفية كاملة لمولد GPU FFT على وحدة المعالجة المركزية في شكل مكون إضافي C ++ أصلي لـ Unity. لم أطبق خوارزمية FFT بنفسي واستخدمتها في مكتبة Intel Performance Primitives (IPP). ولكن تم تنفيذ جميع عمليات ربط نتائج البحث وتوثيقها ، متبوعة بالتحسين على SSE وموازنة المواضيع. وشمل ذلك إعداد مجموعة البيانات ل FFT لكل إطار ، والتحويل النهائي للقيم المحسوبة إلى خريطة إزاحة الموجة.

كان هناك سمة أخرى مثيرة للاهتمام من الخوارزمية ، والتي كانت تستند إلى متطلبات فيزياء المياه. ما هو مطلوب هو الحصول على ارتفاعات موجات بسرعة عند نقطة معينة في العالم. إنه منطقي ، لأن هذا هو الأساس لبناء الطفو لأي كائن. ولكن ، نظرًا لأن ناتج معالج FFT نحصل على تعويض ، وليس خريطة ارتفاع ، فإن الاختيار المعتاد من النسيج لم يمنحنا ارتفاع الموجة عند الضرورة. للبساطة ، والنظر في الخيار 2D:



لتشكيل موجة ، تحتوي texels (عناصر النسيج التي تظهرها الخطوط العمودية) على متجه (أسهم) يحدد إزاحة قمة الرأس للشبكة المسطحة (النقاط الزرقاء) في اتجاه موضعها النهائي (طرف السهم). لنفترض أننا نأخذ هذه البيانات ونحاول أن نستخلص منها ارتفاع الماء عند نقطة الاهتمام بالنسبة لنا. على سبيل المثال ، نحتاج إلى معرفة الارتفاع عند hB. إذا أخذنا texel vector tB ، فسنحصل على إزاحة إلى نقطة بالقرب من hC ، والتي يمكن أن تكون مختلفة تمامًا عما نحتاج إليه. هناك خياران لحل هذه المشكلة: عند كل طلب ارتفاع ، تحقق من مجموعة texels المجاورة حتى نعثر على خيار له تعويض عن موضع الاهتمام بالنسبة لنا. في مثالنا ، نجد أن texel tA يحتوي على أقرب إزاحة. ولكن هذا النهج لا يمكن أن يسمى بسرعة. مسح دائرة نصف قطرها texel غير واضح ما حجم (وما إذا كان البحر العاصف أو الهدوء ، يمكن أن تختلف عمليات النزوح بشكل كبير) يمكن أن يستغرق وقتا طويلا.

الخيار الثاني - بعد حساب خريطة الإزاحة ، قم بتحويلها إلى خريطة ارتفاع باستخدام نهج الانتثار. هذا يعني أنه بالنسبة لكل ناقل متجه ، نكتب ارتفاع الموجة التي تحددها إلى النقطة التي يتم فيها نقلها. ستكون هذه مجموعة بيانات منفصلة ، والتي سيتم استخدامها للحصول على الارتفاع عند نقطة الاهتمام. باستخدام التوضيح لدينا ، سوف تحتوي الخلية tB على الارتفاع hB الذي تم الحصول عليه من المتجه tA → hB. هناك ميزة واحدة أخرى. لن تحتوي الخلية tA على قيمة صالحة ، حيث لا يوجد ناقل متجه إليها. لملء هذه "الثقوب" ، يتم إنشاء مقطع لملئها بالقيم المجاورة.

هكذا يبدو الأمر إذا قمت بتصور عمليات التشريد باستخدام ناقلات (أحمر - إزاحة كبيرة ، خضراء - صغيرة):


الباقي بسيط. تم تعيين الطائرة من خط الماء الشرطي للسفينة. على ذلك ، يتم تحديد شبكة مستطيلة من نقاط العينة ، والتي تحدد أماكن تطبيق القوى التي تخرج من الماء للسفينة. ثم لكل نقطة نتحقق مما إذا كانت تحت الماء أو لا تستخدم خريطة ارتفاع المياه الموضحة أعلاه. إذا كانت النقطة تحت الماء ، فقم بتطبيق القوة الرأسية حتى جسم الفيزياء في الجسم في هذه المرحلة ، مع قياس المسافة من النقطة إلى سطح الماء. إذا فوق الماء ، فلن نفعل شيئًا ، فالجاذبية ستفعل كل شيء من أجلنا. في الواقع ، هناك صيغ أكثر تعقيدًا قليلاً (كل ذلك من أجل ضبط سلوك السفينة بدقة) ، لكن المبدأ الأساسي هو هذا. في مقطع التصور المرئي أدناه ، تعد المكعبات الزرقاء هي مواقع العينات ، والخطوط الموجودة أسفلها هي حجم القوة الخارجة من الماء.


في تنفيذ الخادم هناك نقطة أخرى مثيرة للاهتمام الأمثل. ليست هناك حاجة لمحاكاة المياه المختلفة لحالات القتال المختلفة إذا كانت تمر في نفس الظروف الجوية (نفس معلمات محاكاة FFT). لذلك كان القرار المنطقي هو إنشاء مجموعة من أجهزة المحاكاة ، والتي تفي بها الوحدات القتالية بطلبات الحصول على المياه المحاكاة باستخدام المعلمات المحددة. إذا كانت المعلمات هي نفسها من عدة حالات ، فإن نفس الماء سيعود إليها. يتم تطبيق ذلك باستخدام Memor Mapped File API. عندما يتم إنشاء محاكي FFT ، فإنه يتيح الوصول إلى البيانات الخاصة به عن طريق تصدير واصفات الكتل الضرورية. مثيل الخادم ، بدلاً من تشغيل جهاز محاكاة حقيقي ، يطلق "دمية" تعطي ببساطة البيانات المفتوحة بواسطة هذه الواصفات. كانت هناك بعض الأخطاء مضحك المتعلقة بهذه الوظيفة. نظرًا لوجود أخطاء في حساب المرجع ، تم تدمير جهاز المحاكاة ، لكن الملف المعين للذاكرة قيد التشغيل بينما يكون هناك مقبض واحد على الأقل مفتوحًا. توقفت البيانات عن التحديث (لا يوجد جهاز محاكاة) والماء "توقف".

من جانب العميل ، نحتاج إلى معلومات حول الشكل الموجي لحساب تغلغل النوى في الموجة ولعب أنظمة الجسيمات والرغوة. يتم احتساب الأضرار على الخادم وهناك أيضًا من الضروري تحديد ما إذا كان النواة قد دخلت الماء بشكل صحيح (يمكن للموجة إغلاق السفينة ، خاصة في العواصف). هنا من الضروري بالفعل القيام بتتبع خريطة الارتفاع عن طريق القياس كما هو الحال في رسم خرائط المنظر أو تأثيرات SSAO.

تظليل


من حيث المبدأ ، كما هو الحال في أي مكان آخر. الانعكاسات ، الانكسارات ، الانتثار تحت السطحي عجن ماكر ، مع الأخذ في الاعتبار عمق القاع ، ونحن نأخذ في الاعتبار تأثير فريسنل ، ونحن نعتبر براق. نحن نعتبر نثر التلال تبعًا لموقف الشمس. يتم إنشاء الرغوة على النحو التالي: إنشاء "بقعة رغوة" على قمم الأمواج (استخدم الطول كمقياس) ، ثم قم بتطبيق البقع المنشأة حديثًا على البقع من الإطارات السابقة مع تقليل شدتها. وبالتالي ، نحصل على تلطيخ لبقع الرغوة في شكل ذيل من قمة موجة جارية.


نستخدم نسيج "البقع" الذي تم الحصول عليه كقناع نخلط بينه فقاعات ، بقع ، وما إلى ذلك. نحصل على نمط ديناميكي إلى حد ما من الرغوة على سطح الأمواج. يتم إنشاء هذا القناع لكل طبقة FFT (أذكرك ، لدينا 3 منهم) ، وفي المزيج النهائي يخلط كل منهم.

الفيديو أعلاه يتصور قناع رغوة. الطبقات الأولى والثانية. أقوم بتعديل معلمات المولد والنتيجة واضحة على النسيج.

وفيديو بحر عاصف أخرق قليلاً. هنا يمكنك أن ترى بوضوح الشكل الموجي ، وقدرات المولد والرغوة:


سحب المياه


استخدام الصورة:



تستخدم ل:

  • علامات ، تصور منطقة توسع النوى.
  • رسم الرغوة عند النقطة التي تضرب فيها النوى الماء.
  • الرغوة أعقاب السفينة
  • ضغط المياه أسفل السفينة لإزالة تأثير الأمواج التي تغمر سطح السفينة والممسك بالمياه.

الحالة الأساسية الواضحة هي التركيب الإسقاطي. تم تنفيذه. ولكن هناك متطلبات إضافية. الأنواع القريبة - صابون بسبب عدم كفاية الدقة (يمكنك الزيادة ، ولكن ليس بشكل غير محدود) ، وأريد أن تكون هذه الرسومات الإسقاطية على الماء مرئية إلى حد بعيد. أين يتم حل نفس المشكلة؟ هذا صحيح ، في الظل (خريطة الظل). كيف يتم حلها هناك؟ إلى اليمين ، خرائط الظل المتتالية (الانقسام الموازي). سنأخذ هذه التكنولوجيا أيضًا في الخدمة ونطبقها على مهمتنا. نحن نكسر إحباط الكاميرا إلى N (3-4 عادة) subfrusts. لكل منها ، نقوم ببناء مستطيل وصف في المستوى الأفقي. لكل مستطيل من هذا القبيل ، نقوم ببناء مصفوفة إسقاط هجائية ونرسم كل الأشياء التي تهم كل من هذه الكاميرات N. ترسم كل كاميرا من هذا القبيل في نسيج منفصل ، وبعد ذلك ، في ظلال المحيط ، نجمعها في صورة إسقاطية واحدة صلبة.


لذلك وضعت طائرة ضخمة مع نسيج العلم على البحر:



إليك ما تحتويه الانقسامات:



بالإضافة إلى الصور المعتادة ، من الضروري رسم قناع إضافي من الرغوة (لآثار السفن وأماكن إصابة النوى) بنفس الطريقة تمامًا ، بالإضافة إلى قناع لعصر المياه تحت السفن. هذا هو الكثير من الكاميرات والعديد من الممرات. في البداية كانت تعمل بكبح شديد ، ولكن بعد التبديل إلى D3D11 ، باستخدام "الانتشار" للهندسة في التظليل الهندسي ورسم كل نسخة في هدف تجسيد منفصل عبر SV_RenderTergetArrayIndex ، كان من الممكن تسريع هذا التأثير بشكل كبير.

تحسينات وترقيات


D3D11 هي أيدي حرة للغاية في لحظات عديدة. بعد التحول إليها و Unity 5 ، صنعت مولد FFT على تظليل حساب. بصريا ، لم يتغير شيء ، لكنه أصبح أسرع قليلاً. أعطت ترجمة الخطأ في تقدير ملمس الانعكاسات من كاميرا منفصلة كاملة إلى تقنية Screen Space Planar Reflections دفعة جيدة في الأداء. كتبت عن تحسين الأجسام السطحية للمياه أعلاه ، لكن يدي لم تصل إلى نقل الشبكة إلى وحدة معالجة الرسومات Quadtree.

يمكن القيام بالكثير على النحو الأمثل وببساطة. على سبيل المثال ، لا تقم بتسييج الحدائق باستخدام محاكي وحدة المعالجة المركزية ، ولكن ببساطة قم بتشغيل خيار GPU على خادم مزود بجهاز W3P (برنامج) d3d. صفائف البيانات ليست هناك كبيرة جدا.

حسنا ، بشكل عام ، بطريقة ما. في الوقت الذي بدأ فيه التطوير ، كان كل شيء حديثًا وباردًا. لقد أصبح الآن غير صالح في بعض الأماكن. هناك المزيد من المواد المتاحة ، حتى أن هناك مثيل مماثل لـ github: Crest . معظم الألعاب التي لديها البحار تستخدم نهجا مماثلا.

Source: https://habr.com/ru/post/ar451604/


All Articles