Некоторые шейдеры фрагментов в ShaderToy (например, гидродинамика, https://www.shadertoy.com/view/4tGfDW ) используют один и тот же буфер как для ввода, так и для вывода. Но когда я пытаюсь сделать это в своем коде C/C++, это не работает (я визуализирую странные артефакты шахматной доски, такие как непоследовательная зрительная память). Чтобы обойти эту проблему, я должен использовать два разных FrameBuffers A, B и перевернуть текстуры (сначала визуализировать A в B, а затем визуализировать B обратно в A)
Я понимаю, что OpenGL не позволяет использовать одну и ту же текстуру как для ввода, так и для вывода (?) из-за проблем с согласованностью памяти. Но нет ли более элегантного решения, чем использование двух FrameBuffers? Например. используя некоторую блокировку или временный кеш (я не знаю какой-либо флаг синхронизации, который позаботится об этом) ???
EDIT — Подробная информация для ответа на комментарий/вопрос:
OpenGL (в зависимости от версии GL) имеет некоторые очень специфические правила того, что можно и что нельзя делать, когда одна и та же текстура используется в качестве цели рендеринга и ввода сэмплера. Может ли ваш вариант использования быть реализован в рамках этого набора требований или нет, неясно, поскольку вы не объяснили, что именно вам нужно или вы хотите сделать здесь.
в основном я хочу реализовать решатель Fluid-Dynamics (например, из ShaderToy, указанный выше), а также другие решатели уравнений в частных производных. Это означает, что вывод каждого пикселя зависит от некоторой маски свертки (производной, лапласиана, среднего) соседних пикселей. Также может быть некоторое движение (адвекция), что означает, что значения считывания формируют удаленные пиксели.
В настоящее время я понял, что артефакты появляются в основном, когда я читаю/записываю пиксели, которые находятся в другом месте, т.е. это не локально (например, пиксель[100,100] зависит от пикселя[10,10])
Пример простого решения Fluid-Solver от Shadertoy:
vec4 solveFluid(sampler2D smp, vec2 uv, vec2 w, float time, vec3 mouse, vec3 lastMouse)
{
const float K = 0.2;
const float v = 0.55;
vec4 data = textureLod(smp, uv, 0.0);
vec4 tr = textureLod(smp, uv + vec2(w.x , 0), 0.0);
vec4 tl = textureLod(smp, uv - vec2(w.x , 0), 0.0);
vec4 tu = textureLod(smp, uv + vec2(0 , w.y), 0.0);
vec4 td = textureLod(smp, uv - vec2(0 , w.y), 0.0);
vec3 dx = (tr.xyz - tl.xyz)*0.5;
vec3 dy = (tu.xyz - td.xyz)*0.5;
vec2 densDif = vec2(dx.z ,dy.z);
data.z -= dt*dot(vec3(densDif, dx.x + dy.y) ,data.xyz); //density
vec2 laplacian = tu.xy + td.xy + tr.xy + tl.xy - 4.0*data.xy;
vec2 viscForce = vec2(v)*laplacian;
data.xyw = textureLod(smp, uv - dt*data.xy*w, 0.).xyw; //advection
vec2 newForce = vec2(0);
data.xy += dt*(viscForce.xy - K/dt*densDif + newForce); //update velocity
data.xy = max(vec2(0), abs(data.xy)-1e-4)*sign(data.xy); //linear velocity decay
#ifdef USE_VORTICITY_CONFINEMENT
data.w = (tr.y - tl.y - tu.x + td.x);
vec2 vort = vec2(abs(tu.w) - abs(td.w), abs(tl.w) - abs(tr.w));
vort *= VORTICITY_AMOUNT/length(vort + 1e-9)*data.w;
data.xy += vort;
#endif
data.y *= smoothstep(.5,.48,abs(uv.y-0.5)); //Boundaries
data = clamp(data, vec4(vec2(-10), 0.5 , -10.), vec4(vec2(10), 3.0 , 10.));
return data;
}
gl_LastFragData
) - person Rabbid76   schedule 11.10.2020