<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Szenia Zadvornykh on Medium]]></title>
        <description><![CDATA[Stories by Szenia Zadvornykh on Medium]]></description>
        <link>https://medium.com/@Zadvorsky?source=rss-fb339efe5ccc------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*eGYGPv1nu6PTe_Hl.jpg</url>
            <title>Stories by Szenia Zadvornykh on Medium</title>
            <link>https://medium.com/@Zadvorsky?source=rss-fb339efe5ccc------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 22 May 2026 13:31:40 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@Zadvorsky/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Promise loading with Three.js]]></title>
            <link>https://itnext.io/promise-loading-with-three-js-78a6297652a5?source=rss-fb339efe5ccc------2</link>
            <guid isPermaLink="false">https://medium.com/p/78a6297652a5</guid>
            <category><![CDATA[promises]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[threejs]]></category>
            <dc:creator><![CDATA[Szenia Zadvornykh]]></dc:creator>
            <pubDate>Mon, 30 Apr 2018 18:28:17 GMT</pubDate>
            <atom:updated>2019-02-08T20:51:53.633Z</atom:updated>
            <content:encoded><![CDATA[<p>This is a quick post about my recent experiences using (native) ES6 promises to simplify loading handling in Three.js projects.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1MNcMKEek_Y8q9_HHyNewQ.png" /></figure><p>Going by Three.js examples, a common pattern for loading a geometry and corresponding textures looks something like this:</p><pre>const material = new THREE.MeshStandardMaterial({<br>  map: new THREE.TextureLoader().load(&#39;map.jpg&#39;),<br>  normalMap: new THREE.TextureLoader().load(&#39;normalMap.jpg&#39;)<br>});</pre><pre>const loader = new THREE.JSONLoader();</pre><pre>loader.load(&#39;geometry.json&#39;, geometry =&gt; {<br>  const mesh = new THREE.Mesh(geometry, material);<br>  <br>  scene.add(mesh);<br>});</pre><p>TextureLoader.load() returns a Texture, which is updated when the image is loaded. JSONLoader.load() is passed a onComplete callback, which is called when the JSON is loaded and processed. When the callback is called, a Mesh is created, whether the textures are loaded or not.</p><p>Sometimes this behavior is desired; you’re showing <em>something </em>as soon as possible. But there are also some issues, which I’m sure you’ve all seen before. If the geometry is loaded before the textures, the model appears untextured, <em>naked</em>, before the textures pop in one by one. As they do, there is a noticeable frame drop while they are processed and uploaded to the GPU.</p><p>Fortunately, these issues are easy to fix using <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a>.</p><p>First, let’s make a wrapper function around a JSONLoader and a Promise.</p><pre>function loadJSON(url) {<br>  return new Promise(resolve =&gt; {<br>    new THREE.JSONLoader.load(url, resolve);<br>  });<br>}</pre><p>This function returns a Promise that resolves with the loaded geometry when the file is loaded.</p><p>Next we can make a similar wrapper around a TextureLoader.</p><pre>function loadJSON(url) {<br>  return new Promise(resolve =&gt; {<br>    new THREE.TextureLoader().load(url, resolve);<br>  });<br>}</pre><p>Note that the TextureLoader also has an onComplete callback like the TextureLoader, though it’s used less frequently. In fact, I’m pretty sure all Three.js loaders conform to this convention.</p><p>Now let’s write another wrapper around the texture promises, which will resolve with a Material instance.</p><pre>function loadMaterial() {<br>  const textures = {<br>    map: &#39;map.jpg&#39;,<br>    normalMap: &#39;normalMap.jpg&#39;<br>  };<br>  <br>  const params = {};<br>  <br>  const promises = Object.keys(textures).map(key =&gt; {<br>    return loadTexture(textures[key]).then(texture =&gt; {<br>      params[key] = texture;  <br>    });<br>  });<br>  <br>  return Promise.all(promises).then(() =&gt; {<br>    return new THREE.MeshStandardMaterial(params);<br>  });<br>}</pre><p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all">Promise.all()</a> takes an array of promises and returns a Promise that resolves once all of the sub-promises are resolved.</p><p>Next we can combine the geometry and material promise wrappers into one final majestic wrapper function, once again relying on Promise.all().</p><pre>function loadMesh() {<br>  const promises = [<br>    loadGeometry(),<br>    loadMaterial()<br>  ];<br>  <br>  return Promise.all(promises).then(result =&gt; {<br>    return new THREE.Mesh(result[0], result[1]);<br>  });<br>}</pre><p>Promise.all() resolves with an array of values in the same order as the promises (or values) you supplied. In this case the result array looks like [geometry, material].</p><p>With the code above, we have essentially created a mini-loading manager that creates a Mesh once all of its assets have been loaded, all with very little (native) JavaScript. Neat.</p><p>Let’s flesh it out a little more. The code below is only one of many possible ways of going about this.</p><pre>const model = {<br>  geometry: {<br>    url: &#39;geometry.json&#39;<br>  },<br>  material: {<br>    map: &#39;map.jpg&#39;,<br>    normalMap: &#39;normalMap.jpg&#39;,<br>    metalness: 0.0,<br>    roughness: 1.0<br>  }<br>};</pre><pre>loadMesh(model).then(mesh =&gt; {<br>  scene.add(mesh);<br>});</pre><pre>function loadMesh(model) {<br>  const promises = [<br>    loadGeometry(model.geometry),<br>    loadMaterial(model.material)<br>  ];<br>  <br>  return Promise.all(promises).then(result =&gt; {<br>    return new THREE.Mesh(result[0], result[1]);<br>  });<br>}<br><br>function loadGeometry(model) {<br>  return new Promise(resolve =&gt; {<br>    new THREE.JSONLoader().load(model.url, resolve);<br>  });<br>}<br><br>const textureKeys = [&#39;map&#39;, &#39;normalMap&#39;]; // etc...<br><br>function loadMaterial(model) {<br>  const params = {};<br>  const promises = Object.keys(model).map(key =&gt; {<br>    // load textures for supported keys<br>    if (textureKeys.indexOf(key) !== -1) {<br>      return loadTexture(model[key]).then(texture =&gt; {<br>        params[key] = texture;<br>      });<br>    // just copy the value otherwise  <br>    } else {<br>      params[key] = model[key];<br>    }<br>  });<br>  <br>  return Promise.all(promises).then(() =&gt; {<br>    return new THREE.MeshStandardMaterial(params);<br>  });<br>}</pre><p>The model describes the assets and any additional settings for the Mesh. This is a useful abstraction. We can create many models, and use the code above to create the corresponding meshes. If you need to manage many models at the same time, the createMesh function can be put into another Promise.all() easily. It’s promises all the way down.</p><pre>const promises = models.map(model =&gt; {<br>  return loadMesh(model).then(mesh =&gt; {<br>    scene.add(mesh);<br>  });<br>});</pre><pre>Promise.all(promises).then(() =&gt; {<br>  // load complete! begin rendering<br>});</pre><p>Another upside of this approach is that promises can be resolved with with exiting or cached values without any changes to our API. This makes it easy to mix loaded and generated assets.</p><pre>const model = {<br>  geometry: {<br>    geometry: new THREE.SphereGeometry()<br>  },<br>  material: {...}<br>};<br><br>...<br><br>function loadGeometry(model) {<br>  if (model.geometry) {<br>    return Promise.resolve(model.geometry);<br>  }<br>  <br>  if (model.url) {<br>    return new Promise(resolve =&gt; {<br>      new JSONLoader().load(model.url, resolve);<br>    });  <br>  }<br>}</pre><p>I’ve written a handful of loading managers over the years, and I can tell you that promises simplify things greatly. You will still need to add logic of your own (caching, error handling, different loaders, additional parameters, etc), but not having to deal with concurrent asynchronous requests yourself is a huge time saver.</p><p>The snippets from this post can be found <a href="https://gist.github.com/zadvorsky/a79787a4703ecc74cab2fdbd05888e9b">here</a>. Snippet 06 contains all the final functions, and should work if you paste it.</p><p>I used a similar approach as outlined in this post in <a href="https://nike-react.com/">https://nike-react.com/</a>, which was by far the most asset management heavy project I’ve ever worked on. Promises, especially Promise.all(), were instrumental in keeping things manageable.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=78a6297652a5" width="1" height="1" alt=""><hr><p><a href="https://itnext.io/promise-loading-with-three-js-78a6297652a5">Promise loading with Three.js</a> was originally published in <a href="https://itnext.io">ITNEXT</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Fuzzy Meshes]]></title>
            <link>https://medium.com/@Zadvorsky/fuzzy-meshes-4c7fd3910d6f?source=rss-fb339efe5ccc------2</link>
            <guid isPermaLink="false">https://medium.com/p/4c7fd3910d6f</guid>
            <category><![CDATA[threejs]]></category>
            <category><![CDATA[animation]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[webgl]]></category>
            <dc:creator><![CDATA[Szenia Zadvornykh]]></dc:creator>
            <pubDate>Thu, 26 Oct 2017 15:20:24 GMT</pubDate>
            <atom:updated>2017-10-26T15:20:24.327Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AvIzhN-aqsdWw3GWo0fMUg.png" /></figure><p>I’m a big fan of everything fuzzy and furry, and for a while now I’ve been thinking about a way to implement some of that goodness in WebGL. Recently, as part of a series of code experiments at <a href="https://dpdk.com/">DPDK</a>, I finally found an excuse to dig into this.</p><p>In this post, I will walk though my process and the (mis)steps I took to get to a result that worked out surprisingly well.</p><p>Before I got started, I had the following outline in mind:</p><ul><li>Take a geometry (any geometry would do, but I wanted to start with the DPDK 3D plus model we’ve been using for <a href="https://codepen.io/collection/XMJjxN/">our other experiments</a>).</li><li>For each vertex of the geometry, create a “hair”. This would be a thin and tall THREE.ConeGeometry. The geometry would have multiple height segments to support bending.</li><li>Give each hair a default growth direction. This could be based on the vertex normal.</li><li>Apply a force (gravity) to the hair geometries so they would curve downward.</li></ul><p>I didn’t want to go down the simulation route. This would involve physics and more math than I can handle. Particularly hairy geometries would also likely be too intensive to compute in real time. Instead, I wanted to go for a convincing fake, using <a href="https://github.com/zadvorsky/three.bas">Three.Bas</a> to manipulate the hair geometries with maximum performance.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aCvpBdIraLBKUle9O-oimA.png" /><figcaption>A cone (gray) with gravity applied to it (black).</figcaption></figure><p>At first, I wanted to use data textures in the vertex shader to calculate and store positions for each vertex of the hair geometry. However, this would involve additional render passes, and it felt a little too complicated for my use case.</p><p>After putting some more thought into it, I decided to try using quaternions to rotate each hair vertex. The amount of rotation would depend on the vertex y position (between 0.0 and the length of the hair). This way vertices at the base of the hair would be affected less than vertices at the end, resulting in a nice curve.</p><p>The first result of this approach can be seen below.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fdpdknl%2Fembed%2Fpreview%2FmBwmNZ%3Fheight%3D600%26slug-hash%3DmBwmNZ%26default-tabs%3Djs%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fdpdknl%2Fpen%2FmBwmNZ%2F&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F304639.mBwmNZ.small.57a22d9f-aafc-4d67-9050-3896f15e61a1.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/74a69fd157c24643a6bce9a6cd248aeb/href">https://medium.com/media/74a69fd157c24643a6bce9a6cd248aeb/href</a></iframe><h3>Implementing Version 1</h3><p>The Three.js Quaternion class has an unassuming but very powerful method:</p><pre>Quaternion.setFromUnitVectors(from, to);</pre><p>This method creates a quaternion needed to transform a unit vector from (often representing a direction) to another unit vector to.</p><p>All the vertices in a Cone geometry are spread around the Y axis, so the default “direction” for the cone is up, or vec3(0.0, 1.0, 0.0). To achieve the curvature I was looking for, I added two quaternion attributes to the geometry:</p><ul><li>rMin, representing the rotation from UP to the neutral hair direction, based on the vertex normal.</li><li>rMax, representing the rotation from UP to the hair direction + gravity. Since gravity points downward, this boils down to a vector with a lower y value.</li></ul><p>Below is a simplified implementation of this. If you are unfamiliar with Three.bas and its API, please refer to my <a href="https://medium.com/@Zadvorsky/into-vertex-shaders-594e6d8cd804">previous tutorial series</a>.</p><pre>geometry.createAttribute(&#39;rMin&#39;, 4, (data, i) =&gt; {<br>  const direction = directions[i];</pre><pre>  quat.setFromUnitVectors(UP, direction);<br>  quat.toArray(data);<br>});</pre><pre>geometry.createAttribute(&#39;rMax&#39;, 4, (data, i) =&gt; {<br>  const direction = directions[i];<br>  <br>  direction.y -= GRAVITY; <br>  direction.normalize();<br>    <br>  quat.setFromUnitVectors(UP, direction);<br>  quat.toArray(data);<br>});</pre><p>Inside the vertex shader, I use these quaternions to rotate each vertex. The amount of rotation depends on position.y / hairLength. Vertices at the base of the hair are rotated to the neutral rotation. Vertices towards the end are rotated more downward, because gravity affects them more.</p><pre>float frc = position.y / hairLength;<br>vec3 pMin = rotateVector(rMin, position);<br>vec3 pMax = rotateVector(rMax, position);</pre><pre>transformed = mix(pMin, pMax, frc);<br>transformed += hairPosition;</pre><p>The hairPosition at the end is simply the position of the hair on the underlying model. It’s the same for each vertex in a single hair.</p><p>With this wired up and working, I added the growth animation logic along with some randomness throughout for the fuzzy look. Below you can see a version of the pen without these frills.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fembed%2Fpreview%2FOxKWRP%3Fheight%3D600%26slug-hash%3DOxKWRP%26default-tabs%3Djs%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fpen%2F77c51a650f4ae163bdf569a590354f71&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F175711.OxKWRP.small.5346a310-ab14-4998-8390-eb3d9ca75846.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/ded5323ee332c1490923ffcc406bdfbc/href">https://medium.com/media/ded5323ee332c1490923ffcc406bdfbc/href</a></iframe><h3>Once more, but with forces</h3><p>Next I wanted to implement some sort of faux physics logic so the hair could actually react to the mesh being moved around. This is where things get more complicated.</p><h4>Freeing up gravity</h4><p>In the version above, the rotation change created by the gravity is calculated on the CPU and stored in an attribute. We do not want to update attribute buffers each frame (this is incredibly slow), so the gravitational force is essentially stuck, baked into the attribute data. To get it unstuck (without changing the approach entirely), I decided to move the quaternion calculation logic to GLSL.</p><p>The first step was to port the Three.js Quaternion.setFromUnitVectors method from JavaScript.</p><pre>vec4 quatFromUnitVectors(vec3 from, vec3 to) {<br>  vec3 v;<br>  float r = dot(from, to) + 1.0;<br>  <br>  if (r &lt; 0.00001) {<br>    r = 0.0;<br>    <br>    if (abs(from.x) &gt; abs(from.z)) {<br>      v.x = -from.y;<br>      v.y = from.x;<br>      v.z = 0.0;<br>    }<br>    else {<br>      v.x = 0.0;<br>      v.y = -from.z;<br>      v.z = from.y;<br>    }<br>  }<br>  else {<br>    v = cross(from, to);<br>  }<br>  <br>  return normalize(vec4(v.xyz, r));<br>}</pre><p>As you can see, the method itself isn’t that complicated. There are more conditional steps than I’d like to see in GLSL, but I don’t dare remove them.</p><p>With this logic available on the GPU, I moved the gravity into a uniform, so it could be used in the shader.</p><pre>uniform vec3 gravity;<br>attribute vec3 baseDirection;</pre><pre>...</pre><pre>float frc = position.y / hairLength;<br>vec3 to = normalize(baseDirection + gravity * frc);<br>vec4 quat = quatFromUnitVectors(UP, to);</pre><pre>transformed = rotateVector(quat, transformed);</pre><p>In the code above, baseDirection is the neutral hair direction (the one based on the vertex normal). Gravity is stored as 3D vector (with a negative y value). Adding a fraction of the gravity to the baseDirection yields a new direction. Then we can use the quatFromUnitVectors method to rotate the vertex (which is still facing UP) to match the desired direction.</p><p>At this point, the fuzzy mesh looks pretty much the same as before (though I am now using the actual normals in stead of normalized positions like before).</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fembed%2Fpreview%2FveoxbZ%3Fheight%3D600%26slug-hash%3DveoxbZ%26default-tabs%3Djs%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fpen%2Fe917d43ddcb58d1d543bf32c17d6ae64&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F175711.veoxbZ.small.4629a6cd-ee43-4744-bf3f-9a585720af66.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/61e113478867ed9838c7c18e4e175748/href">https://medium.com/media/61e113478867ed9838c7c18e4e175748/href</a></iframe><p>With the quaternion calculations on the GPU, it was time to start figuring out how to apply additional forces based on movement and rotation.</p><h4>Movement</h4><p>Since the gravity was already stored in a 3D vector, I simply added a movement-based directional force to it. I renamed gravity to globalForce to reflect this change. To determine how much the mash moved, I stored a previous position alongside the current position, and used the difference between the two.</p><pre>FuzzyMesh.prototype.setPosition = function(p) {<br>  this.previousPosition.copy(this.position);<br>  this.position.copy(p);<br>  <br>  this.material.uniforms.globalForce.value<br>    .subVectors(this.previousPosition, this.position);</pre><pre>  this.material.uniforms.globalForce.value.y -= this.gravity;<br>}</pre><p>While this worked, the resulting hair movement was quite sluggish, sometimes a little choppy.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*12YIGTLTTV76NqlOmh-_cA.gif" /><figcaption>Movement force version 1.</figcaption></figure><p>I tried various ways to smooth this out, even going so far as to use short TweenMax animations to change the values. Finally I settled on creating an update function, which would be called each frame regardless of animation. There, I add a fraction of the movement delta to a movement force vector. This movement force vector is scaled down each frame, eventually reaching close to 0 if no new forces are applied.</p><pre>const movementDecay = 0.7;<br>const movementForceFactor = 0.5;</pre><pre>this.movementForce.multiplyScalar(movementDecay);<br>this.movementForce.x += this.positionDelta.x * movementForceFactor;<br>this.movementForce.y += this.positionDelta.y * movementForceFactor;<br>this.movementForce.z += this.positionDelta.z * movementForceFactor;</pre><pre>this.material.uniforms.globalForce.value.set(<br>  this.movementForce.x,<br>  this.movementForce.y - this.config.gravity,<br>  this.movementForce.z<br>);</pre><p>Note that the values for movementDecay and movementForceFactor are completely arbitrary (though the decay should be less than 1.0). As you can see below, the movement is now much smoother. Nice.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*RpBCNXubECJJVcGiHOzqmA.gif" /><figcaption>Movement force version 2.</figcaption></figure><h4>Rotation</h4><p>As for rotation, my goal was to apply a centrifugal force to the hair. I imagine the actual math for this can be pretty complicated. But it should be easy enough to approximate for this use case, right?</p><p>I broke the rotation down into an axis and an angle, which together form the quaternion for the mesh itself (remember that all Three.js objects have both a Euler and a Quaternion describing their rotation, which are kept in sync internally).</p><p>Having a separate angle makes it easier to measure rotation speed. I did this similarly to movement; storing a previousAngle alongside the current angle, and using the difference between the two to determine speed. This gave me the centrifugalForce, but I still needed a direction to apply this in.</p><p>If you spin an object around the y axis, the centrifugal force gets applied on the x and z axes, pushing away from the center of the object, like Homer so elegantly demonstrates below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*RXHlLUhxhsynp-YCDLo05Q.gif" /><figcaption>Centrifugal force.</figcaption></figure><p>If you spin it around the x axis, the force should push away on y and z. For rotation around the z axis, the force should push away on x and y. My initial implementation was as simple as that.</p><pre>FuzzyMesh.prototype.setRotationAxis = function(axis) {<br>  switch(axis) {<br>   case &#39;x&#39;:<br>    this.rotationAxis.set(1, 0, 0);<br>    this.centrifugalDirection.set(0, 1, 1);<br>    break;<br>   case &#39;y&#39;:<br>    this.rotationAxis.set(0, 1, 0);<br>    this.centrifugalDirection.set(1, 0, 1);<br>    break;<br>   case &#39;z&#39;:<br>    this.rotationAxis.set(0, 0, 1);<br>    this.centrifugalDirection.set(1, 1, 0);<br>    break;<br>  }<br>}</pre><p>While I could clearly see there was a pattern here, I could not figure out a way to make this work with an arbitrary rotation axis. This led me down a somewhat roundabout search involving perpendicular vectors, normals, binormals, tangents, and planes.</p><p>This was a classic case of overcomplicating the problem. It look me longer than I care to admit to realize that I could use the same method I had been using all along: Quaternion.setFromUnitVectors.</p><pre>FuzzyMesh.prototype.setRotationAxis = function(axis) {<br>  const ra = this.rotationAxis;<br>  const cd = this.material.uniforms.centrifugalDirection.value;<br>  const q = this._quat;</pre><pre>  ra.set(0, 1, 0);<br>  cd.set(1, 0, 1);</pre><pre>  q.setFromUnitVectors(ra, axis);<br><br>  cd.applyQuaternion(q);<br>  cd.normalize();<br>  cd.x = Math.abs(cd.x);<br>  cd.y = Math.abs(cd.y);<br>  cd.z = Math.abs(cd.z);<br>  <br>  ra.copy(axis);<br>};</pre><p>In the method above, the rotation axis and centrifugal direction are first reset to their default values (rotation around the y axis). Then I calculate the quaternion to rotate the default rotation axis to the new rotation axis. Then I use this quaternion to rotate the centrifugal direction by the same amount. Finally I make sure the centrifugal direction values are positive (always pushing away from the center). I also normalize the value (since this is a direction), which I had forgotten to do before.</p><p>Inside the shader, the rotation force is calculated based on centrifugalDirection and rotation speed (centrifugalForce). I went through several iterations of how to actually apply this force. In the end settled on the code below (though I may still need to change things up).</p><pre>// start with the global force calculated in JS<br>vec3 totalForce = globalForce;<br>// add centrifugal force for this hair / vertex<br>totalForce += <br>  hairPosition * centrifugalDirection * centrifugalForce;</pre><p>I use hairPosition there because hair away from the center of the mesh should be more strongly affected by rotational force.</p><p>There was one more step to take to finalize the rotation logic. If the mesh is rotated, the hair geometries are rotated along with it. To compensate for this, I had to rotate the globalForce in the opposite direction. Luckily, this is easily achieved by using the <em>conjugate</em> of the meshes quaternion. The conjugate of a quaternion is like the inverse of a matrix; it describes the opposite transformation. Luckier still, the Three.js Quaternion class has this method build in.</p><pre>this.conjugate.copy(this.quaternion).conjugate();<br>this.material.uniforms.globalForce.value<br>  .applyQuaternion(this.conjugate);</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*dJVuz8e7vqBYsqMMQpS8og.gif" /><figcaption>Weee!</figcaption></figure><h4>Adding some noise</h4><p>There was one last thing bothering me. When the mesh stops moving, the hair stops moving a little while later. This is good, but all of it stops at the same time. That doesn’t look quite right.</p><p>To solve this, I decided to use the trusty sine wave to add a little oscillation inside the shader. I based this on a global settleTime uniform and a settleOffset attribute, randomized for each hair.</p><pre>totalForce *= <br>  1.0 - (sin(settleTime + settleOffset) * 0.05 * settleScale);</pre><p>settleTime is incremented each frame. settleScale is increased when force is applied (either movement or rotation), and slowly scaled back to 0 each frame.</p><p>All of these changes lead to the result below. The bouncy mesh animation is controlled by TweenMax, and the hair simply reacts to the change in position and rotation. Sweet.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fdpdknl%2Fembed%2Fpreview%2FzEjadW%3Fheight%3D600%26slug-hash%3DzEjadW%26default-tabs%3Djs%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fdpdknl%2Fpen%2FzEjadW&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F304639.zEjadW.small.6ad8979b-4ffe-43e3-aa06-271952111785.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/53bea1354a57bda0bbefa38a5f27fb42/href">https://medium.com/media/53bea1354a57bda0bbefa38a5f27fb42/href</a></iframe><h4>Too much rotation</h4><p>I was pretty stoked about the result, and how well it all seemed to work, but as I was experimenting with different value ranges, I soon realized that I had a serious problem. If the forces, especially gravity, applied to the mesh are strong, the hair that stands close to upright gets noticeably deformed and elongated.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fembed%2Fpreview%2FZXgLEK%3Fheight%3D600%26slug-hash%3DZXgLEK%26default-tabs%3Djs%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fpen%2F5f83a0570cc200ef34958f4bd1d57800&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F175711.ZXgLEK.small.d5cf200c-8e7e-4916-980f-f6fa0d359f85.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/091e8ca74a6a66bb0134522ab60a6127/href">https://medium.com/media/091e8ca74a6a66bb0134522ab60a6127/href</a></iframe><p>No good.</p><p>To try to make sense of why this was happening, I eventually took to Illustrator to help visualize the problem. Below you can see an image showing how the quaternion approach rotates each point on the line.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HruS6G1avt1mSdGerqFZ8g.png" /><figcaption>Approximation of how each vertex is rotated based on gravity.</figcaption></figure><p>As you can see, the distances between the vertices (the black dots) become longer the more a vertex is displaced, while they <em>should</em> stay the same. After some deep thought, I realized this was happening because I was rotating each vertex around the same origin (0, 0, 0).</p><p>First I tried to mitigate this problem by changing how I interpolate the length fractions, which didn’t really solve anything. I also tried simply scaling down the rotated position based on the amount of displacement, but this just lead to different deformities because the origin was still wrong.</p><p>Finally, I figured that there was no way around it: I had to calculate the rotations recursively. I was a little reluctant to go down this path, since I thought it would add a lot of overhead. Luckily, it turned out that I had plenty of leeway there.</p><p>The actual implementation did take <em>some</em> of trial and error. The result can be seen below.</p><pre>defines: {<br>  &#39;HAIR_LENGTH&#39;:  (hairLength).toFixed(2),<br>  &#39;SEGMENT_STEP&#39;: (hairLength / heightSegments).toFixed(2),<br>  &#39;FORCE_STEP&#39;:   (1.0 / hairLength).toFixed(2)<br>}</pre><pre>...</pre><pre>// accumulator for position<br>vec3 finalPosition;</pre><pre>// get height fraction between 0.0 and 1.0<br>float f = position.y / HAIR_LENGTH;<br>// determine target position based on force and height fraction<br>vec3 to = normalize(baseDirection + totalForce * f);<br>// calculate quaterion needed to rotate UP to target rotation<br>vec4 q = quatFromUnitVectors(UP, to);<br>// only apply this rotation to position x and z<br>// position y will be calculated in the loop below<br>vec3 v = vec3(position.x, 0.0, position.z);<br><br>finalPosition += rotateVector(q, v);<br><br>// recursively calculate rotations using the same approach as above<br>for (float i = 0.0; i &lt; HAIR_LENGTH; i += SEGMENT_STEP) {<br>  if (position.y &lt;= i) break;<br><br>  float f = i * FORCE_STEP;<br>  vec3 to = normalize(baseDirection + totalForce * f);<br>  vec4 q = quatFromUnitVectors(UP, to);<br>  // apply this rotation to a &#39;segment&#39;<br>  vec3 v = vec3(0.0, SEGMENT_STEP, 0.0);<br>  // all segments are added to the final position<br>  finalPosition += rotateVector(q, v);<br>}</pre><p>Instead of rotating the vertex around the origin, the loop rotates smaller vectors, equal to the length of the hair divided by the number of height segments, and adds the resulting vectors to the final position of the vertex. The loops breaks when the y coordinate of the vertex is reached. I had to rely on defines here, since GLSL does not support non-static loops.</p><p>While this computation is obviously more expensive, the performance didn’t seem to suffer too much.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fdpdknl%2Fembed%2Fpreview%2FJrgrJN%3Fheight%3D600%26slug-hash%3DJrgrJN%26default-tabs%3Djs%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fdpdknl%2Fpen%2F69aaf21194d8869a9588a68d3be47f43%2F&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F304639.JrgrJN.small.c051b045-119c-4e9b-917f-72cc712fb234.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/dd9e242e96aa35e3cd3d947fd871b187/href">https://medium.com/media/dd9e242e96aa35e3cd3d947fd871b187/href</a></iframe><h4>Final Thoughts</h4><p>The code for this demo can be found <a href="https://github.com/zadvorsky/three-fuzzy-mesh">here</a>. It’s still a work in progress, but you should be able to take src/FuzzyMesh.js for a spin.</p><p>Currently there are a lot of magic numbers that define how much the various forces impact the hair, and you may need to tweak their values depending on your animation. There may also be ways to simplify some of the rotation math. If you have any suggestions, I’m all ears!</p><p>I will continue playing around with this, so expect to see more fuzzy (or perhaps leafy?) WebGL meshes in the near future.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4c7fd3910d6f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Into Vertex Shaders Part 4: Form Follows Function]]></title>
            <link>https://medium.com/@Zadvorsky/into-vertex-shaders-part-4-form-follows-function-1c86d0726ee8?source=rss-fb339efe5ccc------2</link>
            <guid isPermaLink="false">https://medium.com/p/1c86d0726ee8</guid>
            <category><![CDATA[tutorial]]></category>
            <category><![CDATA[threejs]]></category>
            <category><![CDATA[animation]]></category>
            <category><![CDATA[webgl]]></category>
            <dc:creator><![CDATA[Szenia Zadvornykh]]></dc:creator>
            <pubDate>Tue, 01 Aug 2017 19:00:01 GMT</pubDate>
            <atom:updated>2017-08-01T19:00:01.420Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fDzk1IiNl67hW3gBjMWW6Q.jpeg" /></figure><p>This is the fourth and final in a <a href="https://medium.com/@Zadvorsky/into-vertex-shaders-594e6d8cd804">series of articles</a> about advanced WebGL animation using <a href="https://threejs.org/">Three.js</a> and <a href="https://github.com/zadvorsky/three.bas">Three.bas</a>, my extension for complex and highly performant animation systems.</p><p>In the previous post we created a utilitarian animation to demonstrate how Three.bas operates. In this post we will continue down the rabbit hole and explore how we can use vertex shaders to create more pleasing animation systems.</p><h3>Easing</h3><p>First, lets take a look at easing. This is a topic most of you should at least be casually familiar with. The standard <a href="http://easings.net/">easing functions</a>, first formalized by Robert Penner, have made their way into practically every animation tool and library. Simply put, easing functions change the curve of how a value changes over time. These functions also integrate smoothly with GLSL.</p><p>The simplest easing function is linear, or no easing at all.</p><pre>function easeLinear(t, b, c, d) {<br>  return b + (t / d) * c;<br>}</pre><p>The four arguments are as follows:</p><ul><li><strong>t</strong>ime: The current time in the animation (relative to duration).</li><li><strong>b</strong>egin value: The initial value of the property being animated.</li><li><strong>c</strong>hange in value: The delta of the property being animated.</li><li><strong>d</strong>uration: The total duration of the animation (relative to time).</li></ul><p>These four arguments are the same for all other easing functions. Using a different easing function will change the animation curve while keeping the same signature, making them easy to swap in and out.</p><p>Below you can see the quad-in ease function and its GLSL equivalent.</p><pre>// js<br>function easeQuadIn(t, b, c, d) {<br>  return b + (t / d) * (t / d) * c;<br>}</pre><pre>// glsl<br>float easeQuadIn(float t, float b, float c, float d) {<br>  return b + (t / d) * (t / d) * c;<br>)</pre><p>Other than the differences in syntax, the GLSL function is just as simple and compact as the JavaScript version.</p><p>Easing functions can be simplified further if both the change in value and the animation duration are in the range of 0.0 to 1.0 (the value changes from 0.0 to 1.0 over 1 second).</p><pre>// original quad-in formula<br>return b + (t / d) * (t / d) * c;</pre><pre>// begin = 0.0, change = 1.0<br>return 0.0 + (t / d) * ( t / d) * 1.0;</pre><pre>// 0.0 and 1.0 can be removed safely<br>return (t / d) * (t / d);</pre><pre>// d = 1.0<br>return (t / 1.0) * (t / 1.0);</pre><pre>// 1.0 can be removed safely<br>return t * t;</pre><p>The same process can be applied to all other easing functions, giving us functions that take a single argument (time) and return an eased value. In the previous post, we determined the animation state based on a progress value between 0.0 and 1.0. This will match up nicely.</p><p>Three.bas comes with <a href="https://codepen.io/zadvorsky/pen/qNdrmR">GLSL implementations</a> of all the standard Penner easing functions in both the four and the single argument variants. It also comes with a <a href="https://github.com/zadvorsky/three.bas/blob/master/examples/easing_bezier/main.js">Bézier curve based easing implementation</a> similar to CSS.</p><p>Now let’s add some easing to the cube animation we created in the previous post. This is easy; all we have to do is add a few lines in our material definition.</p><pre>material = new THREE.BAS.PhongAnimationMaterial({<br>  vertexFunctions: [<br>    // add the easeCubicInOut function<br>    <strong>THREE.BAS.ShaderChunk[&#39;ease_cubic_in_out&#39;]</strong>   <br>  ],<br>  vertexPosition: [<br>    // calculate progress between 0.0 and 1.0<br>    &#39;float p = clamp(time - startTime, 0.0, d) / d;&#39;,<br>    <br>    // apply easing function  <br>    <strong>&#39;progress = easeCubicInOut(progress);&#39;,</strong></pre><pre>    // ... rest of animation logic<br>  ]<br>});</pre><p>Below you can see the animation with easing applied to it, which makes the motion look more natural. Feel free to switch up the easing functions to see how the motion is effected.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fembed%2Fpreview%2FRZagNp%3Fheight%3D600%26slug-hash%3DRZagNp%26default-tabs%3Djs%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fpen%2F177b9c2ef2d0fc6132446eeb3068b054&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fm.cdpn.io%2Fscreenshot-coming-soon-small.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/87a1124b7cbbad6c845c96a95a5aa9ed/href">https://medium.com/media/87a1124b7cbbad6c845c96a95a5aa9ed/href</a></iframe><h3>Scale &amp; Rotation</h3><p>So far we have only animated position, but that’s not the only (affine) transformation we can use.</p><p>Scale is pretty easy to implement. All we have to do multiply the vertex position by either a number (for the same scale across all axes) or a vector (for different scale across the axes).</p><pre>float scale = 0.5 // or calculate with progress and/or attributes</pre><pre>// apply the scale scale to x, y and z<br>transformed *= scale;</pre><p>Implementing rotation is a little more involved. The most obvious way may be to use a matrix, and fold translation and scale into it. However, this means storing 16 numbers per vertex. It also removes the ability to calculate position, scale, and rotation independently.</p><p>After looking at possible solutions, I settled on using quaternions. A quaternion defines rotation based on a normalized axis (x, y, z) and a rotation around that axis in radians (w). Four numbers in total, which fit neatly into a vec4. The quaternion can then be applied to a vector to rotate it.</p><pre>// create a quaternion from an axis and angle<br>vec4 quatFromAxisAngle(vec3 axis, float angle) {<br>  float halfAngle = angle * 0.5;</pre><pre>  return vec4(axis.xyz * sin(halfAngle), cos(halfAngle));<br>}</pre><pre>// apply the quaternion (q) to a vector (v)<br>vec3 rotateVector(vec4 q, vec3 v) {<br>  return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v);<br>}</pre><p>Please don’t ask me how or why any of this works. Just think of a quaternion as a kind of pseudo-matrix for rotation alone.</p><p>The two functions above are included in Three.bas. They can be used the same way as the easing functions. To animate the rotation, you can calculate the axis and/or angle based on our trusty progress between 0.0 and 1.0.</p><pre>material = new THREE.BAS.PhongAnimationMaterial({<br>  vertexFunctions: [<br>    // add quatFromAxisAngle and rotateVector<br>    <strong>THREE.BAS.ShaderChunk[&#39;quaternion_rotation&#39;]</strong>   <br>  ],<br>  vertexParameters: [<br>   <strong>&#39;attribute vec4 rotation;&#39;</strong><br>  ],<br>  vertexPosition: [<br>    // rotation angle based on progress<br>    <strong>&#39;float angle = rotation.w * progress;&#39;</strong>,</pre><pre>    // quaternion based on axis and current angle     <br>    &#39;<strong>vec4 quat = quatFromAxisAngle(rotation.xyz, angle);</strong>&#39;</pre><pre>    // apply quaternion to vector to rotate it  <br>    &#39;<strong>transformed = rotateVector(quat, transformed);</strong>&#39;<br>  ]<br>});</pre><p>Let’s add some scale and rotation to our animation. Check out the JavaScript for more details about the implementation.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fembed%2Fpreview%2FyXdLEW%3Fheight%3D600%26slug-hash%3DyXdLEW%26default-tabs%3Djs%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fpen%2Ffaf02cf856235cb3fc01b5ae480b5cb4%2F&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F175711.yXdLEW.small.33ee44bb-a687-40c3-9165-e5af7b4c5d25.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/83a2998d3aab54101ff1679d0a5ce3d5/href">https://medium.com/media/83a2998d3aab54101ff1679d0a5ce3d5/href</a></iframe><h3>Interpolations</h3><p>Up until now have mostly used linear interpolation to animate movement. This works quite well, but it may get boring after a while. Fortunately there are many, many functions and equations we can use instead.</p><h4><strong>Bézier </strong>Curves</h4><p>Bézier curves are one step up from linear interpolation. They are ubiquitously used in many types of graphics software and graphics libraries. A Bézier curve is defined by a start point, end point and two control points.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PTufqRlqtzJo0nKWddJvTQ.png" /></figure><p>Positions along the curve can be interpolated based on a value between 0.0 and 1.0. The GLSL implementation of this can be seen below.</p><pre>// p0: start position<br>// c0: control point 1<br>// c1: control point 2<br>// p1: end position<br>vec3 cubicBezier(vec3 p0, vec3 c0, vec3 c1, vec3 p1, float t) {   <br>  float tn = 1.0 - t;</pre><pre>  return <br>    tn * tn * tn * p0 + <br>    3.0 * tn * tn * t * c0 + <br>    3.0 * tn * t * t * c1 + <br>    t * t * t * p1;<br>}</pre><p>This formula may be imposing, but once you define it you can simply use it over and over again. The cubic Bézier is also included in Three.bas. To use it, we have to include it the same way as the functions above. We also need to define two additional vertex attributes for the control points.</p><pre>material = new THREE.BAS.PhongAnimationMaterial({<br>  vertexFunctions: [<br>    // add cubicBezier function<br>    <strong>THREE.BAS.ShaderChunk[&#39;cubic_bezier&#39;]</strong>   <br>  ],<br>  vertexParameters: [<br>   <strong>&#39;attribute vec3 controlPoint0;&#39;,<br>   &#39;attribute vec3 controlPoint1;&#39;<br>  </strong>],<br>  vertexPosition: [<br>    // names abbreviated to fit on one line<br>    // s = startPosition<br>    // c0 = controlPoint0<br>    // c1 = controlPoint1<br>    // e = endPosition<br>    &#39;<strong>transformed += cubicBezier(s, c0, c1, e, progress);</strong>&#39;<br>  ]<br>});</pre><p>Below you can see our animation with the Bézier curve used to interpolate position. Check out the JavaScript for the full code. The logic to define the control points is completely arbitrary, so feel free to experiment.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fembed%2Fpreview%2FawgbXZ%3Fheight%3D600%26slug-hash%3DawgbXZ%26default-tabs%3Djs%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fpen%2F2c82bd5ebf9c41aa067c3ceae74d70e1&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F175711.awgbXZ.small.4b7cc1e8-7efa-49a7-b511-ee09ec401b4d.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/4bb24a1ed2055f247876637e441335af/href">https://medium.com/media/4bb24a1ed2055f247876637e441335af/href</a></iframe><h4>Catmull-Rom Spline</h4><p>A Catmull-Rom spline defines a smooth curve through four or more points. This is similar to a Bézier curve, but the line actually goes through the points instead of only being pulled towards them. Since we are not limited to just four points, we can create complex and smooth motion paths. This does however make splines more difficult to implement.</p><p>We will store the spline as an array of points. We could use an attribute for this, but if the spline is long, storing (and duplicating) the data per vertex will become a bottleneck of its own. Instead I tend to store the spline as a uniform, a master spline if you will. Then I use attributes to store offsets from this spline, giving each prefab its own path to follow. Since we only need 3 components (x, y, z) to store the path itself, I often use the 4th component (w) to scale this offset at each point of the spline. Spline interpolation can be applied in any number of dimensions.</p><p>In the next example you can see our brave little cubes following a spline using the approach outlined above. The master spline and the offset scales are shown in dark gray. Please refer to the JavaScript for the full implementation (this setup is a little different from what we had before).</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fembed%2Fpreview%2FbrporW%3Fheight%3D600%26slug-hash%3DbrporW%26default-tabs%3Djs%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fpen%2F5261849a437ca27aace7cf7b4d60dca4&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F175711.brporW.small.2be41a81-5644-499d-987f-1020bb419bcc.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/013ca0c01eaa5a522bb1915b5b6c14f0/href">https://medium.com/media/013ca0c01eaa5a522bb1915b5b6c14f0/href</a></iframe><h4>Parametric functions</h4><p>Another wealth of interpolation options can be found in <a href="https://en.wikipedia.org/wiki/Parametric_equation">parametric functions</a>. Parametric functions take a one dimensional input (time or progress) and return a multi-dimensional output (position). A basic example of this is using sine and cosine to calculate a position on circle with a given radius.</p><pre>uniform float radius;</pre><pre>vec2 sample(float progress) {<br>  vec2 position;<br>  float angle = progress * PI * 2.0;</pre><pre>  position.x = cos(angle) * radius;<br>  position.y = sin(angle) * radius;</pre><pre>  return pos;<br>}</pre><p>Using this as a basis you can define an endless variety of curves an knots that once again can be interpolated based on a progress value. In the example below we use sine and cosine to create a spiral on the x and z axis, while using linear interpolation along the y axis.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fembed%2Fpreview%2FJyXOwW%3Fheight%3D600%26slug-hash%3DJyXOwW%26default-tabs%3Djs%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fpen%2F0dbcc06d6bb8530204ddd787d695cc2d&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F175711.JyXOwW.small.6d1f23b1-a8ed-4ce3-8cf6-8e28dd0a0d7a.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/2e4b035257cbd17a209b2e0222d2b844/href">https://medium.com/media/2e4b035257cbd17a209b2e0222d2b844/href</a></iframe><p>Again, this is a very basic example, but it should illustrate the principle. Parametric functions can get very complex, creating beautiful shapes and motion paths. Do note however that trigonometric functions (like sine and cosine) tend to be on the expensive side.</p><p>I hope that this post, along with the ones before it, have given you a better understanding of the inner workings of WebGL and Three.js, along with the tools to help you harness their power. We (myself included) have only scratched the surface of what is possible here. To all of you who want to venture deeper, I wish good luck. And thanks for reading.</p><p>For more examples, documentation, and other tidbits, check out the <a href="https://github.com/zadvorsky/three.bas">Three.bas github page</a> or my <a href="https://codepen.io/zadvorsky/">CodePen profile</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1c86d0726ee8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Into Vertex Shaders Part 3: Memory Management]]></title>
            <link>https://medium.com/@Zadvorsky/into-vertex-shaders-part-3-memory-management-9a1204221a0a?source=rss-fb339efe5ccc------2</link>
            <guid isPermaLink="false">https://medium.com/p/9a1204221a0a</guid>
            <category><![CDATA[webgl]]></category>
            <category><![CDATA[threejs]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[tutorial]]></category>
            <dc:creator><![CDATA[Szenia Zadvornykh]]></dc:creator>
            <pubDate>Wed, 28 Jun 2017 17:01:20 GMT</pubDate>
            <atom:updated>2017-08-01T19:00:18.435Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fDzk1IiNl67hW3gBjMWW6Q.jpeg" /></figure><p>This is the third in a <a href="https://medium.com/@Zadvorsky/into-vertex-shaders-594e6d8cd804">series of articles</a> about advanced WebGL animation using <a href="https://threejs.org/">Three.js</a> and <a href="https://github.com/zadvorsky/three.bas">Three.bas</a>, my extension for complex and highly performant animation systems.</p><p>In the previous post we emulated parts of the 3D graphics pipeline to better understand how some key pieces fit together. In this post we will build on this, and take a closer look at what happens on the hardware level when you tell WebGL to do stuff.</p><p>My Three.js extension helps create animations where many objects can be moved (transformed) simultaneously. The key to my approach is moving some logic that is typically done in JavaScript (which is executed on the CPU) to GLSL (which is executed on the GPU). To understand the reasons for this, we will first create an animation system using a more traditional approach.</p><h3>Many Cubes</h3><p>The animation in question will be quite straight forward. We will create a number of cubes, and transition them from a start position to an end position over time.</p><p>First we define a Geometry and a Material. Then we use these to create a number of Meshes. We also define some custom properties to prepare for the animation logic.</p><pre>var geometry = new THREE.BoxGeometry(...);<br>var material = new THREE.MeshPhongMaterial();</pre><pre>for (var x = 0; x &lt; gridLength; x++) {<br>  for (var y = 0; y &lt; gridLength; y++) {<br>    for (var z = 0; z &lt; gridLength; z++) {<br>      var mesh = new THREE.Mesh(geometry, material);</pre><pre>      // define animation properties<br>      mesh.startPosition = new THREE.Vector3(...);<br>      mesh.endPosition = new THREE.Vector3(...);<br>      mesh.duration = 1;<br>      mesh.startTime = 0;</pre><pre>      scene.add(mesh);<br>    }<br>  }<br>}</pre><p>There is a handful of ways you could set up the animation logic, but we will try to do it in a way that minimizes overhead (to give the CPU a fighting chance).</p><p>The crux of our animation logic is <strong>linear interpolation </strong>in the form of</p><pre>currentValue = startValue + (endValue - startValue) * progress</pre><p>This is a generalized formula to calculate a value between a start and an end value based on a progress between 0.0 and 1.0. It has many applications and its use has become quite ubiquitous.</p><p>Each frame, we use linear interpolation to determine the current position of each cube. The progress is calculated based on startTime and duration of each cube, and a global time value. This value controls the state of the animation.</p><pre>function update() {<br>  time += 1/60;<br>  <br>  for (var i = 0; i &lt; cubes.length; i++) {<br>    var cube = cubes[i];<br>    var st = cube.startTime;<br>    var d = cube.duration;<br>    var sp = cube.startPosition;<br>    var ep = cube.endPosition;<br>    // progress in range of [0.0 to 1.0]<br>    var p = THREE.Math.clamp(time - st, 0, d) / d;<br>    <br>    // lerpVectors performs linear interpolation<br>    cube.position.lerpVectors(sp, ep, p);<br>  }<br>}</pre><p>Below you can see the running animation. Please take a look at the JavaScript to see the complete code. The buttons can be used to control the number of cubes that are created.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fembed%2Fpreview%2FowoPaz%3Fheight%3D600%26slug-hash%3DowoPaz%26default-tabs%3Djs%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fpen%2FowoPaz%2F&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F175711.owoPaz.small.b42416fd-de1e-49f1-8621-7d6e91217d06.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/4d37eb4d27409c4c222a323cf636d32e/href">https://medium.com/media/4d37eb4d27409c4c222a323cf636d32e/href</a></iframe><p>Depending on your device, the animation should run fine with a few hundred cubes. It may even be able to handle a thousand. But if you add many more, you will see a sharp decrease in performance.</p><p>Have we hit the limits of what WebGL can do?</p><h3>Too many cubes?</h3><p>The short answer is no.</p><p>For the long answer, we need to examine what is actually happening on the hardware level.</p><p>In the previous post we saw how matrices are used to store the transformation for a mesh in a scene. A transformation matrix consists of 16 numbers. Each mesh in our scene has its own transformation matrix. When the position of a mesh is changed in JavaScript (on the CPU), its matrix needs to be updated and sent to the GPU.</p><p>The CPU and the GPU are two separate entities connected by a strict communication protocol. The GPU is optimized to perform computation in parallel, meaning it can do a lot of math at the same time. However, when you send new data to the GPU, these computations are interrupted. The new data needs to be processed before the GPU can resume. The more data you send to the GPU, the bigger the interruption becomes.</p><p>When our animation system has too many cubes (each representing 16 numbers), the GPU has to spend more time processing new data than it gets to spend on doing what it loves to do: math.</p><p>The key to getting the most out of the GPU is minimizing the quantity of new data that it has to process each frame. While we cannot significantly reduce the amount of data we need to calculate the animation state, we <em>can </em>change how the data is handled between the CPU and the GPU.</p><h3>More Cubes!</h3><p>Currently, the bottleneck is the JavaScript position calculation that forces the meshes’ transformation matrix to update each frame. To resolve this bottleneck, we can move the animation update logic from JavaScript to GLSL. Since the CPU and the GPU are separate entities in terms of memory, we also need to store the required data on the GPU.</p><h4>Custom Attributes</h4><p>When we created the meshes for the animation, we defined four custom properties: startPostion, endPosition, startTime, and duration. This is the data required for the animation state calculation. Since this data is different for each mesh, the best way to store it on the GPU is using custom attributes in the cube geometry.</p><p>As mentioned in the previous post, a 3D geometry consists of a list of vertices. You can think of a vertex as a JavaScript object with a number of properties, called attributes. Position is one such attribute, but like a JavaScript object, a vertex can have any number of attributes.</p><p>Thinking in terms of JavaScript, adding additional properties would be simple:</p><pre>var vertex = {<br>  position: new THREE.Vector3(...),<br><strong>  startPosition: new THREE.Vector3(...),<br>  endPosition: new THREE.Vector3(...),<br>  startTime: 0.0,<br>  duration: 1.0</strong><br>};</pre><p>Unfortunately, adding vertex attributes is a little more involved. While the object representation of a vertex is easy to reason about, objects are an inefficient way of storing (lots of) data in memory. Instead, vertex attributes are flattened (destructured) and stored in arrays called <strong>buffers</strong>.</p><p>Each vertex attribute has its own buffer. Buffers have a fixed size, which is determined upon creation. The size of the buffer depends on two things: the number of vertices and the size of the attribute. For instance, position is defined by 3D vectors, so the size of each attribute is 3 (x, y, z). A single cube has 8 vertices, so the position buffer length would be <strong>8 × 3 = 24</strong>. The buffer itself would look something like this:</p><pre>[v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, ...etc]</pre><p>As for our custom properties, the attribute size for startPosition and endPositions is 3. The attribute size for startTime and duration is 1. Later on, Three.bas will help us create the buffers of the correct size.</p><h4>Buffer Geometry</h4><p>Before we continue, there is one more important thing we need to consider. If you look at how we created the meshes, you may notice that each mesh uses the same geometry and material, in stead of creating new instances. This way Three.js can optimize its internal render logic, and draw all the cubes at once. Each mesh is essentially a copy of the geometry rendered with a different transformation matrix. It is much faster to render the same geometry a thousand times than it is to render a thousand different geometries once.</p><p>We will be adding additional vertex attributes to the geometry, and these values will be different for each mesh. Because of this, Three.js can no longer perform its optimizations, so we will have to do it ourselves. Fortunately Three.js does provide a class that will help us: <a href="https://threejs.org/docs/#api/core/BufferGeometry">THREE.BufferGeometry</a>. Buffer Geometry makes it easier to work with vertex attribute buffers directly (in stead of the object representations found in THREE.Geometry).</p><p>In Three.Bas, I created a wrapper around this class that helps create buffer geometries where base geometries are repeated a given number of times. I refer to this base geometry as a <em>prefab</em>. This wrapper also helps create and populate buffers as discussed above.</p><pre>// create the geometry that will be repeated in the buffer geometry<br>prefab = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);</pre><pre>// create the buffer geometry where the prefabs are repeated<br>geometry = new THREE.BAS.PrefabBufferGeometry(prefab, cubeCount);</pre><pre>// create buffers with the appropriate item size<br>var startPositionBuffer = <br>  geometry.createAttribute(&#39;startPosition&#39;, 3);</pre><pre>var endPositionBuffer = <br>  geometry.createAttribute(&#39;endPosition&#39;, 3);</pre><pre>var durationBuffer = <br>  geometry.createAttribute(&#39;duration&#39;, 1);</pre><pre>var startTimeBuffer = <br>  geometry.createAttribute(&#39;startTime&#39;, 1);</pre><h4>Creating an Animation Shader</h4><p>Now that the data required to calculate the state of our animation is available on the GPU, we need to move the update logic there too. We will do this by “extending” a built-in Three.js material with a few lines of GLSL.</p><p>Three.js has a number of built-in materials, and the corresponding shaders are represented as strings. Because some logic is shared between these materials, the shader code is broken down into <em>chunks</em>, which are concatenated together into the final shader code.</p><p>Three.bas builds on this principle by injecting custom shader chunks in key places inside the original Three.js shader code. This allows you to define arbitrary (animation) logic in GLSL, while still being able to use all of the built-in features of Three.js, like lighting. Pretty cool.</p><p>The GLSL equivalent of our JavaScript update logic is as follows:</p><pre>// define attributes and uniforms</pre><pre>uniform float time;<br>attribute vec3 startPosition;<br>attribute vec3 endPosition;<br>attribute float startTime;<br>attribute float duration;</pre><pre>// ...then inside the main function</pre><pre>float progress = clamp(time - startTime, 0, duration) / duration;<br>position += mix(startPosition, endPosition, progress);</pre><p>The attribute declarations must have the same name and type as the buffers we created. We also use two built-in GLSL methods: clamp and mix. clamp will ensure a value is between a upper and a lower bound. In this case, it will make sure progress is always between 0.0 and duration. Diving this by duration will give us a value between 0.0 and 1.0. mix performs linear interpolation as described earlier this post.</p><p>Below we use Three.bas to inject this GLSL code into the built-in THREE.MeshPhongMaterial. We also define time as a uniform to be used in the vertex shader. When put together, the custom buffer geometry and shader material can be used to create a single mesh, which is added to the scene.</p><pre>material = new THREE.BAS.PhongAnimationMaterial({<br>  uniforms: {<br>    time: {value: 0}<br>  },<br>  vertexParameters: [<br>    &#39;uniform float time;&#39;,<br>    <br>    &#39;attribute vec3 startPosition;&#39;,<br>    &#39;attribute vec3 endPosition;&#39;,<br>    &#39;attribute float startTime;&#39;,<br>    &#39;attribute float duration;&#39;,<br>  ],<br>  vertexPosition: [<br>    &#39;float p = clamp(time - startTime, 0.0, duration) / duration;&#39;,<br>    &#39;transformed += mix(startPosition, endPosition, p);&#39;<br>  ]<br>});</pre><pre>cubes = new THREE.Mesh(geometry, material);<br>scene.add(mesh);</pre><p>Like in the previous update method, time is used to control the state of the animation. We still have to set its value in JavaScript however, which makes our update function look like this:</p><pre>function update() {<br>  cubes.material.uniforms.time.value += 1/60;<br>}</pre><h3>Analyzing the Result</h3><p>Now let’s bask in the glory of the new version of our animation. Check out the full source code for some more details of how everything fits together.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fembed%2Fpreview%2FmwqQaJ%3Fheight%3D600%26slug-hash%3DmwqQaJ%26default-tabs%3Djs%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fpen%2FmwqQaJ%2F&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F175711.mwqQaJ.small.fdb11c43-5b5c-4cca-99dd-86413c77a95e.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/d74f073cd57d66c00c201bc8707c0903/href">https://medium.com/media/d74f073cd57d66c00c201bc8707c0903/href</a></iframe><p>Depending on your hardware, you should be able to go up as high as a million cubes, but in any case you should be able to see between 100 and 1000 times more cubes move at 60 fps.</p><p>Wow.</p><p>This approach is so much faster because we went down from <strong>16 ×</strong> <strong>number of cubes</strong> worth of numbers to be updated and sent to the GPU each frame down to <strong>1</strong>. One number, regardless of how many cubes are on screen.</p><p>The update logic itself is now executed once for each vertex, in stead of once per mesh. That doesn’t feel great, but the impact of the duplicate computations is negligible. The GPU is just that good at math.</p><p>The boost in performance does come at a cost however.</p><p>As you may have noticed, there is a significant delay when you create a large number of cubes. This should be no surprise, as we create and store significantly more data when the cubes are created. We are basically opting to pay our CPU cycle dues up front, in stead of frame by frame installments.</p><p>This approach is also less flexible. Since we are operating close to the hardware, there are some memory considerations we need to work around.</p><p>When the vertex shader is executed, it only has access to the attributes of that particular vertex. This makes it impossible to implement animation systems where positions depend on each other, like flocking.</p><p>Shaders are stateless. They cannot store values between executions. They also cannot modify the values of attributes passed to them. This means that “dynamic” logic where values change incrementally based on various inputs are difficult to implement. This will become much easier in WebGL 2. While it’s still far away, I’m very much looking forward to playing around with <a href="https://open.gl/feedback">transform feedback</a>.</p><p>There is an alternate animation approach that works around these limitations using <a href="https://threejs.org/examples/#webgl_gpgpu_birds">textures in the vertex shader</a>. This is a powerful technique, but it has its own drawbacks. It’s a different beast all together.</p><p>This concludes the overview of the structure and reasoning behind Three.bas. The animation we created as proof may not have been particularly spectacular, but in the <a href="https://medium.com/@Zadvorsky/into-vertex-shaders-part-4-form-follows-function-1c86d0726ee8">next post</a> we will kick it up a notch by throwing rotation, scale, and more interesting interpolations into the mix.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9a1204221a0a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Into Vertex Shaders Addendum 1: Matrix Math and You]]></title>
            <link>https://medium.com/@Zadvorsky/into-vertex-shaders-addendum-1-matrix-math-and-you-565a51094472?source=rss-fb339efe5ccc------2</link>
            <guid isPermaLink="false">https://medium.com/p/565a51094472</guid>
            <category><![CDATA[tutorial]]></category>
            <category><![CDATA[webgl]]></category>
            <category><![CDATA[threejs]]></category>
            <category><![CDATA[math]]></category>
            <dc:creator><![CDATA[Szenia Zadvornykh]]></dc:creator>
            <pubDate>Sun, 18 Jun 2017 22:33:30 GMT</pubDate>
            <atom:updated>2017-06-18T22:49:32.319Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fDzk1IiNl67hW3gBjMWW6Q.jpeg" /></figure><p>Matrices are a crucial part of both 2D and 3D graphics development. If you are unfamiliar with this topic, it can seem quite daunting. But you can go a long way with just a high level understanding of the related concepts and a good math library, which <a href="https://threejs.org/">Three.js</a> provides.</p><p>There are many tutorials and videos explaining <em>how</em> matrices work, but this post will instead focus on how you can use matrices and vectors in Three.js without understanding any of the internals.</p><p>The most common matrix you will be working with is a 4 by 4 matrix called a <strong>transformation matrix</strong>. Similar to the CSS transform property, the types of transformation that can be represented by this matrix include <strong>translation </strong>(change in position), <strong>rotation </strong>and <strong>scale</strong>.</p><p>Think of the transformation matrix as a magic black box. If you put a 3D point (called a <strong>vector</strong>) into this box and “shake” it, a <strong>transformed vector</strong> will come out. Let’s look at an example.</p><p>Say we have a vector with the value{x: 20, y: 20, z: 0} and a matrix representing a <strong>translation</strong> of {x: 10, y: 40, z: 0}. Putting the vector into the matrix will result in a <strong>transformed vector </strong>with the value of {x: 30, y: 60, z: 0}.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*3J7L_plI6-S7NqFU63lJ0Q.png" /><figcaption>Translation (t).</figcaption></figure><p>If we have more vectors we can apply the same transformation by putting them into the same matrix.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*ML8Zll8d3ixBl8P6tGWcqQ.png" /><figcaption>Multiple Translations (t).</figcaption></figure><p>Applying the same transformation to different vectors is a common scenario in graphics development. Vectors often represent shapes: 3D geometries and 2D polygons. Applying a matrix transformation to such a shape will transform it without changing the relative positions of the points. This is called <strong>affine transformation</strong>.</p><h4>Representation in Code</h4><p>The equivalent of putting a vector into a matrix is multiplying the vector by said matrix.</p><pre>transformedVector = vector * transformationMatrix;</pre><p>In JavaScript, we cannot use operators (+, -, *,/) on custom classes like matrices and vectors. Instead Three.js provides a robust API for working with these classes. The Three.js equivalent of the multiplication above is as follows:</p><pre>var vector = new THREE.Vector3(20, 20, 0);<br>var matrix = new THREE.Matrix4();</pre><pre>matrix.makeTranslation(10, 40, 0);</pre><pre>vector.applyMatrix4(matrix);</pre><blockquote>Note than the original vector is now the transformed vector because applyMatrix4 modifies the vector directly.</blockquote><p>By default, a matrix does not represent any transformation. Applying the default matrix, called an <strong>identity matrix</strong>, will return the same vector you put in. The matrix.makeTranslation(x, y, z)method is part of the Three.js API. It will make the matrix represent a translation based on the supplied arguments. If you ever need to reset a matrix, you can do so by calling matrix.identity().</p><p>The API also provides similar methods for <strong>rotation </strong>and <strong>scale</strong>. Scale is fairly straightforward, with a method called matrix.makeScale(x, y, z). Rotation is a little more involved, simply because rotation in 3D can get a little complicated. Three.js provides the following methods for rotation:</p><pre>matrix.makeRotationX(angle);<br>matrix.makeRotationY(angle);<br>matrix.makeRotationZ(angle);<br>matrix.makeRotationAxis(axis, angle);<br>matrix.makeRotationFromEuler(euler);<br>matrix.makeRotationFromQuaternion(quaternion);</pre><blockquote>Note that all angles in Three.js are measured in <strong>radians</strong>, which represent rotation in PI, with 360 degrees being equal to 2 PI.</blockquote><p>The method matrix.makeRotationAxis takes a THREE.Vector3 representing the axis of rotation, and an angle around that axis. It is a condensed version of the three methods above, and provides a way to represent a rotation around an irregular axis. The two lines below are equivalent:</p><pre>matrix.makeRotationX(Math.PI);<br>matrix.makeRotationAxis(new THREE.Vector3(1, 0, 0), Math.PI);</pre><p>A <a href="https://threejs.org/docs/#api/math/Euler">THREE.Euler</a> represents rotation around the x, y, and z axes. This is the most common way of representing rotation. A <a href="https://threejs.org/docs/#api/math/Quaternion">THREE.Quaternion</a> is an alternate way of representing rotation, based on an axis and an angle.</p><p>Depending on what you need to do, and the data you have available, you may end up working with any of these methods. Three.js also provides methods to easily convert between the different representations of rotation.</p><p>Finally, the Three.js api provides a method to create a matrix representing a combination of translation, rotation, and scale: matrix.compose.</p><pre>var translation = new THREE.Vector3();<br>var rotation = new THREE.Quaternion();<br>var scale = new THREE.Vector3();</pre><pre>var matrix = new THREE.Matrix4();</pre><pre>matrix.compose(translation, rotation, scale);</pre><h4><strong>Stacking boxes</strong></h4><p>One of the great things about boxes is that they can be stacked. Similarly, matrices can be “stacked” to create a representation of a combined transformation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*l0qfCgnxyHtavofuY4O0zA.png" /><figcaption>Rotation (r), Scale (s) and Translation (t).</figcaption></figure><p>Moreover, this stack can be “squished” into a single matrix. This allows us to represent more complex transformations while using the same amount of numbers. Neat!</p><p>The equivalent of stacking matrices and squishing the stack into a single matrix is multiplication.</p><pre>combinedMatrix = rotationMatrix * scaleMatrix * translationMatrix;</pre><p>The Three.js API provides 2 methods for multiplying matrices: matrix.multiply(otherMatrix)and matrix.multiplyMatrices(matrixA, matrixB). The first method multiplies the matrix by another matrix. The second method sets the matrix to the result of matrixA * matrixB.</p><pre>var rotationMatrix = new THREE.Matrix4().makeRotation(...);<br>var scaleMatrix = new THREE.Matrix4().makeScale(...);<br>var translationMatrix = new THREE.Matrix4().makeTranslation(...);</pre><pre>var combinedMatrix = new THREE.Matrix4();</pre><pre>combinedMatrix.multiply(rotationMatrix);<br>combinedMatrix.multiply(scaleMatrix);<br>combinedMatrix.multiply(translationMatrix);</pre><blockquote>Multiplying 3 matrices that represent a rotation, scale and translation will result in the same matrix as calling matrix.compose with equal transform values.</blockquote><h4>Pre-multiplication and Post-multiplication</h4><p>When working with numbers, multiplying a list will yield the same result no matter the order of multiplication.</p><pre>1 * 2 * 3 * 4 = 24<br>4 * 3 * 2 * 1 = 24</pre><p>This does not apply to matrices. As such, you always have to pay close attention to the order of multiplication. Consider the example below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*tMvMobvZhOCLiiuHRWpaHw.png" /><figcaption>Translation (t) after Rotation (r).</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*vKp4RU2-CD5ynAZao51cww.png" /><figcaption>Translation (t) before Rotation (r).</figcaption></figure><p>Think of it this way: even though the combined transformation is “squished” into a single matrix, the transformations are still applied in the order they were originally stacked. Cool!</p><p>Multiplying your matrix by another matrix is known as post-multiplication. Multiplying another matrix by your matrix is know as pre-multiplication. Note that matrix.multiply(otherMatrix) always post-multiplies, while matrix.multiplyMatrices(matrixA, matrixB) can do both.</p><p>A common use case for multiplying matrices is traversing up and down a <strong>scene graph</strong>. A scene graph is a data structure consisting of <strong>nodes with children</strong>, where each child is also a node that can have children of its own. Many graphics libraries, including Three.js, use a scene graph. The HTML DOM shares many traits of a scene graph as well.</p><p>When you transform a node in a scene graph, all of its children get the same transformation applied to them. Any of these children can have a transformation of their own, which is usually <strong>relative to their parent node</strong>. If you ever need to determine the transformation of a <strong>nested node relative to the root</strong>, this can be calculated easily by <strong>recursively pre-multiplying parent transformations </strong>until you reach the root node.</p><pre>// start with the transformation for this node<br>var matrixWorld = new THREE.Matrix4().copy(node.matrix);</pre><pre>// get the first parent<br>var parent = node.parent;</pre><pre>do {<br>  // pre-multiply<br>  matrixWorld.multiplyMatrices(parent.matrix, matrixWorld);<br>  // get next parent<br>  parent = parent.parent;<br>}<br>while (parent);</pre><p>In Three.js, the transformation of a child relative to the scene is stored in a property called matrixWorld.</p><h4>The inverse of a matrix</h4><p>When working with numbers, you can ‘undo’ a transformation. Consider the following:</p><pre>4 * 5 = 20;<br>20 / 5 = 4;</pre><p>This does not apply to matrices. You cannot divide a vector by a matrix, but you can do something similar by multiplying a vector by <strong>the inverse of the same matrix</strong>.</p><pre>transformedVector = originalVector * matrix;</pre><pre>inverseMatrix = matrix.inverse();</pre><pre>untransformedVector = transformedVector * inverseMatrix;</pre><pre>// untransformedVector == originalVector</pre><p>The inverse of a transformation matrix represents the <strong>opposite transformation</strong>.</p><p>Three.js provides a method to calculate the inverse of a matrix:</p><pre>var matrix = new THREE.Matrix4();</pre><pre>// apply transformation ...</pre><pre>var inverseMatrix = new THREE.Matrix4();</pre><pre>matrix.getInverse(inverseMatrix);</pre><p>Among other things, the inverse of a matrix is used when working with a camera object in a 3D scene.</p><p>As you can see, matrices are a powerful and versatile tool. They can represent a wide range of simple or complex transformations. Vectors can then be transformed using the same procedure, regardless of what kind of transformation the matrix represents.</p><p>There is much more to matrices than covered here, but I hope this post has given you some insight into their power, and how it can be tapped to deal with common scenarios in graphics development.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=565a51094472" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Into Vertex Shaders Addendum 2: A Brief Look at GLSL]]></title>
            <link>https://medium.com/@Zadvorsky/into-vertex-shaders-addendum-2-a-brief-look-at-glsl-6e928be4ceb1?source=rss-fb339efe5ccc------2</link>
            <guid isPermaLink="false">https://medium.com/p/6e928be4ceb1</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[threejs]]></category>
            <category><![CDATA[tutorial]]></category>
            <category><![CDATA[webgl]]></category>
            <dc:creator><![CDATA[Szenia Zadvornykh]]></dc:creator>
            <pubDate>Sun, 18 Jun 2017 22:32:55 GMT</pubDate>
            <atom:updated>2017-06-18T22:50:00.329Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fDzk1IiNl67hW3gBjMWW6Q.jpeg" /></figure><p>This post will cover some of the basics of writing shaders in GLSL. For a better look at <em>how </em>shaders work, check out my <a href="https://medium.com/@Zadvorsky/into-vertex-shaders-part-2-emulating-the-3d-graphics-pipeline-41e06a8b49a4">other post</a> in this series.</p><p>Shaders in WebGL are written in a language called Open<strong>GL</strong> <strong>S</strong>hading <strong>L</strong>anguage, GLSL for short. As the name suggests, it is part of the OpenGL graphics standard, which WebGL is derived from.</p><blockquote>If you are looking for WebGL resources, and your search yields no satisfactory results, consider expanding it to include OpenGL. OpenGL has a bigger scope and feature set, but there is still a lot of overlap.</blockquote><h3>GLSL Syntax</h3><p>When writing GLSL the first thing you need to remember is to <strong>always</strong> end a line with a semicolon. If you forget one, your shader will likely crash, but rarely in a way that clearly points to a missing semicolon. As shaders can get highly complex, debugging a error (for hours) only to find out that it was caused by a missing semicolon can be very frustrating (or so I’ve heard…).</p><p>The other major difference from JavaScript is the fact that GLSL is strongly typed. GLSL provides a number of built in “classes” for mathematical objects like vectors and matrices. Trying to operate on classes that have no valid interactions, like a 2D vector and a 3D vector, will throw an error.</p><p>Critically, this also applies to numbers. There are two types of numbers in GLSL: <strong>integers</strong> and <strong>floats</strong>. Integers are round numbers (1, 2, 3, 4, etc). Floats are numbers with a fractal component (1.125, 2.0, 3.142, etc). You <strong>cannot use integers and floats in the same operation</strong>. This would be heresy!</p><pre>2.0 + 2.0; // ok!<br>2 + 2; // ok!<br>2.0 + 2; // NOT OK!</pre><p>Next we will take a look at a basic vertex shader, and dissect it word by word.</p><pre>attribute vec3 position;</pre><pre>uniform mat4 modelViewMatrix;<br>uniform mat4 projectionMatrix;</pre><pre>void main() {<br>  mat4 mvpMatrix = modelViewMatrix * projectionMatrix;</pre><pre>  gl_Position = mvpMatrix * vec4(position, 1.0);<br>}</pre><p>Shaders have two main parts. The first part (above the main function) is where we declare our inputs (parameters). The second part (inside the main function) is the entry point of the shader. This is where the math happens. Trying to use parameters you have not declared will throw an error. The order of the parameters is important as well, as you cannot reference a parameter before it has been declared.</p><p>The void keyword implies that the main method does not have a return value. Instead we use gl_Position to represent the output of the vertex shader. You must declare a gl_Position inside the main function, which makes sense since this is kinda our purpose here. Failure to do so will throw an error. The equivalent of gl_Position in fragment shaders is gl_FragColor Note that the shader execution does not halt after these keywords are used.</p><h4>Parameter qualifiers</h4><p>Declaring a parameter has the following syntax:</p><pre>{qualifier} {type} {name}</pre><pre>attribute vec3 position;<br>uniform mat4 modelViewMatrix;</pre><p>The qualifier specifies the source of the parameter. This basically tells the GPU where to look for the data associated with the parameter. It’s important to correctly declare the qualifier, as having incorrect qualifiers will cause the GPU to look in the wrong place, which would be rude.</p><p>In vertex shaders, the following qualifiers are available:</p><ul><li>attribute: This is an attribute of the vertex for which the shader is executed. The data will be different for each execution.</li><li>uniform: This is a uniform value, and will contain the same data for each execution of the shader.</li><li>varying: This is a secondary output of the vertex shader that will be passed to the fragment shader. The fragment shader can then access an interpolated value for each fragment in the face.</li><li>const: This is a “static” value. It’s part of the shader, and cannot be set from outside. This is typically used for values that will never change, like the value of PI. Note that an error will be thrown if you declare a const without assigning it a value.</li></ul><p>Fragment shaders have access to all of these, except for attribute. Since the fragment shader cannot access vertex attributes, the varying qualifier is used to pass attribute data along. Note that if you are using uniforms, you must declare them in both the vertex shader and the fragment shader. This also applies to uniforms and constants, since shader steps have their own isolated execution scopes.</p><p>For variables inside the main function the qualifier should be omitted. These then behave similarly to variables in JavaScript.</p><h4>Types</h4><p>Whenever you declare a variable, you must also specify its type. As mentioned before, GLSL has a number of “classes” to math with.</p><ul><li>Numbers: int, float.</li><li>Vectors: vec2, vec3, vec4.</li><li>Matrices: mat2, mat3, mat4.</li></ul><p>It’s important to make sure the data you supply to the shader matches the type you specified. Failure to do so will, you guessed it, throw an error.</p><p>All of these types behave the same as numbers do in JavaScript. The main advantage of this is that we can use mathematical operators on them, like below:</p><pre>mat4 mvpMatrix = modelViewMatrix * projectionMatrix;</pre><blockquote>Note that WebGL does not support the modulus operator (%).</blockquote><p>This makes it much easier to express mathematical operations, which is pretty cool. This power does have limits however: you can only use operators on appropriate types.</p><pre>gl_Position = mvpMatrix * vec4(position, 1.0);</pre><p>In this line we convert our position attribute (which is a vec3) to a vec4 in order to multiply it by the mvpMatrix (which is a mat4). We have to do this because you cannot multiply a mat4 and a vec3. Trying to do so will throw an error. As a rule, the <em>size</em> of vectors and matrices being operated on must always be the same.</p><h4>Vector Constructors</h4><p>vec4(position, 1.0) is a constructor for a vec4. GLSL constructors like this offer quite a lot of flexibility. In this example, the x, y, and z components of the position vector are <em>destructured</em>, and passed to the new vector. Then the fourth component (w) is set to 1.0. Note that this is a <strong>float</strong>, not an integer. Writing vec4(position, 1) would throw an error, since you cannot put an integer into a float vector. They just don’t get along.</p><p>Below are some other ways a vector can be constructed.</p><pre>vec4 p = vec4(1.0, 2.0, 3.0, 4.0);<br>vec4 p = vec4(myVec2, 3.0, 4.0);<br>vec4 p = vec4(myVec2, myVec2);<br>vec4 p = vec4(1.0, myVec3);</pre><p>The same logic applies to other the vector types. Trying to create a vector with an incorrect number of values will throw an error.</p><h4>Vector Components</h4><p>Once constructed, the vector components can be accessed the same way as in JavaScript: p.x, p.y, p.z and p.w. Since vectors are also used to represent colors, the corresponding components can likewise be accessed using p.r, p.g, p.b and p.a.</p><p>You can also access multiple components at once, which implicitly creates a vector of the appropriate size.</p><pre>vec4 p = vec4(myVec4.xyz, 1.0);</pre><p>Components can be accessed in any given order, which is referred to as <em>swizzling. </em>So flexible!</p><pre>vec4 p = vec4(myVec4.zxy, 1.0);</pre><h4>GLSL Arrays</h4><p>If you want to get fancy, you can also declare arrays. These arrays are also typed, which means they can only contain members of the same type. The line below creates an array of 6 floats.</p><pre>float myArray[](1.0, 2.0, 3.0, 4.0, 5.0, 6.0);</pre><p>Declaring an array you intend to populate from outside the shader looks like this:</p><pre>uniform float myArray[6];</pre><p>Members of arrays can be accessed the same way as in JavaScript.</p><pre>float a = myArray[0]; // a === 1.0</pre><h3>Functions</h3><p>GLSL also supports functions!</p><pre>float decimate(float x) {<br>  return x * 0.9;<br>}</pre><pre>void main() {<br>  float x = 1.0;<br>  <br>  x = decimate(x);<br>  <br>  // x is now 0.9!<br>}</pre><p>As you can see, the syntax is fairly similar to JavaScript. The main difference is that functions, like variables, must declare a type. The value you return must then be of the same type as specified. If your function does not return a value, the return type must be specified as void. Any functions you declare should be placed above the main function (otherwise you cannot use them inside the main function).</p><p>GLSL functions are scoped similarly to JavaScript. If you declare a variable inside the function, you can only access it inside that function. Note however that functions in GLSL cannot be nested.</p><h4>Argument Qualifiers</h4><p>If you want to get <em>really </em>fancy, you can use special qualifiers that change how arguments for a function behave.</p><pre>void decimate(<strong>inout</strong> float x) {<br>  x *= 0.9;<br>}</pre><p>Whoa! What’s happening here?</p><p>By default, any arguments you pass to a function are passed <strong>by value</strong>. This essentially means that the value is copied into the argument, and the variable you passed to the function cannot be modified by it.</p><p>Using the inout qualifier, the argument is instead passed <strong>by reference</strong>, which means that the original variable can be changed directly.</p><pre>void main() {<br>  float x = 1.0;<br>  <br>  decimate(x);<br>  <br>  // x is now 0.9!<br>}</pre><p>One use case for this is creating functions that “return” multiple values.</p><pre>void decimateTwo(inout float x, inout float y) {<br>  x *= 0.9;<br>  y *= 0.9;<br>}</pre><p>Another qualifier you can use is out.</p><pre>void decimate(in float x, out float y) {<br>  y = x * 0.9;<br>}</pre><pre>void main() {<br>  float x = 1.0;<br>  float y = 100.0;  </pre><pre>  decimate(x, y);<br>  <br>  // x is still 1.0!<br>  // y is now 0.9!<br>}</pre><p>When using out, the initial value of the argument is ignored, but it can be set by the function. The in qualifier used for the first argument is the default, so it is usually omitted.</p><h4>Optional Arguments?</h4><p>Before we answer that, I should note that names of variables must be unique. Using the same name more than once in the same scope will throw an error.</p><p>Functions have a slight exception to this rule: their arguments are part of the <strong>function signature</strong>, which means that you can declare multiple functions with the same name, as long as they have different arguments. Functions do not support optional arguments, but the same effect can be achieved using different signatures (albeit with some additional overhead).</p><pre>float easeQuadIn(float t) {<br>  return t * t;<br>} </pre><pre>float easeQuadIn(float t, float b, float c, float d) <br>{  <br>  return b + easeQuadIn(t / d) * c;<br>}</pre><p>In this example, I use two different signatures for an easing function. The first takes an argument t between 0.0 and 1.0, and returns an eased value. The second uses the <a href="http://upshots.org/actionscript/jsas-understanding-easing">four classic Penner easing arguments</a>, and calls the first function internally. Because these functions have different arguments, their signatures are different, and they can coexist within the same scope.</p><p>The order in which these functions are declared is important. The second easing function uses the first, which would not be possible if they were declared the other way around.</p><p>Other than the number of arguments, the type of the arguments is also part of the signature, meaning you can declare multiple functions with the same name that operate on different types.</p><pre>vec3 decimate(vec3 x){<br>  return x * 0.9;<br>}</pre><h4>Built-in functions</h4><p>Aside from custom functions, GLSL also provides a number of functions that cover common mathematical operations. The types mentioned so far do not have any methods themselves. Instead you use the built in functions to operate on variables.</p><p>One of these functions is mix, which linearly interpolates between two values based on a float value between 0.0 and 1.0.</p><pre>vec3 mixed = mix(v0, v1, 0.5);</pre><p>Many of these built-in functions operate on several types. Check <a href="http://www.shaderific.com/glsl-functions/">here</a> for a full list of functions available in OpenGL. Note however that some of these may not work in WebGL. For a list of functions (and other things) that are definitely available, check the last two pages of <a href="https://www.khronos.org/files/webgl/webgl-reference-card-1_0.pdf">this handy reference card</a>.</p><h3>Loops &amp; Conditions</h3><p>GLSL supports loops and conditional statements. The syntax for these is similar to JavaScript (but since GLSL is strongly typed, there is no need for the strict equality operator (===)). Using loops and conditionals is however generally discouraged, as it can create complications for how the shader is executed depending on your hardware.</p><h3>Defines</h3><p>Finally you may encounter <em>defines</em>. These are usually declared at the very start of a shader. They are used for values that are set once when the shader compiles, and do not change afterward. One of the defines Three.js uses is NUM_DIR_LIGHTS, which is set to the number of directional lights added to the scene. This is then used to correctly set the size of an array where these lights are stored.</p><pre>#define NUM_DIR_LIGHTS 6;</pre><pre>uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];</pre><p>In Three.js defines like this are dynamically determined and injected into the shader. If you want to add your own (using a <a href="https://threejs.org/docs/index.html#api/materials/ShaderMaterial">THREE.ShaderMaterial</a>), you can use the defines array in the constructor.</p><h3>Shaders in Three.js</h3><p>In WebGL, shaders are sent to the GPU as strings before being compiled. While this can be a little cumbersome to work with, it does offer a lot of flexibility. There are a number of ways you can deal with shaders, as long as they can be converted to strings in the end.</p><p>One way is to use HTML script tags, and send their textContent to be compiled. You can see an (old) example of this approach <a href="https://codepen.io/zadvorsky/pen/VaXqRW">here</a>.</p><p>Another is to use an array of strings, and concatenate them into a single string delimited by new-line characters. This is the basis for how shaders are used in Three.js. Three.js has multiple materials, all of which have their own corresponding shaders. However, some functionality is shared between different materials. To facilitate this, Three.js shaders are broken down into chunks, and combined in different ways for the final material shaders. My Three.js extension builds on this principle by <a href="https://github.com/zadvorsky/three.bas/blob/master/src/materials/BasicAnimationMaterial.js">injecting my own chunks into the mix</a>.</p><p>If you can use ES6 for your project, you can use a multi-line template string instead of relying on arrays. This is a cleaner approach, and is much easier to maintain and edit.</p><p>Depending on your development environment, there are also <a href="https://github.com/stackgl/glslify">ways to load standalone *.glsl files</a>, and bundle their content with your JavaScript.</p><p>This concludes my brief overview of some of the features and constraints of GLSL. There are more things to know than covered here, but this overview should help you deal with some of the quirks of GLSL you may encounter when exploring the endless possibilities of shaders.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6e928be4ceb1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Into Vertex Shaders part 2: Emulating the 3D Graphics Pipeline]]></title>
            <link>https://medium.com/@Zadvorsky/into-vertex-shaders-part-2-emulating-the-3d-graphics-pipeline-41e06a8b49a4?source=rss-fb339efe5ccc------2</link>
            <guid isPermaLink="false">https://medium.com/p/41e06a8b49a4</guid>
            <category><![CDATA[webgl]]></category>
            <category><![CDATA[tutorial]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[threejs]]></category>
            <dc:creator><![CDATA[Szenia Zadvornykh]]></dc:creator>
            <pubDate>Sun, 18 Jun 2017 22:32:23 GMT</pubDate>
            <atom:updated>2017-06-28T17:00:16.836Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fDzk1IiNl67hW3gBjMWW6Q.jpeg" /></figure><p>This is the second in a <a href="https://medium.com/@Zadvorsky/into-vertex-shaders-594e6d8cd804">series of articles</a> about advanced WebGL animation using <a href="https://threejs.org/">Three.js</a> and <a href="https://github.com/zadvorsky/three.bas">Three.bas</a>, my extension for complex and highly performant animation systems.</p><p>In this post we will emulate part of the 3D graphics pipeline using plain old JavaScript and some of the utility of Three.js. There will be many omissions and simplifications, but this exercise should help you understand how some of the key elements fit together, without having to deal with everything at once.</p><p>If you want to skip ahead, the code we will be working toward can be found <a href="https://codepen.io/zadvorsky/pen/YVjLpw/">here</a>. The whole thing is about 200 lines (excluding comments), so it should be pretty easy to step through even if you don’t read the rest of this post.</p><p>Our goal will be to draw a rectangle (or a Plane in 3D terms). We will defer the actual drawing to the canvas 2D API, but the steps to do so will be based on the WebGL graphics pipeline.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fembed%2Fpreview%2FYVjLpw%3Fheight%3D600%26slug-hash%3DYVjLpw%26default-tabs%3Djs%2Cresult%26host%3Dhttps%3A%2F%2Fcodepen.io%26embed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fpen%2FYVjLpw%2F&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F175711.YVjLpw.small.8676f2b5-cb78-4cf0-96a5-fdc9aee56df7.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/6400afed0387b2ce4dcaea83938a8211/href">https://medium.com/media/6400afed0387b2ce4dcaea83938a8211/href</a></iframe><p>Like in Three.js, we will start by creating a scene, a camera, and a renderer. The scene will contain everything we want to render. The camera will determine our view of the scene. We will use <a href="https://threejs.org/docs/#api/cameras/PerspectiveCamera">THREE.PerspectiveCamera</a> because it encapsulates all of the properties we need. The renderer will contain the bulk of the logic to make things appear on screen.</p><pre>var scene = {<br>  children: []<br>};<br>var camera = new THREE.PerspectiveCamera();<br>var renderer = new Renderer();</pre><p>Before we dive into the Renderer, let’s look at the model for our Plane, which will be represented by a <strong>Mesh</strong> with a <strong>Geometry</strong> and a <strong>Material</strong>.</p><h3>Defining Geometry</h3><p>3D models are represented by a list of “points” in 3D space called <strong>vertices</strong>. It is very important to realize that <strong>position is a property of a vertex</strong>, and not the vertex itself. Think of a vertex as a plain JavaScript object with a property called position.</p><p>Properties of vertices are called attributes. Alongside position, a typical vertex will have an attribute called a normal (a 3D point perpendicular to the surface of the model), used for lighting calculations, and a UV coordinate, used for texture mapping. Like JavaScript objects, vertices can have any number of attributes. This is limited only by the quality of your GPU, though you are much more likely to run into other issues before the number of attributes becomes a problem.</p><pre>var vertex = {<br>  position: {x: 0, y: 0, z: 0},<br>  normal: {x: 0, y: 0, z: 1},<br>  uv: {u: 0, v: 0}<br>  // etc...<br>};</pre><p>To keep things simple, our vertices will only have a position attribute. Our plane will have 4 vertices, centered around its own origin at {x: 0, y: 0, z: 0}. Let’s make it 200 units wide and 100 units high. This gives us the following:</p><pre>var mesh = {<br>  geometry: {<br>    vertices: [<br>      // top left corner<br>      { position: {x: -100, y:  50, z: 0} },<br>      // top right corner      <br>      { position: {x:  100, y:  50, z: 0} },<br>      // bottom right corner<br>      { position: {x:  100, y: -50, z: 0} },<br>      // bottom left corner<br>      { position: {x: -100, y: -50, z: 0} }    <br>    ]<br>  }<br>};</pre><p>Meshes are rendered in triangles called <strong>faces</strong>. Our plane will have two faces, and we will need to tell our renderer how to construct those faces from the vertices. This might seem somewhat arbitrary for a simple plane, but remember that all of this also applies to more complex geometries.</p><p>We will describe the faces using an array called <strong>indicies</strong>. Each number in this array represents the <strong>index of a vertex in the vertices array</strong>. Since we have 2 faces, the indices array will have 6 numbers (3 per face).</p><pre>var mesh = {<br>  geometry: {<br>    vertices: [...],<br>    <strong>indices: [<br>      // first face<br>      0, 1, 3,<br>      // second face<br>      1, 2, 3<br>    ],</strong><br>  }<br>};</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mWTEVzMj2vNE7VvSb_7tVg.png" /><figcaption>Visual representation of our Plane.</figcaption></figure><blockquote>Note that our faces are indexed clock-wise. While we will not take this into account for now, the <strong>winding</strong> of faces is very important in WebGL. Consistent winding enables WebGL to quickly determine whether a face is facing the camera or not. Faces that do not face the camera (the sides of an object you don’t see) are generally not rendered, boosting performance.</blockquote><h3><strong>Defining Material</strong></h3><p>Geometry determines the shape of a mesh. The material determines its appearance. There are a number of different materials built in Three.js, all with their own set of properties. These properties are applied to all vertices. In our emulation, the material will only have one property: color.</p><p>In addition, the material will reference the shaders we will be using. In WebGL shaders are written in a language called GLSL, and sent to the GPU as strings. Our JavaScript emulation will use functions to approximate this process.</p><pre>var mesh = {<br>  geometry: {...},<br>  <strong>material: {<br>    color: &#39;#ff0000&#39;,<br>    vertexShader: basicVertexShader,<br>    fragmentShader: basicFragmentShader<br>  }</strong><br>};</pre><h3>Defining Transformation</h3><p>For the most part, geometries in WebGL should be considered static; once a model is loaded or generated, changing geometry data every frame will be very slow (and we want things to go fast). To facilitate animation, we will add 3 properties to our mesh that represent its transformation relative to the scene.</p><pre>var mesh = {<br>  geometry: {...},<br>  material: {...},<br><strong>  position: new THREE.Vector3(0, 0, 0),<br>  rotation: new THREE.Euler(0, 0, 0),<br>  scale: new THREE.Vector3(1, 1, 1)</strong><br>};</pre><p>We use Vector3 for position and scale, and an Euler for rotation. The Euler defines rotation around the 3 axes using radians (this is the same way you define rotation in CSS). These Three.js classes will make it easier to work with the math API later on.</p><h3>The Renderer</h3><p>As mentioned earlier, the renderer is responsible for drawing our mesh on screen. Since the mesh is defined in 3D coordinates, and the screen is flat, an important part of this responsibility is converting 3D coordinates to 2D. This process is called <strong>projection</strong>.</p><p>In order to correctly project a vertex on screen, we will need to take a number of things into account:</p><ol><li>The position of the vertex relative to the model.</li><li>The transformation (rotation, scale, translation) of the model relative to the scene.</li><li>The transformation of the camera relative to the scene.</li><li>Projection properties of the camera, like field of view and aspect ratio.</li></ol><p>This might seem like a lot, but luckily this process can be greatly streamlined using matrix math.</p><blockquote>The section ahead deals with matrices and vectors (linear algebra). If you are not familiar with this topic, check out <a href="https://medium.com/@Zadvorsky/into-vertex-shaders-addendum-1-matrix-math-and-you-565a51094472">this article</a> that covers the basics of matrices and vectors in Three.js.</blockquote><p>Our render has one main method: render.</p><pre>renderer.render(scene, camera);</pre><p>This will render the scene as viewed through the camera. Let’s look at this method line by line.</p><h4>Step 1: Clear the screen</h4><pre>this.ctx.fillStyle = this.clearColor;<br>this.ctx.fillRect(-1, -1, 2, 2);</pre><p>This will clear the previous frame by filling the screen with a solid clear color. Since we are working in Normalized Device Coordinates (see <a href="https://medium.com/@Zadvorsky/into-vertex-shaders-part-1-the-spaces-of-webgl-c70ded527841">previous post</a>), we can clear the entire screen using fillRect(-1, -1, 2, 2).</p><h4>Step 2: Update the camera</h4><pre>camera.updateProjectionMatrix();<br>camera.updateMatrixWorld();<br>camera.matrixWorldInverse.getInverse(camera.matrixWorld);</pre><p>The projection properties of the camera, including field of view and aspect ratio, are represented internally in camera.projectionMatrix. This matrix needs to be updated whenever any of those values change between draw calls. The same applies to camera.matrixWorld, which represents the transformation of the camera relative to the scene. Because we are looking at the scene <em>through </em>the camera, we also need the <em>inverse </em>of camera.matrixWorld.</p><h4><strong>Step 3: Render each child</strong></h4><pre>scene.children.forEach(function(child) {<br>  this.renderChild(child, camera);<br>}.bind(this));</pre><p>Once the camera matrices are updated, we can move on to rendering the children of the scene. Since the steps for each child are the same, we can move this logic into a separate method renderer.renderChild(), passing the child in question and the camera along.</p><h4>Step 3.1: Create a world matrix</h4><pre>var matrixWorld = new THREE.Matrix4();<br>var quaternion = new THREE.Quaternion()<br>  .setFromEuler(child.rotation);</pre><pre>matrixWorld.compose(child.position, quaternion, child.scale);</pre><p>Inside renderer.renderChild() we first need to create a matrix representation of child’s transformation. This is similar to what we did for the camera. Matrix4.compose will help us do just that, but first we need to turn the Euler we used for rotation into a THREE.Quaternion to conform to the API for Matrix4.compose. After calling this method, we get a matrix that represents the combined transformation for our object.</p><h4>Step 3.2: Create a model view matrix</h4><pre>var modelViewMatrix = new THREE.Matrix4().multiplyMatrices(<br>  camera.matrixWorldInverse,<br>  matrixWorld<br>);</pre><p>Next we need a matrix that represents the transformation of the child relative to the position and rotation of the camera. In other words, this is <strong>how the camera sees the child</strong>. We call this a modelViewMatrix, composed by multiplying the inverse of camera.matrixWorld by the matrixWorld we just composed for the child.</p><pre>var uniforms = {<br>  modelViewMatrix: modelViewMatrix,<br>  projectionMatrix: camera.projectionMatrix,<br>  color: child.material.color<br>};</pre><p>The modelViewMatrix and projectionMatrix, alongside material.color will be used in our shaders as <strong>uniforms</strong>. Uniforms are values that are globally accessible in both the <strong>vertex shader </strong>and the <strong>fragment shader</strong>, which will come into play in the next step. We will also need the vertices and indices we set up earlier.</p><h4>Step 3.3: Render the child face by face</h4><pre>var vertices = child.geometry.vertices;<br>var indices = child.geometry.indices;<br>var indexCount = indices.length;<br>var faceCount = indexCount / 3;<br>    <br>for (var i = 0; i &lt; faceCount; i++) {</pre><pre>  // STEP 3.3.1: Retrieve vertices for this face</pre><pre>  var vertex0Index = indices[i * 3 + 0];<br>  var vertex0 = vertices[vertex0Index];<br>  <br>  var vertex1Index = indices[i * 3 + 1];<br>  var vertex1 = vertices[vertex1Index];<br>  <br>  var vertex2Index = indices[i * 3 + 2];<br>  var vertex2 = vertices[vertex2Index];</pre><pre>  // STEP 3.3.2: Project vertices using vertex shader<br>  <br>  var projectedVertex0 = this.applyVertexShader(<br>    child.material.vertexShader, <br>    uniforms, <br>    vertex0<br>  );</pre><pre>  var projectedVertex1 = this.applyVertexShader(<br>    child.material.vertexShader, <br>    uniforms, <br>    vertex1<br>  );</pre><pre>  var projectedVertex2 = this.applyVertexShader(<br>    child.material.vertexShader, <br>    uniforms, <br>    vertex2<br>  );</pre><pre>  // canvas 2D render logic<br>}</pre><p>The code above renders a mesh face by face. First, the vertices corresponding to the current face are retrieved from geometry.vertices based on the indices array. Then material.vertexShader is executed <strong>once for each vertex in the face</strong>, returning a projected point in Normalized Device Coordinates.</p><p>Once all vertices in a face are projected, the area of the screen covered by this face is determined. Now the fragment shader takes over. The fragment shader is executed <strong>once for each pixel (fragment) in the area of the screen covered by the face</strong>. I couldn’t quite figure out how to effectively emulate this process, so we will just use the canvas 2d API to fill the shape using material.color.</p><pre>this.ctx.fillStyle = this.applyFragmentShader(<br>  child.material.fragmentShader, <br>  uniforms<br>);<br>this.ctx.fill();</pre><h3>What is a shader, anyway?</h3><blockquote>In the section ahead we will be looking at shaders and GLSL. If you want an introductory look into GLSL itself, check out <a href="https://medium.com/@Zadvorsky/into-vertex-shaders-addendum-2-a-brief-look-at-glsl-6e928be4ceb1">this post</a>.</blockquote><p>WebGL shaders have two distinct but tightly coupled parts: a <strong>vertex shader</strong> and a <strong>fragment shader</strong>. These are essentially functions that can be injected into the graphics pipeline. Below is a very basic vertex shader written in GLSL.</p><pre>attribute vec4 position;<br>uniform mat4 modelViewMatrix;<br>uniform mat4 projectionMatrix;<br>  <br>void main() {<br>  mat4 modelViewProjectionMatrix = <br>    projectionMatrix * modelViewMatrix;<br>  <br>  gl_Position = position * modelViewProjectionMatrix;<br>}</pre><p>This shader first calculates a modelViewProjectionMatrix using the supplied uniforms. This matrix represents the transformation for <strong>a vertex as seen by the camera, projected on a flat surface</strong> (the screen). This is the combined transformation for all of the steps we have taken so far. The shader then multiplies the vertex position attribute by this matrix, which gives us the position of this vertex on screen. gl_Position is a reserved keyword in GLSL, representing this final output value.</p><p>Each vertex has a different position, but the transformation represented by the matrix is the same (because it it based on uniforms). When this transformation is applied, each vertex is therefore transformed in the same way, so the shape (relative position of the vertices) of the mesh does not change. This is called an <strong>affine transformation</strong>.</p><p>Now let’s look at a JavaScript emulation of this shader. Below you can see each line and its JavaScript approximation.</p><pre>function basicVertexShader() {<br>  // attribute vec4 position;<br>  var position = this.attributes.position;<br>  // uniform mat4 modelViewMatrix;<br>  var modelViewMatrix = this.uniforms.modelViewMatrix;<br>  // uniform mat4 projectionMatrix;<br>  var projectionMatrix = this.uniforms.projectionMatrix;<br>  <br>  // mat4 modelViewProjectionMatrix = <br>  //   projectionMatrix * modelViewMatrix;<br>  var modelViewProjectionMatrix = <br>    new THREE.Matrix4().multiplyMatrices(<br>      projectionMatrix,<br>      modelViewMatrix<br>  );<br>  <br>  // gl_Position = position * modelViewProjectionMatrix;<br>  return position.applyMatrix4(modelViewProjectionMatrix);<br>}</pre><blockquote>Since JavaScript does not support operators for custom objects, we need to use the Three.js math API to multiply our matrices and vectors.</blockquote><p>Now let’s examine the applyVertexShader method we used earlier to project our vertices.</p><pre>var projectedVertex0 = this.applyVertexShader(<br>  child.material.vertexShader, <br>  uniforms, <br>  vertex0<br>);</pre><pre>...</pre><pre>function applyVertexShader(shader, uniforms, vertex) {<br>  var context = {<br>    attributes: {<br>      position: vertex.position<br>    },<br>    uniforms: uniforms<br>  }</pre><pre>  return shader.apply(context);<br>}</pre><p>To emulate how real shaders work, I created a context object which stores the <strong>values </strong>for attributes and uniforms expected by the shader. The shader is then executed against this context (using this to retrieve the supplied values).</p><p>While not exactly accurate, this is a fair representation of how shaders work on a high level. In JavaScript terms, shaders are <strong>stateless functions </strong>with a particular syntax for inputs and outputs. Inputs are represented by uniforms (which are the same for each execution of the shader within a single draw call) and attributes (which vary for each vertex). The output for the vertex shader is represented by gl_Position, which is essentially the return value of the shader.</p><p>This process is similar for the fragment shader, which is used in the next step of the pipeline. The fragment shader does not have access to vertex attributes, but it does have access to the uniforms. This is however where my emulation tapers off. You can see the complete code <a href="https://codepen.io/zadvorsky/pen/YVjLpw/">here</a>, with some additional info in the comments.</p><p>If you are inclined to dig into the code and experiment some more, I created a little <a href="https://codepen.io/zadvorsky/project/editor/ZbVqma/">CodePen project</a> that can be your playground. It’s mostly the same as discussed in this post, but the scene graph is a little more fleshed out, and there are utility classes to create different plane and polygon geometries.</p><p>There is much more to the graphics pipeline, but I hope this overview has given you new insight into how some important bits fit together. In the <a href="https://medium.com/@Zadvorsky/into-vertex-shaders-part-3-memory-management-9a1204221a0a">next post</a>, we will dive deeper into vertex shaders, and examine how we can make use of the graphics pipeline to maximize performance.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=41e06a8b49a4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Into Vertex Shaders part 1: The Spaces of WebGL]]></title>
            <link>https://medium.com/@Zadvorsky/into-vertex-shaders-part-1-the-spaces-of-webgl-c70ded527841?source=rss-fb339efe5ccc------2</link>
            <guid isPermaLink="false">https://medium.com/p/c70ded527841</guid>
            <category><![CDATA[tutorial]]></category>
            <category><![CDATA[threejs]]></category>
            <category><![CDATA[webgl]]></category>
            <dc:creator><![CDATA[Szenia Zadvornykh]]></dc:creator>
            <pubDate>Sun, 18 Jun 2017 22:32:01 GMT</pubDate>
            <atom:updated>2017-06-18T22:50:27.218Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fDzk1IiNl67hW3gBjMWW6Q.jpeg" /></figure><p>This is the first in a <a href="https://medium.com/@Zadvorsky/into-vertex-shaders-594e6d8cd804">series of articles</a> about advanced WebGL animation using <a href="https://threejs.org/">Three.js</a> and <a href="https://github.com/zadvorsky/three.bas">Three.bas</a>, my extension for complex and highly performant animation systems.</p><p>When I started working with 3D graphics development, one of the initial hurdles I had to overcome was understanding how the different coordinate systems through out the 3D graphics pipeline fit together.</p><p>This brief overview will disambiguate these spaces, helping you not to get lost along the way.</p><h3>Pixel Coordinates</h3><p>The first coordinate system is the one we are all most familiar with: pixel coordinates. It starts in the top left corner of the screen at {x: 0, y: 0}, and moves right and down to {x: viewportWidth, y: viewportHeight}.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xfOyCn4F-Vz996L8uN7xzw.png" /><figcaption>Pixel coordinate space.</figcaption></figure><p>While familiar, you will rarely be working with pixels directly. In fact, conversion to actual pixels on screen is the very last step in the 3D graphics pipeline. If you want a 3D object to show up at a specific location on screen, you will need to use trigonometry to calculate the corresponding position in 3D space first. I may come back to this in a later post, but for now let’s forget that pixels exist at all.</p><h3>Normalized Device Coordinates</h3><p>The second coordinate system is called Normalized Device Coordinates, or NDC for short. It starts in the center of the screen at {x: 0, y: 0}, with the x axis moving right and the y axis moving up. The range of values on both axes is -1 to 1. NDC is the same for all screens; whether you are using a tiny phone or an oversized flat screen, the values will not change.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*w4vnWCJ1xfg0k36V7BBu5Q.png" /><figcaption>Normalized Device Coordinate space.</figcaption></figure><p>If you have had to add pointer interaction to a WebGL project, you probably used a method like this:</p><pre>window.addEventListener(&#39;mousemove&#39;, function(e) {<br>  var x = (e.clientX / window.innerWidth * 2) - 1;<br>  var y = (e.clientY / window.innerHeight * -2) + 1;<br>  <br>  // something awesome<br>});</pre><p>This converts the position of the pointer on screen from pixel coordinates to NDC. You need to do this because NDC is an integral part of the math behind 3D graphics.</p><p>Normalized Device Coordinates are also the final output space for shaders (which we will get to in the next post). Therefor, when WebGL developers refer to <em>screen space</em>, this is the coordinate space we refer to, <strong>not pixels</strong>.</p><h3>3D Coordinates</h3><p>The third coordinate system is the actual 3D coordinates, often called <em>world space </em>or <em>scene space</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*O4kk25S15jYJ4l2tMl0k4w.png" /><figcaption>3D world coordinate space.</figcaption></figure><blockquote>By convention, red is used for the x axis, green is used for the y axis, and blue is used for the z axis. The color channels correspond to the axes; RGB is XYZ.</blockquote><p>It starts in the center at {x: 0, y: 0, z: 0}. In Three.js, the x axis moves to the right (with negative values moving left), the y axis moves up (with negative values moving down), and the z axis moves towards the camera (with negative values moving away). This is called Right Handed Orientation. While common, this orientation is by no means standard. If you are importing models from 3D software, the orientation may be different. You then need to reorient the model by rotating it along one or two axes.</p><p>Other than orientation, you need to consider scale. If, for example, you create a 1 by 1 by 1 cube, what does that really mean?</p><p>The values along the axes in 3D space are essentially unitless; they can be whatever you want them to be. It is advisable to consider the scale of your world before you start building it. If you are working on human scale (cars, buildings), a 3D unit may represent a meter. If you are working with landscapes, it may represent a kilometer, and so on.</p><p>Being mindful of scale, and choosing and consistently applying the right dimensions will save you a lot of headaches down the road. If you don’t, you may find yourself having to work with values that are too big or too small to be practical. Even worse, you may have to go back and change a bunch of numbers throughout your code when things finally stop making sense.</p><h4>UV Space</h4><p>Finally I want to mention UV coordinates, used to map textures to 3D models. This coordinate system starts in the <strong>bottom left corner </strong>at {u: 0, v: 0}, and moves <strong>right</strong> and <strong>up</strong> to {u: 1.0, v: 1.0}.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LaFv6y9qf1f6weg0LMz6AQ.png" /><figcaption>UV Coordinates.</figcaption></figure><p>If you are working with models generated in 3D software, or any of the Three.js primitives, UV coordinates will be generated for you. As such, you will not have to interact with them in code all that often. They may however show up if you are working with post-processing, where textures are used to transfer data between subsequent effects.</p><p>As mentioned before, Normalized Device Coordinates represent the output space for shaders. 3D coordinates (alongside UV coordinates and a whole bunch of other data) represent the input. In the <a href="https://medium.com/@Zadvorsky/into-vertex-shaders-part-2-emulating-the-3d-graphics-pipeline-41e06a8b49a4">next post</a>, we will take a detailed look at how the conversion between the two happens.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c70ded527841" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Into Vertex Shaders]]></title>
            <link>https://medium.com/@Zadvorsky/into-vertex-shaders-594e6d8cd804?source=rss-fb339efe5ccc------2</link>
            <guid isPermaLink="false">https://medium.com/p/594e6d8cd804</guid>
            <category><![CDATA[threejs]]></category>
            <category><![CDATA[tutorial]]></category>
            <category><![CDATA[webgl]]></category>
            <dc:creator><![CDATA[Szenia Zadvornykh]]></dc:creator>
            <pubDate>Sun, 18 Jun 2017 22:31:21 GMT</pubDate>
            <atom:updated>2017-08-01T19:00:13.543Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fDzk1IiNl67hW3gBjMWW6Q.jpeg" /></figure><p>This is a series of tutorials about WebGL, <a href="https://threejs.org/">Three.js</a>, and <a href="https://github.com/zadvorsky/three.bas">Three.bas</a>, my extension for complex and highly performant 3D animation systems.</p><p>These tutorials are intended for people who know JavaScript and want to get into 3D graphics development, though some prior experience with Three.js will help.</p><p>We will start with a high-level overview of some key aspects of the 3D graphics pipeline. Then we will take a more detailed look at geometries, materials and particularly vertex shaders. Understanding how these work together on a hardware level will empower you to create beautiful animation systems without sacrificing performance.</p><h4><a href="https://medium.com/@Zadvorsky/into-vertex-shaders-part-1-the-spaces-of-webgl-c70ded527841">Part 1: The Spaces of WebGL</a></h4><h4><a href="https://medium.com/@Zadvorsky/into-vertex-shaders-part-2-emulating-the-3d-graphics-pipeline-41e06a8b49a4">Part 2: Emulating the 3D Graphics Pipeline</a></h4><h4><a href="https://medium.com/@Zadvorsky/into-vertex-shaders-part-3-memory-management-9a1204221a0a">Part 3: Memory Management</a></h4><h4><a href="https://medium.com/@Zadvorsky/into-vertex-shaders-part-4-form-follows-function-1c86d0726ee8">Part 4: Form Follows Function</a></h4><h4><a href="https://medium.com/@Zadvorsky/into-vertex-shaders-addendum-1-matrix-math-and-you-565a51094472">Addendum 1: Matrix Math and You</a></h4><h4><a href="https://medium.com/@Zadvorsky/into-vertex-shaders-addendum-2-a-brief-look-at-glsl-6e928be4ceb1">Addendum 2: A Brief Look at GLSL</a></h4><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=594e6d8cd804" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[WebGL Masking & Composition]]></title>
            <link>https://medium.com/your-majesty-co/webgl-masking-composition-75b82dd4cdfd?source=rss-fb339efe5ccc------2</link>
            <guid isPermaLink="false">https://medium.com/p/75b82dd4cdfd</guid>
            <category><![CDATA[creative-coding]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[webgl]]></category>
            <dc:creator><![CDATA[Szenia Zadvornykh]]></dc:creator>
            <pubDate>Wed, 09 Nov 2016 18:26:16 GMT</pubDate>
            <atom:updated>2016-11-09T22:16:21.841Z</atom:updated>
            <content:encoded><![CDATA[<p>This month, as part of the wonderful <a href="http://codevember.xyz/">codevember</a> initiative, I’ve been working a <a href="http://codepen.io/collection/DYGyOP/">series that combines cinemagraphs with WebGL content</a>. I love cinemagraphs, and using them to contextualize the WebGL animations I enjoy making has yielded some interesting results.</p><p>The pieces themselves have two main components; a WebGL particle animation system, powered by <a href="https://github.com/zadvorsky/three.bas">THREE.BAS</a>, my THREE.js extension for shader based animation, and a masking/compositing approach. The repo for THREE.BAS has some documentation, examples and a brief explanation of the thinking behind it. I may further elaborate on it at a future post, but today I will focus on masking and compositing.</p><h4>Alpha Masking</h4><p>An alpha mask is a grayscale image that is used to mask out content with degrees of transparency. Below, you can see the original image and the alpha mask that I used for the WebGL content.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/615/1*vEY5zOJU9dVC5wEogxi9LA.gif" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/615/1*_deMNM-CdPBw-S8hGY1znA.jpeg" /></figure><p>When the mask is applied, pixels under the white area are rendered fully opaque, and pixels under the black area are rendered fully transparent. The grays in between create an alpha gradient for smoother blending.</p><p>You can see the final composition below. I simply place a WebGL canvas over the cinemagraph, and apply the alpha mask to it.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fembed%2Fpreview%2FgLOOZR%3Fheight%3D600%26amp%3Bslug-hash%3DgLOOZR%26amp%3Bdefault-tabs%3Djs%2Cresult%26amp%3Bhost%3Dhttp%253A%252F%252Fcodepen.io%26amp%3Bembed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fpen%2FgLOOZR&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F175711.gLOOZR.small.8d5c83ab-fcc1-4d68-b695-414af2d3595f.png&amp;key=d04bfffea46d4aeda930ec88cc64b87c&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/642a146f7486831a4bae9667cfc6df7f/href">https://medium.com/media/642a146f7486831a4bae9667cfc6df7f/href</a></iframe><p>There are a number of ways we can use alpha masks on the web, both inside WebGL/THREE.js and through CSS. Because <a href="http://caniuse.com/#feat=css-masks">support</a> for CSS image masks is still iffy, I decided to add the alpha mask as a post processing step in THREE.js.</p><p>Digging into how shaders/post processing works goes well beyond the scope of this post, but <a href="https://www.airtightinteractive.com/2013/02/intro-to-pixel-shaders-in-three-js/">this tutorial</a> gives a good introduction to the concepts behind it.</p><p>This is code for the alpha mask post processing step:</p><pre>var maskPass = new THREE.ShaderPass({<br> uniforms: {<br> // the underlying image<br> “tDiffuse”: { value: null },<br> // the alpha mask<br> “tMask”: { value: null }<br> },<br> vertexShader: [<br> “varying vec2 vUv;”,<br> <br> “void main() {“,<br> “vUv = uv;”,<br> “gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);”,<br> “}”<br> ].join(“\n”),<br> fragmentShader: [<br> “uniform sampler2D tDiffuse;”,<br> “uniform sampler2D tMask;”,<br> “varying vec2 vUv;”,</pre><pre>“void main() {“,<br> // get the current pixel color<br> “vec4 texel = texture2D(tDiffuse, vUv);”,<br> // get alpha based on the color of the mask image<br> “float alpha = texture2D(tMask, vUv).r;”,<br> // apply the alpha to the current pixel<br> “gl_FragColor = texel * alpha;”,<br> “}”<br> ].join(“\n”)<br>});</pre><p>It’s based on the <a href="https://github.com/mrdoob/three.js/blob/dev/examples/js/shaders/CopyShader.js">THREE.CopyShader</a>, which simply passes through the contents of the screen to a subsequent post processing step. Instead of passing the pixel values directly, the mask pass reads an additional texture (the alpha mask) and applies an alpha based on the <strong>r</strong>ed channel of the mask at the same UV coordinates.</p><pre>// get alpha based on the color of the mask image<br>“float alpha = texture2D(tMask, vUv).r;”,</pre><p>This works because the mask image is grayscale, so the RGB values are all equal. In shaders, color channels are interpreted as numbers between 0.0 and 1.0. Multiplying a pixel color by 0.0 will make it fully transparent, while multiplying it by 1.0 will not change it at all.</p><h4>Making a scene</h4><p>The alpha mask approach creates some interesting possibilities, but it has limitations if you want to treat the cinemagraph as an actual three-dimensional space, like below.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fembed%2Fpreview%2FZBGBEz%3Fheight%3D600%26amp%3Bslug-hash%3DZBGBEz%26amp%3Bdefault-tabs%3Djs%2Cresult%26amp%3Bhost%3Dhttp%253A%252F%252Fcodepen.io%26amp%3Bembed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fpen%2FZBGBEz&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F175711.ZBGBEz.small.2d1e7098-1f81-4fb2-8e0b-a2bb0170ca65.png&amp;key=d04bfffea46d4aeda930ec88cc64b87c&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/b4583691325f5a02aebd91abfdc04cbd/href">https://medium.com/media/b4583691325f5a02aebd91abfdc04cbd/href</a></iframe><p>It <em>should </em>be possible to have the 3D objects pass both behind and in front of the statue using masks, but this makes things needlessly complicated, and may involve rendering the scene several times. Instead, I simply added a 2D cut-out of the statue in the image to the THREE.js scene, and made the particles swirl around it.</p><p>Below is the same composition without the underlying image, and the mouse camera controls enabled.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fembed%2Fpreview%2FqqOxYr%3Fheight%3D600%26amp%3Bslug-hash%3DqqOxYr%26amp%3Bdefault-tabs%3Djs%2Cresult%26amp%3Bhost%3Dhttp%253A%252F%252Fcodepen.io%26amp%3Bembed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fpen%2FqqOxYr&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fm.cdpn.io%2Fscreenshot-coming-soon-small.png&amp;key=d04bfffea46d4aeda930ec88cc64b87c&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/b1858f0b2ee2a101a017f734d2ea6445/href">https://medium.com/media/b1858f0b2ee2a101a017f734d2ea6445/href</a></iframe><p>The only tricky part here is determining where to place the 2D cut-out image in the 3D scene, so that it has the same dimensions as the image in the DOM. Basically, we need to calculate the size of a plane at a given distance from the camera, such that the plane is exactly the same size as our viewport (which is the same size as the image behind it).</p><p>Fortunately, this is pretty easy as long as the camera is looking straight at the scene:</p><pre>var cameraZ = camera.position.z;<br>var planeZ = 5;<br>var distance = cameraZ — planeZ;<br>var aspect = viewWidth / viewHeight;<br>var vFov = camera.fov * Math.PI / 180;<br>var planeHeightAtDistance = 2 * Math.tan(vFov / 2) * distance;<br>var planeWidthAtDistance = planeHeightAtDistance * aspect;</pre><p>This formula uses the camera field of view (fov) and the aspect ratio of the viewport (width / height) to calculate the desired size for the plane on which the cut-out image is rendered as a texture.</p><p>All that’s left to do is make the 3D particles rotate around the same Z coordinate as the plane, and you’ve got yourself a scene.</p><h4>Depth masking</h4><p>Further iterating on this, I wanted to apply the same concept, but with an added layer of depth. This resulted in the composition below.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fembed%2Fpreview%2FZBbzBz%3Fheight%3D600%26amp%3Bslug-hash%3DZBbzBz%26amp%3Bdefault-tabs%3Djs%2Cresult%26amp%3Bhost%3Dhttp%253A%252F%252Fcodepen.io%26amp%3Bembed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fpen%2FZBbzBz&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F175711.ZBbzBz.small.faaad5fb-f0c8-4dbc-a364-50e750e8c353.png&amp;key=d04bfffea46d4aeda930ec88cc64b87c&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/cf53b3a672a125186a27d0addf0adfe5/href">https://medium.com/media/cf53b3a672a125186a27d0addf0adfe5/href</a></iframe><p>Here the 3D particle swarm starts behind the back building, swirls behind the front building, then moves in front of the back building, before going off screen in front of the front building. This effect is achieved by creating a little <em>mock</em> scene over the original image, matching (somewhat) in perspective and size. Once that is in place, coordinating the motion and layering becomes much easier.</p><p>Below is a debug version of the same composition, with the mouse camera controls enabled again.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fembed%2Fpreview%2FENVEam%3Fheight%3D600%26amp%3Bslug-hash%3DENVEam%26amp%3Bdefault-tabs%3Djs%2Cresult%26amp%3Bhost%3Dhttp%253A%252F%252Fcodepen.io%26amp%3Bembed-version%3D2&amp;url=https%3A%2F%2Fcodepen.io%2Fzadvorsky%2Fpen%2FENVEam&amp;image=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fi.cdpn.io%2F175711.ENVEam.small.f08a08bb-be30-41fe-959e-f7febda7b1a7.png&amp;key=d04bfffea46d4aeda930ec88cc64b87c&amp;type=text%2Fhtml&amp;schema=codepen" width="800" height="600" frameborder="0" scrolling="no"><a href="https://medium.com/media/db0e2188abb609ab208e65d867a10ced/href">https://medium.com/media/db0e2188abb609ab208e65d867a10ced/href</a></iframe><p>The two white planes that represent the buildings in the 3D scene are not rendered in the final composition. I could have textured them using the same approach as the Bruce Lee statue, but this would have been harder because of the camera position.</p><p>Since the actual buildings are already in the image, the only thing we care about are their dimensions and position in the 3D scene. Because of this, we can discard the color buffer after the buildings are rendered, as long as we keep the depth buffer intact.</p><pre>// clear color and depth<br>renderer.clear(true, true);</pre><pre>// render the two buildings<br>renderer.render(buildingScene, camera);</pre><pre>// clear color (but not depth)<br>renderer.clear(true, false);</pre><pre>// render the particles<br>renderer.render(particleScene, camera);</pre><p>With this approach the planes that represent the buildings essentially become a depth mask for the particles; invisible walls for them to move behind.</p><h4>What’s next</h4><p>I’m pretty excited to have stumbled upon this format. Codevember is far from over, and I intend to make at least a couple more contributions. One area I want to explore is timing the WebGL content to the cinemagraph. Unfortunately, this is pretty much impossible with gifs, but I can use video or a png sequence for both the cinemagraph and the mask to achieve some cool effects.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=75b82dd4cdfd" width="1" height="1" alt=""><hr><p><a href="https://medium.com/your-majesty-co/webgl-masking-composition-75b82dd4cdfd">WebGL Masking &amp; Composition</a> was originally published in <a href="https://medium.com/your-majesty-co">Your Majesty</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>