Saturday, May 25, 2013

Animated Shaders in Three.js

Once again I have been investigating Shaders in Three.js.  My last post on this topic was inspired by glow effects; this time, my inspiration comes from the Three.js lava shader and Altered Qualia's WebGL shader fireball.


For these examples, I'm really only interested in changing the pixel colors, so I'll just worry about the fragment shader.

The Three.js (v.56) code  for the a simple fragment shader that just displays a texture would be:
<script id="fragmentShader" type="x-shader/x-vertex">
uniform sampler2D texture1;
varying vec2 vUv;
void main() 
{
    vec4 baseColor  = texture2D( texture1, vUv );
    gl_FragColor = baseColor;
} 
</script>

(note that this code is contained within its own script tags.)

Then to create the material in the initialization of the Three.js code:
var lavaTexture = new THREE.ImageUtils.loadTexture( 'images/lava.jpg' );
lavaTexture.wrapS = lavaTexture.wrapT = THREE.RepeatWrapping; 

var customUniforms = { texture1: { type: "t", value: lavaTexture }   };

// create custom material from the shader code above within specially labeled script tags
var customMaterial = new THREE.ShaderMaterial( 
{
    uniforms: customUniforms,
    vertexShader:   document.getElementById( 'vertexShader'   ).textContent,
    fragmentShader: document.getElementById( 'fragmentShader' ).textContent
}   );

What we would like to create a more realistic effect is to:
  • add a bit of "random noise" to the texture coordinates vector (vUv) to cause distortion
  • change the values of the random noise so that the distortions in the image change fluidly
  • (optional) add support for transparency (custom alpha values)
To accomplish this, we can add some additional parameters to the shader, namely:
  • a second texture (noiseTexture) to generate "noise values"; for instance, we can add the red/green values at a given pixel to the x and y coordinates of vUv, causing an offset
  • a float (noiseScale) to scale the effects of the "noise values"  
  • a float (time) to pass a "time" value to the shader to continuously shift the texture used to generate noise values
  • a float (baseSpeed) to scale the effects of the time to either speed up or slow down rate of distortions in the base texture
  • a float (alpha) to set the transparency amount
The new version of the fragment shader code looks like this:
<script id="fragmentShader" type="x-shader/x-vertex"> 
uniform sampler2D baseTexture;
uniform float baseSpeed;
uniform sampler2D noiseTexture;
uniform float noiseScale;
uniform float alpha;
uniform float time;
varying vec2 vUv;

void main() 
{
    vec2 uvTimeShift = vUv + vec2( -0.7, 1.5 ) * time * baseSpeed;
    vec4 noise = texture2D( noiseTexture, uvTimeShift );
    vec2 uvNoisyTimeShift = vUv + noiseScale * vec2( noise.r, noise.g );
    vec4 baseColor = texture2D( baseTexture, uvNoisyTimeShift );
    baseColor.a = alpha;
    gl_FragColor = baseColor;
}
</script>

The new code to create this shader in Three.js:
// initialize a global clock to keep track of time
this.clock = new THREE.Clock();

var noiseTexture = new THREE.ImageUtils.loadTexture( 'images/noise.jpg' );
noiseTexture.wrapS = noiseTexture.wrapT = THREE.RepeatWrapping;

var lavaTexture = new THREE.ImageUtils.loadTexture( 'images/lava.jpg' );
lavaTexture.wrapS = lavaTexture.wrapT = THREE.RepeatWrapping; 

// create global uniforms object so its accessible in update method
this.customUniforms = {
    baseTexture:  { type: "t", value: lavaTexture },
    baseSpeed:    { type: "f", value: 0.05 },
    noiseTexture: { type: "t", value: noiseTexture },
    noiseScale:   { type: "f", value: 0.5337 },
    alpha:        { type: "f", value: 1.0 },
    time:         { type: "f", value: 1.0 }
}

// create custom material from the shader code above within specially labeled script tags
var customMaterial = new THREE.ShaderMaterial( 
{
    uniforms: customUniforms,
    vertexShader:   document.getElementById( 'vertexShader'   ).textContent,
    fragmentShader: document.getElementById( 'fragmentShader' ).textContent
}   );

