diff --git a/README.md b/README.md index 9caa5dd0584590afe2500a56d24234bee40d57d7..7fddaa5bf1e675a1e05d76db736f36800d8d6c91 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# Hello WebGL 2.0 : Using WebGL 2.0 to Implement Fluid Simulation +# Hello WebGL 2.0: Using WebGL 2.0 to Implement Fluid Simulation <div align="center"> <img src="./assets/screenshot.jpg"></img> - <h4 align="center">Hello WebGL 2.0 : Using WebGL 2.0 to Implement Fluid Simulation</h4> + <h4 align="center">Hello WebGL 2.0: Using WebGL 2.0 to Implement Fluid Simulation</h4> <p align="center"> <img src="http://img.shields.io/badge/-WebGL2-990000?style=flat&logo=WebGL&link=https://github.com/htcrefactor/WebGL-Fluid-Simulation"/> <img src="http://img.shields.io/badge/-HTML-E34F26?style=flat&logo=HTML5&link=https://github.com/htcrefactor/WebGL-Fluid-Simulation"/> @@ -37,7 +37,7 @@ - Khronos Group의 WebGL 2.0 Specification에 대한 추적 ## WebGL1과 WebGL2의 차이 -### `getContext`를 호출할 때 `webgl` 대신 `webgl2` 사용 +### 1. `getContext`를 호출할 때 `webgl` 대신 `webgl2` 사용 ```javascript // WebGL1 var gl = canvas.getContext('webgl'); @@ -46,10 +46,10 @@ var gl = canvas.getContext('webgl'); var gl = canvas.getContext('webgl2'); ``` -### 부동 소수점 프레임버퍼 추가 +### 2. 부동 소수점 프레임버퍼 추가 WebGL1에선 부동 소수점 텍스처를 지원하는지 확인하기 위해 `OES_texture_float`를 활성화 한 후 부동 소수점 텍스처를 생성하고 프레임버퍼에 추가해 `gl.checkFramebufferStatus`를 호출해 `gl.FRAMEBUFFER_COMPLETE`를 반환하는지 확인해야 했어요. -WebGL2에서 `gl.checkFramebufferStatus`로 부터 `gl.FRAMEBUFFER_COMPLETE`를 반환받기 위해선 `EXT_color_buffer_float`를 허용해주세요. +WebGL2에서 `gl.checkFramebufferStatus`로 부터 `gl.FRAMEBUFFER_COMPLETE`를 반환받기 위해선 `EXT_color_buffer_float`를 허용해주세요. [공식 문서 보러 가기](https://www.khronos.org/registry/webgl/specs/latest/2.0/#4.1.5) `HALF_FLOAT` 프레임버퍼에도 동일하게 적용해주세요! @@ -75,7 +75,7 @@ function getWebGLContext(canvas) { } ``` -### WebGL1 확장의 WebGL2 표준화 +### 3. WebGL1 확장의 WebGL2 표준화 아래 확장들이 표준에 편입됐어요. - Depth Textures (`WEBGL_depth_texture`) - Floating Point Textures (`OES_texture_float/OES_texture_float_linear`) @@ -104,7 +104,7 @@ if (!ext) { var someVAO = gl.createVertexArray(); ``` -### `GLSL 300 es` 사용 +### 4. `GLSL 300 es` 사용 사용하는 쉐이더를 GLSL 3.00 ES로 업그레이드 하면 좋다. 그러기 위해선 쉐이더 선언의 첫 줄이 `#version 300 es`야 해요. 반드시 첫 줄이여야 하기 때문에 주석이나 개행이 이루어지면 안돼요. ```javascript @@ -121,7 +121,7 @@ var vertexShaderSource = `#version 300 es `; ``` -#### `attribute` 대신 `in` 사용 +#### 4-1. `attribute` 대신 `in` 사용 ```javascript // WebGL1 attribute vec4 a_position; @@ -134,7 +134,7 @@ in vec2 a_texcoord; in vec3 a_normal; ``` -#### `varying` 대신 `in/out` 사용 +#### 4-2. `varying` 대신 `in/out` 사용 ```javascript // WebGL1 varying vec2 v_texcoord; @@ -150,7 +150,7 @@ in vec2 v_texcoord; in vec3 v_normal; ``` -#### `gl_FragColor` 대신 원하는 변수명 사용 가능 +#### 4-3. `gl_FragColor` 대신 원하는 변수명 사용 가능 ```javascript // WebGL1 gl_FragColor = vec4(1, 0, 0, 1); // red @@ -163,7 +163,7 @@ void main() { } ``` -#### `texture2D` 대신 `texture` 사용 +#### 4-4. `texture2D` 대신 `texture` 사용 ```javascript // WebGL1 vec4 color1 = texture2D(u_some2DTexture, ...); @@ -175,10 +175,67 @@ vec4 color2 = texture(u_someCubeTexture, ...); ``` 더 자세한 내용이 궁금하다면? [공식 문서 보러 가기](https://khronos.org/registry/webgl/specs/latest/2.0/#4.3) -### Non-Power-of-Two 텍스처의 사용 허용 -WebGL 1.0 API와 다르게, WebGL 2.0에서는 non power of 2 텍스처를 사용할 수 있어요. 다양한 mipmapping 기능과 wrapping mode를 사용할 수 있어요. [공식 문서 보러 가기](https://www.khronos.org/registry/webgl/specs/latest/2.0/#4.1.3) - +### 5. Non-Power-of-Two 텍스처의 사용 허용 +WebGL 1.0 API와 다르게, WebGL 2.0에서는 non-power-of-two 텍스처를 사용할 수 있어요. 다양한 mipmapping 기능과 wrapping mode를 사용할 수 있어요. [공식 문서 보러 가기](https://www.khronos.org/registry/webgl/specs/latest/2.0/#4.1.3) + +### 6. 새로 추가된 텍스처 포맷 +<details> +<summary>무려 52가지나! 궁금하면 클릭해서 열어보기</summary> + +- `RGBA32I` +- `RGBA32UI` +- `RGBA16I` +- `RGBA16UI` +- `RGBA8` +- `RGBA8I` +- `RGBA8UI` +- `SRGB8_ALPHA8` +- `RGB10_A2` +- `RGB10_A2UI` +- `RGBA4` +- `RGB5_A1` +- `RGB8` +- `RGB565` +- `RG32I` +- `RG32UI` +- `RG16I` +- `RG16UI` +- `RG8` +- `RG8I` +- `RG8UI` +- `R32I` +- `R32UI` +- `R16I` +- `R16UI` +- `R8` +- `R8I` +- `R8UI` +- `RGBA32F` +- `RGBA16F` +- `RGBA8_SNORM` +- `RGB32F` +- `RGB32I` +- `RGB32UI` +- `RGB16F` +- `RGB16I` +- `RGB16UI` +- `RGB8_SNORM` +- `RGB8I` +- `RGB8UI` +- `SRGB8` +- `R11F_G11F_B10F` +- `RGB9_E5` +- `RG32F` +- `RG16F` +- `RG8_SNORM` +- `R32F` +- `R16F` +- `R8_SNORM` +- `DEPTH_COMPONENT32F` +- `DEPTH_COMPONENT24` +- `DEPTH_COMPONENT16` +</details> ## License ### MIT License @@ -192,14 +249,13 @@ WebGL 1.0 API와 다르게, WebGL 2.0에서는 non power of 2 텍스처를 사 ## References ### WebGL 2.0 -- https://webgl2fundamentals.org/webgl/lessons/webgl2-whats-new.html -- https://webgl2fundamentals.org/webgl/lessons/webgl1-to-webgl2.html +- https://webgl2fundamentals.org/ +- https://www.khronos.org/registry/webgl/specs/latest/2.0/ - https://www.khronos.org/assets/uploads/developers/library/2017-webgl-webinar/Khronos-Webinar-WebGL-20-is-here_What-you-need-to-know_Apr17.pdf - https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Using_Extensions -- https://www.khronos.org/registry/webgl/specs/latest/2.0/ ### Open Source Licensing - https://en.wikipedia.org/wiki/Comparison_of_free_and_open-source_software_licences ## Acknowledgements -Many thanks to [PavelDoGreat](https://github.com/PavelDoGreat/WebGL-Fluid-Simulation) for the mesmerizing implementation of the fluid simulator. +Many thanks to [PavelDoGreat](https://github.com/PavelDoGreat/WebGL-Fluid-Simulation) for the mesmerizing fluid simulation implementation. diff --git a/index.html b/index.html index d34d0e4b85d931410173fd8d4a62bcc2232ffbb4..8fc24660a24eb5e66b8440c4ba1969c7d0271e7a 100644 --- a/index.html +++ b/index.html @@ -1,55 +1,289 @@ <!DOCTYPE html> <html> - <head> - <meta charset="utf-8"> - <meta http-equiv="Cache-Control" content="no-cache"> - - <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> - <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> - <meta name="apple-mobile-web-app-capable" content="yes"> - <meta name="mobile-web-app-capable" content="yes"> - - <title>WebGL Fluid Simulation</title> - <meta name="description" content="A WebGL fluid simulation that works in mobile browsers."> - - <!-- <script type="text/javascript" src="dat.gui.min.js"></script> --> - <style> - - - * { - user-select: none; - } - - html, body { - overflow: hidden; - background-color: #000; - } - - body { - margin: 0; - position: fixed; - width: 100%; - height: 100%; - } - - canvas { - width: 100%; - height: 100%; - } - - - - - </style> - <!-- <script> - window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date; - ga('create', 'UA-105392568-1', 'auto'); - ga('send', 'pageview'); - </script> - <script async src="https://www.google-analytics.com/analytics.js"></script> --> - </head> - <body> - <canvas></canvas> - <script src="./script.js"></script> - </body> + +<head> + <meta charset="utf-8"> + <meta http-equiv="Cache-Control" content="no-cache"> + + <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> + <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> + <meta name="apple-mobile-web-app-capable" content="yes"> + <meta name="mobile-web-app-capable" content="yes"> + + <title>WebGL Fluid Simulation</title> + <meta name="description" content="A WebGL fluid simulation that works in mobile browsers."> + + <style> + @import url(https://cdn.jsdelivr.net/gh/tonsky/FiraCode@5.2/distr/fira_code.css); + + * { + user-select: none; + } + + code { + font-family: 'Fira Code', monospace; + } + + pre { + background-color: gray; + border-radius: 8px; + padding: 8px; + } + + html, + body { + overflow: hidden; + background-color: #000; + font-family: 'Noto Sans KR', sans-serif; + } + + body { + margin: 0; + position: fixed; + width: 100%; + height: 100%; + } + + canvas { + width: 100%; + height: 100%; + } + + /* @media (min-width:320px) { + display: smartphones, iPhone, portrait 480x320 phones + } + + @media (min-width:1025px) { + display: big landscape tablets, laptops, and desktops + } + + @media (min-width:1281px) { + display: hi-res laptops and desktops + } */ + + #overlay { + opacity: 0.8; + position: absolute; + top: 0; + left: 0; + background-color: black; + height: 100%; + width: 32.360679775%; + z-index: 5; + color: rgba(255, 255, 255, 1); + padding-top: 24px; + padding-left: 24px; + padding-right: 24px; + overflow: scroll; + -ms-overflow-style: none; + scrollbar-width: none; + } + + #overflow::-webkit-scrollbar { + display: none; + } + + a { + color: blue; + } + + </style> +</head> + +<body> + <div id="overlay"> + <h2 id="webgl1-webgl2-">WebGL1과 WebGL2의 차이</h2> + <h3 id="1-getcontext-webgl-webgl2-">1. <code>getContext</code>를 호출할 때 <code>webgl</code> 대신 <code>webgl2</code> + 사용</h3> + <pre><code class="lang-javascript"><span class="hljs-comment">// WebGL1</span> +<span class="hljs-keyword">var</span> gl = canvas.getContext(<span class="hljs-string">'webgl'</span>); + +<span class="hljs-comment">// WebGL2 @ script.js:121</span> +<span class="hljs-keyword">var</span> gl = canvas.getContext(<span class="hljs-string">'webgl2'</span>); +</code></pre> + <h3 id="2-">2. 부동 소수점 프레임버퍼 추가</h3> + <p>WebGL1에선 부동 소수점 텍스처를 지원하는지 확인하기 위해 <code>OES_texture_float</code>를 활성화 한 후 부동 소수점 텍스처를 생성하고 프레임버퍼에 추가해 + <code>gl.checkFramebufferStatus</code>를 호출해 <code>gl.FRAMEBUFFER_COMPLETE</code>를 반환하는지 확인해야 했어요. + </p> + <p>WebGL2에서 <code>gl.checkFramebufferStatus</code>로 부터 <code>gl.FRAMEBUFFER_COMPLETE</code>를 반환받기 위해선 + <code>EXT_color_buffer_float</code>를 허용해주세요.<br><a + href="https://www.khronos.org/registry/webgl/specs/latest/2.0/#4.1.5">공식 문서 보러 가기</a> + </p> + <p><code>HALF_FLOAT</code> 프레임버퍼에도 동일하게 적용해주세요!</p> + <pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getWebGLContext</span><span class="hljs-params">(canvas)</span> </span>{ + + ... + + <span class="hljs-comment">// WebGL2</span> + <span class="hljs-keyword">if</span> (isWebGL2) { + gl.getExtension(<span class="hljs-string">'EXT_color_buffer_float'</span>); + supportLinearFiltering = gl.getExtension(<span class="hljs-string">'OES_texture_float_linear'</span>); + } + + <span class="hljs-comment">// WebGL1</span> + <span class="hljs-keyword">else</span> { + halfFloat = gl.getExtension(<span class="hljs-string">'OES_texture_half_float'</span>); + supportLinearFiltering = gl.getExtension(<span class="hljs-string">'OES_texture_half_float_linear'</span>); + } + + ... + +} +</code></pre> + <h3 id="3-webgl1-webgl2-">3. WebGL1 확장의 WebGL2 표준화</h3> + <p>아래 확장들이 표준에 편입됐어요.</p> + <ul> + <li>Depth Textures (<code>WEBGL_depth_texture</code>)</li> + <li>Floating Point Textures (<code>OES_texture_float/OES_texture_float_linear</code>)</li> + <li>Half Floating Point Textures (<code>OES_texture_half_float/- OES_texture_half_float_linear</code>)</li> + <li>Vertex Array Objects (<code>OES_vertex_array_object</code>)</li> + <li>Standard Derivatives (<code>OES_standard_derivatives</code>)</li> + <li>Instanced Drawing (<code>ANGLE_instanced_arrays</code>)</li> + <li>UNSIGNED_INT indices (<code>OES_element_index_uint</code>)</li> + <li>Setting gl_FragDepth (<code>EXT_frag_depth</code>)</li> + <li>Blend Equation MIN/MAX (<code>EXT_blend_minmax</code>)</li> + <li>Direct texture LOD access (<code>EXT_shader_texture_lod</code>)</li> + <li>Multiple Draw Buffers (<code>WEBGL_draw_buffers</code>)</li> + <li>Texture access in vertex shaders</li> + </ul> + <p>자주 사용되던 <code>OES_vertex_array_object</code>를 예시로 확장 없이 사용하는 예시를 들어볼게요.</p> + <pre><code class="lang-javascript"><span class="hljs-comment">// WebGL1</span> +<span class="hljs-keyword">var</span> ext = <span class="hljs-keyword">gl</span>.getExtension(<span class="hljs-string">"OES_vertex_array_object"</span>); +<span class="hljs-keyword">if</span> (!ext) { + <span class="hljs-comment">// tell user they don't have the required extension or work around it</span> +} <span class="hljs-keyword">else</span> { + <span class="hljs-keyword">var</span> someVAO = ext.createVertexArrayOES(); +} + +<span class="hljs-comment">// WebGL2</span> +<span class="hljs-keyword">var</span> someVAO = <span class="hljs-keyword">gl</span>.createVertexArray(); +</code></pre> + <h3 id="4-glsl-300-es-">4. <code>GLSL 300 es</code> 사용</h3> + <p>사용하는 쉐이더를 GLSL 3.00 ES로 업그레이드 하면 좋다. 그러기 위해선 쉐이더 선언의 첫 줄이 <code>#version 300 es</code>야 해요. 반드시 첫 줄이여야 하기 때문에 + 주석이나 개행이 이루어지면 안돼요.</p> + <pre><code class="lang-javascript"><span class="hljs-comment">// BAD +---There's a new line here!</span> +<span class="hljs-comment">// BAD V</span> +var vertexShaderSource = ` +#version <span class="hljs-number">300</span> es +... +`; + +<span class="hljs-comment">// GOOD</span> +var vertexShaderSource = `#version <span class="hljs-number">300</span> es +... +`; +</code></pre> + <h4 id="4-1-attribute-in-">4-1. <code>attribute</code> 대신 <code>in</code> 사용</h4> + <pre><code class="lang-javascript"><span class="hljs-comment">// WebGL1</span> +<span class="hljs-keyword">attribute</span> <span class="hljs-type">vec4</span> a_position; +<span class="hljs-keyword">attribute</span> <span class="hljs-type">vec2</span> a_texcoord; +<span class="hljs-keyword">attribute</span> <span class="hljs-type">vec3</span> a_normal; + +<span class="hljs-comment">// WebGL2 </span> +<span class="hljs-keyword">in</span> <span class="hljs-type">vec4</span> a_position; +<span class="hljs-keyword">in</span> <span class="hljs-type">vec2</span> a_texcoord; +<span class="hljs-keyword">in</span> <span class="hljs-type">vec3</span> a_normal; +</code></pre> + <h4 id="4-2-varying-in-out-">4-2. <code>varying</code> 대신 <code>in/out</code> 사용</h4> + <pre><code class="lang-javascript"><span class="hljs-comment">// WebGL1</span> +<span class="hljs-keyword">varying</span> <span class="hljs-type">vec2</span> v_texcoord; +<span class="hljs-keyword">varying</span> <span class="hljs-type">vec3</span> v_normal; + +<span class="hljs-comment">// WebGL2 </span> +<span class="hljs-comment">// Vertex Shader</span> +<span class="hljs-keyword">out</span> <span class="hljs-type">vec2</span> v_texcoord; +<span class="hljs-keyword">out</span> <span class="hljs-type">vec3</span> v_normal; + +<span class="hljs-comment">// Framgent Shader</span> +<span class="hljs-keyword">in</span> <span class="hljs-type">vec2</span> v_texcoord; +<span class="hljs-keyword">in</span> <span class="hljs-type">vec3</span> v_normal; +</code></pre> + <h4 id="4-3-gl_fragcolor-">4-3. <code>gl_FragColor</code> 대신 원하는 변수명 사용 가능</h4> + <pre><code class="lang-javascript"><span class="hljs-comment">// WebGL1</span> +gl_FragColor = vec4(<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>); <span class="hljs-comment">// red</span> + +<span class="hljs-comment">// WebGL2</span> +out vec4 myOutputColor; + +void main() { + myOutputColor = vec4(<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>); <span class="hljs-comment">// red</span> +} +</code></pre> + <h4 id="4-4-texture2d-texture-">4-4. <code>texture2D</code> 대신 <code>texture</code> 사용</h4> + <pre><code class="lang-javascript"><span class="hljs-comment">// WebGL1</span> +<span class="hljs-type">vec4</span> color1 = <span class="hljs-built_in">texture2D</span>(u_some2DTexture, ...); +<span class="hljs-type">vec4</span> color2 = <span class="hljs-built_in">textureCube</span>(u_someCubeTexture, ...); + +<span class="hljs-comment">// WebGL2</span> +<span class="hljs-type">vec4</span> color1 = <span class="hljs-built_in">texture</span>(u_some2DTexture, ...); +<span class="hljs-type">vec4</span> color2 = <span class="hljs-built_in">texture</span>(u_someCubeTexture, ...); +</code></pre> + <p>더 자세한 내용이 궁금하다면?<br><a href="https://khronos.org/registry/webgl/specs/latest/2.0/#4.3">공식 문서 보러 가기</a></p> + <h3 id="5-non-power-of-two-">5. Non-Power-of-Two 텍스처의 사용 허용</h3> + <p>WebGL 1.0 API와 다르게, WebGL 2.0에서는 non-power-of-two 텍스처를 사용할 수 있어요. 다양한 mipmapping 기능과 wrapping mode를 사용할 수 + 있어요.<br><a href="https://www.khronos.org/registry/webgl/specs/latest/2.0/#4.1.3">공식 문서 보러 가기</a></p> + <h3 id="6-">6. 새로 추가된 텍스처 포맷</h3> + <details> + <summary>무려 52가지나! 궁금하면 클릭해서 열어보기</summary> + <ul> + <li><code>RGBA32I</code></li> + <li><code>RGBA32UI</code></li> + <li><code>RGBA16I</code></li> + <li><code>RGBA16UI</code></li> + <li><code>RGBA8</code></li> + <li><code>RGBA8I</code></li> + <li><code>RGBA8UI</code></li> + <li><code>SRGB8_ALPHA8</code></li> + <li><code>RGB10_A2</code></li> + <li><code>RGB10_A2UI</code></li> + <li><code>RGBA4</code></li> + <li><code>RGB5_A1</code></li> + <li><code>RGB8</code></li> + <li><code>RGB565</code></li> + <li><code>RG32I</code></li> + <li><code>RG32UI</code></li> + <li><code>RG16I</code></li> + <li><code>RG16UI</code></li> + <li><code>RG8</code></li> + <li><code>RG8I</code></li> + <li><code>RG8UI</code></li> + <li><code>R32I</code></li> + <li><code>R32UI</code></li> + <li><code>R16I</code></li> + <li><code>R16UI</code></li> + <li><code>R8</code></li> + <li><code>R8I</code></li> + <li><code>R8UI</code></li> + <li><code>RGBA32F</code></li> + <li><code>RGBA16F</code></li> + <li><code>RGBA8_SNORM</code></li> + <li><code>RGB32F</code></li> + <li><code>RGB32I</code></li> + <li><code>RGB32UI</code></li> + <li><code>RGB16F</code></li> + <li><code>RGB16I</code></li> + <li><code>RGB16UI</code></li> + <li><code>RGB8_SNORM</code></li> + <li><code>RGB8I</code></li> + <li><code>RGB8UI</code></li> + <li><code>SRGB8</code></li> + <li><code>R11F_G11F_B10F</code></li> + <li><code>RGB9_E5</code></li> + <li><code>RG32F</code></li> + <li><code>RG16F</code></li> + <li><code>RG8_SNORM</code></li> + <li><code>R32F</code></li> + <li><code>R16F</code></li> + <li><code>R8_SNORM</code></li> + <li><code>DEPTH_COMPONENT32F</code></li> + <li><code>DEPTH_COMPONENT24</code></li> + <li><code>DEPTH_COMPONENT16</code></li> + </ul> + </details> + <br> + </div> + <canvas></canvas> + <script src="./script.js"></script> +</body> + </html> \ No newline at end of file