OpenGL에서 그레이 스케일 렌더링을 구현하는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/867653

  •  22-08-2019
  •  | 
  •  

문제

텍스쳐 다각형의 장면을 렌더링 할 때 원래 색상과 "그레이 스케일"모드에서 렌더링 사이를 전환 할 수 있기를 원합니다. 블렌딩 및 컬러 매트릭스 작업을 사용하여이를 달성하려고 노력했습니다. 그 중 어느 것도 작동하지 않았다 (블렌딩과 함께 내가 원하는 것과 비슷한 일을 달성 한 glblendfunc ()를 찾을 수 없었습니다. ... 여기에서 논의됩니다).

떠오르는 솔루션 (그러나 다소 비싸다)은 모든 프레임마다 화면을 캡처하고 결과 텍스처를 그레이 스케일로 변환하고 대신에 표시하는 것입니다 ... 그러나 가능한 대부분의 솔루션에 대해서는 그레이 스케일과 크게 다르지 않을 것입니다).

다른 옵션은 무엇입니까?

도움이 되었습니까?

해결책

기본 OpenGL FrameBuffer는 RGB 색상 공간을 사용하여 명시 적 포화를 저장하지 않습니다. 포화를 추출하고 수정하고 다시 변경하기위한 접근 방식이 필요합니다.

RGB 벡터 길이를 단순히 사용하여 휘도에서 0을 나타내는 이전의 제안은 스케일링을 고려하지 않았기 때문에 잘못되었습니다.

새로운 짧은 스 니펫에 대한 크레딧은 Freenode/IRC의 ## OpenGL 및 ## OpenGL3의 일반 사용자 "RTFM_FTW"로 이동하며 비용이 많이 드는 RGB-> HSV-> RGB 변환을 계산하지 않고도 포화를 직접 수정할 수 있습니다. 정확히 당신이 원하는 것. HSV 코드는 귀하의 질문과 관련하여 열등하지만, 나는 그것을 유지하게했습니다.

void main( void ) 
{ 
    vec3 R0 = texture2DRect( S, gl_TexCoord[0].st ).rgb;
    gl_FragColor = vec4( mix( vec3( dot( R0, vec3( 0.2125, 0.7154, 0.0721 ) ) ),
        R0, T ), gl_Color.a ); 
}

포화보다 더 많은 제어를 원한다면 HSL 또는 HSV 색상 공간으로 변환해야합니다. GLSL 조각 셰이더를 사용하여 아래에 표시된대로.

OpenGL 3.0 및 GLSL 1.30 사양을 읽으십시오. http://www.opengl.org/registry GLSL v1.30 기능을 사용하는 방법을 배우려면

#version 130
#define RED 0
#define GREEN 1
#define BLUE 2

in vec4 vertexIn;
in vec4 colorIn;
in vec2 tcoordIn;
out vec4 pixel;
Sampler2D tex;
vec4 texel;
const float epsilon = 1e-6;

