Это руководство поясняет работу простейшей программы, производящей вычисления на GPU. Вот ссылка на проект Юнити этой программы:
ссылка на файл проекта .unitypackage
Она рисует фрактал Мандельброта.
Я не буду пояснять каждую строчку кода, укажу только необходимые действия для реализации вычислений на GPU. Поэтому, лучше всего открыть код программы в Юнити и там смотреть, как используются поясняемые мной строчки кода.
Шейдер, который рисует фрактал, написан на языке HLSL. Ниже приведён его текст. Я кратко прокомментировал значимые строки, а развёрнутые объяснения будут ниже.
// выполняющаяся в GPU программа использует данные из видеопамяти через буфферы:
RWTexture2D<float4> textureOut; // это текстура, в которую мы будем записывать пиксели
RWStructuredBuffer<double> rect; // это границы области в пространстве фрактала, которую мы визуализируем
RWStructuredBuffer<float4> colors; // а это гамма цветов, которую мы подготовили на стороне CPU и передали в видеопамять
#pragma kernel pixelCalc // тут мы объявили кернел, по этому имени мы сможем его выполнить со стороны CPU
[numthreads(32,32,1)] // эта директива определяет количество потоков, в которыз выполнится этот кернел
void pixelCalc (uint3 id : SV_DispatchThreadID){ // тут мы задаём код кернела. Параметр id хранит индекс потока, который используется для адресации данных
float k = 0.0009765625; // это просто множитель для проекции пространства 1024х1024 текстуры на маленькую область 2х2 пространства фрактала
double dx, dy;
double p, q;
double x, y, xnew, ynew, d = 0; // использованы переменные двойной точности, чтобы отдалить столкновение с пределом точности при продвижении вглубь фрактала
uint itn = 0;
dx = rect[2] - rect[0];
dy = rect[3] - rect[1];
p = rect[0] + ((int)id.x) * k * dx;
q = rect[1] + ((int)id.y) * k * dy;
x = p;
y = q;
while (itn < 255 && d < 4){ // собственно суть фрактала: в этом цикле вычисляется число шагов, за которые точка покидает пространство 2x2
xnew = x * x - y * y + p;
ynew = 2 * x * y + q;
x = xnew;
y = ynew;
d = x * x + y * y;
itn++;
}
textureOut[id.xy] = colors[itn]; // вот так мы записываем пиксель цвета: пиксель текстуры определяется индексом, а индекс цвета - числом шагов
}
ComputeShader.Dispatch(kernelIndex, 1, 1, 1)
ComputeShader.Dispatch(kernelIndex, 2, 4, 1)
ComputeShader.Dispatch(kernelIndex, 32, 32, 1)
ComputeShader _shader
RenderTexture outputTexture
ComputeBuffer colorsBuffer
outputTexture = new RenderTexture(1024, 1024, 32);
outputTexture.enableRandomWrite = true;
outputTexture.Create();
colorsBuffer = new ComputeBuffer(colorArray.Length, 4 * 4);
colorsBuffer.SetData(colorArray);
_shader = Resources.Load<ComputeShader>("csFractal");
kiCalc = _shader.FindKernel("pixelCalc");
_shader.SetBuffer(kiCalc, "colors", colorsBuffer);
_shader.SetTexture(kiCalc, "textureOut", outputTexture);
_shader.Dispatch(kiCalc, 32, 32, 1);
К сожалению, не доступен сервер mySQL