[컴퓨터 그래픽스] 6장 OpenGL ES 와 쉐이더

함지율·2024년 4월 14일

컴퓨터 그래픽스

목록 보기
3/5

OpenGL ES 와 쉐이더

Transforms (summarized)

이때까지 공부한 내용을 정리하면 다음과 같습니다. n개의 object가 있으면 n번의 world transform을 거칩니다. 그 후 view transform을 하고 해당 변환은 모든 objects에 동일하게 적용됩니다.

Vertex and Index Arrays (revisited)

position, normal, texture coordinates가 vertex array에 저장되어있습니다. GPU는 한번에 한 정점을 처리하게 됩니다. 이렇게 저장된 vertex array의 index 사용하여 polygon mesh를 이루게 됩니다. 이는 index array에 저장되어 삼각 메쉬면 3개의 점이 하나의 surface가 됩니다.

OpenGL ES and shading Languages

OpenGL ES 3.0 API를 사용합니다.
OpenGL ES를 간단히 'GL', OpenGL ES Shading Language는 'GLSL'로 약칭하겠습니다. GLSL은 C-like 언어입니다. 그리고 GPU 언어이기 때문에 여러 타입들이 있습니다. vec4는 4차원 벡터, 정수만으로 구성된 3차원 벡터는 ivec3라고 합니다. 그리고 행렬일 경우 mat3, mat4라고 할 수 있고 숫자를 하나만 쓰면 정사각 행렬을 뜻합니다. 만약에 직사각행렬일 경우 mat3x4라고 쓰고 float형입니다.

Vertex Shader

shader의 입력과 출력에 대해서 살펴보겠습니다.

  • Attributes

    per-vertex data마다 대표적으로 position, normal, texCoord 등이 저장되어있습니다.
  • Uniforms

    per-object data마다 모두 균등하게 적용된다라고 해서 uniform이라고 합니다. 예로 world matrix, view matrix, projection matrix 등이 있습니다.

이러한 정점들은 모든 변환을 거치고 clip space가 출력되는데, 이때 clip space position을 반드시 shader가 정리해서 출력해주어야합니다. 이를 gl_Position이라 하고 이는 반드시 출력해야하는 값이기에 명시적으로 그림에 표시되어 있습니다.


실제 코드로 살펴보겠습니다.

  1. uniform 특성이 첫번째 줄에 명시적으로 적혀있고 이는 4x4 matrix에 world, view, proj 변환이 적용된다는 뜻입니다.
  2. attributes가 입력(in)되는데 이때 position, normal, texCoord이 저장됩니다. texCoord는 2차원으로 저장됩니다. 그리고 출력(out)은 normal, texCoord를 출력합니다.
  3. 이제 첫번째 attribute position은 모든 변환을 거치고 gl_Position은 clip S position이 출력됩니다. 그리고 이때 vec4로 position이 주어지는데 이는 homogeneus 좌표계로 차원을 늘려 연산하기 위함입니다.
  4. normal은 이전에 공부했던 normalize(RT)normalize(R^{-T}) 를 적용하여 구할 수 있습니다.
  5. texCoord는 입력값 그대로를 copy하여 출력합니다.

GL Program

이제 vetex shader의 정의가 끝났습니다. 이제 fragment shader만 정의 해주면 GL 프로그램이 돌아가지만 아직 배우지 않았기에 일단 넘어가겠습니다.

  • GL commands의 prefix는 gl
  • GL data types의 prefix는 GL

로 약속하겠습니다.

GL Program - Shader Object

vertex shader를 파일로 저장해두었다면, 이제 shader object 를 만들어야합니다. 이는 glCreateSahder 를 통해 생성할 수 있습니다. 어떤 shader obeject를 만들지는 GL_VERTEX_SHADER, GL_FRAGMENT_SHADER를 선택할 수 있습니다. 어떤 쉐이 여기에 실제 shader를 저장해야하는데 이를 glShaderSource 이고 &source를 통해 저장된 쉐이더를 불러올 수 있습니다. 그 후 glCompileShader를 통해 compile합니다.

