[GPU프로그래밍] 3. Working with GLSL Programs

jungizz_·2024년 4월 14일
0

GPU Programming

목록 보기
3/15
post-thumbnail

shader에 데이터 보내기

  1. vertex attributes(버텍스별로 달라지는 데이터)와 vertex buffer objects 사용
  2. uniform variables(한 장면 렌더링하는 동안 바뀌지 않는 데이터) 사용

1. Vertex attributes

  • vertex shader에서 각 vertex에 대한 input변수 정의 (per-vertex input)
    • GLSL qualifier를 사용하여 정의
    • ex) in vec3 VertexColor;
  • 데이터는 OpenGL Program에서 제공되어야 하며, Vertex Buffer Object를 통해 전달됨 (VBO에 vertex data가 저장)
  • Buffer와 Input attribute간의 연결 필요 (아래 코드)

📃 Triangle Rendering Example (p.5~8)

  • 들어온 Position 데이터를 그대로 내보내는 중
  • vertex shader의 output이 fragment shader의 input으로 사용 (무조건은 X)
  • 버퍼가 여러 개인 경우 fragment shader의 output이 여러 개일 수 있음 (p.21)
  • VAO: vertex array object
  • VBO: vertex buffer object
    • VAO는 VBO를 포함하며, VBO는 여러개일 수 있음
  1. VAO bind glBindVertexArray
  2. VBO bind 및 세팅 glBindBuffer
  3. binding된 VBO에 data loading glBufferData
  4. Vertex attribute 구성 glVertexAttribPointer
  5. VBO, VAO unbind
  6. Render loop (해당 VAO bind하여 draw) glBindVertexArray
👀 아래부터 위의 코드 부분부분 뜯어 정리한 것

◾ Vertex Attribute Data

  • 모든 vertex들의 vertex attribute(3D position, 3D normal, Color, ...)를 정의한 Array
  • ex) 삼각형의 three vertices의 3D position

◾ VBO (Vertex Buffer Object)

  • 많은 데이터(large batches)를 그래픽카드에 한꺼번에 전달하기 위해 Vertex Buffer를 사용
    • 많은 수의 vertex들을 GPU의 메모리에 저장해야하기 때문
  1. 각 attribute에 VBO 생성
  2. 새롭게 만든 버퍼를 원하는 버퍼 종류로 Bind
    • GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_TEXTURE_BUFFER, …
  3. Binding된 VBO에 데이터 넣기
    • 마지막 파라미터는 그래픽 카드가 주어진 데이터를 관리하는 방법(데이처를 어떻게 사용할건지)
      • GL_STATIC_DRAW: 버퍼에 올린 데이터를 바꿀 일이 거의 없을 때
      • GL_DYNAMIC_DRAW: 데이터가 자주 변경
      • GL_STREAM_DRAW: 데이터가 그려질때마다 변경 (가장 많이 바뀌는 경우) -> 그래픽 카드가 빠르게 쓸 수 있는 메모리에 데이터를 저장함
  4. VBO에 Vertex attribute configurations를 Linking하기
    • Vertex attribute configurations: VBO데이터를 어떻게(어떤 순서로) 사용할건지에 대한 규칙
      • vertex shader의 어떠한 정점 속성이 입력 데이터의 어느 부분과 맞는지 직접 지정해줘야해서 VBO 데이터를 어떻게 사용할건지 규칙을 정해줘야함
    • VBO에 데이터 하나씩 올리면서 Position(버텍스)들이 차례대로 들어가있는 상태
    • 버퍼에 저장된 데이터들을 순서대로 쓰는 경우도 있지만, 그렇지 않은 경우도 있다
      • ex) Position과 Color가 같이 저장된 형태의 한 VAO (보통 따로 버퍼 만들어서 사용함)
      • Position과 Color를 따로 쉐이더에 전달해줘야한다 (두 개의 Input)
        -> 어떤 순서로 데이터를 사용할건지 규칙을 알려줘야한다!
    • glVertexAttribPointer는 vertex attribute configuration 설정하고, VBO들을 vertex attribute들로 구성시킴
      • 각 vertex의 attribute는 VBO에 의헤 관리되는 메모리로부터 데이터를 받는데, 그 VBO는 이 함수를 호출하면서 현재 바인딩된 VBO로 결정됨
      • glEnableVertexAttribArray로 vertex attribute location을 전달하고 호출하여 사용할 수 있도록함
