استكشاف رحلة لعبة تظليل الرمل

بداية سلسلة من المقالات هنا

صورة

الجزء 4: صورة طبق الأصل


في هذا الجزء ، سنركز على انعكاسات المرآة ، والتي بفضلها تشبه الكثبان محيطًا من الرمال.

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

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




قبل وبعد تطبيق انعكاسات المرآة

إضاءة الحافة


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

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

قبل البدء في معرفة كيفية تنفيذ هذا التأثير ، دعنا نوسع وظيفة الإضاءة بإضافة لون منتشر إليها (نظرنا في الجزء السابق من المقالة) ومكون معمم جديد للتفكير المرآوي.

float4 LightingJourney (SurfaceOutput s, fixed3 viewDir, UnityGI gi)
{
    // Lighting properties
    float3 L = gi.light.dir;
    float3 N = s.Normal;

    // Lighting calculation
    float3 diffuseColor	= DiffuseColor (N, L);
    float3 rimColor     = RimLighting  (N, V);

    // Combining
    float3 color = diffuseColor + rimColor;

    // Final color
    return float4(color * s.Albedo, 1);
}

في مقتطف الشفرة الموضح أعلاه ، نرى أن مكون المرآة لإضاءة الحافة ، والذي يسمى rimColor، يضاف ببساطة إلى اللون المنتشر الأصلي.

النطاق الديناميكي العالي وتأثيرات التفتح
, — RGB 01. . , 1.

, , 01. , , 1. High Dynamic Range, 1«» . bloom, . .

تأملات فرينل


يمكن تحقيق توهج الحواف بعدة طرق مختلفة. يستخدم ترميز Shader الأكثر شيوعًا نموذج انعكاس Fresnel المعروف .

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


على غرار ما فعلناه في الجزء الخاص بـ Diffuse Color ، يمكنك استخدام منتج العددية NوV للحصول على مقياس لتوازيها. في هذه الحالةNV يساوي0 ، لأن متجهي وحدتين متعامدين ؛ بدلا من ذلك يمكننا استخدامها1NV للحصول على مقياس عدم التوازي بينهما.

الاستخدام المباشر1NV لن يعطينا N V نتائج جيدة ، لأن الانعكاس سيكون قويًا جدًا. إذا أردنا أن نجعل الانعكاسأكثر حدة، يمكننا فقط أخذ التعبير في الدرجة. درجة المقدار من0 إلى1 يظل محدودًا بفاصل زمني واحد ، لكن الانتقال بين الظلام والضوء يصبح أكثر حدة.

يوضح نموذج انعكاس فرينل أن سطوع الضوءIيتم تعريف أنا على النحو التالي:

I=(1NV)powerstrength(1)


أين powerandstrength معلمتين يمكن استخدامها للتحكم في تباين وقوة التأثير. المعلماتpower andstrengthيُطلق على s t r e n g t h أحيانًا اسمبراقولمعان، ولكن قد تختلف الأسماء.

من السهل جدًا تحويل المعادلة (1) إلى رمز:

float _TerrainRimPower;
float _TerrainRimStrength;
float3 _TerrainRimColor;

float3 RimLighting(float3 N, float3 V)
{
    float rim = 1.0 - saturate(dot(N, V));
    rim = saturate(pow(rim, _TerrainRimPower) * _TerrainRimStrength);
    rim = max(rim, 0); // Never negative
    return rim * _TerrainRimColor;
}

وتظهر نتيجته في الرسوم المتحركة أدناه.


بركان المحيط


واحدة من أكثر الجوانب الأصلية للعب Journey هي أنه في بعض الأحيان يمكن للاعب حرفياً "تصفح" الكثبان الرملية. وأوضح المهندس الرئيسي جون إدواردز أن شركة الألعاب سعت إلى جعل الرمال أكثر صلابة ، ولكنها سائلة.

وهذا ليس خاطئًا تمامًا ، لأن الرمال يمكن اعتبارها تقريبًا تقريبيًا للسائل. وتحت ظروف معينة ، على سبيل المثال ، في الساعة الرملية ، يتصرف مثل السائل.

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


كما كان من قبل ، سنقوم بإجراء تغييرات على وظيفة الإضاءة LightingJourneyلإضافة نوع جديد من الانعكاس المرآوي إليها.