이렇게 fragment shader에도 동일하게 적용해주면 우리는 vertex shader와 fragment shader 두 객체를 얻을 수 잇습니다.

GL Program - Program Object

이제 program object를 통해 앞의 두 shader를 통합해주어야합니다. glCreateProgram을 통해 실제 program 객체를 생성하고 해당 프로그램에 shader를 붙여주어야하기에 glAttachShader 를 사용합니다. 그리고 fragment shader를 붙일려면 한번 더 호출해주면 됩니다. 모두다 attach가 되면 Link를 하고 사용하겠다는 Use 선언을 해주어야합니다.

Attributes

이제 attributes를 정의해보겠습니다. glm은 OpenGL Mathematics를 뜻합니다. Vertex와 index를 vertices와 indices 로 저장하여 최종 ObjData 객체를 만들었습니다.

렌더링을 GPU가 담당하기 때문에 CPU에 있는 ObjData를 GPU로 옮겨 주어야하고 이를 buffer object라고 합니다. vertex array는 GL_ARRAY_BUFFER를 통해 옮기고 index array는 GL_ELEMENT_ARRAY_BUFFER로 옮깁니다.

이제 어떤 이름을 통해 옮기는지 공부했으니 실제로 옮기는 코드를 확인해보겠습니다.
Gen을 통해 buffer를 1개 생성하고 bind를 통해 어떤 array buffer 인지 정의합니다. 그리고 buffer에 data를 제공하기에 vertices.data()를 통해 데이터를 전달합니다.

위는 vertex array이기에 아래는 index array 코드도 한번 보겠습니다.

공통점은 Generate -> Bind -> Data 로 기억하면 될 거 같습니다.


vertex shader는 아주 단순하고 무식하기 때문에 어떻게 읽어야할지 지침을 주어야합니다. position, normal, texCoord의 시작 위치는 어디인지, 다음 점은 어떤 것을 가져올지 정해주어야합니다. 이를 stride라고 합니다.

buffer object에 저장되어있는 vertex arrtributes입니다.

  1. glEnableVertexAttribArray(i) 를 통해 i번째에서 해당 속성이 시작함을 뜻합니다. 그리고 어떤 속성인지 position, normal, texture 를 지정해줄 수 있습니다.
  2. 그 후 glVertexAttribPointer를 통해 다음은 어디를 볼 지 stride를 지정해줄 수 있습니다. (0,3,GL_FLOAT)는 0번째에서 시작하며 3차원 원소이고 float형이라는 뜻입니다.
  3. 사이즈는 모두 동일하기 때문에 sizeof(Vertex)로 주어집니다. 그리고 offsetof(Vertex, pos)를 통해 stride를 줄 수 있습니다. stride는 sizeof(Vertex)입니다. 이유는 구조체의 크기만큼 볼테니 구조체의 크기인 sizeof(Vertex)가 stride입니다.

Uniforms

아래의 코드에서 uniform을 불렀는데 이거는 어떻게 설정할까요?

glGetUniformLocation을 호출하여 먼저 program의 worldMat 좌표를 찾아야합니다. world 행렬의 위치를 loc에 저장해두고 worldMat에 딱 넣어주어야하니 glUniformMatrix4fv를 통해 4x4 행렬로 지정해줍니다. world, view, projection 전부 이러한 방식으로 정의해주면 됩니다.

Drawcalls

이제 polygon mesh를 그리기 위해서는 명령을 해주어야합니다. 이를 drawcalls라고 합니다.

  • glDrawArrays는 non-indexed mesh를 표현합니다
  • glDrawElements는 indexed mesh를 표현합니다
    각 parameters는 아래와 같이 이루어져있습니다. 144개의 index가 있는 이유는 예로 48개의 triangle mesh가 있는 경우 48x3개의 index로 이루어져있기 때문에 144개의 파라미터를 갖습니다.

다음은 rasterizer에 대해서 살펴보겠습니다.


참고자료
고려대학교 정보대학 한정현 교수님 강의

profile
꿈 꾸는 디그다

0개의 댓글