<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Graphics Programming</title>
    <link>https://codeonwort.tistory.com/</link>
    <description>그래픽스 엔지니어의 블로그</description>
    <language>ko</language>
    <pubDate>Mon, 20 Jul 2026 19:30:58 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>minseoklee</managingEditor>
    <image>
      <title>Graphics Programming</title>
      <url>https://t1.daumcdn.net/cfile/tistory/2235FA48542842FD21</url>
      <link>https://codeonwort.tistory.com</link>
    </image>
    <item>
      <title>GPU 패스 트레이싱</title>
      <link>https://codeonwort.tistory.com/405</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;패스 트레이싱은 &lt;a href=&quot;https://github.com/codeonwort/Software-Raytracing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CPU 구현&lt;/a&gt;하던 것이 있지만 최근에 하드웨어 가속을 이용해 리얼타임 GPU 패스 트레이싱을 훌륭하게 구현한 사례가 계속 나오고 있고, 사이버펑크 2077의 경우 패스 트레이싱 모드를 출시한 것이 인상깊어서 나도 GPU 구현으로 갈아타기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히 DXR로 Ray Traced Reflections을, CPU로 패스 트레이싱을 구현했던 적이 있어서 DXR 프로젝트에 CPU 구현을 GPU로 포팅하는 것만으로 &lt;a href=&quot;https://github.com/codeonwort/Cyseal/pull/11&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;기초적인 GPU 패스 트레이싱을 구현&lt;/a&gt;할 수 있었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2023_04_25_diffuse_gi.jpg&quot; data-origin-width=&quot;1586&quot; data-origin-height=&quot;893&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vpHmO/btsczKyXcmL/1SPjxKgoOgkkGHAbvO1nCk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vpHmO/btsczKyXcmL/1SPjxKgoOgkkGHAbvO1nCk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vpHmO/btsczKyXcmL/1SPjxKgoOgkkGHAbvO1nCk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvpHmO%2FbtsczKyXcmL%2F1SPjxKgoOgkkGHAbvO1nCk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1586&quot; height=&quot;893&quot; data-filename=&quot;2023_04_25_diffuse_gi.jpg&quot; data-origin-width=&quot;1586&quot; data-origin-height=&quot;893&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 표면을 램버트로 강제하여 렌더링한 디퓨즈 글로벌 일루미네이션&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2023_04_25_microfacet_1.jpg&quot; data-origin-width=&quot;1586&quot; data-origin-height=&quot;893&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HWD2z/btscKnhsnsl/yg1vON4IXW5WZKFG8kSK9k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HWD2z/btscKnhsnsl/yg1vON4IXW5WZKFG8kSK9k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HWD2z/btscKnhsnsl/yg1vON4IXW5WZKFG8kSK9k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHWD2z%2FbtscKnhsnsl%2Fyg1vON4IXW5WZKFG8kSK9k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1586&quot; height=&quot;893&quot; data-filename=&quot;2023_04_25_microfacet_1.jpg&quot; data-origin-width=&quot;1586&quot; data-origin-height=&quot;893&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이크로파싯 BRDF를 구현해서 디퓨즈 + 스페큘러 리플렉션을 모두 커버하는 글로벌 일루미네이션&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;샘플 씬을 렌더링할 수 있을 정도로만 구현했기 때문에 앞으로 다른 샘플 씬들을 렌더링해보면서 빠진 구현을 채워나가야 한다. 디노이징도 해야 하는데, CPU 패스 트레이싱을 만들 때는 인텔의 oidn 라이브러리를 붙였었다. GPU에서는 어떤 디노이저를 가져다 붙일 수 있을지 찾아봐야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 CPU 구현에서 이 씬을 이 퀄리티로 그리려면 몇 시간이 걸릴텐데 GPU 구현은 1분 정도 기다리면 이렇게 나온다. 진작 GPU로 갈아탈 걸 그랬나 -_-;;&lt;/p&gt;</description>
      <category>Season 2</category>
      <author>minseoklee</author>
      <guid isPermaLink="true">https://codeonwort.tistory.com/405</guid>
      <comments>https://codeonwort.tistory.com/405#entry405comment</comments>
      <pubDate>Wed, 26 Apr 2023 00:24:37 +0900</pubDate>
    </item>
    <item>
      <title>Dear ImGui</title>
      <link>https://codeonwort.tistory.com/404</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;DX12 토이 프로젝트인 Cyseal에 &lt;a href=&quot;https://github.com/codeonwort/Cyseal/pull/9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dear ImGui를 붙여봤다&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;dear.jpg&quot; data-origin-width=&quot;1586&quot; data-origin-height=&quot;893&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4WyB8/btr3uETmYZ5/I7s3otfglEw6nPwkfaQQLk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4WyB8/btr3uETmYZ5/I7s3otfglEw6nPwkfaQQLk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4WyB8/btr3uETmYZ5/I7s3otfglEw6nPwkfaQQLk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4WyB8%2Fbtr3uETmYZ5%2FI7s3otfglEw6nPwkfaQQLk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1586&quot; height=&quot;893&quot; data-filename=&quot;dear.jpg&quot; data-origin-width=&quot;1586&quot; data-origin-height=&quot;893&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dear ImGui는 렌더링 테크데모, 게임 엔진 등의 분야에서 &lt;a href=&quot;https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;많이 쓰이는&lt;/a&gt; imgui 라이브러리다. 이전 회사에서 같이 일했던 선임 엔지니어 분이 간단한 엔진 툴을 만들 때 써봤는데 매우 직관적이고 사용하기 편리하다고 추천하셨던 기억이 난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나도 Dear ImGui에 편승하기로 했다. 듣던 대로 통합하기도 쉽고 사용법도 간단했다. 내 프로젝트에서 Vulkan 백엔드가 제대로 돌지 않고 있기 때문에 일단은 imgui의 win32 + dx12 백엔드 부분만 통합했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 그려보니 글자가 살짝 흐릿하고 마우스 히트 테스트가 어긋나는 문제가 있었는데, 내가 swapchain 이미지들의 크기를 윈도우 client rect와 정확히 일치시키지 않아서였다. win32 윈도우를 생성할 때 지정하는 크기는 윈도우 전체의 크기고 타이틀 바, 테두리 등을 뺀 client rect는 좀 더 작다. Cyseal은 윈도우 리사이즈 이벤트를 받아서 스왑체인 이미지를 재생성하는데, 이때는 client rect를 제대로 반영하므로 리사이즈 후에는 이 문제들이 해결된다. 윈도우 크기를 조절해보고 이 문제인 것을 깨달았다. 내 OpenGL 프로젝트에도 똑같은 문제가 발생할 것 같은데 여기서는 제대로 처리를 해놨는지 나중에 살펴봐야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 특정 렌더 패스만 토글한다던가 하는 옵션을 GUI로 컨트롤할 수 있게 되었다. 통합 난이도를 보아하니 OpenGL 프로젝트에도 Dear ImGui를 그냥 붙이면 잘 동작할 거 같지만, GUI 직접 코딩해놓은 것 버리기 싫어서 아마 Dear ImGui는 안 붙일 듯...&lt;/p&gt;</description>
      <category>Season 2</category>
      <author>minseoklee</author>
      <guid isPermaLink="true">https://codeonwort.tistory.com/404</guid>
      <comments>https://codeonwort.tistory.com/404#entry404comment</comments>
      <pubDate>Sun, 12 Mar 2023 20:27:12 +0900</pubDate>
    </item>
    <item>
      <title>Managed code와 C# 으로 이주하기</title>
      <link>https://codeonwort.tistory.com/403</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래밍을 플래시 액션스크립트로 처음 배웠으니 내 뿌리는 managed code가 맞지만, C++가 주력 언어가 된 후에는 학교에서 공부할 때도 회사에서 일할 때도 C++만 쓰게 되었다. 액션스크립트만큼은 개인적으로 계속 사용했지만 어도비가 플래시를 버린 이후에는 나도 쓰지 않게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전 기억을 잠시 되살려보면 플래시 런타임의 본질은 JVM을 얇게 감싼 것이고 액션스크립트 초기 문법은 자바스크립트에서 가져온 것이다. 그래서 액션스크립트를 깊게 파다 보니 자연스럽게 자바와 자바스크립트도 배우게 되었다. 액션스크립트의 마지막 버전인 3.0에 와서는 오히려 자바를 닮아갔는데, 그러다보니 클래스 기반 상속과 프로토타입 기반 상속이 공존하는 해괴한 언어가 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쨌든 이런 VM 위에서 돌아가는 코드를 직접 만져본 지도, C# 책을 잠깐 거들떠라도 본 것도 10년이 넘은 일이다. 그런데 새로 다닐 직장에서 C#을 쓰기 때문에 C#을 배워야 하는 상황이 되었다. C#을 진지하게 써본 경험이 전무해서 바닥부터 배워야 하는 처지인데, &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/csharp/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MSDN의 C# 가이드&lt;/a&gt;를 pdf로 익스포트해보니 2800쪽 분량이다. 하루에 100쪽씩 읽어도 한 달이 걸리는데 그렇게 부지런히 읽을 것 같지도 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 프로그램을 만들어보며 문법은 그때 그때 찾아보는 걸로 방향을 수정하고, 렌더링 업무 할건데 C#으로도 하나 만들어볼까 생각했지만 효율이 좋지 않아보였다. Rust로 볼륨 렌더링을 구현하다가 이거 그냥 C++로 짜고 말지 하면서 방치한 걸 생각해보면, C# 이어야 할 수 있는 목표가 필요했다. 알고리즘 문제들을 풀어보는 것도 아주 기초적인 문법과 콘솔 입출력 빠르게 하는 것만 알게 될 테니 이것도 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러다 &lt;a href=&quot;https://github.com/codeonwort/Software-Raytracing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;소프트웨어 레이트레이싱&lt;/a&gt; 프로젝트에 GUI를 붙이면 좋겠다는 생각이 들었고, C++/C# interop도 연습해볼 거리가 될 것 같아서 C#으로 GUI을 붙이는 작업에 착수했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레이트레이서의 기존 코드는 모듈 하나에 모든 코드가 엉켜있었다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;레이트레이싱을 구현하는 로직&lt;/li&gt;
