컴퓨터 그래픽스

2024.7.6(토) 6장 OpenGL ES와 쉐이더

새우급여기 2024. 7. 12. 05:53

OpenGL ES

  • 제공되는 API와 쉐이딩 언어 알아야 함.
  • 강의에서는 3.0 버전 이용

Shading Language

  • GPU 전용 언어
  • 행렬, 벡터 지원해주는 특별한 타입 O

→ vec4, ivec3, mat3, mat4 등

Vertex Shader

  1. Attributes: 위치와 같이 정점에 저장된 정점 별 데이터
  2. Uniforms: 월드 변환, 뷰 변환, 투영 변환과 같이 모든 정점마다 유니폼하게 적용되는 데이터

clip-space positionL 내장 변수에다 써 두기 = gl_Position

애트리뷰트가 m개인 경우, 각각의 위치는 0,1,2,…,m-1로 표기됨.

layout이라는 키워드를 사용해 position, normal, textCoord위치를 각각 0,1,2로 지정

layout(location = 0) in vec3 position;

layout(location = 1) in vec3 normal;

layout(location = 2) in vec2 texCoord;

out 키워드로 쉐이더가 출력할 v_normal과 v_texCoord 정의

out vec3 v_normal; out vec2 v_texCoord;

void main(){
    gl_Position = projMat * viewMat * worldMat * vec4(position, 1.0);
    v_normal = normalize(transpose(inverse(mat3(worldMat))) * normal);
    v_texCoord = texCoord;
}

메인 함수 - 오브젝트 공간에서 정의된 normal을 월드 공간으로 변환.

mat3(worldMat)은 월드 행렬의 왼쪽 위 3*3 부분 행렬을 말하는데, 이는 [L|t]로 표기된 월드 행렬 중 L을 의미한다. L의 역전치행렬이 normal에 곱해지고 정규화되어 출력 변수인 v_normal에 저장됨.

마지막 줄은 texCoord를 v_textCoord에 그대로 복사하는데, 총 세 개 출력 값(gl_Position, v_normal, v_texCoord)이 래스터라이저에게 전달됨.

GL 프로그램: 쉐이더 관리 & 쉐이더에 필요한 데이터 공급하는 역할.

함수는 gl로, 데이터는 GL로 시작함.

GLuint shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
  • 쉐이더 오브젝트 - glCreateShader가 생성. GL_VERTEX_SHADER 또는 GL_FRAGMENT_SHADER 입력 받아 쉐이더 오브젝트의 ID를 리턴함.
  • glShaderSource에 의해 쉐이더 오브젝트에 저장됨.
  • 쉐이더 오브젝트는 glCompileShader에 의해 컴파일 됨.
GLuint program = glCreateProgram();
glAttachShader(program, shader);
glLinkProgram(program);
glUseProgram(program);

정점 및 프래그먼트 쉐이더 오브젝트는 모두 프로그램 오브젝트에 붙여져야 한다.

애트리뷰트와 유니폼

stuct Vertex {
   glm::vec3 pos;
   glm::vec3 nor;
   glm::vec2 tex;
};
typedef GLushort Index;

struct ObjData {
   std::vector<Vertex> vertices;
   std::vector<Index> indices;
};

ObjData objData;
  • 정점의 위치(pos), 노멀(nor), 텍스처 좌표(tex)를 가짐
  • 여기서 사용된 glm은 OpenGL 수학 라이브러리
  • GLSL와 동일 이름, 기능 가진 클래스와 함수 제공
GLuint abo;
glGenBuffer(1, &abo);
glBindBuffer(GL_ARRAY_BUFFER, abo);
glBufferData(GL_ARRAY_BUFFER,
           (GLsizei) objData.vertices.size() * sizeof(Vertex),
            objData.vertices.data(), GL_STATIC_DRAW);
  • glGenBuffers(GLsizei n, GLunit* buffers) 호출해 버퍼 오브젝트 생성
  • GL_ARRAY_BUFFER를 파라미터로 glBindBuffer 호출해 버퍼 오브젝트를 정점 배열에 바인드함.
    CPU 메모리의 정점 및 인덱스 배열과 GPU 메모리의 버퍼 오브젝트

GPU 버퍼 오브젝트에 저장된 정점 애트리뷰트

pos, nor, tex 정점 애트리뷰트들이 배열 버퍼 오브젝트에 어떤 방식으로 저장되어 있는지 보여줌.

glEnableVertexAttribArray(0); // position = attribute 0
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
               sizeof(Vertex), (const GLvoid*) offsetof(Vertex, pos));
               
glEnableVertexAtrribArray(); // normal = attribute 1
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
               sizeof(Vertex), (const GLvoid*) offsetof(Vertex, nor));
               
glEnableBertexAttribArray(2); // texture coordinates = attribute 2
glVertexAttribPoint(2, 2, GL_FLOAT, GL_FALSE,
               sizeof(Vertex), (const GLvoid*) offsetof(Vertex, tex));

드로우콜

드로우콜: 폴리곤 메시를 그리는 명령을 내리는 것

  • glDrawArrays(GL_RIANGLES, 0, 144) 호출
  • glDrawElements 이용해 메시 그림.

 


이미지 출처

[OpenGL ES를 이용한 3차원 컴퓨터 그래픽스 입문]