GLSL - gaussian เบลอหนึ่งรอบ


18

เป็นไปได้หรือไม่ที่จะใช้ส่วนของ shader เพื่อทำ gaussian blur One-pass? ฉันพบว่ามีการใช้งานเบลอสองทาง (เกาส์เซียนและเบลอเบลอ):

และอื่น ๆ

ฉันคิดว่าจะใช้ gaussian blur เป็น convolution (อันที่จริงแล้วมันคือ convolution, ตัวอย่างข้างต้นเป็นเพียงการประมาณ):

http://en.wikipedia.org/wiki/Gaussian_blur

คำตอบ:


33

ใช่คุณสามารถใช้ Gaussian เบลอในหนึ่งรอบโดยสุ่มตัวอย่างทั้งหมด n ^ 2 พิกเซลในเคอร์เนล (สำหรับความกว้างเคอร์เนล n) โดยทั่วไปแล้วจะเร็วกว่าที่จะเรียกใช้บนแถวและคอลัมน์สองรอบเนื่องจากคุณมีพิกเซล O (n) ตัวอย่างมากกว่า O (n ^ 2) นี่ไม่ใช่การประมาณค่าเนื่องจากความเบลอของเกาส์เซสสามารถแยกทางคณิตศาสตร์ได้


1
นี่เป็นบัตรเดี่ยวที่ดีและยืดหยุ่นได้ Blur Shader: shadertoy.com/view/XdfGDH
Ray Hulha

7

เคล็ดลับสำหรับการเสียรูปแบบเกาส์เซียนอย่างรวดเร็วด้วย GLSL คือการใช้ประโยชน์จากความจริงที่ว่า GPU ให้การแก้ไขเชิงเส้นในฮาร์ดแวร์ ดังนั้นคุณสามารถสุ่มตัวอย่างสองพิกเซลแบบสี่พิกเซลได้ด้วยการดึงข้อมูลล่วงหน้าหนึ่งครั้งหรือแปด voxels แบบสามมิติ ด้วยการตัดสินใจว่าจะเก็บตัวอย่างที่ใดคุณสามารถถ่วงน้ำหนักเอาต์พุต การอ้างอิงที่ชัดเจนคือ Sigg และ Hadwiger "การกรองพื้นผิวการสั่งซื้อที่รวดเร็ว" ซึ่งคุณสามารถค้นหาทางออนไลน์ได้

สำหรับคำอธิบายที่สามารถอ่านได้พบหน้าเว็บ "เบลอแบบเกาส์ที่มีประสิทธิภาพพร้อมการสุ่มตัวอย่างเชิงเส้น" ดังที่กล่าวไว้เนื่องจากความเบลอของเกาส์แยกออกจากกันด้วยเมล็ดที่กว้างมันจึงมีประสิทธิภาพมากที่สุดในการผ่านหนึ่งมิติต่อมิติ

อย่างไรก็ตามคุณยังสามารถใช้เคล็ดลับนี้เพื่อประมาณ Gaussian ด้วยเคอร์เนลที่แน่นหนาในรอบเดียว ในตัวอย่างด้านล่างฉันจำลองเคอร์เนล 3 มิติด้วยชิ้นส่วนด้านบน = [1 2 1; 2 4 2; 1 2 1]; ชิ้นกลาง = [2 4 2; 4 8 4; 2 4 2]; ท่อนล่าง = [1 2 1; 2 4 2; 1 2 1] โดยการสุ่มตัวอย่าง +/- 0.5 voxels ในแต่ละมิติคุณทำสิ่งนี้ด้วยการดึงข้อมูลพื้นผิวเพียง 8 ครั้งมากกว่า 27. ฉันกำลังสาธิตเรื่องนี้ใน GLSL เป็นไฟล์ shader MRIcroGL - เพียงวางบันทึกสคริปต์ด้านล่างเป็น "a.txt" และวางไว้ใน โฟลเดอร์ "Shader" ของ MRIcroGL เมื่อคุณเปิดโปรแกรมขึ้นใหม่คุณจะเห็นภาพที่ฉายด้วยแสงเบลอ คลิกที่ช่องทำเครื่องหมาย "doBlur" เพื่อสลับการเปิดและปิดการเบลอ ใช้ Intel GPU แบบรวมในแล็ปท็อปและ "chris_t1" ภาพที่มาพร้อมกับ MRIcroGL ฉันได้ 70fps โดยไม่มีการเบลอ (1 fetch texture) และ 21fps ด้วยการเบลอ (8 fetch) รหัสส่วนใหญ่เป็นเพียงล้อเรย์คลาสสิกเงื่อนไข "doBlur" จะสรุปคำถามของคุณ

//-------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;
}

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.