&lt;li&gt;터미널을 통해 렌더링 옵션을 설정하거나 렌더링을 수행하는 Read-Eval-Print 루프 로직&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 별도 모듈(raylib)을 만들어 레이트레이싱 구현을 모두 옮기고 dll로 컴파일했다. 원래 모듈(cui-app)에는 터미널 Read-Eval-Print 로직만 남겼다. raylib이 extern &quot;C&quot;를 붙인, C-compatible API를 익스포트해야 C#에서 임포트해서 사용할 수 있으므로, 그에 앞서 cui-app에서도 C-compatible API만 활용하여 raylib을 호출할 수 있도록 리팩토링을 했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;gui-app.jpg&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;542&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkljCi/btrU5572G6q/FdKdPdWWrC328i6Lo9Ein1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkljCi/btrU5572G6q/FdKdPdWWrC328i6Lo9Ein1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkljCi/btrU5572G6q/FdKdPdWWrC328i6Lo9Ein1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkljCi%2FbtrU5572G6q%2FFdKdPdWWrC328i6Lo9Ein1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1004&quot; height=&quot;542&quot; data-filename=&quot;gui-app.jpg&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;542&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음은 C# WinForm 프로젝트를 만들어 raylib.dll wrapper 클래스를 만들고 cui-app에서 터미널을 통해 컨트롤하던 것들을 gui를 통해 컨트롤하게 만든다. C#의 기본적인 문법은 자바나 액션스크립트와 크게 다르지 않아서 간단한 GUI 정도는 MSDN을 참고해가며 빠르게 만들 수 있었다. 문제는 C++ 자잘한 문법들을 평소에 숙지하고 다니는 만큼 C# 문법도 익히는 건데, 지금 MSDN 주루룩 읽는다고 외울 수 있는 것도 아니고 실제로 써보며 익숙해져야 할 것 같다.&lt;/p&gt;</description>
      <category>Season 2</category>
      <author>minseoklee</author>
      <guid isPermaLink="true">https://codeonwort.tistory.com/403</guid>
      <comments>https://codeonwort.tistory.com/403#entry403comment</comments>
      <pubDate>Tue, 3 Jan 2023 01:48:41 +0900</pubDate>
    </item>
    <item>
      <title>간만에 다시 꺼내든 CPU 레이트레이싱</title>
      <link>https://codeonwort.tistory.com/402</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://codeonwort.tistory.com/386&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://codeonwort.tistory.com/386&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1670702904977&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Ray Tracing: The Next Week&quot; data-og-description=&quot;https://codeonwort.tistory.com/364 1부를 3년 전에 구현했는데 이제서야 2부를 읽고 있다. 맨날 놀다가 질리면 사이드 프로젝트들 중 하나를 골라서 잠깐 하는 것을 반복하니 영 진도가 안 나간다. 모션 &quot; data-og-host=&quot;codeonwort.tistory.com&quot; data-og-source-url=&quot;https://codeonwort.tistory.com/386&quot; data-og-url=&quot;https://codeonwort.tistory.com/386&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/d1migk/hyQRUfp7EW/AKUAR5oSH8UluEJkAodnUK/img.jpg?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/s4PV6/hyQRQc1l38/KIc0ThOzb7R5zsaXSrF6K1/img.jpg?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/F44sE/hyQRMn9lai/SbZKZVSuB60jex6EVS7UXk/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512&quot;&gt;&lt;a href=&quot;https://codeonwort.tistory.com/386&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://codeonwort.tistory.com/386&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/d1migk/hyQRUfp7EW/AKUAR5oSH8UluEJkAodnUK/img.jpg?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/s4PV6/hyQRQc1l38/KIc0ThOzb7R5zsaXSrF6K1/img.jpg?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/F44sE/hyQRMn9lai/SbZKZVSuB60jex6EVS7UXk/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Ray Tracing: The Next Week&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;https://codeonwort.tistory.com/364 1부를 3년 전에 구현했는데 이제서야 2부를 읽고 있다. 맨날 놀다가 질리면 사이드 프로젝트들 중 하나를 골라서 잠깐 하는 것을 반복하니 영 진도가 안 나간다. 모션&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;codeonwort.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이거 이후로 한동안 방치하다가 또 조금씩 깨작거리고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기가바이트 단위의 렌더링 리서치용 애셋들은 있지만 한 장 그릴 때마다 몇십 분씩 기다리기도 싫고 해서 또다시 &lt;a href=&quot;https://casual-effects.com/g3d/data10/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;McGuire&lt;/a&gt;의 간단한 Wavefront OBJ 모델들을 긁어와서 렌더링을 돌려보고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;test-cornell-box.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cD1v0E/btrTmYOglRv/75O79MEOKsPx7rkMPu2941/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cD1v0E/btrTmYOglRv/75O79MEOKsPx7rkMPu2941/img.jpg&quot; data-alt=&quot;Cornell Box&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cD1v0E/btrTmYOglRv/75O79MEOKsPx7rkMPu2941/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcD1v0E%2FbtrTmYOglRv%2F75O79MEOKsPx7rkMPu2941%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;512&quot; data-filename=&quot;test-cornell-box.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Cornell Box&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;test-breakfast-room.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4KWAU/btrThk6pxIq/0msmh4nCKZsTWPKdDTNSv0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4KWAU/btrThk6pxIq/0msmh4nCKZsTWPKdDTNSv0/img.jpg&quot; data-alt=&quot;Breakfast Room&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4KWAU/btrThk6pxIq/0msmh4nCKZsTWPKdDTNSv0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4KWAU%2FbtrThk6pxIq%2F0msmh4nCKZsTWPKdDTNSv0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;512&quot; data-filename=&quot;test-breakfast-room.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Breakfast Room&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;test-dabrovic-sponza.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dq7IW7/btrTifwFQeN/rz9smeqsK7l3CMa7O1sLF0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dq7IW7/btrTifwFQeN/rz9smeqsK7l3CMa7O1sLF0/img.jpg&quot; data-alt=&quot;Dabrovic Sponza&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dq7IW7/btrTifwFQeN/rz9smeqsK7l3CMa7O1sLF0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdq7IW7%2FbtrTifwFQeN%2Frz9smeqsK7l3CMa7O1sLF0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;512&quot; data-filename=&quot;test-dabrovic-sponza.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Dabrovic Sponza&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;test-fireplace-room.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kSJ2m/btrThldcC9X/aFYhcp5zfKjUx9RfMp7rm1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kSJ2m/btrThldcC9X/aFYhcp5zfKjUx9RfMp7rm1/img.jpg&quot; data-alt=&quot;Fireplace Room&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kSJ2m/btrThldcC9X/aFYhcp5zfKjUx9RfMp7rm1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkSJ2m%2FbtrThldcC9X%2FaFYhcp5zfKjUx9RfMp7rm1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;512&quot; data-filename=&quot;test-fireplace-room.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Fireplace Room&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Wavefront OBJ 포맷 자체가 별로 잘 정의되어 있지 않아서 일단 렌더링을 해보고 결과가 이상하면 OBJ 파싱 또는 렌더링 로직을 고치고 있다. 끝까지 다 렌더링하려면 워낙 오래 걸리니 디버그 시각화용 모드를 따로 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;test-breakfast-room-debug.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d1zFre/btrThzJelJC/uA3VsTkMnvgQbSfdI1JVGK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d1zFre/btrThzJelJC/uA3VsTkMnvgQbSfdI1JVGK/img.jpg&quot; data-alt=&quot;OBJ 파싱 디버깅을 위해 만든 vertex normal 시각화 모드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d1zFre/btrThzJelJC/uA3VsTkMnvgQbSfdI1JVGK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd1zFre%2FbtrThzJelJC%2FuA3VsTkMnvgQbSfdI1JVGK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;512&quot; data-filename=&quot;test-breakfast-room-debug.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;OBJ 파싱 디버깅을 위해 만든 vertex normal 시각화 모드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Breakfast Room과 Fireplace Room는 아직 global illumination을 제대로 구현하지 않은 내 OpenGL 프로젝트에서의 렌더링과 비교하면 꽤나 그럴 듯한 결과물이 나온다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 254px;&quot; border=&quot;0&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2022-12-11-05-25-50_shot0.jpg&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9mDks/btrThG9eOjW/rhT0rk8ALFVDEnpb23HUbk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9mDks/btrThG9eOjW/rhT0rk8ALFVDEnpb23HUbk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9mDks/btrThG9eOjW/rhT0rk8ALFVDEnpb23HUbk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9mDks%2FbtrThG9eOjW%2FrhT0rk8ALFVDEnpb23HUbk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;960&quot; height=&quot;540&quot; data-filename=&quot;2022-12-11-05-25-50_shot0.jpg&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2022-12-11-05-26-17_shot0.jpg&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKiYRL/btrTiU6VSJr/dRqyjL7icXMTzRP4RcaIAK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKiYRL/btrTiU6VSJr/dRqyjL7icXMTzRP4RcaIAK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKiYRL/btrTiU6VSJr/dRqyjL7icXMTzRP4RcaIAK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKiYRL%2FbtrTiU6VSJr%2FdRqyjL7icXMTzRP4RcaIAK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;960&quot; height=&quot;540&quot; data-filename=&quot;2022-12-11-05-26-17_shot0.jpg&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OpenGL 엔진에는 아직도 unoccluded sky IBL 밖에 없다. Scene capture 기능을 구현할 때 메인 카메라가 아닌 임의의 시점에서 장면 렌더링한 것을 별도 텍스처에 그릴 수 있게 아키텍처는 만들어놓았기 때문에, 라이트 프로브를 쭉 깔고 프로브의 시점에서 대충 6번 그려서 radiance 프로브를 생성하고, 필터링해서 irradiance 만들고 하면 되는데 귀찮...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU 레이트레이싱의 다음 작업으로는 디노이징을 생각하고 있다. 디노이징이 어떻게 작동하는지 전혀 모르기 때문에 이건 서드파티 라이브러리의 힘을 빌려야겠다. 언리얼 엔진의 패스 트레이싱 모드에서 &lt;a href=&quot;https://github.com/OpenImageDenoise/oidn&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;인텔의 디노이저&lt;/a&gt;를 쓰는 것을 본 기억이 있어서 다시 방문해보니 빌드만 된다면 통합하기는 아주 쉽겠다. 노이즈 있는 이미지만 필수 입력으로 넣으면 되고, 옵션으로 albedo, normal 입력을 넣어서 디노이징 퀄리티를 향상시킬 수 있는데 마침 디버그 모드의 일환으로 구현했던 것들이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;---&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[2022/12/15] 인텔 OpenImageDenoise 를 붙여봤는데 빌드에 통합하기도 쉽고 디노이징이 상당히 깔끔하게 된다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 209px;&quot; border=&quot;0&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 209px;&quot;&gt;
