Notice: file_put_contents(): Write of 4497 bytes failed with errno=28 No space left on device in /var/www/tgoop/post.php on line 50

Warning: file_put_contents(): Only 16384 of 20881 bytes written, possibly out of free disk space in /var/www/tgoop/post.php on line 50
Log of Alprog@logofalprog P.112
LOGOFALPROG Telegram 112
Силуэтики и обводочки
#кодище
Ох и затяжные каникулы сами собой получились на канале! Что ж, давайте попробуем начать что-то вроде второго сезона. Я даже второй гуглдоковский файл завёл по этому поводу.

И начнём мы с такой привычной всем штуки, как силуэты. Способов их делать существует бесчисленное множество. Мы, как водится, запилили нечто своё. Чем-то похожее на то, как везде; а чем-то, возможно, и необычное. Не претендуем на супер новизну или крутость техники, но, тем не менее, кому-нибудь может быть интересно.

Прежде всего надо отметить, что у нас в понятие силуэт входит сразу два цвета: заливка объекта (на скриншоте белый) и обводка (жёлтый). Обводка показывается всегда, а заливка только для тех областей, которые перекрыты какими-то другими объектами. В зависимости от игровой ситуации, геймплейный код помечает объекты, которые нам нужно обвести: дескать, вот этого врага надо залить розовым с красной обводкой, игрока салатовым с зелёным, а вон тот стул — только обвести белым, но не заливать. При этом все объекты могут, само собой, как угодно друг с другом пересекаться.

Мы решаем это так. Сперва берём все комбинации обводка + заливка и загоняем в StructuredBuffer, чтобы обозначать комбинацию одним байтом по индексу. Не более 256 разных вариантов в кадре получается. Нам этого не то, что на один кадр, нам этого на всю игру хватает, так что буфер меняться в процессе не будет.

Затем берём полноэкранный буфер и начинаем рисовать в него все подсвеченные объекты по следующей схеме:
// R — Always 1 (indicate that silhouette exists)
// G — Index of silhouette colors
// B — Opacity if hidden
// A — Is pixel visible? (1 — visible, 0 — hidden by other objects)


Причём достигаем мы этого аж двумя пассами. Для первого прохода выставлена опция ZTest == Equal, то есть он записывает только те пиксели, что не перекрыты другими объектами. По схеме выше выглядит это примерно так (_SilhouetteIndex — это глобальный uniform для текущего draw):
return float4(1, (float)_SilhouetteIndex / 255, 0, 1);


Второй же пасс пишет с опцией ZTest == Greater, то есть, напротив, только те пиксели, которые оказались под чем-то. R и G составляющие выглядят точно также, а для B мы вычисляем значение opacity силуэта, которое зависит от того, насколько глубоко объект перекрыт другой геометрией (сравниваем с текущим значением ZBuffer). Это нужно для того, чтобы маскировать мелкие косяки анимации, когда меш слегка погружается в пол при ходьбе по лестницам и подобным неровным местам.

А вот в альфа-канал на втором пассе мы вообще ничего не пишем! Если кто-то записал 1 в альфу, то она должна там остаться навсегда. Этот трюк необходим как раз для правильной обработки перекрытий силуэтов друг друга. Конечно, цвет испортится, но если силуэт ничем не перекрыт, то нам он и не нужен. Впрочем, при очень большом желании мы могли бы и его сохранить через блендинг вида OneMinusSrcAlpha SrcAlpha.

Но мы отвлеклись. Полноэкранный буфер с мета-инфой о силуэтах это, конечно, прекрасно, но как нарисовать силуэты? А с помощью того шейдера, что показан на скриншоте (разумеется, рисуем не полноэкранно, а только небольшие квады в тех местах, где у нас есть силуэты).

Как видно по коду, там где мы отрисовали силуэт, мы просто достаём цвет заливки и покрываем им скрытые части объекта (видимые не трогаем). А для тех мест, где силуэт не отрисован, мы делаем однопиксельное смещение во все стороны. И если находим хотя бы один пиксель силуэта, то считает это место местом обводки. Цвет обводки берётся при этом как среднее из всех найденных силуэтов вокруг этого пикселя.

Вот примерно такие дела. Надеюсь, не слишком запутанно вышло.

Обсудить



tgoop.com/logofalprog/112
Create:
Last Update:

