في السابق ، تم سحب السحب في الألعاب باستخدام نقوش ثنائية الأبعاد عادية ، والتي يتم تدويرها دائمًا في اتجاه الكاميرا ، ولكن في السنوات الأخيرة ، تتيح لك طرازات بطاقة الفيديو الجديدة رسم السحب الصحيحة ماديًا دون حدوث خسائر ملحوظة في الأداء. من المعتقد أن السحب الضخمة في اللعبة جلبت استوديو Guerrilla Games إلى جانب لعبة Horizon Zero Dawn. بالطبع ، كانت هذه السحب قادرة على تقديمها من قبل ، لكن الاستوديو شكل شيئًا يشبه معيار الصناعة لمصادر المصدر والخوارزميات المستخدمة ، والآن أي تطبيق للسحب الحجمي يتوافق بشكل ما مع هذا المعيار.

تنقسم العملية الكاملة لتقديم السحب إلى مراحل ومن المهم الإشارة إلى أن التنفيذ غير الدقيق حتى في حالة إحداها يمكن أن يؤدي إلى عواقب لا تكون واضحة حيث يوجد الخطأ وكيفية إصلاحه ، لذلك يُنصح بإجراء استنتاج تحكمي للنتيجة في كل مرة.
لهجة الخرائط ، إس آر جي بي
قبل البدء في العمل مع الإضاءة ، من المهم القيام بأمرين:
- قبل عرض الصورة النهائية على الشاشة ، طبق على الأقل تعيين أبسط النغمات:
tunedColor=color/(1+color)
يعد ذلك ضروريًا لأن قيم الألوان المحسوبة ستكون أكبر من الوحدة.
- تأكد من أن أداة إزالة الإطارات النهائية التي تقوم بالرسم عليها وعرضها على الشاشة بتنسيق sRGB. إذا كان تنشيط وضع sRGB يمثل مشكلة ، فيمكن إجراء التحويل يدويًا في التظليل:
finalColor=pow(color, vec3(1.0/2.2))
الصيغة مناسبة لمعظم الحالات ، ولكن ليس بنسبة 100 ٪ حسب الشاشة. من المهم أن يتم تحويل sRGB دائمًا إلى آخر.
نموذج الإضاءة
النظر في الفضاء مليئة مسألة شفافة جزئيا من كثافات مختلفة. عندما تمر شعاع الضوء عبر مثل هذه المادة ، فإنها تتعرض لأربعة تأثيرات: الامتصاص ، والانتثار ، والانتثار المضخم والإشعاع الذاتي. يحدث هذا الأخير في حالة العمليات الكيميائية في مادة ما ، ولا يتأثر هنا.
افترض أن لدينا بصيص ضوء يمر عبر المادة من النقطة أ إلى النقطة ب:
امتصاصيخضع الضوء الذي يمر عبر مادة لامتصاص هذه المادة بالذات. يمكن العثور على الجزء غير الممتص من الضوء بواسطة الصيغة:
حيث

- الضوء الباقي عند نقطة الامتصاص

.

- نقطة على الجزء AB على مسافة

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

- جزء من الضوء لم يغير الاتجاه بعد الانتثار عند نقطة ما

.
يجب الجمع بين الامتصاص والتشتت:
وظيفة

يسمى التوهين أو الانقراض. وظيفة

- وظيفة النقل. يوضح مقدار الضوء المتبقي عند المرور من النقطة أ إلى النقطة ب.
فيما يتعلق

و

:

، حيث C ثابتة ، والتي قد يكون لها قيمة مختلفة لكل قناة في RGB ،

هي كثافة متوسطة عند هذه النقطة

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

، تمامًا كما نعرف فقد الضوء من X إلى O - هذا

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

يعني أخذ جزء لا يتجزأ من الكرة ،

- وظيفة المرحلة

- ضوء قادم من الاتجاه

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

- الزاوية بين شعاع الضوء وحزمة المراقبة (أي الزاوية AXO) ،

- القيمة الأولية لشدة الضوء. تلخيص كل ما سبق ، نحصل على الصيغة:
حيث

- الضوء الوارد