float4 LightingJourney (SurfaceOutput s, fixed3 viewDir, UnityGI gi)
{
    // Lighting properties
    float3 L = gi.light.dir;
    float3 N = s.Normal;
    float3 V = viewDir;

    // Lighting calculation
    float3 diffuseColor	= DiffuseColor  (N, L);
    float3 rimColor     = RimLighting   (N, V);
    float3 oceanColor   = OceanSpecular (N, L, V);

    // Combining
    float3 specularColor = saturate(max(rimColor, oceanColor));
    float3 color = diffuseColor + specularColor;

    // Final color
    return float4(color * s.Albedo, 1);
}

لماذا نأخذ مكونين للانعكاس بحد أقصى؟
, rim lighting ocean specular. , , -. , .

, .

غالبًا ما يتم تحقيق انعكاسات المرآة على الماء باستخدام انعكاس Blinn-Fong ، وهو حل منخفض التكلفة للمواد اللامعة. تم وصفه لأول مرة بواسطة James F. Blinn في عام 1977 (مقالة: " نماذج من انعكاس الضوء للصور المركبة بالكمبيوتر ") كتقريب لتقنية التظليل السابقة التي طورها Bui Tyong Fong في عام 1973 (مقالة: " إضاءة للصور المولدة بالكمبيوتر ") .

عند استخدام تظليل Blinnu-Phong ، اللمعانIيتم إعطاء السطح I بالمعادلة التالية:

I=(NH)powerstrength(2)


أين

H=V+LV+L(3)


يقسم مقام المعادلة (3) المتجه V+Lعلى طوله. هذا يضمن ذلكH له طول 1. وظيفة تظليل مكافئة لتنفيذ هذه العملية هي هذه normalize. من وجهة نظر هندسية ،H يمثل المتجه بين Vو Lوبالتالي يسمى نصف ناقل .



لماذا H بين V و L؟
, , HVL.

, . VLLVVL.

, , V+LL+V, . , :


, , . , ( V+L) . , ( ).


, V+LVL, 1. , 1, ( ).

يمكن العثور على وصف أكثر تفصيلاً حول انعكاس Blinn-Fong في البرنامج التعليمي لنماذج العرض والإضاءة المعتمدة على جسديًا . فيما يلي تنفيذ بسيط لها في كود التظليل.

float _OceanSpecularPower;
float _OceanSpecularStrength;
float3 _OceanSpecularColor;

float3 OceanSpecular (float3 N, float3 L, float3 V)
{
    // Blinn-Phong
    float3 H = normalize(V + L); // Half direction
    float NdotH = max(0, dot(N, H));
    float specular = pow(NdotH, _OceanSpecularPower) * _OceanSpecularStrength;
    return specular * _OceanSpecularColor;
}

تقدم الرسوم المتحركة مقارنة بين التظليل المنتشر التقليدي وفقًا لـ Lambert والمرآة وفقًا لـ Blinn-Fong:


الجزء الخامس: انعكاس رائع


في هذا الجزء ، سنعيد إنشاء الانعكاسات الرائعة التي عادة ما تكون مرئية على الكثبان الرملية.

بعد وقت قصير من نشر لي سلسلة من المقالات، جوليان Oberbek و بول Nadelek يبذل جهدا الخاصة بهم لإعادة مشهد مستوحاة من لعبة رحلة في الوحدة. تُظهر التغريدة أدناه كيفية إتقان الانعكاسات الرائعة لتوفير قدر أكبر من التكامل الزمني. اقرأ المزيد عن تنفيذها في مقال عن IndieBurg Mip Map Folding .


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


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

في ألعاب أخرى ، مثل Astroneer و Slime Rancher ، تم استخدام انعكاسات رائعة للرمل والكهوف.



اللمعان: قبل وبعد تطبيق التأثير

، من الأسهل تقييم خصائص اللمعان هذه في صورة أكبر:



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

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

لكننا بحاجة إلى شيء آخر. إذا أردنا أن تظهر البكسل ساطعة جدًا بحيث ينتشر الضوء على البكسلات المجاورة لها ، فيجب أن يكون اللون أكبر1. حدث هذا لأنه في Unity ، عندما يتم تطبيق مرشح bloom على الكاميرا باستخدام تأثير ما بعد المعالجة ، تكون الألوان أكثر سطوعًا1تنتشر إلى وحدات البكسل المجاورة وتنتج هالة تخلق الشعور بأن بعض وحدات البكسل متوهجة. هذا هو أساس تقديم HDR .

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

نظرية الميكروفاس


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

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

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


