понедельник, 2 августа 2010 г.

Silhouette compute shader

Написал тестовую реализацию на CPU и окончательно определился, как считать силуэты в вычислительном шейдере.

Вообще, силуэты можно искать двумя способами:
1) Идём по всем треугольникам, для каждого определяем, различается ли знак скалярного произведения (между нормалью и позицией) каждого смежного треугольника, и если да, то добавляем общее для этих треугольников ребро в силуэт.
2) Идём по всем рёбрам, для каждого определяем знак скалярного произведения смежных треугольников, если они различаются, добавляем ребро в силуэт.

Для первого способа адаптирован геометрический шейдер. Он несколько менее эффективный чем второй, т. к. на каждый треугольник приходится делать по четыре dot-a, хотя теоретически достаточно одного. Учитывая, что shading rate у GS низкий, это приемлемо.

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

Первый шаг можно описать псевдокодом как-то так: step 1
Т. е. CS получает на вход буфер нормалей треугольников, делает для каждого сэмпла dot() и считает маску. Маска записывается в write-only буфер.

Для второго шага определяем структуры следующего вида:
struct edge
{
  uint a;
  uint b;
  uint left;
  uint right;
};

struct sil_edge
{
  vec3 a
  vec3 b;
  uint mask;
}
Где а, b - индексы в буфере вершин (во второй структуре - сами вершины), left, right - индексы смежных треугольников, mask - маска сэмплов, для которых ребро определяется как силуэтное.

На входе CS - буфер вершин меша и буфер структур edge, на выходе - буфер структур sil_edge. Каждый тред занят своим ребром, псевдокод второго шага: step 2. Силуэтные рёбра получаются уникальными, но каждое хранит маску сэмплов, для которых ребро определено как силуэтное. На этапе вытягивания волюма ещё один CS (или GS, но тогда придётся дублировать маску для каждой вершины, что suxx) может из одного ребра вытянуть несколько квадов, ориентируясь по маске.

Вот такой вот простой алгоритм, но на VS/GS его не реализовать, спасает только GPGPU.

1 комментарий: