목록Season 1/OpenGL (26)
Graphics Programming
OpenGL 처음 배울 때 glUniform()으로 일일이 값 설정하게 짜놓은 코드를 아직도 쓰고 있다. UBO를 쓸까 말까 고민만 하다 이제야 도입하고 있다. 1. DX11에서 constant buffer를 써보니 넘 편했다. 2. model-view transform, camera position 등 한 프레임에서 일정한 유니폼들은 한 번 설정해놓고 잊어버리는 게 편하고 코드 잘못 짤 가능성도 적어진다. 원래는 셰이더 프로그램마다 이런 유니폼들을 각자 선언하고 셰이더 바뀔 때마다 업데이트했다. 이런 유니폼들은 한 프레임에 한 번만 설정하면 전부 맞거나 전부 틀리니 디버깅도 쉽다. 그런데 막상 써보니 넘 구렸다. packed, shared, std140 등 여러 레이아웃이 있지만 오프셋은 아무튼 GL ..
포워드, 디퍼드 렌더링만 만들다가... PBR을 하려니 레이트레이싱을 알아야 하는 것 같아서 뒤늦게 코딩해보고 있다. 맨날 책에서 읽고 만들어야지 하다가 말았는데 겨우 첫 걸음을 떼었다. 요즘 너무 예제 코드를 그대로 치는 것 같아서 기억에만 의존해서 코딩을 해봤는데 다행히 성공했다. 완전히 빡대가리가 되지는 않았나 보다. 그래도 머리가 예전처럼 잘 안 돌아가는 걸 느낀다. 벌써 이러면 나중에 어떡하지... 화면의 각 픽셀에 대응하는 3D 점은 무수히 많다. 그런 점들 중 하나를 uv로부터 얻어내고 가상의 카메라 위치에서 이 점으로 광선을 쏜다. 광선과 구가 교차하는지 검사하고, 그렇다면 구의 방정식에서 P(위치), N(법선) 등을 얻을 수 있다. 이후 셰이딩은 포워드/디퍼드에서 하던 것과 동일하다. 구..
OpenGL 시작할 때는 화면에 뭘 그리는 거에 관심이 있었지 코어 프로필, GL 컨텍스트 생성, OS/벤더 확장이 뭔지 관심도 없었다. 그런 것들은 튜토리얼 따라하면서 freeglut, glew 등으로 대충 떼우고 기억 속에서 잊혀졌다. 빌드 환경, 프로그램 초기화 과정, 버전 관리가 중요하다는 걸 깨닫고 뒤늦게 신경쓰고 있다. DirectX 11, Vulkan을 디버깅할 때 RenderDoc를 유용하게 써서 OpenGL에도 써볼려고 했더니 나니? GL 4.6인데? 검색을 좀 해보니 freeglut에서 OpenGL 컨텍스트 버전과 프로필을 명시해야 하는 것 같다. // glutInit() 호출 후glutInitContextVersion(4, 3);glutInitContextProfile(GLUT_COR..
불칸 책을 다 읽고 뭔가를 만들려고 보니 코딩 분량이 너무 막막해서 예전에 버린 OpenGL 프로젝트를 다시 꺼내들었다.PBR을 조금 알아봤는데 계산만 복잡하지 기존의 블린-퐁 셰이딩과 구현 방법이 별로 다르지 않아서 이거나 해볼려고 했는데 프로젝트를 열어보니 DOF를 만들다 말았었다. DOF는 대략 이런 식으로 구현한다.1. 일단 장면을 그린다.2. 장면 텍스처의 subsum을 컴퓨트 셰이더로 계산한다.3. subsum을 가지고 박스 블러를 계산한다. 이 때 박스 블러의 세기는 각 픽셀의 깊이값을 가지고 결정한다. 뷰에 의존적인 이펙트여서 뷰 스페이스에서 픽셀의 z값을 가지고 계산해야 하는데 내 디퍼드 렌더러를 가만히 보니 라이팅 계산을 월드 스페이스에서 하고 있다. 다행히 추가로 바꿀 것은 별로 없었..
※ 이 글은 미완성입니다.※ 혼동의 여지가 있는 용어는 그대로 적었습니다. 실제 코드와 관련된 경우 영어 단어를 그대로 쓴 것도 있습니다. 목표: 절대로 다 번역하지 못한다. 쭉 훑어보면서 핵심만 번역하고 4.5와의 차이에 집중 OpenGL 4.6 Core: https://www.khronos.org/registry/OpenGL/specs/gl/glspec46.core.pdfGLSL 4.6: https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf OpenGL 4.6 Core 목차서문OpenGL 명세서의 서식OpenGL 그래픽스 시스템이란 무엇인가관련 API버그 리포트 작성OpenGL 기초실행 모델커맨드 신택스스테이트 설정 커맨드를 위한..
구 또는 원통형 물체에 양 끝이 이어지는 텍스처를 입힐 때, 샘플링의 래핑 모드를 GL_REPEAT로 하는 게 자연스럽다. 이러면 버텍스마다 uv 좌표가 0.0 ~ 1.0 사이가 아니라 계산 상의 문제로 0.2 ~ 1.2이여도 텍스처가 좀 옆으로 회전할 뿐 샘플링이 제대로 될...까? 애초에 버텍스의 uv 좌표가 이런 상태로 버텍스 셰이더 -> ... -> 프래그먼트 셰이더를 거치면 u = 1.2와 u = 0.4인 버텍스 사이의 픽셀들에서는 u가 선형 보간되어 1.2 -> 0.4로 변한다. 그러면 텍스처의 왼쪽 끝과 오른쪽 끝이 자연스레 이어지는 것이 아니라 중간 부분이 뒤집혀서 출력된다. 간단한 해결책은 uv를 프래그먼트 셰이더에서 직접 계산하는 것이다. 이러면 연산량이 더 많아지지만 내가 만들고 있는..
스켈레탈 애니메이션은 대충 본 계층도에 버텍스 스키닝을 한다는 정도로만 알고 있었는데, Frank D. Luna의 에서 개념과 구현 방법을 확실히 숙지하고, 코딩을 시작한 것이 아니라... 몇 주를 밍기적거리다 저번 주말에 구현했다. 일단 지금까지는 Wavefront OBJ 모델만 썼는데 OBJ 포맷은 뼈대도 애니메이션도 지원하지 않기 때문에 블렌더로 뼈대 애니메이션을 급조하고 DAE 포맷으로 익스포트했다. 예전에 모델 로더를 처음 만들 때만 해도 DAE 로더를 작성하려 했지만 무슨 이유에선가 OBJ 로더만 만들고 말았는데, 이번 기회에 Assimp 라이브러리를 이용해서 DAE 로더를 작성했다. 구현은 ogldev 튜토리얼을 참고했는데 내 경우는 기존 엔진에 버텍스 스키닝을 통합하려니 셰이더를 전부 손봐..
HDR은 forward/deferred rendering에 무관하게 기존 렌더링 파이프라인에 쉽게 끼워넣을 수 있는 테크닉이다. 일반적인 모니터는 RGB 채널 별로 256가지 강도만 표현할 수 있고 OpenGL의 기본 프레임버퍼(default framebuffer)도 마찬가지다. 기본 프레임버퍼에 출력할 때 프래그먼트 셰이더의 출력은 0.0에서 1.0 사이로 clamping된다. 따라서 여러 광원으로부터 빛을 받아 최종 셰이딩 값이 1.0을 넘어서는 부분은 모두 똑같이 하얀색으로 보인다. HDR은 최종 셰이딩한 색상을 기본 프레임버퍼에 기록하는 대신, 별도로 생성된 고해상도 부동소수점 프레임버퍼에 기록한다. 이 부동소수점 텍스처를 소스로 사용하여, 톤 매핑(tone mapping)한 결과를 기본 프레임버..