CHOU

[OPENGL] 색상, 재질, 조명의 기본 본문

Tech/Technical Tips

[OPENGL] 색상, 재질, 조명의 기본

chobabo 2010. 1. 20. 23:16


1. 쉐이딩

한 색상에서 다른 색상으로 부드럽게 변환하는 과정을 말한다.

 

2. 조명


광원은 주로 한 가지 빛으로만 구성되지 않고 세가지 종류의 빛이 적절히 혼합되어 구성된다.


1) 주변광(ambient)
특정한 방향이 없이 주변을 덮고 있는 빛을 말한다.
광원은 있지만, 여러가지 요소에 부딪히고 반사되어 점차 방향을 잃어 버린 빛의 형태에 해당한다.
따라서 주변광은 물체에 어떤 면에나 비춰지며, 어느 방향이던지 일정한 방향으로 표현된다.


2) 분산광(diffuse)
일정한 방향으로 빛이 들어와서 물체의 표면에서 여러 방향으로 분산되는 빛의 형태를 말한다.
분산되기는 하지만, 빛을 받는 표면은 그렇지 않는 표면에 비해 밝게 보이고,
형광등 불빛이나 한낮에 창문 사이로 비치는 햇빛을 생각할 수 있다.


3) 반사광(specular)
특정한 방향으로 유입되어 한방향으로 완전히 반사되는 빛의 형태로, 강한 반사광은
물체 표면에 밝은 점을 형성하고, 이를 반사 하이라이트라고 한다.
스포트라이트, 태양 빛이 좋은 예 이다.

 



3. 실세계의 재질
조명만으로 물체가 표현되는 것은 아니며, 실제 물체는 자신만의 색상을 가지고 있다.
물체의 색상은 물체가 반사하는 파장의 범위에 따라 달라진다.
푸른 공은 푸른색 양자를 반사하고 나머지 대부분의 빛을 흡수하기 때문에 우리눈에
푸른색으로 보이게 된다.


1) 재질의 특성
우리가 조명을 사용할 때는 폴리곤이 특정한 색상을 가지고 있다고 설정하는게 아니라
특정한 색상을 반사하는 재질로 되어 있다고 설정한다.


물체의 재질을 말할때는 조명 속성(ambient, diffuse, specular) 이외에도, 방출 속성
(emission property)를 지정하는데, 이는 자동차의 미등이나 야광시계의 바늘 같이
자체적으로 빛을 방출하는 물체의 경우를 말한다.


2) 주변광 효과 계산하기
광원이 가진 각 색상의 조합을 먼저 알아내고, 여기에 재질이 가진 고유의 특성인
색상 요소를 반사하는 정도를 곱하면 된다.

주변광:(0.5, 0.5, 0.5)
반사속성: (0.5, 1.0, 0.5)

색상 = (0.5 * 0.5, 0.5 * 1.0, 0.5 * 0.5) = (0.25, 0.5, 0.25)

즉 물체는 적색은 50%만 반사하고 녹색은 100% 반사하며, 청색 요소는 50%만 반사하니까
(0.25, 0.5, 0.25) 의 색상을 가지게 된다.


3) 분산광, 반사광 계산하기
분산광은 방향이 있으니까 표면과 광원 사이의 각도, 광원과의 거리, 등에 따라서
표면에서의 빛의 세기가 달라진다. 또한 계산 값이 1.0이 넘으면 1.0으로 보정해야 한다.
반사광과 재질의 속성은 연한 회색이나, 흰색을 띄는 경향이 많고, 빛의 각도에 따라
크게 달라진다. 빛을 받는 곳은 대게 흰색으로 결정된다.

 


4. 조명 효과의 설정
glEnable(GL_LIGHTING);

장면 내에 있는 버텍스 색상을 결정할 떄 재질 속성과 조명인자를 계산에 넣게 된다.
이러한 인자를 지정하는 부분은 렌더링이 이루어 지기 전에 등장하는 SetupRC 함수에서
이루어 진다.

 


5. 조명 모델의 설정
조명 모델은 세가지가 있는데 glLightModel() 함수를 이용해서 설정한다.

GLfloat ambientLight[] = {1.0, 1.0, 1.0, 1.0};

glEnable(GL_LIGHTING);

glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);

glLightModelfv는 glLightModel()의 변형된 버전으로 첫번째 인자는 조명 모델,
두번째는 조명을 이루는 RGBA 배열을 값으로 받는다.

 


6. 재질 속성의 설정

static GLfloat mat_ambdif[] = {0.0, 0.7, 0.0, 1.0};

glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambdif);

