Computer Graphics

Chapter13-1. 조명과 음영 OpenGL 코딩

CodeJB 2021. 6. 9. 17:54

전역 주변광

  1. 3차원 공간에 벽, 바닥, 공 만들기
  2. 전역 주변광 추가
  3. glEnable(GL_LIGHTING)의 효과 확인
glEnable(GL_LIGHTING);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);

GLfloat light_global_ambient[] = {0.0, 0.0, 0.1, 1.0}; //ambient : 주변광
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, light_global_ambient);

위치성 광원 추가

  1. 위치성 광원 1개 추가
  2. 광원의 위치 변경 테스트
  3. 광원의 색상 변경 테스트
GLfloat bNonDirectionalLight = 1.0; //DirectionalLight가 아니다.
    
GLfloat light_0_pos[] = {Light0_pos_x, Light0_pos_y, Light0_pos_z, bNonDirectionalLight}; //빛 위치 지정 공 바로 위에
GLfloat light_0_specular[] = {1.0, 1.0, 1.0, 1.0};
GLfloat light_0_diffuse[] = {1.0, 1.0, 1.0, 1.0};
GLfloat light_0_ambient[] = {1.0 , 1.0, 1.0, 1.0};//백색광 = 태양
    
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_POSITION, light_0_pos); //0번째 Light Position지정 개수는 GPU에 따라 다름
glLightfv(GL_LIGHT0, GL_SPECULAR, light_0_specular);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_0_diffuse);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_0_ambient);

 

물체의 반사 설정 추가

  1. 물체의 빛 반사 설정
//물체 색깔
GLfloat material_0_specular[] = {1.0, 1.0, 1.0, 1.0};//빛 색깔과 그대로 맞춰주기
GLfloat material_0_diffuse[] = {0.8, 0, 0, 1.0};
GLfloat material_0_ambient[] = {1.0, 0, 0, 1.0};
GLfloat material_0_shininess[] = {25.0};// 0~128
    
glMaterialfv(GL_FRONT, GL_DIFFUSE, material_0_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, material_0_specular);
glMaterialfv(GL_FRONT, GL_AMBIENT, material_0_ambient);
glMaterialfv(GL_FRONT, GL_SHININESS, material_0_shininess);

법선 벡터 설정

  1. 벽과 바닥의 법선 벡터 설정
  2. 법선 벡터는 정점마다 다르게 설정할 수 있음
  3. 따라서, 법선 벡터의 설정에 따라 곡면 표현이 가능해짐
  4. 하지만, 법선 벡터의 크기는 항상 1이므로 정규화를 따로 해줘야함.
void drawFloor(GLfloat y){
    glNormal3f(0, 1, 0);
    glBegin(GL_POLYGON);
}
 
void drawWall(GLfloat z){
	glPushMatrix();
    glNormal3f(0,0,-1);
    glBegin(GL_POLYGON);
}

glEnable(GL_NORMALIZE); //만약 법선 벡터의 크기를 1로 하지 않았다면 꼭 정규화 해줘야함

발광체 설정(스스로 빛나는 물체)

  1. 물체의 발광체 설정
GLfloat material_0_emission[] = {0.0, 0.0, 0.5, 1.0};

glMaterialfv(GL_FRONT, GL_EMISSION, material_0_emisson);
  1. 발광체는 스스로 빛을 발생
  2. 다른 물체에 빛을 보내지는 않음
  3. 시점 위치에 따른 정밀도 설정이 가능함(가까이에 있는 물체는 조금더 정밀하게 : GPU에 따라 차이 발생)
glLightModeli(GL_LIGHT_LOCAL_VIWER, GL_TRUE);

OpenGL 실습코드  : Lighting

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

#define _WINDOW_WIDTH 500
#define _WINDOW_HEIGHT 500

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

GLfloat Light0_pos_x = 5.0, Light0_pos_y = 5.0, Light0_pos_z = 0.0;

