diff --git a/README.md b/README.md index 2d26873..8e00a6a 100644 --- a/README.md +++ b/README.md @@ -1,362 +1,61 @@ -------------------------------------------------------------------------------- -CIS565: Project 5: WebGL -------------------------------------------------------------------------------- -Fall 2014 -------------------------------------------------------------------------------- -Due Monday 11/03/2014 -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -NOTE: -------------------------------------------------------------------------------- -This project requires any graphics card with support for a modern OpenGL -pipeline. Any AMD, NVIDIA, or Intel card from the past few years should work -fine, and every machine in the SIG Lab and Moore 100 is capable of running -this project. - -This project also requires a WebGL capable browser. The project is known to -have issues with Chrome on windows, but Firefox seems to run it fine. - -------------------------------------------------------------------------------- -INTRODUCTION: -------------------------------------------------------------------------------- -In this project, you will get introduced to the world of GLSL in two parts: -vertex shading and fragment shading. The first part of this project is the -Image Processor, and the second part of this project is a Wave Vertex Shader. - -In the first part of this project, you will implement a GLSL vertex shader as -part of a WebGL demo. You will create a dynamic wave animation using code that -runs entirely on the GPU. - -In the second part of this project, you will implement a GLSL fragment shader -to render an interactive globe in WebGL. This will include texture blending, -bump mapping, specular masking, and adding a cloud layer to give your globe a -uniquie feel. - -------------------------------------------------------------------------------- -CONTENTS: -------------------------------------------------------------------------------- -The Project5 root directory contains the following subdirectories: - -* js/ contains the javascript files, including external libraries, necessary. -* assets/ contains the textures that will be used in the second half of the - assignment. -* resources/ contains the screenshots found in this readme file. - -------------------------------------------------------------------------------- -PART 1 REQUIREMENTS: -------------------------------------------------------------------------------- - -In Part 1, you are given code for: - -* Drawing a VBO through WebGL -* Javascript code for interfacing with WebGL -* Functions for generating simplex noise - -You are required to implement the following: - -* A sin-wave based vertex shader: - -![Example sin wave grid](resources/sinWaveGrid.png) - -* One interesting vertex shader of your choice - -------------------------------------------------------------------------------- -PART 1 WALKTHROUGH: -------------------------------------------------------------------------------- -**Sin Wave** - -* For this assignment, you will need the latest version of Firefox. -* Begin by opening index.html. You should see a flat grid of black and white - lines on the xy plane: - -![Example boring grid](resources/emptyGrid.png) - -* In this assignment, you will animate the grid in a wave-like pattern using a - vertex shader, and determine each vertex’s color based on its height, as seen - in the example in the requirements. -* The vertex and fragment shader are located in script tags in `index.html`. -* The JavaScript code that needs to be modified is located in `index.js`. -* Required shader code modifications: - * Add a float uniform named u_time. - * Modify the vertex’s height using the following code: - - ```glsl - float s_contrib = sin(position.x*2.0*3.14159 + u_time); - float t_contrib = cos(position.y*2.0*3.14159 + u_time); - float height = s_contrib*t_contrib; - ``` - - * Use the GLSL mix function to blend together two colors of your choice based - on the vertex’s height. The lowest possible height should be assigned one - color (for example, `vec3(1.0, 0.2, 0.0)`) and the maximum height should be - another (`vec3(0.0, 0.8, 1.0)`). Use a varying variable to pass the color to - the fragment shader, where you will assign it `gl_FragColor`. - - * Using dat.gui, you will add color pickers to modify the max and min colors - via GUI. You will do this by adding the proper uniforms to the fragment - shader, and using the addColor function from dat.GUI. - -* 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()`. - -**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: -* Bump mapped terrain -* Rim lighting to simulate atmosphere -* Night-time lights on the dark side of the globe -* Specular mapping -* Moving clouds +This project has a wave renderer and a globe renderer implemented using WebGL. +To run the demo, you need a WebGL capable browser like FireFox. -You are also required to pick one open-ended effect to implement: +![](step5_addwatersimulation.png) -* 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 +[Live demo](http://jianqiaol.github.io/Project5-WebGL/) -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. +[Video here](https://www.youtube.com/watch?v=zg2oQxpIPbA&feature=youtu.be) -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. +###Globe renderer Walk through +The original code generate this basic globe with Earth terrain color mapping looks like this: -![Completed globe, twilight](resources/globe_twilight.png) +![](step0_nochange.png) -Figure 1. Completed globe renderer, twilight border. +* Night light -![Completed globe, night side](resources/globe_night.png) +By taking the dot product of the light direction and normal direciton of each vertex, I generated a night_flag, from -1 to 1. negative means day time while positive means night time. Then using the mix function I got this: -Figure 2. Completed globe renderer, night side. +![](step1_addNight.png) -------------------------------------------------------------------------------- -PART 2 WALKTHROUGH: -------------------------------------------------------------------------------- - -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. - -**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) +* Add cloud -Figure 6. Clouds with day time shading. +Using the cloud map and cloudTrans map, I mixed the terrian color with cloud. The coordinate of cloud is shifted by time to make it move. -![Night with clouds](resources/globe_nightcloud.png) +![](step2_addCloud.png) -Figure 7. Clouds observing city nights on the dark side of the globe. +* Add Bump mapping -**Bump Mapping** +By adjusting the normal for each vertex based on the height map, we can add 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: +![](step3_bumpMap.png) -`normalize(vec3(center - right, center - top, 0.2))` +* Add Rim lighting -Use `eastNorthUpToEyeCoordinates` to transform this normal to eye coordinates, -normalize it, then use it for diffuse lighting the ground instead of the -original normal. +If the normal direction of a fragment is orthrogonal or close to orthrogonal to camera direction, we add some blue-ish color to it. -![Globe with bump mapping](resources/globe_bumpmap.png) +![](step4_addRim.png) -Figure 8. Bump mapping brings attention to mountains. +* Add water simulation -**Rim Lighting** +By adding some noise to the water diffuse factor, we can make a shiny ocean surface. The random generator was found here: http://www.java-gaming.org/index.php?topic=28018.0 -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. +![](step5_addwatersimulation.png) -For more information on rim lighting, -read http://www.fundza.com/rman_shaders/surface/rim_effects/index.html. +###Custome ripple -------------------------------------------------------------------------------- -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` +This ripple simulates a water drop. The main implementation is based on the distance from the center of drop to each vertex. The height is calculated by a sin function, with parameters such as wave speed,decay factor and so on. -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 +![](ripple.png) -`.github.io/` +###Performance evaluation +Throughout the whole process, I didn't see any noticeable change after any feature is added. -to see your beautiful globe from anywhere. - -------------------------------------------------------------------------------- -README -------------------------------------------------------------------------------- -All students must replace or augment the contents of this Readme.md in a clear -manner with the following: - -* A brief description of the project and the specific features you implemented. -* At least one screenshot of your project running. -* A 30 second or longer video of your project running. To create the video you - can use http://www.microsoft.com/expression/products/Encoder4_Overview.aspx -* A performance evaluation (described in detail below). - -------------------------------------------------------------------------------- -PERFORMANCE EVALUATION -------------------------------------------------------------------------------- -The performance evaluation is where you will investigate how to make your -program more efficient using the skills you've learned in class. You must have -performed at least one experiment on your code to investigate the positive or -negative effects on performance. - -We encourage you to get creative with your tweaks. Consider places in your code -that could be considered bottlenecks and try to improve them. - -Each student should provide no more than a one page summary of their -optimizations along with tables and or graphs to visually explain any -performance differences. - -In this homework, we do not expect crazy performance evaluation in terms of -optimizations. However, it would be good to take performance benchmarks at -every step in this assignment to see how complicated fragment shaders affect the -overall speed. You can do this by using stats.js. ------------------------------------------------------------------------------- THIRD PARTY CODE POLICY ------------------------------------------------------------------------------- -* Use of any third-party code must be approved by asking on the Google groups. - If it is approved, all students are welcome to use it. Generally, we approve - use of third-party code that is not a core part of the project. For example, - for the ray tracer, we would approve using a third-party library for loading - models, but would not approve copying and pasting a CUDA function for doing - refraction. -* Third-party code must be credited in README.md. -* Using third-party code without its approval, including using another - student's code, is an academic integrity violation, and will result in you - receiving an F for the semester. - -------------------------------------------------------------------------------- -SELF-GRADING -------------------------------------------------------------------------------- -* On the submission date, email your grade, on a scale of 0 to 100, to Harmony, - harmoli+cis565@seas.upenn.com, with a one paragraph explanation. Be concise and - realistic. Recall that we reserve 30 points as a sanity check to adjust your - grade. Your actual grade will be (0.7 * your grade) + (0.3 * our grade). We - hope to only use this in extreme cases when your grade does not realistically - reflect your work - it is either too high or too low. In most cases, we plan - to give you the exact grade you suggest. -* Projects are not weighted evenly, e.g., Project 0 doesn't count as much as - the path tracer. We will determine the weighting at the end of the semester - based on the size of each project. - ---- -SUBMISSION ---- -As with the previous project, you should fork this project and work inside of -your fork. Upon completion, commit your finished project back to your fork, and -make a pull request to the master repository. You should include a README.md -file in the root directory detailing the following - -* A brief description of the project and specific features you implemented -* At least one screenshot of your project running. -* A link to a video of your project running. -* Instructions for building and running your project if they differ from the - base code. -* A performance writeup as detailed above. -* A list of all third-party code used. -* This Readme file edited as described above in the README section. +* The random generator I used for water simulation is from here:http://www.java-gaming.org/index.php?topic=28018.0 diff --git a/frag_globe.html b/frag_globe.html index e074492..594b0a6 100644 --- a/frag_globe.html +++ b/frag_globe.html @@ -64,42 +64,109 @@ uniform float u_time; uniform mat4 u_InvTrans; + //for height map + uniform vec3 low_color; + uniform vec3 high_color; + 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 mat3 eastNorthUpToEyeCoordinates(vec3 positionMC, vec3 normalEC); + //random generator from http://www.java-gaming.org/index.php?topic=28018.0 + float rand(vec2 co){ + return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); + } - void main(void) + +void main(void) +{ + // surface normal - normalized after rasterization + vec3 normal = normalize(v_Normal); + float night_flag=dot(v_Normal,u_CameraSpaceDirLight); + // normalized eye-to-position vector in camera coordinates + vec3 eyeToPosition = normalize(v_Position); + //for specular map + vec3 maskColor=texture2D(u_Bump,v_Texcoord).rgb; + + //bump map + vec2 bump_center_coord=v_Texcoord; + vec2 bump_right_coord=bump_center_coord+vec2(1.0/1024.0,0.0); + vec2 bump_top_coord=bump_center_coord+vec2(0.0,1.0/512.0); + float bump_center=texture2D(u_Bump,bump_center_coord).x; + float bump_right=texture2D(u_Bump,bump_right_coord).x; + float bump_top=texture2D(u_Bump,bump_top_coord).x; + + + + vec3 bump_normal=eastNorthUpToEyeCoordinates(v_positionMC,v_Normal)*normalize(vec3(bump_center-bump_right,bump_center-bump_top,0.15)); + + float bump_diffuse=clamp(dot(-u_CameraSpaceDirLight, bump_normal), 0.0, 1.0); + + float diffuse = clamp(dot(-u_CameraSpaceDirLight, normal), 0.0, 1.0); + + vec3 toReflectedLight = reflect(-u_CameraSpaceDirLight, normal); + float specular = max(dot(toReflectedLight, eyeToPosition), 0.0); + specular = pow(specular, 20.0); + + float gammaCorrect = 1.0/1.3; //gamma correct by 1/1.2 + + vec3 dayColor = texture2D(u_DayDiffuse, v_Texcoord).rgb; + vec3 nightColor = texture2D(u_Night, v_Texcoord).rgb; + //apply gamma correction to nighttime texture + nightColor = pow(nightColor,vec3(gammaCorrect)); + + if(maskColor.r>0.0) + { + specular=0.0; + } + if(maskColor.r==0.0) + { + bump_diffuse+=(rand(v_Texcoord*u_time*0.1)+rand(v_positionMC.xy*u_time*0.1))*0.3; + } + vec3 day_color = ((0.9 * bump_diffuse) + (0.5 * specular)) * dayColor; + //for height map + float altitude=texture2D(u_Bump,v_Texcoord).r; + if(altitude<0.5) + { + day_color=mix(day_color,low_color,0.1); + } + else + { + day_color=mix(day_color,high_color,0.1); + } + + + + + //for clouds + vec2 v_cloud=v_Texcoord+vec2(u_time*0.25,0.0); + //vec2 v_cloud=v_Texcoord; + //v_cloud+=vec2(u_time,u_time); + vec3 cloudColor=texture2D(u_Cloud,v_cloud).rgb; + vec3 cloudTrans=texture2D(u_CloudTrans,v_cloud).rgb; + //day cloud + vec3 dayCloud=cloudColor; + vec3 nightCloud=vec3(0.0,0.0,0.0); + //mixed day and night cloud + vec3 mixed_dayColor=mix(dayCloud*0.8,day_color,cloudTrans.r); + vec3 mixed_nightColor=mix(nightCloud,nightColor,cloudTrans.r); + + vec3 color=mix(mixed_dayColor,mixed_nightColor,(night_flag+1.0)/2.0); + float rimfactor=clamp(dot(v_Normal,v_Position)+1.0,0.0,0.5); + if(rimfactor>0.0) { - // surface normal - normalized after rasterization - 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); - - vec3 toReflectedLight = reflect(-u_CameraSpaceDirLight, normal); - float specular = max(dot(toReflectedLight, -eyeToPosition), 0.0); - specular = pow(specular, 20.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; - //apply gamma correction to nighttime texture - nightColor = pow(nightColor,vec3(gammaCorrect)); - - vec3 color = ((0.6 * diffuse) + (0.4 * specular)) * dayColor; - gl_FragColor = vec4(color, 1.0); + color+=vec3(rimfactor/4.0,rimfactor/2.0,rimfactor/2.0); } + gl_FragColor = vec4(color, 1.0); +} mat3 eastNorthUpToEyeCoordinates(vec3 positionMC, vec3 normalEC) { // normalized surface tangent in model coordinates - vec3 tangentMC = normalize(vec3(-positionMC.z, positionMC.x, 0.0)); - // normalized surface tangent in eye coordiantes + vec3 tangentMC = normalize(vec3(-positionMC.z, positionMC.x, 0.0)); + // normalized surface tangent in eye coordiantes vec3 tangentEC = normalize(mat3(u_InvTrans) * tangentMC); // normalized surface bitangent in eye coordinates vec3 bitangentEC = normalize(cross(normalEC, tangentEC)); diff --git a/js/frag_globe.js b/js/frag_globe.js index f37830d..3e95851 100644 --- a/js/frag_globe.js +++ b/js/frag_globe.js @@ -55,6 +55,11 @@ var u_EarthSpecLocation; var u_BumpLocation; var u_timeLocation; + var low_colorLocation; + var high_colorLocation; + var lowColor=[1.0,0.0,0.0,0.0]; + var highColor=[0.0,0.0,1.0,0.0]; + (function initializeShader() { var vs = getShaderSource(document.getElementById("vs")); @@ -76,6 +81,8 @@ u_BumpLocation = gl.getUniformLocation(program,"u_Bump"); u_timeLocation = gl.getUniformLocation(program,"u_time"); u_CameraSpaceDirLightLocation = gl.getUniformLocation(program,"u_CameraSpaceDirLight"); + low_colorLocation=gl.getUniformLocation(program,"low_color"); + high_colorLocation=gl.getUniformLocation(program,"high_color"); gl.useProgram(program); })(); @@ -265,9 +272,12 @@ gl.uniformMatrix4fv(u_ViewLocation, false, view); gl.uniformMatrix4fv(u_PerspLocation, false, persp); gl.uniformMatrix4fv(u_InvTransLocation, false, invTrans); - + gl.uniform1f(u_timeLocation,time); gl.uniform3fv(u_CameraSpaceDirLightLocation, lightdir); - + gl.uniform3fv(low_colorLocation,lowColor); + gl.uniform3fv(high_colorLocation,highColor); + + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, dayTex); gl.uniform1i(u_DayDiffuseLocation, 0); @@ -287,6 +297,7 @@ gl.bindTexture(gl.TEXTURE_2D, specTex); gl.uniform1i(u_EarthSpecLocation, 5); gl.drawElements(gl.TRIANGLES, numberOfIndices, gl.UNSIGNED_SHORT,0); + time += 0.001; window.requestAnimFrame(animate); diff --git a/my_wave.html b/my_wave.html new file mode 100644 index 0000000..9547cec --- /dev/null +++ b/my_wave.html @@ -0,0 +1,320 @@ + + + +Vertex Wave + + + + + +
+ + + + + + + + + + + + + + diff --git a/reference list.txt b/reference list.txt new file mode 100644 index 0000000..2ecbc7d --- /dev/null +++ b/reference list.txt @@ -0,0 +1,2 @@ +http://nehe.gamedev.net/article/glsl_an_introduction/25007/ +http://www.lwjgl.org/wiki/index.php?title=GLSL_Tutorial:_Communicating_with_Shaders \ No newline at end of file diff --git a/ripple.png b/ripple.png new file mode 100644 index 0000000..b3e54b3 Binary files /dev/null and b/ripple.png differ diff --git a/step0_nochange.png b/step0_nochange.png new file mode 100644 index 0000000..d13fc60 Binary files /dev/null and b/step0_nochange.png differ diff --git a/step1_addNight.png b/step1_addNight.png new file mode 100644 index 0000000..1face74 Binary files /dev/null and b/step1_addNight.png differ diff --git a/step2_addCloud.png b/step2_addCloud.png new file mode 100644 index 0000000..b7a166a Binary files /dev/null and b/step2_addCloud.png differ diff --git a/step3_bumpMap.png b/step3_bumpMap.png new file mode 100644 index 0000000..2d18b8e Binary files /dev/null and b/step3_bumpMap.png differ diff --git a/step4_addRim.png b/step4_addRim.png new file mode 100644 index 0000000..bd09448 Binary files /dev/null and b/step4_addRim.png differ diff --git a/step5_addwatersimulation.png b/step5_addwatersimulation.png new file mode 100644 index 0000000..5ac40d6 Binary files /dev/null and b/step5_addwatersimulation.png differ diff --git a/vert_wave.html b/vert_wave.html index 5c7495b..0d8493c 100644 --- a/vert_wave.html +++ b/vert_wave.html @@ -15,29 +15,34 @@