Software Development/Graphics

OpenGL Super Bible 그래픽스 공부하기 - 2. 첫번째 OpenGL 프로그램

huiyu 2018. 1. 14. 12:15

OpenGL Super Bible 그래픽스 공부하기 - 1. OpenGL 기본개념이해

Part2. 첫번째 OpenGL 프로그램

  - 쉐이더 코드 생성 / 컴파일
  - OpenGL로 그리기
  - AppFw이용, 프로그램 초기화 정리

2.1 간단한 애플리케이션 ->(SDL+GL 사용한 샘플, 간단하게 glClearBuffv를 사용하고 있다.)

 - 모든 OpenGL 함수는 gl로 시작, 일부 인자 타입을 함수 이름 끝에 접미사로 줄여쓰는 등 여러 네이밍 컨벤션을 따름

1
2
void glClearBufferfv(GLenum buffer, GLint drawBuffer, const GLfloat *value)
//접미사, f(floating point) + v(vector)
cs

  -> value(r,g,b,a) ---(clear)--->buffer //a - 0:완전투명(Transparent), 1:불투명(Opaque)
  -> drawBuffer는 지울 출력 버퍼가 여럿일 때 사용

2.2 Shader

 - OpenGL은 Shader라 불리는 여러 작은 프로그램을 연결시켜 작동.
 - OpenGL Shading Language(GLSL)로 작성, C기반, 컴파일러는 OpenGL에 내장
 - (Shader Source)---(Compile)--->(Shader Object),
   (Shader Object)+(Shader Object)+(Shader Object) ---(Link)--->(Program Object, 프로그램 객체)
  * 작성한 쉐이더 소스 코드는 쉐이더 객체로 바뀌어 컴파일 되고, 여러 쉐이더 객체들이 하나의 프로그램 객체로 링크된다.

예제1) 첫번째 버텍스 쉐이더

1
2
3
4
5
6
#version 430 core
 
void main(void)
{
    gl_Position = vec4(0.00.00.51.0);
}
cs

  - #version 430 core : shader language 4.3 사용, OpenGL Core profile 사용
  - main : 쉐이더 시작 부분, 일반적인 C프로그램과 동일, 단 main 함수는 인자가 없다.
  - gl_Position : gl_로 시작하는 모든 변수는 OpenGL의 일부이며 쉐이더와 다른 부분 또는 고정함수 기능의 여러 부분과 연결하는 역할
                    gl_Position은 vertex의 출력 위치를 나타낸다.
  - vec4(0.0, 0.0, 0.5, 1.0) : OpenGL의 클립 공간(Clip Space)의 중앙에 위치
      *클립공간 : OpenGL 파이프라인의 다음 스테이지에서 적용되는 좌표계

예제2) 첫번째 프래그먼트 쉐이더

1
2
3
4
5
6
7
8
#version 430 core
 
out vec4 color;
 
void main(void)
{
    color = vec4(0.00.81.01.0);
}
cs

  - out : color 변수를 출력 변수로 선언, 출력 변수값은 윈도우나 화면으로 보내진다.
  - vec4(0.0, 0.8, 1.0, 1.0) : r, g, b, a 의미, 청록색


이제 실행시켜보자...실행은 SDL2와 OpenGL을 이용하여 사용할 예정이다.
아래에서 간단하게 세팅은 확인할 수있다. (SDL2+GL 기본 프레임워크 기반에서 수정해나가자)

http://huiyu.tistory.com/210 


SDL을 사용하는 이유는 SDL이 GL을 사용하는데 있어서 간단하고, 샘플코드도 직관적으로 이해하기 쉽기 때문이다.
무엇보다 나한테 익숙하단 장점이 있다...ㅎㅎ

이제 위의 쉐이더 코드를 사용하기 위해 SDL2+GL 기본 프레임워크에서 compile_shaders() 함수를 추가하자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
GLuint compile_shaders(void)
{
        GLuint vertex_shader;
        GLuint fragment_shader;
        GLuint program;
 
        //vertext shader source code
        static const GLchar * vertex_shader_source[] =
        {
                "#version 430 core                           \n"
                "                                            \n"
                "void main(void)                             \n"
                "{                                           \n"
                "    gl_Position = vec4(0.0, 0.0, 0.5, 1.0); \n"
                "}                                           \n"
        };
 
        //fragment shader source code
        static const GLchar * fragment_shader_source[] =
        {
                "#version 430 core                          \n"
                "                                           \n"
                "out vec4 color;                            \n"
                "                                           \n"
                "void main(void)                            \n"
                "{                                          \n"
                "    color = vec4(0.0, 0.8, 1.0, 1.0);      \n"
                "}                                          \n"
        };
 
        //create vertex shader and compile
        vertex_shader = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertex_shader, 1, vertex_shader_source, NULL);
        glCompileShader(vertex_shader);
 
        //create fragment shader and compile
        fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragment_shader, 1, fragment_shader_source, NULL);
        glCompileShader(fragment_shader);
 
        //create program->attach shader->link
        program = glCreateProgram();
        glAttachShader(program, vertex_shader);
        glAttachShader(program, fragment_shader);
        glLinkProgram(program);
 
        //delete shader, 프로그램이 쉐이더를 소유하므로 삭제 필요
        glDeleteShader(vertex_shader);
        glDeleteShader(fragment_shader);
 
        return program;
}
cs

create_shaders()는 작성한 shader source code를 이용하여 쉐이더를 생성 후 컴파일한다.
이후 생성한 쉐이더를 프로그램에 붙이고 링크, 생성된 프로그램을 리턴한다.
  1) glCreateShader() : 빈 쉐이더 객체 생성, 소스를 받은 후 컴파일
  2) glShaderSource() : 쉐이더 소스코드를 쉐이더 객체로 전달 후 복사본 유지
  3) glCompileShader() : 쉐이더 객체에 포함된 소스코드 컴파일
  4) glCreateProgram0 : 쉐이더 객체에 attach시킬 프로그램 객체 생성
  5) glAttachShader() : 쉐이더 객체를 프로그램 객체에 어태치
  6) glLinkProgram() : 프로그램 객체에 어태치된 모든 쉐이더 객체 링크
  7) glDeleteShader() : 쉐이더 객체를 삭제
    *쉐이더 프로그램 객체에 링크되면 프로그램이 바이너리 코드를 보관하며 쉐이더는 필요하지 않는다.


사용자는 생성한 프로그램을 glUseProgram()을 호출하여 사용하면 된다.

1
2
3
4
5
static const GLfloat red[] = {1.0f, 0.0f, 0.0f, 1.0f};
glClearBufferfv(GL_COLOR, 0, red);
glUseProgram(rendering_program);
glDrawArrays(GL_POINTS,01);
SDL_GL_SwapWindow(win);
cs

 - glUseProgram() : OpenGL에 해당 프로그램 객체를 사용하여 렌더링 시킨다.
 - glDrawArrays() : mode : 어떤 타입의 프리미티브로 그릴지 설정(GL_POINTS, GL_LINES, GL_TRIANGLES)
    -> drawing명령어로 vertex를 파이프라인으로 보내게 된다.

1
2
3
void glDrawArrays(    GLenum mode,
     GLint first,
     GLsizei count);
cs


이대로 프로그램을 실행시켜도 이전과 차이가 없는데, 점의 크기가 너무 작아서 그렇다.
메인루프 이전에 점의 크기를 키워주는 glPointSize()를 호출해준다.

1
glPointSize(40);
cs


다시 실행시키면 아래와 같이 나오는 걸 볼 수 있다.


728x90