- الضوء الذي يصل إلى المراقب.
نحن تعقيد المهمة أكثر من ذلك بقليل. لنفترض أن الضوء ينبعث من ضوء اتجاهي ، أي الشمس:
كل شيء يحدث كما هو الحال في الحالة السابقة ، ولكن عدة مرات. ينتشر الضوء من النقطة A1 في النقطة X1 باتجاه المراقب عند النقطة O ، وينتشر الضوء من النقطة A2 عند النقطة X2 باتجاه المراقب عند النقطة O ، إلخ. نرى أن الضوء الذي يصل إلى المراقب يساوي المجموع:
أو تعبير متكامل أكثر دقة:
من المهم أن نفهم ذلك هنا

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

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

- ارتفاع التحجيم ، ح - الارتفاع الحالي.
حل متكامل بسيط سيكون:
حيث dh هو حجم الخطوة التي يتم أخذ عينة الارتفاع بها.
انظر الآن إلى الشكل واستخدم الصيغة المشتقة في الجزء السابق من "نموذج الإضاءة":
ينظر المراقب من O إلى O. نريد جمع كل الضوء الذي يصل إلى النقاط X1 ، X2 ، ... ، Xn ، منتشرة فيها ، ثم يصل إلى المراقب:
حيث

شدة الضوء المنبعثة من الشمس ،

- الارتفاع في نقطة

. في حالة السماء ، ثابت C ، والتي هي في وظيفة

يشار إليه باسم

.
يمكن أن يكون الحل المتكامل كما يلي:
هذه الصيغة صالحة لكل من نثر رايلي ونثر مي. نتيجة لذلك ، تضيف قيم الضوء لكل من التشتت ببساطة:
تشتت رايلي

(يحتوي على قيم لكل قناة RGB)

النتيجة:
مبعثر مي

(القيم لجميع قنوات RGB هي نفسها)

النتيجة:
عدد العينات لكل قطعة

وعلى الجزء

