diff --git a/README.md b/README.md index 06fcfd4..b4497e5 100644 --- a/README.md +++ b/README.md @@ -3,371 +3,139 @@ CIS565: Project 5: WebGL ------------------------------------------------------------------------------- Fall 2013 ------------------------------------------------------------------------------- -Due Friday 11/08/2013 +Qiong Wang ------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -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. +This is a webGL based project for CIS 565 GPU Programming. +In this project, some beautiful animations were made and can be seen directly from anywhere throught internet. +There is no need for specific graphics card, and all the following contents were done through general intel graphics card. -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 Project4 root directory contains the following subdirectories: - -* part1/ contains the base code for the Wave Vertex Shader. -* part2/ contains the base code for the Globe Fragment Shader. -* resources/ contains the screenshots found in this readme file. +In the first part, the simulation is about different kinds of waves. +The second part is about the rotating globe with some fantastic features such as bumping, moving clouds, rim lighting, etc. ------------------------------------------------------------------------------- -PART 1 REQUIREMENTS: +FEATURES IMPLEMENTED ------------------------------------------------------------------------------- +###**PART 1** -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: +Features: * A sin-wave based vertex shader: - -![Example sin wave grid](resources/sinWaveGrid.png) - * A simplex noise based vertex shader: +* One interesting vertex shader: *Aladdin's Magic carpet* -![Example simplex noise wave grid](resources/oceanWave.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`. - -* 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()`. - -**Simplex Wave** - -* Now that you have the sin wave working, create a new copy of `index.html`. - Call it `index_simplex.html`, or something similar. -* Open up `simplex.vert`, which contains a compact GLSL simplex noise - implementation, in a text editor. Copy and paste the functions included - inside into your `index_simplex.html`'s vertex shader. -* Try changing s_contrib and t_contrib to use simplex noise instead of sin/cos - functions with the following code: - -```glsl -vec2 simplexVec = vec2(u_time, position); -float s_contrib = snoise(simplexVec); -float t_contrib = snoise(vec2(s_contrib,u_time)); -``` - -**Wave Of Your Choice** - -* 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. - -------------------------------------------------------------------------------- -PART 2 REQUIREMENTS: -------------------------------------------------------------------------------- -In Part 2, you are given code for: - -* 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 - -You are required to implement: +###**PART 2** +Basic Features: * Bump mapped terrain * Rim lighting to simulate atmosphere * Night-time lights on the dark side of the globe * Specular mapping * Moving clouds -You are also required to pick one open-ended effect to implement: - +Optional features: * 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 - -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. - -Some examples of what your completed globe renderer will look like: - -![Completed globe, day side](resources/globe_day.png) - -Figure 0. Completed globe renderer, daylight side. - -![Completed globe, twilight](resources/globe_twilight.png) - -Figure 1. Completed globe renderer, twilight border. - -![Completed globe, night side](resources/globe_night.png) - -Figure 2. Completed globe renderer, night side. +* Orbiting Moon with texture mapping with Bump mapped terrain +* Draw a skybox around the entire scene for the stars (continue debugging) ------------------------------------------------------------------------------- -PART 2 WALKTHROUGH: +RESULTS OF PART 1 ------------------------------------------------------------------------------- +Please click the images to see the animation :) -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. - -![Initial globe](resources/globe_initial.png) - -Figure 3. Initial globe with diffuse and specular lighting. - -**Night Lights** - -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: - -```glsl -float gammaCorrect = 1/1.2; -vec4 nightColor = pow(texture2D(u_Night, v_Texcoord), vec4(gammaCorrect)); -``` - -Feel free to play with gamma correcting the night and day textures if you -wish. Find values that you think look nice! - -![Day/Night without specular mapping](resources/globe_nospecmap.png) - -Figure 4. Globe with night lights and day/night blending at dusk/dawn. +**Sin Wave** -**Specular Map** +[![Sin Wave](https://raw.github.com/GabriellaQiong/Project5-WebGL/master/basic_wave.png)](http://gabriellaqiong.github.io/Project5-WebGL/part1/index.html) -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. -![Day/Night with specular mapping](resources/globe_specmap.png) +**Simplex Noise** -Figure 5. Globe with specular map. Compare to Figure 4. Here, the specular -component is not used when shading the land. +[![Simplex Noise](https://raw.github.com/GabriellaQiong/Project5-WebGL/master/simplex_wave.png)](http://gabriellaqiong.github.io/Project5-WebGL/part1/index_simplex.html) -**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. +**Aladdin's Magic Carpet** -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. +[![Aladdin's carpet](https://raw.github.com/GabriellaQiong/Project5-WebGL/master/magic_carpet.png)](http://gabriellaqiong.github.io/Project5-WebGL/part1/index_custom.html) -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) +------------------------------------------------------------------------------- +RESULTS OF PART 2 +------------------------------------------------------------------------------- +**Moon with Bumping** -Figure 6. Clouds with day time shading. +![moon](https://raw.github.com/GabriellaQiong/Project5-WebGL/master/moon_bump.png) -![Night with clouds](resources/globe_nightcloud.png) +Please click the image below to see the animation :) -Figure 7. Clouds observing city nights on the dark side of the globe. +**Virtual Globe with Moon** +[![globe](https://raw.github.com/GabriellaQiong/Project5-WebGL/master/globe_moon_water.png)](http://gabriellaqiong.github.io/Project5-WebGL/part2/index.html) -**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: +------------------------------------------------------------------------------- +PERFORMANCE EVALUATION +------------------------------------------------------------------------------- +In the performance evaluation part, I used the JavaScript Performance Monitor library: https://github.com/mrdoob/stats.js -`normalize(vec3(center - right, center - top, 0.2))` +This class provides a simple info box that will help you monitor your code performance. -Use `eastNorthUpToEyeCoordinates` to transform this normal to eye coordinates, -normalize it, then use it for diffuse lighting the ground instead of the -original normal. +* **FPS** Frames rendered in the last second. The higher the number the better. +* **MS** Milliseconds needed to render a frame. The lower the number the better. -![Globe with bump mapping](resources/globe_bumpmap.png) +### Screenshots ### -Figure 8. Bump mapping brings attention to mountains. +![stats_js_fps.png](http://mrdoob.github.com/stats.js/assets/stats_js_fps.png) +![stats_js_ms.png](http://mrdoob.github.com/stats.js/assets/stats_js_ms.png) -**Rim Lighting** +We need to add the following codes in the javascript. +```javascript +var stats = new Stats(); +stats.setMode(1); // 0: fps, 1: ms -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. +// Align top-left +stats.domElement.style.position = 'absolute'; +stats.domElement.style.left = '0px'; +stats.domElement.style.top = '0px'; -For more information on rim lighting, -read http://www.fundza.com/rman_shaders/surface/fake_rim/fake_rim1.html. +document.body.appendChild( stats.domElement ); -------------------------------------------------------------------------------- -GH-PAGES -------------------------------------------------------------------------------- -Since this assignment is in WebGL you will make your project easily viewable by -taking advantage of GitHub's project pages feature. +setInterval( function () { -Once you are done you will need to create a new branch named gh-pages: + stats.begin(); -`git branch gh-pages` + // animation codes -Switch to your new branch: + stats.end(); -`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 +}, 1000 / 60 ); +``` -`.github.io/` +The upper instructions are from Mr. doob's github. After adding the codes of animation as this, we can have -to see your beautiful globe from anywhere. +![eval](https://raw.github.com/GabriellaQiong/Project5-WebGL/master/performance_eval.png) -------------------------------------------------------------------------------- -README -------------------------------------------------------------------------------- -All students must replace or augment the contents of this Readme.md in a clear -manner with the following: +However, the actual framerate is definitely higher than that when using the monitor and the animation with the monitor code is not smooth playing. In the final demo, I removed the evaluation part in the html file. -* 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). +Instead, I used one [bookmarklet](http://ricardocabello.com/blog/post/707). With the help from this monitor, I can get the following result: -------------------------------------------------------------------------------- -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. +| features | approximate fps | +|:---------------------------------------------------------------------:|:-----------------:| +| globe with clouds, running water, day night, rim lighting, etc | 58 ~ 60 | +| adding general moon | 57 ~ 60 | +| adding bumped moon | 57 ~ 60 | +| simplex wave | 59 ~ 60 | -We encourage you to get creative with your tweaks. Consider places in your code -that could be considered bottlenecks and try to improve them. +They are not quite different from each other in this case. -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. ------------------------------------------------------------------------------- -THIRD PARTY CODE POLICY +THIRD PARTY CODE ------------------------------------------------------------------------------- -* 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. +JavaScript Performance Monitor library: The MIT License, Copyright (c) 2009-2012 Mr.doob ------------------------------------------------------------------------------- -SELF-GRADING +ACKNOWLEDGEMENT ------------------------------------------------------------------------------- -* On the submission date, email your grade, on a scale of 0 to 100, to Liam, - liamboone@gmail.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. +Thanks a lot to Patrick and Liam for the preparation of this project. Thank you :) diff --git a/basic_globe.png b/basic_globe.png new file mode 100644 index 0000000..dd686ef Binary files /dev/null and b/basic_globe.png differ diff --git a/basic_wave.png b/basic_wave.png new file mode 100644 index 0000000..7052387 Binary files /dev/null and b/basic_wave.png differ diff --git a/globe_moon.png b/globe_moon.png new file mode 100644 index 0000000..635ba4b Binary files /dev/null and b/globe_moon.png differ diff --git a/globe_moon_water.png b/globe_moon_water.png new file mode 100644 index 0000000..4f40740 Binary files /dev/null and b/globe_moon_water.png differ diff --git a/magic_carpet.png b/magic_carpet.png new file mode 100644 index 0000000..d3c9142 Binary files /dev/null and b/magic_carpet.png differ diff --git a/moon_bump.png b/moon_bump.png new file mode 100644 index 0000000..718af48 Binary files /dev/null and b/moon_bump.png differ diff --git a/part1/index.html b/part1/index.html new file mode 100644 index 0000000..3f4d954 --- /dev/null +++ b/part1/index.html @@ -0,0 +1,59 @@ + + + +Vertex Wave + + + + + +
+ + + + + + + + + + + + diff --git a/part1/index_custom.html b/part1/index_custom.html new file mode 100644 index 0000000..28e34d8 --- /dev/null +++ b/part1/index_custom.html @@ -0,0 +1,104 @@ + + + +Vertex Wave + + + + + +
+ + + + + + + + + + + + diff --git a/part1/index_custom.js b/part1/index_custom.js new file mode 100644 index 0000000..972005d --- /dev/null +++ b/part1/index_custom.js @@ -0,0 +1,168 @@ +(function() { + "use strict"; + /*global window,document,Float32Array,Uint16Array,mat4,vec3,snoise*/ + /*global getShaderSource,createWebGLContext,createProgram*/ + + var NUM_WIDTH_PTS = 100; + var NUM_HEIGHT_PTS = 100; + + var message = document.getElementById("message"); + var canvas = document.getElementById("canvas"); + var context = createWebGLContext(canvas, message); + if (!context) { + return; + } + + /////////////////////////////////////////////////////////////////////////// + + context.viewport(0, 0, canvas.width, canvas.height); + context.clearColor(1.0, 1.0, 1.0, 1.0); + context.enable(context.DEPTH_TEST); + + var persp = mat4.create(); + mat4.perspective(45.0, 0.5, 0.1, 100.0, persp); + + var eye = [2.0, 1.0, 3.0]; + var center = [0.0, 0.0, 0.0]; + var up = [0.0, 0.0, 1.0]; + var view = mat4.create(); + mat4.lookAt(eye, center, up, view); + + var positionLocation = 0; + var heightLocation = 1; + var u_modelViewPerspectiveLocation; + + // Initialize the u_timeLocation and time in float + var u_timeLocation; + var time = 0.0; + + (function initializeShader() { + var program; + 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"); + + // Query the location of u_time + u_timeLocation = context.getUniformLocation(program, "u_time"); + + context.useProgram(program); + })(); + + var heights; + var numberOfIndices; + + (function initializeGrid() { + function uploadMesh(positions, heights, indices) { + // Positions + var positionsName = context.createBuffer(); + context.bindBuffer(context.ARRAY_BUFFER, positionsName); + context.bufferData(context.ARRAY_BUFFER, positions, context.STATIC_DRAW); + context.vertexAttribPointer(positionLocation, 2, context.FLOAT, false, 0, 0); + context.enableVertexAttribArray(positionLocation); + + if (heights) + { + // Heights + var heightsName = context.createBuffer(); + context.bindBuffer(context.ARRAY_BUFFER, heightsName); + context.bufferData(context.ARRAY_BUFFER, heights.length * heights.BYTES_PER_ELEMENT, context.STREAM_DRAW); + context.vertexAttribPointer(heightLocation, 1, context.FLOAT, false, 0, 0); + context.enableVertexAttribArray(heightLocation); + } + + // Indices + var indicesName = context.createBuffer(); + context.bindBuffer(context.ELEMENT_ARRAY_BUFFER, indicesName); + context.bufferData(context.ELEMENT_ARRAY_BUFFER, indices, context.STATIC_DRAW); + } + + var WIDTH_DIVISIONS = NUM_WIDTH_PTS - 1; + var HEIGHT_DIVISIONS = NUM_HEIGHT_PTS - 1; + + var numberOfPositions = NUM_WIDTH_PTS * NUM_HEIGHT_PTS; + + var positions = new Float32Array(2 * numberOfPositions); + var indices = new Uint16Array(2 * ((NUM_HEIGHT_PTS * (NUM_WIDTH_PTS - 1)) + (NUM_WIDTH_PTS * (NUM_HEIGHT_PTS - 1)))); + + var positionsIndex = 0; + var indicesIndex = 0; + var length; + + for (var j = 0; j < NUM_WIDTH_PTS; ++j) + { + positions[positionsIndex++] = j /(NUM_WIDTH_PTS - 1); + positions[positionsIndex++] = 0.0; + + if (j>=1) + { + length = positionsIndex / 2; + indices[indicesIndex++] = length - 2; + indices[indicesIndex++] = length - 1; + } + } + + for (var i = 0; i < HEIGHT_DIVISIONS; ++i) + { + var v = (i + 1) / (NUM_HEIGHT_PTS - 1); + positions[positionsIndex++] = 0.0; + positions[positionsIndex++] = v; + + length = (positionsIndex / 2); + indices[indicesIndex++] = length - 1; + indices[indicesIndex++] = length - 1 - NUM_WIDTH_PTS; + + for (var k = 0; k < WIDTH_DIVISIONS; ++k) + { + positions[positionsIndex++] = (k + 1) / (NUM_WIDTH_PTS - 1); + positions[positionsIndex++] = v; + + length = positionsIndex / 2; + var new_pt = length - 1; + indices[indicesIndex++] = new_pt - 1; // Previous side + indices[indicesIndex++] = new_pt; + + indices[indicesIndex++] = new_pt - NUM_WIDTH_PTS; // Previous bottom + indices[indicesIndex++] = new_pt; + } + } + + uploadMesh(positions, heights, indices); + numberOfIndices = indices.length; + })(); + + // Initialize angle incremental + var theta = 0.0; + + (function animate(){ + /////////////////////////////////////////////////////////////////////////// + // Update + + var model = mat4.create(); + mat4.identity(model); + // Add rotation and new translation + theta += 1.0 / 180.0; + mat4.translate(model, [-0.5, -0.5, 2.0 * Math.cos(Math.PI * theta) - 1.0]); + mat4.rotate(model, Math.PI * theta, [0.0, 0.0, 1.0]); + var mv = mat4.create(); + mat4.multiply(view, model, mv); + var mvp = mat4.create(); + mat4.multiply(persp, mv, mvp); + + // Increase time in every animation step and set the uniform value + time += 0.01; + context.uniform1f(u_timeLocation, time); + + /////////////////////////////////////////////////////////////////////////// + // Render + context.clear(context.COLOR_BUFFER_BIT | context.DEPTH_BUFFER_BIT); + + context.uniformMatrix4fv(u_modelViewPerspectiveLocation, false, mvp); + context.drawElements(context.LINES, numberOfIndices, context.UNSIGNED_SHORT,0); + + window.requestAnimFrame(animate); + })(); + +}()); diff --git a/part1/index_simplex.html b/part1/index_simplex.html new file mode 100644 index 0000000..fe76090 --- /dev/null +++ b/part1/index_simplex.html @@ -0,0 +1,99 @@ + + + +Vertex Wave + + + + + +
+ + + + + + + + + + + + diff --git a/part1/vert_wave.html b/part1/vert_wave.html index 57107ca..3f4d954 100644 --- a/part1/vert_wave.html +++ b/part1/vert_wave.html @@ -15,19 +15,39 @@ uniform mat4 u_modelViewPerspective; + // Add uniform time + uniform float u_time; + + // Bounded colors + const vec3 minColor = vec3(1.0, 0.2, 0.0); + const vec3 maxColor = vec3(0.0, 0.8, 1.0); + + // Color for fragment shader. Note: varying variable need to be called both in vs and fs + varying vec3 color; + void main(void) { - float height = 0.0; + // Pass sinuoidal wave to the height + 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; + + // Assign height value for the color + color = mix(minColor, maxColor, height); + gl_Position = u_modelViewPerspective * vec4(vec3(position, height), 1.0); } diff --git a/part1/vert_wave.js b/part1/vert_wave.js index b90b9cf..847ccb8 100644 --- a/part1/vert_wave.js +++ b/part1/vert_wave.js @@ -32,6 +32,10 @@ var heightLocation = 1; var u_modelViewPerspectiveLocation; + // Initialize the u_timeLocation and time in float + var u_timeLocation; + var time = 0.0; + (function initializeShader() { var program; var vs = getShaderSource(document.getElementById("vs")); @@ -41,6 +45,9 @@ context.bindAttribLocation(program, positionLocation, "position"); u_modelViewPerspectiveLocation = context.getUniformLocation(program,"u_modelViewPerspective"); + // Query the location of u_time + u_timeLocation = context.getUniformLocation(program, "u_time"); + context.useProgram(program); })(); @@ -125,7 +132,7 @@ uploadMesh(positions, heights, indices); numberOfIndices = indices.length; })(); - + (function animate(){ /////////////////////////////////////////////////////////////////////////// // Update @@ -137,6 +144,10 @@ mat4.multiply(view, model, mv); var mvp = mat4.create(); mat4.multiply(persp, mv, mvp); + + // Increase time in every animation step and set the uniform value + time += 0.01; + context.uniform1f(u_timeLocation, time); /////////////////////////////////////////////////////////////////////////// // Render diff --git a/part2/frag_globe.html b/part2/frag_globe.html index 6aa5609..95f8daf 100644 --- a/part2/frag_globe.html +++ b/part2/frag_globe.html @@ -8,7 +8,7 @@
- + + + + + + + + + diff --git a/part2/frag_globe.html~ b/part2/frag_globe.html~ new file mode 100644 index 0000000..13b49b6 --- /dev/null +++ b/part2/frag_globe.html~ @@ -0,0 +1,322 @@ + + + +Fragment Globe + + + + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/part2/frag_globe.js b/part2/frag_globe.js index 1d8a877..d61a2a5 100644 --- a/part2/frag_globe.js +++ b/part2/frag_globe.js @@ -55,12 +55,37 @@ var u_EarthSpecLocation; var u_BumpLocation; var u_timeLocation; + + var u_MoonLocation; + var positionMoonLocation; + var normalMoonLocation; + var texCoordMoonLocation; + var u_ModelMoonLocation; + var u_InvTransMoonLocation; + var u_ModelMoonLocation; + var u_ViewMoonLocation; + var u_PerspMoonLocation; + var u_CameraSpaceDirLightMoonLocation; + var u_BumpMoonLocation; + + var u_BGLocation; + var normalBGLocation; + var texCoordBGLocation; + var positionBGLocation; + var u_ModelBGLocation; + var u_ViewBGLocation; + var u_PerspBGLocation; + var u_InvTransBGLocation; + + var program; + var program_moon; + var program_starField; (function initializeShader() { var vs = getShaderSource(document.getElementById("vs")); var fs = getShaderSource(document.getElementById("fs")); - var program = createProgram(gl, vs, fs, message); + program = createProgram(gl, vs, fs, message); positionLocation = gl.getAttribLocation(program, "Position"); normalLocation = gl.getAttribLocation(program, "Normal"); texCoordLocation = gl.getAttribLocation(program, "Texcoord"); @@ -77,15 +102,45 @@ u_timeLocation = gl.getUniformLocation(program,"u_time"); u_CameraSpaceDirLightLocation = gl.getUniformLocation(program,"u_CameraSpaceDirLight"); - gl.useProgram(program); - })(); - - var dayTex = gl.createTexture(); - var bumpTex = gl.createTexture(); - var cloudTex = gl.createTexture(); - var transTex = gl.createTexture(); - var lightTex = gl.createTexture(); - var specTex = gl.createTexture(); + var moon_vs = getShaderSource(document.getElementById("moon_vs")); + var moon_fs = getShaderSource(document.getElementById("moon_fs")); + + program_moon = createProgram(gl, moon_vs, moon_fs, message); + positionMoonLocation = gl.getAttribLocation(program_moon, "PositionMoon"); + normalMoonLocation = gl.getAttribLocation(program_moon, "NormalMoon"); + texCoordMoonLocation = gl.getAttribLocation(program_moon, "TexcoordMoon"); + u_ModelMoonLocation = gl.getUniformLocation(program_moon,"u_ModelMoon"); + u_ViewMoonLocation = gl.getUniformLocation(program_moon,"u_View"); + u_PerspMoonLocation = gl.getUniformLocation(program_moon,"u_Persp"); + u_InvTransMoonLocation = gl.getUniformLocation(program_moon,"u_InvTrans"); + u_CameraSpaceDirLightMoonLocation = gl.getUniformLocation(program_moon,"u_CameraSpaceDirLight"); + u_MoonLocation = gl.getUniformLocation(program_moon, "u_Moon"); + u_BumpMoonLocation = gl.getUniformLocation(program_moon, "u_BumpMoon"); + + var vs_bg = getShaderSource(document.getElementById("vs_bg")); + var fs_bg = getShaderSource(document.getElementById("fs_bg")); + + program_starField = createProgram(gl, vs_bg, fs_bg, message); + u_BGLocation = gl.getUniformLocation(program_starField, "u_bg"); + texCoordBGLocation = gl.getAttribLocation(program_starField, "TexcoordBG"); + normalBGLocation = gl.getAttribLocation(program_starField, "NormalBG"); + positionBGLocation = gl.getAttribLocation(program_starField, "PositionBG"); + u_ModelBGLocation = gl.getUniformLocation(program_starField,"u_Model"); + u_ViewBGLocation = gl.getUniformLocation(program_starField,"u_View"); + u_PerspBGLocation = gl.getUniformLocation(program_starField,"u_Persp"); + u_InvTransBGLocation = gl.getUniformLocation(program_starField,"u_InvTrans"); + + })(); + + var dayTex = gl.createTexture(); + var bumpTex = gl.createTexture(); + var cloudTex = gl.createTexture(); + var transTex = gl.createTexture(); + var lightTex = gl.createTexture(); + var specTex = gl.createTexture(); + var moonTex = gl.createTexture(); + var moonBumpTex = gl.createTexture(); + var starFieldTex = gl.createTexture(); function initLoadedTexture(texture){ gl.bindTexture(gl.TEXTURE_2D, texture); @@ -93,6 +148,8 @@ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); gl.bindTexture(gl.TEXTURE_2D, null); @@ -128,7 +185,6 @@ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesName); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW); } - var WIDTH_DIVISIONS = NUM_WIDTH_PTS - 1; var HEIGHT_DIVISIONS = NUM_HEIGHT_PTS - 1; @@ -174,6 +230,83 @@ uploadMesh(positions, texCoords, indices); numberOfIndices = indicesIndex; })(); + + /* + var numberOfIndicesBG; + + (function initializeBG() { + function uploadMesh(positions, texCoords, indices) { + // Positions + var positionsName = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, positionsName); + gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW); + gl.vertexAttribPointer(positionBGLocation, 3, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(positionBGLocation); + + // Normals + var normalsName = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, normalsName); + gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW); + gl.vertexAttribPointer(normalBGLocation, 3, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(normalBGLocation); + + // TextureCoords + var texCoordsName = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, texCoordsName); + gl.bufferData(gl.ARRAY_BUFFER, texCoords, gl.STATIC_DRAW); + gl.vertexAttribPointer(texCoordBGLocation, 2, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(texCoordBGLocation); + + // Indices + var indicesName = gl.createBuffer(); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesName); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW); + } + + var numberOfPositionsBG = 4; + + var positionsBG = new Float32Array(3 * numberOfPositionsBG); + var texCoordsBG = new Float32Array(2 * numberOfPositionsBG); + var indicesBG = new Uint16Array(6); + + var positionsIdx = 0; + var texCoordsIdx = 0; + var indicesIdx = 0; + + positionsBG[positionsIdx++] = 0.0; + positionsBG[positionsIdx++] = 0.0; + positionsBG[positionsIdx++] = 1.0; + texCoordsBG[texCoordsIdx++] = 1.0; + texCoordsBG[texCoordsIdx++] = 0.0; + + positionsBG[positionsIdx++] = 1.0; + positionsBG[positionsIdx++] = 0.0; + positionsBG[positionsIdx++] = 1.0; + texCoordsBG[texCoordsIdx++] = 1.0; + texCoordsBG[texCoordsIdx++] = 1.0; + + positionsBG[positionsIdx++] = 1.0; + positionsBG[positionsIdx++] = 1.0; + positionsBG[positionsIdx++] = 1.0; + texCoordsBG[texCoordsIdx++] = 0.0; + texCoordsBG[texCoordsIdx++] = 1.0; + + positionsBG[positionsIdx++] = 0.0; + positionsBG[positionsIdx++] = 1.0; + positionsBG[positionsIdx++] = 1.0; + texCoordsBG[texCoordsIdx++] = 0.0; + texCoordsBG[texCoordsIdx++] = 0.0; + + indicesBG[indicesIdx++] = 0; + indicesBG[indicesIdx++] = 1; + indicesBG[indicesIdx++] = 2; + indicesBG[indicesIdx++] = 3; + indicesBG[indicesIdx++] = 0; + indicesBG[indicesIdx++] = 2; + + uploadMesh(positionsBG, texCoordsBG, indicesBG); + numberOfIndicesBG = indicesIdx; + })();*/ var time = 0; var mouseLeftDown = false; @@ -233,16 +366,15 @@ document.onmouseup = handleMouseUp; document.onmousemove = handleMouseMove; - function animate() { /////////////////////////////////////////////////////////////////////////// // Update - var model = mat4.create(); mat4.identity(model); mat4.rotate(model, 23.4/180*Math.PI, [0.0, 0.0, 1.0]); mat4.rotate(model, Math.PI, [1.0, 0.0, 0.0]); mat4.rotate(model, -time, [0.0, 1.0, 0.0]); + var mv = mat4.create(); mat4.multiply(view, model, mv); @@ -250,7 +382,7 @@ mat4.inverse(mv, invTrans); mat4.transpose(invTrans); - var lightdir = vec3.create([1.0, 0.0, 1.0]); + var lightdir = vec3.create([0.0, 0.0, 1.0]); var lightdest = vec4.create(); vec3.normalize(lightdir); mat4.multiplyVec4(view, [lightdir[0], lightdir[1], lightdir[2], 0.0], lightdest); @@ -261,11 +393,33 @@ // Render gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + /* + var model_star = model; + mat4.scale(model_star, [100.0, 100.0, 100.0]); + + // Star Field Program + gl.useProgram(program_starField); + + gl.uniformMatrix4fv(u_ModelBGLocation, false, model_star); + gl.uniformMatrix4fv(u_ViewBGLocation, false, view); + gl.uniformMatrix4fv(u_PerspBGLocation, false, persp); + gl.uniformMatrix4fv(u_InvTransBGLocation, false, invTrans); + + gl.activeTexture(gl.TEXTURE8); + gl.bindTexture(gl.TEXTURE_2D, starFieldTex); + gl.uniform1i(u_BGLocation, 8); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT,0); + */ + + gl.useProgram(program); + + time += 0.001; + gl.uniform1f(u_timeLocation, time); + gl.uniformMatrix4fv(u_ModelLocation, false, model); gl.uniformMatrix4fv(u_ViewLocation, false, view); gl.uniformMatrix4fv(u_PerspLocation, false, persp); gl.uniformMatrix4fv(u_InvTransLocation, false, invTrans); - gl.uniform3fv(u_CameraSpaceDirLightLocation, lightdir); gl.activeTexture(gl.TEXTURE0); @@ -288,20 +442,68 @@ gl.uniform1i(u_EarthSpecLocation, 5); gl.drawElements(gl.TRIANGLES, numberOfIndices, gl.UNSIGNED_SHORT,0); - time += 0.001; - window.requestAnimFrame(animate); - } + // Start moon program + gl.useProgram(program_moon); + + // Moon transformation + var model_moon = mat4.create(); + mat4.identity(model_moon); + mat4.rotate(model_moon, 23.4/180*Math.PI, [0.0, 0.0, 1.0]); + mat4.rotate(model_moon, Math.PI, [1.0, 0.0, 0.0]); + mat4.rotate(model_moon, -2.3 * time, [0.0, 1.0, 0.0]); + mat4.translate(model_moon, [-2.0, 0.0, 0.0]); + mat4.scale(model_moon, [0.2, 0.2, 0.2]); + mat4.rotate(model_moon,-0.01 * time, [0.0, 1.0, 0.0]); + + var mv_moon = mat4.create(); + mat4.multiply(view, model_moon, mv_moon); + + var invTrans_moon = mat4.create(); + mat4.inverse(mv_moon, invTrans_moon); + mat4.transpose(invTrans_moon); + + gl.uniformMatrix4fv(u_ModelMoonLocation, false, model_moon); + gl.uniformMatrix4fv(u_ViewMoonLocation, false, view); + gl.uniformMatrix4fv(u_PerspMoonLocation, false, persp); + gl.uniformMatrix4fv(u_InvTransMoonLocation, false, invTrans_moon); + gl.uniform3fv(u_CameraSpaceDirLightMoonLocation, lightdir); + + // Moon texture activation and draw + gl.activeTexture(gl.TEXTURE6); + gl.bindTexture(gl.TEXTURE_2D, moonTex); + gl.uniform1i(u_MoonLocation, 6); + gl.activeTexture(gl.TEXTURE7); + gl.bindTexture(gl.TEXTURE_2D, moonBumpTex); + gl.uniform1i(u_BumpMoonLocation, 7); + gl.drawElements(gl.TRIANGLES, numberOfIndices, gl.UNSIGNED_SHORT,0); + window.requestAnimFrame(animate); + } + var textureCount = 0; function initializeTexture(texture, src) { texture.image = new Image(); texture.image.onload = function() { - initLoadedTexture(texture); - - // Animate once textures load. - if (++textureCount === 6) { - animate(); + initLoadedTexture(texture); + + // Animate once textures load. + if (++textureCount === 9) { + /* + var stats = new Stats(); + stats.setMode(0); // 0: fps, 1: ms + + // Align top-left + stats.domElement.style.position = 'absolute'; + stats.domElement.style.left = '0px'; + stats.domElement.style.top = '0px'; + + document.body.appendChild( stats.domElement ); + setInterval( function () { + sats.begin();*/ + animate(); + /* stats.end(); + }, 100 );*/ } } texture.image.src = src; @@ -313,4 +515,7 @@ initializeTexture(transTex, "earthtrans1024.png"); initializeTexture(lightTex, "earthlight1024.png"); initializeTexture(specTex, "earthspec1024.png"); + initializeTexture(moonTex, "moon1024.jpg"); + initializeTexture(moonBumpTex, "moonBump1024.jpg"); + initializeTexture(starFieldTex, "starField1024.jpg"); }()); diff --git a/part2/frag_globe.js~ b/part2/frag_globe.js~ new file mode 100644 index 0000000..fd18d34 --- /dev/null +++ b/part2/frag_globe.js~ @@ -0,0 +1,429 @@ +(function() { + "use strict"; + /*global window,document,Float32Array,Uint16Array,mat4,vec3,snoise*/ + /*global getShaderSource,createWebGLContext,createProgram*/ + + function sphericalToCartesian( r, a, e ) { + var x = r * Math.cos(e) * Math.cos(a); + var y = r * Math.sin(e); + var z = r * Math.cos(e) * Math.sin(a); + + return [x,y,z]; + } + + var NUM_WIDTH_PTS = 64; + var NUM_HEIGHT_PTS = 64; + + var message = document.getElementById("message"); + var canvas = document.getElementById("canvas"); + var gl = createWebGLContext(canvas, message); + if (!gl) { + return; + } + + /////////////////////////////////////////////////////////////////////////// + + gl.viewport(0, 0, canvas.width, canvas.height); + gl.clearColor(0.0, 0.0, 0.0, 1.0); + gl.enable(gl.DEPTH_TEST); + + var persp = mat4.create(); + mat4.perspective(45.0, canvas.width/canvas.height, 0.1, 100.0, persp); + + var radius = 5.0; + var azimuth = Math.PI; + var elevation = 0.0001; + + var eye = sphericalToCartesian(radius, azimuth, elevation); + var center = [0.0, 0.0, 0.0]; + var up = [0.0, 1.0, 0.0]; + var view = mat4.create(); + mat4.lookAt(eye, center, up, view); + + var positionLocation; + var normalLocation; + var texCoordLocation; + var u_InvTransLocation; + var u_ModelLocation; + var u_ViewLocation; + var u_PerspLocation; + var u_CameraSpaceDirLightLocation; + var u_DayDiffuseLocation; + var u_NightLocation; + var u_CloudLocation; + var u_CloudTransLocation; + var u_EarthSpecLocation; + var u_BumpLocation; + var u_timeLocation; + + var u_MoonLocation; + var positionMoonLocation; + var normalMoonLocation; + var texCoordMoonLocation; + var u_ModelMoonLocation; + var u_InvTransMoonLocation; + var u_ModelMoonLocation; + var u_ViewMoonLocation; + var u_PerspMoonLocation; + var u_CameraSpaceDirLightMoonLocation; + var u_BumpMoonLocation; + + var u_BGLocation; + var texCoordBGLocation; + var positionBGLocation; + var u_ModelBGLocation; + var u_ViewBGLocation; + var u_PerspBGLocation; + var u_InvTransBGLocation; + + var program; + var program_moon; + var program_starField; + + (function initializeShader() { + var vs = getShaderSource(document.getElementById("vs")); + var fs = getShaderSource(document.getElementById("fs")); + + program = createProgram(gl, vs, fs, message); + positionLocation = gl.getAttribLocation(program, "Position"); + normalLocation = gl.getAttribLocation(program, "Normal"); + texCoordLocation = gl.getAttribLocation(program, "Texcoord"); + u_ModelLocation = gl.getUniformLocation(program,"u_Model"); + u_ViewLocation = gl.getUniformLocation(program,"u_View"); + u_PerspLocation = gl.getUniformLocation(program,"u_Persp"); + u_InvTransLocation = gl.getUniformLocation(program,"u_InvTrans"); + u_DayDiffuseLocation = gl.getUniformLocation(program,"u_DayDiffuse"); + u_NightLocation = gl.getUniformLocation(program,"u_Night"); + u_CloudLocation = gl.getUniformLocation(program,"u_Cloud"); + u_CloudTransLocation = gl.getUniformLocation(program,"u_CloudTrans"); + u_EarthSpecLocation = gl.getUniformLocation(program,"u_EarthSpec"); + u_BumpLocation = gl.getUniformLocation(program,"u_Bump"); + u_timeLocation = gl.getUniformLocation(program,"u_time"); + u_CameraSpaceDirLightLocation = gl.getUniformLocation(program,"u_CameraSpaceDirLight"); + + var moon_vs = getShaderSource(document.getElementById("moon_vs")); + var moon_fs = getShaderSource(document.getElementById("moon_fs")); + + program_moon = createProgram(gl, moon_vs, moon_fs, message); + positionMoonLocation = gl.getAttribLocation(program_moon, "PositionMoon"); + normalMoonLocation = gl.getAttribLocation(program_moon, "NormalMoon"); + texCoordMoonLocation = gl.getAttribLocation(program_moon, "TexcoordMoon"); + u_ModelMoonLocation = gl.getUniformLocation(program_moon,"u_ModelMoon"); + u_ViewMoonLocation = gl.getUniformLocation(program_moon,"u_View"); + u_PerspMoonLocation = gl.getUniformLocation(program_moon,"u_Persp"); + u_InvTransMoonLocation = gl.getUniformLocation(program_moon,"u_InvTrans"); + u_CameraSpaceDirLightMoonLocation = gl.getUniformLocation(program_moon,"u_CameraSpaceDirLight"); + u_MoonLocation = gl.getUniformLocation(program_moon, "u_Moon"); + u_BumpMoonLocation = gl.getUniformLocation(program_moon, "u_BumpMoon"); + + var vs_bg = getShaderSource(document.getElementById("vs_bg")); + var fs_bg = getShaderSource(document.getElementById("fs_bg")); + + program_starField = createProgram(gl, vs_bg, fs_bg, message); + u_BGLocation = gl.getUniformLocation(program_starField, "u_bg"); + texCoordBGLocation = gl.getAttribLocation(program_starField, "TexcoordBG"); + positionBGLocation = gl.getAttribLocation(program_starField, "PositionBG"); + u_ModelBGLocation = gl.getUniformLocation(program_starField,"u_Model"); + u_ViewBGLocation = gl.getUniformLocation(program_starField,"u_View"); + u_PerspBGLocation = gl.getUniformLocation(program_starField,"u_Persp"); + u_InvTransBGLocation = gl.getUniformLocation(program_starField,"u_InvTrans"); + + })(); + + var dayTex = gl.createTexture(); + var bumpTex = gl.createTexture(); + var cloudTex = gl.createTexture(); + var transTex = gl.createTexture(); + var lightTex = gl.createTexture(); + var specTex = gl.createTexture(); + var moonTex = gl.createTexture(); + var moonBumpTex = gl.createTexture(); + var starFieldTex = gl.createTexture(); + + function initLoadedTexture(texture){ + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + gl.bindTexture(gl.TEXTURE_2D, null); + } + + var numberOfIndices; + + (function initializeSphere() { + function uploadMesh(positions, texCoords, indices) { + // Positions + var positionsName = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, positionsName); + gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW); + gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(positionLocation); + + // Normals + var normalsName = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, normalsName); + gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW); + gl.vertexAttribPointer(normalLocation, 3, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(normalLocation); + + // TextureCoords + var texCoordsName = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, texCoordsName); + gl.bufferData(gl.ARRAY_BUFFER, texCoords, gl.STATIC_DRAW); + gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(texCoordLocation); + + // Indices + var indicesName = gl.createBuffer(); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesName); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW); + } + + var WIDTH_DIVISIONS = NUM_WIDTH_PTS - 1; + var HEIGHT_DIVISIONS = NUM_HEIGHT_PTS - 1; + + var numberOfPositions = NUM_WIDTH_PTS * NUM_HEIGHT_PTS; + + var positions = new Float32Array(3 * numberOfPositions); + var texCoords = new Float32Array(2 * numberOfPositions); + var indices = new Uint16Array(6 * (WIDTH_DIVISIONS * HEIGHT_DIVISIONS)); + + var positionsIndex = 0; + var texCoordsIndex = 0; + var indicesIndex = 0; + var length; + + for( var j = 0; j < NUM_HEIGHT_PTS; ++j ) + { + var inclination = Math.PI * (j / HEIGHT_DIVISIONS); + for( var i = 0; i < NUM_WIDTH_PTS; ++i ) + { + var azimuth = 2 * Math.PI * (i / WIDTH_DIVISIONS); + positions[positionsIndex++] = Math.sin(inclination)*Math.cos(azimuth); + positions[positionsIndex++] = Math.cos(inclination); + positions[positionsIndex++] = Math.sin(inclination)*Math.sin(azimuth); + texCoords[texCoordsIndex++] = i / WIDTH_DIVISIONS; + texCoords[texCoordsIndex++] = j / HEIGHT_DIVISIONS; + } + } + + for( var j = 0; j < HEIGHT_DIVISIONS; ++j ) + { + var index = j*NUM_WIDTH_PTS; + for( var i = 0; i < WIDTH_DIVISIONS; ++i ) + { + indices[indicesIndex++] = index + i; + indices[indicesIndex++] = index + i+1; + indices[indicesIndex++] = index + i+NUM_WIDTH_PTS; + indices[indicesIndex++] = index + i+NUM_WIDTH_PTS; + indices[indicesIndex++] = index + i+1; + indices[indicesIndex++] = index + i+NUM_WIDTH_PTS+1; + } + } + + uploadMesh(positions, texCoords, indices); + numberOfIndices = indicesIndex; + })(); + + var time = 0; + var mouseLeftDown = false; + var mouseRightDown = false; + var lastMouseX = null; + var lastMouseY = null; + + function handleMouseDown(event) { + if( event.button == 2 ) { + mouseLeftDown = false; + mouseRightDown = true; + } + else { + mouseLeftDown = true; + mouseRightDown = false; + } + lastMouseX = event.clientX; + lastMouseY = event.clientY; + } + + function handleMouseUp(event) { + mouseLeftDown = false; + mouseRightDown = false; + } + + function handleMouseMove(event) { + if (!(mouseLeftDown || mouseRightDown)) { + return; + } + var newX = event.clientX; + var newY = event.clientY; + + var deltaX = newX - lastMouseX; + var deltaY = newY - lastMouseY; + + if( mouseLeftDown ) + { + azimuth += 0.01 * deltaX; + elevation += 0.01 * deltaY; + elevation = Math.min(Math.max(elevation, -Math.PI/2+0.001), Math.PI/2-0.001); + } + else + { + radius += 0.01 * deltaY; + radius = Math.min(Math.max(radius, 2.0), 10.0); + } + eye = sphericalToCartesian(radius, azimuth, elevation); + view = mat4.create(); + mat4.lookAt(eye, center, up, view); + + lastMouseX = newX; + lastMouseY = newY; + } + + canvas.onmousedown = handleMouseDown; + canvas.oncontextmenu = function(ev) {return false;}; + document.onmouseup = handleMouseUp; + document.onmousemove = handleMouseMove; + + + function animate() { + /////////////////////////////////////////////////////////////////////////// + // Update + var model = mat4.create(); + mat4.identity(model); + mat4.rotate(model, 23.4/180*Math.PI, [0.0, 0.0, 1.0]); + mat4.rotate(model, Math.PI, [1.0, 0.0, 0.0]); + mat4.rotate(model, -time, [0.0, 1.0, 0.0]); + + var mv = mat4.create(); + mat4.multiply(view, model, mv); + + var invTrans = mat4.create(); + mat4.inverse(mv, invTrans); + mat4.transpose(invTrans); + + var lightdir = vec3.create([0.0, 0.0, 1.0]); + var lightdest = vec4.create(); + vec3.normalize(lightdir); + mat4.multiplyVec4(view, [lightdir[0], lightdir[1], lightdir[2], 0.0], lightdest); + lightdir = vec3.createFrom(lightdest[0],lightdest[1],lightdest[2]); + vec3.normalize(lightdir); + + /////////////////////////////////////////////////////////////////////////// + // Render + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); +/* + var model_star = model; + mat4.scale(model_star, [100.0, 100.0, 100.0]); + + // Star Field Program + gl.useProgram(program_starField); + + gl.uniformMatrix4fv(u_ModelBGLocation, false, model_star); + gl.uniformMatrix4fv(u_ViewBGLocation, false, view); + gl.uniformMatrix4fv(u_PerspBGLocation, false, persp); + gl.uniformMatrix4fv(u_InvTransBGLocation, false, invTrans); + //gl.uniform3fv(u_CameraSpaceDirLightLocation, lightdir); + + + gl.activeTexture(gl.TEXTURE8); + gl.bindTexture(gl.TEXTURE_2D, starFieldTex); + gl.uniform1i(u_BGLocation, 8); + gl.drawElements(gl.TRIANGLES, numberOfIndices, gl.UNSIGNED_SHORT,0); +*/ + gl.useProgram(program); + + time += 0.001; + gl.uniform1f(u_timeLocation, time); + + gl.uniformMatrix4fv(u_ModelLocation, false, model); + gl.uniformMatrix4fv(u_ViewLocation, false, view); + gl.uniformMatrix4fv(u_PerspLocation, false, persp); + gl.uniformMatrix4fv(u_InvTransLocation, false, invTrans); + gl.uniform3fv(u_CameraSpaceDirLightLocation, lightdir); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, dayTex); + gl.uniform1i(u_DayDiffuseLocation, 0); + gl.activeTexture(gl.TEXTURE1); + gl.bindTexture(gl.TEXTURE_2D, bumpTex); + gl.uniform1i(u_BumpLocation, 1); + gl.activeTexture(gl.TEXTURE2); + gl.bindTexture(gl.TEXTURE_2D, cloudTex); + gl.uniform1i(u_CloudLocation, 2); + gl.activeTexture(gl.TEXTURE3); + gl.bindTexture(gl.TEXTURE_2D, transTex); + gl.uniform1i(u_CloudTransLocation, 3); + gl.activeTexture(gl.TEXTURE4); + gl.bindTexture(gl.TEXTURE_2D, lightTex); + gl.uniform1i(u_NightLocation, 4); + gl.activeTexture(gl.TEXTURE5); + gl.bindTexture(gl.TEXTURE_2D, specTex); + gl.uniform1i(u_EarthSpecLocation, 5); + gl.drawElements(gl.TRIANGLES, numberOfIndices, gl.UNSIGNED_SHORT,0); + + // Start moon program + gl.useProgram(program_moon); + + // Moon transformation + var model_moon = mat4.create(); + mat4.identity(model_moon); + mat4.rotate(model_moon, 23.4/180*Math.PI, [0.0, 0.0, 1.0]); + mat4.rotate(model_moon, Math.PI, [1.0, 0.0, 0.0]); + mat4.rotate(model_moon, -2.3 * time, [0.0, 1.0, 0.0]); + mat4.translate(model_moon, [-2.0, 0.0, 0.0]); + mat4.scale(model_moon, [0.2, 0.2, 0.2]); + mat4.rotate(model_moon,-0.01 * time, [0.0, 1.0, 0.0]); + + var mv_moon = mat4.create(); + mat4.multiply(view, model_moon, mv_moon); + + var invTrans_moon = mat4.create(); + mat4.inverse(mv_moon, invTrans_moon); + mat4.transpose(invTrans_moon); + + gl.uniformMatrix4fv(u_ModelMoonLocation, false, model_moon); + gl.uniformMatrix4fv(u_ViewMoonLocation, false, view); + gl.uniformMatrix4fv(u_PerspMoonLocation, false, persp); + gl.uniformMatrix4fv(u_InvTransMoonLocation, false, invTrans_moon); + gl.uniform3fv(u_CameraSpaceDirLightMoonLocation, lightdir); + + // Moon texture activation and draw + gl.activeTexture(gl.TEXTURE6); + gl.bindTexture(gl.TEXTURE_2D, moonTex); + gl.uniform1i(u_MoonLocation, 6); + gl.activeTexture(gl.TEXTURE7); + gl.bindTexture(gl.TEXTURE_2D, moonBumpTex); + gl.uniform1i(u_BumpMoonLocation, 7); + gl.drawElements(gl.TRIANGLES, numberOfIndices, gl.UNSIGNED_SHORT,0); + + + window.requestAnimFrame(animate); + } + + var textureCount = 0; + + function initializeTexture(texture, src) { + texture.image = new Image(); + texture.image.onload = function() { + initLoadedTexture(texture); + + // Animate once textures load. + if (++textureCount === 9) { + animate(); + } + } + texture.image.src = src; + } + + initializeTexture(dayTex, "earthmap1024.png"); + initializeTexture(bumpTex, "earthbump1024.png"); + initializeTexture(cloudTex, "earthcloud1024.png"); + initializeTexture(transTex, "earthtrans1024.png"); + initializeTexture(lightTex, "earthlight1024.png"); + initializeTexture(specTex, "earthspec1024.png"); + initializeTexture(moonTex, "moon1024.jpg"); + initializeTexture(moonBumpTex, "moonBump1024.jpg"); + initializeTexture(starFieldTex, "starField1024.jpg"); +}()); diff --git a/part2/moon1024.jpg b/part2/moon1024.jpg new file mode 100644 index 0000000..3a89d2a Binary files /dev/null and b/part2/moon1024.jpg differ diff --git a/part2/moonBump1024.jpg b/part2/moonBump1024.jpg new file mode 100644 index 0000000..739a6c7 Binary files /dev/null and b/part2/moonBump1024.jpg differ diff --git a/part2/moonBump1k.jpg b/part2/moonBump1k.jpg new file mode 100644 index 0000000..405cb50 Binary files /dev/null and b/part2/moonBump1k.jpg differ diff --git a/part2/starField1024.jpg b/part2/starField1024.jpg new file mode 100644 index 0000000..5714ee8 Binary files /dev/null and b/part2/starField1024.jpg differ diff --git a/part2/stats.js b/part2/stats.js new file mode 160000 index 0000000..923ab65 --- /dev/null +++ b/part2/stats.js @@ -0,0 +1 @@ +Subproject commit 923ab65e86dc56bae4d7fbc2967747f0ecb2d94f diff --git a/part2/three.js b/part2/three.js new file mode 160000 index 0000000..f396baf --- /dev/null +++ b/part2/three.js @@ -0,0 +1 @@ +Subproject commit f396baf5876eb41bcd2ee34eb65b1f97bb92d530 diff --git a/performance_eval.png b/performance_eval.png new file mode 100644 index 0000000..a8fb4c0 Binary files /dev/null and b/performance_eval.png differ diff --git a/simplex_wave.png b/simplex_wave.png new file mode 100644 index 0000000..8831a16 Binary files /dev/null and b/simplex_wave.png differ