JavaScript. Interpolated points

Similar documents
Introduction to OpenGL/GLSL and WebGL GLSL

Lecture 11 Shaders and WebGL. October 8, 2015

WebGL: Hands On. DevCon5 NYC Kenneth Russell Software Engineer, Google, Inc. Chair, WebGL Working Group

OPENGL RENDERING PIPELINE

WebGL. Creating Interactive Content with WebGL. Media #WWDC14. Session 509 Dean Jackson and Brady Eidson WebKit Engineers

Game Graphics & Real-time Rendering

C P S C 314 S H A D E R S, O P E N G L, & J S RENDERING PIPELINE. Mikhail Bessmeltsev

Comp4422. Computer Graphics. Lab 02: WebGL API Prof. George Baciu. PQ838 x7272.

Workshop 04: A look at three.js

The Graphics Pipeline and OpenGL III: OpenGL Shading Language (GLSL 1.10)!

OpenGL shaders and programming models that provide object persistence

Programming with OpenGL Complete Programs Objectives Build a complete first program

CS452/552; EE465/505. Image Formation

CPSC 436D Video Game Programming

WebGL A quick introduction. J. Madeira V. 0.2 September 2017

WebGL and GLSL Basics. CS559 Fall 2015 Lecture 10 October 6, 2015

Models and Architectures. Angel and Shreiner: Interactive Computer Graphics 7E Addison-Wesley 2015

CS452/552; EE465/505. Image Processing Frame Buffer Objects

Web-Based Visualization

BCA611 Video Oyunları için 3B Grafik

WebGL and GLSL Basics. CS559 Fall 2016 Lecture 14 October

Introduction to Computer Graphics with WebGL

Mining the Rendering Power in Web Browsers. Jianxia Xue Jan. 28, 2014

COMP371 COMPUTER GRAPHICS

The Graphics Pipeline and OpenGL III: OpenGL Shading Language (GLSL 1.10)!

CS452/552; EE465/505. Review & Examples

Programmable Graphics Hardware

Objectives. Programming with WebGL Part 1: Background. Retained vs. Immediate Mode Graphics. Early History of APIs. PHIGS and X.

12.2 Programmable Graphics Hardware

CS559 Computer Graphics Fall 2015

Programming with WebGL Part 1: Background. CS 432 Interactive Computer Graphics Prof. David E. Breen Department of Computer Science

Computer graphics 2: Graduate seminar in computational aesthetics

WebGL Game Development

Graphics Programming. Computer Graphics, VT 2016 Lecture 2, Chapter 2. Fredrik Nysjö Centre for Image analysis Uppsala University

CS 4620 Midterm, October 23, 2018 SOLUTION

Rasterization-based pipeline

Programmable GPUs. Real Time Graphics 11/13/2013. Nalu 2004 (NVIDIA Corporation) GeForce 6. Virtua Fighter 1995 (SEGA Corporation) NV1

Introduction to Computer Graphics with WebGL

CSE 167: Introduction to Computer Graphics Lecture #7: GLSL. Jürgen P. Schulze, Ph.D. University of California, San Diego Spring Quarter 2016

Lighting and Shading II. Angel and Shreiner: Interactive Computer Graphics 7E Addison-Wesley 2015

Shader Programming 1. Examples. Vertex displacement mapping. Daniel Wesslén 1. Post-processing, animated procedural textures

CS 418: Interactive Computer Graphics. Basic Shading in WebGL. Eric Shaffer

WebGL (Web Graphics Library) is the new standard for 3D graphics on the Web, designed for rendering 2D graphics and interactive 3D graphics.

Introduction to Computer Graphics. April 6, 2017 Kenshi Takayama

EDAF80 Introduction to Computer Graphics. Seminar 3. Shaders. Michael Doggett. Slides by Carl Johan Gribel,

Converts geometric primitives into images Is split into several independent stages Those are usually executed concurrently

I Can t Believe It s Not

Sign up for crits! Announcments

Shaders. Introduction. OpenGL Grows via Extensions. OpenGL Extensions. OpenGL 2.0 Added Shaders. Shaders Enable Many New Effects

GLSL Introduction. Fu-Chung Huang. Thanks for materials from many other people

