Sztuką szybkiego rozmycia gaussowskiego za pomocą GLSL jest wykorzystanie faktu, że GPU zapewnia interpolację liniową w sprzęcie. Dlatego możesz skutecznie próbkować cztery piksele 2D za pomocą pojedynczego pobrania wstępnego lub ośmiu wokseli 3D. Decydując, gdzie próbkować, możesz zważyć wynik. Ostatecznym odniesieniem jest „Szybkie filtrowanie tekstur trzeciego rzędu” Sigga i Hadwigera, które można znaleźć w Internecie.
Aby uzyskać czytelne wyjaśnienie, należy znaleźć stronę internetową „Efektywne rozmycie gaussowskie z próbkowaniem liniowym”. Jak zauważono, ponieważ rozmycie gaussowskie można rozdzielić szerokimi ziarnami, najskuteczniejsze jest wykonanie jednego przejścia na wymiar.
Możesz jednak użyć tej sztuczki, aby zbliżyć Gaussa z ciasnym jądrem w jednym przejściu. W poniższym przykładzie emuluję jądro 3D z górnym wycięciem = [1 2 1; 2 4 2; 1 2 1]; środkowy plasterek = [2 4 2; 4 8 4; 2 4 2]; dolny plasterek = [1 2 1; 2 4 2; 1 2 1]. Próbkując +/- 0,5 wokseli w każdym wymiarze, robisz to za pomocą 8 pobrań tekstur zamiast 27. Pokazuję to w GLSL jako plik modułu cieniującego MRIcroGL - po prostu upuść, zapisz poniższy skrypt jako „a.txt” i umieść go w Folder „Shader” MRIcroGL. Po ponownym uruchomieniu programu zobaczysz rozmazany obraz. Kliknięcie pola wyboru „doBlur” włącza i wyłącza rozmycie. Używanie zintegrowanego procesora graficznego Intel w laptopie i „chris_t1” obraz, który pochodzi z MRIcroGL Dostaję 70 klatek na sekundę bez rozmycia (1 pobieranie tekstury) i 21 klatek na sekundę z rozmyciem (8 pobrań). Większość kodu to tylko klasyczny rayaster, warunek „doBlur” zawiera w sobie twoje pytanie.
Następuje plik //-------a.txt
//pref
doBlur|bool|true
//vert
void main() {
gl_TexCoord[1] = gl_MultiTexCoord1;
gl_Position = ftransform();
}
//frag
uniform int loops;
uniform float stepSize, sliceSize, viewWidth, viewHeight;
uniform sampler3D intensityVol;
uniform sampler2D backFace;
uniform vec3 clearColor;
uniform bool doBlur;
void main() {
// get normalized pixel coordinate in view port (e.g. [0,1]x[0,1])
vec2 pixelCoord = gl_FragCoord.st;
pixelCoord.x /= viewWidth;
pixelCoord.y /= viewHeight;
// starting position of the ray is stored in the texture coordinate
vec3 start = gl_TexCoord[1].xyz;
vec3 backPosition = texture2D(backFace,pixelCoord).xyz;
vec3 dir = backPosition - start;
float len = length(dir);
dir = normalize(dir);
vec3 deltaDir = dir * stepSize;
vec4 colorSample,colAcc = vec4(0.0,0.0,0.0,0.0);
float lengthAcc = 0.0;
float opacityCorrection = stepSize/sliceSize;
//ray dithering http://marcusbannerman.co.uk/index.php/home/42-articles/97-vol-render-optimizations.html
vec3 samplePos = start.xyz + deltaDir* (fract(sin(gl_FragCoord.x * 12.9898 + gl_FragCoord.y * 78.233) * 43758.5453));
//offset to eight locations surround target: permute top/bottom, anterior/posterior, left/right
float dx = 0.5; //distance from target voxel
vec3 vTAR = vec3( dx, dx, dx)*sliceSize;
vec3 vTAL = vec3( dx, dx,-dx)*sliceSize;
vec3 vTPR = vec3( dx,-dx, dx)*sliceSize;
vec3 vTPL = vec3( dx,-dx,-dx)*sliceSize;
vec3 vBAR = vec3(-dx, dx, dx)*sliceSize;
vec3 vBAL = vec3(-dx, dx,-dx)*sliceSize;
vec3 vBPR = vec3(-dx,-dx, dx)*sliceSize;
vec3 vBPL = vec3(-dx,-dx,-dx)*sliceSize;
for(int i = 0; i < loops; i++) {
if (doBlur) {
colorSample = texture3D(intensityVol,samplePos+vTAR);
colorSample += texture3D(intensityVol,samplePos+vTAL);
colorSample += texture3D(intensityVol,samplePos+vTPR);
colorSample += texture3D(intensityVol,samplePos+vTPL);
colorSample += texture3D(intensityVol,samplePos+vBAR);
colorSample += texture3D(intensityVol,samplePos+vBAL);
colorSample += texture3D(intensityVol,samplePos+vBPR);
colorSample += texture3D(intensityVol,samplePos+vBPL);
colorSample *= 0.125; //average of 8 sample locations
} else
colorSample = texture3D(intensityVol,samplePos);
colorSample.a = 1.0-pow((1.0 - colorSample.a), opacityCorrection);
colorSample.rgb *= colorSample.a;
//accumulate color
colAcc = (1.0 - colAcc.a) * colorSample + colAcc;
samplePos += deltaDir;
lengthAcc += stepSize;
// terminate if opacity > 95% or the ray is outside the volume
if ( lengthAcc >= len || colAcc.a > 0.95 ) break;
}
colAcc.rgb = mix(clearColor,colAcc.rgb,colAcc.a);
gl_FragColor = colAcc;
}