Trik untuk kabur Gaussian cepat dengan GLSL adalah untuk mengambil keuntungan dari kenyataan bahwa GPU menyediakan interpolasi linier dalam perangkat keras. Oleh karena itu, Anda dapat secara efektif mencicipi empat piksel 2D dengan satu prefetch atau delapan voxels 3D. Dengan memutuskan tempat sampel Anda dapat menimbang hasilnya. Referensi definitif adalah Sigg dan Hadwiger's "Fast-Order Texture Filtering" yang dapat Anda temukan online.
Untuk penjelasan yang mudah dibaca, temukan halaman web "Efficient Gaussian blur with linear sampling". Sebagaimana dicatat, karena blur Gaussian dapat dipisahkan dengan kernel yang luas, maka paling efisien untuk melakukan satu lintasan per dimensi.
Namun, Anda juga dapat menggunakan trik ini untuk memperkirakan Gaussian dengan kernel yang ketat dalam sekali operan. Pada contoh di bawah ini saya mengemulasi kernel 3D dengan slice atas = [1 2 1; 2 4 2; 1 2 1]; slice tengah = [2 4 2; 4 8 4; 2 4 2]; irisan bawah = [1 2 1; 2 4 2; 1 2 1]. Dengan mengambil sampel +/- 0,5 voxels di setiap dimensi Anda melakukan ini hanya dengan 8 tekstur mengambil daripada 27. Saya mendemonstrasikan ini dalam GLSL sebagai file shader MRIcroGL - cukup simpan save script di bawah ini sebagai "a.txt" dan letakkan di dalam Folder "Shader" MRIcroGL. Ketika Anda meluncurkan kembali program ini, Anda akan melihat gambar ray cast Anda kabur. Mengklik kotak centang "doBlur" mengaktifkan dan menonaktifkan pengaburan. Menggunakan Intel GPU terintegrasi saya di laptop saya dan "chris_t1" gambar yang datang dengan MRIcroGL saya mendapatkan 70fps tanpa kabur (1 fetch tekstur) dan 21fps dengan blurring (8 fetches). Sebagian besar kode hanyalah ray caster klasik, "doBlur" bersyarat merangkum pertanyaan Anda.
//-------a.txt mengikuti
//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;
}