<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>codingfarm</title>
    <link>https://codingfarm.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sun, 19 Jul 2026 09:09:02 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>scarecrow1992</managingEditor>
    <image>
      <title>codingfarm</title>
      <url>https://tistory1.daumcdn.net/tistory/3092945/attach/d42197e246c749c689ed98bf840b2d61</url>
      <link>https://codingfarm.tistory.com</link>
    </image>
    <item>
      <title>Normal Map 쉐이딩</title>
      <link>https://codingfarm.tistory.com/697</link>
      <description>&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;756&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qY36R/dJMb991kk5I/ZK0E9egP0RKMclp0xmtOm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qY36R/dJMb991kk5I/ZK0E9egP0RKMclp0xmtOm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qY36R/dJMb991kk5I/ZK0E9egP0RKMclp0xmtOm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqY36R%2FdJMb991kk5I%2FZK0E9egP0RKMclp0xmtOm0%2Fimg.png&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;554&quot; height=&quot;275&quot; data-origin-width=&quot;756&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Noise Texture를 통해 normal map 을 절차적으로 만들기 위해 위와 같이 쉐이더 그래프를 구성하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 노말맵 상태를 확인하기 위해 &lt;b&gt;Material Output&lt;/b&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 alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;919&quot; data-origin-height=&quot;940&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVxDWH/dJMcafArZ2d/moAZviC6EiGkTNXrOwaX0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVxDWH/dJMcafArZ2d/moAZviC6EiGkTNXrOwaX0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVxDWH/dJMcafArZ2d/moAZviC6EiGkTNXrOwaX0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVxDWH%2FdJMcafArZ2d%2FmoAZviC6EiGkTNXrOwaX0K%2Fimg.png&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;475&quot; height=&quot;486&quot; data-origin-width=&quot;919&quot; data-origin-height=&quot;940&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 data-ke-size=&quot;size16&quot;&gt;청보라색이 아닌 완전 파란색으로 보인다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1399&quot; data-origin-height=&quot;1105&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r3bEv/dJMcabrhtx9/EUB0Raj9TEMrKTrTned411/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r3bEv/dJMcabrhtx9/EUB0Raj9TEMrKTrTned411/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r3bEv/dJMcabrhtx9/EUB0Raj9TEMrKTrTned411/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr3bEv%2FdJMcabrhtx9%2FEUB0Raj9TEMrKTrTned411%2Fimg.png&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;705&quot; height=&quot;557&quot; data-origin-width=&quot;1399&quot; data-origin-height=&quot;1105&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 왜 기본값이 (0.5, 0.5, 1.0) 이 되었는지를 알아야 하는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 인코딩/디코딩 때문이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 탄젠트 공간 노말 벡터 범위는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;~1 ~ 1&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이지만, 텍스쳐의 범위&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;0~1&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;로 변환하기 위해 보정 작업을 거치며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로인해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;(0, 0, 1)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;(0.5, 0.5, 1)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;로 변환된것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;493&quot; data-origin-height=&quot;277&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/M3JnI/dJMcaf8dkDG/3R8oZASjPKlSgUzTTjqdMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/M3JnI/dJMcaf8dkDG/3R8oZASjPKlSgUzTTjqdMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/M3JnI/dJMcaf8dkDG/3R8oZASjPKlSgUzTTjqdMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FM3JnI%2FdJMcaf8dkDG%2F3R8oZASjPKlSgUzTTjqdMK%2Fimg.png&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;493&quot; height=&quot;277&quot; data-origin-width=&quot;493&quot; data-origin-height=&quot;277&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;627&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JfOaR/dJMb991kldo/ZzXk9aYrCLhVXwMMCpKsak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JfOaR/dJMb991kldo/ZzXk9aYrCLhVXwMMCpKsak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JfOaR/dJMb991kldo/ZzXk9aYrCLhVXwMMCpKsak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJfOaR%2FdJMb991kldo%2FZzXk9aYrCLhVXwMMCpKsak%2Fimg.png&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;576&quot; height=&quot;661&quot; data-origin-width=&quot;627&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Blender3d의 Normal Map 노드의 기본색상도 (0.5, 0.5, 1)이며, 해당 노드를 그대로 Material Output에 연결해도&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;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;0~1&lt;/b&gt;만을 지원하는 이미지 파일에 -1~1의 범위를 가지는 벡터를 반영하기 위해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;음수를 양수로 바꾸는 offset 및 scaling 작업이 필요했으며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로인해 데이터 정규화 과정을 거치며 노말맵의 청보라색이 파란색으로 변형되는것이다.&lt;/p&gt;</description>
      <category>blender3d/기타</category>
      <author>scarecrow1992</author>
      <guid isPermaLink="true">https://codingfarm.tistory.com/697</guid>
      <comments>https://codingfarm.tistory.com/697#entry697comment</comments>
      <pubDate>Sat, 4 Jul 2026 19:36:14 +0900</pubDate>
    </item>
    <item>
      <title>Texture Baking</title>
      <link>https://codingfarm.tistory.com/696</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Blender3d 에서 모델링된 3d 모델을 어플리케이션에서 사용하기 위해서는 glb 등의 확장자로 export 해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 해당 확장자 파일이 blender3d 의 기능을 요구하지 않는다면, 해당 데이터는 상실되며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어플리케이션 내에서의 렌더링 결과도 blender3d와 달라지게된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;glb로 exporting 불가능한, blender3d 자체 기능들은 대표적으로 shader node 가 있다.&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://docs.blender.org/manual/nb/3.6/addons/import_export/node_shaders_info.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.blender.org/manual/nb/3.6/addons/import_export/node_shaders_info.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;blender3d 는 Node Shader를 import/export 하는 가이드를 안내해주는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;사실상&lt;b&gt; Principled BSDF&lt;/b&gt;와 &lt;b&gt;Normal Map&lt;/b&gt;, &lt;b&gt;Textures&lt;/b&gt;를 제외한 나머지 노드나 설정등은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;glb로 export 한 순간 데이터를 잃는다는 가정하에 작업하는것이 유용하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 베이킹&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1318&quot; data-origin-height=&quot;660&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cY1dw6/dJMcahygzRk/U7KITGgBXIkas5kwlwTg1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cY1dw6/dJMcahygzRk/U7KITGgBXIkas5kwlwTg1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cY1dw6/dJMcahygzRk/U7KITGgBXIkas5kwlwTg1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcY1dw6%2FdJMcahygzRk%2FU7KITGgBXIkas5kwlwTg1K%2Fimg.png&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;1318&quot; height=&quot;660&quot; data-origin-width=&quot;1318&quot; data-origin-height=&quot;660&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;noise texture를 이용한 diffuse map과 normal map 이 적용된 간단한 material 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 쉐이더를 기준으로 모델에 적용된 Diffuse Map과 Normal Map 을 texture로 베이킹 하는 방법은 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) UV-unwrapping&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;586&quot; data-origin-height=&quot;712&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/E95aN/dJMcai4Vci6/lBklVk3Sp1DgvHQOvbDKCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/E95aN/dJMcai4Vci6/lBklVk3Sp1DgvHQOvbDKCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/E95aN/dJMcai4Vci6/lBklVk3Sp1DgvHQOvbDKCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FE95aN%2FdJMcai4Vci6%2FlBklVk3Sp1DgvHQOvbDKCk%2Fimg.png&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;423&quot; height=&quot;514&quot; data-origin-width=&quot;586&quot; data-origin-height=&quot;712&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;shader node 를 사용하여 절차적으로 material을 만들때는, 좌표들을 3d 공간에서 직접 얻을 수 있지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;베이킹을 위해선 모델에 map 적용될 uv 좌표를 알아야 하며, 이를 위해 unwrapping을 수행해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;편집모드에서 모든 요소를 선택한 후 단축키 u를 누르면 &lt;b&gt;UV Mapping&lt;/b&gt; 컨텍스트 메뉴를 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;b&gt;Smart UV Project&lt;/b&gt;를 통해 간단하게 &lt;b&gt;uv mapping&lt;/b&gt; 수행이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2) Texture 생성하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;베이킹된 결과가 반영될 texture를 미리 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;텍스쳐는 &lt;b&gt;Shading Editor&lt;/b&gt; 에서 &lt;b&gt;Image Texture&lt;/b&gt; 노드를 생성한 후, &lt;b&gt;new&lt;/b&gt; 버튼을 눌러 생성할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;385&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6Pwoj/dJMb99NGSOe/cx1tdHkzzOTD0SqTqmaMYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6Pwoj/dJMb99NGSOe/cx1tdHkzzOTD0SqTqmaMYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6Pwoj/dJMb99NGSOe/cx1tdHkzzOTD0SqTqmaMYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6Pwoj%2FdJMb99NGSOe%2Fcx1tdHkzzOTD0SqTqmaMYk%2Fimg.png&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;586&quot; height=&quot;302&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;385&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3) Baking 설정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.blender.org/manual/en/latest/render/cycles/baking.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.blender.org/manual/en/latest/render/cycles/baking.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;베이킹은&amp;nbsp;&lt;b&gt;Properties&lt;/b&gt; 의 &lt;b&gt;Render&lt;/b&gt; 탭에서 설정/수행 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매터리얼/조명 결과를 이미지 텍스쳐로 굽는 기능은 &lt;b&gt;Cycles&lt;/b&gt; 전용이므로,&amp;nbsp; &lt;b&gt;Render Engine&amp;nbsp;&lt;/b&gt;을&amp;nbsp;&lt;b&gt;Cycles&lt;/b&gt;로&amp;nbsp;설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면&amp;nbsp;&lt;b&gt;Bake&lt;/b&gt; 아코디언 UI가 활성화됨을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;558&quot; data-origin-height=&quot;604&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/div0Q6/dJMcad3C9JB/ikzYr4kk9acUdM86r9k7i1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/div0Q6/dJMcad3C9JB/ikzYr4kk9acUdM86r9k7i1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/div0Q6/dJMcad3C9JB/ikzYr4kk9acUdM86r9k7i1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdiv0Q6%2FdJMcad3C9JB%2FikzYr4kk9acUdM86r9k7i1%2Fimg.png&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;384&quot; height=&quot;416&quot; data-origin-width=&quot;558&quot; data-origin-height=&quot;604&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;Normal&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;594&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/unOKn/dJMb99NGSU8/BlABvldv2dkgej6k5dLK3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/unOKn/dJMb99NGSU8/BlABvldv2dkgej6k5dLK3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/unOKn/dJMb99NGSU8/BlABvldv2dkgej6k5dLK3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FunOKn%2FdJMb99NGSU8%2FBlABvldv2dkgej6k5dLK3k%2Fimg.png&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;472&quot; height=&quot;504&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;594&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Space는 &lt;b&gt;Tangent&lt;/b&gt;와 &lt;b&gt;Object&lt;/b&gt;가 제공되는데, &lt;b&gt;Tangent&lt;/b&gt;는 각 표면의 접선 좌표계를 기준으로 색상을 만들며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Object&lt;/b&gt;는 오브젝트의 로컬 좌표계를 기준으로 색을 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 객체의 옆면을 베이킹 할 경우 &lt;b&gt;Tangent&lt;/b&gt; 에서는&amp;nbsp; (0.5, 0.5, 1.0) 색이 설정되지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Object&lt;/b&gt;는 해당 면이 향하는 실제 좌표를 기준으로 색을 형성하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 경우 &lt;b&gt;Tangent&lt;/b&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;&amp;nbsp;Diffuse&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;565&quot; data-origin-height=&quot;351&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k5t40/dJMcagszv6l/8cSxfNv86LL1fzx1kuKRYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k5t40/dJMcagszv6l/8cSxfNv86LL1fzx1kuKRYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k5t40/dJMcagszv6l/8cSxfNv86LL1fzx1kuKRYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk5t40%2FdJMcagszv6l%2F8cSxfNv86LL1fzx1kuKRYk%2Fimg.png&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;565&quot; height=&quot;351&quot; data-origin-width=&quot;565&quot; data-origin-height=&quot;351&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Contributions&lt;/b&gt; 항목에서는 3개의 옵션이 주어진다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Direct / Indirect : 직접광, 간접광에 의한 조명효과 적용 여부&lt;/li&gt;
