diff --git a/README.md b/README.md index 9bd6107..af9170f 100644 --- a/README.md +++ b/README.md @@ -3,375 +3,77 @@ CIS565: Project 5: WebGL ------------------------------------------------------------------------------- Fall 2013 ------------------------------------------------------------------------------- -Due Friday 11/08/2013 -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -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. +There are 2 projects, both based on WebGL and shaded with glsl. -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. +The first one is a shader for a grid that is waving with some kinds of function. The first one is a sin function, the second one is a random wave, the third one is a strange wave using some kinds of function. -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. +The theme of the 2nd project is to real-time render a rotating globe which is illuminated by sunshine. With the height map of the globe given, the globe is shaded so that it looks like + a globe with mountain scattered on it. Also, I made a simple noise-based water shader to shade the ocean. -------------------------------------------------------------------------------- -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. ------------------------------------------------------------------------------- -PART 1 REQUIREMENTS: +PART 1 ------------------------------------------------------------------------------- +The first 2 grids are just following the walkthrough. Nothing special, just play with the color. -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: +The 3rd grid follows the rule: -![Example sin wave grid](resources/sinWaveGrid.png) - -* A simplex noise based vertex shader: - -![Example simplex noise wave grid](resources/oceanWave.png) - -* One interesting vertex shader of your choice + float s_contrib = sin(position.x*4.0*3.14159 + u_time*4.0); + float t_contrib = cos(position.y*1.0*3.14159 + u_time*0.5*4.0); + float height = s_contrib+t_contrib; + +I don't quite know what it does.... ------------------------------------------------------------------------------- -PART 1 WALKTHROUGH: +PART 2 ------------------------------------------------------------------------------- -**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** +Besides the basic part, I implemented water shader and the height shader. -* 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: +For the height shader, I used a rainbow color-ramp to shade the different height. The lower part is more tends to be blue, while the higher part is more tends to be red. +It looks like this: +![Height Map](https://github.com/heguanyu/WebGL-Globe/blob/master/results/height.jpg?raw=true) -```glsl -vec2 simplexVec = vec2(u_time, position); -float s_contrib = snoise(simplexVec); -float t_contrib = snoise(vec2(s_contrib,u_time)); -``` +Also, I add a noise texture and using it to fulfill the water shader. To implement this, I distort the origin normal according to the color value of the noise map. And to make the ocean floating, +I move the texture coordination randomly. It is not a procedural water shader, and not that real. -**Wave Of Your Choice** +![Water](https://github.com/heguanyu/WebGL-Globe/blob/master/results/water.jpg?raw=true) -* 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. +For the future work, I would still like to try skybox at the background. ------------------------------------------------------------------------------- -PART 2 REQUIREMENTS: +LINK ------------------------------------------------------------------------------- -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 +Part1: http://guanyuhe.com/WebGL-Wave/index.html -You are required to implement: - -* 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: - -* 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. - -------------------------------------------------------------------------------- -PART 2 WALKTHROUGH: -------------------------------------------------------------------------------- - -In part 1, we render a globe with night lights on the unlit side; a specular -map so specular highlights only occur in the ocean; animated clouds; and bump -mapping, which perturbs the surface normal to give the appears of mountains. - -Open Globe\Globe\Globe.sln in Visual Studio and 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, fs.glsl. - -![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. - -**Specular Map** - -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) - -Figure 5. Globe with specular map. Compare to Figure 4. Here, the specular -component is not used when shading the land. - -**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/fake_rim/fake_rim1.html. +Part2: http://guanyuhe.com/WebGL-Globe/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. +I'd tried my best with gh-pages but it have sth wrong when updated. Therefore, I had to put it on the my personal website. It is interesting that when I put it on the website instead of running on local machine, + the Globe one work on Chrome again! ------------------------------------------------------------------------------- -README +VIDEO ------------------------------------------------------------------------------- -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). +The project is lived on the link above, so I don't think a video is required. ------------------------------------------------------------------------------- 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. +I got no idea how to test fps for it... And as the there's not a conception as tilesize in cuda, got no idea on what to test for this project. Actually everythign is running in real time. -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. +But one thing that I noticed is that when I open my globe on multiple tabs, the web browser is becoming laggy. Is this a kind of evaluation? ------------------------------------------------------------------------------- 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 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. - +None. ---- -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 +Just to mention, for the rainbow color ramp, I referred to my own code from my bachelor's thesis project. -* 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. diff --git a/README.md.bak b/README.md.bak new file mode 100644 index 0000000..9c38431 --- /dev/null +++ b/README.md.bak @@ -0,0 +1,79 @@ +------------------------------------------------------------------------------- +CIS565: Project 5: WebGL +------------------------------------------------------------------------------- +Fall 2013 +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +INTRODUCTION: +------------------------------------------------------------------------------- +There are 2 projects, both based on WebGL and shaded with glsl. + +The first one is a shader for a grid that is waving with some kinds of function. The first one is a sin function, the second one is a random wave, the third one is a strange wave using some kinds of function. + +The theme of the 2nd project is to real-time render a rotating globe which is illuminated by sunshine. With the height map of the globe given, the globe is shaded so that it looks like + a globe with mountain scattered on it. Also, I made a simple noise-based water shader to shade the ocean. + + +------------------------------------------------------------------------------- +PART 1 +------------------------------------------------------------------------------- +The first 2 grids are just following the walkthrough. Nothing special, just play with the color. + +The 3rd grid follows the rule: + + float s_contrib = sin(position.x*4.0*3.14159 + u_time*4.0); + float t_contrib = cos(position.y*1.0*3.14159 + u_time*0.5*4.0); + float height = s_contrib+t_contrib; + +I don't quite know what it does.... + +------------------------------------------------------------------------------- +PART 2 +------------------------------------------------------------------------------- +Besides the basic part, I implemented water shader and the height shader. + +For the height shader, I used a rainbow color-ramp to shade the different height. The lower part is more tends to be blue, while the higher part is more tends to be red. +It looks like this: +![Height Map](https://github.com/heguanyu/WebGL-Globe/blob/master/results/height.jpg?raw=true) + +Also, I add a noise texture and using it to fulfill the water shader. To implement this, I distort the origin normal according to the color value of the noise map. And to make the ocean floating, +I move the texture coordination randomly. It is not a procedural water shader, and not that real. + +![Water](https://github.com/heguanyu/WebGL-Globe/blob/master/results/height.jpg?raw=true) + +For the future work, I would still like to try skybox at the background. + +------------------------------------------------------------------------------- +LINK +------------------------------------------------------------------------------- + +Part1: http://guanyuhe.com/WebGL-Wave/index.html + +Part2: http://guanyuhe.com/WebGL-Globe/index.html + +------------------------------------------------------------------------------- +GH-PAGES +------------------------------------------------------------------------------- +I'd tried my best with gh-pages but it have sth wrong when updated. Therefore, I had to put it on the my personal website. It is interesting that when I put it on the website instead of running on local machine, + the Globe one work on Chrome again! + +------------------------------------------------------------------------------- +VIDEO +------------------------------------------------------------------------------- +The project is lived on the link above, so I don't think a video is required. + +------------------------------------------------------------------------------- +PERFORMANCE EVALUATION +------------------------------------------------------------------------------- +I got no idea how to test fps for it... And as the there's not a conception as tilesize in cuda, got no idea on what to test for this project. Actually everythign is running in real time. + +But one thing that I noticed is that when I open my globe on multiple tabs, the web browser is becoming laggy. Is this a kind of evaluation? + +------------------------------------------------------------------------------- +THIRD PARTY CODE POLICY +------------------------------------------------------------------------------- +None. + +Just to mention, for the rainbow color ramp, I referred to my own code from my bachelor's thesis project. + diff --git a/part1/index.html b/part1/index.html new file mode 100644 index 0000000..9a86df0 --- /dev/null +++ b/part1/index.html @@ -0,0 +1,16 @@ + + + +BASIC SIN WAVE + + + + + + +Go to the Sine Wave
+Go to the Simplex Wave
+Go to the Customized Wave
+ + + diff --git a/part1/index.html.bak b/part1/index.html.bak new file mode 100644 index 0000000..9b8341e --- /dev/null +++ b/part1/index.html.bak @@ -0,0 +1,16 @@ + + + +BASIC SIN WAVE + + + + + + +Go to the Sine Wave +Go to the Simplex Wave +Go to the Customized Wave + + + diff --git a/part1/mixsine.html b/part1/mixsine.html new file mode 100644 index 0000000..fbc21fe --- /dev/null +++ b/part1/mixsine.html @@ -0,0 +1,53 @@ + + + +MIXER SIN WAVE + + + + + +

This is the customized wave, the function is sin(4PiX+4t)+cos(Piy+2t)

+Go Back to Main Page
+ +
+ + + + + + + + + + + + diff --git a/part1/mixsine.html.bak b/part1/mixsine.html.bak new file mode 100644 index 0000000..1319c1c --- /dev/null +++ b/part1/mixsine.html.bak @@ -0,0 +1,53 @@ + + + +MIXER SIN WAVE + + + + + +

This is the customized wave, the function is sin(t)+cos(t/2)

+Go Back to Main Page
+ +
+ + + + + + + + + + + + diff --git a/part1/simplex.html b/part1/simplex.html new file mode 100644 index 0000000..9e854ee --- /dev/null +++ b/part1/simplex.html @@ -0,0 +1,91 @@ + + + +Random Noise Wave + + + + + +

This is the simplex wave

+Go Back to Main Page
+
+ + + + + + + + + + + + diff --git a/part1/simplex.html.bak b/part1/simplex.html.bak new file mode 100644 index 0000000..961fc2a --- /dev/null +++ b/part1/simplex.html.bak @@ -0,0 +1,91 @@ + + + +Random Noise Wave + + + + + +

This is the simplex wave

+Go Back to Main Page
+
+ + + + + + + + + + + + diff --git a/part1/simplex.vert b/part1/simplex.vert index 13dd1ca..89c4e1a 100644 --- a/part1/simplex.vert +++ b/part1/simplex.vert @@ -1,3 +1,4 @@ + vec3 permute(vec3 x) { x = ((x*34.0)+1.0)*x; return x - floor(x * (1.0 / 289.0)) * 289.0; diff --git a/part1/simplex.vert.bak b/part1/simplex.vert.bak new file mode 100644 index 0000000..33dd01f --- /dev/null +++ b/part1/simplex.vert.bak @@ -0,0 +1,45 @@ +uniform float u_time; + +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; + +vec3 permute(vec3 x) { + x = ((x*34.0)+1.0)*x; + return x - floor(x * (1.0 / 289.0)) * 289.0; +} + +float simplexNoise(vec2 v) + { + const vec4 C = vec4(0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439); + + vec2 i = floor(v + dot(v, C.yy) ); + vec2 x0 = v - i + dot(i, C.xx); + + vec2 i1; + i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); + + vec4 x12 = x0.xyxy + C.xxzz; + x12.xy -= i1; + + i = i - floor(i * (1.0 / 289.0)) * 289.0; + + vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) + + i.x + vec3(0.0, i1.x, 1.0 )); + + vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); + m = m*m ; + m = m*m ; + + vec3 x = 2.0 * fract(p * C.www) - 1.0; + vec3 h = abs(x) - 0.5; + vec3 ox = floor(x + 0.5); + vec3 a0 = x - ox; + + m *= inversesqrt( a0*a0 + h*h ); + + vec3 g; + g.x = a0.x * x0.x + h.x * x0.y; + g.yz = a0.yz * x12.xz + h.yz * x12.yw; + return 130.0 * dot(m, g); +} \ No newline at end of file diff --git a/part1/vert_wave.html b/part1/vert_wave.html index 57107ca..39d569d 100644 --- a/part1/vert_wave.html +++ b/part1/vert_wave.html @@ -1,33 +1,47 @@ -Vertex Wave +BASIC SIN WAVE + +