&lt;td style=&quot;width: 412.5px; height: 209px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;test-fireplace-room.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kSJ2m/btrThldcC9X/aFYhcp5zfKjUx9RfMp7rm1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kSJ2m/btrThldcC9X/aFYhcp5zfKjUx9RfMp7rm1/img.jpg&quot; data-alt=&quot;Fireplace Room (path tracing result)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kSJ2m/btrThldcC9X/aFYhcp5zfKjUx9RfMp7rm1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkSJ2m%2FbtrThldcC9X%2FaFYhcp5zfKjUx9RfMp7rm1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;512&quot; data-filename=&quot;test-fireplace-room.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Fireplace Room (path tracing result)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 412.5px; height: 209px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;test-fireplace-room-denoise.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RsH1k/btrTFJRxbr0/Plqf9R9ZRqEwjmatMpDng0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RsH1k/btrTFJRxbr0/Plqf9R9ZRqEwjmatMpDng0/img.jpg&quot; data-alt=&quot;Fireplace Room (denoised)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RsH1k/btrTFJRxbr0/Plqf9R9ZRqEwjmatMpDng0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRsH1k%2FbtrTFJRxbr0%2FPlqf9R9ZRqEwjmatMpDng0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;512&quot; data-filename=&quot;test-fireplace-room-denoise.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Fireplace Room (denoised)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;0&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;test-dabrovic-sponza-highres.jpg&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccPBlb/btrTGQqS84l/Al7IUhKFAQTxaGZ6abk441/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccPBlb/btrTGQqS84l/Al7IUhKFAQTxaGZ6abk441/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccPBlb/btrTGQqS84l/Al7IUhKFAQTxaGZ6abk441/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccPBlb%2FbtrTGQqS84l%2FAl7IUhKFAQTxaGZ6abk441%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;1080&quot; data-filename=&quot;test-dabrovic-sponza-highres.jpg&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;test-dabrovic-sponza-highres-denoised.jpg&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwhlvo/btrTKljnf3o/DrdlDLKkxnpLBUNm6fDPh1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwhlvo/btrTKljnf3o/DrdlDLKkxnpLBUNm6fDPh1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwhlvo/btrTKljnf3o/DrdlDLKkxnpLBUNm6fDPh1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdwhlvo%2FbtrTKljnf3o%2FDrdlDLKkxnpLBUNm6fDPh1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;1080&quot; data-filename=&quot;test-dabrovic-sponza-highres-denoised.jpg&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;0&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;test_LivingRoom.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6r8uq/btrTR1c5etx/rW5Cc3PKKvAanojSij4kV1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6r8uq/btrTR1c5etx/rW5Cc3PKKvAanojSij4kV1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6r8uq/btrTR1c5etx/rW5Cc3PKKvAanojSij4kV1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6r8uq%2FbtrTR1c5etx%2FrW5Cc3PKKvAanojSij4kV1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;512&quot; data-filename=&quot;test_LivingRoom.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;test_LivingRoom_2.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZleUG/btrTP4WAeOC/1mgBkhKiPtr5DLFtmqafc0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZleUG/btrTP4WAeOC/1mgBkhKiPtr5DLFtmqafc0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZleUG/btrTP4WAeOC/1mgBkhKiPtr5DLFtmqafc0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZleUG%2FbtrTP4WAeOC%2F1mgBkhKiPtr5DLFtmqafc0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;512&quot; data-filename=&quot;test_LivingRoom_2.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;test_SanMiguel_highres_2.jpg&quot; data-origin-width=&quot;2560&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blUkFW/btrT9Fuputg/E4L9wohTlIkTAt2Rq8sguK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blUkFW/btrT9Fuputg/E4L9wohTlIkTAt2Rq8sguK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blUkFW/btrT9Fuputg/E4L9wohTlIkTAt2Rq8sguK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblUkFW%2FbtrT9Fuputg%2FE4L9wohTlIkTAt2Rq8sguK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2560&quot; height=&quot;1440&quot; data-filename=&quot;test_SanMiguel_highres_2.jpg&quot; data-origin-width=&quot;2560&quot; data-origin-height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 렌더링하던 noisy image, albedo, normal 이미지를 float3로 덤프해서 디노이저에 넣으면 결과가 나온다. 역시 머신 러닝이 미래인가? 머신 러닝은 언제 해보나...&lt;/p&gt;</description>
      <category>Season 2</category>
      <author>minseoklee</author>
      <guid isPermaLink="true">https://codeonwort.tistory.com/402</guid>
      <comments>https://codeonwort.tistory.com/402#entry402comment</comments>
      <pubDate>Sun, 11 Dec 2022 05:45:10 +0900</pubDate>
    </item>
    <item>
      <title>DXR 첫걸음</title>
      <link>https://codeonwort.tistory.com/401</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;DirectX 12, RTX 그래픽카드, 하드웨어 레이트레이싱 가속 등이 처음으로 거론되던 시절에 레포지토리를 파놓고 4년 간 방치하다 이제서야 DXR 코딩을 시작했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;RTR.jpg&quot; data-origin-width=&quot;1586&quot; data-origin-height=&quot;893&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ynDrT/btrRicowihx/XPk0IIFyuvfkIVGk4U0sOk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ynDrT/btrRicowihx/XPk0IIFyuvfkIVGk4U0sOk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ynDrT/btrRicowihx/XPk0IIFyuvfkIVGk4U0sOk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FynDrT%2FbtrRicowihx%2FXPk0IIFyuvfkIVGk4U0sOk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1586&quot; height=&quot;893&quot; data-filename=&quot;RTR.jpg&quot; data-origin-width=&quot;1586&quot; data-origin-height=&quot;893&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음으로 뭘 구현할까 고민하다 간접 스페큘러 리플렉션을 선택했다. 리얼타임 렌더링에서 래스터와 레이트레이싱을 섞어 쓰는 하이브리드 렌더링을 할 때 흔히 레이트레이싱으로는 RT Shadow, RTAO, RTGI(Diffuse GI), RTR(Specular GI) 등을 구현하는데 경험상 처음 3개는 레이트레이싱으로 인해 증가하는 비용에 비해 극적인 차이를 낸다고는 느끼지 못했다. 반면 RTR은 SSR + 리플렉션 큐브맵에서 아쉬웠던 문제점들을 깔끔히 해결한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트를 워낙에 방치했던 터여서 RTR 구현에 앞서 여러가지 선행작업이 필요했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 버텍스/인덱스 버퍼로부터 메시별 suballocation 및 버퍼 오프셋 저장&lt;/li&gt;