Lecture 17: Shading in OpenGL. CITS3003 Graphics & Animation

CSE 167. Discussion 03 ft. Glynn 10/16/2017

Efficient and Scalable Shading for Many Lights

Shaders. Slide credit to Prof. Zwicker

The Basic Computer Graphics Pipeline, OpenGL-style. Introduction to the OpenGL Shading Language (GLSL)

GLSL 1: Basics. J.Tumblin-Modified SLIDES from:

Adaptive Point Cloud Rendering

Computergraphics Exercise 15/ Shading & Texturing

Objectives Shading in OpenGL. Front and Back Faces. OpenGL shading. Introduce the OpenGL shading methods. Discuss polygonal shading

Introduction to Computer Graphics with WebGL

Using Shaders for Lighting

INFOGR Computer Graphics

Comp 410/510 Computer Graphics Spring Programming with OpenGL Part 2: First Program

INFOGR Computer Graphics

Using Shaders for Lighting

Technical Game Development II. Reference: Rost, OpenGL Shading Language, 2nd Ed., AW, 2006 The Orange Book Also take CS 4731 Computer Graphics

Programming shaders & GPUs Christian Miller CS Fall 2011

Technical Game Development II. Reference: Rost, OpenGL Shading Language, 2nd Ed., AW, 2006 The Orange Book Also take CS 4731 Computer Graphics

The Rasterization Pipeline

CS452/552; EE465/505. Lighting & Shading

Discussion 3. PPM loading Texture rendering in OpenGL

Introduction to the OpenGL Shading Language (GLSL)

Mobile Application Programing: Android. OpenGL Operation

CS452/552; EE465/505. Overview of Computer Graphics

MXwendler Fragment Shader Development Reference Version 1.0

CS4621/5621 Fall Basics of OpenGL/GLSL Textures Basics

To Do. Demo for mytest3. Methodology for Lecture. Importance of Lighting. Brief primer on Color. Computer Graphics

Computer Graphics with OpenGL ES (J. Han) Chapter 6 Fragment shader

Introductory Seminar

Today. Texture mapping in OpenGL. Texture mapping. Basic shaders for texturing. Today. Computergrafik

Blis: Better Language for Image Stuff Project Proposal Programming Languages and Translators, Spring 2017

CGT520 Lighting. Lighting. T-vertices. Normal vector. Color of an object can be specified 1) Explicitly as a color buffer

CSE 4431/ M Advanced Topics in 3D Computer Graphics. TA: Margarita Vinnikov

GLSL Introduction. Fu-Chung Huang. Thanks for materials from many other people

WebGL Seminar: O3D. Alexander Lokhman Tampere University of Technology

Programming Graphics Hardware

CISC 3620 Lecture 7 Lighting and shading. Topics: Exam results Buffers Texture mapping intro Texture mapping basics WebGL texture mapping

WebGL. Announcements. WebGL for Graphics Developers. WebGL for Web Developers. Homework 5 due Monday, 04/16. Final on Tuesday, 05/01

We assume that you are familiar with the following:

Computer Graphics Coursework 1

CS 130 Final. Fall 2015

GPU Programming EE Final Examination

3D Programming. 3D Programming Concepts. Outline. 3D Concepts. 3D Concepts -- Coordinate Systems. 3D Concepts Displaying 3D Models

Page of 4 To view this demonstration, you will need a WebGL compatible browser. If you have a recent version of Chrome, Firefox, Safari or Internet Ex

CS452/552; EE465/505. Texture Mapping in WebGL

Content. Building Geometry Appearance Lights Model Loaders

1 of 5 9/10/ :11 PM

Zeyang Li Carnegie Mellon University

OpenGL Performances and Flexibility

Understanding M3G 2.0 and its Effect on Producing Exceptional 3D Java-Based Graphics. Sean Ellis Consultant Graphics Engineer ARM, Maidenhead

Transcription:

GLSL WebGL is a combination of JavaScript and GLSL providing commands that allow access to and control the GPU via shader programs. What is a Shader? A program which is compiled and run on the GPU. Shaders are written in GLSL, are text strings or files, are compiled in the browser and sent to the GPU where they are executed. The GPU side WebGL code should run as fast as other native code. Shader programs are massively parallel, working on many individual vertices or pixels at once. While data can be passed from the browser and from the vertex shader to the fragment shader, data cannot be passed directly between instances of the shader program. A workaround of sorts is possible with textures but the result of one shader program cannot be passed another. Shader Program In WebGL a shader program must have a vertex shader and a fragment shader. The vertex shader works on vertex data, while the fragment shader works on pixel data. OpenGL also has geometry and compute shaders. e.g. avertexposition = gl.getattriblocation(shaderprogram, "avertexposition"); gl.enablevertexattribarray(avertexposition);... gl.vertexattribpointer(itemsize, gl.float, false, 0, 0); JavaScript ucolor = gl.getuniformlocation(shaderprogram, "ucolor"); gl.uniform4fv(ucolor, [0.0, 1.0, 0.0, 1.0]); Vertex data (3 points) Colour data Vertex shader (GLSL) attribute vec4 avertexposition; gl_position = avertexposition); Interpolated points Fragment shader (GLSL) uniform vec4 ucolor; gl_fragcolor = ucolor; gl_position and gl_fragcolor (along with gl_pointsize and gl_fragdata[]) are built-in variables and represent the output of the shader (gl_fragcoord, gl_pointcoord, gl_frontfacing are built-in inputs). 1

Exercises We'll be using Three.js as it provides the use of custom shaders and takes care of the heavy lifting. (Babylon.js and Clara.io also provide the use of custom shaders.) Show clipping volume Demo vertex displacement cube to sphere & animate Demo vertex displacement wavy cube & animate (shadows won't work) SIMD Texture (vertex shader, fragment shader) Transparency, iridescence, multiple materials Procedural texture, static, animated Light and anisotropic material - teapot Normals Mandelbrot Image processing GPGPU, render to texture, multiple passes, post-processing and ping ponging Babylon.js 2

