{"id":4421,"date":"2016-09-30T08:45:35","date_gmt":"2016-09-30T14:45:35","guid":{"rendered":"http:\/\/www.realtimerendering.com\/blog\/?p=4421"},"modified":"2017-03-04T18:20:16","modified_gmt":"2017-03-05T00:20:16","slug":"webgl-2-basics","status":"publish","type":"post","link":"https:\/\/www.realtimerendering.com\/blog\/webgl-2-basics\/","title":{"rendered":"WebGL 2 Basics"},"content":{"rendered":"<p><em>This guest blog post is by\u00a0<span class=\"fn\"><span class=\"full-name\" dir=\"auto\"><a href=\"https:\/\/www.linkedin.com\/in\/shuai-shao-3718818b\">Shuai Shao<\/a>, a Masters student at UPenn under Patrick Cozzi. After hearing the announcement at SIGGRAPH, I was asking around for someone to write a &#8220;basics of WebGL 2&#8221; article and Patrick got Shuai involved. If you&#8217;re reading this any time after October 2016, see <a href=\"https:\/\/github.com\/shrekshao\/MoveWebGL1EngineToWebGL2\/blob\/master\/Move-a-WebGL-1-Engine-To-WebGL-2-Blog-1.md\">his Github repo<\/a>\u00a0for the latest version of this article, with any corrections folded in since then (we encourage you to contribute to it).<\/span><\/span><\/em><\/p>\n<p>WebGL 2 is coming! <a href=\"https:\/\/www.youtube.com\/watch?v=0eWUzCa_M0E&amp;feature=youtu.be&amp;t=66\">Google Chrome just announced<\/a> at SIGGRAPH 2016 that 100% of the WebGL 2 conformance suite is passing (on the first configurations).<\/p>\n<p>If I have an engine that works well in WebGL 1, how do I move to WebGL 2? Things to consider:<\/p>\n<ul>\n<li>What has to be changed?<\/li>\n<li>What can be done in a better way?<\/li>\n<li>What new features and functionalities can I add to my engine?<\/li>\n<\/ul>\n<p>In this article we are focused on the first question. We discuss the main promoted features, which are supported\u00a0by extensions in WebGL 1 that are part of the core of WebGL 2 and thus cannot be accessed in the old manner, along with some other compatibility issues.<\/p>\n<p>You can find answers to the other two questions in our next article, which focuses on introducing new features.<\/p>\n<p>In the future you may want some complete working sample code for reference, instead of just code snippets. <a href=\"https:\/\/github.com\/WebGLSamples\/WebGL2Samples\"><strong>WebGL 2 Samples pack<\/strong><\/a> is a resource you&#8217;ll find useful.<\/p>\n<p>That&#8217;s enough for an intro. First of all, let&#8217;s get WebGL 2 working on your machine.<\/p>\n<h1><a id=\"user-content-how-do-i-start-using-webgl-2\" class=\"anchor\" href=\"https:\/\/github.com\/shrekshao\/MoveWebGL1EngineToWebGL2\/blob\/master\/Move-a-WebGL-1-Engine-To-WebGL-2-Blog-1.md#how-do-i-start-using-webgl-2\"><\/a>How do I start using WebGL 2?<\/h1>\n<h2><a id=\"user-content-get-a-webgl-2-implementation-browser\" class=\"anchor\" href=\"https:\/\/github.com\/shrekshao\/MoveWebGL1EngineToWebGL2\/blob\/master\/Move-a-WebGL-1-Engine-To-WebGL-2-Blog-1.md#get-a-webgl-2-implementation-browser\"><\/a>Get a WebGL 2 Implementation (Browser)<\/h2>\n<p>You may have seen this before, let&#8217;s just hit the main points:<\/p>\n<ul>\n<li>Just do it: <a href=\"https:\/\/www.khronos.org\/webgl\/wiki\/Getting_a_WebGL_Implementation\">Getting a WebGL Implementation<\/a><\/li>\n<li>Check if your current browser supports it; see the WebGL 2 tab of the <a href=\"https:\/\/www.khronos.org\/webgl\/wiki\/Getting_a_WebGL_Implementation\">WebGL Report<\/a><\/li>\n<\/ul>\n<h2><a id=\"user-content-get-a-webgl-2-context\" class=\"anchor\" href=\"https:\/\/github.com\/shrekshao\/MoveWebGL1EngineToWebGL2\/blob\/master\/Move-a-WebGL-1-Engine-To-WebGL-2-Blog-1.md#get-a-webgl-2-context\"><\/a>Get a WebGL 2 Context<\/h2>\n<p>Programmers always try to support as many browsers as possible. So do I. On top the WebGL 1 version of getContext, we will first try to access WebGL 2. If this fails, then drop back to WebGL 1. Here&#8217;s an example dervived from the Cesium WebGL engine:<\/p>\n<div class=\"highlight highlight-source-js\">\n<pre><span class=\"pl-k\">var<\/span> defaultToWebgl2 <span class=\"pl-k\">=<\/span> <span class=\"pl-c1\">false<\/span>;\r\n\r\n<span class=\"pl-k\">var<\/span> webgl2Supported <span class=\"pl-k\">=<\/span> (<span class=\"pl-k\">typeof<\/span> WebGL2RenderingContext <span class=\"pl-k\">!==<\/span> <span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>undefined<span class=\"pl-pds\">'<\/span><\/span>);\r\n<span class=\"pl-k\">var<\/span> webgl2 <span class=\"pl-k\">=<\/span> <span class=\"pl-c1\">false<\/span>;\r\n<span class=\"pl-k\">var<\/span> gl;\r\n\r\n<span class=\"pl-k\">if<\/span> (defaultToWebgl2 <span class=\"pl-k\">&amp;&amp;<\/span> webgl2Supported) {\r\n    gl <span class=\"pl-k\">=<\/span> <span class=\"pl-smi\">canvas<\/span>.<span class=\"pl-c1\">getContext<\/span>(<span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>webgl2<span class=\"pl-pds\">'<\/span><\/span>, webglOptions);\r\n    <span class=\"pl-k\">if<\/span> (gl) {\r\n        webgl2 <span class=\"pl-k\">=<\/span> <span class=\"pl-c1\">true<\/span>;\r\n    }\r\n}\r\n<span class=\"pl-k\">if<\/span> (<span class=\"pl-k\">!<\/span>gl) {\r\n    gl <span class=\"pl-k\">=<\/span> <span class=\"pl-smi\">canvas<\/span>.<span class=\"pl-c1\">getContext<\/span>(<span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>webgl<span class=\"pl-pds\">'<\/span><\/span>, webglOptions);\r\n}\r\n<span class=\"pl-k\">if<\/span> (<span class=\"pl-k\">!<\/span>gl) {\r\n    <span class=\"pl-k\">throw<\/span> <span class=\"pl-k\">new<\/span> <span class=\"pl-en\">Error<\/span>(<span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>The browser supports WebGL, but initialization failed.<span class=\"pl-pds\">'<\/span><\/span>);\r\n}<\/pre>\n<\/div>\n<h1><a id=\"user-content-promoted-features\" class=\"anchor\" href=\"https:\/\/github.com\/shrekshao\/MoveWebGL1EngineToWebGL2\/blob\/master\/Move-a-WebGL-1-Engine-To-WebGL-2-Blog-1.md#promoted-features\"><\/a>Promoted Features<\/h1>\n<p>Some of the new WebGL 2 features are already available in WebGL 1 as extensions. However, these features will be part of the core spec in WebGL 2, which means support is guaranteed. In this first blog entry we are going to focus on these promoted features, together with potential compatibility issues they may cause.<\/p>\n<p>First let&#8217;s find if there&#8217;s a way to change fewest existing WebGL 1 code using the extension to make it work correctly with a WebGL 2 context.<\/p>\n<p>We may find that in some cases (instancing and VAO), it&#8217;s only the function we are calling that changes from the extension version to core version, while the parameters and pipeline don&#8217;t change. We used to call <code>fooEXT<\/code>, now we simply switch to <code>foo<\/code>.<\/p>\n<p>Thanks to\u00a0Javascript&#8217;s neat support of function objects, one solution is\u00a0that we can create a function handler at startup, assigned with either the extension version from WebGL 1 or the core version from WebGL 2. Within the rest of the code we call this function handler.<\/p>\n<div class=\"highlight highlight-source-js\">\n<pre><span class=\"pl-k\">if<\/span> (<span class=\"pl-k\">!<\/span>webgl2) {\r\n    vaoExt <span class=\"pl-k\">=<\/span> <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">getExtension<\/span>(<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>OES_vertex_array_object<span class=\"pl-pds\">\"<\/span><\/span>);\r\n    <span class=\"pl-c\">\/\/...<\/span>\r\n    <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-smi\">createVertexArray<\/span> <span class=\"pl-k\">=<\/span> <span class=\"pl-smi\">vaoExt<\/span>.<span class=\"pl-smi\">createVertexArrayOES<\/span>;\r\n    <span class=\"pl-c\">\/\/...<\/span>\r\n}<\/pre>\n<\/div>\n<p>Yet this method can fail when changes are made in the shader (e.g., MRT). We still need to take a close look at each of these promoted features. So now let\u2019s take a look at how the code changes for each of them.<\/p>\n<h2><a id=\"user-content-multiple-render-targets\" class=\"anchor\" href=\"https:\/\/github.com\/shrekshao\/MoveWebGL1EngineToWebGL2\/blob\/master\/Move-a-WebGL-1-Engine-To-WebGL-2-Blog-1.md#multiple-render-targets\"><\/a>Multiple Render Targets<\/h2>\n<p>MRT is a commonly used extension for deferred rendering, OIT, single-pass picking, etc.<\/p>\n<p><a id=\"user-content-webgl-1\" class=\"anchor\" href=\"https:\/\/github.com\/shrekshao\/MoveWebGL1EngineToWebGL2\/blob\/master\/Move-a-WebGL-1-Engine-To-WebGL-2-Blog-1.md#webgl-1\"><\/a><strong>WebGL 1<\/strong><\/p>\n<p>For MRT we used the <a href=\"https:\/\/www.khronos.org\/registry\/webgl\/extensions\/WEBGL_draw_buffers\/\"><code>WEBGL_draw_buffers<\/code><\/a> extension as a work-around to write g-buffers in a single pass. Though it is widely supported (currently 57%+ browsers, according to <a href=\"http:\/\/webglstats.com\/\">WebGL stats<\/a>), the extension-style code isn&#8217;t as clean as WebGL 2:<\/p>\n<div class=\"highlight highlight-source-js\">\n<pre><span class=\"pl-k\">var<\/span> ext <span class=\"pl-k\">=<\/span> <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">getExtension<\/span>(<span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>WEBGL_draw_buffers<span class=\"pl-pds\">'<\/span><\/span>);\r\n<span class=\"pl-k\">if<\/span> (<span class=\"pl-k\">!<\/span>ext) {\r\n  <span class=\"pl-c\">\/\/ ...<\/span>\r\n}<\/pre>\n<\/div>\n<p>We then bind multiple textures, tx[] in the example below, to different framebuffer color attachments.<\/p>\n<div class=\"highlight highlight-source-js\">\n<pre><span class=\"pl-k\">var<\/span> fb <span class=\"pl-k\">=<\/span> <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">createFramebuffer<\/span>();\r\n<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">bindFramebuffer<\/span>(<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">FRAMEBUFFER<\/span>, fb);\r\n<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">framebufferTexture2D<\/span>(<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">FRAMEBUFFER<\/span>, <span class=\"pl-smi\">ext<\/span>.<span class=\"pl-c1\">COLOR_ATTACHMENT0_WEBGL<\/span>, <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">TEXTURE_2D<\/span>, tx[<span class=\"pl-c1\">0<\/span>], <span class=\"pl-c1\">0<\/span>);\r\n<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">framebufferTexture2D<\/span>(<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">FRAMEBUFFER<\/span>, <span class=\"pl-smi\">ext<\/span>.<span class=\"pl-c1\">COLOR_ATTACHMENT1_WEBGL<\/span>, <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">TEXTURE_2D<\/span>, tx[<span class=\"pl-c1\">1<\/span>], <span class=\"pl-c1\">0<\/span>);\r\n<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">framebufferTexture2D<\/span>(<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">FRAMEBUFFER<\/span>, <span class=\"pl-smi\">ext<\/span>.<span class=\"pl-c1\">COLOR_ATTACHMENT2_WEBGL<\/span>, <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">TEXTURE_2D<\/span>, tx[<span class=\"pl-c1\">2<\/span>], <span class=\"pl-c1\">0<\/span>);\r\n<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">framebufferTexture2D<\/span>(<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">FRAMEBUFFER<\/span>, <span class=\"pl-smi\">ext<\/span>.<span class=\"pl-c1\">COLOR_ATTACHMENT3_WEBGL<\/span>, <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">TEXTURE_2D<\/span>, tx[<span class=\"pl-c1\">3<\/span>], <span class=\"pl-c1\">0<\/span>);<\/pre>\n<\/div>\n<p>Next we map the color attachments to draw buffer slots that the fragment shader will write to using <code>gl_FragData<\/code>.<\/p>\n<div class=\"highlight highlight-source-js\">\n<pre><span class=\"pl-smi\">ext<\/span>.<span class=\"pl-en\">drawBuffersWEBGL<\/span>([\r\n  <span class=\"pl-smi\">ext<\/span>.<span class=\"pl-c1\">COLOR_ATTACHMENT0_WEBGL<\/span>, <span class=\"pl-c\">\/\/ gl_FragData[0]<\/span>\r\n  <span class=\"pl-smi\">ext<\/span>.<span class=\"pl-c1\">COLOR_ATTACHMENT1_WEBGL<\/span>, <span class=\"pl-c\">\/\/ gl_FragData[1]<\/span>\r\n  <span class=\"pl-smi\">ext<\/span>.<span class=\"pl-c1\">COLOR_ATTACHMENT2_WEBGL<\/span>, <span class=\"pl-c\">\/\/ gl_FragData[2]<\/span>\r\n  <span class=\"pl-smi\">ext<\/span>.<span class=\"pl-c1\">COLOR_ATTACHMENT3_WEBGL<\/span>  <span class=\"pl-c\">\/\/ gl_FragData[3]<\/span>\r\n]);<\/pre>\n<\/div>\n<p>Also, an extra flag is needed in the shader:<\/p>\n<div class=\"highlight highlight-source-glsl\">\n<pre><span class=\"pl-k\">#extension<\/span> GL_EXT_draw_buffers <span class=\"pl-k\">:<\/span> require\r\n<span class=\"pl-k\">precision<\/span> <span class=\"pl-k\">highp<\/span> <span class=\"pl-k\">float<\/span>;\r\n<span class=\"pl-c\">\/\/ ...<\/span>\r\n<span class=\"pl-k\">void<\/span> main() {\r\n    gl_FragData[<span class=\"pl-c1\">0<\/span>] <span class=\"pl-k\">=<\/span> <span class=\"pl-k\">vec4<\/span>( v_position.xyz, <span class=\"pl-c1\">1.0<\/span> );\r\n    gl_FragData[<span class=\"pl-c1\">1<\/span>] <span class=\"pl-k\">=<\/span> <span class=\"pl-k\">vec4<\/span>( v_normal.xyz, <span class=\"pl-c1\">1.0<\/span> );\r\n    gl_FragData[<span class=\"pl-c1\">2<\/span>] <span class=\"pl-k\">=<\/span> <span class=\"pl-c1\">texture2D<\/span>( u_colmap, v_uv );\r\n    gl_FragData[<span class=\"pl-c1\">3<\/span>] <span class=\"pl-k\">=<\/span> <span class=\"pl-c1\">texture2D<\/span>( u_normap, v_uv );\r\n}<\/pre>\n<\/div>\n<p><a id=\"user-content-webgl-2\" class=\"anchor\" href=\"https:\/\/github.com\/shrekshao\/MoveWebGL1EngineToWebGL2\/blob\/master\/Move-a-WebGL-1-Engine-To-WebGL-2-Blog-1.md#webgl-2\"><\/a><strong>WebGL 2<\/strong><\/p>\n<p>For MRT our code becomes neat and clean in WebGL 2.<\/p>\n<div class=\"highlight highlight-source-js\">\n<pre><span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">framebufferTexture2D<\/span>(<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">DRAW_FRAMEBUFFER<\/span>, <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">COLOR_ATTACHMENT0<\/span>, <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">TEXTURE_2D<\/span>, tex[<span class=\"pl-c1\">0<\/span>], <span class=\"pl-c1\">0<\/span>);\r\n<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">framebufferTexture2D<\/span>(<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">DRAW_FRAMEBUFFER<\/span>, <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">COLOR_ATTACHMENT1<\/span>, <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">TEXTURE_2D<\/span>, tex[<span class=\"pl-c1\">1<\/span>], <span class=\"pl-c1\">0<\/span>);\r\n<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">framebufferTexture2D<\/span>(<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">DRAW_FRAMEBUFFER<\/span>, <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">COLOR_ATTACHMENT2<\/span>, <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">TEXTURE_2D<\/span>, tex[<span class=\"pl-c1\">2<\/span>], <span class=\"pl-c1\">0<\/span>);<\/pre>\n<\/div>\n<p>defines an array of buffers into which outputs will be written. Draw by:<\/p>\n<pre><span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">drawBuffers<\/span>( [<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">COLOR_ATTACHMENT0<\/span>, <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">COLOR_ATTACHMENT1<\/span>, <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">COLOR_ATTACHMENT2<\/span>] );<\/pre>\n<p>Instead of mapping color attachments to the draw buffer, we directly use multiple <code>out<\/code> variables in the fragment shader. This code actually benefits from the new <a href=\"https:\/\/www.khronos.org\/registry\/gles\/specs\/3.0\/GLSL_ES_Specification_3.00.3.pdf\">GLSL 3.0 ES<\/a>, which we will discuss later in another blog post. However, using <code>out<\/code> itself is straightforward.<\/p>\n<div class=\"highlight highlight-source-glsl\">\n<pre><span class=\"pl-k\">#version<\/span> <span class=\"pl-c1\">300<\/span> es\r\n<span class=\"pl-k\">precision<\/span> <span class=\"pl-k\">highp<\/span> <span class=\"pl-k\">float<\/span>;\r\n<span class=\"pl-k\">layout<\/span>(location <span class=\"pl-k\">=<\/span> <span class=\"pl-c1\">0<\/span>) <span class=\"pl-k\">out<\/span> <span class=\"pl-k\">vec4<\/span> gbuf_position;\r\n<span class=\"pl-k\">layout<\/span>(location <span class=\"pl-k\">=<\/span> <span class=\"pl-c1\">1<\/span>) <span class=\"pl-k\">out<\/span> <span class=\"pl-k\">vec4<\/span> gbuf_normal;\r\n<span class=\"pl-k\">layout<\/span>(location <span class=\"pl-k\">=<\/span> <span class=\"pl-c1\">2<\/span>) <span class=\"pl-k\">out<\/span> <span class=\"pl-k\">vec4<\/span> gbuf_colmap;\r\n<span class=\"pl-k\">layout<\/span>(location <span class=\"pl-k\">=<\/span> <span class=\"pl-c1\">3<\/span>) <span class=\"pl-k\">out<\/span> <span class=\"pl-k\">vec4<\/span> gbuf_normap;\r\n<span class=\"pl-c\">\/\/...<\/span>\r\n<span class=\"pl-k\">void<\/span> main()\r\n{\r\n    gbuf_position <span class=\"pl-k\">=<\/span> <span class=\"pl-k\">vec4<\/span>( v_position.xyz, <span class=\"pl-c1\">1.0<\/span> );\r\n    gbuf_normal <span class=\"pl-k\">=<\/span> <span class=\"pl-k\">vec4<\/span>( v_normal.xyz, <span class=\"pl-c1\">1.0<\/span> );\r\n    gbuf_colmap <span class=\"pl-k\">=<\/span> <span class=\"pl-c1\">texture2D<\/span>( u_colmap, v_uv );\r\n    gbuf_normap <span class=\"pl-k\">=<\/span> <span class=\"pl-c1\">texture2D<\/span>( u_normap, v_uv );\r\n}<\/pre>\n<\/div>\n<p>Additionally, since <strong>Texture 2D Array<\/strong> is now available, we can choose to render to different layers of an array of texture 2d&#8217;s instead of separate 2d textures.<\/p>\n<div class=\"highlight highlight-source-js\">\n<pre><span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">framebufferTextureLayer<\/span>(<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">DRAW_FRAMEBUFFER<\/span>, <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">COLOR_ATTACHMENT0<\/span>, texture, <span class=\"pl-c1\">0<\/span>, <span class=\"pl-c1\">0<\/span>);\r\n<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">framebufferTextureLayer<\/span>(<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">DRAW_FRAMEBUFFER<\/span>, <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">COLOR_ATTACHMENT1<\/span>, texture, <span class=\"pl-c1\">0<\/span>, <span class=\"pl-c1\">1<\/span>);\r\n<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">framebufferTextureLayer<\/span>(<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">DRAW_FRAMEBUFFER<\/span>, <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">COLOR_ATTACHMENT2<\/span>, texture, <span class=\"pl-c1\">0<\/span>, <span class=\"pl-c1\">2<\/span>);<\/pre>\n<\/div>\n<h2><a id=\"user-content-instancing\" class=\"anchor\" href=\"https:\/\/github.com\/shrekshao\/MoveWebGL1EngineToWebGL2\/blob\/master\/Move-a-WebGL-1-Engine-To-WebGL-2-Blog-1.md#instancing\"><\/a>Instancing<\/h2>\n<p>Instancing is a great performance booster for certain types of geometry, especially objects with many instances but without many vertices. Good examples are grass and fur. Instancing avoids the overhead of an individual API call per object, while minimizing memory costs by avoiding storing geometric data for each separate instance.<\/p>\n<p>Instancing is exposed through the <a href=\"https:\/\/www.khronos.org\/registry\/webgl\/extensions\/ANGLE_instanced_arrays\/\"><code>ANGLE_instanced_arrays<\/code><\/a> extension in WebGL 1 (<a href=\"http:\/\/webglstats.com\/\">92%+ support<\/a>). Now with WebGL 2 we can simply use <code>drawArraysInstanced<\/code> or <code>drawArraysInstanced<\/code> for the draw calls.<\/p>\n<div class=\"highlight highlight-source-js\">\n<pre><span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">drawArraysInstanced<\/span>(<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">TRIANGLES<\/span>, <span class=\"pl-c1\">0<\/span>, <span class=\"pl-c1\">3<\/span>, <span class=\"pl-c1\">2<\/span>);<\/pre>\n<\/div>\n<p>There is a new built-in variable (GLSL 3.0 ES) in the vertex shader called <code>gl_InstanceID<\/code> that can help with the draw instance call. For example, we can use this to assign each instance with a separate color.<\/p>\n<div class=\"highlight highlight-source-glsl\">\n<pre><span class=\"pl-c\">\/\/ Vertex Shader<\/span>\r\n<span class=\"pl-k\">flat<\/span> <span class=\"pl-k\">out<\/span> <span class=\"pl-k\">int<\/span> <span class=\"pl-k\">in<\/span> instance\r\n<span class=\"pl-c\">\/\/ ...<\/span>\r\n<span class=\"pl-k\">void<\/span> main() {\r\n    instance <span class=\"pl-k\">=<\/span> <span class=\"pl-c1\">gl_InstanceID<\/span>;\r\n}<\/pre>\n<\/div>\n<div class=\"highlight highlight-source-glsl\">\n<pre><span class=\"pl-c\">\/\/ Fragment Shader<\/span>\r\n<span class=\"pl-k\">uniform<\/span> Material {\r\n    <span class=\"pl-k\">vec4<\/span> diffuse[NUM_MATERIALS];\r\n} material;\r\n<span class=\"pl-k\">flat<\/span> <span class=\"pl-k\">in<\/span> <span class=\"pl-k\">int<\/span> instance;   <span class=\"pl-c\">\/\/ `flat` is a must for a int varying, plus we don't want the instance id to be interpolated<\/span>\r\n<span class=\"pl-c\">\/\/ ...<\/span>\r\n<span class=\"pl-k\">void<\/span> main() {\r\n    color <span class=\"pl-k\">=<\/span> material.diffuse[instance <span class=\"pl-k\">%<\/span> NUM_MATERIALS];\r\n}<\/pre>\n<\/div>\n<h2><a id=\"user-content-vertex-array-object\" class=\"anchor\" href=\"https:\/\/github.com\/shrekshao\/MoveWebGL1EngineToWebGL2\/blob\/master\/Move-a-WebGL-1-Engine-To-WebGL-2-Blog-1.md#vertex-array-object\"><\/a>Vertex Array Object<\/h2>\n<p>VAO is very useful in terms of engine design. It allows us to store vertex array states for a set of buffers in a single, easy to manage object. It is exposed through the <a href=\"https:\/\/www.khronos.org\/registry\/webgl\/extensions\/OES_vertex_array_object\/\"><code>OES_vertex_array_object<\/code><\/a> extension in WebGL 1 (<a href=\"http:\/\/webglstats.com\/\">89%+<\/a>).<\/p>\n<table>\n<thead>\n<tr>\n<th>WebGL 1 with extension<\/th>\n<th>WebGL 2<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>createVertexArrayOES<\/code><\/td>\n<td><code>createVertexArray<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>deleteVertexArrayOES<\/code><\/td>\n<td><code>deleteVertexArray<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>isVertexArrayOES<\/code><\/td>\n<td><code>isVertexArray<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>bindVertexArrayOES<\/code><\/td>\n<td><code>bindVertexArray<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>An example:<\/p>\n<div class=\"highlight highlight-source-js\">\n<pre><span class=\"pl-k\">var<\/span> vertexArray <span class=\"pl-k\">=<\/span> <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">createVertexArray<\/span>();\r\n<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">bindVertexArray<\/span>(vertexArray);\r\n\r\n<span class=\"pl-c\">\/\/ set vertex array states<\/span>\r\n<span class=\"pl-k\">var<\/span> vertexPosLocation <span class=\"pl-k\">=<\/span> <span class=\"pl-c1\">0<\/span>; <span class=\"pl-c\">\/\/ set with GLSL layout qualifier<\/span>\r\n<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">enableVertexAttribArray<\/span>(vertexPosLocation);\r\n<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">bindBuffer<\/span>(<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">ARRAY_BUFFER<\/span>, vertexPosBuffer);\r\n<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">vertexAttribPointer<\/span>(vertexPosLocation, <span class=\"pl-c1\">2<\/span>, <span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">FLOAT<\/span>, <span class=\"pl-c1\">false<\/span>, <span class=\"pl-c1\">0<\/span>, <span class=\"pl-c1\">0<\/span>);\r\n<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">bindBuffer<\/span>(<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">ARRAY_BUFFER<\/span>, <span class=\"pl-c1\">null<\/span>);\r\n<span class=\"pl-c\">\/\/ ...<\/span>\r\n\r\n<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">bindVertexArray<\/span>(<span class=\"pl-c1\">null<\/span>);\r\n\r\n<span class=\"pl-c\">\/\/ ...<\/span>\r\n\r\n<span class=\"pl-c\">\/\/ render<\/span>\r\n<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">bindVertexArray<\/span>(vertexArray);\r\n<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-en\">drawArrays<\/span>(<span class=\"pl-smi\">gl<\/span>.<span class=\"pl-c1\">TRIANGLES<\/span>, <span class=\"pl-c1\">0<\/span>, <span class=\"pl-c1\">6<\/span>);<\/pre>\n<\/div>\n<h2><a id=\"user-content-shader-texture-lod\" class=\"anchor\" href=\"https:\/\/github.com\/shrekshao\/MoveWebGL1EngineToWebGL2\/blob\/master\/Move-a-WebGL-1-Engine-To-WebGL-2-Blog-1.md#shader-texture-lod\"><\/a>Shader Texture LOD<\/h2>\n<p>The Shader Texture LOD Bias control makes mipmap level control simpler for glossy environment effects in physically based rendering. This functionality is exposed through the <a href=\"https:\/\/www.khronos.org\/registry\/webgl\/extensions\/EXT_shader_texture_lod\/\"><code>EXT_shader_texture_lod<\/code><\/a> extension in WebGL 1 (<a href=\"http:\/\/webglstats.com\/\">71%+<\/a>).<\/p>\n<div class=\"highlight highlight-source-glsl\">\n<pre><span class=\"pl-k\">vec4<\/span> texture2DLodEXT(<span class=\"pl-k\">sampler2D<\/span> <span class=\"pl-k\">sampler<\/span>, <span class=\"pl-k\">vec2<\/span> coord, <span class=\"pl-k\">float<\/span> lod)<\/pre>\n<\/div>\n<p>Now as part of core, the lodBias can be passed as an optional parameter to <code>texture<\/code><\/p>\n<div class=\"highlight highlight-source-glsl\">\n<pre>gvec4 texture (gsampler2D <span class=\"pl-k\">sampler<\/span>, <span class=\"pl-k\">vec2<\/span> P [, <span class=\"pl-k\">float<\/span> bias] )<\/pre>\n<\/div>\n<h2><a id=\"user-content-fragment-depth\" class=\"anchor\" href=\"https:\/\/github.com\/shrekshao\/MoveWebGL1EngineToWebGL2\/blob\/master\/Move-a-WebGL-1-Engine-To-WebGL-2-Blog-1.md#fragment-depth\"><\/a>Fragment Depth<\/h2>\n<p>The fragment shader can explicitly set the depth value for the current fragment. This operation can be expensive because it can cause the early-z optimization to be disabled. However, it is needed in cases where the z-depth is modified on the fly.<\/p>\n<p>This functionality is exposed through the <a href=\"https:\/\/www.khronos.org\/registry\/webgl\/extensions\/EXT_frag_depth\/\"><code>EXT_frag_depth<\/code><\/a> extension in WebGL 1 (<a href=\"http:\/\/webglstats.com\/\">66%+<\/a>).<\/p>\n<div class=\"highlight highlight-source-glsl\">\n<pre><span class=\"pl-k\">out<\/span> <span class=\"pl-k\">float<\/span> gl_FragDepth;<\/pre>\n<\/div>\n<p>More details can be found in the <a href=\"https:\/\/www.khronos.org\/registry\/gles\/specs\/3.0\/GLSL_ES_Specification_3.00.4.pdf\">GLSL 3.0 ES Spec<\/a>.<\/p>\n<h1><a id=\"user-content-other-compatibility-issues\" class=\"anchor\" href=\"https:\/\/github.com\/shrekshao\/MoveWebGL1EngineToWebGL2\/blob\/master\/Move-a-WebGL-1-Engine-To-WebGL-2-Blog-1.md#other-compatibility-issues\"><\/a>Other compatibility issues<\/h1>\n<p>Look here for more information: <a href=\"https:\/\/www.khronos.org\/registry\/webgl\/specs\/latest\/2.0\/#4.1\">WebGL 2 Spec Ch4.1<\/a><\/p>\n<h1><a id=\"user-content-credits\" class=\"anchor\" href=\"https:\/\/github.com\/shrekshao\/MoveWebGL1EngineToWebGL2\/blob\/master\/Move-a-WebGL-1-Engine-To-WebGL-2-Blog-1.md#credits\"><\/a>Credits<\/h1>\n<ul>\n<li>Brandon Jones <a href=\"http:\/\/blog.tojicode.com\/2013\/09\/whats-coming-in-webgl-20.html\">http:\/\/blog.tojicode.com\/2013\/09\/whats-coming-in-webgl-20.html<\/a><\/li>\n<li>Hongwei Li <a href=\"https:\/\/zhuanlan.zhihu.com\/p\/19957067?refer=webgl\">https:\/\/zhuanlan.zhihu.com\/p\/19957067?refer=webgl<\/a><\/li>\n<li>WebGL 2 Spec <a href=\"https:\/\/www.khronos.org\/registry\/webgl\/specs\/latest\/2.0\/\">https:\/\/www.khronos.org\/registry\/webgl\/specs\/latest\/2.0\/<\/a><\/li>\n<li>OpenGL ES 3 Spec <a href=\"https:\/\/www.khronos.org\/registry\/gles\/specs\/3.0\/es_spec_3.0.0.pdf\">https:\/\/www.khronos.org\/registry\/gles\/specs\/3.0\/es_spec_3.0.0.pdf<\/a><\/li>\n<li>OpenGL ES 3 Programming Guide <a href=\"http:\/\/1.droppdf.com\/files\/v4voM\/addison-wesley-opengl-es-3-0-programming-guide-2nd-2014.pdf\">http:\/\/1.droppdf.com\/files\/v4voM\/addison-wesley-opengl-es-3-0-programming-guide-2nd-2014.pdf<\/a><\/li>\n<li><a href=\"http:\/\/gamedev.stackexchange.com\/questions\/9668\/what-are-3d-textures\">http:\/\/gamedev.stackexchange.com\/questions\/9668\/what-are-3d-textures<\/a><\/li>\n<li><a href=\"http:\/\/www.gamedev.net\/topic\/655969-speed-gluniform-vs-uniform-buffer-objects\/\">http:\/\/www.gamedev.net\/topic\/655969-speed-gluniform-vs-uniform-buffer-objects\/<\/a><\/li>\n<li>Sijie Tian <a href=\"https:\/\/hacks.mozilla.org\/2014\/01\/webgl-deferred-shading\/\">https:\/\/hacks.mozilla.org\/2014\/01\/webgl-deferred-shading\/<\/a><\/li>\n<li>Dong Dong <a href=\"https:\/\/www.zhihu.com\/question\/49327688\/answer\/115691345?from=profile_answer_card\">https:\/\/www.zhihu.com\/question\/49327688\/answer\/115691345?from=profile_answer_card<\/a><\/li>\n<li>Cesium <a href=\"https:\/\/github.com\/AnalyticalGraphicsInc\/cesium\">https:\/\/github.com\/AnalyticalGraphicsInc\/cesium<\/a><\/li>\n<li>WebGL Stats <a href=\"http:\/\/webglstats.com\/\">http:\/\/webglstats.com\/<\/a><\/li>\n<li>WebGL 2 for Siggraph Asia 2015 <a href=\"https:\/\/docs.google.com\/presentation\/d\/1Orx0GB0cQcYhHkYsaEcoo5js3c5-pv7ahPniIRIzzfg\/edit#slide=id.gd1fc5cab2_0_8\">https:\/\/docs.google.com\/presentation\/d\/1Orx0GB0cQcYhHkYsaEcoo5js3c5-pv7ahPniIRIzzfg\/edit#slide=id.gd1fc5cab2_0_8<\/a><\/li>\n<li><a href=\"https:\/\/software.intel.com\/en-us\/articles\/early-z-rejection-sample\">https:\/\/software.intel.com\/en-us\/articles\/early-z-rejection-sample<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>This guest blog post is by\u00a0Shuai Shao, a Masters student at UPenn under Patrick Cozzi. After hearing the announcement at SIGGRAPH, I was asking around for someone to write a &#8220;basics of WebGL 2&#8221; article and Patrick got Shuai involved. If you&#8217;re reading this any time after October 2016, see his Github repo\u00a0for the latest [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[631,523,630],"class_list":["post-4421","post","type-post","status-publish","format-standard","hentry","category-misc","tag-opengl-es-3","tag-webgl","tag-webgl-2"],"_links":{"self":[{"href":"https:\/\/www.realtimerendering.com\/blog\/wp-json\/wp\/v2\/posts\/4421","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.realtimerendering.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.realtimerendering.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.realtimerendering.com\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.realtimerendering.com\/blog\/wp-json\/wp\/v2\/comments?post=4421"}],"version-history":[{"count":2,"href":"https:\/\/www.realtimerendering.com\/blog\/wp-json\/wp\/v2\/posts\/4421\/revisions"}],"predecessor-version":[{"id":4487,"href":"https:\/\/www.realtimerendering.com\/blog\/wp-json\/wp\/v2\/posts\/4421\/revisions\/4487"}],"wp:attachment":[{"href":"https:\/\/www.realtimerendering.com\/blog\/wp-json\/wp\/v2\/media?parent=4421"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.realtimerendering.com\/blog\/wp-json\/wp\/v2\/categories?post=4421"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.realtimerendering.com\/blog\/wp-json\/wp\/v2\/tags?post=4421"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}