&lt;li&gt;머티리얼 SRV와 CBV의 bindless 메커니즘&lt;/li&gt;
&lt;li&gt;컴퓨트 파이프라인 추상화&lt;/li&gt;
&lt;li&gt;컴퓨트 셰이더를 통한 gpu scene 관리&lt;/li&gt;
&lt;li&gt;간단한 forward shading + thin gbuffer 출력&lt;/li&gt;
&lt;li&gt;FXC &amp;rarr; DXC 으로 컴파일러 변경&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 DXR 코딩에는 &lt;a href=&quot;https://github.com/microsoft/DirectX-Graphics-Samples&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;마이크로소프트의 DXR 샘플&lt;/a&gt; 들이 큰 도움이 되었다. 메시 지오메트리들을 긁어모아 BLAS, TLAS, RTPSO 등등을 생성하고 closest hit 셰이더에서 표면의 한 점에 대응하는 전역 버텍스/인덱스 버퍼, bindless CBV/SRV, gpu scene 정보를 읽어서 머티리얼 정보를 재구성하고 셰이딩에 반영한다. 셰이딩 계산은 대충 짰는데 또 Cook-Torrance 모델을 코딩하기는 지루하고 다른 셰이딩 모델을 시도해볼 생각이다. NPR을 시도해봐도 재밌을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 RTR 효과가 더 잘 드러나게 데모 씬을 가다듬고, 구현하는 과정에서 엉망이 된 추상화 레이어를 리팩토링해야 한다. 특히나 셰이더 리소스들을 관리하기 위한 래퍼 클래스들이 너무 엉망이여서 어떻게 정리할지 고민이다.&lt;/p&gt;</description>
      <category>Season 2</category>
      <author>minseoklee</author>
      <guid isPermaLink="true">https://codeonwort.tistory.com/401</guid>
      <comments>https://codeonwort.tistory.com/401#entry401comment</comments>
      <pubDate>Wed, 16 Nov 2022 01:46:49 +0900</pubDate>
    </item>
    <item>
      <title>github.io로의 이전?</title>
      <link>https://codeonwort.tistory.com/400</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최근에 티스토리 서비스가 한동안 먹통이 되는 사고가 발생한 후에 내 블로그 기록을 잃을 수도 있겠다는 생각이 들었다. 그렇다고 집에서 설치형 블로그를 직접 호스팅할 생각까지는 없어서, 백업 및 복구가 편리한 플랫폼을 찾아보다 &lt;a href=&quot;https://codeonwort.github.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github.io&lt;/a&gt;에 정착하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다들 github.io를 Hugo나 Jekyll 같은 정적 사이트 생성기와 함께 쓰는 모양이지만 이것저것 세팅하기도 귀찮아서 베어본 HTML과 마크다운만으로 글을 쓰는 단순한 환경을 구축했다. Notepad++에서 마크다운으로 글을 쓰면 HTML 파일이 자동 생성되게 만들고, 그렇게 생성된 포스트들을 index.html에 링크한다. 글 원본이 마크다운 포맷이므로 컨텐츠 손상될 일 없이 백업할 수 있고 혹여나 다른 플랫폼으로 옮기게 될 경우 HTML 생성과 스타일시트 적용만 다시 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다고 지금의 티스토리 블로그를 완전히 버리지는 않을 것 같고, 티스토리는 계속 일기장처럼 쓰고 github.io는 테크니컬 라이팅에 집중한 형태가 될 것 같다. 티스토리에 글을 쓸 때는 뭔가를 구현하면 기술적인 세부사항을 적는 대신 무엇무엇을 만들어봤다는 식으로만 적었는데, 그런 기술적인 내용은 이미 원본 스펙이나 컨퍼런스 발표자료에 잘 정리되어 있어서 내가 사족을 덧붙일 필요가 없다고 느꼈기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 서적, GDC, SIGGRAPH 같은 '공신력 있는' 자료도 시간이 지남에 따라 낡은 정보가 되거나 구현 디테일을 생략했거나 단순히 오타 등으로 인해 내용이 틀린 경우가 있어서, github.io에는 내 프로그래밍 경험을 기술적으로 정확하게 서술하는 글을 쓰게 될 것 같다. 일단은 FSR1 통합했던 경험을 &lt;span&gt;첫번째 글로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;써봤고, 티스토리도 딱히 열심히 쓰지 않았는데 -_-; 앞으로도 글을 활발하게 쓸지는 모르겠다. 깃헙 프로 구매한 것이 아까워서라도 github.io는 조금 더 열심히 쓰지 않을까...&lt;/p&gt;</description>
      <category>Season 2</category>
      <author>minseoklee</author>
      <guid isPermaLink="true">https://codeonwort.tistory.com/400</guid>
      <comments>https://codeonwort.tistory.com/400#entry400comment</comments>
      <pubDate>Thu, 10 Nov 2022 16:51:31 +0900</pubDate>
    </item>
    <item>
      <title>렌더링 챌린지 일지 2</title>
      <link>https://codeonwort.tistory.com/398</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://codeonwort.tistory.com/381&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;렌더링 챌린지 일지 1&lt;/a&gt; 을 작성한 것이 벌써 2년 전이다. 이 데모 씬(이하 RC1)를 내버려두고 다른 렌더링 테크닉만 구현해왔는데, 마무리를 짓고 다른 챌린지 월드를 만들어야겠다 싶어서 손질에 들어갔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 258px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style16&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 241px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 241px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2020.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1SjSZ/btrQrrmeZPn/47x9T6vLJrFzptgu5YOq20/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1SjSZ/btrQrrmeZPn/47x9T6vLJrFzptgu5YOq20/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1SjSZ/btrQrrmeZPn/47x9T6vLJrFzptgu5YOq20/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1SjSZ%2FbtrQrrmeZPn%2F47x9T6vLJrFzptgu5YOq20%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1922&quot; height=&quot;1112&quot; data-filename=&quot;2020.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 241px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2022.jpg&quot; data-origin-width=&quot;2560&quot; data-origin-height=&quot;1392&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hg6w5/btrQq4kwSbj/PWCwaiLbrPbqocWoxe0AYk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hg6w5/btrQq4kwSbj/PWCwaiLbrPbqocWoxe0AYk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hg6w5/btrQq4kwSbj/PWCwaiLbrPbqocWoxe0AYk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHg6w5%2FbtrQq4kwSbj%2FPWCwaiLbrPbqocWoxe0AYk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2560&quot; height=&quot;1392&quot; data-filename=&quot;2022.jpg&quot; data-origin-width=&quot;2560&quot; data-origin-height=&quot;1392&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;리워크 중간 결과물&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 최근에 작성한 일지인 &lt;a href=&quot;https://codeonwort.tistory.com/396&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AMD FSR1 통합&lt;/a&gt; 이후로 GLTF 로더, TAA 구현, 톤 매퍼 변경(Reinhard &amp;rarr; ACES), CPU 프로파일러 개선, SSR 개선 등의 작업을 했고, 그 이후 RC1 손질을 시작했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;타워 모델&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;guard_tower_before.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czqOiK/btrQq30d08b/2yDEQKL9TDj0mjJE8AiyGk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czqOiK/btrQq30d08b/2yDEQKL9TDj0mjJE8AiyGk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czqOiK/btrQq30d08b/2yDEQKL9TDj0mjJE8AiyGk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczqOiK%2FbtrQq30d08b%2F2yDEQKL9TDj0mjJE8AiyGk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1922&quot; height=&quot;1112&quot; data-filename=&quot;guard_tower_before.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;guard_tower_after.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cU4cfK/btrQqKs2Rr8/P1qa1cwOnksilIZYKSLXJ1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cU4cfK/btrQqKs2Rr8/P1qa1cwOnksilIZYKSLXJ1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cU4cfK/btrQqKs2Rr8/P1qa1cwOnksilIZYKSLXJ1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcU4cfK%2FbtrQqKs2Rr8%2FP1qa1cwOnksilIZYKSLXJ1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1922&quot; height=&quot;1112&quot; data-filename=&quot;guard_tower_after.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벽돌 텍스처를 바르기 위해 triplanar mapping을 썼는데 노멀맵 계산이 틀려서 라이팅이 이상했었다. &lt;a href=&quot;https://developer.nvidia.com/gpugems/gpugems3/part-i-geometry/chapter-1-generating-complex-procedural-terrains-using-gpu&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GPU Gems 3 - Generating Complex Procedural Terrains Using the GPU&lt;/a&gt; 을 참고해서 고쳤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;번개 이펙트&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;lightning_before.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D4Dbf/btrQqIWinFe/J0aZWkhkYa5FkwaKtqWjA1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D4Dbf/btrQqIWinFe/J0aZWkhkYa5FkwaKtqWjA1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D4Dbf/btrQqIWinFe/J0aZWkhkYa5FkwaKtqWjA1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD4Dbf%2FbtrQqIWinFe%2FJ0aZWkhkYa5FkwaKtqWjA1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1922&quot; height=&quot;1112&quot; data-filename=&quot;lightning_before.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;lightning_after.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/M0jBB/btrQrFq0jlc/pBvcxYWeXhlka72YjAks5k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/M0jBB/btrQrFq0jlc/pBvcxYWeXhlka72YjAks5k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/M0jBB/btrQrFq0jlc/pBvcxYWeXhlka72YjAks5k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FM0jBB%2FbtrQrFq0jlc%2FpBvcxYWeXhlka72YjAks5k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1922&quot; height=&quot;1112&quot; data-filename=&quot;lightning_after.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 그럴듯하게 만들었다. 더 역동적으로 만들고 싶었지만 내가 테크니컬 아티스트가 아니라는 핑계로 이 정도에서 타협했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;볼류메트릭 클라우드&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;cloud_before_1.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sZvAw/btrQqJnpIjR/0StYKsAvnh0Mjy3GBqFpkk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sZvAw/btrQqJnpIjR/0StYKsAvnh0Mjy3GBqFpkk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sZvAw/btrQqJnpIjR/0StYKsAvnh0Mjy3GBqFpkk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsZvAw%2FbtrQqJnpIjR%2F0StYKsAvnh0Mjy3GBqFpkk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1922&quot; height=&quot;1112&quot; data-filename=&quot;cloud_before_1.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;cloud_before_2.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TV1Pd/btrQqL6BSRZ/WWCRkoNxrQbRQ08uYg5G7K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TV1Pd/btrQqL6BSRZ/WWCRkoNxrQbRQ08uYg5G7K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TV1Pd/btrQqL6BSRZ/WWCRkoNxrQbRQ08uYg5G7K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTV1Pd%2FbtrQqL6BSRZ%2FWWCRkoNxrQbRQ08uYg5G7K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1922&quot; height=&quot;1112&quot; data-filename=&quot;cloud_before_2.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;cloud_before_3.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdt1IV/btrQqLrXPSa/jB1Seylio03d0BKKIfLTd0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdt1IV/btrQqLrXPSa/jB1Seylio03d0BKKIfLTd0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdt1IV/btrQqLrXPSa/jB1Seylio03d0BKKIfLTd0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbdt1IV%2FbtrQqLrXPSa%2FjB1Seylio03d0BKKIfLTd0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1922&quot; height=&quot;1112&quot; data-filename=&quot;cloud_before_3.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2년 전에 어떻게 구름처럼 보이게는 만들었지만 사실 weather map, cloud coverage, cloud type, density gradient, shape noise, erosion noise 등 다양한 구성요소가 의도대로 조합되어서 구름 모양을 형성해야 하는데 전혀 그렇지 못했다. 예를 들어 weather map에서 cloud coverage가 높은 부분만 구름이 보이고, shape noise는 구름의 덩어리 모양을 결정하고, erosion noise는 작은 디테일만 더하는 역할을 해야 하는데 렌더링 결과물은 그렇지 않았다. 과거의 작업물은 여기저기 매직 넘버를 끼워넣어서 구름 모양이 나오게 했을 뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 지금 보니 이전 작업물도 나름의 아트 스타일이 있다. 새로운 렌더링 결과물이 코드는 더 올바르게 되었지만 비주얼이 '개선' 되었다고 말할 수 있을지 모르겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;cloud_after_1.jpg&quot; data-origin-width=&quot;2560&quot; data-origin-height=&quot;1369&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hl9g5/btrQqjo0clf/n6GpLKsoxkdjTpVi2nb1tk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hl9g5/btrQqjo0clf/n6GpLKsoxkdjTpVi2nb1tk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hl9g5/btrQqjo0clf/n6GpLKsoxkdjTpVi2nb1tk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHl9g5%2FbtrQqjo0clf%2Fn6GpLKsoxkdjTpVi2nb1tk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2560&quot; height=&quot;1369&quot; data-filename=&quot;cloud_after_1.jpg&quot; data-origin-width=&quot;2560&quot; data-origin-height=&quot;1369&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;cloud_after_2.jpg&quot; data-origin-width=&quot;2560&quot; data-origin-height=&quot;1392&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkYori/btrQqMEqKig/Fz1CO9n7eFXpwmBFP73H5K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkYori/btrQqMEqKig/Fz1CO9n7eFXpwmBFP73H5K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkYori/btrQqMEqKig/Fz1CO9n7eFXpwmBFP73H5K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkYori%2FbtrQqMEqKig%2FFz1CO9n7eFXpwmBFP73H5K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2560&quot; height=&quot;1392&quot; data-filename=&quot;cloud_after_2.jpg&quot; data-origin-width=&quot;2560&quot; data-origin-height=&quot;1392&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;cloud_after_3.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUTSZY/btrQqKzQyfE/xAlh0wPjXVBkseya88ZERk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUTSZY/btrQqKzQyfE/xAlh0wPjXVBkseya88ZERk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUTSZY/btrQqKzQyfE/xAlh0wPjXVBkseya88ZERk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUTSZY%2FbtrQqKzQyfE%2FxAlh0wPjXVBkseya88ZERk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1922&quot; height=&quot;1112&quot; data-filename=&quot;cloud_after_3.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 그런 것들을 모두 고쳐서 의도대로 작동하게 만들고 있다. 매직 넘버들을 최대한 걷어내고, 렌더링 퀄리티를 높이기 위해 추가 테크닉들을 도입했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Adaptive ray marching: 예전에는 레이 마칭 거리가 일정한 uniform ray marching을 썼다. 이제는 길게 전진(coarse march)하다가 구름을 만나면 짧게 전진(fine march)하고, 그러다 구름 영역을 벗어나면 다시 coarse march로 돌아간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Banding artifact: before 이미지 중 가운데 이미지에서 두드러지는 것처럼, 가로로 층이 난 것처럼 보이는 결함이 있었는데 &lt;a href=&quot;https://github.com/NVIDIAGameWorks/SpatiotemporalBlueNoiseSDK&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;엔비디아 STBN&lt;/a&gt;을 이용해 레이 마칭 시작 위치를 흔드는 것만으로 해결되었다. 노이즈를 줬음에도 지글거림이 느껴지지 않아서 조금 놀라웠다. 이 노이즈 라이브러리는 다음에 jittering이 필요할 일이 생기면 또 써봐야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구름에서 남은 작업은 레이 마칭을 더 개선하는 것과 볼륨 렌더링용 temporal reprojection을 구현하는 것이다. 마칭 횟수는 호라이즌 제로 던처럼 54 ~ 96번을 목표로 잡았지만, coarse march &amp;rarr; fine march &amp;rarr; coarse march를 하게 되면 이미 마칭 횟수가 별로 남아있지 않아 다음 구름까지 가지 못하고 마칭이 종료된다. 위 이미지들은 레이 마칭 횟수를 임의로 200~400번으로 크게 높여서 찍은 것이고, 원래 목표한 횟수인 54~96번으로도 화면 끝의 구름까지 마칭이 되려면 아직 조율을 더 해야 한다. 그리고 TAA에서 reprojection을 이미 구현해봤지만 이전 프레임에서 버텍스 위치를 정확하게 알 수 있고 벨로시티 버퍼를 자명하게 생성할 수 있는 TAA와 달리 볼류메트릭에서는 구름의 한 지점이 이전 프레임에 어디에 있었는지를 도출하는 것이 애매하다. 지상에서 하늘을 바라보는 거면 구름이 스카이박스처럼 무한히 멀다고 가정하고 reprojection을 하면 되겠지만, RC1은 구름이 초근접거리에 있어서 그런 가정을 할 수 없다. &lt;a href=&quot;https://jcgt.org/published/0010/03/02/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Fast temporal reprojection without motion vectors&lt;/a&gt; 에서 제시하는 솔루션이 내 상황에 딱이긴 한데 논문을 훑어보니 메모리를 너무 많이 쓴다. 화면 해상도와 같은 텍스처가 적어도 25장 필요한데 딸랑 reprojection에 메모리를 그만큼 태우기는 죠금 -_-;; 어쨌든 reprojection 안하면 렌더링 비용이 너무 크니 어떻게든 구현할 방법을 고민해봐야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스카이 박스 &lt;/b&gt;(TODO)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;galaxy.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcFfsO/btrQqlfY92u/lDb4vpWhWIdDHpDTQDuimk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcFfsO/btrQqlfY92u/lDb4vpWhWIdDHpDTQDuimk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcFfsO/btrQqlfY92u/lDb4vpWhWIdDHpDTQDuimk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcFfsO%2FbtrQqlfY92u%2FlDb4vpWhWIdDHpDTQDuimk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1922&quot; height=&quot;1112&quot; data-filename=&quot;galaxy.jpg&quot; data-origin-width=&quot;1922&quot; data-origin-height=&quot;1112&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배경 텍스처는 아직 아무 작업도 못했다. 셰이더토이에서 galaxy, nebula 등으로 검색해서 예쁜 것들을 적당히 조합하려고 했는데 대부분 2D용 셰이더이고, 파노라마 형태로 억지로 늘려서 천구에 덮으면 이쁘지도 않고 타일링도 안 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;galaxy_wip.jpg&quot; data-origin-width=&quot;1647&quot; data-origin-height=&quot;532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFWTug/btrQrFR7OK1/fVk2B3gWPqSfuQVSkkjxu0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFWTug/btrQrFR7OK1/fVk2B3gWPqSfuQVSkkjxu0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFWTug/btrQrFR7OK1/fVk2B3gWPqSfuQVSkkjxu0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFWTug%2FbtrQrFR7OK1%2FfVk2B3gWPqSfuQVSkkjxu0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1647&quot; height=&quot;532&quot; data-filename=&quot;galaxy_wip.jpg&quot; data-origin-width=&quot;1647&quot; data-origin-height=&quot;532&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘 알지도 못하는 서브스탠스 디자이너로 똥꼬쇼를 해보고 있기는 한데 만족할 만한 스카이 박스가 나올 지는 모르겠다. 다만 지금은 equirectangular map 형태로 만들어서 sphere에 프로젝션하고 있는데, 지상에서 지평선 위주로 바라볼 때나 적절한 방법이지 RC1처럼 아무 방향으로나 둘러보는 상황이면 텍스처 늘어지는게 너무 눈에 띄어서 큐브맵 텍스처로 익스포트해야 할 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 손에 잡기까지 2년이나 걸렸는데 또 한눈 팔기 전에 RC1을 후딱 끝내야겠다. 사실 이미 compute shader 기반 테셀레이션에 한눈을 파는 중이다.&lt;/p&gt;</description>
      <category>Season 2</category>
      <author>minseoklee</author>
      <guid isPermaLink="true">https://codeonwort.tistory.com/398</guid>
      <comments>https://codeonwort.tistory.com/398#entry398comment</comments>
      <pubDate>Sat, 5 Nov 2022 04:06:23 +0900</pubDate>
    </item>
    <item>
      <title>CUDA를 시작하며</title>
      <link>https://codeonwort.tistory.com/397</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;CUDA &lt;a href=&quot;https://github.com/codeonwort/cuda-study&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;공부&lt;/a&gt;를 시작했다. 레퍼런스로는 마침 올해 개정판이 나온 &quot;&lt;a href=&quot;https://www.elsevier.com/books/programming-massively-parallel-processors/hwu/978-0-323-91231-0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Programming Massively Parallel Processors&lt;/a&gt;&quot; 4판을 쓰고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제 코드를 몇 개 따라해보니 그래픽스 API에서 컴퓨트 셰이더를 쓰는 것과 모델이 크게 다르지 않다. 호스트(CPU+RAM)에서 디바이스(GPU+VRAM)로 데이터를 업로드하고 커널을 실행한다. 실행 결과를 다시 호스트 메모리로 가져온다. 그래픽스 API에서 셰이더 리소스 바인딩 &amp;rarr; 컴퓨트 셰이더 실행 &amp;rarr; CPU readback하는 것에 그대로 대응된다. 산술 연산과 메모리 액세스의 비율, 블록 사이즈, 레지스터 등을 고려한 최적화는 GPU 프로파일러를 돌려서 occupancy, VGPR, VMEM/VDATA throughput 등을 따지는 것에 대응된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CUDA라는 모델을 통해 GPU를 다시 보니 신선하고, GPGPU를 하기 위한 셋업은 CUDA가 더 간소하고 편리하다. 일단은 책에 나오는 예시 알고리즘들을 따라만들어보고 있는데 그 후에 무엇을 할지는 정하지 못했다. 3D 그래픽스에 관련된 것이라면 기존에 익숙하게 쓰던 OpenGL/Vulkan/DirectX를 계속 쓸 것 같고... 항상 그래픽스에 우선순위가 밀리던 머신 러닝을 마침내 CUDA와 함께 시작하게 될 지도 모르겠다.&lt;/p&gt;</description>
      <category>Season 2</category>
      <author>minseoklee</author>
      <guid isPermaLink="true">https://codeonwort.tistory.com/397</guid>
      <comments>https://codeonwort.tistory.com/397#entry397comment</comments>
      <pubDate>Sat, 8 Oct 2022 02:45:50 +0900</pubDate>
    </item>
    <item>
      <title>AMD FSR1 통합</title>
      <link>https://codeonwort.tistory.com/396</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/codeonwort/pathosengine/pull/33&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;OpenGL 프로젝트&lt;/a&gt;에 AMD FSR1을 붙여봤다. 원래는 FSR2를 붙이고 싶었지만 벨로시티 버퍼, TAA 등을 먼저 구현해야 FSR2를 붙일 수 있어서 현 상황에서 바로 붙일 수 있는 FSR1을 작업해봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FSR1 &lt;a href=&quot;https://gpuopen.com/fidelityfx-superresolution/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;홈페이지&lt;/a&gt;에 있는 가이드 문서를 보고 그대로 따라하니 금방 끝낼 수 있었다. DX12, DX11, Vulkan를 지원한다고 쓰여있지만 어차피 FSR1 셰이더 자체는 GLSL로도 컴파일 가능하도록 작성되어 있어서 OpenGL에 붙이는데 큰 문제는 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageslideblock alignCenter&quot; data-image=&quot;[{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/vN96J/btrNFSOKWH7/AV14jkxG0RUYdZvtB66yXK/img.jpg&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/ck6ohJ/btrNDUsxBlB/ZFS0hKkm16tebNKG9hNN50/img.jpg&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/bzmtDK/btrNNfIwKPY/GwVmIRyw02sPSoKfrR0C90/img.jpg&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/lEu2O/btrNM3VOmjX/ICPWBCydUJBzY4InRCLKa0/img.jpg&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/bbjuGM/btrNLBSP9e5/kKyZ4GklZSEFMg4qV3qlB1/img.jpg&amp;quot;}]&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span class=&quot;image-wrap selected&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vN96J/btrNFSOKWH7/AV14jkxG0RUYdZvtB66yXK/img.jpg&quot; data-url=&quot;https://blog.kakaocdn.net/dn/vN96J/btrNFSOKWH7/AV14jkxG0RUYdZvtB66yXK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vN96J/btrNFSOKWH7/AV14jkxG0RUYdZvtB66yXK/img.jpg&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvN96J%2FbtrNFSOKWH7%2FAV14jkxG0RUYdZvtB66yXK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; data-origin-width=&quot;2003&quot; data-origin-height=&quot;1127&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ck6ohJ/btrNDUsxBlB/ZFS0hKkm16tebNKG9hNN50/img.jpg&quot; data-url=&quot;https://blog.kakaocdn.net/dn/ck6ohJ/btrNDUsxBlB/ZFS0hKkm16tebNKG9hNN50/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ck6ohJ/btrNDUsxBlB/ZFS0hKkm16tebNKG9hNN50/img.jpg&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fck6ohJ%2FbtrNDUsxBlB%2FZFS0hKkm16tebNKG9hNN50%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; data-origin-width=&quot;2003&quot; data-origin-height=&quot;1127&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzmtDK/btrNNfIwKPY/GwVmIRyw02sPSoKfrR0C90/img.jpg&quot; data-url=&quot;https://blog.kakaocdn.net/dn/bzmtDK/btrNNfIwKPY/GwVmIRyw02sPSoKfrR0C90/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzmtDK/btrNNfIwKPY/GwVmIRyw02sPSoKfrR0C90/img.jpg&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzmtDK%2FbtrNNfIwKPY%2FGwVmIRyw02sPSoKfrR0C90%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; data-origin-width=&quot;2003&quot; data-origin-height=&quot;1127&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lEu2O/btrNM3VOmjX/ICPWBCydUJBzY4InRCLKa0/img.jpg&quot; data-url=&quot;https://blog.kakaocdn.net/dn/lEu2O/btrNM3VOmjX/ICPWBCydUJBzY4InRCLKa0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lEu2O/btrNM3VOmjX/ICPWBCydUJBzY4InRCLKa0/img.jpg&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlEu2O%2FbtrNM3VOmjX%2FICPWBCydUJBzY4InRCLKa0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; data-origin-width=&quot;2003&quot; data-origin-height=&quot;1127&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbjuGM/btrNLBSP9e5/kKyZ4GklZSEFMg4qV3qlB1/img.jpg&quot; data-url=&quot;https://blog.kakaocdn.net/dn/bbjuGM/btrNLBSP9e5/kKyZ4GklZSEFMg4qV3qlB1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbjuGM/btrNLBSP9e5/kKyZ4GklZSEFMg4qV3qlB1/img.jpg&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbjuGM%2FbtrNLBSP9e5%2FkKyZ4GklZSEFMg4qV3qlB1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; data-origin-width=&quot;2003&quot; data-origin-height=&quot;1127&quot;/&gt;&lt;/span&gt;&lt;button class=&quot;btn btn-prev&quot;&gt;&lt;span class=&quot;ico-prev&quot;&gt;이전&lt;/span&gt;&lt;/button&gt;&lt;button class=&quot;btn btn-next&quot;&gt;&lt;span class=&quot;ico-next&quot;&gt;다음&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;
  &lt;div class=&quot;mark&quot;&gt;&lt;span data-index=&quot;0&quot;&gt;0&lt;/span&gt;&lt;span data-index=&quot;1&quot;&gt;1&lt;/span&gt;&lt;span data-index=&quot;2&quot;&gt;2&lt;/span&gt;&lt;span data-index=&quot;3&quot;&gt;3&lt;/span&gt;&lt;span data-index=&quot;4&quot;&gt;4&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;클로즈 샷&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageslideblock alignCenter&quot; data-image=&quot;[{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/z1hfl/btrNEwE10fz/eaBASBdb81iEPTQGKjPKeK/img.jpg&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/QPDkW/btrNEv7deOB/R3pV4eFgi12x7DVzjO9PXK/img.jpg&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/c3L5o9/btrNKVDZtZu/89kNKgkkDInAXB847fxZt1/img.jpg&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/kTxvg/btrNJBMxfo8/T2681cTKNiho72MEmpX1e0/img.jpg&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/01ycg/btrNMG7t7je/WwXWzDdTSwSsQEovKd4RoK/img.jpg&amp;quot;}]&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span class=&quot;image-wrap selected&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z1hfl/btrNEwE10fz/eaBASBdb81iEPTQGKjPKeK/img.jpg&quot; data-url=&quot;https://blog.kakaocdn.net/dn/z1hfl/btrNEwE10fz/eaBASBdb81iEPTQGKjPKeK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z1hfl/btrNEwE10fz/eaBASBdb81iEPTQGKjPKeK/img.jpg&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz1hfl%2FbtrNEwE10fz%2FeaBASBdb81iEPTQGKjPKeK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; data-origin-width=&quot;2003&quot; data-origin-height=&quot;1127&quot; data-is-animation=&quot;false&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QPDkW/btrNEv7deOB/R3pV4eFgi12x7DVzjO9PXK/img.jpg&quot; data-url=&quot;https://blog.kakaocdn.net/dn/QPDkW/btrNEv7deOB/R3pV4eFgi12x7DVzjO9PXK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QPDkW/btrNEv7deOB/R3pV4eFgi12x7DVzjO9PXK/img.jpg&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQPDkW%2FbtrNEv7deOB%2FR3pV4eFgi12x7DVzjO9PXK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; data-origin-width=&quot;2003&quot; data-origin-height=&quot;1127&quot; data-is-animation=&quot;false&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3L5o9/btrNKVDZtZu/89kNKgkkDInAXB847fxZt1/img.jpg&quot; data-url=&quot;https://blog.kakaocdn.net/dn/c3L5o9/btrNKVDZtZu/89kNKgkkDInAXB847fxZt1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3L5o9/btrNKVDZtZu/89kNKgkkDInAXB847fxZt1/img.jpg&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3L5o9%2FbtrNKVDZtZu%2F89kNKgkkDInAXB847fxZt1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; data-origin-width=&quot;2003&quot; data-origin-height=&quot;1127&quot; data-is-animation=&quot;false&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kTxvg/btrNJBMxfo8/T2681cTKNiho72MEmpX1e0/img.jpg&quot; data-url=&quot;https://blog.kakaocdn.net/dn/kTxvg/btrNJBMxfo8/T2681cTKNiho72MEmpX1e0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kTxvg/btrNJBMxfo8/T2681cTKNiho72MEmpX1e0/img.jpg&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkTxvg%2FbtrNJBMxfo8%2FT2681cTKNiho72MEmpX1e0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; data-origin-width=&quot;2003&quot; data-origin-height=&quot;1127&quot; data-is-animation=&quot;false&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/01ycg/btrNMG7t7je/WwXWzDdTSwSsQEovKd4RoK/img.jpg&quot; data-url=&quot;https://blog.kakaocdn.net/dn/01ycg/btrNMG7t7je/WwXWzDdTSwSsQEovKd4RoK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/01ycg/btrNMG7t7je/WwXWzDdTSwSsQEovKd4RoK/img.jpg&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F01ycg%2FbtrNMG7t7je%2FWwXWzDdTSwSsQEovKd4RoK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; data-origin-width=&quot;2003&quot; data-origin-height=&quot;1127&quot; data-is-animation=&quot;false&quot;/&gt;&lt;/span&gt;&lt;button class=&quot;btn btn-prev&quot;&gt;&lt;span class=&quot;ico-prev&quot;&gt;이전&lt;/span&gt;&lt;/button&gt;&lt;button class=&quot;btn btn-next&quot;&gt;&lt;span class=&quot;ico-next&quot;&gt;다음&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;
  &lt;div class=&quot;mark&quot;&gt;&lt;span data-index=&quot;0&quot;&gt;0&lt;/span&gt;&lt;span data-index=&quot;1&quot;&gt;1&lt;/span&gt;&lt;span data-index=&quot;2&quot;&gt;2&lt;/span&gt;&lt;span data-index=&quot;3&quot;&gt;3&lt;/span&gt;&lt;span data-index=&quot;4&quot;&gt;4&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;롱 샷&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 여러 렌더 패스가 실행되고 있는 엔진에 FSR1을 붙이려니 다음 사항들을 고려해야 했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;렌더 타겟들을 화면 해상도와 무관한 것(shadowmap), FSR1 이전의 해상도를 가지는 것(gbuffer, sceneColor, sceneDepth 등), FSR1 이후의 해상도를 가지는 것(sceneColorUpscaled, sceneColorFinal, DoF 등)으로 명확히 구분하고, screen uv나 texel coord를 계산할 때는 관련 렌더 타겟의 사이즈를 제대로 고려했는지 점검해야 했다.&lt;/li&gt;
