[9th week] cg_practice_lighting

Download Report

Transcript [9th week] cg_practice_lighting

Implement of lighting
Hanyang University
Jungsik Park
Normal vector
 조명효과를 적용하게 되면 조명과 폴리곤이 이루는 각도에
따라 물체의 색상이 다르게 표현되어야 한다.
 폴리곤은 버텍스들의 집합으로 만들어지고, 폴리곤 내부의
색상은 폴리곤을 구성하는 버텍스 색상으로부터
계산되므로 버텍스마다 법선 벡터를 지정한다.
 법선 벡터 지정함수



void glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz);
void glNormal3fv (const GLfloat *v);
조명 효과 계산이 올바르게 수행되게 위해서는 법선 벡터는
단위 벡터로 지정되어야 한다.

glEnable(GL_NORMALIZE); 를 사용하면 약간의 성능
저하가 발생하지만, 법선 벡터를 강제로 단위 법선 벡터로
변환하여 지정하게 된다.
Division of Electrical and Computer Engineering, Hanyang University
Modified Phong model
 OpenGL에서 사용되는 조명 모델로 다음의 세 요소로
구성된다.



분산광(diffuse)
반사광(specular)
주변광(ambient)
빛의 세기
재질의
반사지수
I =kd Id l · n + ks Is (h · n )a + ka Ia
재질 표면의 반사율
Division of Electrical and Computer Engineering, Hanyang University
조명 설정
 조명 사용
 glEnable(GL_LIGHTING);
 전역 주변광 설정
 void glLightModelfv (GLenum pname, const GLfloat
*params);
 pname : 속성 종류
• GL_LIGHT_MODEL_AMBIENT

params : 속성값 배열(4차원 벡터 형태)
Division of Electrical and Computer Engineering, Hanyang University
광원 설정
 광원 설정
 glEnable(GL_LIGHT0);


광원은 최소한 8개까지 설정 가능(GL_LIGHT0 ~ GL_LIGHT8)
광원의 속성 지정

void glLightfv (GLenum light, GLenum pname, const GLfloat
*params);
• light : 광원의 이름 (GL_LIGHT0 ~ GL_LIGHT8)
• pname : 속성 종류
 GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR,
GL_POSITION
• params : 속성값 배열(4차원 벡터 형태)
 빛의 세기값은 0~1사이의 값
 광원 위치의 4번째 요소의 값이 0인 경우 배열 내의 벡터
방향으로 무한대 떨어진 곳에 광원이 위치
Division of Electrical and Computer Engineering, Hanyang University
Example code - lightsource
#include <gl/glut.h>
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;
static GLfloat xRotLight = 0.0f;
static GLfloat yRotLight = 0.0f;
static int width, height;
GLfloat ambientLight[] = { 0.3f, 0.3f, 0.3f, 1.0f };
GLfloat diffuseLight[] = { 0.7f, 0.7f, 0.7f, 1.0f };
GLfloat lightPos[] = { -50.f, 50.0f, 100.0f, 1.0f };
bool bMoveLightSource = false;
void SetProjection()
{
GLfloat fAspect = (GLfloat)width/(GLfloat)height;
GLfloat nRange = height/4.0;
if(height == 0)
height = 1;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f, fAspect, 1.0, 400.0);
void SpecialKeys(int key, int x, int y)
{
if (!bMoveLightSource)
{
if(key == GLUT_KEY_UP)
xRot-= 5.0f;
if(key == GLUT_KEY_DOWN)
xRot += 5.0f;
if(key == GLUT_KEY_LEFT)
yRot -= 5.0f;
if(key == GLUT_KEY_RIGHT)
yRot += 5.0f;
xRot = (GLfloat)((const int)xRot % 360);
yRot = (GLfloat)((const int)yRot % 360);
}
else
{
if(key == GLUT_KEY_UP)
xRotLight-= 5.0f;
if(key == GLUT_KEY_DOWN)
xRotLight += 5.0f;
if(key == GLUT_KEY_LEFT)
yRotLight -= 5.0f;
if(key == GLUT_KEY_RIGHT)
yRotLight += 5.0f;
xRotLight = (GLfloat)((const int)xRotLight % 360);
yRotLight = (GLfloat)((const int)yRotLight % 360);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
}
void ChangeSize(GLsizei w, GLsizei h)
{
width = w;
height = h;
SetProjection();
}
if (key == GLUT_KEY_F1)
{
bMoveLightSource = !bMoveLightSource;
}
glutPostRedisplay();
}
Division of Electrical and Computer Engineering, Hanyang University
Example code - lightsource
oid SetupRC()
{
glEnable(GL_DEPTH_TEST);
glCullFace(GL_BACK);
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);
glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT,
ambientLight);
glEnable(GL_LIGHT0);
}
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(0.0f, 0.0f, -300.0f);
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
glPushMatrix();
glRotatef(xRotLight, 1.0f, 0.0f, 0.0f);
glRotatef(yRotLight, 0.0f, 1.0f, 0.0f);
glLightfv(GL_LIGHT0,GL_POSITION,lightPo
s);
glPopMatrix();
//
glColor로지정된색상은무시
glColor3f(1.0, 0.0, 0.0);
glutSolidTeapot(100.0);
glPopMatrix();
glutSwapBuffers();
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB |
GLUT_DEPTH);
glutInitWindowSize(600, 600);
glutCreateWindow(“Light source");
glutReshapeFunc(ChangeSize);
glutSpecialFunc(SpecialKeys);
glutDisplayFunc(RenderScene);
SetupRC();
glutMainLoop();
}
return 0;
}
Division of Electrical and Computer Engineering, Hanyang University
실행 결과
 glColor3f(1.0,0.0,0.0); 으로 모델 색상을 적색으로
