2009-05-15 2 views
5

, 나는 원래 색상과 "그레이 스케일"모드에서 렌더링 사이를 전환 할 수 있도록하고 싶습니다. 블렌딩 및 컬러 행렬 작업을 사용하여이 작업을 수행하려고했습니다. 그것은 아무도 (나는 내가 원하는 것을 원격으로 닮은 무언가를 달성 glBlendFunc() 및 색상 행렬 연산 ...are discussed here를 찾을 수 없습니다 혼합으로) 일하지.OpenGL에서 그레이 스케일 렌더링을 구현하는 방법은 무엇입니까? 질감 다각형의 한 장면을 렌더링 할 때

마음에 떠오르는 솔루션은 프레임마다 화면을 캡처하고 그 결과 텍스처를 회색 음영으로 변환하여 대신 표시하는 것입니다. (회색 음영이 실제로 의미하는 부분은 낮은 채도이지만 가능한 대부분의 솔루션이 회색 음영과 많이 다르지는 않을 것입니다.

다른 옵션에는 어떤 것이 있습니까? 당신이 현대만큼의 OpenGL에 대해 작업하는 경우

답변

9

기본 OpenGL을 프레임 버퍼는 명시 적 포화를 저장하지 않는 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 조각 셰이더를 사용합니다.

GLSL v1.30 기능 사용법을 배우려면 http://www.opengl.org/registry에서 OpenGL 3.0 및 GLSL 1.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); 
} 
+0

"v"가 정의되지 않았습니다. hsv2rgb에 대한 다른 알고리즘을 보면 이것이 실제로 "값"이어야합니다. 또한 마지막 사례 문 (사례 5)도 기본 사례 여야합니다. –

2

, 나는 pixel shaders 여기에 매우 적합한 솔루션입니다 말할 것입니다. 렌더링 할 때 각 다각형의 음영에 연결하거나 각 픽셀을 읽고 회색 음영으로 변환 한 다음 다시 쓰는 두 번째 패스에서 하나의 전체 화면 쿼드를 사용합니다. 해상도, 그래픽 하드웨어 및 대상 프레임 레이트가 어떻게 든 극단적 인 경우가 아니라면 요즘 대부분의 경우 가능합니다.

2

대부분의 데스크톱 렌더 - 투 - 텍스처가, 더 이상 그 비용이 컴 피즈, 항공 등과 꽃이나 최근의 제목에서 볼 수 피사계 심도와 같은 효과 모두가에 따라 달라집니다.

실제로 화면 질감을 그레이 스케일로 변환하지 않으면 텍스처로 화면 크기의 쿼드를 그리고 그 값을 그레이 스케일로 변환하는 프래그먼트 셰이더를 그리는 것이 좋습니다.

또 다른 옵션은 삼각형에 대해 두 세트의 조각 쉐이더를 사용하는 것입니다. 하나는 고정 함수 pieline처럼 gl_FrontColor 특성을 복사하는 것이고 다른 하나는 화면 버퍼에 회색 음영 값을 씁니다.

당신이 그레이 스케일 팔레트를 UUP 설정하면 세 번째 옵션은 색상 모드를 인덱싱 할 수 있지만 해당 모드는 사용되지 않으며 제대로 지금에 의해 지원 될 수있다; 블렌딩과 같은 많은 기능을 잃어 버렸습니다. 올바르게 기억한다면 말이죠.

+0

예, colorindex 모드와 블렌딩하지 않습니다. "컴 피즈, 에어로 등 전부"란 무엇을 의미합니까? – zyndor

+0

그는 데스크톱 윈도우 렌더러가 요즘 종종 텍스처에 렌더링을 사용한다는 것을 의미합니다 (그는 아마도 윈도우 매니저 프로그래머 일 것입니다). – Triang3l

관련 문제