GLSL-원 패스 가우시안 블러


18

원 패스 가우시안 블러를 수행하기 위해 프래그먼트 셰이더를 구현할 수 있습니까? 2 패스 블러 (가우시안 및 박스 블러)의 많은 구현을 발견했습니다.

등등.

나는 가우시안 블러를 컨볼 루션으로 구현하려고 생각했습니다 (실제로는 컨볼 루션이며 위의 예는 근사치입니다).

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

답변:


33

예, 커널의 모든 n ^ 2 픽셀 (커널 폭 n)을 샘플링하여 한 번에 가우시안 블러를 구현할 수 있습니다 . 일반적으로 O (n ^ 2) 대신 O (n) 픽셀을 샘플링하므로 행과 열에서 두 번의 패스로 실행하는 것이 더 빠릅니다 . 가우시안 블러는 수학적으로 분리 가능하기 때문에 이것은 근사치가 아닙니다.


1
: 여기에 좋은 유연한 단일 패스 블러 쉐이더입니다 shadertoy.com/view/XdfGDH
레이 Hulha는

7

GLSL을 사용한 빠른 가우시안 블러 링의 비결은 GPU가 하드웨어에서 선형 보간을 제공한다는 사실을 이용하는 것입니다. 따라서 단일 프리 페치 또는 8 개의 3D 복셀로 4 개의 2D 픽셀을 효과적으로 샘플링 할 수 있습니다. 샘플링 위치를 결정하면 출력에 가중치를 부여 할 수 있습니다. 결정적인 참조는 Sigg와 Hadwiger의 "Fast Third-Order Texture Filtering"이며 온라인에서 찾을 수 있습니다.

읽기 쉬운 설명을 보려면 웹 페이지 "선형 샘플링을 통한 효율적인 가우시안 블러"를 찾으십시오. 언급 한 바와 같이 가우시안 블러는 넓은 커널로 분리 할 수 ​​있으므로 차원 당 한 번만 통과하는 것이 가장 효율적입니다.

그러나이 트릭을 사용하여 단일 패스에서 단단한 커널로 가우시안을 추정 할 수도 있습니다. 아래 예에서 상단 슬라이스 = [1 2 1; 2 4 2; 1 2 1]; 중간 슬라이스 = [2 4 2; 4 8 4; 2 4 2]; 바닥 슬라이스 = [12 2; 2 4 2; 1 2 1]. 각 차원에서 +/- 0.5 복셀을 샘플링하여 27이 아닌 8 개의 텍스처 패치로이 작업을 수행 할 수 있습니다. GLSL에서 MRIcroGL 셰이더 파일로 시연하고 있습니다. 아래의 스크립트를 "a.txt"로 저장 한 다음 MRIcroGL의 "Shader"폴더 프로그램을 다시 시작하면 레이 캐스트 이미지가 흐려집니다. "doBlur"체크 상자를 클릭하면 흐림 효과를 켜거나 끕니다. 랩탑과 "chris_t1"에서 통합 Intel GPU 사용 MRIcroGL과 함께 제공되는 이미지 흐림 효과가없는 70fps (1 텍스처 가져 오기) 및 흐림 효과가있는 21fps (8 가져 오기)를 얻습니다. 대부분의 코드는 고전적인 레이 캐스터이며 "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;
}

2
Daniel Rákos의 선형 샘플링을 통한 효율적인 가우시안 블러 ( Christian Cann Schuldt Jensen 의 의견 참고 )
Benji XVI
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.