지정하였지만, 무시되고 회색으로 그려졌다(광원의 diffuse
세기가 0.7,0.7,0.7이므로)
 물체의 고유한 색상을 표현하기 위해서는 재질 속성을
지정해야 한다.
Division of Electrical and Computer Engineering, Hanyang University
재질 속성
 재질 속성 설정

void glMaterialfv (GLenum face, GLenum pname,
const GLfloat *params);



face : 폴리곤의 어떤 면에 대한 속성인지 지정.
• GL_FRONT, GL_BACK, GL_FRONT_AND_BACK
pname : 속성 종류.
• GL_AMBIENT, GL_DIFFUSE, GL_EMISSION,
GL_SPECULAR,GL_AMBIENT_AND_DIFFUSE
params : 속성값 배열(4차원 벡터 형태)
 반사율 값은 0~1사이의 값
Division of Electrical and Computer Engineering, Hanyang University
Example code – material properties
 다음을 전역 변수에 추가하고
 GLfloat material[] = { 0.75f, 0.0, 0.0, 1.0f };
 RenderScene() 함수를 다음과 같이 바꾼다.
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(0.0f, 0.0f, -300.0f);
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
glPushMatrix();
glRotatef(xRotLight, 1.0f, 0.0f, 0.0f);
glRotatef(yRotLight, 0.0f, 1.0f, 0.0f);
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
glPopMatrix();
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, material);
glutSolidTeapot(100.0);
glPopMatrix();
glutSwapBuffers();
}
Division of Electrical and Computer Engineering, Hanyang University
실행 결과
Division of Electrical and Computer Engineering, Hanyang University
재질 속성
 색상 트래킹(color tracking) 방법

버텍스 색상을 재질 속성으로 사용(ambient, diffuse)
glEnable(GL_COLOR_MATERIAL);

void glColorMaterial (GLenum face, GLenum mode);




face : 폴리곤의 어떤 면에 대해 적용할지 지정
• GL_FRONT, GL_BACK, GL_FRONT_AND_BACK
mode : 어떤 속성이 버텍스 색상의 영향을 받을 것인지 지정
• GL_EMISSION, GL_AMBIENT, GL_DIFFUSE,
GL_SPECULAR, GL_AMBIENT_AND_DIFFUSE
일반적으로 물체의 고유한 색상을 표현하기 위해 ambient 및
diffuse 성분은 색상 트래킹으로 지정하고, specular 성분은
따로 glMaterial3f를 이용하여 [1.0,1.0,1.0,1.0]과 같은 값을
지정.
Division of Electrical and Computer Engineering, Hanyang University
Example code – color tracking
 SetupRC()에 다음을 추가하고


glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
 RenderScene() 함수를 다음과 같이 바꾼다.
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(0.0f, 0.0f, -300.0f);
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
glPushMatrix();
glRotatef(xRotLight, 1.0f, 0.0f, 0.0f);
glRotatef(yRotLight, 0.0f, 1.0f, 0.0f);
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
glPopMatrix();
glColor3f(0.0, 1.0, 0.0);
glutSolidTeapot(100.0);
glPopMatrix();
glutSwapBuffers();
}
Division of Electrical and Computer Engineering, Hanyang University
Division of Electrical and Computer Engineering, Hanyang University
재질 속성
 재질의 반사지수 설정
 Specular term ks Is (h · n )a 에서 α에 해당하는 값으로
하이라이트가 생기는 영역의 크기
 void glMaterialf (GLenum face, GLenum pname, const GLfloat
param);
 pname : 속성 종류
• GL_SHINESS : 재질의 반사지수(specular exponent)