This is the sine wave, the function is sin(2PiX+t)*cos(2PiY+t)

+Go Back to Main Page
diff --git a/part1/vert_wave.html.bak b/part1/vert_wave.html.bak new file mode 100644 index 0000000..5214919 --- /dev/null +++ b/part1/vert_wave.html.bak @@ -0,0 +1,53 @@ + + + +BASIC SIN WAVE + + + + + + +

This is the sine wave, the function is sin(t)*cos(t)

+Go Back to Main Page
+
+ + + + + + + + + + + + diff --git a/part1/vert_wave.js b/part1/vert_wave.js index b90b9cf..016bc07 100644 --- a/part1/vert_wave.js +++ b/part1/vert_wave.js @@ -26,19 +26,23 @@ var center = [0.0, 0.0, 0.0]; var up = [0.0, 0.0, 1.0]; var view = mat4.create(); + var curtime=0; mat4.lookAt(eye, center, up, view); var positionLocation = 0; var heightLocation = 1; var u_modelViewPerspectiveLocation; + var u_timelocation; (function initializeShader() { - var program; + //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_timelocation=context.getUniformLocation(program, "u_time"); u_modelViewPerspectiveLocation = context.getUniformLocation(program,"u_modelViewPerspective"); context.useProgram(program); @@ -129,7 +133,7 @@ (function animate(){ /////////////////////////////////////////////////////////////////////////// // Update - + curtime+=0.01; var model = mat4.create(); mat4.identity(model); mat4.translate(model, [-0.5, -0.5, 0.0]); @@ -141,7 +145,8 @@ /////////////////////////////////////////////////////////////////////////// // Render context.clear(context.COLOR_BUFFER_BIT | context.DEPTH_BUFFER_BIT); - + //alert(curtime); + context.uniform1f(u_timelocation, curtime); context.uniformMatrix4fv(u_modelViewPerspectiveLocation, false, mvp); context.drawElements(context.LINES, numberOfIndices, context.UNSIGNED_SHORT,0); diff --git a/part1/vert_wave.js.bak b/part1/vert_wave.js.bak new file mode 100644 index 0000000..05b6daa --- /dev/null +++ b/part1/vert_wave.js.bak @@ -0,0 +1,156 @@ +(function() { + "use strict"; + /*global window,document,Float32Array,Uint16Array,mat4,vec3,snoise*/ + /*global getShaderSource,createWebGLContext,createProgram*/ + + var NUM_WIDTH_PTS = 32; + var NUM_HEIGHT_PTS = 32; + + 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(); + var curtime=0; + mat4.lookAt(eye, center, up, view); + + var positionLocation = 0; + var heightLocation = 1; + var u_modelViewPerspectiveLocation; + var u_timelocation; + + (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_timelocation=context.getUniformLocation(program, "u_time"); + u_modelViewPerspectiveLocation = context.getUniformLocation(program,"u_modelViewPerspective"); + + 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; + })(); + + (function animate(){ + /////////////////////////////////////////////////////////////////////////// + // Update + curtime+=0.05; + var model = mat4.create(); + mat4.identity(model); + mat4.translate(model, [-0.5, -0.5, 0.0]); + var mv = mat4.create(); + mat4.multiply(view, model, mv); + var mvp = mat4.create(); + mat4.multiply(persp, mv, mvp); + + /////////////////////////////////////////////////////////////////////////// + // Render + context.clear(context.COLOR_BUFFER_BIT | context.DEPTH_BUFFER_BIT); + //alert(curtime); + context.uniform1f(u_timelocation, curtime); + context.uniformMatrix4fv(u_modelViewPerspectiveLocation, false, mvp); + context.drawElements(context.LINES, numberOfIndices, context.UNSIGNED_SHORT,0); + + window.requestAnimFrame(animate); + })(); + +}()); diff --git a/part2/frag_globe.html b/part2/frag_globe.html index 6aa5609..f98f3af 100644 --- a/part2/frag_globe.html +++ b/part2/frag_globe.html @@ -7,6 +7,7 @@ +

Please note that this globe app can only work on Firefox browser.
If you are using Chrome right now, please change to Firefox, sorry about the inconvenience!

@@ -21,20 +22,26 @@ attribute vec3 Position; attribute vec3 Normal; attribute vec2 Texcoord; + attribute vec3 randHeight; varying vec3 v_Normal; varying vec2 v_Texcoord; varying vec3 v_Position; varying vec3 v_positionMC; + varying vec3 waterTurb; + void main(void) { + v_Normal = (u_InvTrans*vec4(Normal,0.0)).xyz; + v_Texcoord = Texcoord; vec4 world = u_Model * vec4(Position, 1.0); vec4 camera = u_View * world; v_Position = camera.xyz; v_positionMC = Position; + waterTurb = randHeight; gl_Position = u_Persp * camera; } @@ -60,38 +67,226 @@ uniform sampler2D u_EarthSpec; //Bump map uniform sampler2D u_Bump; + uniform sampler2D u_noise; uniform float u_time; + uniform float u_showWhich; uniform mat4 u_InvTrans; + uniform vec3 u_CameraSpacePosLight; varying vec3 v_Normal; // surface normal in camera coordinates varying vec2 v_Texcoord; varying vec3 v_Position; // position in camera coordinates varying vec3 v_positionMC; // position in model coordinates + varying vec3 waterTurb; mat3 eastNorthUpToEyeCoordinates(vec3 positionMC, vec3 normalEC); + + vec3 permute(vec3 x) { + x = ((x*34.0)+1.0)*x; + return x - floor(x * (1.0 / 289.0)) * 289.0; + } + + float snoise(vec2 v) + { + const vec4 C = vec4(0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439); + + vec2 i = floor(v + dot(v, C.yy) ); + vec2 x0 = v - i + dot(i, C.xx); + + vec2 i1; + i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); + + vec4 x12 = x0.xyxy + C.xxzz; + x12.xy -= i1; + + i = i - floor(i * (1.0 / 289.0)) * 289.0; + + vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) + + i.x + vec3(0.0, i1.x, 1.0 )); + + vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); + m = m*m ; + m = m*m ; + + vec3 x = 2.0 * fract(p * C.www) - 1.0; + vec3 h = abs(x) - 0.5; + vec3 ox = floor(x + 0.5); + vec3 a0 = x - ox; + + m *= inversesqrt( a0*a0 + h*h ); + + vec3 g; + g.x = a0.x * x0.x + h.x * x0.y; + g.yz = a0.yz * x12.xz + h.yz * x12.yw; + return 130.0 * dot(m, g); + } + + vec3 getRainbow(float x) + { + + vec3 flags[7]; + flags[0]=vec3(0.0,0.0,1.0); + flags[1]=vec3(0.0,0.99,1.0); + flags[2]=vec3(0.0,0.99,1.0); + flags[3]=vec3(1.0,1.0,0.0); + flags[4]=vec3(1.0,0.51,0.0); + flags[5]=vec3(1.0,0.0,0.0); + flags[6]=vec3(1.0,1.0,1.0); + + x=clamp(x,0.0,0.98); + int idx=int(floor(x/0.188)); + //int idx=0; + float ofst, ofst2; + if(idx==0) + { + ofst=x-0.0*0.188; + ofst2=1.0*0.188-x; + return flags[0]*(ofst2/(ofst+ofst2))+flags[1]*(ofst/(ofst+ofst2)); + } + else if(idx==1) + { + ofst=x-1.0*0.188; + ofst2=2.0*0.188-x; + return flags[1]*(ofst2/(ofst+ofst2))+flags[2]*(ofst/(ofst+ofst2)); + } + else if(idx==2) + { + ofst=x-2.0*0.188; + ofst2=3.0*0.188-x; + return flags[2]*(ofst2/(ofst+ofst2))+flags[3]*(ofst/(ofst+ofst2)); + } + else if(idx==3) + { + ofst=x-3.0*0.188; + ofst2=4.0*0.188-x; + return flags[3]*(ofst2/(ofst+ofst2))+flags[4]*(ofst/(ofst+ofst2)); + } + else if(idx==4) + { + ofst=x-4.0*0.188; + ofst2=5.0*0.188-x; + return flags[4]*(ofst2/(ofst+ofst2))+flags[5]*(ofst/(ofst+ofst2)); + } + else if(idx==5) + { + ofst=x-5.0*0.188; + ofst2=6.0*0.188-x; + return flags[5]*(ofst2/(ofst+ofst2))+flags[6]*(ofst/(ofst+ofst2)); + } + return vec3(1.0); + } void main(void) { // surface normal - normalized after rasterization - vec3 normal = normalize(v_Normal); + vec2 upTexcoord=v_Texcoord; + vec2 rightTexcoord=v_Texcoord; + upTexcoord.t-=1.0/512.0; + rightTexcoord.s+=1.0/1024.0; + + float checkDayNightnorm=dot(u_CameraSpaceDirLight, v_Normal); + + float center=texture2D(u_Bump,v_Texcoord).r; + float theright=texture2D(u_Bump, rightTexcoord).r; + float theUp=texture2D(u_Bump, upTexcoord).r; + + vec3 turbnormal=normalize(vec3(center-theright, center-theUp,0.2)); + vec3 normal=normalize(eastNorthUpToEyeCoordinates(v_positionMC, v_Normal)*turbnormal); + + + + + vec2 ocean_Texcoord = v_Texcoord; + float fragutime=u_time-10.0*float(int(u_time/10.0)); + float ocean_texcoord_noise=snoise(ocean_Texcoord*(fragutime)); + ocean_Texcoord.s-=0.00002*fragutime*ocean_texcoord_noise; + ocean_Texcoord.t+=0.00001*fragutime*ocean_texcoord_noise; + + vec2 ocean_upTexcoord=ocean_Texcoord; + vec2 ocean_rightTexcoord=ocean_Texcoord; + ocean_upTexcoord.t-=1.0/512.0; + ocean_rightTexcoord.s+=1.0/1024.0; + + + float ocean_center=texture2D(u_noise,ocean_Texcoord).r; + float ocean_theright=texture2D(u_noise, ocean_rightTexcoord).r; + float ocean_theUp=texture2D(u_noise, ocean_upTexcoord).r; + + vec3 ocean_turbnormal=normalize(vec3(ocean_center-ocean_theright, ocean_center-ocean_theUp,3.0)); + vec3 ocean_normal=normalize(eastNorthUpToEyeCoordinates(v_positionMC, v_Normal)*ocean_turbnormal); + + + + vec3 oceanStatus = texture2D(u_EarthSpec, v_Texcoord).rgb; + bool isOcean=length(oceanStatus)>0.5; + + //ray-trace to check if it is in shadow + + + if(isOcean) + { + normal=ocean_normal; + } + float dotlightnorm=dot(u_CameraSpaceDirLight, normal); + //vec3 normal = normalize(v_Normal); // normalized eye-to-position vector in camera coordinates vec3 eyeToPosition = normalize(v_Position); - float diffuse = clamp(dot(u_CameraSpaceDirLight, normal), 0.0, 1.0); + + float diffuse = clamp(dotlightnorm, 0.0, 1.0); vec3 toReflectedLight = reflect(-u_CameraSpaceDirLight, normal); float specular = max(dot(toReflectedLight, -eyeToPosition), 0.0); - specular = pow(specular, 20.0); + specular = pow(specular, 50.0); float gammaCorrect = 1.0/1.2; //gamma correct by 1/1.2 vec3 dayColor = texture2D(u_DayDiffuse, v_Texcoord).rgb; vec3 nightColor = texture2D(u_Night, v_Texcoord).rgb; + + + vec2 v_Texcoord2=v_Texcoord; // Cloud texture coord + v_Texcoord2.s-=0.0005*u_time; + vec3 cloudColor = texture2D(u_Cloud, v_Texcoord2).rgb; + vec3 cloudTrans = texture2D(u_CloudTrans, v_Texcoord2).rgb; + + //apply gamma correction to nighttime texture nightColor = pow(nightColor,vec3(gammaCorrect)); - vec3 color = ((0.6 * diffuse) + (0.4 * specular)) * dayColor; + vec3 color; + if(checkDayNightnorm>0.0) //day + { + cloudColor*=0.6*diffuse+0.8*specular; + + if(u_showWhich>0.5) + dayColor=getRainbow(center*2.7); + + color = ((0.6 * diffuse) + (0.8 * specular*(isOcean?1.0:0.0))) * dayColor; + + color = mix(cloudColor, color, cloudTrans.r); + + } + else //night + { + if(u_showWhich>0.5) + nightColor=getRainbow(center*2.7); + color = (-dotlightnorm)*nightColor*0.5; + cloudColor*=(1.0-cloudTrans.g)*0.2; + + color = mix(color, cloudColor,clamp(length(color),0.0,1.0)); + + + } + + float rimfactor=dot(v_Normal, v_Position)+1.0; + if(rimfactor>-0.0) + { + color+=vec3(rimfactor/4.0, rimfactor/2.0, rimfactor*1.0); + } + + gl_FragColor = vec4(color, 1.0); } @@ -110,7 +305,9 @@ normalEC.x, normalEC.y, normalEC.z); } - +
+ + diff --git a/part2/frag_globe.html.bak b/part2/frag_globe.html.bak new file mode 100644 index 0000000..6ffdbf6 --- /dev/null +++ b/part2/frag_globe.html.bak @@ -0,0 +1,317 @@ + + + +Fragment Globe + + + + + +

Please note that this globe app can only work on Firefox browser.
If you are using Chrome right now, please change to Firefox, sorry about the inconvenience!

+
+ + + + + +
+ + + + + + + + diff --git a/part2/frag_globe.js b/part2/frag_globe.js index 6e667be..2679ddc 100644 --- a/part2/frag_globe.js +++ b/part2/frag_globe.js @@ -1,3 +1,18 @@ + + var radius = 5.0; + var azimuth = Math.PI; + var elevation = 0.0001; + + var showWhich = 0.0; + +function showSat() +{ + showWhich=0.0; +} +function showHM() +{ + showWhich=1.0; +} (function() { "use strict"; /*global window,document,Float32Array,Uint16Array,mat4,vec3,snoise*/ @@ -30,9 +45,6 @@ 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]; @@ -40,29 +52,39 @@ var view = mat4.create(); mat4.lookAt(eye, center, up, view); - var positionLocation = 0; - var normalLocation = 1; - var texCoordLocation = 2; + var positionLocation;// = 0; + var normalLocation;// = 1; + var texCoordLocation;// = 2; + var heightLocation;// = 3; + var u_InvTransLocation; var u_ModelLocation; var u_ViewLocation; var u_PerspLocation; var u_CameraSpaceDirLightLocation; + var u_CameraSpacePosLightLocation; var u_DayDiffuseLocation; var u_NightLocation; var u_CloudLocation; var u_CloudTransLocation; var u_EarthSpecLocation; + var u_NoiseTexLocation; var u_BumpLocation; var u_timeLocation; + var u_showWhichLocation; + + var curtime=0; (function initializeShader() { - var program; var vs = getShaderSource(document.getElementById("vs")); var fs = getShaderSource(document.getElementById("fs")); - var program = createProgram(gl, vs, fs, message); - gl.bindAttribLocation(program, positionLocation, "Position"); + var program = createProgram(gl, vs, fs, message); + //gl.bindAttribLocation(program, positionLocation, "Position"); + 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"); @@ -72,9 +94,12 @@ u_CloudLocation = gl.getUniformLocation(program,"u_Cloud"); u_CloudTransLocation = gl.getUniformLocation(program,"u_CloudTrans"); u_EarthSpecLocation = gl.getUniformLocation(program,"u_EarthSpec"); + u_NoiseTexLocation = gl.getUniformLocation(program, "u_noise"); u_BumpLocation = gl.getUniformLocation(program,"u_Bump"); + u_showWhichLocation=gl.getUniformLocation(program,"u_showWhich"); u_timeLocation = gl.getUniformLocation(program,"u_time"); u_CameraSpaceDirLightLocation = gl.getUniformLocation(program,"u_CameraSpaceDirLight"); + u_CameraSpacePosLightLocation = gl.getUniformLocation(program,"u_CameraSpacePosLight"); gl.useProgram(program); })(); @@ -85,44 +110,23 @@ var transTex = gl.createTexture(); var lightTex = gl.createTexture(); var specTex = gl.createTexture(); - - (function initTextures() { - 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); - } - - function initializeTexture(texture, src) { - texture.image = new Image(); - texture.image.onload = function() { - initLoadedTexture(texture); - } - 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"); - })(); + var noiseTex = 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) { + function uploadMesh(positions, texCoords, randHeight, indices) { // Positions var positionsName = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, positionsName); @@ -143,6 +147,13 @@ gl.bufferData(gl.ARRAY_BUFFER, texCoords, gl.STATIC_DRAW); gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(texCoordLocation); + /* + var randHeightName = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, randHeightName); + gl.bufferData(gl.ARRAY_BUFFER, randHeight, gl.STATIC_DRAW); + gl.vertexAttribPointer(heightLocation, 3, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(heightLocation); + */ // Indices var indicesName = gl.createBuffer(); @@ -157,10 +168,12 @@ var positions = new Float32Array(3 * numberOfPositions); var texCoords = new Float32Array(2 * numberOfPositions); + var randHeight = new Float32Array(3 * numberOfPositions); var indices = new Uint16Array(6 * (WIDTH_DIVISIONS * HEIGHT_DIVISIONS)); var positionsIndex = 0; var texCoordsIndex = 0; + var heightIndex = 0; var indicesIndex = 0; var length; @@ -175,9 +188,28 @@ positions[positionsIndex++] = Math.sin(inclination)*Math.sin(azimuth); texCoords[texCoordsIndex++] = i / WIDTH_DIVISIONS; texCoords[texCoordsIndex++] = j / HEIGHT_DIVISIONS; + randHeight[heightIndex+2] = Math.random(); + var leftindex=(i-1)+j*NUM_WIDTH_PTS; + var upindex=i+(j-1)*NUM_WIDTH_PTS; + var leftval=0; + var upval=0; + if(i!=0) leftval=randHeight[leftindex*3+2]; + if(j!=0) upval=randHeight[upindex*3+2]; + randHeight[heightIndex]=randHeight[heightIndex+2]-leftval; + randHeight[heightIndex+1]=randHeight[heightIndex+2]-upval; + heightIndex+=3; } } - + heightIndex=0; + for( var j = 0; j < NUM_HEIGHT_PTS; ++j ) + { + for( var i = 0; i < NUM_WIDTH_PTS; ++i ) + { + randHeight[heightIndex+2]=0.2; + heightIndex+=3; + } + } + for( var j = 0; j < HEIGHT_DIVISIONS; ++j ) { var index = j*NUM_WIDTH_PTS; @@ -192,7 +224,7 @@ } } - uploadMesh(positions, texCoords, indices); + uploadMesh(positions, texCoords,randHeight, indices); numberOfIndices = indicesIndex; })(); @@ -255,7 +287,7 @@ document.onmousemove = handleMouseMove; - (function animate(){ + function animate(){ /////////////////////////////////////////////////////////////////////////// // Update @@ -276,10 +308,11 @@ vec3.normalize(lightdir); mat4.multiplyVec4(view, [lightdir[0], lightdir[1], lightdir[2], 0.0], lightdest); lightdir = vec3.createFrom(lightdest[0],lightdest[1],lightdest[2]); + var lightpos=lightdir; vec3.normalize(lightdir); - + curtime+=0.5; /////////////////////////////////////////////////////////////////////////// // Render gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); @@ -288,7 +321,9 @@ gl.uniformMatrix4fv(u_ViewLocation, false, view); gl.uniformMatrix4fv(u_PerspLocation, false, persp); gl.uniformMatrix4fv(u_InvTransLocation, false, invTrans); - + gl.uniform1f(u_timeLocation,curtime); + gl.uniform1f(u_showWhichLocation,showWhich); + gl.uniform3fv(u_CameraSpacePosLightLocation,lightpos); gl.uniform3fv(u_CameraSpaceDirLightLocation, lightdir); gl.activeTexture(gl.TEXTURE0); @@ -309,11 +344,36 @@ gl.activeTexture(gl.TEXTURE5); gl.bindTexture(gl.TEXTURE_2D, specTex); gl.uniform1i(u_EarthSpecLocation, 5); + + gl.activeTexture(gl.TEXTURE6); + gl.bindTexture(gl.TEXTURE_2D, noiseTex); + gl.uniform1i(u_NoiseTexLocation, 6); gl.drawElements(gl.TRIANGLES, numberOfIndices, gl.UNSIGNED_SHORT,0); time += 0.001; - window.requestAnimFrame(animate); - })(); + 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(); + } + } + 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(noiseTex, "noisemap.png"); }()); diff --git a/part2/frag_globe.js.bak b/part2/frag_globe.js.bak new file mode 100644 index 0000000..3bee4f9 --- /dev/null +++ b/part2/frag_globe.js.bak @@ -0,0 +1,378 @@ + + var radius = 5.0; + var azimuth = Math.PI; + var elevation = 0.0001; + + var showWhich = 0.0; + +function showSat() +{ + showWhich=0.0; +} +function showHM() +{ + showWhich=1.0; +} +(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 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;// = 0; + var normalLocation;// = 1; + var texCoordLocation;// = 2; + var heightLocation;// = 3; + + var u_InvTransLocation; + var u_ModelLocation; + var u_ViewLocation; + var u_PerspLocation; + var u_CameraSpaceDirLightLocation; + var u_CameraSpacePosLightLocation; + var u_DayDiffuseLocation; + var u_NightLocation; + var u_CloudLocation; + var u_CloudTransLocation; + var u_EarthSpecLocation; + var u_NoiseTexLocation; + var u_BumpLocation; + var u_timeLocation; + var u_showWhichLocation; + + var curtime=0; + + (function initializeShader() { + var vs = getShaderSource(document.getElementById("vs")); + var fs = getShaderSource(document.getElementById("fs")); + + var program = createProgram(gl, vs, fs, message); + //gl.bindAttribLocation(program, positionLocation, "Position"); + 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_NoiseTexLocation = gl.getUniformLocation(program, "u_noise"); + u_BumpLocation = gl.getUniformLocation(program,"u_Bump"); + u_showWhichLocation=gl.getUniformLocation(program,"u_showWhich"); + u_timeLocation = gl.getUniformLocation(program,"u_time"); + u_CameraSpaceDirLightLocation = gl.getUniformLocation(program,"u_CameraSpaceDirLight"); + u_CameraSpacePosLightLocation = gl.getUniformLocation(program,"u_CameraSpacePosLight"); + + 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 noiseTex = 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, randHeight, 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); + /* + var randHeightName = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, randHeightName); + gl.bufferData(gl.ARRAY_BUFFER, randHeight, gl.STATIC_DRAW); + gl.vertexAttribPointer(heightLocation, 3, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(heightLocation); + */ + + // 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 randHeight = new Float32Array(3 * numberOfPositions); + var indices = new Uint16Array(6 * (WIDTH_DIVISIONS * HEIGHT_DIVISIONS)); + + var positionsIndex = 0; + var texCoordsIndex = 0; + var heightIndex = 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; + randHeight[heightIndex+2] = Math.random(); + var leftindex=(i-1)+j*NUM_WIDTH_PTS; + var upindex=i+(j-1)*NUM_WIDTH_PTS; + var leftval=0; + var upval=0; + if(i!=0) leftval=randHeight[leftindex*3+2]; + if(j!=0) upval=randHeight[upindex*3+2]; + randHeight[heightIndex]=randHeight[heightIndex+2]-leftval; + randHeight[heightIndex+1]=randHeight[heightIndex+2]-upval; + heightIndex+=3; + } + } + heightIndex=0; + for( var j = 0; j < NUM_HEIGHT_PTS; ++j ) + { + for( var i = 0; i < NUM_WIDTH_PTS; ++i ) + { + randHeight[heightIndex+2]=0.2; + heightIndex+=3; + } + } + + 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,randHeight, 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([1.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]); + var lightpos=lightdir; + vec3.normalize(lightdir); + + + curtime+=0.5; + /////////////////////////////////////////////////////////////////////////// + // Render + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + 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.uniform1f(u_timeLocation,curtime); + gl.uniform1f(u_showWhichLocation,showWhich); + gl.uniform3fv(u_CameraSpacePosLightLocation,lightpos); + 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.activeTexture(gl.TEXTURE6); + gl.bindTexture(gl.TEXTURE_2D, noiseTex); + gl.uniform1i(u_NoiseTexLocation, 6); + + gl.drawElements(gl.TRIANGLES, numberOfIndices, gl.UNSIGNED_SHORT,0); + + time += 0.001; + 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(); + } + } + 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"); +}()); diff --git a/part2/index.html b/part2/index.html new file mode 100644 index 0000000..f98f3af --- /dev/null +++ b/part2/index.html @@ -0,0 +1,316 @@ + + + +Fragment Globe + + + + + +

Please note that this globe app can only work on Firefox browser.
If you are using Chrome right now, please change to Firefox, sorry about the inconvenience!

+
+ + + + + +
+ + + + + + + + diff --git a/part2/noisemap.png b/part2/noisemap.png new file mode 100644 index 0000000..8e689c8 Binary files /dev/null and b/part2/noisemap.png differ diff --git a/results/height.jpg b/results/height.jpg new file mode 100644 index 0000000..43d3bf5 Binary files /dev/null and b/results/height.jpg differ diff --git a/results/water.jpg b/results/water.jpg new file mode 100644 index 0000000..9d47087 Binary files /dev/null and b/results/water.jpg differ