Силуэтики и обводочки
#кодище
Ох и затяжные каникулы сами собой получились на канале! Что ж, давайте попробуем начать что-то вроде второго сезона. Я даже второй гуглдоковский файл завёл по этому поводу.

И начнём мы с такой привычной всем штуки, как силуэты. Способов их делать существует бесчисленное множество. Мы, как водится, запилили нечто своё. Чем-то похожее на то, как везде; а чем-то, возможно, и необычное. Не претендуем на супер новизну или крутость техники, но, тем не менее, кому-нибудь может быть интересно.

Прежде всего надо отметить, что у нас в понятие силуэт входит сразу два цвета: заливка объекта (на скриншоте белый) и обводка (жёлтый). Обводка показывается всегда, а заливка только для тех областей, которые перекрыты какими-то другими объектами. В зависимости от игровой ситуации, геймплейный код помечает объекты, которые нам нужно обвести: дескать, вот этого врага надо залить розовым с красной обводкой, игрока салатовым с зелёным, а вон тот стул — только обвести белым, но не заливать. При этом все объекты могут, само собой, как угодно друг с другом пересекаться.

Мы решаем это так. Сперва берём все комбинации обводка + заливка и загоняем в StructuredBuffer, чтобы обозначать комбинацию одним байтом по индексу. Не более 256 разных вариантов в кадре получается. Нам этого не то, что на один кадр, нам этого на всю игру хватает, так что буфер меняться в процессе не будет.

Затем берём полноэкранный буфер и начинаем рисовать в него все подсвеченные объекты по следующей схеме:

// R — Always 1 (indicate that silhouette exists)
// G — Index of silhouette colors
// B — Opacity if hidden
// A — Is pixel visible? (1 — visible, 0 — hidden by other objects)


Причём достигаем мы этого аж двумя пассами. Для первого прохода выставлена опция ZTest == Equal, то есть он записывает только те пиксели, что не перекрыты другими объектами. По схеме выше выглядит это примерно так (_SilhouetteIndex — это глобальный uniform для текущего draw):
return float4(1, (float)_SilhouetteIndex / 255, 0, 1);


Второй же пасс пишет с опцией ZTest == Greater, то есть, напротив, только те пиксели, которые оказались под чем-то. R и G составляющие выглядят точно также, а для B мы вычисляем значение opacity силуэта, которое зависит от того, насколько глубоко объект перекрыт другой геометрией (сравниваем с текущим значением ZBuffer). Это нужно для того, чтобы маскировать мелкие косяки анимации, когда меш слегка погружается в пол при ходьбе по лестницам и подобным неровным местам.

А вот в альфа-канал на втором пассе мы вообще ничего не пишем! Если кто-то записал 1 в альфу, то она должна там остаться навсегда. Этот трюк необходим как раз для правильной обработки перекрытий силуэтов друг друга. Конечно, цвет испортится, но если силуэт ничем не перекрыт, то нам он и не нужен. Впрочем, при очень большом желании мы могли бы и его сохранить через блендинг вида OneMinusSrcAlpha SrcAlpha.

Но мы отвлеклись. Полноэкранный буфер с мета-инфой о силуэтах это, конечно, прекрасно, но как нарисовать силуэты? А с помощью того шейдера, что показан на скриншоте (разумеется, рисуем не полноэкранно, а только небольшие квады в тех местах, где у нас есть силуэты).

Как видно по коду, там где мы отрисовали силуэт, мы просто достаём цвет заливки и покрываем им скрытые части объекта (видимые не трогаем). А для тех мест, где силуэт не отрисован, мы делаем однопиксельное смещение во все стороны. И если находим хотя бы один пиксель силуэта, то считает это место местом обводки. Цвет обводки берётся при этом как среднее из всех найденных силуэтов вокруг этого пикселя.

Вот примерно такие дела. Надеюсь, не слишком запутанно вышло.

Обсудить

BY Log of Alprog


Share with your friend now:
tgoop.com/logofalprog/112

View MORE
Open in Telegram


Telegram News

Date: |

The Channel name and bio must be no more than 255 characters long Telegram channels enable users to broadcast messages to multiple users simultaneously. Like on social media, users need to subscribe to your channel to get access to your content published by one or more administrators. Polls 2How to set up a Telegram channel? (A step-by-step tutorial) Telegram is a leading cloud-based instant messages platform. It became popular in recent years for its privacy, speed, voice and video quality, and other unmatched features over its main competitor Whatsapp.
from us


Telegram Log of Alprog
FROM American