Task 1 (Raw WebGL) Draw a Triangle Not really, this is just for reference, to show how to set up and use WebGL without any libraries, SDKs, etc.. However, note the shaders at lines 18 and 26. 1 <html> 2 <head> 3 <title>base</title> 4 <style> canvas { width: 100%; height: 100% </style> 5 </head> 6 <body onload="main()"> 7 </body> 8 9 <script id="vertex-shader" type="x-shader/x-vertex"> 10 precision highp float; 11 attribute vec3 avertexposition; 12 13 gl_position = vec4(avertexposition, 1.0); 14 15 </script> 16 17 <script id="fragment-shader" type="x-shader/x-fragment"> 18 precision highp float; 19 uniform vec4 ucolor; 20 21 gl_fragcolor = ucolor; 22 23 </script> 24 25 <script> 26 var shaderprogram; 27 var cubevertexpositionbuffer; 28 var vertices; 29 30 function init() { 31 initwebgl(); 32 initshaderprogram(); 33 initgeometry(); 34 animate(); 35 36 37 function initwebgl() { 38 canvas = document.getelementbyid("mycanvas"); 39 gl = canvas.getcontext("webgl"); 40 41 var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"]; 42 for (var i = 0; i < names.length; ++i) { 43 try { 44 gl = canvas.getcontext(names[i]); 45 46 catch (e) { 47 if (gl) break; 48 49 50 gl.viewportwidth = canvas.width; 51 gl.viewportheight = canvas.height; 52 53 54 function initshaderprogram() { 55 var v = document.getelementbyid("vertex").firstchild.nodevalue; 56 var f = document.getelementbyid("fragment").firstchild.nodevalue; 57 58 var vs = gl.createshader(gl.vertex_shader); 59 gl.shadersource(vs, v); 60 gl.compileshader(vs); 61 62 var fs = gl.createshader(gl.fragment_shader); 63 gl.shadersource(fs, f); 64 gl.compileshader(fs); 65 66 shaderprogram = gl.createprogram(); 3

67 gl.attachshader(shaderprogram, vs); 68 gl.attachshader(shaderprogram, fs); 69 gl.linkprogram(shaderprogram); 70 71 if (!gl.getshaderparameter(vs, gl.compile_status)) 72 console.log(gl.getshaderinfolog(vs)); 73 74 if (!gl.getshaderparameter(fs, gl.compile_status)) 75 console.log(gl.getshaderinfolog(fs)); 76 77 if (!gl.getprogramparameter(shaderprogram, gl.link_status)) 78 console.log(gl.getprograminfolog(shaderprogram)); 79 80 gl.useprogram(shaderprogram); 81 82 shaderprogram.ucolor = gl.getuniformlocation(shaderprogram, "ucolor"); 83 gl.uniform4fv(shaderprogram.ucolor, [0.0, 1.0, 0.0, 1.0]); 84 85 shaderprogram.avertexposition = gl.getattriblocation(shaderprogram, "avertexposition"); 86 gl.enablevertexattribarray(shaderprogram.avertexposition); 87 88 89 function initgeometry() { 90 vertices = new Float32Array([-0.5, 0.5, 0.0, 91 0.5, -0.5, 0.0, 92-0.5, -0.5, 0.0]); 93 94 cubevertexpositionbuffer = gl.createbuffer(); 95 gl.bindbuffer(gl.array_buffer, cubevertexpositionbuffer); 96 gl.bufferdata(gl.array_buffer, vertices, gl.static_draw); 97 98 cubevertexpositionbuffer.itemsize = 3; 99 cubevertexpositionbuffer.numitems = vertices.length / cubevertexpositionbuffer.itemsize; 100 101 102 function draw() { 103 gl.vertexattribpointer(shaderprogram.avertexposition, cubevertexpositionbuffer.itemsize, gl.float, false, 0, 0); 104 105 gl.clearcolor(0, 0.5, 0, 1); 106 gl.clear(gl.color_buffer_bit); 107 108 gl.drawarrays(gl.triangles, 0, cubevertexpositionbuffer.numitems); 109 110 111 function animate() { 112 requestanimationframe(animate); 113 draw(); 114 115 </script> 116 </html> 4

Vertex Shader Task 2 Make a Box in THREE.js (base for rest of exercises) Again, not really, note the shaders (lines 9 and 18) and the shadermaterial (line 75). The shaders take the same form as those is plain WebGL. This is where we'll be focusing our attention. Here the colour of the mesh is controlled by the uniform variable ucolour (line 77). You might wish to try changing the value. An orbit control is added just to allow interaction and make things a bit more interesting. Since there is no lighting in the scene (yet), wireframe is used to make things clearer. 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>glsl - Three.js Cube</title> 5 6 <script src="three.js"></script> 7 <script src="orbitcontrols.js"></script> 8 9 <script id="vertexshader" type="x-shader/x-vertex"> 10 varying vec2 vuv; 11 12 13 vuv = uv; 14 gl_position = projectionmatrix * modelviewmatrix * vec4( position, 1.0 ); 15 16 </script> 17 18 <script id="fragmentshader" type="x-shader/x-fragment"> 19 varying vec2 vuv; 20 uniform vec4 ucolour; 21 22 23 gl_fragcolor = ucolour; 24 25 </script> 26 27 <script> 28 window.addeventlistener? 29 window.addeventlistener("load", init, false) : 30 window.attachevent && window.attachevent("onload", init); 31 32 function init() { 33 var container; 34 var renderer; 35 var camera; 36 37 var scene = new THREE.Scene(); 38 var clock = new THREE.Clock(); 39 var orbitcontrol; 40 41 container = document.getelementbyid("rendertarget"); 42 renderer = createrenderer(container); 43 camera = createcamera(container); 44 var shape = addshape(scene); 45 46 orbitcontrol = new THREE.OrbitControls(camera, renderer.domelement); 47 orbitcontrol.object.position.z *= 1.25; 48 49 window.addeventlistener('resize', function (event) { 50 var w = container.clientwidth; 51 var h = container.clientheight; 52 renderer.setsize(w, h); 53 camera.aspect = w / h; 54 camera.updateprojectionmatrix(); 55 ); 56 57 var render = function () { 5

58 orbitcontrol.update(clock.getdelta()); 59 renderer.render(scene, camera); 60 requestanimationframe(render); 61 ; 62 63 render(); 64 65 66 function addshape(scene) { 67 var geometry = new THREE.BoxGeometry(15, 15, 15, 10, 10, 10); 68 var material = creatematerial(); 69 material.wireframe = true; 70 var shape = new THREE.Mesh(geometry, material); 71 scene.add(shape); 72 73 74 function creatematerial() { 75 var shadermaterial = new THREE.ShaderMaterial({ 76 uniforms: { 77 ucolour: { type: "v4", value: new THREE.Vector4(1, 0, 0, 1), 78, 79 //attributes: {, 80 vertexshader: document.getelementbyid('vertexshader').textcontent, 81 fragmentshader: document.getelementbyid('fragmentshader').textcontent 82 ); 83 84 return shadermaterial; 85 86 87 function createcamera(container) { 88 var w = container.clientwidth; 89 var h = container.clientheight; 90 var camera = new THREE.PerspectiveCamera(75, w / h, 0.1, 1000); 91 camera.position.z = 30; 92 return camera; 93 94 95 function createrenderer(container) { 96 var renderer = new THREE.WebGLRenderer({ alpha: true ); 97 renderer.setpixelratio(window.devicepixelratio); 98 container.appendchild(renderer.domelement); 99 renderer.setsize(container.clientwidth, container.clientheight); 100 return renderer; 101 102 </script> 103 </head> 104 <body> 105 <div style="position: absolute; width: 98%; height: 98%;" id="rendertarget"></div> 106 </body> 107 </html> 6

Task 3 Make the Box Spherical Static Now let's make the box spherical. All points on the surface of a sphere are equidistant from the centre, so we need to move all the boxes' vertices so that they are. For each point, find its unit vector and multiply by the desired radius. 1. Change the vertex shader to do the following: a. Add a uniform (uradius) for the radius of the sphere b. For a vertex, find its unit position vector (the vector from the centre to the vertex) c. Multiply the vector by the radius 2. Add a uniform for the radius (uradius) to the list of uniforms in creatematerial Solution file -- 11.Threejs-Spherise.html Change over time Let's transform between the cube and sphere over time. The control logic will be split over JavaScript and GLSL. 1. Change the vertex shader to do the following: a. Add a uniform (ulimit) b. Add an "if" statement, such that if the vertex position is greater than the radius apply the "sphere" logic as above else leave it unchanged. 2. Change the JavaScript render function (~line 66) to the following: var radius = 0, min = 10, off = 5; var render = function () { var delta = clock.getdelta(); orbitcontrol.update(delta); radius += delta / 5; radius %= 10; material.uniforms.uradius.value = min + off * Math.sin(2 * Math.PI * radius); renderer.render(scene, camera); requestanimationframe(render); ; Note: using sin guarantees values between 1 and -1. Rewrite without "if" statement Warning, Will Robinson! Warning! GLSL uses a SIMD (Single Instruction, Multiple Data) model, a single instruction is run on the data in each thread (not a CPU thread), so when an if statement is encountered if the result can vary between threads BOTH branches are executed (e.g. for a single uniform if(uvalue == 3) would only a single branch would be executed, whereas for a varying if(vvalue == 3) both branches would be executed). So, here using "if" is bad. To avoid this the body of the main becomes: 7

8 vuv = uv; float mag = min(length(position), uradius); vec3 t = max(normalize(position) * uradius, position); gl_position = projectionmatrix * modelviewmatrix * vec4( mag * normalize(position), 1.0 ); Try changing min to max for a different effect. Solution file -- 12.Threejs-Spherise-animated.html Task 4 Make the Cube Wobbly For a slightly different animation, let's make the box wobbly. Offset all points along one axis by some amount at right angles. 1. Change the vertex shader to do the following: vuv = uv; tposition = position; tposition.x += cos(uradius + tposition.y); gl_position = projectionmatrix * modelviewmatrix * vec4( tposition, 1.0 ); 2. In the JavaScript render function change: to material.uniforms.uradius.value = min + off * Math.sin(2 * Math.PI * radius); material.uniforms.uradius.value = radius * 5; Solution file -- 13.Threejs-Spherise-wave.html Task 5 Display an Image The sampler2d type allows the use of textures in GLSL. It can be used in vertex and fragment shaders. Here, we'll demo its use in a vertex shader. It's more properly used in fragment shaders but can be used as a method to get data into a vertex shader. 1. In the header include the smiley and dm js files (these hold the base 64 encoded images) <script src="smiley.js"></script> <script src="dm.js"></script> 2. In the vertex shader: a. Add a sampler2d and a varying b. Read a colour for the current from the sampler uniform sampler2d utexture; varying vec4 vcolour; vcolour = texture2d( utexture, uv ); gl_position = projectionmatrix * modelviewmatrix * vec4( position, 1.0 ); 3. In the fragment shader: a. Assign the varying to gl_fragcolor varying vec4 vcolour; gl_fragcolor = vcolour; 4. In JavaScript in the addshape function: a. Revert the render function to its simpler form var render = function () {

orbitcontrol.update(clock.getdelta()); requestanimationframe(render); renderer.render(scene, camera); ; b. Change BoxGeometry to PlaneGeometry function addshape(scene) { var geometry = new THREE.PlaneGeometry(15, 15, 10, 10); c. Change the creatematerial function to load and use an image function creatematerial() { var image = new Image(); var texture = new THREE.Texture(image); texture.needsupdate = true; var shadermaterial = new THREE.ShaderMaterial({ uniforms: { utexture: { type: "t", value: texture, //attributes: {, vertexshader: document.getelementbyid('vertexshader').textcontent, fragmentshader: document.getelementbyid('fragmentshader').textcontent ); image.onload = function () { texture.needsupdate = true; ; image.src = imgdm;// imgsmiley; return shadermaterial; The image will initially look like pants. Increasing the height and width segment count for the PlaneGeometry will improve it. Fragment Shader Task 6 Display an Image (properly) When displaying images, a fragment shader should really be used (the exception is volume rendering or similar). So let's do it properly, by moving the sampler2d to fragment shader. 1. In the vertex shader: varying vec4 vuv; vuv = uv; gl_position = projectionmatrix * modelviewmatrix * vec4( position, 1.0 ); 2. In the fragment shader: varying vec4 vuv; uniform sampler2d utexture; gl_fragcolor = texture2d( utexture, uv ); 3. The vertex density is now irrelevant to image quality (and the wireframe looks the same). So, in JavaScript in the addshape function, reduce the height and width segments: function addshape(scene) { var geometry = new THREE.PlaneGeometry(15, 15, 1, 1); Play around with the colours and transparency, rotate/mirror the image. Solution file -- 21.Threejs-image-fragment.html 9

Task 7 Image Processing We've done some simple image processing, but using a convolution kernel (just a 3 3 or 5 5 matrix) it's possible to achieve a variety of more sophisticated effects. For instance, to perform edge detection, for each pixel its neighbouring pixels are weighted and summed. 1. In the fragment shader: varying vec2 vuv; uniform sampler2d utexture; uniform vec2 utexturesize; uniform float ukernel[9]; vec2 onepixel = vec2(1.0, 1.0) / utexturesize; vec4 colorsum = texture2d(utexture, vuv + onepixel * vec2(-1, -1)) * ukernel[0] + texture2d(utexture, vuv + onepixel * vec2( 0, -1)) * ukernel[1] + texture2d(utexture, vuv + onepixel * vec2( 1, -1)) * ukernel[2] + texture2d(utexture, vuv + onepixel * vec2(-1, 0)) * ukernel[3] + texture2d(utexture, vuv + onepixel * vec2( 0, 0)) * ukernel[4] + texture2d(utexture, vuv + onepixel * vec2( 1, 0)) * ukernel[5] + texture2d(utexture, vuv + onepixel * vec2(-1, 1)) * ukernel[6] + texture2d(utexture, vuv + onepixel * vec2( 0, 1)) * ukernel[7] + texture2d(utexture, vuv + onepixel * vec2( 1, 1)) * ukernel[8] ; float kernelweight = ukernel[0] + ukernel[1] + ukernel[2] + ukernel[3] + ukernel[4] + ukernel[5] + ukernel[6] + ukernel[7] + ukernel[8] ; if (kernelweight <= 0.0) { kernelweight = 1.0; gl_fragcolor = vec4((colorsum / kernelweight).rgb, 1); 2. In JavaScript in the creatematerial function: a. In the creatematerial function, add uniforms for utexturesize, ukernel and utexture to the ShaderMaterial and assign values to them function creatematerial() { var image = new Image(); var texture = new THREE.Texture(image); var edgedetectkernel = [ 1, -1, -1, -1, +8, -1, -1, -1, -1 ]; var shadermaterial = new THREE.ShaderMaterial({ uniforms: { utexturesize: { type: "v2", value: new THREE.Vector2(0,0), ukernel: { type: "fv1", value: edgedetectkernel, utexture: { type: "t", value: texture,, //attributes: {, vertexshader: document.getelementbyid('vertexshader').textcontent, fragmentshader: document.getelementbyid('fragmentshader').textcontent ); 10 image.onload = function () { shadermaterial.uniforms.utexturesize.value = new THREE.Vector2(image.width, image.height); texture.needsupdate = true; ; image.src = imgdm;// imgsmiley;

11 return shadermaterial; Task 8 Procedural texturing part 1 Let's get ambitious and replace the plain colours with a procedural texture. The texture is taken from http://glslsandbox.com/e#7868.1 (formerly http://glsl.heroku.com/e#7868.1) 1. The vertex shader: gl_position = projectionmatrix * modelviewmatrix * vec4(position, 1.0 ); 2. The fragment shader: uniform float time; uniform float alpha; uniform vec2 resolution; #define PI 3.14159 #define TWO_PI (PI*2.0) #define N 68.5 vec2 center = gl_fragcoord.xy; center.x=-10.12*sin(time/200.0); center.y=-10.12*cos(time/200.0); vec2 v = (gl_fragcoord.xy - resolution/20.0) / min(resolution.y,resolution.x) * 0.1; v.x=v.x-10.0; v.y=v.y-200.0; float col = 0.0; for(float i = 0.0; i < N; i++) { float a = i * (TWO_PI/N) * 61.95; col += cos(two_pi*(v.y * cos(a) + v.x * sin(a) + sin(time*0.004)*100.0 )); col /= 5.0; gl_fragcolor = vec4(col*1.0, -col*1.0, -col*4.0, 1.0); 3. In JavaScript in function creatematerial() function creatematerial() { var shadermaterial = new THREE.ShaderMaterial({ uniforms: { time: { type: 'f', value: 0.2, scale: { type: 'f', value: 0.2, alpha: { type: 'f', value: 0.6, resolution: { type: "v2", value: new THREE.Vector2(5, 5), //attributes: {, vertexshader: document.getelementbyid('vertexshader').textcontent, fragmentshader: document.getelementbyid('fragmentshader').textcontent ); return shadermaterial; Task 9 Procedural texturing part 2 The texture looks wrong, it doesn t change when the cube rotates; this is because the shader uses gl_fragcoord which works in screen space and so never changes for a given pixel. For a better effect we need to use uv coordinates for each face. 1. In the vertex shader: a. Add a varying for a texture co-ordinate (i.e. vec2 vuv) b. Assign uv to vuv

12 varying vec2 vuv; vuv = uv; gl_position = projectionmatrix * modelviewmatrix * vec4(position, 1.0 ); 2. In the fragment shader: a. Add a varying for a texture co-ordinate (i.e. vec2 vuv) <script id="vertexshader" type="x-shader/x-vertex"> varying vec2 vuv; b. Replace gl_fragcoord.xy with vuv: i. Assign (vuv.xy - resolution) / min(resolution.y,resolution.x) * 15.0 to v vec2 center = gl_fragcoord.xy; center.x=-10.12*sin(time/200.0); center.y=-10.12*cos(time/200.0); vec2 v = (vuv.xy - resolution) / min(resolution.y,resolution.x) * 15.0; 3. In the Javascript to animate the texture: a. In the render function, update the time value var render = function () { orbitcontrol.update(clock.getdelta()); material.uniforms.time.value += 0.005; requestanimationframe(render); renderer.render(scene, camera); ; Task 11 Interacting with Light This is a bit messy as the last couple of versions of Three.js appears to have broken the ShaderMaterial light interaction and I've had to cobble something together at the last minute. 1. In the vertex shader: varying vec3 vnormal; varying vec3 vviewposition; varying vec3 vworldposition; gl_position = projectionmatrix * modelviewmatrix * vec4( position, 1.0 ); vnormal = normalize( normalmatrix * normal ); vec4 mvposition = modelviewmatrix * vec4( position, 1.0 ); vviewposition = -mvposition.xyz; vworldposition = position; 2. In the fragment shader: uniform vec3 umaterialcolor; uniform vec3 uspecularcolor; uniform vec3 udirlightpos; uniform vec3 udirlightcolor; uniform vec3 uambientlightcolor; uniform float ukd; uniform float uks; uniform float shininess; uniform float ugroove; varying vec3 vnormal;

varying vec3 vviewposition; varying vec3 vworldposition; gl_fragcolor = vec4( uambientlightcolor, 1.0 ); // compute direction to light vec4 ldirection = viewmatrix * vec4( udirlightpos, 0.0 ); vec3 lvector = normalize( ldirection.xyz ); vec3 normal = normalize( vnormal ); for ( int i = 0; i < 4; i++) { vec3 offset = vworldposition; if(i==1) offset = -vworldposition; else if(i==2) { //offset.xy = vworldposition.yx; offset.y = -vworldposition.y; else if(i==3) { //offset.xy = vworldposition.yx; offset.x = -vworldposition.x; offset.y = 0.0; vec3 jigglednormal = normalize( normal + ugroove * normalize( offset ) ); // diffuse: N * L. Normal must be normalized, since it's interpolated. float diffuse = 0.25 * max( dot( jigglednormal, lvector ), 0.0); gl_fragcolor.rgb += ukd * umaterialcolor * udirlightcolor * diffuse; // specular: N * H to a power. H is light vector + view vector vec3 viewposition = normalize( vviewposition ); vec3 pointhalfvector = normalize( lvector + viewposition ); float pointdotnormalhalf = max( dot( jigglednormal, pointhalfvector ), 0.0 ); float specular = uks * pow( pointdotnormalhalf, shininess ); specular *= diffuse*(2.0 + shininess)/8.0; // This can give a hard termination to the highlight, but it's better than some weird sparkle. // Note: we don't quit here because the solution will use this code twice. if (diffuse <= 0.0) { specular = 0.0; gl_fragcolor.rgb += udirlightcolor * uspecularcolor * specular; 3. In JavaScript in function creatematerial() a. Major changes to handle lights and their properties function creatematerial() { var shader = { uniforms: { "udirlightpos": { type: "v3", value: new THREE.Vector3(), "udirlightcolor": { type: "c", value: new THREE.Color(0xFFFFFF), "uambientlightcolor": { type: "c", value: new THREE.Color(0x050505), "umaterialcolor": { type: "c", value: new THREE.Color(0xFFFFFF), "uspecularcolor": { type: "c", value: new THREE.Color(0xFFFFFF), 13 ukd: { type: "f", value: 0.7, uks: { type: "f", value: 0.3, shininess: {

; type: "f", value: 100.0, ugroove: { type: "f", value: 1.0 var u = THREE.UniformsUtils.clone(shader.uniforms); var vs = document.getelementbyid('vertexshader').text; var fs = document.getelementbyid('fragmentshader').text; var material = new THREE.ShaderMaterial({ uniforms: u, vertexshader: vs, fragmentshader: fs ); return material; b. Set the properties var material = addshape(scene); //material.wireframe = true; material.uniforms.udirlightpos.value = light.position; material.uniforms.udirlightcolor.value = light.color; material.uniforms.uambientlightcolor.value = ambientlight.color; var ambientlight = new THREE.AmbientLight(0x333333); var light = new THREE.PointLight(0xffff00, 1.0); light.position.set(100.0, 100.0, 0.1); scene.add(light); 14

References and resources Shader based on http://glsl.heroku.com/e#7868.1 Three.js Resources Online GLSL editors Cheat sheets https://www.khronos.org/files/webgl/webgl-reference-card-1_0.pdf http://appletree.or.kr/quick_reference_cards/web_development/webgl%20cheat%20sheet.pdf (original 404) 15