최신의 OpenGL과 Shader를 사용하기 위해 glew 연동까지 준비가 되었습니다.
1. 기본 랜더링 코드
이후에 진행 될 GLSL 기반의 랜더링과 비교를 용이하게 하기 위해, 1.1 기반의 랜더링에 조금 신경을 써보겠습니다.
삼각형 대신 glut에서 제공되는 주전자 그리기 기능으로 주전자를 그리고, 배경색이나 Depth 버퍼 초기화도 추가했습니다.
void display() {
//Clear
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//Draw
glColor3f(0.0f, 0.0f, 1.0f);
glutSolidTeapot(0.5);
glFinish();
}
2. 조명 효과
조명 효과를 위해서, 최소한의 파라미터로 조명을 활성화 시키겠습니다. glew는 활성화 시키지 않겠습니다.
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutCreateWindow("OpenGL");
//initGLEW();
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
이 상태로 랜더링을 해 보면 아래와 같이 주전자가 흰색으로 반쯤 보이네요.(사용자 환경에 따라 다르게 나올 수도 있을 것 같습니다.)
OpenGL의 조명에 대해서도 꽤 많은 양의 학습이 필요한데, 여기서 다룰 수 없으니, 아주 초간단 요약만 좀 하겠습니다.
검색을 조금 해 보니, 요즘은 opengl 조명이라고 하면 쉐이더로 조명 설정하는 내용이 많고, 1.1 조명 설정에 대한 내용은 찾아보기 어렵네요. 억지로 1.1을 넣어서 검색하면 나오긴 합니다.
http://math.hws.edu/graphicsbook/c4/s2.html
조명을 쓰려면 glEnable(GL_LIGHTING)으로 조명 기능을 활성화 시켜줘야 하고,
OpenGL에서 지원하는 기본 조명은 8개가 있는데 각 조명도 별도로 활성화(glEnable(GL_LIGHTn)) 시켜줘야 합니다.
조명에는 아주 다양한 속성이 있는데, 색상/위치/방향/반사특성 등을 정할 수 있습니다. 또, 조명을 사용하게 되면, 재질도 정해줘야 하는데, 재질 X 조명의 결과가 화면에 그려지게 됩니다. 그래서, 조명 설정을 하지 않은 상태에서는 파란색 삼각형이 그려진 것이고, 조명을 설정하니, 재질 정보가 없으니 기본값인 흰색이 적용되었습니다. 이 설정 색상(glColor)이 재질로 사용되게 하는 옵션이 있는데, glEnable(GL_COLOR_MATERIAL)을 적용하면, 삼각형을 봤을 때 처럼 지정 된 색상이 (재질의 diffuse 성분으로 적용되어) 나타납니다.
입체감을 나타내기 위해서는, 조명 외에도 Depth test, Font face, Projection volume 등 다양한 설정이 필요한데, 그건 여기서 따로 설명하지 않고, 아래 코드로 기본적인 입체감이 확인되는 설정을 한 것으로 하겠습니다.
void initGL()
{
//Enable/Disable
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
//Rendering
glFrontFace(GL_CCW);
//Light
GLfloat lightPos[] = { 0.f, 0.f, 10.f, 0.f };
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
glEnable(GL_COLOR_MATERIAL);
//Modelview and projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.f, 1.f, -1.f, 1.f, -1.f, 1.f);
glMatrixMode(GL_MODELVIEW);
}
아래와 같이 나옵니다.
뒤에서 살펴보겠지만, Shader로 이러한 조명 효과를 내기 위해서는 꽤 많은 작업이 필요합니다. 이 작업은 조명을 위한 작업이라기 보다는, Shader를 쓰기 위한 작업입니다. 이렇게 뭐 하나 새로운 것 하려면 쉽지 않죠. 그렇지만, 어렵게 해 둔 후, 그 다음 그 기반으로 뭔가 만들어 가는 것은 많은 작업을 필요로 하지 않습니다. OpenGL 초기 환경 설정은 번거루웠지만, 그 상태에서 조명 적용은 간단히 된 것 처럼 말이죠.
3. animation 적용
Shader의 참맛은 표면 형상에 따른 변화가 부드럽게 이어지는 것을 보는데 있어요. 그래서, 굴곡을 느낄 수 있도록 회전 animation도 걸어두겠습니다. 조명의 느낌이 잘 나도록 색상도 조금 밝게 수정했습니다.
glut의 창을 만들고, 랜더링 하는 설정을 조금 손보고, 간단한 회전 코드를 추가하겠습니다.
이 상태에서는, glew를 초기화 해도 아무 것도 달라지지 않습니다.
이렇게 1.1로 랜더링 된 상태에서, 이 상태를 GLSL을 이용해서 만드는 과정을 쉐이더로 직접 구현 해 보면, OpenGL pipeline을 이해하는데 큰 도움이 되고, 그래서, GLSL이 무엇을 할 수 있는지 가늠하는데 도움이 됩니다.
여기까지 구현한 코드는 아래와 같습니다.
#include <iostream>
#include <gl/glew.h>
#include <GL/glut.h>
float rotate_angle = 0.f;
void changeSize(int w, int h) {
if (h == 0) h = 1;
float ratio = 1.0 * w / h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, w, h);
glOrtho(-1.f, 1.f, -1.f, 1.f, -1.f, 1.f);
glMatrixMode(GL_MODELVIEW);
}
void display() {
//Clear
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//Draw
glPushMatrix();
glRotatef(rotate_angle, 0.f, 1.f, 0.f);
glutSolidTeapot(0.5);
glPopMatrix();
glFlush();
glutSwapBuffers();
rotate_angle = rotate_angle + 0.1f;
if (rotate_angle > 360.f) rotate_angle -= 360.f;
}
void initGLEW()
{
//Initialize GLEW
GLenum err = glewInit();
if (GLEW_OK != err)
{
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
exit(0);
}
fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
//Check Shader
//ARB
if (GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader)
printf("Ready for GLSL (ARB)\n");
else
{
printf("No GLSL support\n");
exit(0);
}
//OpenGL 4.6
if (glewIsSupported("GL_VERSION_4_6"))
printf("Ready for OpenGL 4.6\n");
else {
printf("OpenGL 4.6 not supported\n");
exit(0);
}
}
void initGL()
{
//Enable/Disable
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
//Rendering
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glFrontFace(GL_CCW);
glColor3f(0.0f, 0.5f, 1.0f);
//Light
GLfloat lightPos[] = { 0.f, 0.f, 10.f, 0.f };
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
glEnable(GL_COLOR_MATERIAL);
//Modelview and projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.f, 1.f, -1.f, 1.f, -1.f, 1.f);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitWindowPosition(100, 100);
glutInitWindowSize(300, 300);
glutCreateWindow("OpenGL");
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutDisplayFunc(display);
glutReshapeFunc(changeSize);
glutIdleFunc(display);
initGLEW();
initGL();
glutMainLoop();
return 0;
}
다음 시간부터, 본격적으로 쉐이더 쓸 준비를 해볼께요.
https://learn-and-give.tistory.com/13
'공허의 유산 > 표현의 자유' 카테고리의 다른 글
[아빠의 Roblox 숙제]#1. 와리가리 물체를 이용해서 건너가기 (0) | 2021.01.29 |
---|---|
[opengl].[#2.GLSL] 02. Shader 사용 기반 코드 작성 (0) | 2020.08.09 |
[opengl].[#1.Setup] Windows/VS2019/glut 기반의 셋업(3) - glew로 shader 사용 환경 구축 (0) | 2020.08.08 |
[opengl].[#1.Setup] Windows/VS2019/glut 기반의 셋업(2) - glut(freeglut)로 opengl 창 띄우기 (0) | 2020.08.08 |
[opengl].[#1.Setup] Windows/VS2019/glut 기반의 셋업(1) - Visual studio 2019 설치 (0) | 2020.08.08 |
댓글