2D світло і тінь

Вступ

Цей урок пояснює, як працює 2D-освітлення в демонстраційному проєкті світло і тінь. Він починається з короткого опису ресурсів, використаних у фінальній демонстрації, а потім описує, як поетапно зробити сцену з демонстрації.

../../_images/light_shadow_main.png

Усі ресурси цього урока можна знайти в офіційному демо сховищі на GitHub. Пропоную завантажити його перед початком роботи. Крім того, його можна завантажити з Менеджера Проєкта. Запустіть Godot і на верхній панелі виберіть Шаблони та знайдіть "2D Lights and Shadows Demo".

Налаштування

Для цієї демонстрації ми використовуємо чотири текстури: дві для світла, одну для тіні і одну для фону. Я включив тут посилання на всі, якщо ви хочете завантажити їх окремо від демонстрації.

Перша - це фонове зображення (background.png), яке використовується в демонстраційній версії. Вам не обов’язково потрібен фон, але ми використовуємо його для демонстрації.

Друга - це звичайне чорне зображення (caster.png), яке буде використано в якості об'єкта, що відкидає тінь. Для гри зверху вниз це може бути стіна, або будь-який інший предмет, що кидає тінь.

Далі йде саме світло (light.png). Якщо натиснути посилання, ви помітите, наскільки воно велике. Зображення, яке ви використовуєте для світла, повинно охоплювати область, яку ви хочете, щоб ваше світло покривало. Це зображення має розмір 1024x1024 пікселів, тому ви повинні використовувати його для покриття 1024x1024 пікселів у грі.

Нарешті, ми маємо зображення прожектора (spot.png). Демо використовує крапку, щоб показати, де знаходиться світло, і більше світле зображення, щоб показати вплив світла на решту сцени.

Вузли

Демонстрація використовує чотири різні вузли:

CanvasModulate використовується для затемнення сцени.

Sprites використовуються для відображення текстур світлових плям, фону та об'єктів, що відкидають тінь.

Light2Ds використовуються для освітлення сцени. Зазвичай світло працює шляхом додавання вибраної текстури до решти сцени для імітації освітлення. Але його можна використовувати і іншими способами, наприклад, маскуванням частин сцени.

LightOccluder2Ds використовуються, щоб повідомляти шейдеру, які частини сцени відкидають тінь. Тіні з’являються лише на ділянках, покритих Light2D і їх напрямок залежить від центра Світла.

Освітлення

Світла охоплюють всю протяжність відповідної текстури. Вони використовують суміш добавок, щоб додати колір своєї фактури до сцени.

../../_images/light_shadow_light.png

Світло має чотири Mode (Режими): Add, Sub, Mix, і Mask.

Add додає колір текстури світла до сцени. Він освітлює область під світлом.

Sub віднімає колір світла зі сцени. Він затемнює область під світлом.

Mix змішує колір світла з основою сцени. Отримана яскравість десь посередині між кольором світла та кольором під ним.

Mask використовується для маскування ділянок, покритих світлом. Замасковані ділянки приховані або розкриті залежно від кольору світла.

В демонстрації світло має два компоненти: власне Light, яка є зображенням, що показує розташування джерела світла. Нащадок Sprite не потрібен для роботи Light.

../../_images/light_shadow_light_blob.png

Тіні

Тіні створюються перетином Light з LightOccluder2D.

За замовчуванням тіні вимкнені. Щоб увімкнути їх, натисніть на Light і в розділі Тіні поставте галочку Enabled.

У демонстраційній версії ми використовуємо Sprite. Сам по собі LightOccluder2D виглядає темною плямою, і в цій демонстрації Sprite - це просто чорний квадрат.

Крок-за-кроком

Тепер, коли ми розкрили основи використовуваних вузлів, ми можемо крок за кроком пройти процес створення сцени, подібної до тієї, що міститься в демонстрації.

Спочатку додайте Sprite і встановіть його текстуру як фонове зображення. Для вашої гри це може бути будь-який фон, який ви оберете. Для цього стилю тіней це, швидше за все, текстура підлоги.

../../_images/light_shadow_background.png

Далі створіть три Light2D і встановіть їх текстуру на зображення світла. Ви можете змінити їх колір у верхньому розділі. За замовчуванням тіні вимкнені, а mode встановлений на значенні add. Це означає, що кожне світло додає свій колір усьому, що знаходиться під ним.

../../_images/light_shadow_all_lights_no_blob.png