👀 현재까지는 vertex 데이터를 그래픽카드의 메모리에 저장한 상태, 이 메모리는 VBO가 관리하게된다.
  • (위에서 한 것처럼..) 한 VBO에서 데이터를 읽는 규칙을 수정하는 것은 번거롭다
  • 그래서, 규칙이 여러개인 경우에는 각 VAO에 규칙들 세팅해두고, 필요한 세팅을 가진 VAO를 binding하여 사용하면 간편하다! (편의성을 위해)

◾ VAO (Vertex Array Object)

  • VAO로 사용 규칙을 관리
    • 위의 상태 설정을 VAO에 저장하고, VAO를 바인딩하여 상태를 복원
      (VAO를 사용하지 않으면, 오브젝트를 그릴 때마다 위의 짓을 반복해야함)
    • VAO는 (3)데이터를 저장하는 것(4)데이터를 사용하는 방법이 분리되어있다
      -> VAO = VBO + VBO 사용 규칙
    • 아래 이미지는 각각 다른 사용 규칙을 가지는 VAO (한 VBO에 다른 규칙을 갖기도 함)
  • Core OpenGL은 VAO 사용 필수가 됨 (최신 버전은 필수)

  • 초기화 과정
    1. VAO 생성 및 Bind
    2. 그 상태에서 원하는 VBO를 Bind하고, attribute 를 구성
    3. VBO unbind하고 VAO를 나중에 사용하기 위해 VAO도 unbind
      -> VAO에 세팅 완료!
  • 드로잉 과정 (렌더링 루프 안)
    1. 그릴 오브젝트에 해당하는 VAO를 Bind한 후 draw
    • glDrawArray: VBO에 있는 데이터를 하나씩 읽으면서 그려줌
      -> 버텍스 중복이 생기는 경우 발생 (사각형을 두개의 삼각형으로 그릴 때) glDrawArray(GL_TRIANGLES, 0, 6)
      -> Element Array 사용
  • 위대로 하면 VAO의 attribute pointer 0에 규칙이 들어가고 활성화 됨
👀 추가 Attributes 예시 (p.18~20)

+) EBO (Element Buffer Object)

  • glDrawArray처럼 버텍스 버퍼의 데이터를 하나씩 읽으면서 그리는 것이 아닌, 인덱스 버퍼에서 인덱싱해서 그림 -> glDrawElements
    • 버텍스 중복을 방지하여 쓸데없이 버텍스가 더 많이 사용되지 않도록 함
  1. 첫번째 버퍼: 버텍스 정보 저장 (사각형)
  2. 두번째 버퍼: 인덱스 정보 저장 (삼각형 2개)
    • 겹쳐봤자 인덱스 번호만 겹침
    • 버퍼가 2개지만 버텍스 정보가 겹치는 것보단 중복량이 적음
  • Element array buffer 를 사용하여 EBO를 만들고, 인덱스 정보를 넘겨주어 오브젝트를 그린다
  • 복잡한 모델인 경우 glDrawElements를 사용하여 그리는 경우가 더 많다 (대부분 그렇다 ~..)
    • VAO는 EBO도 저장한다. VAO가 바인딩 되어있는 동안 EBO가 바인딩되면 VAO의 버퍼 객체로 저장된다.

2. Uniform Variables

  • 버텍스마다 달라지는 정보가 아닌 경우 -> 버텍스마다 보내줄 필요가 없음, 개별적으로 보내줌
    • 변환 Matrix, 라이트 정보 등..
  • Shader code 안에서는 변하지 않는 상수값 Input
  • unique per-shader program object
  • 아무 쉐이더에 input 변수로 보내줄 수 있음

📃 시간에 따라 G컬러가 달라지는 예제

  • OpenGL Application에서 넘겨줄 변수를 정의
  • 해당 Shader Program의 Shader code에 존재하는 Uniform 변수의 이름으로 위치(포인터) 찾음 glGetUniformLocation
  • 그 위치로 Uniform 변수를 Shader로 넘겨준다 glUniform데이터타입
  • Shader 코드에서는 unifrom을 사용해 Uniform 변수를 정의한다
  • OpenGL Application에서 넘겨준 변수값이 Uniform 변수에 들어간다

◾ glUnifrom 데이터 타입

  • f: float
  • i: int
  • ui: unsigned int
  • 3f: 3 floats
  • fv: float vector/array
profile
( •̀ .̫ •́ )✧

0개의 댓글