&lt;li&gt;Color : Colorize Pass 적용 여부&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Pricipled BSDF&lt;/b&gt;의 &lt;b&gt;BaseColor&lt;/b&gt;에 적용된 색상이 그대로 베이킹 되길 원한다면, &lt;b&gt;Color&lt;/b&gt; 옵션만 살린다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4) Bake 수행&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Layout View&lt;/b&gt;에서 모델 선택&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Shading UI&lt;/b&gt; 에서 Image Texture 선택&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Bake&lt;/b&gt; 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 작업을 수행하면, &lt;b&gt;선택된 모델&lt;/b&gt;의 베이킹 결과를 &lt;b&gt;Image Texture&lt;/b&gt; 노드에 할당된 &lt;b&gt;Texture&lt;/b&gt;에 베이킹된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;646&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d6aouu/dJMcai4VdsE/MyDD26KgtBctM7ChOgnhk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d6aouu/dJMcai4VdsE/MyDD26KgtBctM7ChOgnhk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d6aouu/dJMcai4VdsE/MyDD26KgtBctM7ChOgnhk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd6aouu%2FdJMcai4VdsE%2FMyDD26KgtBctM7ChOgnhk0%2Fimg.png&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;474&quot; height=&quot;437&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;646&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;682&quot; data-origin-height=&quot;643&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bo5nKr/dJMcafArZZ2/QTNkEd7F0dm7AD1vINOUlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bo5nKr/dJMcafArZZ2/QTNkEd7F0dm7AD1vINOUlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bo5nKr/dJMcafArZZ2/QTNkEd7F0dm7AD1vINOUlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbo5nKr%2FdJMcafArZZ2%2FQTNkEd7F0dm7AD1vINOUlk%2Fimg.png&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;465&quot; height=&quot;438&quot; data-origin-width=&quot;682&quot; data-origin-height=&quot;643&quot;/&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://docs.blender.org/manual/en/latest/editors/image/image_settings.html#bpy-types-colormanagedinputcolorspacesettings-name&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.blender.org/manual/en/latest/editors/image/image_settings.html#bpy-types-colormanagedinputcolorspacesettings-name&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOmAiA/dJMcajbGlhL/yKiwZi0dk0J9DfM59aE8Mk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOmAiA/dJMcajbGlhL/yKiwZi0dk0J9DfM59aE8Mk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOmAiA/dJMcajbGlhL/yKiwZi0dk0J9DfM59aE8Mk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOmAiA%2FdJMcajbGlhL%2FyKiwZi0dk0J9DfM59aE8Mk%2Fimg.png&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;1264&quot; height=&quot;364&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;364&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;361&quot; data-origin-height=&quot;348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEvdx7/dJMcajv5cHN/zNzL1qBVlwOqxcvxfFUNVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEvdx7/dJMcajv5cHN/zNzL1qBVlwOqxcvxfFUNVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEvdx7/dJMcajv5cHN/zNzL1qBVlwOqxcvxfFUNVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEvdx7%2FdJMcajv5cHN%2FzNzL1qBVlwOqxcvxfFUNVk%2Fimg.png&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;361&quot; height=&quot;348&quot; data-origin-width=&quot;361&quot; data-origin-height=&quot;348&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Normal, Stencil, Bump&lt;/b&gt; 처럼 비색상 텍스쳐는 baking 및 load시 색공간을 sRGB가 아닌 Non-Color로 설정해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;색보정이 발생하면서, 데이터 자체가 변조되는 현상을 막기 위함이며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;three.js에서 Normal 등의 비색상 텍스쳐에 명시적으로&lt;b&gt; NoColorSpace&lt;/b&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 alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;654&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cudW65/dJMcahSuIiv/chreJ6I2iFW4EtHw6dAYxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cudW65/dJMcahSuIiv/chreJ6I2iFW4EtHw6dAYxk/img.png&quot; data-alt=&quot;sRGB 적용시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cudW65/dJMcahSuIiv/chreJ6I2iFW4EtHw6dAYxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcudW65%2FdJMcahSuIiv%2FchreJ6I2iFW4EtHw6dAYxk%2Fimg.png&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;358&quot; height=&quot;339&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;654&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;sRGB 적용시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;469&quot; data-origin-height=&quot;463&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VBvVM/dJMcadCuSRc/YGM3lT889OMq3aqs9k7O71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VBvVM/dJMcadCuSRc/YGM3lT889OMq3aqs9k7O71/img.png&quot; data-alt=&quot;Non-Color 적용시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VBvVM/dJMcadCuSRc/YGM3lT889OMq3aqs9k7O71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVBvVM%2FdJMcadCuSRc%2FYGM3lT889OMq3aqs9k7O71%2Fimg.png&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;344&quot; height=&quot;340&quot; data-origin-width=&quot;469&quot; data-origin-height=&quot;463&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Non-Color 적용시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Blender3d로 이미지를 Image Texture 노드에 로드시, 색공간을 Non-Color로 설정하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Image Editor 윈도우에서 표시되는 이미지 색상에도 차이가 생긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러므로 Browser나 뷰어앱을 통해 이미지를 보는것보다 밝은색으로 표현될 수 있다.&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;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgGaLU/dJMcabx0bbk/X3EAcKnjHyLL8xylmrIBD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgGaLU/dJMcabx0bbk/X3EAcKnjHyLL8xylmrIBD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgGaLU/dJMcabx0bbk/X3EAcKnjHyLL8xylmrIBD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgGaLU%2FdJMcabx0bbk%2FX3EAcKnjHyLL8xylmrIBD0%2Fimg.png&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;604&quot; height=&quot;300&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Normal Texture의 경우, Normal Map을 통해 이미지 텍스쳐의 데이터를 노말벡터 정보로 정규화 하는 과정을 진행하면된다.&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 alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;475&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XlQ06/dJMcadvKSGs/zNA2DVWfFroDwZD9pkFxk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XlQ06/dJMcadvKSGs/zNA2DVWfFroDwZD9pkFxk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XlQ06/dJMcadvKSGs/zNA2DVWfFroDwZD9pkFxk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXlQ06%2FdJMcadvKSGs%2FzNA2DVWfFroDwZD9pkFxk0%2Fimg.png&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;640&quot; height=&quot;363&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;475&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지파일을 외부에서 로드할 경우 Color Space를 직접 설정 가능gksep,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 설명한대로 Non-Color로 설정해주면된다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본문에서는 당장 필요로한 Bake Type에 대해서만 간략히 정리하였으나,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Blender3d는 매우 다양한 종류의 Bake Type을 지원하며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;렌더링 품질을 올리기 위해서는, 해당 타입들 모두에 대해 면밀하게 학습하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;import 환경에서도 품질 손실없이 렌더링 할 수 있는 기술들에 대해 부지런히 학습해야겠다.&lt;/p&gt;</description>
      <category>blender3d/기타</category>
      <author>scarecrow1992</author>
      <guid isPermaLink="true">https://codingfarm.tistory.com/696</guid>
      <comments>https://codingfarm.tistory.com/696#entry696comment</comments>
      <pubDate>Sat, 4 Jul 2026 19:04:19 +0900</pubDate>
    </item>
    <item>
      <title>customDepthMaterial을 이용한 그림자 렌더링</title>
      <link>https://codingfarm.tistory.com/695</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1.소개&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://screen.toys/firewood/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://screen.toys/firewood/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2199&quot; data-origin-height=&quot;1252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LTtZe/dJMcabxU3EE/RvaP9DwO6wiyoFdfjbGhU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LTtZe/dJMcabxU3EE/RvaP9DwO6wiyoFdfjbGhU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LTtZe/dJMcabxU3EE/RvaP9DwO6wiyoFdfjbGhU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLTtZe%2FdJMcabxU3EE%2FRvaP9DwO6wiyoFdfjbGhU1%2Fimg.png&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;2199&quot; height=&quot;1252&quot; data-origin-width=&quot;2199&quot; data-origin-height=&quot;1252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Three.js 메인 페이지에 소개된 장작패기 프로젝트이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mp4 동영상 파일과 VideoTexture를 이용하여, 바람에 나무가 움직이는 연출이 인상적이며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 프로젝트를 참고하여, 움직이는 그림자를 렌더링하는 방법을 학습하였다.&lt;/p&gt;
&lt;pre id=&quot;code_1782565286671&quot; class=&quot;nix&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;const video = document.createElement(&quot;video&quot;);
video.src = &quot;video/gobo.mp4&quot;;
video.loop = true;
video.muted = true;
video.playsInline = true;
video.preload = &quot;auto&quot;;
video.crossOrigin = `anonymous`;

video.addEventListener(&quot;loadeddata&quot;, () =&amp;gt; {
  video.play();
});

video.load();

const videoTexture = new THREE.VideoTexture(video);

videoTexture.colorSpace = THREE.SRGBColorSpace;

const colorMaterial = new THREE.MeshBasicMaterial({
  map: videoTexture,
  transparent: true,
  alphaTest: 0.5,
  side: THREE.DoubleSide,
  depthWrite: false,
});