parans : 속성값
• 반사지수의 경우 1 ~ 128 의 값. 작을수록 하이라이트의 면적이
넓어지고, 클수록 하이라이트 면적이 좁아진다.
Division of Electrical and Computer Engineering, Hanyang University
Example code – specular highlight
 다음을 전역 변수에 추가하고
 GLfloat materialSpecular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
 RenderScene() 함수를 다음과 같이 바꾼다.
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(0.0f, 0.0f, -300.0f);
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
glPushMatrix();
glRotatef(xRotLight, 1.0f, 0.0f, 0.0f);
glRotatef(yRotLight, 0.0f, 1.0f, 0.0f);
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
glPopMatrix();
glMaterialfv(GL_FRONT, GL_SPECULAR,materialSpecular);
glMaterialf(GL_FRONT,GL_SHININESS,100);
glColor3f(0.0, 1.0, 0.0);
glutSolidTeapot(100.0);
glPopMatrix();
glutSwapBuffers();
}
Division of Electrical and Computer Engineering, Hanyang University
실행 결과
 GL_SHININESS를 100으로 지정할 경우 왼쪽 그림과 같이 specular
highlight가 좁은 영역에 나타난다(붉은 원 표시된 부분, 시점에 따라
밝기가 다르다.).
 GL_SHININESS를 1로 지정한 경우 오른쪽 그림과 같이 specular
highlight가 넓은 영역에 나타난다(h · n 가 한 번만 곱해지기 때문.).
Division of Electrical and Computer Engineering, Hanyang University
Example code


직접 버텍스 좌표를 지정하여 모델링하는 경우
법선 벡터도 지정해 주어야 한다.
다읨의 코드를 추가하고,
void DrawCube()
{
glBegin(GL_QUADS);
glNormal3f(0.0, 0.0, 1.0);
glVertex3f(50.0,50.0,50.0); glVertex3f(50.0,-50.0,50.0);
glVertex3f(-50.0,-50.0,50.0); glVertex3f(-50.0,50.0,50.0);
glNormal3f(0.0, 0.0, -1.0);
glVertex3f(50.0,50.0,-50.0); glVertex3f(-50.0,50.0,-50.0);
glVertex3f(-50.0,-50.0,-50.0); glVertex3f(50.0,-50.0,-50.0);
glNormal3f(0.0, 1.0, 0.0);
glVertex3f(50.0,50.0,-50.0); glVertex3f(50.0,50.0,50.0);
glVertex3f(-50.0,50.0,50.0); glVertex3f(-50.0,50.0,-50.0);
glNormal3f(0.0, -1.0, 0.0);
glVertex3f(50.0,-50.0,-50.0); glVertex3f(-50.0,-50.0,-50.0);
glVertex3f(-50.0,-50.0,50.0); glVertex3f(50.0,-50.0,50.0);
glNormal3f(1.0, 0.0, 0.0);
glVertex3f(50.0,50.0,50.0);glVertex3f(50.0,50.0,-50.0);
glVertex3f(50.0,-50.0,-50.0); glVertex3f(50.0,-50.0,50.0);
glNormal3f(-1.0, 0.0, 0.0);
glVertex3f(-50.0,50.0,50.0); glVertex3f(-50.0,-50.0,50.0);
glVertex3f(-50.0,-50.0,-50.0); glVertex3f(-50.0,50.0,-50.0);
glEnd();
}

RenderScene()에서 glutSolidTeapot() 대신
DrawCube() 호출
Division of Electrical and Computer Engineering, Hanyang University
Spot light
 스포트라이트 조명의 설정을 위해서는 빛을 비추는
방향과 cut-off angle을 지정해야 한다.


glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,angle);
 도(degree) 단위의 cut-off angle 지정
glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,spotDir);
Division of Electrical and Computer Engineering, Hanyang University
Example code - spotlight
 전역 변수로 다음을 추가
 GLfloat spotDir[] = { -lightPos[0],-lightPos[1],lightPos[2], 1.0 };
 물체가 있는 곳을 비추기 위해 스포트라이트의 방향을
조명위치와 반대로 적용
 SetupRC()에 다음을 추가
 glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,60.0f);
 SetupRC()에서 조명의 ambient 성분을 제거
 RenderScene()에서 조명 위치를 지정하는 부분
다음에 다음을 추가

glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,spotDir);
Division of Electrical and Computer Engineering, Hanyang University
실행결과
 왼쪽 그림은 cut-off angle이 60도인 경우
 오른쪽 그림은 cut-off angle이 10도인 경우
Division of Electrical and Computer Engineering, Hanyang University
Shade model
 glShadeModel(GL_
SMOOTH);
 glShadeModel(GL_
FLAT);
Division of Electrical and Computer Engineering, Hanyang University