Next add a child Sprite to each of the Light nodes, and set the Sprite's texture to the blob image. Each of these should stay centered on the Light node. The blob is the image of the light itself while the Light shows the effect that the light has on the scene. The LightOccluder2D's will treat the position of the light as the center of the Light node, which is why we want the blob to be centered on its parent Light.

../../_images/light_shadow_all_lights.png

Примітка

The animations in the demo will not be covered here. See Introduction to the animation features for information on creating animations.

Right now the scene should look too bright. This is because all three lights are adding color to the scene. This is why the demo uses a CanvasModulate in the scene. The CanvasModulate multiples the entire viewport by a specific color.

Add a CanvasModulate to the scene and set its color to rgb(70, 70, 70). This will make the scene sufficiently dark to see the effects of the lights distinctly.

../../_images/light_shadow_ambient.png

Now we add the shadow casters.

The demo uses a Node named "casters" to organize the shadow casters. Add a Node2D to the scene. It will be used to group all the shadow casters together. This way we can show and hide them all at the same time.

Each shadow caster is made of a Sprite, with a LightOccluder2D child. For the demo the Sprite has a texture set to the caster image and nothing else. The child LightOccluder2D is where all the magic happens. In a game the Sprite could be more than a black box; it could be an image of whatever object is casting the shadow: a wall, a magical chest, or anything else.

../../_images/light_shadow_sprites.png

LightOccluder2Ds tell the game what shape the occluder has. They hold an OccluderPolygon2D, which is a container for a polygon and some other information. For this demo, since our wall is a square, we set Polygon to a square. The other default settings are fine.

The first setting, Closed can be either on or off. A closed polygon occludes light coming from all directions. An open polygon only occludes light from one direction.

Cull Mode lets you select which direction gets culled. The default is Disabled, meaning the occluder will cast a shadow no matter which side the light is on. The other two settings Clockwise and Counter-Clockwise refer to the winding order of the vertices of the polygon. The winding order is used to determine which side of the line is inside the polygon. Only outward facing lines cast shadows.

To illustrate the difference, here is an image of a LightOccluder2D with Closed set to off in the corresponding OccluderPolygon2D, so that the lines of the polygon can be seen:

../../_images/light_shadow_cull_disabled.png

Примітка

Cull Mode is set to Disabled. All three lines cast shadows.

../../_images/light_shadow_cull_clockwise.png

Примітка

Cull Mode is set to Clockwise. Only the top and right lines cast shadows.

../../_images/light_shadow_cull_counter_clockwise.png

Примітка

Cull Mode is set to Counter-Clockwise. Only the bottom line casts a shadow. If Closed was set to on there would be an additional vertical line on the left which would cast a shadow as well.

When you have added the LightOccluder2Ds the shadows still won't appear. You need to go back into the Light2Ds and under the Shadow section set Enable to on. This turns on shadows with hard edges like in the image below.

../../_images/light_shadow_filter0_pcf0.png

To give the shadows that nice, soft edge look we set the variables filter, filter smooth, and gradient length. Godot supports Percentage Closer Filtering (PCF), which takes multiple samples of the shadow map around a pixel and blurs them to create a smooth shadow effect. The higher the number of samples the smoother the shadow will look, but the slower it will run. That is why Godot provides 3-13 samples by default and allows you to choose. The demo uses PCF7.

../../_images/light_shadow_normal.png

Примітка

This is a shadow rendered with the demo's settings. gradient length is set to 1.3, filter smooth is set to 11.1, and filter is set to PCF7.

../../_images/light_shadow_pcf13.png

Примітка

filter is set to PCF13. Notice how the shadow becomes wider, this is because the distance between samples is based on the variable filter smooth.

In order to make use of filtering you need to set the filter smooth variable. This dictates how far apart the samples are. If you want the soft area to extend quite far, you can increase the size of filter smooth. However, with few samples and a large filter smooth, you can see lines forming between the samples.

../../_images/light_shadow_filter30.png

Примітка

filter smooth is set to 30.

The different Light nodes in the demo use different values for filter smooth. Play around with it and see what you like.

../../_images/light_shadow_filter0.png

Примітка

filter smooth is set to 0.

Lastly, there is the variable gradient length. For some smooth shadows it is preferable not to have the shadow start immediately on the object, as this produces a hard edge. The gradient length variable creates a smooth gradient to begin the shadow to reduce the effect of the hard edge.

../../_images/light_shadow_grad0.png

Примітка

gradient length is set to 0.

../../_images/light_shadow_grad10.png

Примітка

gradient length is set to 10.

You will need to play around with the options a bit to find settings that suit your project. There is no right solution for everyone, which is why Godot provides so much flexibility. Just keep in mind that the higher filter set the more expensive the shadows will be.