void MaterialLightInit(GLfloat am_R, GLfloat am_G, GLfloat am_B, GLfloat am_A , GLfloat di_R, GLfloat di_G, GLfloat di_B, GLfloat di_A){
    
    glDisable(GL_COLOR_MATERIAL); //display할 때마다 기존의 색상을 무효화시키고 새로 그려라, 이렇게 안하면 reshape될때 색이 바뀜
    GLfloat material_0_specular[] = {1.0, 1.0, 1.0, 1.0};//빛 색깔과 그대로 맞춰주기
    GLfloat material_0_diffuse[] = {di_R, di_G, di_B, di_A};
    GLfloat material_0_ambient[] = {am_R, am_G, am_B, am_A};
    GLfloat material_0_shininess[] = {25.0};// 0~128
    //GLfloat material_0_emission[] = {0.0, 0.0, 1.0, 1.0};

    glMaterialfv(GL_FRONT, GL_DIFFUSE, material_0_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, material_0_specular);
    glMaterialfv(GL_FRONT, GL_AMBIENT, material_0_ambient);
    glMaterialfv(GL_FRONT, GL_SHININESS, material_0_shininess);
    //glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
}
void drawFloor(GLfloat y){
    GLfloat x = -2.5, z = -2.5, w = 5;
    
    MaterialLightInit(0, 0, 1.0, 1.0, 0, 0, 0.8, 1.0);
    glBegin(GL_POLYGON);
         glNormal3f(-2, 1, 0);
        //법선벡터는 따로 해줘야 쉐이딩이 적용된다.
        //법선 벡터의 방향에 따라서 평면이 볼록&오목(곡면 설정)하다라고 인식함 이를 이용해서 적절하게 음영을 주는거임
        //하지만 이렇게되면 법선벡터의 크기가 1이 아니기 때문에 Normalize해줘야함.
         glVertex3f(x,y,z);
         glVertex3f(x,y,z+w);
    
         glNormal3f(2, 1, 0);
         glVertex3f(x+w,y,z+w);
         glVertex3f(x+w,y,z);
    
        //이렇게 설정하면 평면이 오목하게돼서 왼쪽 두 점은 더 어두워지고
        //오른쪽 두 점은 약간 더 어두워짐
         
       
         
    glEnd();
}

void drawWall(GLfloat z){
    GLfloat x = -2.5, y = -2.5, w = 5;
    //glColor3f(0.2, 0.6, 0.2);
    MaterialLightInit(1.0, 1.0, 0, 1.0, 1.0, 1.0, 0, 1.0);
    glNormal3f(0, 0, -1); //법선벡터는 따로 해줘야 쉐이딩이 적용된다.
    glBegin(GL_POLYGON);
         glVertex3f(x,y,z);
         glVertex3f(x,y+w,z);
         glVertex3f(x+w,y+w,z);
         glVertex3f(x+w,y,z);
    glEnd();
}

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 drawSphere(){
    MaterialLightInit(1.0, 0, 0, 1.0, 0.8, 0, 0, 1.0);
    
    glutSolidSphere(0.3, 20, 20);
}
void MyDisplay(){
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_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);
    
    drawFloor(-2.5);
    drawWall(2.5);
    drawSphere();
    //glColor3f(0.8, 0.2, 0.0);
    glFlush();
}

void Init_light(){
    
    GLfloat bNonDirectionalLight = 1.0; //DirectionalLight가 아니다.
    glEnable(GL_LIGHTING); //빛을 쓰겠다
    glShadeModel(GL_SMOOTH); //구로 셰이딩 쓰겠다 퐁 셰이딩은 GL에 없음
    glEnable(GL_DEPTH_TEST);
    
    GLfloat light_global_ambient[] = {0.3,0.3,0.3, 1}; //전역 주변광 색깔 지정
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, light_global_ambient);//전역 주변광을 주겠다.
    
    GLfloat light_0_pos[] = {Light0_pos_x, Light0_pos_y, Light0_pos_z, bNonDirectionalLight}; //빛 위치 지정 공 바로 위에
    GLfloat light_0_specular[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat light_0_diffuse[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat light_0_ambient[] = {1.0 , 1.0, 1.0, 1.0};//백색광 = 태양
    
    glEnable(GL_LIGHT0);
    glLightfv(GL_LIGHT0, GL_POSITION, light_0_pos); //0번째 Light Position지정 개수는 GPU에 따라 다름
   // glLightfv(GL_LIGHT0, GL_SPECULAR, light_0_specular);
   // glLightfv(GL_LIGHT0, GL_DIFFUSE, light_0_diffuse);
   // glLightfv(GL_LIGHT0, GL_AMBIENT, light_0_ambient);
    
    glEnable(GL_NORMALIZE);//법선벡터 정규화 크기를 1로 바꾸기
}
int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(_WINDOW_WIDTH, _WINDOW_HEIGHT);
    glutInitWindowPosition(300, 200);
    
    glutCreateWindow("Lighting & Shading");
    
    glClearColor(0,0,0,0.0);
    Init_light();
    
    glutDisplayFunc(MyDisplay);
    glutReshapeFunc(MyReshape);
    
    glutMainLoop();
    return 0;
}

