Вычислительные шейдеры
Вычислительные шейдеры - программы, запущенные на видеокарте за пределами территории обычного рендеринга. Они могут быть использованы для массивных параллельных GPGPU алгоритмов или для ускорения элементов рендеринга игры. Для того, чтобы эффективно их использовать, зачастую требуется глубокое знание GPU архитектур и параллельных алгоритмов; так же, как и знание DirectCompute, OpenCL или CUDA.
Compute shaders in Unity closely match DirectX 11 DirectCompute technology. Platforms where compute shaders work:
Ассеты вычислительных шейдеров
Подобно обычным шейдерам, вычислительные шейдеры являются файлами ассетов в вашем проекте с расширением файла *.compute
. Они написаны на языке HLSL в стиле DirectX 11 с минимальным количеством компиляционных директив #pragma
, для определения, какие функции нужно компилировать в роли ядер вычислительных шейдеров.
Вот минимальный пример файла вычислительного шейдера:
// test.compute
#pragma kernel FillWithRed
RWTexture2D<float4> res;
[numthreads(1,1,1)]
void FillWithRed (uint3 dtid : SV_DispatchThreadID)
{
res[dtid.xy] = float4(1,0,0,1);
}
Учтите, что пример, указанный выше, не делает ничего интересного - он просто заливает итоговую текстуру красным.
Языком является стандартный DX11 HLSL, с исключением в виде директивы #pragma kernel FillWithRed
. Один файл ассета вычислительного шейдера должен содержать по крайней мере “вычислительное ядро”, которое может быть вызвано, и эта функция помечена директивой #pragma. В файле может быть ещё больше ядер; просто добавьте несколько строк #pragma kernel
.
Please note when using multiple #pragma kernel
lines that comments of the style // text
are not permitted on the same line as the #pragma kernel
directives and will cause compilation errors.
По желанию, после строки #pragma kernel
может быть указан номер макроса препроцессора, для назначения во время компиляции этого ядра, например:
#pragma kernel KernelOne SOME_DEFINE DEFINE_WITH_VALUE=1337
#pragma kernel KernelTwo OTHER_DEFINE
// ...
Вызов вычислительных шейдеров
В вашем скрипте, задайте переменную типа ComputeShader
, назначьте ссылку на ассет, и тогда вы сможете вызывать их при помощи функции ComputeShader.Dispatch. Для деталей, см. класс ComputeShader
С вычислительными шейдерами тесно связан класс ComputeBuffer, который задаёт произвольный буфер данных (“структурированный буфер”, говоря языком DX11). Рендер текстуры также могут быть записаны в вычислительные шейдеры, если у них включён флажок “Random access” (“unordered access view” в DX11), см. RenderTexture.enableRandomWrite.
Семплеры текстур в вычислительных шейдерах
Текстуры и семплеры в Unity не являются отдельными объектами, так что для того, чтобы их использовать в вычислительном шейдере, вам надо следовать некоторым особым правилам Unity:
Texture2D MyTex; SamplerState samplerMyTex
). В таком случае семплер будет определён в настройках фильтра/оборачивания/анизотропной фильтрации текстуры."SamplerState MyLinearClampSampler"
- линейный фильтр с “Clamp” режимом оборачивания.As with regular shaders, Unity is capable of translating compute shaders from HLSL to GLSL. Therefore for the easiest cross-platform builds it is recommended to write compute shaders in HLSL.
In order to achieve shaders working on multiple different platforms one should consider these limitations:
Typically compute shader files are written in HLSL, and compiled or translated into all needed platforms automatically. However it is possible to either prevent translation to GLSL (i.e. only keep HLSL platforms), or to write GLSL compute code manually.
CGPROGRAM
and ENDCG
keywords will not be processed for OpenGL/GLSL platforms.GLSLPROGRAM
and ENDGLSL
keywords will be treated as GLSL source, and emitted verbatim. This will only work when targetting OpenGL/GLSL platforms.Note that for cross-platform builds neither of the above is recommended, since it very much ties compute shader source into being excluded from some platforms.