본문 바로가기
C++ 200제/코딩 IT 정보

[OpenGL ES] 8. 쉐이더와 프로그램 vsh, fsh (shader, program)

by vicddory 2017. 10. 26.

[OpenGL ES] 8. 쉐이더와 프로그램 vsh, fsh (shader, program)


OpenGL ES Shader id를 생성하고, 소스 코드를 업로드하고 컴파일한다. 이미 소스 코드를 가지고 있는 Shader에 새로운 코드를 업로드하면 기존의 소스 코드는 없어진다.


일단 OpenGL ES shader가 컴파일되면 소스 코드를 바꿀 순 없으며, 각 shader는 컴파일 여부를 알려주는 Glboolean형 상태 값을 가지고 있다. Shader가 성공적으로 컴파일되면 이 상태는 TRUE가 되는데, 디버그 모드에서 유용하게 쓰이기도 한다.


이것과 더불어 glGetShaderiv와 glGetShaderInfoLog 함수를 써서 어디서 오류가 발생했는지도 확인할 수 있다. 여기서 이 함수를 설명하진 않지만, 간단한 소스를 보여줄 거다.


만약 당신이 vsh 하나를 생성하면 id 값은 1이 될 테고, 이 숫자는 id에 다시 할당되진 않을 것이다. 당신이 fsh를 하나 더 생성하면 아마도 id는 2가 될 테니, vsh와 fsh는 같은 id 값을 가질 수는 없다. (0번은 절대 할당되지도, 할당할 수도 없음을 기억하자)


OpenGL ES의 vsh, fsh가 정상적으로 컴파일되면 program 객체를 만들어 shader를 넣는다. Program을 만드는 과정은 shader 때와 비슷하다. 먼저 program을 만들고, 무언가를 업로드하고 (여기서는 컴파일된 shader), 프로그램을 링크한다.


근데, program은 뭘 링크하지?


Program은 shader 2개를 링크하고, 자기 자신을 opengl ES 코어와 링크한다. program도 link 상태와 link 정보 로그를 가지고 있으니, 우리는 이걸로 에러를 체크할수 있다. Program이 성공적으로 링크되면, shader가 올바로 동작할 것이다.


OpenGL ES 쉐이더 프로그램 vsh fsh[[OpenGL ES] 8. 쉐이더와 프로그램 vsh, fsh (shader, program)]


아래는 program 객체 관련된 함수들이다.


Program Object Creation


GLuint glCreateProgram(void)

This function requires no parameter. This is because only exist one kind of Program Object, unlike the shaders. Plus, instead to take the memory location to one variable, this function will return the name/id directly, this different behavior is because you can't create more than one Program Object at once, so you don't need to inform a pointer.


GLvoid glAttachShader(GLuint program, GLuint shader)

program: The program name/id generated by the glCreateProgram function.

shader: The shader name/id generated by the glCreateShader function.


GLvoid glLinkProgram(GLuint program)

program: The program name/id generated by the glCreateProgram function.


OpenGL ES glAttachShader 함수에서는 넘겨주는 shader가 vertex인지 fragment인지 알려주는 파라미터가 없다.


OpenGL ES, 쉐이더, vsh, fsh[[OpenGL ES] 8. 쉐이더와 프로그램 vsh, fsh (shader, program)]


Shader의 id는 중복되지 않는다는 것을 기억하는가.


OpenGL ES는 유니크한 shader id를 통해 어떤 종류의 shader인지 자동으로 구분한다. 중요한 것은 glAttachShade를 2번 호출한다는 것이다(vsh 한번, fsh 한번). 만약 vsh를 2번 붙이거나, fsh를 2번 붙이면, program은 링크되지 않는다. shader를 2개 이상 붙여도 링크는 실패한다.


개발자는 program의 객체를 여러 개 생성할 수 있는데, OpenGL ES는 glDraw 할 때 어떤 program 객체를 사용할지 어떻게 판단할 수 있을까?


다음의 함수를 써서, 어떤 프로그램을 사용할지 지정할 수 있다.


