Learn OpenGL
Shaders
- GPU에서 실행되는 작은 프로그램들
- 특징
- 위치: CPU가 아닌 GPU에서 실행
- 역할: 입력을 받아서 변환하여 출력으로 내보내는 변환 프로그램
- 격리성: shader들은 서로 직접 통신할 수 없고, 오직 입력과 출력을 통해서만 소통
- why GPU?: GPU는 병렬 처리에 특화되어있음
- 버텍스 데이터 -> [버텍스 셰이더] -> 기하학적 처리 -> [프래그먼트 셰이더] -> 픽셀 출력
GLSL
// 버전 선언, 사용할 OpenGL 버전 명시
#version 330 core
// 입력 변수(in)
in type aPos; // 위치 데이터
in type aColor; // 색상 데이터
// 출력 변수 (out)
out type out_variable_name; // 다음 셰이더로 전달할 데이터
// 유니폼
uniform type uniform_name; // CPU에서 전달받는 전역 변수
// 모든 처리 로직이 들어가는 main 함수
void main()
{
// 입력을 처리하고 그래픽 관련 작업 수행
...
// 처리된 결과를 출력 변수에 저장
out_variable_name = weird_stuff_we_processed;
}
- C언어와 차이점: 벡터/행렬 연산, 그래픽 전용 함수들, 내장 변수들
Types
- basic types: int, float, double, uint, bool
- container types: vectors, matrices
- float가 대부분의 목적에 충분하기 때문에 vecn을 사용함
Vectors
- 기본 접근 방법: vec.x -> .x, .y, .z, .w
- 다양한 접근 방식: 색상(rgba), 텍스처 좌표(stpq)
- swizzling: 벡터의 구성요소들을 재배열, 복제, 선택하여 새로운 벡터를 만드는 기법, ex) vec.xyxx
Ins and outs
- 개별 shader들에게 입력과 출력을 가져서 데이터를 주고받을 수 있기를 원함
- in ,out 키워드로 지정하고, 출력 변수가 다음 shader 스테이지의 입력 변수와 일치하면 데이터가 전달됨
vertext shader의 특별한 점
- 입력 데이터
- vertex data로 부터 직접 입력을 받음
- layout 지정자
- 어느 위치의 데이터를 받을지 알려주는 주소 표시
fragment shader의 특별한 점
- fragment shader는 vec4 색상 출력 변수가 필요함
- out 사용은 CPU 코드에서 프레임 버퍼 구성시 정암
Uniforms
- CPU에서 GPU로 데이터를 전달하는 전역 변수
- GPU 메모리에 한 번 전송함, constant cache 사용
- 너무 자주 업데이트, 너무 많으면 성능 문제 발생
- 선언은 했지만 사용하지 않으면 자동으로 제거됨
- OpenGL은 C 라이브러리이므로 함수 오버로딩을 지원하지 않음, 타입에 따른 접미사를 붙인 glUniform 함수들이 있음
More Attributes
- 캐시 효율성을 위해 인터리브드(Interleaved) 데이터를 사용함
- 메모리 접근 패턴에 의해 분리된 배열보다 효율이 좋음
- 타입에 무관한 메모리 주소를 가리키기 위해 (void*) 사용
Fragment Interpolation
- 과정
- vertex shader 실행
- primitive를 assemble
- rasterization이 일어나서 primitive에 해당하는 모든 픽셀을 결정하고, fragment shader 실행
- rasterization 전에 클리핑이 수행되어 뷰 밖에 있는 모든 프래그먼트를 버려서 성능 향상
- 보간 과정
- OpenGL이 해줌
- 기본적으로 Linear Interpolation
- GLSL에서 보간 방식을 제어할 수 있음