const depthMaterial = new THREE.MeshBasicMaterial({
  map: videoTexture,
  alphaTest: 0.5,
  side: THREE.DoubleSide,
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Video Texture를 사용하여, colorMaterial과 depthMaterial을 각각 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1782565363170&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const geometry = new THREE.PlaneGeometry(10, 10);
const mesh = new THREE.Mesh(geometry, colorMaterial);

mesh.customDepthMaterial = depthMaterial;
mesh.visible = true;
mesh.receiveShadow = false;
mesh.castShadow = true;
mesh.material.colorWrite = false;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 plane geometry를 사용하여 &lt;b&gt;mesh&lt;/b&gt;를 생성하는데, &lt;b&gt;customDepthMaterial&lt;/b&gt;에 앞서 생성한 &lt;b&gt;depthMaterial&lt;/b&gt;을 할당한다.&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;h2 data-ke-size=&quot;size26&quot;&gt;2. 문제&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1126&quot; data-origin-height=&quot;901&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byrb86/dJMcajirNWs/rD0z3qeqykASRX3pjg3cd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byrb86/dJMcajirNWs/rD0z3qeqykASRX3pjg3cd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byrb86/dJMcajirNWs/rD0z3qeqykASRX3pjg3cd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbyrb86%2FdJMcajirNWs%2FrD0z3qeqykASRX3pjg3cd0%2Fimg.png&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;434&quot; height=&quot;901&quot; data-origin-width=&quot;1126&quot; data-origin-height=&quot;901&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;738&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KfBFE/dJMcai4P72y/LRghui6R21Rpm8VKzZvYc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KfBFE/dJMcai4P72y/LRghui6R21Rpm8VKzZvYc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KfBFE/dJMcai4P72y/LRghui6R21Rpm8VKzZvYc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKfBFE%2FdJMcai4P72y%2FLRghui6R21Rpm8VKzZvYc1%2Fimg.png&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;439&quot; height=&quot;738&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;738&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상 : 나무 그림자 active&lt;/li&gt;
&lt;li&gt;하 : 나무 그림자 inactive&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 plane mesh 아래에 존재하는 모델의 그림자 생성을 막아버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나무와 장작의 그림자를 동시에 렌더링 하기위해서, three.js가 그림자를 만드는 방법에 대해 간략히 알아보았다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Light의 시점에서 scene을 한번 렌더링 한다.&lt;/li&gt;
&lt;li&gt;각 픽셀마다 라이트에서 가장 가까운 depth를 shadow map에 저장한다.&lt;/li&gt;
&lt;li&gt;메인 렌더의 fragment shader에서, 특정 표면이 해당 depth 보다 뒤에 있으면 그림자라고 판단한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 그림자가 만들어지지 않는 이유는, 광원의 shadow camera 시점에서 plane이 사물보다 앞에 있어 가장 가까운 depth로 기록된. 그 결과 뒤쪽 사물의 fragment는 shadow map에 자신의 depth를 기록할 수 없게된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 해결&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;plane을 shadow map에 렌더링 할때, 빛을 통과시켜야하는 영역의 fragment를 discard 시키면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;three.js에서는 material 생성시 alphaTest 수치를 설정할 수 있으며, fragment shader에서 이 alpha 값이 지정된 수치보다 낮다면, discard를 발생시켜 shadow map에 depth를 기록하지 않게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 three.js는 해당 판정코드를 수월하게 작성 할 수 있도록,&amp;nbsp;&lt;b&gt;alphatest_fragment&lt;/b&gt; 청크를 제공하며, 아래와 같이 쉐이더 코드를 삽입하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1782567356699&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const ALPHA_TEST_FRAGMENT_CHUNK = &quot;#include &amp;lt;alphatest_fragment&amp;gt;&quot;;

const GOBO_LUMINANCE_ALPHA_MASK = `
float goboLuminance = dot(diffuseColor.rgb, vec3(0.299, 0.587, 0.114));
diffuseColor.a = 1.0 - goboLuminance;
${ALPHA_TEST_FRAGMENT_CHUNK}
`;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 결과&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1171&quot; data-origin-height=&quot;895&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWwTSw/dJMcahkHlgM/ZTKhUX5eTPD72pgUkqsdIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWwTSw/dJMcahkHlgM/ZTKhUX5eTPD72pgUkqsdIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWwTSw/dJMcahkHlgM/ZTKhUX5eTPD72pgUkqsdIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWwTSw%2FdJMcahkHlgM%2FZTKhUX5eTPD72pgUkqsdIk%2Fimg.png&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;723&quot; height=&quot;553&quot; data-origin-width=&quot;1171&quot; data-origin-height=&quot;895&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 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;customDepthMaterial에 의 shadow pass에서 어떤 fragment가 유효한 caster로 남을지 결정된다&lt;/li&gt;
&lt;li&gt;원본 plane의 형상에 맞춰 shadowMap의 depth가 기록된다.&lt;/li&gt;
&lt;li&gt;분명 그림자가 없는 fragment 임에도, discard 판정이 없지만 depth 판정은 발생하는 비직관적인 현상이 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 시각적으로는&amp;nbsp;비어&amp;nbsp;있거나&amp;nbsp;빛이&amp;nbsp;통과해야&amp;nbsp;하는&amp;nbsp;영역인데도,&amp;nbsp;shadow&amp;nbsp;map에는&amp;nbsp;plane의&amp;nbsp;가까운&amp;nbsp;depth가&amp;nbsp;기록되어&amp;nbsp;그림자가&amp;nbsp;있는&amp;nbsp;것으로&amp;nbsp;잘못&amp;nbsp;판정된&amp;nbsp;현상이다.&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;본문에서는 alphaTest와 fragmentShader의 alpha 값을 통한 discard로 해결하는 방법을 사용했지만, rgb값을 통해 마스크를 재해석 하는 방법이 아니라, &lt;b&gt;alphaMap&lt;/b&gt;을 사용하는 방식이 더 안정적이라는데, 다음에 테스트 해봐야겠다.&lt;/p&gt;
&lt;pre id=&quot;code_1782569194760&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;depthMaterial.alphaMap = maskTexture;
depthMaterial.alphaTest = 0.5;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아울러 three.js의 렌더링 파이프라인에 대해서 심도있게 학습하고, Shadow Map, Depth Test, Discard에 대해서도 제대로 정리해야겠다.&lt;/p&gt;</description>
      <category>computer graphics/Three.js</category>
      <author>scarecrow1992</author>
      <guid isPermaLink="true">https://codingfarm.tistory.com/695</guid>
      <comments>https://codingfarm.tistory.com/695#entry695comment</comments>
      <pubDate>Sat, 27 Jun 2026 23:18:05 +0900</pubDate>
    </item>
    <item>
      <title>4. Principled BSDF</title>
      <link>https://codingfarm.tistory.com/693</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.blender.org/manual/en/latest/render/shader_nodes/shader/principled.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.blender.org/manual/en/latest/render/shader_nodes/shader/principled.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1781061539529&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Principled BSDF - Blender 5.1 Manual&quot; data-og-description=&quot;Previous Metallic BSDF&quot; data-og-host=&quot;docs.blender.org&quot; data-og-source-url=&quot;https://docs.blender.org/manual/en/latest/render/shader_nodes/shader/principled.html&quot; data-og-url=&quot;https://docs.blender.org/manual/en/latest/render/shader_nodes/shader/principled.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.blender.org/manual/en/latest/render/shader_nodes/shader/principled.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.blender.org/manual/en/latest/render/shader_nodes/shader/principled.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;Principled BSDF - Blender 5.1 Manual&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Previous Metallic BSDF&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.blender.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 소개&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;373&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqIis3/dJMb99UcYyK/bSyNRFDpjIhQA9bz2D5cL1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqIis3/dJMb99UcYyK/bSyNRFDpjIhQA9bz2D5cL1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqIis3/dJMb99UcYyK/bSyNRFDpjIhQA9bz2D5cL1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqIis3%2FdJMb99UcYyK%2FbSyNRFDpjIhQA9bz2D5cL1%2Fimg.webp&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;279&quot; height=&quot;347&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;373&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Blender3d에서제일 흔하게 사용되는 표면 셰이더 노드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OpenPBR Surface shading model을 기반으로 두기 때문에, 업계 표준 PBR 셰이더들과의 호환이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주로 &lt;b&gt;Material Output&lt;/b&gt; 노드의 &lt;b&gt;Surface&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 특징&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델의 표면이 빛과 어떻게 상호작용 할지를 결정한다.&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;플라스틱&lt;/li&gt;
&lt;li&gt;금속&lt;/li&gt;
&lt;li&gt;유리&lt;/li&gt;
&lt;li&gt;고무&lt;/li&gt;
&lt;li&gt;도자기&lt;/li&gt;
&lt;li&gt;피부&lt;/li&gt;
&lt;li&gt;페인트&lt;/li&gt;
&lt;li&gt;나무&lt;/li&gt;
&lt;li&gt;반투명 재질&lt;/li&gt;
&lt;li&gt;etc&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. BSDF 란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BSDF는 Bidirectional Scattering Distribution Function의 약자이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 말하면, &lt;b&gt;표면에 들어오는 빛이 어느 방향으로, 얼마나 반사되거나 투과되는지 결정하는 함수&lt;/b&gt; 를 칭한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Pricinpled BSDF는 함수를 PBR 방식으로 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2. PBR 이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PBR은 &amp;nbsp;Physically Based Rendering의 약자이며 한국어로 &quot;물리 기반 렌더링&quot; 이라고 칭한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과거에는 질감 표현을 위해 Diffuse Color, Specular Color, Shininess 등의 매개변수를 사용했으며, 기본색, 하이라이팅 색, 반짝임 정도를 아티스트가 직접 결정하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 오늘날에는 Base Color, Metalic, Roughness, Normal 등의 매개변수가 제공되며, 이는 조명이 바뀌어도 재질의 물성은 유지되며, 비교적 일관되게 보인다는 장점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;PBR(Physically Based Rendering)&lt;/b&gt;을 위한 다양한 매개변수들이 제공되며, GLB 와의 호환성이 높기 때문에, Three.js 나 Unity/Unreal 같은 3d 라이브러리 및 엔진으로의 export/import 가 안정적인 편이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 레이어&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;229&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nVjfS/dJMcadPM1VS/ZBD6MUZbixaNukkboUVM6K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nVjfS/dJMcadPM1VS/ZBD6MUZbixaNukkboUVM6K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nVjfS/dJMcadPM1VS/ZBD6MUZbixaNukkboUVM6K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnVjfS%2FdJMcadPM1VS%2FZBD6MUZbixaNukkboUVM6K%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;764&quot; height=&quot;229&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;229&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pricipled BSDF 의 질감표현은 여러 재질 반응들을 층층히 쌓아올려 혼합되는 구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 node 상에서는 각 입력들이 별개로 들어오는것처럼 보이지만, 실제로는 서로 다른 input에 영향을 줄 수 있는 구조이다. 가령 Duffuse와 Subsurface는 Specular의 하위에 있으며, 선택적 광탱 코팅(coat)와 광택층(Sheen)은 다른 모든 레이어 위에 존재하는데, coat는 아주 얇은층을 표현하며, sheen은 먼지/보풀의 표현을 담당한다. Emission은 자체 발광을 담당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무적으로는 우선 아래 정도로만 이해하자&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Base Layer: metalness, roughness 등 기본 재질정보&lt;br /&gt;Specular Layer: 표면이 빛을 어떻게 반사하는가&lt;br /&gt;Coat Layer: 투명 코팅이 있는가&lt;br /&gt;Sheen Layer: 보풀,먼지,섬유감이 있는가&lt;br /&gt;Emission: 스스로 빛을 내는&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Metallic 과 Roughness&lt;/h2&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://www.reddit.com/r/blender/comments/jxz6fk/whats_the_difference_from_the_roughness_and/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.reddit.com/r/blender/comments/jxz6fk/whats_the_difference_from_the_roughness_and/&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>blender3d/Shader Nodes</category>
      <author>scarecrow1992</author>
      <guid isPermaLink="true">https://codingfarm.tistory.com/693</guid>
      <comments>https://codingfarm.tistory.com/693#entry693comment</comments>
      <pubDate>Wed, 10 Jun 2026 13:38:22 +0900</pubDate>
    </item>
    <item>
      <title>3. Displacement Node</title>
      <link>https://codingfarm.tistory.com/692</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 소개&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.blender.org/manual/en/latest/render/shader_nodes/output/material.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.blender.org/manual/en/latest/render/shader_nodes/output/material.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;192&quot; data-origin-height=&quot;166&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSBefD/dJMcahdE5ua/Pckfw0hN1Auk50A5MjEkN1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSBefD/dJMcahdE5ua/Pckfw0hN1Auk50A5MjEkN1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSBefD/dJMcahdE5ua/Pckfw0hN1Auk50A5MjEkN1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcSBefD%2FdJMcahdE5ua%2FPckfw0hN1Auk50A5MjEkN1%2Fimg.webp&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;192&quot; height=&quot;166&quot; data-origin-width=&quot;192&quot; data-origin-height=&quot;166&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Material Output&lt;/b&gt; 노드의&lt;b&gt; Displacement&lt;/b&gt; 슬롯에 전달되는 노드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로&amp;nbsp;&lt;b&gt;Texture / Noise / Height Map&lt;/b&gt;&amp;nbsp;등의 노드들이&amp;nbsp;&lt;b&gt;Displacement&lt;/b&gt;&amp;nbsp;노드와 연결된 뒤, Output과 연결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표면에서의 빛과의 상호작용에만 관여하는 Surface, Volume 슬롯과 달리, Displacement는 geometry가 변형되는 방향과 강도등을 결정하며, 이에따른 자연스러운 연출을 위해 Normal 등의 정보를 가공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;모델의 외형에 직접적으로 영향을 주는 노드&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 사용&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1106&quot; data-origin-height=&quot;770&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/egi4hm/dJMcahrdwXE/QSF7AxoYT6PPRJkDKly7wK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/egi4hm/dJMcahrdwXE/QSF7AxoYT6PPRJkDKly7wK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/egi4hm/dJMcahrdwXE/QSF7AxoYT6PPRJkDKly7wK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fegi4hm%2FdJMcahrdwXE%2FQSF7AxoYT6PPRJkDKly7wK%2Fimg.png&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;1106&quot; height=&quot;770&quot; data-origin-width=&quot;1106&quot; data-origin-height=&quot;770&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;position: absolute;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1153&quot; data-origin-height=&quot;370&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKlfFz/dJMcageJUjH/KKckYKHtHDP0IX45Tn0s3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKlfFz/dJMcageJUjH/KKckYKHtHDP0IX45Tn0s3k/img.png&quot; data-alt=&quot;왼쪽 : 큐브, 중앙 : subdivde 적용된 큐브, 오른쪽 : subdivision 5 Ico Sphere&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKlfFz/dJMcageJUjH/KKckYKHtHDP0IX45Tn0s3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKlfFz%2FdJMcageJUjH%2FKKckYKHtHDP0IX45Tn0s3k%2Fimg.png&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;1153&quot; height=&quot;370&quot; data-origin-width=&quot;1153&quot; data-origin-height=&quot;370&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;왼쪽 : 큐브, 중앙 : subdivde 적용된 큐브, 오른쪽 : subdivision 5 Ico Sphere&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;geometry의 좌표를 직접 변형하기 때문에, vertex가 많을수록, 섬세하게 나뉘는것을 볼 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그러므로 주로 subdivision 및 shade smooth와 함께 사용된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이를통해 표면이 울퉁불퉁한 모델도, 쉐이더만으로 질감을 표현할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;435&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4TdQl/dJMcac4saxB/61uHjkfkh1LeeDqHeWPRjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4TdQl/dJMcac4saxB/61uHjkfkh1LeeDqHeWPRjk/img.png&quot; data-alt=&quot;solid view (edit mode) (subdivision 적용)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4TdQl/dJMcac4saxB/61uHjkfkh1LeeDqHeWPRjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4TdQl%2FdJMcac4saxB%2F61uHjkfkh1LeeDqHeWPRjk%2Fimg.png&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;568&quot; height=&quot;351&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;435&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;solid view (edit mode) (subdivision 적용)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;401&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dtntvH/dJMcah5PnER/RjhnyOQkgpU8w1xK39b20K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dtntvH/dJMcah5PnER/RjhnyOQkgpU8w1xK39b20K/img.png&quot; data-alt=&quot;displacement scale : 0.001&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dtntvH/dJMcah5PnER/RjhnyOQkgpU8w1xK39b20K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdtntvH%2FdJMcah5PnER%2FRjhnyOQkgpU8w1xK39b20K%2Fimg.png&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;568&quot; height=&quot;329&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;401&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;displacement scale : 0.001&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;406&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ce0meE/dJMcajbmKmK/fiqUT7GEehvgVJrAvipXFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ce0meE/dJMcajbmKmK/fiqUT7GEehvgVJrAvipXFk/img.png&quot; data-alt=&quot;displacement scale : 0.01&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ce0meE/dJMcajbmKmK/fiqUT7GEehvgVJrAvipXFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fce0meE%2FdJMcajbmKmK%2FfiqUT7GEehvgVJrAvipXFk%2Fimg.png&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;564&quot; height=&quot;313&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;406&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;displacement scale : 0.01&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;3. Material Setting&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;972&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PxttC/dJMcageJUPj/ueUtZYLQvVTqyp7tg858wK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PxttC/dJMcageJUPj/ueUtZYLQvVTqyp7tg858wK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PxttC/dJMcageJUPj/ueUtZYLQvVTqyp7tg858wK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPxttC%2FdJMcageJUPj%2FueUtZYLQvVTqyp7tg858wK%2Fimg.png&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;383&quot; height=&quot;613&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;972&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Displacement 효과를 올바르게 적용 위해선, Material Setting을 설정해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 옵션을 통해, Material Output의 Displacement 슬롯을 통해 들어온 정보를 렌더러가 어떻게 해석할지 결정한다.&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;Setting-Surface 카테고리의 Displacement 항목에서 3가지 옵션을 제공하며, 각 옵션의 적용 결과는 아래와 같다.&lt;br /&gt;( &lt;span style=&quot;color: #777777; text-align: center;&quot;&gt;displacement scale 0.01 적용)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQnz3p/dJMcaiKk2El/BaGchKYgBR3zc86Meyo5n0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQnz3p/dJMcaiKk2El/BaGchKYgBR3zc86Meyo5n0/img.png&quot; data-alt=&quot;Bump Only&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQnz3p/dJMcaiKk2El/BaGchKYgBR3zc86Meyo5n0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQnz3p%2FdJMcaiKk2El%2FBaGchKYgBR3zc86Meyo5n0%2Fimg.png&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;580&quot; height=&quot;334&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Bump Only&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;384&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ca17R/dJMcafz8ZUc/lDXStEh3UWndmBmH6yE8O0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ca17R/dJMcafz8ZUc/lDXStEh3UWndmBmH6yE8O0/img.png&quot; data-alt=&quot;Displacement Only&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ca17R/dJMcafz8ZUc/lDXStEh3UWndmBmH6yE8O0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCa17R%2FdJMcafz8ZUc%2FlDXStEh3UWndmBmH6yE8O0%2Fimg.png&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;579&quot; height=&quot;320&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;384&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Displacement Only&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;394&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dWX2aB/dJMcai4Cxy4/a6BK2kq3DKemcArMiYmqlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dWX2aB/dJMcai4Cxy4/a6BK2kq3DKemcArMiYmqlK/img.png&quot; data-alt=&quot;Displacement and Bump&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dWX2aB/dJMcai4Cxy4/a6BK2kq3DKemcArMiYmqlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdWX2aB%2FdJMcai4Cxy4%2Fa6BK2kq3DKemcArMiYmqlK%2Fimg.png&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;577&quot; height=&quot;324&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;394&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Displacement and Bump&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Bump는 실제 지오메트리를 변경시키진 않음을 확인 가능하다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하지만, 표면의 normal 을 변경시키므로, 굴곡 효과를 줄 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그러므로 표면의 vertex가 세밀하게 나뉘어진 모델이 아니라면, output material의 displacement는 비워두고, shader nodes에 normal 데이터를 전달하는것이 유용할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;4. Render Engine과 Displacement&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.blender.org/manual/en/latest/render/eevee/limitations/limitations.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.blender.org/manual/en/latest/render/eevee/limitations/limitations.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1268&quot; data-origin-height=&quot;406&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJ2uf0/dJMcaaS8kgQ/3TSPbAE4mmJhJ21Gx6PRYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJ2uf0/dJMcaaS8kgQ/3TSPbAE4mmJhJ21Gx6PRYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJ2uf0/dJMcaaS8kgQ/3TSPbAE4mmJhJ21Gx6PRYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJ2uf0%2FdJMcaaS8kgQ%2F3TSPbAE4mmJhJ21Gx6PRYK%2Fimg.png&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;1268&quot; height=&quot;406&quot; data-origin-width=&quot;1268&quot; data-origin-height=&quot;406&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;공식문서에 의하면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;EEVEE&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;렌더 환경에서는 flat shaded 가 적용된 표면이 삼각형으로 분리될 수 있음을 알려준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 아래와 같이 vertex가 충분히 나뉘어지지 않은 모델에 한해서는, displacement 결과가 부정확하게 렌더링 됨이 확인된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1014&quot; data-origin-height=&quot;603&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dTulE7/dJMcaiKk3in/OOv8ukMJVkCfNMVk49GkLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dTulE7/dJMcaiKk3in/OOv8ukMJVkCfNMVk49GkLK/img.png&quot; data-alt=&quot;EEVEE 엔진 &amp;amp;amp; Shade Smooth 적용 전&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dTulE7/dJMcaiKk3in/OOv8ukMJVkCfNMVk49GkLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdTulE7%2FdJMcaiKk3in%2FOOv8ukMJVkCfNMVk49GkLK%2Fimg.png&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;678&quot; height=&quot;603&quot; data-origin-width=&quot;1014&quot; data-origin-height=&quot;603&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;EEVEE 엔진 &amp;amp; Shade Smooth 적용 전&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GlI1Q/dJMcacDrTko/katlJ6W1RJfwh03ilT0k7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GlI1Q/dJMcacDrTko/katlJ6W1RJfwh03ilT0k7K/img.png&quot; data-alt=&quot;EEVEE 엔진 &amp;amp;amp; Shade Smooth 적용 후&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GlI1Q/dJMcacDrTko/katlJ6W1RJfwh03ilT0k7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGlI1Q%2FdJMcacDrTko%2FkatlJ6W1RJfwh03ilT0k7K%2Fimg.png&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;674&quot; height=&quot;384&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;576&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;EEVEE 엔진 &amp;amp; Shade Smooth 적용 후&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>blender3d/Shader Nodes</category>
      <author>scarecrow1992</author>
      <guid isPermaLink="true">https://codingfarm.tistory.com/692</guid>
      <comments>https://codingfarm.tistory.com/692#entry692comment</comments>
      <pubDate>Tue, 9 Jun 2026 20:24:47 +0900</pubDate>
    </item>
    <item>
      <title>2. Material Output 노드</title>
      <link>https://codingfarm.tistory.com/691</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.blender.org/manual/en/latest/render/shader_nodes/output/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.blender.org/manual/en/latest/render/shader_nodes/output/index.html&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 소개&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Output 노드는 트리의 마지막에 위치하는 노드이며, 출력을&amp;nbsp; 담당&lt;/li&gt;
&lt;li&gt;여러개를 추가할 수 있지만, 하나만 사용됨&lt;/li&gt;
&lt;li&gt;출력 노드 직전에는 항상 &lt;b&gt;Shader 노드&lt;/b&gt;가 오지만, &lt;b&gt;Material Output&lt;/b&gt;의 &lt;b&gt;Displacement&lt;/b&gt; 는 예외&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 종류&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Material Output&lt;/li&gt;
&lt;li&gt;Light Output&lt;/li&gt;
&lt;li&gt;World Output&lt;/li&gt;
&lt;li&gt;AOV Output&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. Material Output&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;677&quot; data-origin-height=&quot;417&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcGp3L/dJMcajbmHWB/vBS8wEOUE3nB5XkmNNGLV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcGp3L/dJMcajbmHWB/vBS8wEOUE3nB5XkmNNGLV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcGp3L/dJMcajbmHWB/vBS8wEOUE3nB5XkmNNGLV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcGp3L%2FdJMcajbmHWB%2FvBS8wEOUE3nB5XkmNNGLV0%2Fimg.png&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;677&quot; height=&quot;417&quot; data-origin-width=&quot;677&quot; data-origin-height=&quot;417&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3d 모델의 표면에 덧입혀 재질의 출력을 담당하는 노드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;다른 Output 노드들과 달리,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Shader Node&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이외에도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Displacement&lt;/b&gt;를 입력으로 받을 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Surface : 표면에서의 빛 처리&lt;/li&gt;
&lt;li&gt;Volume : 객체 내부의 부피에 대한 빛 처리&lt;/li&gt;
&lt;li&gt;Displacement : 표면의 위치 정보 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) Surface&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;물체의 표면과 빛의 상호작용을 담당&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주로 &lt;b&gt;Principled BSDF&lt;/b&gt;와 같은 &lt;b&gt;Shader Node&lt;/b&gt;의 출력을 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 단순히 &lt;b&gt;색&lt;/b&gt;&amp;nbsp;뿐만 아니라, &lt;b&gt;빛반사/거칠기/금속/굴절/발광&lt;/b&gt; 등의 데이터를 받을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주로 아래의 Shader Node 들과 연결된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Pricipled BSDF : 대부분의 PBR 매터리얼을 구현하기 위해 사용됨&lt;/li&gt;
&lt;li&gt;Diffuse BSDF : 빛을 여러방향으로 고르게 확산시키는 반사 쉐이더&lt;/li&gt;
&lt;li&gt;Glossy BSDF : 거울반사에 사용&lt;/li&gt;
&lt;li&gt;Glass BSDF: 유리의 반사와 굴절&lt;/li&gt;
&lt;li&gt;Transparent BSDF : 표면을 투명하게 통과시&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2) Volume&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 내부의 부피에 대한 빛 처리를 담당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안개, 연기, 구름, 유리, 수면 내부, 발광 매질(용암, 마법...) 등의 빛 처리를 담당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주로 아래의 Shader Node 들과 연결된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Volume Absorption : 빛을 흡수함&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Volume Scatter : 빛을 산란시킴&lt;/li&gt;
&lt;li&gt;Principled Volume : 흡수, 산란, 방출을 통합적으로 제어&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3) Displacement&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표면의 위치를 &lt;b&gt;어떤방향으로, 얼마나 밀어낼지&lt;/b&gt; 결정하며, 굴곡효과를 주기 위해 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;일반적으로 &lt;b&gt;Texture / Noise / Height Map&lt;/b&gt; 등의 노드들이 &lt;b&gt;Displacement&lt;/b&gt; 노드와 연결된 뒤, Output의 Displacement 슬롯으로 연결된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1106&quot; data-origin-height=&quot;770&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/egi4hm/dJMcahrdwXE/QSF7AxoYT6PPRJkDKly7wK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/egi4hm/dJMcahrdwXE/QSF7AxoYT6PPRJkDKly7wK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/egi4hm/dJMcahrdwXE/QSF7AxoYT6PPRJkDKly7wK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fegi4hm%2FdJMcahrdwXE%2FQSF7AxoYT6PPRJkDKly7wK%2Fimg.png&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;1106&quot; height=&quot;770&quot; data-origin-width=&quot;1106&quot; data-origin-height=&quot;770&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1153&quot; data-origin-height=&quot;370&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKlfFz/dJMcageJUjH/KKckYKHtHDP0IX45Tn0s3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKlfFz/dJMcageJUjH/KKckYKHtHDP0IX45Tn0s3k/img.png&quot; data-alt=&quot;왼쪽 : 큐브, 중앙 : subdivde 적용된 큐브, 오른쪽 : subdivision 5 Ico Sphere&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKlfFz/dJMcageJUjH/KKckYKHtHDP0IX45Tn0s3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKlfFz%2FdJMcageJUjH%2FKKckYKHtHDP0IX45Tn0s3k%2Fimg.png&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;1153&quot; height=&quot;370&quot; data-origin-width=&quot;1153&quot; data-origin-height=&quot;370&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;왼쪽 : 큐브, 중앙 : subdivde 적용된 큐브, 오른쪽 : subdivision 5 Ico Sphere&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;geometry의 좌표를 직접 변형하기 때문에, vertex가 섬세하게 나뉘어져 있을수록, 섬세하게 나뉘는것을 볼 수 있으며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주로 subdivision 및 shade smooth 기능과 함께 사용하면 편리하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>blender3d/Shader Nodes</category>
      <author>scarecrow1992</author>
      <guid isPermaLink="true">https://codingfarm.tistory.com/691</guid>
      <comments>https://codingfarm.tistory.com/691#entry691comment</comments>
      <pubDate>Tue, 9 Jun 2026 19:39:09 +0900</pubDate>
    </item>
    <item>
      <title>1. 소개</title>
      <link>https://codingfarm.tistory.com/690</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.blender.org/manual/en/latest/render/shader_nodes/introduction.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.blender.org/manual/en/latest/render/shader_nodes/introduction.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1780994331923&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Introduction - Blender 5.1 Manual&quot; data-og-description=&quot;Previous Shader Nodes&quot; data-og-host=&quot;docs.blender.org&quot; data-og-source-url=&quot;https://docs.blender.org/manual/en/latest/render/shader_nodes/introduction.html&quot; data-og-url=&quot;https://docs.blender.org/manual/en/latest/render/shader_nodes/introduction.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.blender.org/manual/en/latest/render/shader_nodes/introduction.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.blender.org/manual/en/latest/render/shader_nodes/introduction.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;Introduction - Blender 5.1 Manual&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Previous Shader Nodes&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.blender.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Shader Node 란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉐이더 언어나, 컴파일, gpu 자원관리, 선형대수학, 렌더링파이프라인 등, 복잡한 3d 렌더링 지식 없이도 material 이나 특수효과들의 생성/편집을 편리하게 수행하게끔 해주는 기능을 Shader Node라 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3d 모델 위에 덧입혀질 material의 색상이나, 재질, 형상등을 shader node를 통해 설정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 종류&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드는 크게 아래와 같은 범주로 나뉜다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 181px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;역할&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;설명&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;예시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;Input&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;좌표, 오브젝트 정보, UV, 카메라 정보 등 외부/장면 데이터 제공&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;Texture Coordinate, Geometry, Object Info, Attribute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;Texture&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;이미지나 절차적 패턴 생성&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;Image Texture, Noise Texture, Voronoi Texture&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;Color&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;색 보정/색 조합&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;ColorRamp, Hue/Saturation, Mix Color&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;Vector&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;좌표/방향/노멀/범프/디스플레이스먼트 조작&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;Mapping, Bump, Normal Map, Vector Math&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;Converter&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;값 변환, 범위 매핑, 분리/결합, 수학 연산&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;Math, Map Range, Clamp, Separate/Combine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;Shader&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;실제 표면/볼륨/광학 반응 정의&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;Principled BSDF, Glass BSDF, Emission&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;Output&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;최종 머티리얼/월드/라이트 출력&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;Material Output, World Output&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;1. Input을 통해 입력이 접수됨&lt;br /&gt;2. 여러 노드들을 통해 입력값을 가공&lt;br /&gt;3. Shader Node를 통해, 여러 레이어의 결과를 하나로 합침&lt;br /&gt;4. Output Node로 최종 정보를 출력&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 엔진&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;blender3d에서는 주로 &lt;b&gt;EEVEE&lt;/b&gt;와 &lt;b&gt;Cycles&lt;/b&gt; 2종류의 엔진이 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;EEVEE&lt;/b&gt;는 실시간렌더링에 특화된 &lt;b&gt;래스터라이저&lt;/b&gt; 엔진으로, 실시간성이 중요한 게임엔진과 유사하다. 정확한 렌더링 결과보다는 실시간성에 초점을 맞추었다. 최적화를 위해 baking, screen space reflection 등 눈속임이 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Cycles&lt;/b&gt;는 &lt;b&gt;레이트레이싱&lt;/b&gt;을 사용하며, 물리적으로 정확한 렌더링을 수행하는데 특화되어있다. 하지만 한장의 장면을 렌더링 하기 위한 시간과 자원이 &lt;b&gt;EEVEE&lt;/b&gt; 보다 오래 걸리므로, 건축 시각화나 영화처럼 사전 녹화가 가능한 분야에 널리 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사용하기에 따라서, EEVEE &lt;/b&gt;도&amp;nbsp;&lt;b&gt;Cycles&lt;/b&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;&amp;nbsp;&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>blender3d/Shader Nodes</category>
      <author>scarecrow1992</author>
      <guid isPermaLink="true">https://codingfarm.tistory.com/690</guid>
      <comments>https://codingfarm.tistory.com/690#entry690comment</comments>
      <pubDate>Tue, 9 Jun 2026 18:16:52 +0900</pubDate>
    </item>
    <item>
      <title>WebGL과  GLSL</title>
      <link>https://codingfarm.tistory.com/689</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://webglfundamentals.org/webgl/lessons/ko/webgl-fundamentals.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://webglfundamentals.org/webgl/lessons/ko/webgl-fundamentals.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://webgl2fundamentals.org/webgl/lessons/ko/webgl-fundamentals.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://webgl2fundamentals.org/webgl/lessons/ko/webgl-fundamentals.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 소개&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;WebGL&lt;/b&gt;은 브라우저의 &lt;b&gt;&amp;lt;canvas&amp;gt; context&lt;/b&gt;를 통해 GPU를 사용하여 2D/3D 렌더링을 가속하기위한 &lt;b&gt;API&lt;/b&gt; 이다. Scene이나 Camera 같은 추상화된 정보 없으며, 점/선/삼각형을 렌더링 하기 위해 &lt;b&gt;GPU 정점, 쉐이더,텍스처, 상태를 전달&lt;/b&gt;하고 &lt;b&gt;draw call을 실행&lt;/b&gt;하는 저수준기능만을 제공한다. &lt;b&gt;쉐이더&lt;/b&gt;는 GPU의 각 파이프라인에 실행되는 프로그램이며, &lt;b&gt;GLSL&lt;/b&gt;은 이 쉐이더를 작성하기 위한 언이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;WebGL&lt;/b&gt;은&amp;nbsp;&lt;b&gt;WebGL과 WebGL2&amp;nbsp;&lt;/b&gt;두가지 버전으로 나뉘는데, WebGL1의 번거로움을 해결하기 위한 여러 extension들을 WebGL2에서 표준기능으로 포용한 버전에 가깝다. &lt;b&gt;Three.js&lt;/b&gt;의 &lt;b&gt;WebGLRenderer&lt;/b&gt;는 WebGL2를 사용중이며, r163 이후의 버전부터 WebGL1을 지원하지 않는다.(&lt;a href=&quot;https://threejs.org/docs/#WebGLRenderer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크&lt;/a&gt;) 그렇다고&amp;nbsp;&lt;b&gt;WebGL2&lt;/b&gt;가 단순히&amp;nbsp;&lt;b&gt;WebGL1&lt;/b&gt;의 extension들을 공식 기능으로 도입만 한것은 결코 아니다. 특히 UBO나 MRT 관련 기능들을 &lt;b&gt;WebGL1&lt;/b&gt;에서 구현하기 위해서는 수많은 draw call이나 복잡한 shader가 필요하며 이는 성능차이로 이어질 수 있다. 즉, &lt;b&gt;WebGL2&lt;/b&gt;은 &lt;b&gt;WebGL1의&lt;/b&gt; extension을 단순히 포함하기만하는 래퍼로써의 기능이 아닌, 상위호환격인 별도의 API라고 보는것이 옳다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;GLSL(OpenGL Shading Language)&lt;/b&gt;는 OpenGL 계열 그래픽 API에서 GPU Shader를 작성하기 위한 C계열 언어이다. 브라우저라는 한정된 환경에서 효율적인 렌더링을 위해, 경량화된 그래픽 API인 &lt;b&gt;OpenGL ES&lt;/b&gt;를 웹에 맞게 설계한것이 &lt;b&gt;WebGL&lt;/b&gt;이며, 이에따라 shading 언어도 &lt;b&gt;GLSL&lt;/b&gt;을 사용하게되었다. Three.js에서는 &lt;b&gt;GLSL ES&lt;/b&gt;를 사용중이며 기본적으로&amp;nbsp;&lt;b&gt;GLSL ES 1.00&lt;/b&gt;을 사용하되, &lt;b&gt;GLSL ES 3.00&lt;/b&gt;도 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 버전별 정보&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;WebGL1/2와 GLSL ES 1.00/3.00 버전차이에 따른 차이점을 간략히 정리하고자한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1) WebGL1 / 2&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WebGL1의 불편함을 감수하기 위해 제공되던 Extension들을 공식 기능으로 도입한것이 WebGL2이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적으로 VAO가 있으며, vectex attribute에 대한 데이터 관리를 효율적으로 추상화하는데 유용하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 자세한 정보는&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a style=&quot;color: #0070d1; text-align: start;&quot; href=&quot;https://webgl2fundamentals.org/webgl/lessons/ko/webgl1-to-webgl2.html&quot;&gt;링크&lt;/a&gt;에 정리되어 있으며, 주요 차이는 아래와 같이 정리된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;VAO(Vertex Array Object) 지원&lt;/li&gt;