Program Object Usage

GLvoid glUseProgram(GLuint program)

program: The program name/id generated by the glCreateProgram function.


위 함수를 호출한 뒤, 나오는 모든 glDraw* 함수는 program 파라미터의 값(id)을 사용한다.


glBind* 함수들처럼 program id 0번은 opengl ES에서 예약되어 있다. 그래서 glUseProgram(0)처럼 인자로 0을 넘길 순 없다. 못한다. 하지 마라.


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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
GLuint createShader(GLenum type, const char **source)  
{
    GLuint name;
 
    // Creates a Shader Object and returns its name/id.
    name = glCreateShader(type);
 
    // Uploads the source to the Shader Object.
    glShaderSource(name, 1&source, NULL);
 
    // Compiles the Shader Object.
    glCompileShader(name);
 
    // If you are running in debug mode, query for info log.
    // DEBUG is a pre-processing Macro defined to the compiler.
    // Some languages could not has a similar to it.
#if defined(DEBUG)
 
    GLint logLength;
 
    // Instead use GL_INFO_LOG_LENGTH we could use COMPILE_STATUS.
    // I prefer to take the info log length, because it'll be 0 if the
    // shader was successful compiled. If we use COMPILE_STATUS
    // we will need to take info log length in case of a fail anyway.
    glGetShaderiv(name, GL_INFO_LOG_LENGTH, &logLength);
 
    if (logLength > 0)
    {
        // Allocates the necessary memory to retrieve the message.
        GLchar *log = (GLchar *)malloc(logLength);
 
        // Get the info log message.
        glGetShaderInfoLog(name, logLength, &logLength, log);
 
        // Shows the message in console.
        printf("%s",log);
 
        // Frees the allocated memory.
        free(log);
    }
#endif
 
    return name;
}
 
GLuint createProgram(GLuint vertexShader, GLuint fragmentShader)  
{
    GLuint name;
 
    // Creates the program name/index.
    name = glCreateProgram();
 
    // Will attach the fragment and vertex shaders to the program object.
    glAttachShader(name, vertexShader);
    glAttachShader(name, fragmentShader);
 
    // Will link the program into OpenGL's core.
    glLinkProgram(_name);
 
#if defined(DEBUG)
 
    GLint logLength;
 
    // This function is different than the shaders one.
    glGetProgramiv(name, GL_INFO_LOG_LENGTH, &logLength);
 
    if (logLength > 0)
    {
        GLchar *log = (GLchar *)malloc(logLength);
 
        // This function is different than the shaders one.
        glGetProgramInfoLog(name, logLength, &logLength, log);
 
        printf("%s",log);
 
        free(log);
    }
#endif
 
    return name;
}
 
void initProgramAndShaders()  
{
    const char *vshSource = "... Vertex Shader source using SL ...";
    const char *fshSource = "... Fragment Shader source using SL ...";
 
    GLuint vsh, fsh;
 
    vsh = createShader(GL_VERTEX_SHADER, &vshSource);
    fsh = createShader(GL_FRAGMENT_SHADER, &fshSource);
 
    _program = createProgram(vsh, fsh);
 
    // Clears the shaders objects.
    // In this case we can delete the shader because we
    // will not use they anymore and once compiled,
    // the OpenGL stores a copy of they into the program object.
    glDeleteShader(vsh);
    glDeleteShader(fsh);
 
    // Later you can use the _program variable to use this program.
    // If you are using an Object Oriented Programming is better make
    // the program variable an instance variable, otherwise is better make
    // it a static variable to reuse it in another functions.
    // glUseProgram(_program);
}
cs


나는 OpenGL ES 객체의 재사용성을 높이기 위해 기능을 최대한 분리했는데, 개발자는 OOP를 사용해 더 정교한 클래스를 생성할 수 있다.


출처 : All About OpenGL ES 2.X 번역

[OpenGL ES] 8. 쉐이더와 프로그램 vsh, fsh (shader, program)

댓글