هنا يمكننا مرة أخرى استخدام منتج العددية Rو Vللحصول على مقاييس توازيهم.

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

التنفيذ


يمكننا بسهولة تنفيذ تأثير اللمعان الموضح أعلاه باستخدام دالة reflectفي Cg ، مما يجعل من السهل جدًا الحسابR.

sampler2D_float _GlitterTex;
float _GlitterThreshold;
float3 _GlitterColor;

float3 GlitterSpecular (float2 uv, float3 N, float3 L, float3 V)
{
    // Random glitter direction
    float3 G = normalize(tex2D(_GlitterTex, uv).rgb * 2 - 1); // [0,1]->[-1,+1]

    // Light that reflects on the glitter and hits the eye
    float3 R = reflect(L, G);
    float RdotV = max(0, dot(R, V));
	
    // Only the strong ones (= small RdotV)
    if (RdotV > _GlitterThreshold)
        return 0;
	
    return (1 - RdotV) * _GlitterColor;
}

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

النتائج موضحة أدناه:


كما نتذكر من الجزء الأول من البرنامج التعليمي ، تتم إضافة مكون اللمعان إلى اللون النهائي.

#pragma surface surf Journey fullforwardshadows

float4 LightingJourney (SurfaceOutput s, fixed3 viewDir, UnityGI gi)
{
    float3 diffuseColor = DiffuseColor    ();
    float3 rimColor     = RimLighting     ();
    float3 oceanColor   = OceanSpecular   ();
    float3 glitterColor = GlitterSpecular ();

    float3 specularColor = saturate(max(rimColor, oceanColor));
    float3 color = diffuseColor + specularColor + glitterColor;
	
    return float4(color * s.Albedo, 1);
}

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

هناك طرق عديدة لتحسين هذه التقنية. كل هذا يتوقف على النتيجة التي تريد تحقيقها. في Astroneer و Slime Rancher ، على سبيل المثال ، يتم استخدام هذا التأثير فقط في الليل. يمكن تحقيق ذلك عن طريق تقليل قوة تأثير اللمعان اعتمادًا على اتجاه ضوء الشمس.

على سبيل المثال، فإن القيمة max(dot(L, fixed3(0,1,0),0))هي1عندما تسقط الشمس من فوق ، وتساوي الصفر عندما تكون خارج الأفق. ولكن يمكنك إنشاء نظامك الخاص ، والذي يعتمد مظهره على تفضيلاتك.

لماذا لا يستخدم الانعكاس في انعكاس بلين فونغ؟
ocean specular, , -.

, 3D- , , . , reflect . - RVNH, .

الجزء السادس: الأمواج


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




موجات على سطح الكثبان: قبل وبعد

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

خرائط عادية


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


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

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

موجات في الرمال


ومع ذلك ، تظهر الكثبان الرملية ميزة أخرى لا يمكن تجاهلها: الموجات. على كل الكثبان الرملية توجد كثبان أصغر تظهر بسبب تأثير الريح وتماسكها مع احتكاك حبيبات الرمل الفردية.

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


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


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

تحقيق الأمواج


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

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

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

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

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

نظرًا لأن الموجات تحتاج إلى محاكاة على سطح ثلاثي الأبعاد ، سيكون من المنطقي تنفيذ تغيير في اتجاه المعايير لكل بكسل. من الأسهل استخدام خريطة عادية سلسة بنمط موجة. سيتم دمج هذه الخريطة بعد ذلك مع الخريطة العادية الحالية المستخدمة سابقًا للرمل.

خرائط عادية


حتى هذه اللحظة ، التقينا بثلاثة معايير مختلفة :

  • الهندسة العادية : اتجاه كل وجه للنموذج ثلاثي الأبعاد ، الذي يتم تخزينه مباشرة في القمم ؛
  • الرمل العادي : محسوب باستخدام نسيج الضجيج ؛
  • Wave Normal : التأثير الجديد الذي تمت مناقشته في هذا الجزء.

يوضح المثال أدناه ، المأخوذ من صفحة أمثلة Unity Surface Shader ، طريقة قياسية لإعادة كتابة الوضع العادي للنموذج ثلاثي الأبعاد. يتطلب ذلك تغيير القيمة o.Normal، والتي يتم إجراؤها عادةً بعد أخذ عينات النسيج (غالبًا ما تسمى الخريطة العادية ).

  Shader "Example/Diffuse Bump" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _BumpMap ("Bumpmap", 2D) = "bump" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input {
        float2 uv_MainTex;
        float2 uv_BumpMap;
      };
      sampler2D _MainTex;
      sampler2D _BumpMap;
      void surf (Input IN, inout SurfaceOutput o) {
        o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
        o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }

