Mẹo để làm mờ Gaussian nhanh chóng với GLSL là tận dụng thực tế là GPU cung cấp phép nội suy tuyến tính trong phần cứng. Do đó, bạn có thể lấy mẫu bốn pixel 2D một cách hiệu quả bằng một lần tải trước hoặc tám voxels 3D. Bằng cách quyết định nơi lấy mẫu, bạn có thể cân trọng lượng đầu ra. Tham chiếu dứt khoát là "Lọc kết cấu thứ tự nhanh thứ ba" của Sigg và Hadwiger mà bạn có thể tìm thấy trực tuyến.
Để giải thích có thể đọc được, hãy tìm trang web "Làm mờ hiệu quả Gaussian với lấy mẫu tuyến tính". Như đã lưu ý, vì độ mờ Gaussian có thể tách rời với các hạt rộng, nên hiệu quả nhất là thực hiện một lần cho mỗi chiều.
Tuy nhiên, bạn cũng có thể sử dụng thủ thuật này để ước tính một Gaussian với một hạt nhân chặt chẽ trong một lần chạy. Trong ví dụ dưới đây, tôi mô phỏng nhân 3D với lát trên cùng = [1 2 1; 2 4 2; 1 2 1]; lát giữa = [2 4 2; 4 8 4; 2 4 2]; lát dưới = [1 2 1; 2 4 2; 1 2 1]. Bằng cách lấy mẫu +/- 0,5 voxels trong mỗi thứ nguyên, bạn thực hiện việc này chỉ với 8 lần tải kết cấu thay vì 27. Tôi đang chứng minh điều này trong GLSL dưới dạng tệp shader MRIcroGL - chỉ cần thả lưu tập lệnh bên dưới dưới dạng "a.txt" và đặt nó vào Thư mục "Shader" của MRIcroGL. Khi bạn khởi chạy lại chương trình, bạn sẽ thấy hình ảnh chiếu tia của bạn bị mờ. Nhấp vào hộp kiểm "doBlur" để bật và tắt. Sử dụng GPU Intel tích hợp của tôi trong máy tính xách tay của tôi và "chris_t1" hình ảnh đi kèm với MRIcroGL Tôi nhận được 70 khung hình / giây mà không bị mờ (1 lần tải kết cấu) và 21 khung hình / giây với độ mờ (8 lần tải). Hầu hết các mã chỉ là một caster ray cổ điển, điều kiện "doBlur" gói gọn câu hỏi của bạn.
//-------a.txt tệp theo sau
//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;
}