Modifying text in your html file: If your web page has a named span element, such as: <span id=foo>this is my span element</span>then you can set the text of that span via the following code in your script: document.getElementById(id).firstChild.nodeValue = str;where 'id' in the above case would be "foo", and 'str' is whatever you would like the new text to be. I've found it convenient to implement this as a function: function setSpan(id, str) { document.getElementById(id).firstChild.nodeValue = str; } Using this technique, you can empower your WebGL interactions to make changes to the text of the surrounding document, which will allow you to do things such as having your document text correctly state the current angle or length of something in an accompanying interactive figure. Setting white background color for your scene: You can set the background color of your WebGL canvas to be anything you want. In particular, if you want your figure to "blend in" to the page, so that it looks like a diagram in your document, you might went to set it to have the same background color as the rest of your page (eg: white).
To do this, in gl.clearColor(0.0, 0.0, 0.0, 1.0);to: gl.clearColor(1.0, 1.0, 1.0, 1.0); Improved noise in JavaScript: As I mentioned in class, I've ported my Improved Noise algorithm to JavaScript, as the file inoise.js. You can use it to model shapes in various ways. For example, a bumpy spheroid might be implemented like this: var sph = function(u,v) { var theta = 2 * Math.PI * u, phi = Math.PI * (v - .5), cosT = Math.cos(theta) , cosP = Math.cos(phi) , sinT = Math.sin(theta) , sinP = Math.sin(phi) ; var x = cosT * cosP, y = sinT * cosP, z = sinP; var r = 1 + noise(2*x, 2*y, 2*z) / 12 + noise(4*x, 4*y, 4*z) / 24; return [ r * x, r * y, 1.3 * r * z ]; } Feel free to use this function in your geometric modeling.
Triangle strips:
As I explained in class, triangle strips
allow you to keep the transfer of geometry data from your CPU
to your GPU down to rougly one vertex per triangle.
In the version of
Texture mapping: In order to load textures while working on your local computer, you need to make your browser think of your local file system as a server source. You can do that via this shell script, which was graciously provided by Francisca: #!/bin/sh python -m SimpleHTTPServer & open -a /Applications/*Chrome.app http://localhost:8000In order to do texture mapping, you need to include the following code in your drawObject() function,
after the line gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer); :
if (! (obj.textureSrc === undefined)) if (obj.texture === undefined) { var image = new Image(); image.onload = function() { var gl = this.gl; gl.bindTexture (gl.TEXTURE_2D, this.obj.texture = gl.createTexture()); gl.texImage2D (gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this); gl.texParameteri (gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri (gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); gl.generateMipmap(gl.TEXTURE_2D); gl.bindTexture(gl.TEXTURE_2D, null); }; image.gl = gl; image.obj = obj; image.src = obj.textureSrc; } else { gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, obj.texture); gl.uniform1i(gl.getUniformLocation(sProgram, "uSampler"), 0); } This will then allow you to define a shader that contains a texture sampler, such as: <script id=fs_wood type=x-shader/x-fragment> uniform sampler2D uSampler; uniform vec3 uLDir; varying vec3 vNormal; varying vec2 vUV; void main(void) { float d = .1 + .9 * max(0., dot(uLDir, normalize(vNormal))); vec3 rgb = vec3(d,d,d); vec3 trgb = ungammaCorrect(texture2D(uSampler, vUV).xyz); rgb = rgb * trgb; gl_FragColor = vec4(gammaCorrect(rgb), 1.); } </script>where the ungammaCorrect and
gammaCorrect
functions can be defined, respectively, as:
vec3 ungammaCorrect(vec3 c) { return vec3(pow(c.x,2.222),pow(c.y,2.222),pow(c.z,2.222)); } vec3 gammaCorrect(vec3 c) { return vec3(pow(c.x,.45),pow(c.y,.45),pow(c.z,.45)); }Note in the above how we needed to un-gamma-correct the loaded texture image before combining it linearly with the other shading factors. Then when everything was all done, we gamma-corrected the final result
Now all you need to do, when you define an object that contains
a texture sampler, you just need to set its
objects[0].textureSrc = "wood_floor.jpg";
Bump mapping: For fine perturbations of a surface, it can be very expensive to generate and render the large number of triangles required for true surface normal perturbation. Therefore for finely detailed bumps, we sometimes just use Bump Mapping, a technique first described by Jim Blinn about 40 years ago. The basic idea is to modulate the surface normal, within the fragment shader, to reflect the changes in surface direction that would be produced by an actual bumpy surface. Since the human eye is more sensitive to variations in shading than to variations in object silhouette, this technique can produce a fairly convincing approximation to the appearance of surface bumpiness, at a fraction of the computational cost of building finely detailed geometric models. To do bump mapping of a procedural texture T that is defined over the (x,y,z) domain (the noise function is an example of one such procedural texture), we can think of the value of T(x,y,z) as a variation in surface height. In order to simulate the hills and valleys of this bumpy surface, we subtract the derivative of T from the normal (because the normal will point toward the valleys), and then renormalize to restore the normal vector to unit length. We can approximate the vector valued derivative at surface point (x,y,z) by finite differences (where ε below is some very small positive number): p0 = T(x,y,z)which we can then use to modify the surface normal: normal ← normalize( normal - vec3(px,py,pz) )
HOMEWORK: Implement as many of the topics we covered in class as you would like. As usual, make something cool and fun and interesting. Surprise me if you can. :-) Definitely implement both proper triangle strips and texture mapping, since those will be important for the assignments that follow in later weeks. |