استخدمنا نفس التقنية بالضبط لاستبدال عادي الهندسة بعادي الرمال.

ما هو UnpackNormal؟
. ( 1), , . X, Y Z R, G B .

1+1. 01. , «» «» . (normal packing) (normal unpacking). :

R=X2+12G=Y2+12B=Z2+12(1)


:

X=2R1Y=2G1Z=2B1(2)


Unity (2), UnpackNormal. .

Normal Map Technical Details polycount.

انحدار الكثبان


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

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


الخريطة العادية للكثبان الرملية


الخريطة العادية للكثبان المسطحة

خرائط عادية وقناة زرقاء
, .

, . , (X Y) (Z) .

length(N)=1X2+Y2+Z2=1(3)


:

X2+Y2+Z2=1X2+Y2+Z2=12Z2=1X2Y2Z=1X2Y2(4)


UnpackNormal Unity. Shader API .

inline fixed3 UnpackNormal(fixed4 packednormal)
{
#if defined(SHADER_API_GLES)  defined(SHADER_API_MOBILE)
    return packednormal.xyz * 2 - 1;
#else
    fixed3 normal;
    normal.xy = packednormal.wy * 2 - 1;
    normal.z = sqrt(1 - normal.x*normal.x - normal.y * normal.y);
    return normal;
#endif
}

Unity DXT5nm, (packednormal.xy) - (packednormal.wy).

Normal Map Compression polycount.

لماذا تبدو الخرائط العادية أرجواني؟
, , .

, . , [0,0,1].

[0,0,1][0.5,0.5,1], RGB.

; , [0,0,1].

, «». , B 1+1, 0+1. .

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


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


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

لحسن الحظ ، تأتي الوحدة إلى الإنقاذ بوظيفة WorldNormalVectorتسمح لنا بتحويل المتجه العادي من الفضاء المماس إلى الفضاء العالمي . لاستخدام هذه الميزة ، نحتاج إلى تغيير البنية Input، بحيث يتم تضمينها float3 worldNormalو INTERNAL_DATA:

struct Input
{
    ...

    float3 worldNormal;
    INTERNAL_DATA
};

هذا موضح في مقال من وثائق Unity Writing Surface Shaders تقول:

INTERNAL_DATA — , o.Normal.

, WorldNormalVector (IN, o.Normal).

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

إذا قمت بتسجيل الدخول o.Normal، ولكنك لا تزال بحاجة إلى الوصول إلى الوضع الطبيعي في الفضاء العالمي (كما في حالتنا) ، فيمكنك استخدامه WorldNormalVector (IN, o.Normal). ومع ذلك ، لهذا تحتاج إلى إجراء تغيير طفيف على الهيكل الموضح أعلاه Input.

ما هي INTERNAL_DATA؟
INTERNAL_DATA Unity.

, , WorldNormalVector. , , . ( ).

, 3D- 3×3. , , (tangent to world matrix), Unity TtoW.

INTERNAL_DATA TtoW Input. , «Show generated code» :


, INTERNAL_DATA — , TtoW:

#define INTERNAL_DATA
    half3 internalSurfaceTtoW0;
    half3 internalSurfaceTtoW1;
    half3 internalSurfaceTtoW2;

half3x3, half3.

WorldNormalVector, , ( ) TtoW:

#define WorldNormalVector(data,normal)
    fixed3
    (
        dot(data.internalSurfaceTtoW0, normal),
        dot(data.internalSurfaceTtoW1, normal),
        dot(data.internalSurfaceTtoW2, normal)
    )

mul, TtoW , .

, :

[ToW1,1ToW1,2ToW1,3ToW2,1ToW2,2ToW2,3ToW3,1ToW3,2ToW3,3][N1N2N3]=[[ToW1,1ToW1,2ToW1,3][N1N2N3][ToW2,1ToW2,2ToW2,3][N1N2N3][ToW3,1ToW3,2ToW3,3][N1N2N3]]


LearnOpenGL.

التنفيذ


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

// Calculates normal in world space
float3 N_WORLD = WorldNormalVector(IN, o.Normal);
float3 UP_WORLD = float3(0, 1, 0);

