Computer Graphics

Chapter12. 에일리어싱과 안티 에일리어싱

CodeJB 2021. 6. 7. 21:15

에일리어싱

  • 원 신호 중 일부만 사용하기 때문에 발생하는 신호왜곡
  • 야구를 할때 야구공이 날라옴에 따라 수 많은 위치적 변화가 발생할텐데, 동체시력이 좋은 사람은 이 위치를 모두 캐치해서 공을 치겠지만 동체시력이 안좋은 사람들은 위치를 놓치게되고 헛스윙을 할 것이다. 이 것과 같은 이치이다.

중간에 있는 신호가 소실되었음

  • 그래픽스 세계에서 에일리어싱은 어떨까? 우리가 3차원 공간 상의 레스터 그래픽에서는 정점 사이를 잇고, 이를 통해 모델링을 하게되는데 이를 래스터 그래픽으로 화소에 그리게 되면 아래 그림과 같은 모습일 것이다. 이러한 왜곡된 모습을 에일리어싱이라고 칭한다.

안티 에일리어싱

  • 위에서 살펴본, 래스터 변환을 함에 따라서 발생하는 에일리어싱(계단 현상)을 해결하기 위해서 어떤 방식을 사용해야할까?
  • 첫번째로, 더 많은 화소를 지원하는 디스플레이와 그래픽카드와 같은 하드웨어의 성능을 높이는 것이다. 하지만, 당연히 그래픽스 공부하는 사람들이 하드웨어 성능에만 의존했을리가 없다.
  • 따라서 두번째로, 안티 에일리어싱이라고하는 에일리어싱의 오차를 보정하는 방식을 사용한다.
  • 안티 에일리어싱 방식은 슈퍼 샘플링, 영역 샘플링, 블러링이 존재한다

슈퍼샘플링

  • 가상의 픽셀을 만들어 픽셀값을 계산한 후, 각 픽셀의 평균값을 사용하는 것이다.
  • (a) 픽셀을 보면 칠해진 부분이 절반 이하기 때문에 값이 0이될테지만, 이를 4등분하게 되면 (b)와 같이 표현할 수 있다.
  • (b)에서 보면, 밑의 두 부분픽셀은 절반 이상 칠해져있고, 위의 두 부분필셀은 절반 이하로 칠해져있다. 따라서 이에 대한 평균을 내보면 (대충 절반정도의 흐린 색깔이 되겠지? (1+1+0+0)/4 = 0.5) (c)의 색깔로 칠해지게되는 것이다.

  • 실제로 레스터 그래픽을 자세히 확대해보면 아래와 같이 돼있다.

영역 샘플링

  • 위에서 (b)과정, 가상의 픽셀을 계산하는 과정을 생략한다.
  • (a)에서 색이 칠해진 부분의 면적 비율을 계산해서 픽셀값을 결정해버리는 것이다.

블러링

  • 인접한 화소의 값과 가중치를 사용하여 블러링 효과를 적용하는 것이다.
  • 영역 샘플링에 비해 퀄리티가 낮다.

안티 에일리어싱 구현

  • 안티 에일리어싱은 블랜딩과 밀접한 관련이 있다. 위에서 살펴봤던 것처럼, 슈퍼샘플링이나 영역샘플링이나 블러링이나 결국엔 배경색과 물체의 색깔을 섞게되기 때문이다.
  • 그래픽스 상에서 투명도를 나타낼때도 이와 비슷하다. 배경색과 물체의 색깔을 교묘하게 섞음으로써 물체에 배경색깔이 투영되게끔 하는 것이다.
glEnable(GL_BLEND); 
//블랜딩 활성화
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//내가 현재 그리고자하는 것을 SRC, 이미 그려져있는 것을 DST
//SRC RGBA는 SRC Alpha에 의해 칠해지고, DST RGBA는 (1-SRC Alhpa)로 칠하게된다.
<인자 설명>
GL_ZERO, //그냥 의미 그대로 0, 
GL_ONE, //있는 그대로 그림
GL_SRC_COLOR, //SRC Color비율 대로 칠함
GL_ONE_MINUS_SRC_COLOR, //1.0 - (SRC Color) 비율대로 칠함
GL_DST_COLOR,//칠해져 있는 Color 비율에 의해 결정
GL_ONE_MINUS_DST_COLOR, //1.0 - DST COLOR
GL_SRC_ALPHA, //일반적인 SRC Blending 옵션, 소스의 알파 비율대로 색,알파 결정
GL_ONE_MINUS_SRC_ALPHA, //일반적인 DST Blending 옵션, 1.0 - 소스의 알파 비율대로 색, 알파 결정
GL_DST_ALPHA, 
GL_ONE_MINUS_DST_ALPHA, 
GL_CONSTANT_COLOR, //이건 glBlendColor로 설정한 Constant값에 의해 결정
GL_ONE_MINUS_CONSTANT_COLOR, // 1.0 - constant
GL_CONSTANT_ALPHA, 
GL_ONE_MINUS_CONSTANT_ALPHA, 
GL_SRC_ALPHA_SATURATE //Saturate 한 값 , 클램핑이라 생각하면됨!

glEnable(GL_POINT_SMOOTH);
<인자 설명>
GL_POINT_SMOOTH
GL_LINE_SMOOTH
GL_POLYGON_SMOOTH

glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); //안티 에일리어싱을 위한 '희망사항'을 GPU에 전달(예 : 빠르게, 정확하게)
<인사 설명>
GL_NICEST : 정확하게
GL_FESTEST : 빠르게

출처 : https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=itrainl4&logNo=90188723209

OpenGL 실습 : 안티 에일리어싱 점, 선

#include <GLUT/GLUT.h>
#include <OpenGL/OpenGL.h>
#include <iostream>

void MyReshape(int width, int height){
    GLfloat left = 0, bottom = 0;
    glViewport(left, bottom, width-left, height-bottom);
    glMatrixMode(GL_PROJECTION);//투영변환 모드 초기화
    glLoadIdentity();
    glOrtho(-2, 2, -2, 2, -2, 2);
}

void MyDisplay(){
    glClear(GL_COLOR_BUFFER_BIT);
    
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    
    //glutWireTeapot(0.5);
    
    glEnable(GL_BLEND);
    glEnable(GL_POINT_SMOOTH);
    glEnable(GL_LINE_SMOOTH);
    
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glPointSize(100);
    glLineWidth(10);
    glBegin(GL_POINTS);
        glVertex3f(0, 0, 0);
    glEnd();
    
    glBegin(GL_LINES);
        glVertex3f(0, 0, 0);
        glVertex3f(0, 2, 0);
        glVertex3f(0, 0, 0);
        glVertex3f(2, 2, 0);
        glVertex3f(0, 0, 0);
        glVertex3f(2, 4, 0);
        glVertex3f(0, 0, 0);
        glVertex3f(4, 2, 0);
    glEnd();
    
    glDisable(GL_BLEND);
    
    glFlush();
}

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB);
    glutInitWindowSize(512, 512);
    glutInitWindowPosition(50, 50);
    
    glutCreateWindow("anti aliasing");
    
    glutDisplayFunc(MyDisplay);
    glutReshapeFunc(MyReshape);
    
    glutMainLoop();
    return 0;
}

참고로 왼쪽 네모는 점임.. 안티에일리어싱 해서 오른쪽처럼 동그란 점으로 바뀜 Line은 확대해보면 이렇게 차이가 남

OpenGL 실습 : 안티에일리어싱 체스판 다각형 에일리어싱

#include <GLUT/GLUT.h>
#include <OpenGL/OpenGL.h>
#include <iostream>

#define _WINDOW_WIDTH 500
#define _WINDOW_HEIGHT 500

GLfloat camPos_x = 0, camPos_y = 5, camPos_z = -4; //위치
GLfloat camAt_x = 0, camAt_y = 0, camAt_z = 10; //바라보는 곳
GLfloat camUp_x = 0, camUp_y = 1, camUp_z = 0; //방향

void MyReshape(int width, int height){
    GLfloat left = 0, bottom = 0;
    glViewport(left, bottom, width-left, height-bottom);
    glMatrixMode(GL_PROJECTION);//투영변환 모드 초기화
    glLoadIdentity();
    GLfloat ratio = (float)(width-left)/(height-bottom); //비율 값
    gluPerspective(40, ratio, 0.1, 1000); //원근 투영
}

void drawRect(GLfloat x,GLfloat y,GLfloat z,GLfloat width,GLfloat r,GLfloat g,GLfloat b){
    glColor3f(r, g, b);
    glBegin(GL_POLYGON);
        glVertex3f(x,y,z);
        glVertex3f(x+width,y,z);
        glVertex3f(x+width,y,z+width);
        glVertex3f(x,y,z+width);
    glEnd();
}

void drawBlackWhiteRect(GLint nx, GLint nz, GLfloat sx, GLfloat sy, GLfloat sz,GLfloat w, int bBlack){
    GLfloat x, y, z;
    x = sx + nx * w;
    y = sy;
    z = sz + nz * w;
    
    if(bBlack == 1)
        drawRect(x, y, z, w, 0, 0, 0);
    else
        drawRect(x, y, z, w, 1, 1, 1);
}

void MyDisplay(){
    glClear(GL_COLOR_BUFFER_BIT);
    
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    
    gluLookAt(camPos_x, camPos_y, camPos_z, camAt_x, camAt_y, camAt_z, camUp_x,camUp_y, camUp_z);
    
    glEnable(GL_BLEND);
    
    glEnable(GL_POLYGON_SMOOTH);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
    
    for(int i =0; i < 1000; i++){
        for(int j =0; j < 1000; j++){
            int bBlack = (i+j)%2;
            drawBlackWhiteRect(i, j, -10, 0, 0, 0.2, bBlack);
        }
    }
    
    glDisable(GL_BLEND);
    
    glFlush();
}

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB);
    glutInitWindowSize(512, 512);
    glutInitWindowPosition(50, 50);
    
    glutCreateWindow("anti aliasing");
    
    glutDisplayFunc(MyDisplay);
    glutReshapeFunc(MyReshape);
    
    glutMainLoop();
    return 0;
}

일부 그래픽 하드웨어는 polygon aliasing  지원을 안한다고 한다... 그래서 강의자료 캡쳐해옴 https://stackoverflow.com/questions/1975778/opengl-antialiasing-isnt-working