[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