&lt;li&gt;instancing 지원&lt;/li&gt;
&lt;li&gt;MRT(Multi Render Target)&lt;/li&gt;
&lt;li&gt;텍스쳐 타입 명시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;gl.R8. gl.RGBA8, gl.R32F, gl. DEPTH_COMPONENT24 , gl. DEPTH24_STENCIL8...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;UBO(Uniform Buffer Object) 지원&lt;/li&gt;
&lt;li&gt;&amp;nbsp;Transform Feedback : vertex shader의 출력을 버퍼에 저장&lt;/li&gt;
&lt;li&gt;Texture Array ( gl. TEXTURE_2D_ARRAY)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;타일맵, sprite atlas, material array&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;sampler 타입 확대&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780112610969&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;uniform sampler2D colorMap;
uniform isampler2D idMap;
uniform usampler2D objectIdMap;
uniform sampler2DShadow shadowMap;
uniform sampler3D volumeMap;
uniform sampler2DArray arrayMap;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;object picking, clustered lighting, shadow mapping, volume rendering 등에 활용 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2) GLSL ES 1.00 / 3.00&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GLSL ES의 1.00에서 3.00 버전업에 따른 주요 변화는 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) 암묵적 인터페이스에서 명시적인 인터페이스로&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GLSL ES 1.00은 내장상태에 기대 암묵적으로 포용되던 관용구나 셰이더 언어들이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가령, 1.00 버전의 fragment shader 코드는 기본적으로 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1780113720317&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;attribute vec3 position;
varying vec2 vUv;

