Render Script для начинающих. 3. Вне матрицы (render predicates и draw) [Defold без боли]

Если вам поможет это материал в обучении, буду искренне благодарен вам за то, что вы не поленитесь порекомендовать его для начинающих!

В прошлом посте мы говорили о цветовом буфере. По логике, мы должны были быть последовательными и перейти к знакомству с буфером трафарета и буфером глубины. Погружаясь в эту кроличью нору, мне кажется, что прежде чем говорить понятным языком про остальные буферы, нам не помешает затронуть предварительно несколько других тем, связанные с рендер-скриптом напрямую.

Render Predicates (предикаты рендеринга)

В Defold предикат — это фильтр, созданный с помощью render.predicate(), который определяет, какие игровые компоненты (с определёнными тегами) будут отрисованы в render.draw(). Он работает как “да/нет” для каждого draw call на основе тегов.

А что вообще можно рисовать в Defold?

Развернуть список:
  • Sprites: 2D-изображения, часто используемые для персонажей, фонов или UI-элементов.
  • Tilemaps: Карты из тайлов (плиток), для создания уровней, ландшафтов или сеток.
  • Models: 3D-модели (импортированные из .dae файлов), включая анимированные.
  • Meshes(component “mesh”): Пользовательские meshes (сетки вершин) для продвинутой геометрии, как procedural generation.
  • Particles: Эффекты частиц через ParticleFX, для огня, дыма, взрывов и т.д.
  • Labels: Текст (надписи), для отображения строк, счетчиков или сообщений.
  • GUI nodes: Узлы GUI, включая:
    Box nodes (прямоугольники, для кнопок или панелей).
    Text nodes (текст в GUI).
    Pie nodes (круговые/секторные формы).
    Примечание: В Defold GUI рендерится отдельно от игрового мира, часто в overlay.
  • Spine nodes (анимации Spine в GUI). (Относительно новый компонент).
  • ParticleFX nodes (частицы в GUI).
  • Template nodes (вложенные GUI-шаблоны).
  • Spine animations: Анимации на основе Spine (как модели или в GUI).
  • Rive animations: Анимации через Rive model components для векторной графики. (Относительно новый компонент).

Как видите, список огромен!

Давайте попробуем отобразить компонент спрайт на нашем экране. Для этого создайте в коллекции игровой объект и добавьте какое-нибудь изображение спрайту:


Разместите созданный игровой объект в диапазон ширины и высоты экрана игры, указанного в настройках game.project:

Если мы добавим в наш рендер скрипт код ниже и запустим проект:

function init(self)
    self.sprite_pred = render.predicate({hash("tile")})
end

function update(self, dt)
    render.draw(self.sprite_pred)
end

К сожалению, мы не сможешь увидеть наш спрайт :sob:

Как думаете, почему?

Мы как игровые разработчики, не знакомые с рендер-скриптом, привыкли видеть игровой мир в пикселях от 0 до 720, 960, 1080, 1920 и т.д. Где координаты X и Y имеют соответствующее значение нашему разрешению экрана, указанные в настройках игры.
Мы можем даже не догадываться о том, что, в самом конце, когда рендер-скрипт передаёт данные видеокарте. Видеокарта видит мир как единичный куб (NDC — Normalized Device Coordinates):

  • X (Ширина): Левый край экрана = -1, Правый край = +1. (Центр = 0).
  • Y (Высота): Низ экрана = -1, Верх экрана = +1.
  • Z (Глубина): Ближе всего к экрану = -1, Дальше всего = +1.

Всё, что попадает в эти цифры — рисуется. Всё, что больше 1 или меньше -1 — отрезается (clipping) и невидимо.
Кстати, В Defold/OpenGL NDC — пост-проекционный пространство.

Попробуйте теперь расположить игровой объект в координаты (0,0,0) и запустите проект:


Теперь мы явно что-то видим…
И если я разверну экран, то я увижу какой-то белый прямоугольник:

Вам напоминает это небоскрёб?


Такое ощущение, как будто мы находимся на крыше небоскрёба и смотрим в пол:

Давайте изменим масштаб спрайта:


А теперь запустим проект:

Боже мой, кажись мы “находились” в центре Вселенной :sweat_smile:

Как говорилось выше, видеокарта видит в диапазонах от -1 до 1.
Не верите? Проверьте сами, поиграйте с значением масштаба этого спрайта!


Домашнее задание:

  1. Познакомиться с матрицами (ничего сложного в них нет).
    Они в дальнейшем нам пригодятся.
  2. Ознакомиться с render.draw()
  3. Ознакомиться с render.predicate()

Спасибо за внимание!

Если есть вопросы или ошибки, сообщите о них!