Волшебный блендинг

Давненько ничего не писал в блог, буду исправляться потихоньку.

В системах частиц и всяких спецэффектах часто нужно рисовать с различным блендингом,
классически это add blend и alpha blend.

Обычно рисуют сортированные (по эмиттерам или по частицам) партиклы с alpha blend, а потом поверх кладут частицы с add blend (их уже можно не сортировать).

Но, художникам иногда очень хочется нарисовать партикл с add blend, а поверх него с alpha blend.

И уж точно программистам всегда хочется рисовать все частицы за один batch, независимо от их блендинга.

Итак, немного простой математики:
Формула блендинга destColor = sourcePixel * srcBlend + screenPixel * dstBlend;

Для add blend задают srcBlend и dstBlend как one, получая:

//blend function
destColor = sourcePixel + screenPixel;
_Winnie C++ Colorizer

Для alpha blend задают srcBlend как srcAlpha и dstBlend как invSrcAlpha, получая:

//blend function
destColor = sourcePixel * srcAlpha  + screenPixel * invSrcAlpha;
_Winnie C++ Colorizer

Так как же совместить эти два режима блендинга в одном ?

Задаем srcBlend как one и dstBlend как invSrcAlpha, получаем:

//blend function
destColor = sourcePixel + screenPixel * invSrcAlpha;
_Winnie C++ Colorizer

Теперь, следите за руками :) несколько манипуляций в pixel shader:

//0.0 это Add blend
//1.0 это Alpha blend
float addOrBlend = 0.0; 

float4 ps_test( PS_INPUT pix ) : COLOR0
{
   float4 texel = tex2D(baseMap, pix.texCoord0);
   texel.rgb = texel.rgb * texel.a;
   texel.a = texel.a * addOrBlend;
   return texel;
}
_Winnie C++ Colorizer

Посмотрим, что же получилось и самое главное, как.

Итак наша формула блендинга destColor = sourcePixel + screenPixel * invSrcAlpha;
при значении addOrBlend = 0.0; получаем (с учетом математики в pixel shader):

//blend function
destColor = sourcePixel * srcAlpha  + screenPixel;
_Winnie C++ Colorizer

при значении addOrBlend = 1.0; получаем (с учетом математики в pixel shader):

//blend function
destColor = sourcePixel * srcAlpha  + screenPixel * invSrcAlpha;
_Winnie C++ Colorizer

Как видно, add blend получается не совсем “чистый”, цвет текстуры умножается на альфу, но это дает нам возможность плавно менять addOrBlend соответственно плавно изменяя режим блендинга.

Если вдруг нужно только бинарное значение и хочется “чистый” блендинг, можно немного изменить наш шейдер: texel.rgb = texel.rgb * lerp (texel.a, 1.0, addOrBlend);

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

Надеюсь это пригодится и в вашем проекте.

Leave a comment

Your comment