and in the update or render method, don't forget to update the time using something like:
var delta = clock.getDelta();
customUniforms.time.value += delta;

That's about it -- for a live example, check out the demo in my GitHub collection, which uses this shader to create an animated lava-style texture and animated water-style texture.


Happy coding!

Saturday, March 16, 2013

Using Shaders and Selective Glow Effects in Three.js

When I first started working with Three.js, in addition to the awe-inspiring collection of examples from Mr.doob, I was also dazzled by the "glow examples" of Thibaut Despoulain: the glowing Tron disk, the animated glowing Tron disk (with accompanying blog post), the Tron disk with particles, and more recently, the volumetric light approximation (with accompanying blog post).  At the time, I didn't know anything about shaders (although there were some excellent tutorials at Aerotwist, part 1 and part 2).

Recently, I learned about the Interactive 3D Graphics course being offered (for free!) at Udacity, that teaches participants all about Three.js. This course is taught by Eric Haines (Google+, Blog), who has written the excellent book Real-Time Rendering.  Eric stumbled across my own collection of introductory examples for Three.js, and recommended a really great article about an introduction to pixel shaders in Three.js  (a.k.a. fragment shaders) by Felix Turner at Airtight Interactive. This motivated me to do two things: (1) sign up for the Udacity course (which is really excellent, and highly recommended!), and (2) to update my collection of Three.js examples for the latest release of Three.js (version 56 at the time of writing).

While updating, I noticed that a number of new classes had been created for shaders and post-processing effects, and so I spent a lot of time looking through source code and examples, and eventually created two new demos of my own: a minimal example of using a Three.js pixel shader, and a shader explorer, which lets you see the results of applying a variety of the Three.js shaders (sepia, vignette, dot screen, bloom, and blur) and the effects of changing the values of their parameters.

Inspired, I revisited the glowing Tron disk examples, hoping to use the BlendShader.js now included as part of the Three.js github repo.  Alas, the search term "THREE.BlendShader" is almost a Googlewhack, with only two results appearing (at the time of writing, which will hopefully change soon); using these links as a starting point, I found a nice example of using the BlendShader to create a neat motion blur effect on a spinning cube.

Next came some experimentation to implement the approach described by Thibaut above, which requires the creation of two scenes to achieve the glow effect.  The first is the "base scene"; the second contains copies of the base scene objects with either bright textures (for the objects that will glow) or black textures (for nonglowing objects, so that they will block the glowing effect properly in the combined scene). The secondary scene is blurred and then blended with the base scene.  However, BlendShader.js creates a linear combination of the pixels from each image, and this implementation of the glow effect requires additive blending.  So I wrote AdditiveBlendShader.js, which is one of the simplest shaders to write, as you are literally adding together the two color values at the pixels of the two textures you are combining.  The result (with thoroughly commented code) can be viewed here:


Hopefully other Three.js enthusiasts will find this example helpful!








Friday, October 5, 2012

Using Game Controllers for Browser-Based Games

