[OpenGL Tutorial] Transparent by The Blending

사용자 삽입 이미지이 장은 OpenGL의 Blend 기능을 이용하여 투명한 물체를 만들어 보는 것을 예로써 Blend를 설명하고 한다.

OpenGL에서 대부분의 특수효과는 Blending를 이용한다. 블랜딩은 이미 화면상에 그려진 픽셀의 색과 이제 바로 같은 위치에 그려질 픽셀의 색의 조합하는 방식이다. 어떤식으로 색상을 조합하는 지는 알파값과 블랜딩 함수에 의해 정해진다. 알파값이란 보통 색상을 지정할때 4가지 구성요소중 마지막 네번째 값이다. 지금까지 색상을 지정하는 방식으로 GL_RGB를 사용했었는데 여기에는 알파값이 없다. 알파값의 추가를 위해 GL_RGBA를 사용할수있다. 그리고 알파값을 포함한 색상을 지정하기 위해 glColor3f 대신 glColor4f를 사용할 수 있다.

대부분의 사람들은 알파값을 물체의 불투명 정도라고 생각한다. 알파값 0.0은 완전한 투명이고 1.0은 완전이 불투명하다.

블랜딩 공식
(Rs Sr + Rd Dr , Gs Sg + Gd Dg , Bs Sb + Bd Db , As Sa + Ad Da)

OpenGL은 두픽셀간의 블랜딩 결과를 계산하기 위해 위의 공식을 이용한다. s와 d의 꼬리 글자는 원본(Source)와 대상(Destination) 픽셀을 나타낸다. S와 D 요소는 블랜딩 요소이다. 이러한 값들이 어떤 방식으로 블랜딩할것인지를 지정한다. 또한 r, g, b, a의 첨자는 색의 3요소(빨강, 초록, 파랑)과 알파값이다. S와 D의 일반적인 값으로는 S에 대해서는 (As, As, As, As) (줄여 말하면, 원본 알파값)이며 D에 대해서는 (1, 1, 1, 1) – (As, As, As, As) (줄여 말하면, 1 – 원본 알파값)이다. 이것은 다음과 같은 블랜딩 공식을 만들어 낸다.

( Rs As + Rd (1 – As), Gs As + Gd (1 – As), Bs As + Bs (1 – As), As As + Ad (1 – As) )

이 공식은 투명/반투명 효과를 낼수 있다.

우리는 다른 것들과 마찬가지로 블랜딩을 사용할 수 있다. 물체를 투명하게 그릴때는 Depth Buffer 사용을 막는다. 어떤 물체의 앞에 투명한 물체를 그릴때 투명한 물체를 통해서 그 뒤의 그 물체가 보여야하기 때문이다.

자 이제 블랜딩에 대한 수학적, 개론적인 설명을 접고 실제로 프로그래밍 예를 통해 블랜딩을 접해보자. 사용할 소스는 6장에서 만든 코드를 이용하기로 한다.

우리가 원하는 결과는 투명한 정육면체(?), 바로 이것이다. 실제 결과를 미리 보인다. 아래를 보라.

사용자 삽입 이미지

6장에서 보았던 것과 같은 내용인데 차이점은 정육면체의 면이 투명해서 반대쪽 면까지도 보인다는 것이다. 텍스쳐 맵핑 소스를 보다 그럴싸한 것으로 변경해서 다시 실행해 보면 또 다른 멋진 결과가 나온다. 직접 해보기 바란다.

이제 코드에 대해서 알아보자.

먼저 블랜딩을 위해서 초기화 시켜줘야 할 것들에 대해서 알아보자. 우리가 잘알고 있듯이 초기화는 InitGL 함수에서 해준다. 기존의 소스 코드에서 삭제되고 추가거나 변경될 코드를 설명하자면 먼저 glEnable(GL_CULL_FACE)를 삭제한다. 왜냐하면 이 코드는 면의 앞면에 대해서만 그리고 뒷면을 그리지 않게 하는 코드인데 그렇게 하면 투명한 면을 통해서 그 뒷면이 보이지 않기 때문이다. 그리고 glEnable(GL_DEPTH_TEST)를 glDisable(GL_DEPTH_TEST)로 변경한다. 이유는 앞서 설명했던 바와 같다. 그리고 물체의 재질에 대해 설정해 주는 모든 코드를 삭제한다. 사실 텍스쳐 맵핑을 입힌 물체는 더 이상 재질이 필요없을 뿐더러 블랜딩 효과에서는 재질의 성질이 블랜딩 효과를 방해함으로써 둔탁한 느낌의 결과를 얻을수밖에 없다. 재질에 관계되는 코드들을 제거한다. 제거할 코드는 다음 InitGL 함수의 전체 구현 소스를 보이겠다. 그리고 가장 중요한 블랜딩 기능을 사용하는 것을 지정하고 블랜딩 함수를 지정하는 코드이다.그 두 코드는 다음과 같다.

glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glEnable(GL_BLEND);