// Calculates "steepness"
// => 0: steep (90 degrees surface)
//  => 1: shallow (flat surface)
float steepness = saturate(dot(N_WORLD, UP_WORLD));

الآن بعد أن حسبنا انحدار الكثبان الرملية ، يمكننا استخدامه لخلط الخريطتين العاديتين. يتم أخذ كل من الخرائط العادية ، سواء مسطحة أو باردة (في الرمز أدناه تسمى _ShallowTexو _SteepTex). ثم يتم خلطهم بناءً على القيمة steepness:

float2 uv = W.xz;

// [0,1]->[-1,+1]
float3 shallow = UnpackNormal(tex2D(_ShallowTex, TRANSFORM_TEX(uv, _ShallowTex)));
float3 steep   = UnpackNormal(tex2D(_SteepTex,   TRANSFORM_TEX(uv, _SteepTex  )));

// Steepness normal
float3 S = normalerp(steep, shallow, steepness);

كما هو مذكور في الجزء المتعلق بالمعايير الرملية ، من الصعب جدًا الجمع بين الخرائط العادية بشكل صحيح ، ولا يمكن القيام بذلك lerp. في هذه الحالة slerp، من الأصح استخدام ، ولكن بدلاً من ذلك ، تسمى وظيفة أقل تكلفة normalerp.

خلط الموجة


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

// Steepness to blending
steepness = pow(steepness, _SteepnessSharpnessPower);

عند خلط نسيجين ، غالبًا ما يتم استخدامه للتحكم في حدته وتباينه pow. لقد تعلمنا كيف ولماذا يعمل في البرنامج التعليمي للعرض الجسدي .

أدناه نرى اثنين من التدرجات. يظهر الجزء العلوي الألوان من الأسود إلى الأبيض ، محرف خطيًا على طول المحور X مع c = uv.x. في الأسفل ، يتم تمثيل نفس التدرج بـ c = pow(uv.x*1.5)*3.0:



من السهل ملاحظة ذلك ، مما powيسمح لك بإنشاء انتقال أكثر حدة بين الأسود والأبيض. عندما نعمل مع مواد ، فإن هذا يقلل من تداخلها ، مما يخلق حواف أكثر وضوحًا.

اتجاه الكثبان الرملية


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

لجعل الموجات أكثر واقعية ، نحتاج إلى إضافة خريطتين عاديتين أخريين (انظر الجدول أدناه). يمكن أن تكون مختلطة اعتمادًا على التوازي لكثيب المحور X أو المحور Z.

رائعمسطحة
Xبارد العاشرمسطح س
ضبارد ضشقة ض

نحتاج هنا إلى تنفيذ حساب التوازي للكثافة بالنسبة للمحور Z ، ويمكن القيام بذلك على نحو مماثل لحساب الانحدار ، ولكن float3 UP_WORLD = float3(0, 1, 0);يمكن استخدامه بدلاً من ذلك float3 Z_WORLD = float3(0, 0, 1);.

هذه الخطوة الأخيرة سأترك لكم. إذا كان لديك أي مشاكل ، في نهاية هذا البرنامج التعليمي ، يوجد رابط لتنزيل حزمة Unity الكاملة.

استنتاج


هذا هو الجزء الأخير من سلسلة من الدروس حول جعل الرمال من Journey.

يوضح ما يلي مدى تمكننا من التقدم في هذه السلسلة:



قبل وبعد

أود أن أشكرك على قراءة هذا البرنامج التعليمي الطويل إلى حد ما حتى النهاية. آمل أن تكون قد استمتعت باستكشاف وإعادة إنشاء هذا الظل.

شكر وتقدير


تم تطوير لعبة الفيديو Journey بواسطة شركة Thatgamecompany ونشرتها شركة Sony Computer Entertainment . وهي متاحة لأجهزة الكمبيوتر ( متجر Epic ) و PS4 ( متجر PS ).

تم إنشاء نماذج الكثبان والخلفيات وخيارات الإضاءة ثلاثية الأبعاد بواسطة Jiadi Deng .

تم العثور على نموذج ثلاثي الأبعاد لشخصية الرحلة في منتدى FacePunch (مغلق الآن).

حزمة الوحدة


إذا كنت ترغب في إعادة إنشاء هذا التأثير ، فإن حزمة Unity الكاملة متاحة للتنزيل على Patreon . لديها كل ما تحتاجه ، من تظليل إلى نماذج ثلاثية الأبعاد.

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


All Articles