첫번째 인자는 폴리곤의 어떤면의 재질을 설정할 건지, 두번째 인자는 어떤 속성을
설정할 건지, 세번째 인자는 RGBA값이 담긴 배열을 통해 속성을 설정하라는 이야기 이다.
이 호출이 있은 후 다음 기본 모델은 다음 glMaterial() 호출이 있기 전까지 영향을
받는다.

대부분의 경우 주변광과 분산광에 대한 반사도는 같게 설정되며, 빛이 나거나 번쩍하는
효과가 필요하지 않는 경우를 제외하고 반사광은 설정하지 않아도 된다.

 
#include <windows.h>
#include <gl\glut.h>
#include <math.h>

static GLfloat glb_amb[] = {0.1, 0.1, 0.1, 1.0};
static GLfloat light_amb[] = {0.1, 0.1, 0.1, 1.0};
static GLfloat light_dif[] = {1.0, 1.0, 1.0, 1.0};
static GLfloat light_spc[] = {1.0, 1.0, 1.0, 1.0};

static GLfloat light0_pos[] = {1.0, 1.0, 1.0, 0.0};
static GLfloat light1_pos[] = {-1.0, 0.8, -0.4, 0.0};

static GLfloat mat_ambdif[] = {0.0, 0.7, 0.0, 1.0};
static GLfloat mat_spc[] = {1.0, 1.0, 1.0, 1.0};
static GLfloat mat_shn[] = {10.0};

// Rotation amounts
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;
static GLfloat trans_z = 150.0f;

static GLfloat vrp_x = 0.0f;
static GLfloat vrp_y = 0.0f;
static GLfloat vrp_z = 0.0f;

void display(void)
{
 glLoadIdentity();
 glTranslatef(0.0, 0.0, -trans_z);
 glRotatef(xRot, 1.0, 0.0, 0.0);
 glRotatef(yRot, 0.0, 1.0, 0.0);
 glTranslatef(-vrp_x, -vrp_y, -vrp_z);

 glLightfv(GL_LIGHT0, GL_POSITION, light0_pos);
 glLightfv(GL_LIGHT1, GL_POSITION, light1_pos);

 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambdif);
 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_ambdif);
 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_spc);
 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shn);

 glutSolidSphere(15.0f, 100, 100);

 glutSwapBuffers();
}

 

// Respond to arrow keys
void SpecialKeys(unsigned char key, int x, int y)
{
 if(key == 100)
  xRot-= 5.0f;

 if(key == 117)
  xRot += 5.0f;

 if(key == 108)
  yRot -= 5.0f;

 if(key == 114)
  yRot += 5.0f;
            
 xRot = (GLfloat)((const int)xRot % 360);
 yRot = (GLfloat)((const int)yRot % 360);

 // Refresh the Window
 glutPostRedisplay();
}

// This function does any needed initialization on the rendering
// context.
void SetupRC(void)
{

 glEnable(GL_LIGHTING);
 glShadeModel(GL_SMOOTH);
 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, glb_amb);
 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
 glEnable(GL_LIGHT0);
 glEnable(GL_LIGHT1);
 glLightfv(GL_LIGHT0, GL_AMBIENT, light_amb);
 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_dif);
 glLightfv(GL_LIGHT0, GL_SPECULAR, light_spc);

 glLightfv(GL_LIGHT1, GL_AMBIENT, light_amb);
 glLightfv(GL_LIGHT1, GL_DIFFUSE, light_dif);
 glLightfv(GL_LIGHT1, GL_SPECULAR, light_spc);
 
}

void TimerFunc(int value)
{
 glutPostRedisplay();
 glutTimerFunc(100, TimerFunc, 1);
}


void ChangeSize(int w, int h)
{
 GLfloat fAspect;

 // Prevent a divide by zero
 if(h == 0)
  h = 1;

 // Set Viewport to window dimensions
 glViewport(0, 0, w, h);

 // Calculate aspect ratio of the window
 fAspect = (GLfloat)w/(GLfloat)h;

 // Set the perspective coordinate system
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();

 // field of view of 45 degrees, near and far planes 1.0 and 425
 gluPerspective(45.0f, fAspect, 1.0, 425.0);

 // Modelview matrix reset
 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();
}

int main(int argc, char* argv[])
{
 glutInit(&argc, argv);
 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
 glutInitWindowSize(800, 600);
 glutCreateWindow("report3_1 - 2010/02/05");
 glutReshapeFunc(ChangeSize);
 glutKeyboardFunc(SpecialKeys);
 glutDisplayFunc(display);
 //glutTimerFunc(250, TimerFunc, 1);

 SetupRC();
 glutMainLoop();

 return 0;
}


Reference
1. http://www.cadgraphics.co.kr/education/upload/157-161_case_opengl.pdf