Color를 넣은게 아니고 빛에 의한 색상들이다.

OpenGL 실습코드 : SpotLight

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

#define _WINDOW_WIDTH 500
#define _WINDOW_HEIGHT 500

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

GLfloat Light0_pos_x = 2.0, Light0_pos_y = 2.0, Light0_pos_z = -2.0;
GLfloat bNonDirectionalLight = 1.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 Init_light(){
    glEnable(GL_LIGHTING); //빛을 쓰겠다
    glShadeModel(GL_SMOOTH); //구로 셰이딩 쓰겠다 퐁 셰이딩은 GL에 없음
    glEnable(GL_DEPTH_TEST);
    
    glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
}

void MyDisplay(){
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_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);
     
    //전역광
    GLfloat light_global_ambient[] = {0.3,0.3,0.3, 1}; //전역 주변광 색깔 지정
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, light_global_ambient);
    
    //조명 설정 & 스포트라이트
    glEnable(GL_LIGHT0);
    GLfloat light_0_pos[] = {Light0_pos_x, Light0_pos_y, Light0_pos_z, bNonDirectionalLight}; //빛 위치 지정 공 바로 위에
    GLfloat light_0_dir[] = {-1, -1, 1};
    GLfloat light_0_SpotAngle[] = {3};
    GLfloat light_0_SpotExp1[] = {10.0};
    glLightfv(GL_LIGHT0, GL_POSITION, light_0_pos);
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_0_dir);
    glLightfv(GL_LIGHT0, GL_SPOT_CUTOFF, light_0_SpotAngle);
    glLightfv(GL_LIGHT0, GL_SPOT_EXPONENT, light_0_SpotExp1); //확산 적용이 안되는 것 같음
    
    //주변광, 확산광, 경면광
    GLfloat light_0_specular[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat light_0_diffuse[] = {0, 0, 1.0, 1.0};
    GLfloat light_0_ambient[] = {1.0 , 1.0, 1.0, 1.0};//백색광 = 태양
    
    glLightfv(GL_LIGHT0, GL_SPECULAR, light_0_specular);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light_0_diffuse);
    glLightfv(GL_LIGHT0, GL_AMBIENT, light_0_ambient);
    
    //물체 반사광
    glDisable(GL_COLOR_MATERIAL); //display할 때마다 기존의 색상을 무효화시키고 새로 그려라, 이렇게 안하면 reshape될때 색이 바뀜
    GLfloat material_0_specular[] = {1.0, 1.0, 1.0, 1.0};//빛 색깔과 그대로 맞춰주기
    GLfloat material_0_diffuse[] = {0.8,0,0.3,1.0}; // 파란색도 어느정도 반사되게 함
    GLfloat material_0_ambient[] = {0.3,0.3,0.3,1.0};
    GLfloat material_0_shininess[] = {25.0};// 0~128
    //GLfloat material_0_emission[] = {0.0, 0.0, 1.0, 1.0};

    glMaterialfv(GL_FRONT, GL_DIFFUSE, material_0_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, material_0_specular);
    glMaterialfv(GL_FRONT, GL_AMBIENT, material_0_ambient);
    glMaterialfv(GL_FRONT, GL_SHININESS, material_0_shininess);
    //glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
    
    glutSolidTeapot(0.3);
    
    glEnable(GL_COLOR_MATERIAL);
    
    glFlush();
}
int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(_WINDOW_WIDTH, _WINDOW_HEIGHT);
    glutInitWindowPosition(300, 200);
    
    glutCreateWindow("Lighting & Shading");
    
    glClearColor(0,0,0,0.0);
    Init_light();
    
    glutDisplayFunc(MyDisplay);
    glutReshapeFunc(MyReshape);
    
    glutMainLoop();
    return 0;
}

 

'Computer Graphics' 카테고리의 다른 글

Chapter15. 텍스쳐  (0) 2021.06.14
Chapter14. 모델 Load & 조명주기  (0) 2021.06.09
Chapter13. 조명과 음영  (0) 2021.06.08
Chapter12. 에일리어싱과 안티 에일리어싱  (0) 2021.06.07
Chapter11. 래스터 변환  (0) 2021.06.07