يمكنك أن تأخذ 32 وما فوق. قطر الأرض 6371000 متر ، والغلاف الجوي 100000 متر.
ما يجب القيام به مع كل هذا:
- في كل بكسل من الشاشة ، نحسب اتجاه المراقب V
- نتخذ موقف المراقب O يساوي {0 ، 6371000 ، 0}
- نجد
نتيجة تقاطع الشعاع الناشئ عند النقطة O واتجاه V والكرة المتمركزة عند النقطة {0،0،0} ونصف قطرها 6471000 - قطاع الخط
تنقسم إلى 32 أقسام متساوية الطول - لكل قسم ، نحسب نثر رايلي ونثر ميا ، وإضافة كل شيء. علاوة على ذلك ، لحساب
سنحتاج أيضًا إلى تقسيم الجزء
32 مؤامرات متساوية في كل حالة.
يمكن قراءتها من خلال متغير ، تزداد قيمته في كل خطوة في الدورة.
النتيجة النهائية:
نموذج سحابة
سنحتاج إلى عدة أنواع من الضوضاء ثلاثية الأبعاد. الأول هو ضوضاء الحركة البركانية الكامنة الكامنة في بيرلين (fBm):
النتيجة لشريحة ثنائية الأبعاد:
والثاني هو الضوضاء fBm ترويض فورونوي.
النتيجة لشريحة ثنائية الأبعاد:
للحصول على ضوضاء fBm المغطاة من Vorley ، تحتاج إلى عكس ضوضاء fBm المغطاة من Voronoj. ومع ذلك ، قمت بتغيير نطاقات القيم قليلاً حسب تقديري:
float fbmTiledWorley3(...) { return clamp((1.0-fbmTiledVoronoi3(...))*1.5-0.25, 0.0, 1.0); }
النتيجة على الفور تشبه الهياكل السحابية:
لالغيوم ، تحتاج إلى الحصول على اثنين من القوام الخاص. الأول بحجم 128 × 128 × 128 وهو مسؤول عن الضوضاء منخفضة التردد ، والثاني بحجم 32 × 32 × 32 وهو مسؤول عن الضوضاء عالية التردد. يستخدم كل نسيج قناة واحدة فقط بتنسيق R8. في بعض الأمثلة ، يتم استخدام 4 قنوات من R8G8B8A8 للنسيج الأول وثلاث قنوات من R8G8B8 للمرة الثانية ، ثم يتم خلط القنوات في تظليل. لا أرى هذه النقطة ، لأن الخلط يمكن أن يتم مقدمًا وبالتالي الحصول على ضربة أكبر في تماسك ذاكرة التخزين المؤقت.
للخلط ، وكذلك في بعض الأماكن ، سيتم استخدام وظيفة remap () التي تقيس القيم من نطاق إلى آخر:
float remap(float value, float minValue, float maxValue, float newMinValue, float newMaxValue) { return newMinValue+(value-minValue)/(maxValue-minValue)*(newMaxValue-newMinValue); }
لنبدأ في تحضير النسيج بضوضاء منخفضة التردد:
R- قناة - الضوضاء fBm بيرلين
G- قناة - البلاط fBm فورلي الضوضاء
B- قناة - أصغر fBm Worley الضوضاء مع نطاق أصغر
A- قناة - الضوضاء fBm taylable فارلي مع نطاق أصغر
يتم الخلط بهذه الطريقة:
finalValue=remap(noise.x, (noise.y * 0.625 + noise.z*0.25 + noise.w * 0.125)-1, 1, 0, 1)
النتيجة لشريحة ثنائية الأبعاد:
الآن تحضير الملمس مع ضوضاء عالية التردد:
R- قناة - البلاط fBm Vorley الضوضاء
G- قناة - أصغر fBm تحجيم الضوضاء Vorley
B- قناة - Varley taylivaya الضوضاء fBm مع نطاق أصغر
finalValue=noise.x * 0.625 + noise.y*0.25 + noise.z * 0.125;
النتيجة لشريحة ثنائية الأبعاد:
نحتاج أيضًا إلى خريطة ثنائية الأبعاد لنسيج الطقس تحدد وجود السحب وكثافتها وشكلها ، اعتمادًا على إحداثيات الفضاء. تم رسمها من قبل الفنانين لضبط الغطاء السحابي. قد يكون تفسير القنوات الملونة لخريطة الطقس مختلفًا ، في الإصدار الذي قدمته ، على النحو التالي:
قناة R - غطاء سحابي منخفض الارتفاع
G- قناة - الغطاء السحابي على علو شاهق
قناة B - أقصى ارتفاع سحابة
قناة - الكثافة السحابية
نحن الآن على استعداد لإنشاء وظيفة تعيد كثافة السحب حسب إحداثيات الفضاء ثلاثي الأبعاد.
عند المدخل ، نقطة في الفضاء مع الإحداثيات في كم
vec3 position
أضف على الفور الأوفست إلى الريح
position.xz+=vec2(0.2f)*ufmParams.time;
الحصول على قيم خريطة الطقس
vec4 weather=textureLod(ufmWeatherMap, position.xz/4096.0f, 0);
نحصل على نسبة الارتفاع (من 0 إلى 1)
float height=cloudGetHeight(position);
أضف تقريبًا صغيرًا من السحب أدناه:
float SRb=clamp(remap(height, 0, 0.07, 0, 1), 0, 1);
نحقق انخفاضًا خطيًا في الكثافة إلى 0 مع زيادة الارتفاع وفقًا لقناة B لخريطة الطقس:
float SRt=clamp(remap(height, weather.b*0.2, weather.b, 1, 0), 0, 1);
الجمع بين النتيجة:
float SA=SRb*SRt;
أضف مرة أخرى التقريب بين السحب أدناه:
float DRb=height*clamp(remap(height, 0, 0.15, 0, 1), 0, 1);
أضف أيضًا تقريب السحب في الأعلى:
float DRt=height*clamp(remap(height, 0.9, 1, 1, 0), 0, 1);
نحن نجمع بين النتيجة ، وهنا نضيف تأثير الكثافة من خريطة الطقس وتأثير الكثافة ، والذي يتم تعيينه عبر واجهة المستخدم الرسومية:
float DA=DRb*DRt*weather.a*2*ufmProperties.density;
اجمع بين الضوضاء المنخفضة التردد والعالية التردد من موادنا:
float SNsample=textureLod(ufmLowFreqNoiseTexture, position/48.0f, 0).x*0.85f+textureLod(ufmHighFreqNoiseTexture, position/4.8f, 0).x*0.15f;
في جميع المستندات التي قرأتها ، يتم الدمج بطريقة مختلفة ، لكني أحببت هذا الخيار.
نحدد مقدار التغطية (٪ من السماء التي تشغلها السحب) ، والتي يتم تعيينها عبر واجهة المستخدم الرسومية ، كما يتم استخدام قنوات R- و G في خريطة الطقس:
float WMc=max(weather.r, clamp(ufmProperties.coverage-0.5, 0, 1)*weather.g*2);
احسب الكثافة النهائية:
float d=clamp(remap(SNsample*SA, 1-ufmProperties.coverage*WMc, 1, 0, 1), 0, 1)*DA;
وظيفة كاملة:
float cloudSampleDensity(vec3 position) { position.xz+=vec2(0.2f)*ufmParams.time; vec4 weather=textureLod(ufmWeatherMap, position.xz/4096.0f+vec2(0.2, 0.1), 0); float height=cloudGetHeight(position); float SRb=clamp(remap(height, 0, 0.07, 0, 1), 0, 1); float SRt=clamp(remap(height, weather.b*0.2, weather.b, 1, 0), 0, 1); float SA=SRb*SRt; float DRb=height*clamp(remap(height, 0, 0.15, 0, 1), 0, 1); float DRt=height*clamp(remap(height, 0.9, 1, 1, 0), 0, 1); float DA=DRb*DRt*weather.a*2*ufmProperties.density; float SNsample=textureLod(ufmLowFreqNoiseTexture, position/48.0f, 0).x*0.85f+textureLod(ufmHighFreqNoiseTexture, position/4.8f, 0).x*0.15f; float WMc=max(weather.r, clamp(ufmProperties.coverage-0.5, 0, 1)*weather.g*2); float d=clamp(remap(SNsample*SA, 1-ufmProperties.coverage*WMc, 1, 0, 1), 0, 1)*DA; return d; }
ما يجب أن تكون عليه بالضبط هذه الوظيفة هو سؤال مفتوح ، لأن تجاهل القوانين التي تطيعها الغيوم عند تحديد المعلمات ، يمكنك الحصول على نتيجة غير عادية وجميلة للغاية. كل هذا يتوقف على التطبيق.
التكامل
ينقسم جو الأرض إلى طبقتين: داخلي وخارجي ، يمكن أن توجد بينهما السحب. يمكن تمثيل هذه الطبقات بواسطة كرات ، ولكن أيضًا بواسطة طائرات. أنا استقر على المجالات. بالنسبة للطبقة الأولى ، أخذت نصف قطر المجال البالغ 6415 كم ، أما بالنسبة للطبقة الثانية ، فإن نصف قطرها 6435 كم. تقريب نصف قطر الأرض إلى 6400 كم. تعتمد بعض المعلمات على السُمك الشرطي للجزء "الغائم" من الغلاف الجوي (20 كم).
على عكس السماء ، تكون السحب معتمة ، والتكامل لا يتطلب فقط الحصول على اللون ، ولكن أيضًا الحصول على قيمة قناة ألفا. تحتاج أولاً إلى وظيفة تُرجع الكثافة الإجمالية للسحابة التي تمر عبرها أشعة الضوء من الشمس.
لا أحد يلفت الانتباه إلى ذلك ، لكن الممارسة أظهرت أنه ليس من الضروري على الإطلاق مراعاة المسار الكامل للحزمة ، فلا يلزم سوى الفجوة القصوى. نحن نفترض أن الغيوم فوق شريحة مقطوعة لا وجود لها على الإطلاق.
بالإضافة إلى ذلك ، نحن محدودون للغاية في عدد عينات الكثافة التي يمكن القيام بها دون قتل الأداء. ألعاب حرب العصابات تفعل 6. علاوة على ذلك ، في أحد العروض التقديمية ، قال المطور إنهم ينتشرون هذه العينات داخل المخروط ، وأن آخر عينة تم تصنيعها خصيصًا بعيدًا عن الباقي لتغطية أكبر مساحة ممكنة. ستبقى الدقة الناتجة عن عدم الدقة والضوضاء على خلفية العينات المجاورة ، وهذا سيتحول إلى زيادة الدقة.
في النهاية ، استقرت على 4 عينات تقع على نفس الخط ، ولكن تم أخذ الأخير بخطوة زادت بنسبة 6 مرات. حجم الخطوة 20 كم * 0.01 ، وهو 200 متر.
وظيفة بسيطة جدا:
float cloudSampleDirectDensity(vec3 position, vec3 sunDir) {
يمكنك الآن الانتقال إلى الجزء الأكثر صعوبة. نحدد المراقب على سطح الأرض عند النقطة {0 ، 6400،0} ونجد تقاطع حزمة المراقبة مع دائرة نصف قطرها 6415 كم والمركز {0،0،0} - نحصل على نقطة البداية S.
أدناه هو الإصدار الأساسي من الوظيفة:
vec4 mainMarching(vec3 viewDir, vec3 sunDir) { vec3 position; crossRaySphereOutFar(vec3(0.0, 6400.0, 0.0), viewDir, vec3(0.0), 6415.0, position); float avrStep=(6435.0-6415.0)/64.0; for(int i=0;i<128;i++) { position+=viewDir*step; if(length(position)>6435.0) break; } return vec4(0.0); }
يعرف حجم الخطوة بأنه 20 كم / 64. أي في حالة الاتجاه الرأسي بدقة لحزمة المراقب ، سنقوم بعمل 64 عينة. ومع ذلك ، عندما يكون هذا الاتجاه أفقيًا ، ستكون العينات أكبر قليلاً ، لذلك لا توجد 64 خطوة في الدورة ، ولكن 128 بهامش.
في البداية ، نفترض أن اللون النهائي أسود ، والشفافية هي الوحدة. مع كل خطوة ، سنزيد قيمة اللون ونخفض قيمة الشفافية. إذا كانت الشفافية قريبة من 0 ، فيمكنك الخروج من الحلقة مسبقًا:
vec3 color=vec3(0.0); float transmittance=1.0; …
ufmProperties.attenuation - لا يوجد شيء سوى C في

و ufmProperties.attenuation2 هو C in

. ufmProperties.sunIntensity - شدة إشعاع الشمس. sunColor - لون الشمس.
النتيجة:
عيب واضح على الفور - التظليل الشديد. ولكن الآن سنقوم بتصحيح عدم وجود إضاءة مضخمة بالقرب من الشمس. حدث ذلك لأننا لم نضيف وظيفة المرحلة. لحساب نثر الضوء الذي يمر عبر السحب ، نستخدم مرحلة وظيفة Hengy-Greenstein ، التي فتحتها في عام 1941 لإجراء عمليات حسابية مماثلة في مجموعات الغاز في الفضاء:
وينبغي أن يكون الاكتئاب هنا. وفقا لنموذج الإضاءة الكنسي ، يجب أن تكون وظيفة الطور واحدة. ومع ذلك ، في الواقع ، فإن النتيجة التي تم الحصول عليها لا تناسب أي شخص والجميع يستخدم دالات المرحلة ، وحتى يجمع بين قيمهم بطريقة خاصة. ركزت أيضًا على وظائف مرحلتين ، لكنني ببساطة أضيف قيمها. تحتوي وظيفة المرحلة الأولى على مقربة من 1 وتسمح لك بإضاءة ساطعة بالقرب من الشمس. تحتوي وظيفة المرحلة الثانية على نسبة قريبة من 0.5 وتتيح لك إجراء انخفاض تدريجي في الإضاءة في جميع أنحاء الكرة السماوية.
كود محدث:
ufmProperties.eccentrisy ، ufmProperties.eccentrisy2 هي قيم g
النتيجة:
الآن يمكنك أن تبدأ المعركة مع الكثير من التظليل. إنه موجود لأننا لم نأخذ في الاعتبار الضوء من الغيوم المحيطة والسماء ، التي هي في الحياة الحقيقية.
لقد حللت هذه المشكلة مثل هذا:
return vec4(color+ambientColor*ufmProperties.ambient, 1.0-transmittance);
عندما يكون ambientColor هو لون السماء في اتجاه حزمة المراقبة ، فإن ufmProperties.ambient هي معلمة التوليف.
النتيجة:
يبقى لحل المشكلة الأخيرة. في الحياة الواقعية ، كلما كانت الرؤية أفقية ، كلما رأينا ضبابًا أو ضبابًا معينًا لا يسمح لنا برؤية أشياء بعيدة جدًا. هذا يحتاج أيضا إلى أن تنعكس في التعليمات البرمجية. أخذت جيب التمام المعتاد لزاوية النظرة والوظيفة الأسية. بناءً على ذلك ، يتم حساب معامل مزج معين ، والذي يسمح باستكمال خطي بين اللون الناتج ولون الخلفية.
float blending=1.0-exp(-max(0.0, dot(viewDir, vec3(0.0,1.0,0.0)))*ufmProperties.fog); blending=blending*blending*blending; return vec4(mix(ambientColor, color+ambientColor*ufmProperties.ambient, blending), 1.0-transmittance);
ufmProperties.fog - للتكوين اليدوي.
ملخص الوظيفة:
vec4 mainMarching(vec3 viewDir, vec3 sunDir, vec3 sunColor, vec3 ambientColor) { vec3 position; crossRaySphereOutFar(vec3(0.0, 6400.0, 0.0), viewDir, vec3(0.0), 6415.0, position); float avrStep=(6435.0-6415.0)/64.0; vec3 color=vec3(0.0); float transmittance=1.0; for(int i=0;i<128;i++) { float density=cloudSampleDensity(position)*avrStep; if(density>0.0) { float sunDensity=cloudSampleDirectDensity(position, sunDir); float mu=max(0.0, dot(viewDir, sunDir)); float m11=ufmProperties.phaseInfluence*cloudPhaseFunction(mu, ufmProperties.eccentrisy); float m12=ufmProperties.phaseInfluence2*cloudPhaseFunction(mu, ufmProperties.eccentrisy2); float m2=exp(-ufmProperties.attenuation*sunDensity); float m3=ufmProperties.attenuation2*density; float light=ufmProperties.sunIntensity*(m11+m12)*m2*m3; color+=sunColor*light*transmittance; transmittance*=exp(-ufmProperties.attenuation*density); } position+=viewDir*avrStep; if(transmittance<0.05 || length(position)>6435.0) break; } float blending=1.0-exp(-max(0.0, dot(viewDir, vec3(0.0,1.0,0.0)))*ufmProperties.fog); blending=blending*blending*blending; return vec4(mix(ambientColor, color+ambientColor*ufmProperties.ambient, blending), 1.0-transmittance); }
فيديو تجريبي:
التحسين والتحسينات الممكنة
بعد تطبيق خوارزمية التقديم الأساسية ، المشكلة التالية هي أنها تعمل ببطء شديد. أنتجت روايتي 25 إطارًا في الثانية عالية الدقة على radeon rx 480. تم اقتراح النهجين التاليين لحل المشكلة بواسطة ألعاب حرب العصابات نفسها.
نرسم ما هو مرئي حقاتنقسم الشاشة إلى مربعات بحجم 16 × 16 بكسل. أولاً ، يتم رسم البيئة ثلاثية الأبعاد المعتادة. اتضح أن معظم السماء مغطاة بالجبال أو الأشياء الكبيرة. وفقًا لذلك ، تحتاج إلى إجراء الحساب فقط في تلك البلاطات التي لا يتم حظر السحب بواسطة أي شيء.
إعادة الإسقاطعندما تكون الكاميرا ثابتة ، اتضح أنه لا يمكن تحديث السحب بشكل عام. ومع ذلك ، إذا تحركت الكاميرا ، فإن هذا لا يعني أننا نحتاج إلى تحديث الشاشة بأكملها. تم رسم كل شيء بالفعل ، تحتاج فقط إلى إعادة بناء الصورة وفقًا للإحداثيات الجديدة. إن العثور على إحداثيات قديمة على إحداثيات جديدة ، من خلال الإسقاطات ومصفوفات العرض للإطارات الحالية والسابقة ، يُسمى الإسقاط. وبالتالي ، في حالة تحول الكاميرا ، نقوم ببساطة بنقل الألوان وفقًا للإحداثيات الجديدة. في الحالات التي تشير فيها هذه الإحداثيات إلى خارج الشاشة ، يجب إعادة رسم السحب بأمانة.
التحديث الجزئيلا أحب فكرة الرفض لأنه مع انعطاف الكاميرا بشكل حاد ، قد يتضح أن السحب يجب أن تقدم لثلث الشاشة ، مما قد يتسبب في حدوث تأخير. لا أعرف كيف تعاملت لعبة Guerrilla Games مع هذا ، ولكن على الأقل في Horizon Zero Dawn ، عند التحكم في ذراع التحكم ، تتحرك الكاميرا بسلاسة ولا توجد مشاكل في القفزات الحادة. لذلك ، كتجربة ، توصلت إلى مقاربة خاصة بي. يتم رسم السحب في خريطة مكعب ، في 5 وجوه ، لأنه القاع لا يهمنا.
يتميز جانب الخريطة المكعبة بدقة منخفضة تساوي ⅔ ارتفاع الشاشة. ينقسم كل وجه من الخريطة المكعبة إلى بلاط 8 × 8. يتم تحديث كل إطار على كل وجه مع واحد فقط من 64 بكسل في كل البلاط. وهذا يعطي التحف ملحوظ خلال التغييرات المفاجئة ، ولكن بسبب السحب ثابتة تمامًا ، فهذه الحيلة غير مرئية. نتيجة لذلك ، ينتج radeon rx 480 500 إطارًا في الثانية بدقة عالية للبركان و 330 إطارًا في الثانية لأوبنجل. سلسلة Radeon hd 5700 تنتج 109 إطارًا في الثانية بجودة عالية بالكامل في إطار opengl (لا يدعم vulkan).استخدام مستويات mipعند الوصول إلى مواد ذات ضوضاء ، يمكنك أخذ البيانات من مستوى mip الصفري فقط في العينات الأولى ، وبعد ذلك ، كلما كانت العينات التي نصنعها أعلى ، يمكن أخذ مستوى mip أعلى.غيوم عاليةلمحاكاة وجود غيوم التشاؤم والارتفاعات المخروطية في ألعاب حرب العصابات أثناء الدمج ، لم تُصنع أحدث العينات من القوالب ثلاثية الأبعاد التي تحدثت عنها ، ولكن من نسيج ثنائي الأبعاد خاص.ضجيج الضفيرةيتم استخدام العديد من القوام الإضافي لضوضاء الضفيرة لإنشاء تأثير سحب الرياح. هناك حاجة إلى هذه القوام لتحويل الإحداثيات الأصلية.الأشعة الإلهيةيتم تحقيق مثل هذه الأشعة ، واللعب على الدراما ، في مرحلة ما بعد المعالجة. أولاً ، يتم رسم إضاءة ساطعة حول الشمس ، حيث لا يتم حظرها بواسطة السحب. ثم يجب أن يتم تعويض هذا الضوء الخلفي شعاعيا بعيدا عن الشمس.الآن تحتاج إلى تطبيق تجانس شعاعي.في الواقع ، هناك المزيد من التحسينات والدقة الدقيقة ، لكنني لم أتحقق منها جميعًا ، لذلك لا يمكنني أن أخبرها بثقة عنها. ومع ذلك ، يمكنك التعرف على نفسك معهم. أقوى ما أعتقد هو التوثيق السحابي من محرك Frostbite.روابط مفيدة
Guerrilla Gamesd1z4o56rleaq4j.cloudfront.net/downloads/assets/Nubis-Authoring-Realtime-Volumetric-Cloudscapes-with-the-Decima-Engine-Final.pdf?mtime=20170807141817killzone.dl.playstation.net/killzone/horizonzerodawn/presentations/Siggraph15_Schneider_Real-Time_Volumetric_Cloudscapes_of_Horizon_Zero_Dawn.pdfwww.youtube.com/watch?v=-d8qT5-1LOIGPU Pro 7vk.com/doc179245989_437393482?hash=a9af5f665eda4edf58&dl=806d4dbdac0f7a761cwww.scratchapixel.com/lessons/procedural-generation-virtual-worlds/simulating-sky/simulating-colors-of-the-skyFrostbitemedia.contentapi.ea.com/content/dam/eacom/frostbite/files/s2016-pbs-frostbite-sky-clouds-new.pdfwww.shadertoy.com/view/XlBSRz