استبدال اللوحات في اللعبة باستخدام تظليل

في هذه المدونة ، سوف أريكم تقنيتي المفضلة التي أستخدمها بنشاط في لعبة Vagabond: استبدال اللوحات.

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



تحضير الصور


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

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

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

فيما يلي مثال على ما نتوقع أن نتلقاه:


لتحقيق ذلك ، استخدم دالة Python صغيرة تستخدم مكتبة Pillow :

import io import numpy as np from PIL import Image def convert_to_indexed_image(image, palette_size): # Convert to an indexed image indexed_image = image.convert('RGBA').convert(mode='P', dither='NONE', colors=palette_size) # Be careful it can remove colors # Save and load the image to update the info (transparency field in particular) f = io.BytesIO() indexed_image.save(f, 'png') indexed_image = Image.open(f) # Reinterpret the indexed image as a grayscale image grayscale_image = Image.fromarray(np.asarray(indexed_image), 'L') # Create the palette palette = indexed_image.getpalette() transparency = list(indexed_image.info['transparency']) palette_colors = np.asarray([[palette[3*i:3*i+3] + [transparency[i]] \ for i in range(palette_size)]]).astype('uint8') palette_image = Image.fromarray(palette_colors, mode='RGBA') return grayscale_image, palette_image 

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

تظليل


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

ها هي تظليلي ، لقد كتبت في GLSL ، لكنني أعتقد أنه يمكن نقله بسهولة إلى لغة أخرى لإنشاء تظليل:

 #version 330 core in vec2 TexCoords; uniform sampler2D Texture; uniform vec4 Palette[32]; out vec4 Color; void main() { Color = Palette[int(texture(Texture, TexCoords).r * 255)]; } 

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

الرسوم المتحركة في بداية المقال مأخوذة من لقطات شاشة داخل اللعبة ، حيث أستخدم اللوحات التالية لتغيير لون جسم الشخصية:

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


All Articles