&lt;li&gt;FSR1을 사용한다면 FSR1 이후의 패스들은 모두 업스케일된 해상도를 가진다. 따라서 그런 패스에서 sceneDepth, gbuffers 등 다운스케일된 텍스처들을 샘플링할 일이 있으면 더 이상 텍셀 매칭이 안 된다. 다행히 내 경우에는 실행 순서를 따져보니 그런 샘플링이 필요한 패스들은 모두 FSR1 이전에 실행되어서 문제가 없었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FSR1은 FP16 모드와 FP32 fallback 모드가 있는데 FP16 모드를 사용하려면 GL 확장인 GL_EXT_shader_16bit_storage 와 GL_EXT_shader_explicit_arithmetic_types 이 필요하다. 어째선지 최신 그래픽카드인 RTX 3080 Ti 의 OpenGL 드라이버에서도 해당 확장들을 지원하지 않아서 FP16 모드는 컴파일이 되지 않았다. 일단은 FP32 모드로만 작동하게 만들고, 추가 조사를 해보니 &lt;span&gt;GL_EXT_shader_16bit_storage&lt;span&gt; 에서 정의하는 &lt;/span&gt;&lt;/span&gt;16비트 자료형들은 GL_NV_gpu_shader5 확장으로 대체 가능하고 &lt;span&gt;GL_EXT_shader_explicit_arithmetic_types&lt;span&gt; 에서 정의하는 &lt;/span&gt;&lt;/span&gt;형변환 함수들은 딱히 대체재를 못 찾아서 직접 정의했다. 수정 내역은 &lt;a href=&quot;https://github.com/codeonwort/pathosengine/commit/79fe01467786e60d349ab9c428526e60fc4275a7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이 커밋&lt;/a&gt;에서 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 환경이 여의치 않아서 테스트하지 못한 것들도 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FSR1에 넣을 입력 이미지는 안티앨리어싱이 잘 되어있어야 하는데 지금은 옵션이 FXAA 밖에 없어서 TAA보다 입력 이미지의 퀄리티가 떨어진다.&lt;/li&gt;
&lt;li&gt;가이드 문서는 FSR1에 넣을 입력 이미지를 생성할 때 Negative MIP bias 적용을 권장한다. 텍스처를 잔뜩 바른 멋진 데모 씬이 있어야 퀄리티 비교를 해볼 텐데 내 데모 씬들이 다 조악해서 굳이 확인해보지 않았다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Season 2</category>
      <category>FSR1</category>
      <category>OpenGL</category>
      <author>minseoklee</author>
      <guid isPermaLink="true">https://codeonwort.tistory.com/396</guid>
      <comments>https://codeonwort.tistory.com/396#entry396comment</comments>
      <pubDate>Tue, 4 Oct 2022 16:30:07 +0900</pubDate>
    </item>
    <item>
      <title>렌더링 일지 - 스크린샷 기능</title>
      <link>https://codeonwort.tistory.com/395</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;쉬어갈 겸 보조 기능으로 스크린샷 찍는 것을 &lt;a href=&quot;https://github.com/codeonwort/pathosengine/commit/7568f8eaee28e72ff25aea19bde5f11ead8e85da&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;구현&lt;/a&gt;해봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;screenshot_1.jpg&quot; data-origin-width=&quot;379&quot; data-origin-height=&quot;464&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bt33jh/btrNyFtx8YD/wuko3SeQx3oPLMOl4udDJ1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bt33jh/btrNyFtx8YD/wuko3SeQx3oPLMOl4udDJ1/img.jpg&quot; data-alt=&quot;콘솔 창에서 screenshot 커맨드를 실행&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bt33jh/btrNyFtx8YD/wuko3SeQx3oPLMOl4udDJ1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbt33jh%2FbtrNyFtx8YD%2Fwuko3SeQx3oPLMOl4udDJ1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;379&quot; height=&quot;464&quot; data-filename=&quot;screenshot_1.jpg&quot; data-origin-width=&quot;379&quot; data-origin-height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;콘솔 창에서 screenshot 커맨드를 실행&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;screenshot_2.jpg&quot; data-origin-width=&quot;1049&quot; data-origin-height=&quot;514&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chJ2BR/btrNvPEbeS5/j2rcrIBMqYwKBfAHRUKw30/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chJ2BR/btrNvPEbeS5/j2rcrIBMqYwKBfAHRUKw30/img.jpg&quot; data-alt=&quot;프레임버퍼를 읽어서 png로 출력&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chJ2BR/btrNvPEbeS5/j2rcrIBMqYwKBfAHRUKw30/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchJ2BR%2FbtrNvPEbeS5%2Fj2rcrIBMqYwKBfAHRUKw30%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1049&quot; height=&quot;514&quot; data-filename=&quot;screenshot_2.jpg&quot; data-origin-width=&quot;1049&quot; data-origin-height=&quot;514&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;프레임버퍼를 읽어서 png로 출력&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VRAM에 있는 텍스처를 제대로 읽기만 하면 할 일의 90%는 끝난다. 그런데 검색을 해봐도 GL_HALF_FLOAT, 즉 16비트 정밀도의 rgba16f 텍스처를 어떻게 읽어와야 하는 지에 대해 파편화된 정보들만 있어서 삽질을 조금 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 렌더링 파이프라인에서는 포스트 프로세싱 패스들을 토글할 수 있기 때문에 마지막으로 실행된 포스트 프로세싱이 무엇인지에 따라 백버퍼로 blit하기 직전 sceneColor 텍스처의 픽셀 포맷이 달라질 수 있다. 그래서 최종 PP 실행 결과를 무조건 rgba16f 포맷의 sceneFinal 텍스처에 복사하고, 스크린샷을 찍어야 하면 sceneFinal을 읽고, sceneFinal을 백버퍼로 blit하도록 절차를 수정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1664599368294&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Assumes rendering result is always written to sceneFinal and it's pixel format is rgba16f.