void main() {
  gl_FragColor = vec4(1.0);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드에서는 여러 정보들 언어차원에서 사실상 고정되어있다. 가령&amp;nbsp;&lt;b&gt;gl_FragColor&lt;/b&gt; 또는 &lt;b&gt;gl_FragData&lt;/b&gt;이다. 또한 vertex input은 attribute, stage간 전달은 varying, 텍스쳐 샘플링은&amp;nbsp;&lt;b&gt;texture2D, &lt;/b&gt;&lt;b&gt;textureCube&lt;/b&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;하지만 3.00 버전의 shader 코드는 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1780113814551&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#version 300 es
layout(location = 0) in vec3 position;

out vec2 vUv;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1780113824860&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#version 300 es
precision highp float;

in vec2 vUv;

layout(location = 0) out vec4 outColor;
layout(location = 1) out vec4 outNormal;

void main() {
  outColor = vec4(1.0);
  outNormal = vec4(0.0, 0.0, 1.0, 1.0);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정해진 이름의 내장 변수(&lt;b&gt;gl_FragColor&lt;/b&gt;)에 쓰는 방식이 아닌, 셰이더가 자신의 입출력 인터페이스를 직접 선언하는 방식으로 바뀌었음이 확인된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GLSL ES 3.00은 고정적이고 관례적인 작성법을 탈피하여, 셰이더코드가 더 많은 GPU리소스 파이프라인 기능을 명확하게 표현하도록 탈바꿈되었음을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2)&amp;nbsp; 색 계산이 아닌 데이터 연산 중심으로&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.00은 화면에 표기하기 위한 색상 출력에 집중되어 있다. 그렇기에 fragment shader의 최종 출력값도 사실상 &lt;b&gt;gl_FragColor&lt;/b&gt;로 고정되며, 데이터 표현도 float vector 중심이다.&lt;br /&gt;(vec2, vec3, vec4, sampler2D, samplerCube)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.00은 색상 계산만이 아닌, GPU기반 데이터연산 중심으로 발전하였으며, 보다 다양한 데이터 타입과 연산들을 지원한다.&lt;br /&gt;(uint, uvec2, uvec3, uvec4, isampler2D, sampler3D, sampler2DArray, bitwise Operation, texelFetch, textureSize, uniform blocks...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 기존 1.00 에서는 색상/좌표/법선과 같은 그래픽 데이터 중심이었다면, 3.00에서는 Id, index, 플래그, 레이어, uniform block 등 다양한 데이터에 대한 연산을 중심으로 확장되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가령 1.00에서는 picking을 위해 id를 vec4 타입의 색상정보로 우회 표기해야했다.&lt;/p&gt;
&lt;pre id=&quot;code_1780114691312&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;gl_FragColor = vec4(encodedIdColor);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만3.00에서는 직접적으로 정수데이터를 다룰 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1780114701958&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#version 300 es
precision highp float;
precision highp usampler2D;

flat in uint vObjectId;

layout(location = 0) out uint outObjectId;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 int형 render target을 쓰기 위해서는 texture/render target 포맷 framebuffer 조건도 맞는 등 여러 조건이 따라오지만, 철학자체는 그래픽 렌더링(float only)에 그치지 않고, 범용 데이터 연산 방식으로 옮겨졌음을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.00과 3.00의 주요 차이는 아래와 같이 정리될 수 있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 79.0698%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7519%;&quot;&gt;GLSL ES 1.00&lt;/td&gt;
&lt;td style=&quot;width: 23.5659%;&quot;&gt;GLSL ES 3.00&lt;/td&gt;
&lt;td style=&quot;width: 32.7519%;&quot;&gt;목표&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7519%;&quot;&gt;attribute&lt;/td&gt;
&lt;td style=&quot;width: 23.5659%;&quot;&gt;in&lt;/td&gt;
&lt;td style=&quot;width: 32.7519%;&quot;&gt;stage input 일반화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7519%;&quot;&gt;varying&lt;/td&gt;
&lt;td style=&quot;width: 23.5659%;&quot;&gt;out / in&lt;/td&gt;
&lt;td style=&quot;width: 32.7519%;&quot;&gt;stage 간 인터페이스 일반화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7519%;&quot;&gt;gl_FragColor&lt;/td&gt;
&lt;td style=&quot;width: 23.5659%;&quot;&gt;사용자 정의 out&lt;/td&gt;
&lt;td style=&quot;width: 32.7519%;&quot;&gt;출력 타겟 명시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7519%;&quot;&gt;texture2D, textureCube&lt;/td&gt;
&lt;td style=&quot;width: 23.5659%;&quot;&gt;texture&lt;/td&gt;
&lt;td style=&quot;width: 32.7519%;&quot;&gt;sampler 기반 함수 오버로드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.7519%;&quot;&gt;gl_FragData[i]&lt;/td&gt;
&lt;td style=&quot;width: 23.5659%;&quot;&gt;layout (location) out&lt;/td&gt;
&lt;td style=&quot;width: 32.7519%;&quot;&gt;MRT 출력 명시&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. WebGL과 GLSL&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WebGL은 GPU를 통해 점/선/면을 그리거나 일반 데이터를 연산하기 위한 API 이며, GLSL은 GPU에서 동작하는 프로그램을 작성하는 언어이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 둘은 함께 사용되어야만 하는 관계이므로 버전별 호환성이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WebGL과 GLSL 간의 버전 호환은 간단히 아래와 같이 정리될 수 있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;컨텍스트&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;GLSL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;WebGL1&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;GLSL ES 1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;WebGL2&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;GLSL ES 1.00 &amp;amp; 3.00&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실상 WebGL1은 GLSL ES 1.00 호환되며, WebGL2는 GLSL ES 3.00과 호환된다고 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WebGL2도 GLSL ES 1.00 을 사용 가능하지만, WebGL2의 여러 기능들 (UBO, MRT 등)을 본격적으로 쓰기 위해선 3.00 사용이 권장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-1) Three.js 환경&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Three.js&lt;/b&gt; 의 THREE.WebGLRenderer는 WebGL2만을 지원한다. 하지만 three.js에 내장된 MeshStandardMaterial와 MeshPhysicalMaterial 등의 매터리얼등은 &lt;b&gt;GLSL ES 1.00&lt;/b&gt; 으로 작성되었다. 또한 &lt;b&gt;THREE.ShaderMaterial&lt;/b&gt;과 &lt;b&gt;THREE.RawShaderMaterial&lt;/b&gt;도 &lt;b&gt;glslVersion: THREE.GLSL3&lt;/b&gt; 옵션을 넘기지 않는다면, 1.00버전으로 컴파일된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 ShaderMaterial을 3.00으로 생성하여도, 1.00 과 마찬가지로 기본적인 uniform 이나 attribute 정보들은 Three.js가 직접 전달해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[THREE.ShaderMaterial - 1.00]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1780116707433&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const material = new THREE.ShaderMaterial({
  vertexShader: `
    attribute vec3 position;
    attribute vec3 normal;
    attribute vec2 uv;

    uniform mat4 modelViewMatrix;
    uniform mat4 projectionMatrix;

    varying vec2 vUv;

    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    precision highp float;

    varying vec2 vUv;

    void main() {
      gl_FragColor = vec4(vUv, 0.0, 1.0);
    }
  `
});&lt;/code&gt;&lt;/pre&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;[THREE.ShaderMaterial - 3.00]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1780116731505&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const material = new THREE.ShaderMaterial({
  glslVersion: THREE.GLSL3,

  vertexShader: `
    in vec3 position;
    in vec3 normal;
    in vec2 uv;

    uniform mat4 modelViewMatrix;
    uniform mat4 projectionMatrix;

    out vec2 vUv;

    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,

  fragmentShader: `
    precision highp float;

    in vec2 vUv;
    out vec4 outColor;

    void main() {
      outColor = vec4(vUv, 0.0, 1.0);
    }
  `
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 ShaderMaterial 이나 RawShaderMaterial 을 통해 쉐이더를 직접 생성할 경우, 가급적 ES 3.00 버전으로 생성하고 해당 양식에 맞추어 작성하는것이 권장되나,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;built-in material에서 shader chunk를 통해 replace 하는 방식으로 shader 코드를 가공한다면, ES 1.00 버전을 기준으로 작성해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>computer graphics/Three.js</category>
      <author>scarecrow1992</author>
      <guid isPermaLink="true">https://codingfarm.tistory.com/689</guid>
      <comments>https://codingfarm.tistory.com/689#entry689comment</comments>
      <pubDate>Sat, 30 May 2026 14:00:11 +0900</pubDate>
    </item>
    <item>
      <title>1. WebGL2 기본 API 정리</title>
      <link>https://codingfarm.tistory.com/686</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://webgl2fundamentals.org/webgl/lessons/ko/webgl-fundamentals.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://webgl2fundamentals.org/webgl/lessons/ko/webgl-fundamentals.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://webgl2fundamentals.org/webgl/lessons/resources/webgl-state-diagram.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://webgl2fundamentals.org/webgl/lessons/resources/webgl-state-diagram.html&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;WebGL2 초기화 및 렌더링 사이클을 위한 기본적인 API 사용방법 및 자주 사용되는 패턴들을 내 나름대로 정리해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹/게임을 가리지않고 개발이란 결국 데이터를 읽고, 쓰고, 만들고, 지우는 과정의 반복이라 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 Webgl2의 주요 리소스들을 CRUD 관점에 맞추어 API를 정리하였다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 101.163%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.64348%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 18.1589%;&quot;&gt;program&lt;/td&gt;
&lt;td style=&quot;width: 13.6207%;&quot;&gt;shader&lt;/td&gt;
&lt;td style=&quot;width: 14.7127%;&quot;&gt;vertex array&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;buffer&lt;/td&gt;
&lt;td style=&quot;width: 17.8295%;&quot;&gt;texture&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.64348%;&quot;&gt;생성&lt;/td&gt;
&lt;td style=&quot;width: 18.1589%;&quot;&gt;createProgram&lt;/td&gt;
&lt;td style=&quot;width: 13.6207%;&quot;&gt;createShader&lt;/td&gt;
&lt;td style=&quot;width: 14.7127%;&quot;&gt;createVertexArray&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;createBuffer&lt;/td&gt;
&lt;td style=&quot;width: 17.8295%;&quot;&gt;createTexture&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.64348%;&quot;&gt;바인&lt;/td&gt;
&lt;td style=&quot;width: 18.1589%;&quot;&gt;linkProgram&lt;/td&gt;
&lt;td style=&quot;width: 13.6207%;&quot;&gt;attachShader&lt;br /&gt;detachShader&lt;/td&gt;
&lt;td style=&quot;width: 14.7127%;&quot;&gt;bindVertexArray&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;bindBuffer&lt;/td&gt;
&lt;td style=&quot;width: 17.8295%;&quot;&gt;bindTexture&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.64348%;&quot;&gt;작업&lt;/td&gt;
&lt;td style=&quot;width: 18.1589%;&quot;&gt;uniform1i&lt;br /&gt;uniform3fv&lt;br /&gt;uniformMatrix4fv&lt;br /&gt;uniformMatrix4fv&lt;/td&gt;
&lt;td style=&quot;width: 13.6207%;&quot;&gt;shaderSource&lt;br /&gt;compileShader&lt;/td&gt;
&lt;td style=&quot;width: 14.7127%;&quot;&gt;vertexAttribPointer&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;bufferData&lt;/td&gt;
&lt;td style=&quot;width: 17.8295%;&quot;&gt;texImage2D&lt;br /&gt;texParameteri&lt;br /&gt;generateMipmap&lt;br /&gt;activeTexture&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.64348%;&quot;&gt;참조&lt;/td&gt;
&lt;td style=&quot;width: 18.1589%;&quot;&gt;getAttribLocation&lt;br /&gt;getUniformLocation&lt;/td&gt;
&lt;td style=&quot;width: 13.6207%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.7127%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 17.8295%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.64348%;&quot;&gt;제거&lt;/td&gt;
&lt;td style=&quot;width: 18.1589%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 13.6207%;&quot;&gt;deleteShader&lt;/td&gt;
&lt;td style=&quot;width: 14.7127%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 17.8295%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;gpu 자원과 cpu 자원을 별도의 함수로 순차적으로 호출하고, 작업을 진행하는 방식이 다소 비직관적이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가령 buffer와 attribute를 한데 묶어서 호출하는 방식이 아니라, 전역 상태에 원하는 리소스를 먼저 바인딩하고(bindBuffer), 이에 대한 작업 함수를 호출하는 방식(bufferData)이라 다소 비직관적이게 느껴젔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 global 하게 관리되는 webgl 상태가 존재하고, 해당 상태에 설정된 대상에 대해 작업을 수행한다는 발상으로 접근하니 어느정도 이해가 갔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결정적으로 두번째 링크에서 매 코드 라인마다 webgl의 상태를 다이어그램으로 가시화해주었기 때문에 코드를 이해하기 한결 간편했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Shader와 Program&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정점의 위치를 계산하기 위한 vertex shader와 각 픽셀의 색상을 결정하는 fragment shader의 쌍으로 구성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vertex는 각 정점에 대해 수행되며, 이들로부터 보간된 데이터가 fragment shader로 전달된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;988&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGVWpo/dJMcaibP7UN/sjrThedku8hxKTLeTyazFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGVWpo/dJMcaibP7UN/sjrThedku8hxKTLeTyazFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGVWpo/dJMcaibP7UN/sjrThedku8hxKTLeTyazFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGVWpo%2FdJMcaibP7UN%2FsjrThedku8hxKTLeTyazFK%2Fimg.png&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;800&quot; height=&quot;988&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;988&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vertex shader는 GPU에 존재하는 데이터만 읽을 수 있으며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 보내는 방법은 아래와 같다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) Attribute, Buffer, Vertex Array&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;414&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Kl3nh/dJMcafTHSFp/C7AkdSMRyyZ6q33VIkyYx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Kl3nh/dJMcafTHSFp/C7AkdSMRyyZ6q33VIkyYx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Kl3nh/dJMcafTHSFp/C7AkdSMRyyZ6q33VIkyYx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKl3nh%2FdJMcafTHSFp%2FC7AkdSMRyyZ6q33VIkyYx1%2Fimg.png&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;904&quot; height=&quot;414&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;414&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vertex shader에서 in 예약어로 정의되는 변수에 대응되는 데이터이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 vertex 마다 할당 되어야 하는 데이터들이 전달되며,&amp;nbsp; vertex 자체의 위치, 법선, uv 좌표, 색상 등의 정보를 전달한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Buffer:&amp;nbsp;GPU에 올라가는 바이너리 데이터 배열이다. 일반적으로 각 정점에 대한 실제 정보들이 전달되며 주로 위치, 법선, uv 좌표, 색상 등이 전달된다.&lt;/li&gt;
&lt;li&gt;Attribute:&amp;nbsp;버퍼에서 데이터를 읽어 오기 위한 일종의 명세이다. 타입, 위치, 이동수치 등의 데이터가 attribute에 보관된다.&lt;/li&gt;
&lt;li&gt;VAO(Vertex Array Object) :&amp;nbsp;각각의 attribute가 사용할 버퍼가 무엇인지, 버퍼로부터 데이터를 어떻게 추출할지, location 정보가 어떻게 되는지 등, attribute의 상태가 저장된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버퍼는 랜덤 접근이 불가능하며, attribute에서 지정한 크기만큼 vertex shader에 전달된다.&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;사실 webgl 코드에서는 attribute는 별도의 create api가 주어지지 않기에 그 실체가 모호한 기분이며, 이름 그대로 속성(Attribute)처럼 다가온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 program에서 attribute info는 &lt;b&gt;gl.linkProgram&lt;/b&gt; 호출시점에 shader 코드의 상태에 따라 결정되고, 개발자는 해당 info에 맞추어 shader에 전달하기 위한 데이터를 &lt;b&gt;buffer&lt;/b&gt;에 담고, 해석 정보를&amp;nbsp;&lt;b&gt;vertex array&lt;/b&gt;에 구현하면 될 뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;attribute&lt;/b&gt;에 데이터를 전달하는 스켈레톤 코드는 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1775563821342&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const positionLoc = gl.getAttribLocation(prg, 'position');

// vertex positions for a cube
const cubeVertexPositions = new Float32Array([
    1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1,
]);


const cubeVertexArray = gl.createVertexArray();
gl.bindVertexArray(cubeVertexArray);

const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, cubeVertexPositions, gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionLoc);
gl.vertexAttribPointer(
    positionLoc,  // location
    3,            // size (components per iteration)
    gl.FLOAT,     // type of to get from buffer
    false,        // normalize
    0,            // stride (bytes to advance each iteration)
    0,            // offset (bytes from start of buffer)
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 쉐이더 코드를 보면 position 은 vec4로 선언되었고, attribute info 도 분명 FLOAT_VEC4 타입인데, 정작 vertex array에는 size 3으로 설정되었다. 행렬 계산을 위해선, 배열로부터 translate의 영향을 받기 위해 마지막 원소가 자동으로 1로 채워져야 할것같은데, 해당 부분은 정확한 확인이 필요할것같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) Uniform&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 셰이더 프로그램이 동시 참조하는 전역변수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가령 &quot;각각의 vertex에 대한 좌표&quot; 정보는 vertex마다 다른 정보이므로 attribute로 전달되어야 하지만, &quot;모델의 transform matrix&quot;는 모든 vertex가 동시에 참조해도 충분하므로 Uniform으로 전달하면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;uniform 은 데이터가 이진데이터와 비이진데이터로 크게 2가지로 나뉜다,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-1) binary uniform&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;554&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vT6bL/dJMcadarN85/gk0DkobjoblQsMcZ3AJzwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vT6bL/dJMcadarN85/gk0DkobjoblQsMcZ3AJzwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vT6bL/dJMcadarN85/gk0DkobjoblQsMcZ3AJzwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvT6bL%2FdJMcadarN85%2Fgk0DkobjoblQsMcZ3AJzwk%2Fimg.png&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;276&quot; height=&quot;554&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;554&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이진 배열의 형태로 표현 가능한 데이터. 주로 transform matrix, light intensity, light dir 등의 정보가 전달된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다이어그램 상으로는 program 내에 직접 보관되는것으로 보이며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비교적 간단한 절차로 설정할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1775564348706&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const modelViewLoc = gl.getUniformLocation(prg, 'modelView');
gl.uniformMatrix4fv(modelViewLoc, false, modelView);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다이어그램 상으로는 localtion이 안보이지만, &lt;b&gt;getUniformLocation&lt;/b&gt; 함수로 봐선 실제 location 자체는 존재하는것으로 고려된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;절차가 간단한 만큼, 매 렌더링 마다 달라질 수 있는 데이터를 전달하는데에도 적합해보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(transform 데이터 등)&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-2) non-birary uniform (Texture)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1019&quot; data-origin-height=&quot;932&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d8J2Tj/dJMcaaESCCZ/yFrAdvvbNSMkzOmcFXwzkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d8J2Tj/dJMcaaESCCZ/yFrAdvvbNSMkzOmcFXwzkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d8J2Tj/dJMcaaESCCZ/yFrAdvvbNSMkzOmcFXwzkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd8J2Tj%2FdJMcaaESCCZ%2FyFrAdvvbNSMkzOmcFXwzkk%2Fimg.png&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;1019&quot; height=&quot;932&quot; data-origin-width=&quot;1019&quot; data-origin-height=&quot;932&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이진 배열 형태로 표현 불가능한 데이터들이며, 주로 diffuse, ao, normal 등의 텍스처 정보들이 전달된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 특수성 때문에 리소스 자체는 webgl에 의해 직접 관리되며, program에서는 location으로 간접 참조하는 방식으로 접근하는것으로 보인다.&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;webgl에 bind&lt;/li&gt;
&lt;li&gt;uniform 로케이션 맵&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1775565058487&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 1. 텍스처 생성
const checkerTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, checkerTexture);
gl.texImage2D(
    gl.TEXTURE_2D,
    0,                // mip level
    gl.LUMINANCE,     // internal format
    4,                // width
    4,                // height
    0,                // border
    gl.LUMINANCE,     // format
    gl.UNSIGNED_BYTE, // type
    new Uint8Array([  // data
      192, 128, 192, 128,
      128, 192, 128, 192,
      192, 128, 192, 128,
      128, 192, 128, 192,
    ]));
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

// 2. webgl 등록
const diffuseLoc = gl.getUniformLocation(prg, 'diffuse');
let texUnit = 6;
gl.activeTexture(gl.TEXTURE0 + texUnit);
gl.bindTexture(gl.TEXTURE_2D, checkerTexture);

// 3. uniform location 맵핑
gl.uniform1i(diffuseLoc, texUnit);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;webgl2fundamentals 문서에서는 각각 uniform과 texture라는 별도의 방법으로 안내해주긴 하지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;shader 코드상에서는 uniform으로 전달되고, 코드상에서도 간접적으로나마 참조되기 때문에 하나의 범주로 묶어 정리하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3) varying&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한마디로, vertex shader(out)에서 fragment shader(in)로 보내는 값이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 데이터는 해당 픽셀이 속한 폴리곤을 구성하는 3개의 vertex로부터 보간되어 내려보내진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WebGL 1.0 에서는 varying 을 사용하지만, 최신 OpenGL/ WebGL2.0 에서는 in/out 키워드로 대체되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용법은 그냥 직관적으로 shader내에서 사용하면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 vertex/fragment 양측 쉐이더에서 동일한 이름과 형식을 사용해야한다.&lt;/p&gt;
&lt;pre id=&quot;code_1775565544318&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 버텍스 셰이더
varying vec3 vColor; // 프래그먼트로 전달할 변수
attribute vec3 aColor;

void main() {
    vColor = aColor; // 속성값을 varying에 할당
    gl_Position = ...;
}

// 프래그먼트 셰이더
varying vec3 vColor; // 버텍스에서 보간된 값을 받음

void main() {
    gl_FragColor = vec4(vColor, 1.0); // 보간된 색상 적용
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>computer graphics/WebGL</category>
      <author>scarecrow1992</author>
      <guid isPermaLink="true">https://codingfarm.tistory.com/686</guid>
      <comments>https://codingfarm.tistory.com/686#entry686comment</comments>
      <pubDate>Tue, 7 Apr 2026 21:46:21 +0900</pubDate>
    </item>
    <item>
      <title>Feature-Sliced Design (FSD)</title>
      <link>https://codingfarm.tistory.com/683</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://feature-sliced.design/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://feature-sliced.design/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 소개&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Feature-Sliced Design(FSD)&lt;/b&gt;는 대규모 프론트엔드 애플리케이션을 &lt;b&gt;기능 중심(Feature-Driven)&lt;/b&gt; 으로 구조화 하는 아키텍쳐 방법론이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;핵심 철학&lt;br /&gt;파일을 기술(components, hooks) 기준이 아니라 &lt;b&gt;비즈니스 기능 기준&lt;/b&gt;으로 나눈다.&lt;/blockquote&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;pre id=&quot;code_1771048363837&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/components
/hooks
/pages
/utils
/store&lt;/code&gt;&lt;/pre&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;컴포넌트 하나를 구성하는 요소들이 여러 폴더에 산재됨&lt;/li&gt;
&lt;li&gt;기능 하나를 수정하기 위해 여러 폴더를 오가야함&lt;/li&gt;
&lt;li&gt;재사용 경계가 모호&lt;/li&gt;
&lt;li&gt;기능 단위 분리가 어려움&lt;/li&gt;
&lt;/ul&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;span style=&quot;color: #333333; text-align: start;&quot;&gt;대규모 프로젝트의 핵심은&lt;b&gt;&lt;span&gt; 갈수록&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;복잡해지는 의존성 문제를 어떻게 풀어낼것인가&lt;/b&gt;에 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FSD는 이를 해결하기 위해&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;상위에서 하위로 &lt;b&gt;순방향 참조&lt;/b&gt;를 가진 레이어를 구성하고&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기능 중심&lt;/b&gt;으로 구조를 설계하여&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구조를 무너뜨리지&lt;/b&gt; 않고, &lt;b&gt;순환참조를 방지&lt;/b&gt;하며, &lt;b&gt;확장성을 유지&lt;/b&gt;할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 구조&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1030&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwUoxa/dJMcajnAk2b/GLc181sWOV2346Ca0Epkm1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwUoxa/dJMcajnAk2b/GLc181sWOV2346Ca0Epkm1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwUoxa/dJMcajnAk2b/GLc181sWOV2346Ca0Epkm1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwUoxa%2FdJMcajnAk2b%2FGLc181sWOV2346Ca0Epkm1%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;1030&quot; height=&quot;573&quot; data-origin-width=&quot;1030&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FSD는&amp;nbsp; 레이어(Layer), 슬라이스(Slice) 그리고 세그먼트(Segments)으로 프로젝트를 구성한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. 레이어(Layer)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 레이어는 &lt;b&gt;의존성이 단방향&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 레이어는 상위 레이어를 몰라도 되지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상위 레이어는 하위 레이어를 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;상위 레이어는 하위 레이어를 포함&lt;/b&gt;한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;app &amp;rarr; pages &amp;rarr; widgets &amp;rarr; features &amp;rarr; entities &amp;rarr; shared&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;p data-ke-size=&quot;size16&quot;&gt;총 7개로 구성된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;App&lt;/b&gt; - 앱을 실행하는 모든것 (라우팅, 진입점, 글로벌 스타일, provider 등)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Process(deprecated)&lt;/b&gt; - 복잡한 페이지 내부 시나리오&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Pages&lt;/b&gt; - 전체 페이지 또는 중첩된 라우팅 방식의 페이지 일부&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Widgets&lt;/b&gt; - 큰 독립형 기능 덩어리나 UI, 전체 use case를 제공&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Features&lt;/b&gt; - 사용자에게 비즈니스 가치를 제공하는 행동 단위&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Entities&lt;/b&gt; - 비즈니스 엔티티 (User, Product 등)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Shared&lt;/b&gt; - 재사용 가능한 기능&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) app - 앱 초기화 레이어&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;역할&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;라우팅 설정&lt;/li&gt;
&lt;li&gt;전역 스타일&lt;/li&gt;
&lt;li&gt;전역 Provider&lt;/li&gt;
&lt;li&gt;스토어 세팅&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예:&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1771065040287&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app/
  providers/
  router/
  index.tsx&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2) pages - 페이지 단위&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;URL 단위 화면&lt;/li&gt;
&lt;li&gt;여러 widget을 조합하여 페이지를 구성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예:&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1771065109544&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pages/
  login/
  profile/
  dashboard/&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3) widgets - 복합 UI 블록&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 feature + entity를 조합 하여 UI 블록을 구성한다.&lt;/li&gt;
&lt;li&gt;독립적인 화면 블록&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예:&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1771065186368&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;widgets/
  header/
  sidebar/
  post-list/&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4) features - 사용자 액션 단위&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자가 할 수 있는 동작 단위&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;로그인 하기&lt;/li&gt;
&lt;li&gt;게시글 좋아요 누르기&lt;/li&gt;
&lt;li&gt;댓글 작성하기&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1771065861638&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;features/
  auth/
  add-comment/
  like-post/&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5) entities - 비즈니스 도메인 객체&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제 데이터 모델 단위&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;User&lt;/li&gt;
&lt;li&gt;Post&lt;/li&gt;
&lt;li&gt;Comment&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6) shared - 공통 코드&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1529&quot; data-start=&quot;1521&quot;&gt;UI kit&lt;/li&gt;
&lt;li data-end=&quot;1537&quot; data-start=&quot;1530&quot;&gt;유틸 함수&lt;/li&gt;
&lt;li data-end=&quot;1549&quot; data-start=&quot;1538&quot;&gt;API 클라이언트&lt;/li&gt;
&lt;li data-end=&quot;1557&quot; data-start=&quot;1550&quot;&gt;공통 타입&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1771068324886&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;shared/
  ui/
  lib/
  api/
  config/&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2. Slices (슬라이스)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각각의 레이어를 기능 단위(Slice)로 나눈것&lt;/li&gt;
&lt;li&gt;코드를 비즈니스 도메인별로 분할함으로써, 폴더명을 자유롭게 설정 가능&lt;/li&gt;
&lt;li&gt;Slice 간에는 상호 참조가 불가능해야한다. (높은 응집력, 낮은 결합)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예 : features 레이어의 auth 슬라이스&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1771068559879&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;features/
  auth/
    ui/
    model/
    api/
    lib/&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-3. Segments(세그먼트)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;세그먼트 상위 레이어들은 파일을 &lt;b&gt;기능(feature)&lt;/b&gt; 단위로 분류했지만, 세그먼트는 &lt;b&gt;기술&lt;/b&gt; 단위로 분류한다.&lt;/li&gt;
&lt;li&gt;세그먼트끼리는 상호 참조가 가능하다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;사실상 레이어를 구성하는 최소 단위이며, 분류는 표준화되어있다.&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;span style=&quot;letter-spacing: 0px;&quot;&gt;세그먼트 종류&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ui : UI 디스플ㄹ레이와 관련된 모든것 (UI 컴포넌트, 날짜 포맷터, 스타일 등)&lt;/li&gt;
&lt;li&gt;api : 백엔드 상호작용 코드&lt;/li&gt;
&lt;li&gt;model : 데이터 모델 (스키마, 인터페이스, 저장소, 비즈니스 로직)&lt;/li&gt;
&lt;li&gt;lib : 이 슬라이스의 다른 모듈들이 필요로 하는 라이브러리 코드&lt;/li&gt;
&lt;li&gt;config : 구성 파일과 기능 플래&lt;/li&gt;
&lt;/ul&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;&amp;nbsp;&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;&amp;nbsp;&lt;/p&gt;</description>
      <author>scarecrow1992</author>
      <guid isPermaLink="true">https://codingfarm.tistory.com/683</guid>
      <comments>https://codingfarm.tistory.com/683#entry683comment</comments>
      <pubDate>Sat, 14 Feb 2026 20:43:09 +0900</pubDate>
    </item>
  </channel>
</rss>