첫번째는 블랜딩 함수를 지정해 주는 코드이다. 첫번째 인자인 GL_SRC_ALPHA는 원본 픽셀에 대한 블랜딩 계수를 계산하는 방식인데 원본칼라를 원본 알파값으로 곱하는 것이다. 그리고 두번째 인자는 대상 픽셀에 대한 블랜딩 계수를 계산하는 방식인데 그냥 대상 칼라를 사용한다는 것이다. 즉 블랜딩 계수는 1이 되겠다. 최종적으로 이렇게 처리된 두 픽셀값이 합해져서 최종 픽셀값으로 처리되어 화면상에 나타나게 된다.


여기까지가 블랜딩을 이용한 투명한 물체를 생성하는 초기화 코드이다. 아래에 전체 코드를 기록하니 참고바란다. 노랜색 부분이 변경된 부분이다.

int InitGL(GLvoid)
{
    GLfloat ambientLight[] = { 0.25f, 0.25f, 0.25f, 1.0f };
    GLfloat diffuseLight[] = { 0.9f, 0.9f, 0.9f, 1.0f };
    GLfloat lightPos[] = { -100.0f, 130.0f, 150.0f, 1.0f };
    GLfloat specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
   
    AUX_RGBImageRec *texRec[3];
    memset(texRec, 0, sizeof(void *)*3);
   
    if((texRec[0]=LoadBMPFile("img.bmp")) &&
       (texRec[1]=LoadBMPFile("img2.bmp")) &&
       (texRec[2]=LoadBMPFile("img3.bmp"))) {
        glGenTextures(3, &tex[0]);
        for(int i=0; i<3; i++) {
            glBindTexture(GL_TEXTURE_2D, tex[i]);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexImage2D(GL_TEXTURE_2D, 
            0, 
            3, 
            texRec[i]->sizeX, 
            texRec[i]->sizeY, 
            0, 
            GL_RGB, 
            GL_UNSIGNED_BYTE, 
            texRec[i]->data);
        }
    } else return FALSE;
   
    for(int i=0; i<3; i++) {
        if(texRec[i])
        {
            if(texRec[i]->data) free(texRec[i]->data);
            free(texRec[i]);
        } else return FALSE;
    }
   
    glEnable(GL_TEXTURE_2D);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   
    glShadeModel(GL_SMOOTH);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClearDepth(1.0f);
    // glEnable(GL_CULL_FACE); //
    glFrontFace(GL_CCW);
    glEnable(GL_LIGHTING);
   
    /////////// NEW ///////////////////////////////
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    glEnable(GL_BLEND);
    /////////// NEW ///////////////////////////////
    glDisable(GL_DEPTH_TEST); //
   
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
    glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
    glEnable(GL_LIGHT0);
   
    // glEnable(GL_COLOR_MATERIAL); // 
    // glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); // 
    // glMaterialfv(GL_FRONT, GL_SPECULAR, specref); // 
    // glMateriali(GL_FRONT, GL_SHININESS, 10); // 
   
    glDepthFunc(GL_LEQUAL);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
   
    return TRUE;
}

자 이제 실제 물체를 그려주는 코드를 살펴보자. 변경된 부분은 단 한줄이다. 즉 색상을 지정할때 알파값을 추가하는 것이다. 아래는 glDrawScene 함수의 일부분이다.

int DrawGLScene(GLvoid)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    glTranslatef(0.0f, 0.0f, -7.0f);
   
    glColor4f(1.0f, 1.0f, 1.0f, 0.2f); // 
   
    glRotatef(rot, 1.0f, 0.1f, 0.4f);
    glBindTexture(GL_TEXTURE_2D, tex[0]);
    glBegin(GL_QUADS);
    glNormal3f(0.0f, 0.0f, 1.0f);
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
    glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, -1.0f, 1.0f);
   
        .
        .
        .

위의 노란색 코드가 유일한 변경 코드인데 알파값으로 0.2를 주었다. 이것은 투명도가 80%를 나타내는 수치이다.

이것으로 블랜딩을 이용한 투명한 객체를 만들어 보는 것을 마친다. 재미 삼아 다른 텍스쳐 맵핑 소스에 대한 그림 파일만을 바꿔서 실행본 결과를 아래에 제시한다. 보기 바란다.
사용자 삽입 이미지

“[OpenGL Tutorial] Transparent by The Blending”에 대한 11개의 댓글

  1. 이런 질문해도 되는지 모르겠지만 너무 궁금하여 여쭤봅니다. model을 투명화하는건 알려주신 방법을 사용하여 잘 진행하였는데, 혹시 model이 display되는 창도 투명하게 할 수 있는지 궁금합니다. opengl을 이용하여 캠으로 찍는 화면에 model을 추가하여 display하려고 코드를 짜는 중인데 쉽지 않아서 여쭤봅니다.

    1. Windows 2000 부터는 기본적으로 모든 윈도우에 대해서 투명도를 지정할 수 있습니다. 이 기능을 이용해 보시는게 어떨까요?

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다