Расчет глубины пикселя
В процессе оптимизации демки для PS3 выяснилось, что было бы неплохо оптимизировать шейдер для частиц. В вершинном шейдере происходит расчет позиций 4 вершин (частицы – билборд), а-ля point sprite, но размер указывается в world space, и частицы можно крутить. В пиксельном шейдере считается глубина, читается глубина из depth texture, и разница с коэффициентом используется как множитель к альфе.
Выглядит шейдер так:
float depth = uvDepth.z / uvDepth.w;
float4 screenDepthARGB = tex2Dproj(depthMap, uvDepth);
// B is stencil, ARG are depth bits, A is MSB, G is LSB
float screenDepth = dot(screenDepthARGB, float4(1/255.0, 1/255.0/255.0, 0, 1));
color_out = tex2D(diffuseMap, uv) * color_in;
color_out.a *= saturate((screenDepth - depth) * depthCoeff);
Одна оптимизация очевидна – в последней строчке можно либо заменить sub + mul на mad, либо просто оставить sub (умножать в VS uvDepth.z на depthCoeff, и в качестве второго аргумента dot использовать float4(1/255.0, 1/255.0/255.0, 0, 1) * depthCoeff (посчитанное на CPU, конечно же).
Хочется сказать о другой. Вычисление глубины пикселя можно вынести в VS. После того, как в первый раз натыкаешься на то, что частное интерполированных величин от интерполирования частного отличается, как-то дальше уже не приходит в голову то, что иногда – операция законна. И не дает артефактов даже теоретически.
Действительно, т.к. частицы – билборды, то во всех точках одной частицы глубина – одинаковая. Можно смело делить в VS.
Не умею правильно считать глубину, умею правильно считать глубину, умею не считать глубину правильно.
crossposted to zeux.livejournal.com