diff --git a/INSTRUCTIONS.md b/INSTRUCTIONS.md new file mode 100644 index 0000000..2d26873 --- /dev/null +++ b/INSTRUCTIONS.md @@ -0,0 +1,362 @@ +------------------------------------------------------------------------------- +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 + +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: +------------------------------------------------------------------------------- + +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) + +Figure 6. Clouds with day time shading. + +![Night with clouds](resources/globe_nightcloud.png) + +Figure 7. Clouds observing city nights on the dark side of the globe. + +**Bump Mapping** + +Add the appearance of mountains by perturbing the normal used for diffuse +lighting the ground (not the clouds) by using the bump map texture, `u_Bump`. +This texture is 1024x512, and is zero when the fragment is at sea-level, and +one when the fragment is on the highest mountain. Read three texels from this +texture: once using `v_Texcoord`; once one texel to the right; and once one +texel above. Create a perturbed normal in tangent space: + +`normalize(vec3(center - right, center - top, 0.2))` + +Use `eastNorthUpToEyeCoordinates` to transform this normal to eye coordinates, +normalize it, then use it for diffuse lighting the ground instead of the +original normal. + +![Globe with bump mapping](resources/globe_bumpmap.png) + +Figure 8. Bump mapping brings attention to mountains. + +**Rim Lighting** + +Rim lighting is a simple post-processed lighting effect we can apply to make +the globe look as if it has an atmospheric layer catching light from the sun. +Implementing rim lighting is simple; we being by finding the dot product of +`v_Normal` and `v_Position`, and add 1 to the dot product. We call this value +our rim factor. If the rim factor is greater than 0, then we add a blue color +based on the rim factor to the current fragment color. You might use a color +something like `vec4(rim/4, rim/2, rim/2, 1)`. If our rim factor is not greater +than 0, then we leave the fragment color as is. Figures 0,1 and 2 show our +finished globe with rim lighting. + +For more information on rim lighting, +read http://www.fundza.com/rman_shaders/surface/rim_effects/index.html. + +------------------------------------------------------------------------------- +GH-PAGES +------------------------------------------------------------------------------- +Since this assignment is in WebGL you will make your project easily viewable by +taking advantage of GitHub's project pages feature. + +Once you are done you will need to create a new branch named gh-pages: + +`git branch gh-pages` + +Switch to your new branch: + +`git checkout gh-pages` + +Create an index.html file that is either your renamed frag_globe.html or +contains a link to it, commit, and then push as usual. Now you can go to + +`.github.io/` + +to see your beautiful globe from anywhere. + +------------------------------------------------------------------------------- +README +------------------------------------------------------------------------------- +All students must replace or augment the contents of this Readme.md in a clear +manner with the following: + +* A brief description of the project and the specific features you implemented. +* At least one screenshot of your project running. +* A 30 second or longer video of your project running. To create the video you + can use http://www.microsoft.com/expression/products/Encoder4_Overview.aspx +* A performance evaluation (described in detail below). + +------------------------------------------------------------------------------- +PERFORMANCE EVALUATION +------------------------------------------------------------------------------- +The performance evaluation is where you will investigate how to make your +program more efficient using the skills you've learned in class. You must have +performed at least one experiment on your code to investigate the positive or +negative effects on performance. + +We encourage you to get creative with your tweaks. Consider places in your code +that could be considered bottlenecks and try to improve them. + +Each student should provide no more than a one page summary of their +optimizations along with tables and or graphs to visually explain any +performance differences. + +In this homework, we do not expect crazy performance evaluation in terms of +optimizations. However, it would be good to take performance benchmarks at +every step in this assignment to see how complicated fragment shaders affect the +overall speed. You can do this by using stats.js. + +------------------------------------------------------------------------------- +THIRD PARTY CODE POLICY +------------------------------------------------------------------------------- +* Use of any third-party code must be approved by asking on the Google groups. + If it is approved, all students are welcome to use it. Generally, we approve + use of third-party code that is not a core part of the project. For example, + for the ray tracer, we would approve using a third-party library for loading + models, but would not approve copying and pasting a CUDA function for doing + refraction. +* Third-party code must be credited in README.md. +* Using third-party code without its approval, including using another + student's code, is an academic integrity violation, and will result in you + receiving an F for the semester. + +------------------------------------------------------------------------------- +SELF-GRADING +------------------------------------------------------------------------------- +* On the submission date, email your grade, on a scale of 0 to 100, to Harmony, + harmoli+cis565@seas.upenn.com, with a one paragraph explanation. Be concise and + realistic. Recall that we reserve 30 points as a sanity check to adjust your + grade. Your actual grade will be (0.7 * your grade) + (0.3 * our grade). We + hope to only use this in extreme cases when your grade does not realistically + reflect your work - it is either too high or too low. In most cases, we plan + to give you the exact grade you suggest. +* Projects are not weighted evenly, e.g., Project 0 doesn't count as much as + the path tracer. We will determine the weighting at the end of the semester + based on the size of each project. + +--- +SUBMISSION +--- +As with the previous project, you should fork this project and work inside of +your fork. Upon completion, commit your finished project back to your fork, and +make a pull request to the master repository. You should include a README.md +file in the root directory detailing the following + +* A brief description of the project and specific features you implemented +* At least one screenshot of your project running. +* A link to a video of your project running. +* Instructions for building and running your project if they differ from the + base code. +* A performance writeup as detailed above. +* A list of all third-party code used. +* This Readme file edited as described above in the README section. diff --git a/README.md b/README.md index 2d26873..e047d99 100644 --- a/README.md +++ b/README.md @@ -3,360 +3,78 @@ CIS565: Project 5: WebGL ------------------------------------------------------------------------------- Fall 2014 ------------------------------------------------------------------------------- -Due Monday 11/03/2014 +Jiatong He ------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -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. - +![globe](https://raw.githubusercontent.com/JivingTechnostic/Project5-WebGL/master/renders/globe.png) ------------------------------------------------------------------------------- -INTRODUCTION: +PART 1 - Mesh Vertex Shader ------------------------------------------------------------------------------- -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. +###Implemented Features -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. +####Sin wave +![sin wave](https://raw.githubusercontent.com/JivingTechnostic/Project5-WebGL/master/renders/sin_wave.png) +Implemented custom color selection using dat.GUI, and basic color interpolation for between the high and low points on the grid. -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. +####Circular ripple wave +![ripple wave](https://raw.githubusercontent.com/JivingTechnostic/Project5-WebGL/master/renders/ripple_wave.png) +This wave spreads out from the center and has an exponential falloff in height as it moves away from the center. +The sin function is based on distance from the center of the grid. ------------------------------------------------------------------------------- -CONTENTS: +PART 2 - Globe Fragment Shader ------------------------------------------------------------------------------- -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: +![Video Demo](https://raw.githubusercontent.com/JivingTechnostic/Project5-WebGL/master/renders/globe_video.mp4) -* A sin-wave based vertex shader: +[Live Demo](http://jivingtechnostic.github.io/Project5-WebGL/) -![Example sin wave grid](resources/sinWaveGrid.png) +###Implemented Features -* One interesting vertex shader of your choice +####Night-time lights on the dark side of the globe +![night lighting](https://raw.githubusercontent.com/JivingTechnostic/Project5-WebGL/master/renders/globe_night.png) +The sphere began with just daylight texture implemented, so I added the code for nighttime texture and added a mix to blend daylight and nighttime. The mix I used keeps full dayColor until the diffuse term < 0.5, and full nightColor on the back of the sphere. -------------------------------------------------------------------------------- -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: +####Specular mapping +![specular lighting](https://raw.githubusercontent.com/JivingTechnostic/Project5-WebGL/master/renders/globe_specular.png) +The sphere originally had specular lighting on all areas. I changed that so that only the water has specular highlights by reading from the specular map. -![Example boring grid](resources/emptyGrid.png) +####Moving clouds +![clouds](https://raw.githubusercontent.com/JivingTechnostic/Project5-WebGL/master/renders/globe_all.png) +Implemented moving clouds by reading in from the cloud map and offsetting texture coordinates by a time value. -* 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: +####Bump mapped terrain +![bump mapping](https://raw.githubusercontent.com/JivingTechnostic/Project5-WebGL/master/renders/globe_labeled.png) +Implemented bump mapping by reading in the current position, one unit up, and one unit right, and calculating a new normal using those values. - ```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; - ``` +####Rim lighting to simulate atmosphere +![rim lighting](https://raw.githubusercontent.com/JivingTechnostic/Project5-WebGL/master/renders/globe_rim.png) +Simple rim lighting using a dot product between the normal and position. - * 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`. +###Extra Feature: Cloud Shadows +![cloud shadows](https://raw.githubusercontent.com/JivingTechnostic/Project5-WebGL/master/renders/globe_labeled.png) +I implemented a rather basic cloud shadow technique for the globe. The logic behind these shadows is that the light (the lit part of the globe) should cast long visible shadows near the day-night borders, and nearly no visible shadows where the globe is closest to the light. You can see this in the image below. - * 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. +![clouds shadows white](https://raw.githubusercontent.com/JivingTechnostic/Project5-WebGL/master/renders/globe_shadows_labeled.png) +Clouds cast shadows to the left on the left (with respect to the light) of the globe, right on the right, and none in the center. -* 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 - -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: -------------------------------------------------------------------------------- - -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) - -Figure 6. Clouds with day time shading. - -![Night with clouds](resources/globe_nightcloud.png) - -Figure 7. Clouds observing city nights on the dark side of the globe. - -**Bump Mapping** - -Add the appearance of mountains by perturbing the normal used for diffuse -lighting the ground (not the clouds) by using the bump map texture, `u_Bump`. -This texture is 1024x512, and is zero when the fragment is at sea-level, and -one when the fragment is on the highest mountain. Read three texels from this -texture: once using `v_Texcoord`; once one texel to the right; and once one -texel above. Create a perturbed normal in tangent space: - -`normalize(vec3(center - right, center - top, 0.2))` - -Use `eastNorthUpToEyeCoordinates` to transform this normal to eye coordinates, -normalize it, then use it for diffuse lighting the ground instead of the -original normal. - -![Globe with bump mapping](resources/globe_bumpmap.png) - -Figure 8. Bump mapping brings attention to mountains. - -**Rim Lighting** - -Rim lighting is a simple post-processed lighting effect we can apply to make -the globe look as if it has an atmospheric layer catching light from the sun. -Implementing rim lighting is simple; we being by finding the dot product of -`v_Normal` and `v_Position`, and add 1 to the dot product. We call this value -our rim factor. If the rim factor is greater than 0, then we add a blue color -based on the rim factor to the current fragment color. You might use a color -something like `vec4(rim/4, rim/2, rim/2, 1)`. If our rim factor is not greater -than 0, then we leave the fragment color as is. Figures 0,1 and 2 show our -finished globe with rim lighting. - -For more information on rim lighting, -read http://www.fundza.com/rman_shaders/surface/rim_effects/index.html. - -------------------------------------------------------------------------------- -GH-PAGES -------------------------------------------------------------------------------- -Since this assignment is in WebGL you will make your project easily viewable by -taking advantage of GitHub's project pages feature. - -Once you are done you will need to create a new branch named gh-pages: - -`git branch gh-pages` - -Switch to your new branch: - -`git checkout gh-pages` - -Create an index.html file that is either your renamed frag_globe.html or -contains a link to it, commit, and then push as usual. Now you can go to - -`.github.io/` - -to see your beautiful globe from anywhere. - -------------------------------------------------------------------------------- -README -------------------------------------------------------------------------------- -All students must replace or augment the contents of this Readme.md in a clear -manner with the following: - -* A brief description of the project and the specific features you implemented. -* At least one screenshot of your project running. -* A 30 second or longer video of your project running. To create the video you - can use http://www.microsoft.com/expression/products/Encoder4_Overview.aspx -* A performance evaluation (described in detail below). +All I did to implement this was to sample the cloud density some distance along the direction of light - position, and shifted the density to range from [0.5, 1]. Then I used it as a multiplier on the base daylight texture color. The [0.5, 1] range was chosen because I didn't want the shadows to be too dark. ------------------------------------------------------------------------------- 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. +To determine where to best start with the performance evaluation, I began by comparing the ms/frame of the globe with all shaders on, and with only a color=white fragment shader. However, both values were so low (10-20 ms, 50-60 fps) that I couldn't determine if the calculations actually made a significant impact on the code. -We encourage you to get creative with your tweaks. Consider places in your code -that could be considered bottlenecks and try to improve them. +This being the case, I don't think that I will be able to actually measure any improvements on the code. However, looking at frag_globe.js, I have identified some areas in animate() that could be improved. -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. +####Calculating the model matrix +The model matrix begins as an identity matrix, and is then taken through 3 separate rotation calculations. Two of these rotations are constant: -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. +>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]); -------------------------------------------------------------------------------- -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. +And don't need to be calculated every single animate() call. ---- -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 +####Calculating the light vectors +Similarly, the light vectors do not change over time, and are constants. As such, they do not need to be created every single animate() call. -* 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. +####Mipmapping +I don't think that this will change the performance significantly, and it's fairly limited because the user specifies the distance from the camera to the globe, but we can use lower-resolution textures for zoomed out shots. However, there isn't a large range of possible levels of detail, so the benefits of mipmapping are marginal at best. diff --git a/frag_globe.html b/frag_globe.html index e074492..efc02ed 100644 --- a/frag_globe.html +++ b/frag_globe.html @@ -60,6 +60,7 @@ uniform sampler2D u_EarthSpec; //Bump map uniform sampler2D u_Bump; + uniform vec2 u_BumpResolution; uniform float u_time; uniform mat4 u_InvTrans; @@ -73,8 +74,15 @@ void main(void) { - // surface normal - normalized after rasterization - vec3 normal = normalize(v_Normal); + // Bump Mapping + float bumpCenter = texture2D(u_Bump, v_Texcoord).r; + float bumpTop = texture2D(u_Bump, v_Texcoord + vec2(0, 1.0 / u_BumpResolution.y)).r; + float bumpRight = texture2D(u_Bump, v_Texcoord + vec2(1.0 / u_BumpResolution.x, 0)).r; + + vec3 bump_normal = normalize(vec3(bumpCenter - bumpRight, bumpCenter - bumpTop, 0.2)); + + vec3 normal = normalize(eastNorthUpToEyeCoordinates(v_positionMC, v_Normal) * bump_normal); + // normalized eye-to-position vector in camera coordinates vec3 eyeToPosition = normalize(v_Position); @@ -86,12 +94,43 @@ 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 dayTextureColor = texture2D(u_DayDiffuse, v_Texcoord).rgb; + vec3 nightTextureColor = texture2D(u_Night, v_Texcoord).rgb; + + // Reads from a black-white specular map, white (1) = full specular, black (0) = none. + // Only reads the 'r' property because it should be grayscale. + float specularCoeff = texture2D(u_EarthSpec, v_Texcoord).r; + + // Cloud Textures + vec2 cloud_Texcoord = vec2(v_Texcoord.s + u_time, v_Texcoord.t); + vec3 cloudTextureColor = texture2D(u_Cloud, cloud_Texcoord).rgb; + + // Reads from a black-white transparency map, white (1) = transparent, black (0) = opaque. + // Only reads the 'r' property because it should be grayscale. + float cloudTrans = texture2D(u_CloudTrans, cloud_Texcoord).r; + + // Compute shadows from clouds, based on light position with respect to cloud position. + // Currently *shouldn't* work for all cases, in theory it cloudDirection needs to be transformed into the + // coordinate space of the + vec3 cloudDirection = v_Position - u_CameraSpaceDirLight; + // The 100 is simply a hardcoded height value (lower values mean the clouds are higher). + float cloudShadow = texture2D(u_CloudTrans, cloud_Texcoord - cloudDirection.xy / 100.0).x; + + // Kdiffuse = 0.6, Kspecular = 0.4. + float diffuseCoeff = 0.6 + 0.4 * (1.0 - specularCoeff); + specularCoeff *= 0.4; + + // Calculate day colour with blinn-phong shading, and mix in cloud color and shadows. + vec3 dayColor = mix(cloudTextureColor, ((diffuseCoeff * diffuse) + (specularCoeff * specular)) * dayTextureColor * (cloudShadow / 2.0 + 0.5), cloudTrans); + + // Apply gamma correction to nighttime texture, and mix in clouds (black) + vec3 nightColor = mix(vec3(0.0), pow(nightTextureColor,vec3(gammaCorrect)), cloudTrans); - vec3 color = ((0.6 * diffuse) + (0.4 * specular)) * dayColor; + float rimFactor = clamp(dot(v_Normal, v_Position) + 1.0, 0.0, 2.0); + + // Currently using a full gradient mix with a more heavily-weighted night because I don't really like how it treats half the world as a flat plane + // Full dayColor until diffuse < 0.5, and full nightColor on the back of the sphere. + vec3 color = mix(dayColor, nightColor, clamp(1.0 - 2.0 * diffuse, 0.0, 1.0)) + vec3(rimFactor / 4.0, rimFactor / 3.0, rimFactor / 2.0); gl_FragColor = vec4(color, 1.0); } @@ -111,6 +150,7 @@ } + diff --git a/js/frag_globe.js b/js/frag_globe.js index f37830d..f62ff57 100644 --- a/js/frag_globe.js +++ b/js/frag_globe.js @@ -21,6 +21,10 @@ return; } + var stats = new Stats(); + stats.setMode(0); + document.body.appendChild(stats.domElement); + /////////////////////////////////////////////////////////////////////////// gl.viewport(0, 0, canvas.width, canvas.height); @@ -54,6 +58,7 @@ var u_CloudTransLocation; var u_EarthSpecLocation; var u_BumpLocation; + var u_BumpResolutionLocation; var u_timeLocation; (function initializeShader() { @@ -74,6 +79,7 @@ u_CloudTransLocation = gl.getUniformLocation(program,"u_CloudTrans"); u_EarthSpecLocation = gl.getUniformLocation(program,"u_EarthSpec"); u_BumpLocation = gl.getUniformLocation(program,"u_Bump"); + u_BumpResolutionLocation = gl.getUniformLocation(program, "u_BumpResolution"); u_timeLocation = gl.getUniformLocation(program,"u_time"); u_CameraSpaceDirLightLocation = gl.getUniformLocation(program,"u_CameraSpaceDirLight"); @@ -237,7 +243,8 @@ function animate() { /////////////////////////////////////////////////////////////////////////// // Update - + stats.end(); + stats.begin(); var model = mat4.create(); mat4.identity(model); mat4.rotate(model, 23.4/180*Math.PI, [0.0, 0.0, 1.0]); @@ -286,7 +293,9 @@ gl.activeTexture(gl.TEXTURE5); gl.bindTexture(gl.TEXTURE_2D, specTex); gl.uniform1i(u_EarthSpecLocation, 5); + gl.uniform2f(u_BumpResolutionLocation, 1024, 512); gl.drawElements(gl.TRIANGLES, numberOfIndices, gl.UNSIGNED_SHORT,0); + gl.uniform1f(u_timeLocation, time); time += 0.001; window.requestAnimFrame(animate); diff --git a/js/stats/build/stats.min.js b/js/stats/build/stats.min.js new file mode 100644 index 0000000..52539f4 --- /dev/null +++ b/js/stats/build/stats.min.js @@ -0,0 +1,6 @@ +// stats.js - http://github.com/mrdoob/stats.js +var Stats=function(){var l=Date.now(),m=l,g=0,n=Infinity,o=0,h=0,p=Infinity,q=0,r=0,s=0,f=document.createElement("div");f.id="stats";f.addEventListener("mousedown",function(b){b.preventDefault();t(++s%2)},!1);f.style.cssText="width:80px;opacity:0.9;cursor:pointer";var a=document.createElement("div");a.id="fps";a.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#002";f.appendChild(a);var i=document.createElement("div");i.id="fpsText";i.style.cssText="color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px"; +i.innerHTML="FPS";a.appendChild(i);var c=document.createElement("div");c.id="fpsGraph";c.style.cssText="position:relative;width:74px;height:30px;background-color:#0ff";for(a.appendChild(c);74>c.children.length;){var j=document.createElement("span");j.style.cssText="width:1px;height:30px;float:left;background-color:#113";c.appendChild(j)}var d=document.createElement("div");d.id="ms";d.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#020;display:none";f.appendChild(d);var k=document.createElement("div"); +k.id="msText";k.style.cssText="color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";k.innerHTML="MS";d.appendChild(k);var e=document.createElement("div");e.id="msGraph";e.style.cssText="position:relative;width:74px;height:30px;background-color:#0f0";for(d.appendChild(e);74>e.children.length;)j=document.createElement("span"),j.style.cssText="width:1px;height:30px;float:left;background-color:#131",e.appendChild(j);var t=function(b){s=b;switch(s){case 0:a.style.display= +"block";d.style.display="none";break;case 1:a.style.display="none",d.style.display="block"}};return{REVISION:12,domElement:f,setMode:t,begin:function(){l=Date.now()},end:function(){var b=Date.now();g=b-l;n=Math.min(n,g);o=Math.max(o,g);k.textContent=g+" MS ("+n+"-"+o+")";var a=Math.min(30,30-30*(g/200));e.appendChild(e.firstChild).style.height=a+"px";r++;b>m+1E3&&(h=Math.round(1E3*r/(b-m)),p=Math.min(p,h),q=Math.max(q,h),i.textContent=h+" FPS ("+p+"-"+q+")",a=Math.min(30,30-30*(h/100)),c.appendChild(c.firstChild).style.height= +a+"px",m=b,r=0);return b},update:function(){l=this.end()}}};"object"===typeof module&&(module.exports=Stats); diff --git a/js/stats/src/Stats.js b/js/stats/src/Stats.js new file mode 100644 index 0000000..90b2a27 --- /dev/null +++ b/js/stats/src/Stats.js @@ -0,0 +1,149 @@ +/** + * @author mrdoob / http://mrdoob.com/ + */ + +var Stats = function () { + + var startTime = Date.now(), prevTime = startTime; + var ms = 0, msMin = Infinity, msMax = 0; + var fps = 0, fpsMin = Infinity, fpsMax = 0; + var frames = 0, mode = 0; + + var container = document.createElement( 'div' ); + container.id = 'stats'; + container.addEventListener( 'mousedown', function ( event ) { event.preventDefault(); setMode( ++ mode % 2 ) }, false ); + container.style.cssText = 'width:80px;opacity:0.9;cursor:pointer'; + + var fpsDiv = document.createElement( 'div' ); + fpsDiv.id = 'fps'; + fpsDiv.style.cssText = 'padding:0 0 3px 3px;text-align:left;background-color:#002'; + container.appendChild( fpsDiv ); + + var fpsText = document.createElement( 'div' ); + fpsText.id = 'fpsText'; + fpsText.style.cssText = 'color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px'; + fpsText.innerHTML = 'FPS'; + fpsDiv.appendChild( fpsText ); + + var fpsGraph = document.createElement( 'div' ); + fpsGraph.id = 'fpsGraph'; + fpsGraph.style.cssText = 'position:relative;width:74px;height:30px;background-color:#0ff'; + fpsDiv.appendChild( fpsGraph ); + + while ( fpsGraph.children.length < 74 ) { + + var bar = document.createElement( 'span' ); + bar.style.cssText = 'width:1px;height:30px;float:left;background-color:#113'; + fpsGraph.appendChild( bar ); + + } + + var msDiv = document.createElement( 'div' ); + msDiv.id = 'ms'; + msDiv.style.cssText = 'padding:0 0 3px 3px;text-align:left;background-color:#020;display:none'; + container.appendChild( msDiv ); + + var msText = document.createElement( 'div' ); + msText.id = 'msText'; + msText.style.cssText = 'color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px'; + msText.innerHTML = 'MS'; + msDiv.appendChild( msText ); + + var msGraph = document.createElement( 'div' ); + msGraph.id = 'msGraph'; + msGraph.style.cssText = 'position:relative;width:74px;height:30px;background-color:#0f0'; + msDiv.appendChild( msGraph ); + + while ( msGraph.children.length < 74 ) { + + var bar = document.createElement( 'span' ); + bar.style.cssText = 'width:1px;height:30px;float:left;background-color:#131'; + msGraph.appendChild( bar ); + + } + + var setMode = function ( value ) { + + mode = value; + + switch ( mode ) { + + case 0: + fpsDiv.style.display = 'block'; + msDiv.style.display = 'none'; + break; + case 1: + fpsDiv.style.display = 'none'; + msDiv.style.display = 'block'; + break; + } + + }; + + var updateGraph = function ( dom, value ) { + + var child = dom.appendChild( dom.firstChild ); + child.style.height = value + 'px'; + + }; + + return { + + REVISION: 12, + + domElement: container, + + setMode: setMode, + + begin: function () { + + startTime = Date.now(); + + }, + + end: function () { + + var time = Date.now(); + + ms = time - startTime; + msMin = Math.min( msMin, ms ); + msMax = Math.max( msMax, ms ); + + msText.textContent = ms + ' MS (' + msMin + '-' + msMax + ')'; + updateGraph( msGraph, Math.min( 30, 30 - ( ms / 200 ) * 30 ) ); + + frames ++; + + if ( time > prevTime + 1000 ) { + + fps = Math.round( ( frames * 1000 ) / ( time - prevTime ) ); + fpsMin = Math.min( fpsMin, fps ); + fpsMax = Math.max( fpsMax, fps ); + + fpsText.textContent = fps + ' FPS (' + fpsMin + '-' + fpsMax + ')'; + updateGraph( fpsGraph, Math.min( 30, 30 - ( fps / 100 ) * 30 ) ); + + prevTime = time; + frames = 0; + + } + + return time; + + }, + + update: function () { + + startTime = this.end(); + + } + + } + +}; + +if ( typeof module === 'object' ) { + + module.exports = Stats; + +} \ No newline at end of file diff --git a/renders/globe.png b/renders/globe.png new file mode 100644 index 0000000..de2c55c Binary files /dev/null and b/renders/globe.png differ diff --git a/renders/globe_all.png b/renders/globe_all.png new file mode 100644 index 0000000..7c08c24 Binary files /dev/null and b/renders/globe_all.png differ diff --git a/renders/globe_day.png b/renders/globe_day.png new file mode 100644 index 0000000..b60f2b1 Binary files /dev/null and b/renders/globe_day.png differ diff --git a/renders/globe_labeled.png b/renders/globe_labeled.png new file mode 100644 index 0000000..715f9bc Binary files /dev/null and b/renders/globe_labeled.png differ diff --git a/renders/globe_middle.png b/renders/globe_middle.png new file mode 100644 index 0000000..4280b43 Binary files /dev/null and b/renders/globe_middle.png differ diff --git a/renders/globe_night.png b/renders/globe_night.png new file mode 100644 index 0000000..a19e965 Binary files /dev/null and b/renders/globe_night.png differ diff --git a/renders/globe_rim.png b/renders/globe_rim.png new file mode 100644 index 0000000..c084939 Binary files /dev/null and b/renders/globe_rim.png differ diff --git a/renders/globe_shadows.png b/renders/globe_shadows.png new file mode 100644 index 0000000..f4f63b7 Binary files /dev/null and b/renders/globe_shadows.png differ diff --git a/renders/globe_shadows_labeled.png b/renders/globe_shadows_labeled.png new file mode 100644 index 0000000..8d9b76f Binary files /dev/null and b/renders/globe_shadows_labeled.png differ diff --git a/renders/globe_specular.png b/renders/globe_specular.png new file mode 100644 index 0000000..dd2c4db Binary files /dev/null and b/renders/globe_specular.png differ diff --git a/renders/globe_video.mp4 b/renders/globe_video.mp4 new file mode 100644 index 0000000..7f0a85c Binary files /dev/null and b/renders/globe_video.mp4 differ diff --git a/renders/performance.png b/renders/performance.png new file mode 100644 index 0000000..39d815b Binary files /dev/null and b/renders/performance.png differ diff --git a/renders/ripple_wave.png b/renders/ripple_wave.png new file mode 100644 index 0000000..f23647e Binary files /dev/null and b/renders/ripple_wave.png differ diff --git a/renders/sin_wave.png b/renders/sin_wave.png new file mode 100644 index 0000000..3fe93fc Binary files /dev/null and b/renders/sin_wave.png differ diff --git a/vert_ripple.html b/vert_ripple.html new file mode 100644 index 0000000..2c73304 --- /dev/null +++ b/vert_ripple.html @@ -0,0 +1,256 @@ + + + +Vertex Ripple + + + + + +
+ + + + + + + + + + + + + + diff --git a/vert_wave.html b/vert_wave.html index 5c7495b..3a67951 100644 --- a/vert_wave.html +++ b/vert_wave.html @@ -14,30 +14,38 @@