With the recent release of Google Chrome version 22, the Gamepad API is ready for action (no manual adjustment of chrome://flags required).  

Recommended reading:




A great interface to use:
However, due to issues as described in the post:
for the time being, it is better to use the patched version of the code posted at: 
(a GitHub fork of sgraham's code)
at least until the main branch is updated with these changes.

Sunday, September 9, 2012

Digital Humanities

I was recently asked to attend an informal discussion about the "Digital Humanities".  Some quick Google searching revealed a wealth of interesting links, which I'm posting here for my own (and possibly others' ?) future reference:


Wikipedia
http://en.wikipedia.org/wiki/Digital_humanities
"...today digital humanities embrace a variety of topics ranging from curating online collections to data mining large cultural data sets. Digital Humanities currently incorporates both digitized and born-digital materials and combines the methodologies from the traditional humanities disciplines ... with tools provided by computing (such as data visualisation, information retrieval, data mining, statistics, computational analysis) and digital publishing."

Alliance of Digital Humanities Organizations
http://digitalhumanities.org/
http://digitalhumanities.org/dhq/
http://digitalhumanities.org/answers/topic/what-is-digital-humanities
"The Alliance of Digital Humanities Organizations (ADHO) promotes and supports digital research and teaching across all arts and humanities disciplines, acting as a community-based advisory force, and supporting excellence in research, publication, collaboration and training."

CUNY Digital Humanities Resource Guide
http://commons.gc.cuny.edu/wiki/index.php/The_CUNY_Digital_Humanities_Resource_Guide
"...a collaboratively produced introduction to the field of Digital Humanities..."

Digital Humanities Now
http://digitalhumanitiesnow.org/
"Digital Humanities Now showcases the scholarship and news of interest to the digital humanities community through a process of aggregation, discovery, curation, and review. Digital Humanities Now also is an experiment in ways to identify, evaluate, and distribute scholarship on the open web through a weekly publication and the quarterly Journal of Digital Humanities."

Humanities Blast 
http://humanitiesblast.com/publications/
"Engaged Digital Humanities Scholarship"

National Endowment for the Humanities
http://www.neh.gov/divisions/odh
"...supports projects that employ digital technology to improve humanities research, education, preservation, access, and public programming. To that end, ODH works with the scholarly community, and with other funding agencies in the United States and abroad, to encourage collaboration across national and disciplinary boundaries. In addition to sponsoring grant programs, ODH also works collaboratively with the field, participating in conferences and workshops with scholars, librarians, scientists, and other funders to learn more about how to best serve digital scholarship."

Thursday, August 16, 2012

Google Apps Script

Time to prep for the Fall semester classes.  I typically create a spreadsheet of topics on Google Docs Drive, and for student-ease-of-use I would like to use that data in a Google Calendar.  To get these two apps talking, I'm learning Google Apps Script.  It is simple to complete https://developers.google.com/apps-script/your_first_script in a matter of minutes, the syntax is quite readable and easy to understand...

Helpful links:
https://developers.google.com/apps-script/defaultservices

Functions for interacting with spreadsheets:
https://developers.google.com/apps-script/class_spreadsheetapp

Functions for interacting with calendars:
https://developers.google.com/apps-script/class_calendarapp

Here's the function I wrote to export data (lists of dates and topic names for a Calculus 2 course for Fall 2012) to a calendar.

To use it: from Google Spreadsheets, go to Tools -- Script Editor... and enter in the function below (changing variable values as necessary). Save it, then execute the script from Tools -- Script Manager..., accept all the permission requests (only necessary on the first run, as in the tutorial example linked to above), and then execute this script again.

function SpreadsheetToCalendar() 
{
  // This function should be executed from the 
  //  spreadsheet you want to export to the calendar
  var mySpreadsheet = SpreadsheetApp.getActiveSheet();
  
  var myCalendar = CalendarApp.openByName("Calculus 2");
  
  // optional - delete existing events
  var events = myCalendar.getEvents(new Date("January 1, 2011 EST"), 
      new Date("January 1, 2013 EST"));
  for (var i = 0; i < events.length; i++) 
  {
     events[i].deleteEvent();
  }
  
  var dataRange = mySpreadsheet.getRange("B2:C46");
  var data = dataRange.getValues();
  
  // process the data
  for (i in data) 
  {
      var row = data[i];
      // assume that each row contains a date entry and a text entry
      var theDate  = row[0];  // First column of row
      var theTitle = row[1];  // Second column of row
      myCalendar.createAllDayEvent(theTitle, theDate);
  }
 
}
P.S. I've switched to using http://www.stylifyyourblog.com/2012/07/syntax-highlighting-in-blogger-using.html and http://www.tools.stylifyyourblog.com/p/postify.html to format code snippets in this blog... highly recommended!

Saturday, June 9, 2012

Three.js examples on GitHub

In the process of learning Three.js, I am creating my own comprehensive set of examples.  For my own convenience as well as anyone else that may be interested, I'm posting all the code on GitHub at:

http://stemkoski.github.com/Three.js

(As an added bonus, I'm learning how to use GitHub.)