if (scene-&amp;gt;bScreenshotReserved) {
    cmdList.bindFramebuffer(GL_READ_FRAMEBUFFER, fboScreenshot);
    cmdList.namedFramebufferTexture(fboScreenshot, GL_COLOR_ATTACHMENT0, sceneFinal, 0);
    cmdList.namedFramebufferReadBuffer(fboScreenshot, GL_COLOR_ATTACHMENT0);

    // NOTE: std::vector&amp;lt;uint16&amp;gt; screenshotRawData;
    scene-&amp;gt;screenshotSize = vector2i(sceneWidth, sceneHeight);
    scene-&amp;gt;screenshotRawData.resize(4 * sceneWidth * sceneHeight);
    cmdList.pixelStorei(GL_PACK_ALIGNMENT, 1);
    cmdList.readPixels(0, 0, sceneWidth, sceneHeight,
    	GL_RGBA, GL_HALF_FLOAT,
    	scene-&amp;gt;screenshotRawData.data());
    cmdList.pixelStorei(GL_PACK_ALIGNMENT, 4);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;half float은 16비트이므로 uint16_t 버퍼를 준비하고 glReadPixels()로 읽어온다. 이 half float 값들을 일반적인 32비트 float으로 변환해야 한다. 변환 공식은 &lt;a href=&quot;https://stackoverflow.com/a/60047308&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/a/60047308&lt;/a&gt; 의 것을 가져다 썼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1664599661454&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Transfer screenshot pixels if exist.
if (sceneProxy-&amp;gt;bScreenshotReserved &amp;amp;&amp;amp; sceneProxy-&amp;gt;screenshotRawData.size() &amp;gt; 0) {
    vector2i screenshotSize = sceneProxy-&amp;gt;screenshotSize;

    auto half_to_float = [](const uint16 x) -&amp;gt; float { ... };
    
    const int32 totalPixels = screenshotSize.x * screenshotSize.y;
    const std::vector&amp;lt;uint16&amp;gt;&amp;amp; rawPixels = sceneProxy-&amp;gt;screenshotRawData;
    uint8* pixels = new uint8[totalPixels * 3];
    
    for (int32 i = 0; i &amp;lt; totalPixels; ++i) {
        float R = half_to_float(rawPixels[i * 4 + 0]);
        float G = half_to_float(rawPixels[i * 4 + 1]);
        float B = half_to_float(rawPixels[i * 4 + 2]);
        pixels[i * 3 + 0] = (uint8)badger::clamp(0u, (uint32)(B * 255.0f), 255u);
        pixels[i * 3 + 1] = (uint8)badger::clamp(0u, (uint32)(G * 255.0f), 255u);
        pixels[i * 3 + 2] = (uint8)badger::clamp(0u, (uint32)(R * 255.0f), 255u);
    }
    
    auto screenshot = std::make_pair(sceneProxy-&amp;gt;screenshotSize, pixels);
    gEngine-&amp;gt;pushScreenshot(screenshot);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sceneFinal에서 읽어온 픽셀들은 이미 톤매핑까지 끝낸 LDR 값들이므로 0.0 ~ 1.0 사이의 float으로 변환하고 나면 다시 0x00 ~ 0xff 범위로 매핑한다. 최종적으로는 이미지 라이브러리를 통해 png로 저장하며, 위 코드에서는 생략했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;glReadPixels()만 테스트해보는 데모였다면 드로우콜 &amp;rarr; glFlush() -&amp;gt; glReadPixels() &amp;rarr; 이미지 파일로 출력을 한번에 처리했겠지만 이미 나름의 아키텍처가 있는 프로젝트에 추가하다보니 실제 처리 과정은 조금 더 복잡하다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;메인 쓰레드: screenshot 커맨드를 감지하여 렌더 쓰레드에 스크린샷 촬영 요청&lt;/li&gt;
&lt;li&gt;렌더 쓰레드: 바로 다음에 렌더링할 scene proxy에 스크린샷 플래그를 설정하고, 플래그가 설정된 경우에만 glReadPixels() 실행하여 screenshot raw data를 생성&lt;/li&gt;
&lt;li&gt;렌더 쓰레드: scene proxy 렌더링 끝냈는데 screenshot raw data가 존재한다면 스크린샷 큐에 넣고 메인 쓰레드에 통지&lt;/li&gt;
&lt;li&gt;메인 쓰레드: 스크린샷 큐에 있는 raw data를 적절하게 변환하여 이미지 파일로 출력&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HDR 이미지 포맷으로 저장하는 기능도 생각해볼 수 있는데, 그러려면 톤매핑 패스에서 HDR &amp;rarr; LDR 변환을 하지 않고 HDR 값을 그대로 출력해야 한다. 이는 나중에 해볼 &lt;a href=&quot;https://on-demand.gputechconf.com/gtc/2017/presentation/s7394-tom-true-programming-for-high-dynamic-range.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HDR 디스플레이 지원&lt;/a&gt;과도 관련있다.&lt;/p&gt;</description>
      <category>Season 2</category>
      <category>GL_HALF_FLOAT</category>
      <category>rgba16f</category>
      <author>minseoklee</author>
      <guid isPermaLink="true">https://codeonwort.tistory.com/395</guid>
      <comments>https://codeonwort.tistory.com/395#entry395comment</comments>
      <pubDate>Sat, 1 Oct 2022 14:04:21 +0900</pubDate>
    </item>
  </channel>
</rss>