Graphics Programming

UBO 활용 본문

Season 1/OpenGL

UBO 활용

minseoklee 2018. 7. 14. 15:54

OpenGL 처음 배울 때 glUniform()으로 일일이 값 설정하게 짜놓은 코드를 아직도 쓰고 있다. UBO를 쓸까 말까 고민만 하다 이제야 도입하고 있다.


1. DX11에서 constant buffer를 써보니 넘 편했다.


2. model-view transform, camera position 등 한 프레임에서 일정한 유니폼들은 한 번 설정해놓고 잊어버리는 게 편하고 코드 잘못 짤 가능성도 적어진다. 원래는 셰이더 프로그램마다 이런 유니폼들을 각자 선언하고 셰이더 바뀔 때마다 업데이트했다. 이런 유니폼들은 한 프레임에 한 번만 설정하면 전부 맞거나 전부 틀리니 디버깅도 쉽다.


그런데 막상 써보니 넘 구렸다. packed, shared, std140 등 여러 레이아웃이 있지만 오프셋은 아무튼 GL 쪽이 정하는데 이게 되게 헷갈린다.


// in view space

layout (std140, binding = 0) uniform UBO_UnpackHDR {

vec3 eyeDirection;

vec3 eyePosition;

uint numDirLights;

vec3 dirLightDirs[MAX_DIRECTIONAL_LIGHTS];

vec3 dirLightColors[MAX_DIRECTIONAL_LIGHTS];

uint numPointLights;

vec3 pointLightPos[MAX_POINT_LIGHTS];

vec3 pointLightColors[MAX_POINT_LIGHTS];

} ubo;


vec3는 4N 워드 정렬이라 eyeDirection이 HLSL의 packoffset(c0), eyePosition이 packoffset(c1)에 해당하는 오프셋에 위치한다.


그러면 uint는 packoffset(c2.x)에 있나 싶었는데 packoffset(c1.w)에 있다.


그래서 numPointLights는 dirLightColors의 마지막 vec3의 w 성분에 들어가냐 하면, 그 다음 4N 워드 경계에서 시작한다.


이상한 레이아웃 규칙을 외우게 하지 말고 그냥 내가 packoffset을 지정할 수 있게 해달라고 -_-


struct UBO_UnpackHDR {

glm::vec3 eyeDirection; float __pad0;

glm::vec3 eyePosition; uint32_t numDirLights;

glm::vec4 dirLightDirs[MAX_DIRECTIONAL_LIGHTS]; // w components are not used

glm::vec4 dirLightColors[MAX_DIRECTIONAL_LIGHTS]; // w components are not used

uint32_t numPointLights; glm::vec3 __pad1;

glm::vec4 pointLightPos[MAX_POINT_LIGHTS]; // w components are not used

glm::vec4 pointLightColors[MAX_POINT_LIGHTS]; // w components are not used

};


UBO_UnpackHDR data;

data.eyeDirection = glm::vec3(camera->getViewMatrix() * glm::vec4(camera->getEyeVector(), 0.0f));

data.eyePosition = glm::vec3(camera->getViewMatrix() * glm::vec4(camera->getPosition(), 1.0f));

data.numDirLights = std::min(static_cast<uint32_t>(scene->directionalLights.size()), MAX_DIRECTIONAL_LIGHTS);

// ... 이하 생략


glBindBuffer(GL_UNIFORM_BUFFER, ubo_hdr);

glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(UBO_UnpackHDR), &data);

glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo_hdr);


레이아웃 맞추기는 홧병나지만 애플리케이션 측 구조체와 GL측 유니폼 블록의 레이아웃을 맞추고 나면 한방에 유니폼들을 밀어넣을 수 있다.


Comments