vec3 RGBtoHSV(vec3 color)
{
    /* hue, saturation and value are all in the range [0,1> here, as opposed to their
       normal ranges of: hue: [0,360>, sat: [0, 100] and value: [0, 256> */
    int sortindex[3] = {RED,GREEN,BLUE};
    float rgbArr[3] = float[3](color.r, color.g, color.b);

    float hue, saturation, value, diff;
    float minCol, maxCol;
    int minIndex, maxIndex;

    if(color.g < color.r)
        swap(sortindex[0], sortindex[1]);
    if(color.b < color.g)
        swap(sortindex[1], sortindex[2]);
    if(color.r < color.b)
        swap(sortindex[2], sortindex[0]);

    minIndex = sortindex[0];
    maxIndex = sortindex[2];
    minCol = rgbArr[minIndex];
    maxCol = rgbArr[maxIndex];

    diff = maxCol - minCol;

    /* Hue */
    if( diff < epsilon){
        hue = 0.0;
    }
    else if(maxIndex == RED){
        hue = ((1.0/6.0) * ( (color.g - color.b) / diff )) + 1.0;
        hue = fract(hue);
    }
    else if(maxIndex == GREEN){
        hue = ((1.0/6.0) * ( (color.b - color.r) / diff )) + (1.0/3.0);
    }
    else if(maxIndex == BLUE){
        hue = ((1.0/6.0) * ( (color.r - color.g) / diff )) + (2.0/3.0);        
    }

    /* Saturation */
    if(maxCol < epsilon)
        saturation = 0;
    else
        saturation = (maxCol - minCol) / maxCol;

    /* Value */
    value = maxCol;

    return vec3(hue, saturation, value);
}
vec3 HSVtoRGB(vec3 color)
{
    float f,p,q,t, hueRound;
    int hueIndex;
    float hue, saturation, value;
    vec3 result;

    /* just for clarity */
    hue = color.r;
    saturation = color.g;
    value = color.b;

    hueRound = floor(hue * 6.0);
    hueIndex = int(hueRound) % 6;
    f = (hue * 6.0) - hueRound;
    p = value * (1.0 - saturation);
    q = value * (1.0 - f*saturation);
    t = value * (1.0 - (1.0 - f)*saturation);

    switch(hueIndex)
    {
        case 0:
            result = vec3(value,t,p);
        break;
        case 1:
            result = vec3(q,value,p);
        break;
        case 2:
            result = vec3(p,value,t);
        break;
        case 3:
            result = vec3(p,q,value);
        break;
        case 4:
            result = vec3(t,p,value);
        break;
        default:
            result = vec3(value,p,q);
        break;
    }
    return result;
}
void main(void)
{
    vec4 srcColor;
    vec3 hsvColor;
    vec3 rgbColor;
    texel = Texture2D(tex, tcoordIn);
    srcColor = texel*colorIn;
    hsvColor = RGBtoHSV(srcColor.rgb);
    /* You can do further changes here, if you want. */
    hsvColor.g = 0; /* Set saturation to zero */
    rgbColor = HSVtoRGB(hsvColor);
    pixel = vec4(rgbColor.r, rgbColor.g, rgbColor.b, srcColor.a);
}

다른 팁

현대식 OpenGL에 대항하여 일하고 있다면 픽셀 셰이더 여기에서 매우 적합한 솔루션입니다. 렌더링 할 때 각 다각형의 음영에 연결하거나 각 픽셀을 읽고 그레이 스케일로 변환하고 다시 쓰는 두 번째 패스에서 단일 풀 스크린 쿼드를 수행함으로써. 해상도, 그래픽 하드웨어 및 대상 프레임 속도가 어떻게 든 "극단적 인"것이 아니라면 대부분의 경우 요즘에는 가능해야합니다.

대부분의 데스크톱 렌더 텍스트의 경우 더 이상 비용이 많이 들지 않으며 Compiz, Aero 등 및 최근 타이틀에서 볼 수있는 Bloom 또는 Field 심도와 같은 효과는 이에 따라 다릅니다.

실제로 스크린 텍스처 자체를 그레이 스케일로 변환하지 않으므로, 텍스처와 밸런터를 회색으로 변환하는 조각 크기의 쿼드를 그리는 것입니다.

또 다른 옵션은 삼각형을위한 두 개의 조각 셰이더 세트를 갖는 것입니다. 하나는 고정 된 기능 Pieline이 원하는대로 GL_FRONTCOLOR 속성을 복사하고 다른 하나는 화면 버퍼에 GrayScale 값을 작성하는 것입니다.

세 번째 옵션은 GrayScale 팔레트를 Uüp로 설정하면 색인화 된 색상 모드 일 수 있지만 해당 모드는 지금까지 더 이상 사용되지 않고 제대로 지원되지 않을 수 있습니다. 또한 내가 정확하게 기억한다면 블렌딩과 같은 많은 기능을 잃습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top