diff --git a/README.md b/README.md index 2d26873..453d42c 100644 --- a/README.md +++ b/README.md @@ -1,362 +1,86 @@ -------------------------------------------------------------------------------- -CIS565: Project 5: WebGL -------------------------------------------------------------------------------- -Fall 2014 -------------------------------------------------------------------------------- -Due Monday 11/03/2014 -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -NOTE: -------------------------------------------------------------------------------- -This project requires any graphics card with support for a modern OpenGL -pipeline. Any AMD, NVIDIA, or Intel card from the past few years should work -fine, and every machine in the SIG Lab and Moore 100 is capable of running -this project. - -This project also requires a WebGL capable browser. The project is known to -have issues with Chrome on windows, but Firefox seems to run it fine. - -------------------------------------------------------------------------------- -INTRODUCTION: -------------------------------------------------------------------------------- -In this project, you will get introduced to the world of GLSL in two parts: -vertex shading and fragment shading. The first part of this project is the -Image Processor, and the second part of this project is a Wave Vertex Shader. - -In the first part of this project, you will implement a GLSL vertex shader as -part of a WebGL demo. You will create a dynamic wave animation using code that -runs entirely on the GPU. - -In the second part of this project, you will implement a GLSL fragment shader -to render an interactive globe in WebGL. This will include texture blending, -bump mapping, specular masking, and adding a cloud layer to give your globe a -uniquie feel. - -------------------------------------------------------------------------------- -CONTENTS: -------------------------------------------------------------------------------- -The Project5 root directory contains the following subdirectories: - -* js/ contains the javascript files, including external libraries, necessary. -* assets/ contains the textures that will be used in the second half of the - assignment. -* resources/ contains the screenshots found in this readme file. - -------------------------------------------------------------------------------- -PART 1 REQUIREMENTS: -------------------------------------------------------------------------------- - -In Part 1, you are given code for: - -* Drawing a VBO through WebGL -* Javascript code for interfacing with WebGL -* Functions for generating simplex noise - -You are required to implement the following: - -* A sin-wave based vertex shader: - -![Example sin wave grid](resources/sinWaveGrid.png) - -* One interesting vertex shader of your choice - -------------------------------------------------------------------------------- -PART 1 WALKTHROUGH: -------------------------------------------------------------------------------- -**Sin Wave** - -* For this assignment, you will need the latest version of Firefox. -* Begin by opening index.html. You should see a flat grid of black and white - lines on the xy plane: - -![Example boring grid](resources/emptyGrid.png) - -* In this assignment, you will animate the grid in a wave-like pattern using a - vertex shader, and determine each vertex’s color based on its height, as seen - in the example in the requirements. -* The vertex and fragment shader are located in script tags in `index.html`. -* The JavaScript code that needs to be modified is located in `index.js`. -* Required shader code modifications: - * Add a float uniform named u_time. - * Modify the vertex’s height using the following code: - - ```glsl - float s_contrib = sin(position.x*2.0*3.14159 + u_time); - float t_contrib = cos(position.y*2.0*3.14159 + u_time); - float height = s_contrib*t_contrib; - ``` - - * Use the GLSL mix function to blend together two colors of your choice based - on the vertex’s height. The lowest possible height should be assigned one - color (for example, `vec3(1.0, 0.2, 0.0)`) and the maximum height should be - another (`vec3(0.0, 0.8, 1.0)`). Use a varying variable to pass the color to - the fragment shader, where you will assign it `gl_FragColor`. - - * Using dat.gui, you will add color pickers to modify the max and min colors - via GUI. You will do this by adding the proper uniforms to the fragment - shader, and using the addColor function from dat.GUI. +WebGL Globe Rendering -* Required JavaScript code modifications: - * A floating-point time value should be increased every animation step. - Hint: the delta should be less than one. - * To pass the time to the vertex shader as a uniform, first query the location - of `u_time` using `context.getUniformLocation` in `initializeShader()`. - Then, the uniform’s value can be set by calling `context.uniform1f` in - `animate()`. +This is a globe renderer implemented using WebGL. +This project requires a WebGL capable browser. FireFox is recommended. -**Wave Of Your Choice** +[Video Demo] (https://www.youtube.com/watch?v=eMhoia_TiMs&feature=youtu.be) -* Create another copy of `index.html`. Call it `index_custom.html`, or - something similar. -* Implement your own interesting vertex shader! In your README.md with your - submission, describe your custom vertex shader, what it does, and how it - works. +![](day1.jpg) +![](day2.jpg) +![](midDay1.jpg) -------------------------------------------------------------------------------- -PART 2 REQUIREMENTS: -------------------------------------------------------------------------------- -In Part 2, you are given code for: +###Features -* Reading and loading textures -* Rendering a sphere with textures mapped on -* Basic passthrough fragment and vertex shaders -* A basic globe with Earth terrain color mapping -* Gamma correcting textures -* javascript to interact with the mouse - * left-click and drag moves the camera around - * right-click and drag moves the camera in and out +* Bump Map -You are required to implement: +Normals are adjusted according to a texture map of heights. -* Bump mapped terrain -* Rim lighting to simulate atmosphere -* Night-time lights on the dark side of the globe -* Specular mapping -* Moving clouds +* Rim Lighting to simulate atmosphere -You are also required to pick one open-ended effect to implement: +This is done by testing normal and position of the fragment in camera space, and according to their dot +product, when they are orthogonal, gives it a light blue color and smooths out as becoming less orthogonal. -* Procedural water rendering and animation using noise -* Shade based on altitude using the height map -* Cloud shadows via ray-tracing through the cloud map in the fragment shader -* Orbiting Moon with texture mapping and shadow casting onto Earth -* Draw a skybox around the entire scene for the stars. -* Your choice! Email Liam and Patrick to get approval first +* Night-time Lights on dark side of earth -Finally in addition to your readme, you must also set up a gh-pages branch -(explained below) to expose your beautiful WebGL globe to the world. +Switch texture to night texture when rendering dark side of earth. Smooth transition between day and night using mix(). -Some examples of what your completed globe renderer will look like: +* Specular Mapping -![Completed globe, day side](resources/globe_day.png) +According to a specular map, fragment shader will decide whether to show specular on that fragment. Land doesn't show +specular while ocean does. -Figure 0. Completed globe renderer, daylight side. +* Moving Cloud -![Completed globe, twilight](resources/globe_twilight.png) +Two textures, one of cloud color and the other of cloud transparency are read and mix with terrain color accordingly. +UV coordinates are shifted by time to make cloud move. -Figure 1. Completed globe renderer, twilight border. +* Ocean Shader -![Completed globe, night side](resources/globe_night.png) +Generated two snoise() (*using Ashima's Implementation, link below). The 2 noises have different frequencies, and opposite direction +of uv movement. Stacking the two together created moving, shiny ocean surface. -Figure 2. Completed globe renderer, night side. +###Performance Analysis -------------------------------------------------------------------------------- -PART 2 WALKTHROUGH: -------------------------------------------------------------------------------- +There was no any noticeable difference after adding each feature (60 FPS all the way). +So I went on to do some test like adding meaningless computation to the fragment shader: -Open part2/frag_globe.html in Firefox to run it. You’ll see a globe -with Phong lighting like the one in Figure 3. All changes you need to make -will be in the fragment shader portion of this file. + float dumb; -![Initial globe](resources/globe_initial.png) + for(float i = 0.0;i< 100.0; i+=1.0) -Figure 3. Initial globe with diffuse and specular lighting. + { -**Night Lights** + dumb += cos(snoise(v_Texcoord + v_Position.xy + i))/3.0; -The backside of the globe not facing the sun is completely black in the -initial globe. Use the `diffuse` lighting component to detect if a fragment -is on this side of the globe, and, if so, shade it with the color from the -night light texture, `u_Night`. Do not abruptly switch from day to night; -instead use the `GLSL mix` function to smoothly transition from day to night -over a reasonable period. The resulting globe will look like Figure 4. -Consider brightening the night lights by multiplying the value by two. + } -The base code shows an example of how to gamma correct the nighttime texture: + float foo = dumb; -```glsl -float gammaCorrect = 1/1.2; -vec4 nightColor = pow(texture2D(u_Night, v_Texcoord), vec4(gammaCorrect)); -``` +I observed something interesting. -Feel free to play with gamma correcting the night and day textures if you -wish. Find values that you think look nice! +Iteration | FPS +----- | ----- +50 | 60 FPS +100 | 60 FPS +150 | 60 FPS (started lower) +200 | ~51 FPS +250 | ~39 FPS +>250 | unable to run -![Day/Night without specular mapping](resources/globe_nospecmap.png) +Anything below 200 iterations runs at 60 fps however anything greater than 250, even 260 won't even run. +No matter how long I waited. Some started with less than 60 FPS but came back to 60 after few seconds. -Figure 4. Globe with night lights and day/night blending at dusk/dawn. -**Specular Map** +###Part 1 Custom Wave -Our day/night color still shows specular highlights on landmasses, which -should only be diffuse lit. Only the ocean should receive specular highlights. -Use `u_EarthSpec` to determine if a fragment is on ocean or land, and only -include the specular component if it is in ocean. +Seismic Wave: It's implemented based on a sin function of distance of a point to the epic center along with other settings and parameters. +![](seismic.jpg) -![Day/Night with specular mapping](resources/globe_specmap.png) +###Third Party Code: -Figure 5. Globe with specular map. Compare to Figure 4. Here, the specular -component is not used when shading the land. +snoise() by: +* License : Copyright (C) 2011 Ashima Arts. All rights reserved. -**Clouds** - -In day time, clouds should be diffuse lit. Use `u_Cloud` to determine the -cloud color, and `u_CloudTrans` and `mix` to determine how much a daytime -fragment is affected by the day diffuse map or cloud color. See Figure 6. - -In night time, clouds should obscure city lights. Use `u_CloudTrans` and `mix` -to blend between the city lights and solid black. See Figure 7. - -Animate the clouds by offseting the `s` component of `v_Texcoord` by `u_time` -when reading `u_Cloud` and `u_CloudTrans`. - -![Day with clouds](resources/globe_daycloud.png) - -Figure 6. Clouds with day time shading. - -![Night with clouds](resources/globe_nightcloud.png) - -Figure 7. Clouds observing city nights on the dark side of the globe. - -**Bump Mapping** - -Add the appearance of mountains by perturbing the normal used for diffuse -lighting the ground (not the clouds) by using the bump map texture, `u_Bump`. -This texture is 1024x512, and is zero when the fragment is at sea-level, and -one when the fragment is on the highest mountain. Read three texels from this -texture: once using `v_Texcoord`; once one texel to the right; and once one -texel above. Create a perturbed normal in tangent space: - -`normalize(vec3(center - right, center - top, 0.2))` - -Use `eastNorthUpToEyeCoordinates` to transform this normal to eye coordinates, -normalize it, then use it for diffuse lighting the ground instead of the -original normal. - -![Globe with bump mapping](resources/globe_bumpmap.png) - -Figure 8. Bump mapping brings attention to mountains. - -**Rim Lighting** - -Rim lighting is a simple post-processed lighting effect we can apply to make -the globe look as if it has an atmospheric layer catching light from the sun. -Implementing rim lighting is simple; we being by finding the dot product of -`v_Normal` and `v_Position`, and add 1 to the dot product. We call this value -our rim factor. If the rim factor is greater than 0, then we add a blue color -based on the rim factor to the current fragment color. You might use a color -something like `vec4(rim/4, rim/2, rim/2, 1)`. If our rim factor is not greater -than 0, then we leave the fragment color as is. Figures 0,1 and 2 show our -finished globe with rim lighting. - -For more information on rim lighting, -read http://www.fundza.com/rman_shaders/surface/rim_effects/index.html. - -------------------------------------------------------------------------------- -GH-PAGES -------------------------------------------------------------------------------- -Since this assignment is in WebGL you will make your project easily viewable by -taking advantage of GitHub's project pages feature. - -Once you are done you will need to create a new branch named gh-pages: - -`git branch gh-pages` - -Switch to your new branch: - -`git checkout gh-pages` - -Create an index.html file that is either your renamed frag_globe.html or -contains a link to it, commit, and then push as usual. Now you can go to - -`.github.io/` - -to see your beautiful globe from anywhere. - -------------------------------------------------------------------------------- -README -------------------------------------------------------------------------------- -All students must replace or augment the contents of this Readme.md in a clear -manner with the following: - -* A brief description of the project and the specific features you implemented. -* At least one screenshot of your project running. -* A 30 second or longer video of your project running. To create the video you - can use http://www.microsoft.com/expression/products/Encoder4_Overview.aspx -* A performance evaluation (described in detail below). - -------------------------------------------------------------------------------- -PERFORMANCE EVALUATION -------------------------------------------------------------------------------- -The performance evaluation is where you will investigate how to make your -program more efficient using the skills you've learned in class. You must have -performed at least one experiment on your code to investigate the positive or -negative effects on performance. - -We encourage you to get creative with your tweaks. Consider places in your code -that could be considered bottlenecks and try to improve them. - -Each student should provide no more than a one page summary of their -optimizations along with tables and or graphs to visually explain any -performance differences. - -In this homework, we do not expect crazy performance evaluation in terms of -optimizations. However, it would be good to take performance benchmarks at -every step in this assignment to see how complicated fragment shaders affect the -overall speed. You can do this by using stats.js. - -------------------------------------------------------------------------------- -THIRD PARTY CODE POLICY -------------------------------------------------------------------------------- -* Use of any third-party code must be approved by asking on the Google groups. - If it is approved, all students are welcome to use it. Generally, we approve - use of third-party code that is not a core part of the project. For example, - for the ray tracer, we would approve using a third-party library for loading - models, but would not approve copying and pasting a CUDA function for doing - refraction. -* Third-party code must be credited in README.md. -* Using third-party code without its approval, including using another - student's code, is an academic integrity violation, and will result in you - receiving an F for the semester. - -------------------------------------------------------------------------------- -SELF-GRADING -------------------------------------------------------------------------------- -* On the submission date, email your grade, on a scale of 0 to 100, to Harmony, - harmoli+cis565@seas.upenn.com, with a one paragraph explanation. Be concise and - realistic. Recall that we reserve 30 points as a sanity check to adjust your - grade. Your actual grade will be (0.7 * your grade) + (0.3 * our grade). We - hope to only use this in extreme cases when your grade does not realistically - reflect your work - it is either too high or too low. In most cases, we plan - to give you the exact grade you suggest. -* Projects are not weighted evenly, e.g., Project 0 doesn't count as much as - the path tracer. We will determine the weighting at the end of the semester - based on the size of each project. - ---- -SUBMISSION ---- -As with the previous project, you should fork this project and work inside of -your fork. Upon completion, commit your finished project back to your fork, and -make a pull request to the master repository. You should include a README.md -file in the root directory detailing the following - -* A brief description of the project and specific features you implemented -* At least one screenshot of your project running. -* A link to a video of your project running. -* Instructions for building and running your project if they differ from the - base code. -* A performance writeup as detailed above. -* A list of all third-party code used. -* This Readme file edited as described above in the README section. +Distributed under the MIT License. See LICENSE file. + + https://github.com/ashima/webgl-noise diff --git a/assets/Thumbs.db b/assets/Thumbs.db new file mode 100644 index 0000000..0c2017f Binary files /dev/null and b/assets/Thumbs.db differ diff --git a/custom_vert_wave.html b/custom_vert_wave.html new file mode 100644 index 0000000..6ace5f1 --- /dev/null +++ b/custom_vert_wave.html @@ -0,0 +1,292 @@ + + + +Vertex Wave + + + + + +
+ + + + + + + + + + + + + + diff --git a/day1.jpg b/day1.jpg new file mode 100644 index 0000000..1a8b49f Binary files /dev/null and b/day1.jpg differ diff --git a/day2.jpg b/day2.jpg new file mode 100644 index 0000000..7ac4fe0 Binary files /dev/null and b/day2.jpg differ diff --git a/frag_globe.html b/frag_globe.html index e074492..387ffa1 100644 --- a/frag_globe.html +++ b/frag_globe.html @@ -1,15 +1,15 @@ -Fragment Globe +Globe Renderer +
- - + diff --git a/index.html b/index.html new file mode 100644 index 0000000..b14d051 --- /dev/null +++ b/index.html @@ -0,0 +1,232 @@ + + + +Fragment Globe + + + + + +
+ + + + + + + + + + + + diff --git a/js/frag_globe.js b/js/frag_globe.js index f37830d..436d42f 100644 --- a/js/frag_globe.js +++ b/js/frag_globe.js @@ -17,10 +17,15 @@ var message = document.getElementById("message"); var canvas = document.getElementById("canvas"); var gl = createWebGLContext(canvas, message); + + + if (!gl) { return; } - + var stats = new Stats(); + stats.setMode(1); + document.body.appendChild(stats.domElement); /////////////////////////////////////////////////////////////////////////// gl.viewport(0, 0, canvas.width, canvas.height); @@ -237,7 +242,7 @@ function animate() { /////////////////////////////////////////////////////////////////////////// // Update - + stats.update(); var model = mat4.create(); mat4.identity(model); mat4.rotate(model, 23.4/180*Math.PI, [0.0, 0.0, 1.0]); @@ -286,6 +291,7 @@ gl.activeTexture(gl.TEXTURE5); gl.bindTexture(gl.TEXTURE_2D, specTex); gl.uniform1i(u_EarthSpecLocation, 5); + gl.uniform1f(u_timeLocation, time); gl.drawElements(gl.TRIANGLES, numberOfIndices, gl.UNSIGNED_SHORT,0); time += 0.001; diff --git a/js/lib/Stats.js b/js/lib/Stats.js new file mode 100644 index 0000000..90b2a27 --- /dev/null +++ b/js/lib/Stats.js @@ -0,0 +1,149 @@ +/** + * @author mrdoob / http://mrdoob.com/ + */ + +var Stats = function () { + + var startTime = Date.now(), prevTime = startTime; + var ms = 0, msMin = Infinity, msMax = 0; + var fps = 0, fpsMin = Infinity, fpsMax = 0; + var frames = 0, mode = 0; + + var container = document.createElement( 'div' ); + container.id = 'stats'; + container.addEventListener( 'mousedown', function ( event ) { event.preventDefault(); setMode( ++ mode % 2 ) }, false ); + container.style.cssText = 'width:80px;opacity:0.9;cursor:pointer'; + + var fpsDiv = document.createElement( 'div' ); + fpsDiv.id = 'fps'; + fpsDiv.style.cssText = 'padding:0 0 3px 3px;text-align:left;background-color:#002'; + container.appendChild( fpsDiv ); + + var fpsText = document.createElement( 'div' ); + fpsText.id = 'fpsText'; + fpsText.style.cssText = 'color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px'; + fpsText.innerHTML = 'FPS'; + fpsDiv.appendChild( fpsText ); + + var fpsGraph = document.createElement( 'div' ); + fpsGraph.id = 'fpsGraph'; + fpsGraph.style.cssText = 'position:relative;width:74px;height:30px;background-color:#0ff'; + fpsDiv.appendChild( fpsGraph ); + + while ( fpsGraph.children.length < 74 ) { + + var bar = document.createElement( 'span' ); + bar.style.cssText = 'width:1px;height:30px;float:left;background-color:#113'; + fpsGraph.appendChild( bar ); + + } + + var msDiv = document.createElement( 'div' ); + msDiv.id = 'ms'; + msDiv.style.cssText = 'padding:0 0 3px 3px;text-align:left;background-color:#020;display:none'; + container.appendChild( msDiv ); + + var msText = document.createElement( 'div' ); + msText.id = 'msText'; + msText.style.cssText = 'color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px'; + msText.innerHTML = 'MS'; + msDiv.appendChild( msText ); + + var msGraph = document.createElement( 'div' ); + msGraph.id = 'msGraph'; + msGraph.style.cssText = 'position:relative;width:74px;height:30px;background-color:#0f0'; + msDiv.appendChild( msGraph ); + + while ( msGraph.children.length < 74 ) { + + var bar = document.createElement( 'span' ); + bar.style.cssText = 'width:1px;height:30px;float:left;background-color:#131'; + msGraph.appendChild( bar ); + + } + + var setMode = function ( value ) { + + mode = value; + + switch ( mode ) { + + case 0: + fpsDiv.style.display = 'block'; + msDiv.style.display = 'none'; + break; + case 1: + fpsDiv.style.display = 'none'; + msDiv.style.display = 'block'; + break; + } + + }; + + var updateGraph = function ( dom, value ) { + + var child = dom.appendChild( dom.firstChild ); + child.style.height = value + 'px'; + + }; + + return { + + REVISION: 12, + + domElement: container, + + setMode: setMode, + + begin: function () { + + startTime = Date.now(); + + }, + + end: function () { + + var time = Date.now(); + + ms = time - startTime; + msMin = Math.min( msMin, ms ); + msMax = Math.max( msMax, ms ); + + msText.textContent = ms + ' MS (' + msMin + '-' + msMax + ')'; + updateGraph( msGraph, Math.min( 30, 30 - ( ms / 200 ) * 30 ) ); + + frames ++; + + if ( time > prevTime + 1000 ) { + + fps = Math.round( ( frames * 1000 ) / ( time - prevTime ) ); + fpsMin = Math.min( fpsMin, fps ); + fpsMax = Math.max( fpsMax, fps ); + + fpsText.textContent = fps + ' FPS (' + fpsMin + '-' + fpsMax + ')'; + updateGraph( fpsGraph, Math.min( 30, 30 - ( fps / 100 ) * 30 ) ); + + prevTime = time; + frames = 0; + + } + + return time; + + }, + + update: function () { + + startTime = this.end(); + + } + + } + +}; + +if ( typeof module === 'object' ) { + + module.exports = Stats; + +} \ No newline at end of file diff --git a/js/lib/stats.min.js b/js/lib/stats.min.js new file mode 100644 index 0000000..68c673c --- /dev/null +++ b/js/lib/stats.min.js @@ -0,0 +1 @@ +var Stats=function(){var e=Date.now(),t=e,i=0,n=1/0,r=0,s=0,o=1/0,a=0,l=0,h=0,c=document.createElement("div");c.id="stats",c.addEventListener("mousedown",function(e){e.preventDefault(),v(++h%2)},!1),c.style.cssText="width:80px;opacity:0.9;cursor:pointer";var u=document.createElement("div");u.id="fps",u.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#002",c.appendChild(u);var d=document.createElement("div");d.id="fpsText",d.style.cssText="color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px",d.innerHTML="FPS",u.appendChild(d);var p=document.createElement("div");for(p.id="fpsGraph",p.style.cssText="position:relative;width:74px;height:30px;background-color:#0ff",u.appendChild(p);74>p.children.length;){var f=document.createElement("span");f.style.cssText="width:1px;height:30px;float:left;background-color:#113",p.appendChild(f)}var m=document.createElement("div");m.id="ms",m.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#020;display:none",c.appendChild(m);var g=document.createElement("div");g.id="msText",g.style.cssText="color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px",g.innerHTML="MS",m.appendChild(g);var y=document.createElement("div");for(y.id="msGraph",y.style.cssText="position:relative;width:74px;height:30px;background-color:#0f0",m.appendChild(y);74>y.children.length;){var f=document.createElement("span");f.style.cssText="width:1px;height:30px;float:left;background-color:#131",y.appendChild(f)}var v=function(e){switch(h=e){case 0:u.style.display="block",m.style.display="none";break;case 1:u.style.display="none",m.style.display="block"}},b=function(e,t){var i=e.appendChild(e.firstChild);i.style.height=t+"px"};return{REVISION:11,domElement:c,setMode:v,begin:function(){e=Date.now()},end:function(){var h=Date.now();return i=h-e,n=Math.min(n,i),r=Math.max(r,i),g.textContent=i+" MS ("+n+"-"+r+")",b(y,Math.min(30,30-30*(i/200))),l++,h>t+1e3&&(s=Math.round(1e3*l/(h-t)),o=Math.min(o,s),a=Math.max(a,s),d.textContent=s+" FPS ("+o+"-"+a+")",b(p,Math.min(30,30-30*(s/100))),t=h,l=0),h},update:function(){e=this.end()}}}; \ No newline at end of file diff --git a/midDay1.jpg b/midDay1.jpg new file mode 100644 index 0000000..51434fd Binary files /dev/null and b/midDay1.jpg differ diff --git a/resources/Thumbs.db b/resources/Thumbs.db new file mode 100644 index 0000000..64f05b5 Binary files /dev/null and b/resources/Thumbs.db differ diff --git a/seismic.jpg b/seismic.jpg new file mode 100644 index 0000000..c318c51 Binary files /dev/null and b/seismic.jpg differ diff --git a/vert_wave.html b/vert_wave.html index 5c7495b..847d008 100644 --- a/vert_wave.html +++ b/vert_wave.html @@ -17,26 +17,33 @@ attribute vec2 position; uniform mat4 u_modelViewPerspective; - - void main(void) - { - // NOTE : according to the WebGL standard, 0.0f is not accepted - float height = 0.0; + uniform float u_time; + uniform vec4 u_lowCol; + uniform vec4 u_highCol; - // NOTE : gl_Position is always a vec4 - gl_Position = u_modelViewPerspective * vec4(vec3(position, height), 1.0); + varying vec4 f_color; + + void main(void) + { + float frequency = 1.0; + float s_contrib = sin(frequency * position.x*2.0*3.14159 + u_time); + float t_contrib = cos(frequency * position.y*2.0*3.14159 + u_time); + float height = s_contrib*t_contrib; + + gl_Position = u_modelViewPerspective * vec4(vec3(position, height), 1.0); + f_color = mix(u_lowCol,u_highCol, (height + 1.0)/2.0); } @@ -45,8 +52,18 @@ var positionLocation = 0; var heightLocation = 1; var u_modelViewPerspectiveLocation; - var u_color; - + var u_lowColorLocation; + var u_highColorLocation; + var u_timeLocation; + + var colorController; + + + var lowCol = [0.0,1.0,0.0,1.0]; + var highCol = [0.0, 1.0, 0.0, 1.0]; + var time = 0.0; + var deltaT = 0.02; + var heights; var numberOfIndices; @@ -64,17 +81,46 @@ var persp = mat4.create(); var view = mat4.create(); - - // Function called when the window is loaded - window.onload = function() { - // Add GUI component - var gui = new dat.GUI(); - init(); - animate(); + var ColorControl = function () { + + this.minCol = [255,0,0,1]; + this.maxCol = [0, 0, 255,1]; + }; + window.onload = function () { + + colorController = new ColorControl(); + var gui = new dat.GUI(); + + gui.addColor(colorController, 'minCol').onChange(function() + { + for (var i = 0; i < 4; ++i) { + lowCol[i] = colorController.minCol[i]/255.0; + } + }); + + + gui.addColor(colorController, 'maxCol').onChange(function() + { + for (var i = 0; i < 4; ++i) { + highCol[i] = colorController.maxCol[i]/255.0; + } + }); + //init color + for (var i = 0; i < 4; ++i) { + lowCol[i] = colorController.minCol[i] / 255.0; + highCol[i] = colorController.maxCol[i] / 255.0; + } + + init(); + + animate(); + + }; + function init() { message = document.getElementById("message"); canvas = document.getElementById("canvas"); @@ -88,6 +134,7 @@ context.viewport(0, 0, canvas.width, canvas.height); context.clearColor(1.0, 1.0, 1.0, 1.0); context.enable(context.DEPTH_TEST); + mat4.perspective(45.0, 0.5, 0.1, 100.0, persp); @@ -98,7 +145,9 @@ } - function animate(){ + function animate() { + time += deltaT; + // Update var model = mat4.create(); mat4.identity(model); @@ -108,10 +157,16 @@ var mvp = mat4.create(); mat4.multiply(persp, mv, mvp); - // Render + // clear context.clear(context.COLOR_BUFFER_BIT | context.DEPTH_BUFFER_BIT); - context.uniformMatrix4fv(u_modelViewPerspectiveLocation, false, mvp); + //pass uniforms to shader + context.uniformMatrix4fv(u_modelViewPerspectiveLocation, false, mvp); + context.uniform1f(u_timeLocation, time); + context.uniform4fv(u_lowColorLocation, lowCol); + context.uniform4fv(u_highColorLocation, highCol); + + //render context.drawElements(context.LINES, numberOfIndices, context.UNSIGNED_SHORT,0); window.requestAnimFrame(animate); @@ -122,10 +177,14 @@ var vs = getShaderSource(document.getElementById("vs")); var fs = getShaderSource(document.getElementById("fs")); - var program = createProgram(context, vs, fs, message); - context.bindAttribLocation(program, positionLocation, "position"); - u_modelViewPerspectiveLocation = context.getUniformLocation(program,"u_modelViewPerspective"); - u_colorLocation = context.getUniformLocation(program, "u_color"); + var program = createProgram(context, vs, fs, message); + context.bindAttribLocation(program, positionLocation, "position"); + + //set up uniform locations + u_modelViewPerspectiveLocation = context.getUniformLocation(program,"u_modelViewPerspective"); + u_lowColorLocation = context.getUniformLocation(program, "u_lowCol"); + u_highColorLocation = context.getUniformLocation(program, "u_highCol"); + u_timeLocation = context.getUniformLocation(program, "u_time"); context.useProgram(program); }