diff --git a/README.md b/README.md index 2d26873..32e4ecb 100644 --- a/README.md +++ b/README.md @@ -1,362 +1,70 @@ -------------------------------------------------------------------------------- +------------------------------------------------------------------------------- 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. +![final rendering](https://raw.githubusercontent.com/XJMa/Project5-WebGL/master/result/pic1.gif) -------------------------------------------------------------------------------- -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. +demo link: +https://www.youtube.com/watch?v=-qVH-0hQkc0&feature=youtu.be ------------------------------------------------------------------------------- -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 - +Part1: ------------------------------------------------------------------------------- -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. +In the first part of this project, I implemented a GLSL vertex shader as +part of a WebGL demo. +![simple wave](https://raw.githubusercontent.com/XJMa/Project5-WebGL/master/result/part11.gif) +custom vertex shader: Each vertex's color depend on its height. Height will change according to a sin function based on +the distance between this vertex and the center. +![custom wave](https://raw.githubusercontent.com/XJMa/Project5-WebGL/master/result/part12.gif) ------------------------------------------------------------------------------- -PART 2 WALKTHROUGH: +Part2: ------------------------------------------------------------------------------- +In the second part of this project, I implemented a GLSL fragment shader +to render an interactive globe in WebGL. This include texture blending, +bump mapping, specular masking, and adding a cloud layer to give globe a +uniquie feel. -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) +Given code: -Figure 7. Clouds observing city nights on the dark side of the globe. +*Rendering a sphere with textures mapped on -**Bump Mapping** +*Basic passthrough fragment and vertex shaders -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: +*A basic globe with Earth terrain color mapping -`normalize(vec3(center - right, center - top, 0.2))` +*Gamma correcting textures -Use `eastNorthUpToEyeCoordinates` to transform this normal to eye coordinates, -normalize it, then use it for diffuse lighting the ground instead of the -original normal. +*Javascript to interact with the mouse -![Globe with bump mapping](resources/globe_bumpmap.png) +*Left-click and drag moves the camera around -Figure 8. Bump mapping brings attention to mountains. +*Right-click and drag moves the camera in and out -**Rim Lighting** +Implemented: -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. +*Bump mapped terrain -For more information on rim lighting, -read http://www.fundza.com/rman_shaders/surface/rim_effects/index.html. +*Rim lighting to simulate atmosphere -------------------------------------------------------------------------------- -GH-PAGES -------------------------------------------------------------------------------- -Since this assignment is in WebGL you will make your project easily viewable by -taking advantage of GitHub's project pages feature. +*Night-time lights on the dark side of the globe -Once you are done you will need to create a new branch named gh-pages: +*Specular mapping -`git branch gh-pages` +*Moving clouds -Switch to your new branch: -`git checkout gh-pages` +I also implemented Cloud shadows via ray-tracing through the cloud map in the fragment shader -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 +result without cloud shadows: -`.github.io/` +![without cloud shadow](https://raw.githubusercontent.com/XJMa/Project5-WebGL/master/result/withoutshadow.jpg) -to see your beautiful globe from anywhere. +result with cloud shadows: +![without cloud shadow](https://raw.githubusercontent.com/XJMa/Project5-WebGL/master/result/withshadow.jpg) ------------------------------------------------------------------------------- -README +Performance Evaluation ------------------------------------------------------------------------------- -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 feature I implemented in this project seems has little influnce in the performance. The FPS hardly change no matter I added these features or not. diff --git a/Xinjie_frag_globe - Copy.html b/Xinjie_frag_globe - Copy.html new file mode 100644 index 0000000..1f87b3c --- /dev/null +++ b/Xinjie_frag_globe - Copy.html @@ -0,0 +1,176 @@ + + + +Fragment Globe + + + + + +
+ + + + + + + + + + + + diff --git a/frag_globe.html b/frag_globe.html index e074492..a864201 100644 --- a/frag_globe.html +++ b/frag_globe.html @@ -45,7 +45,7 @@ //View-Space directional light //A unit vector uniform vec3 u_CameraSpaceDirLight; - + uniform vec3 u_DirLight; //Diffuse texture map for the day uniform sampler2D u_DayDiffuse; //Ambient texture map for the night side @@ -75,6 +75,26 @@ { // surface normal - normalized after rasterization vec3 normal = normalize(v_Normal); + float EarthSpec = texture2D(u_EarthSpec, v_Texcoord).r; + float diffpart = 0.6,specpart = 0.4; + float center = 0.0,right=0.0,above = 0.0; + //vec3 normal= normalize(vec3(0.0, 0.0, 0.2)); + if(EarthSpec<0.5){//bump map + center = texture2D(u_Bump, v_Texcoord).r; + float r = clamp(v_Texcoord.s + 1.0/1024.0, 0.0, 1.0); + if(v_Texcoord.s*1024.0 + 1.0>1024.0) + r = 1.0/1024.0; + + right = texture2D(u_Bump, vec2(r,v_Texcoord.t)).r; + float u = clamp(v_Texcoord.t + 1.0/512.0, 0.0, 1.0); + if(v_Texcoord.t*512.0 + 1.0>512.0) + u = 1.0/512.0; + + above = texture2D(u_Bump, vec2(v_Texcoord.s,u)).r; + normal = normalize(vec3(center - right, center - above, 0.2)); + } + normal = eastNorthUpToEyeCoordinates(v_positionMC,v_Normal) * normal; + normal = normalize(normal); // normalized eye-to-position vector in camera coordinates vec3 eyeToPosition = normalize(v_Position); @@ -90,9 +110,46 @@ 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); + + + + //Clouds + vec2 v_Texcoord2 = v_Texcoord - vec2(u_time * 0.2, 0.0); + vec3 cloudsColor = texture2D(u_Cloud,v_Texcoord2).rgb; + float cloudMix = texture2D(u_CloudTrans,v_Texcoord2).r; + //cloud shadow + mat3 transformMatrix = eastNorthUpToEyeCoordinates(v_positionMC, normalize(v_Normal)); + vec3 cloudShadowOffset = transformMatrix * u_DirLight; + vec2 cloudShadowOffset2 = v_Texcoord2 + vec2(-cloudShadowOffset.x * 0.01,-cloudShadowOffset.y * 0.01); + //vec2 v_TexcoordCloudShadow = vec2(v_Texcoord.s - 0.01 * u_time,v_Texcoord.t) + vec2(-u_CameraSpaceDirLight.x*0.007, -u_CameraSpaceDirLight.y*0.007); + float cloudTransShadow = texture2D(u_CloudTrans, cloudShadowOffset2).r; + + dayColor = mix((0.6 * diffuse + 0.4 * specular*EarthSpec )* dayColor, vec3(0.0,0.0,0.0), 1.0-cloudTransShadow); + //dayColor =(0.6 * diffuse + 0.4 * specular*EarthSpec )* dayColor; + dayColor = mix(cloudsColor, dayColor, cloudMix); + nightColor = 1.5 * mix(vec3(0.0,0.0,0.0),nightColor,cloudMix); + + //night lights + float rperiod = 0.1; // transition from day to night + float diffjudge = dot(u_CameraSpaceDirLight, normal); + vec3 color; + if(diffjudge >= rperiod) + color = dayColor; + else if(diffjudge <= -rperiod) + color = nightColor; + else + { + float alpha = (diffjudge + rperiod)/(2.0*rperiod); + color = mix(nightColor,dayColor,alpha); + } + //Rim Lighting + float rim = dot(v_Normal,v_Position) + 1.5; + vec3 rimcolor = vec3(0.0,0.0,0.0); + if(rim>0.0) + rimcolor = vec3(rim/4.0, rim/2.0, rim/2.0); + + rimcolor = clamp(rimcolor, vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0)); + gl_FragColor = vec4(color + rimcolor, 1.0); } mat3 eastNorthUpToEyeCoordinates(vec3 positionMC, vec3 normalEC) diff --git a/js/frag_globe.js b/js/frag_globe.js index f37830d..cfa4753 100644 --- a/js/frag_globe.js +++ b/js/frag_globe.js @@ -48,6 +48,7 @@ var u_ViewLocation; var u_PerspLocation; var u_CameraSpaceDirLightLocation; + var u_DirLightLocation;//for cloud shadow var u_DayDiffuseLocation; var u_NightLocation; var u_CloudLocation; @@ -76,7 +77,7 @@ u_BumpLocation = gl.getUniformLocation(program,"u_Bump"); u_timeLocation = gl.getUniformLocation(program,"u_time"); u_CameraSpaceDirLightLocation = gl.getUniformLocation(program,"u_CameraSpaceDirLight"); - + u_DirLightLocation = gl.getUniformLocation(program,"u_DirLight"); gl.useProgram(program); })(); @@ -267,7 +268,7 @@ gl.uniformMatrix4fv(u_InvTransLocation, false, invTrans); gl.uniform3fv(u_CameraSpaceDirLightLocation, lightdir); - + gl.uniform3fv(u_DirLightLocation, vec3.create([1.0, 0.0, 1.0])); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, dayTex); gl.uniform1i(u_DayDiffuseLocation, 0); @@ -287,7 +288,7 @@ gl.bindTexture(gl.TEXTURE_2D, specTex); gl.uniform1i(u_EarthSpecLocation, 5); gl.drawElements(gl.TRIANGLES, numberOfIndices, gl.UNSIGNED_SHORT,0); - + gl.uniform1f(u_timeLocation, time); time += 0.001; window.requestAnimFrame(animate); } diff --git a/js/frag_globe.js.bak b/js/frag_globe.js.bak new file mode 100644 index 0000000..4208056 --- /dev/null +++ b/js/frag_globe.js.bak @@ -0,0 +1,316 @@ +(function() { + "use strict"; + /*global window,document,Float32Array,Uint16Array,mat4,vec3,snoise*/ + /*global getShaderSource,createWebGLContext,createProgram*/ + + function sphericalToCartesian( r, a, e ) { + var x = r * Math.cos(e) * Math.cos(a); + var y = r * Math.sin(e); + var z = r * Math.cos(e) * Math.sin(a); + + return [x,y,z]; + } + + var NUM_WIDTH_PTS = 64; + var NUM_HEIGHT_PTS = 64; + + var message = document.getElementById("message"); + var canvas = document.getElementById("canvas"); + var gl = createWebGLContext(canvas, message); + if (!gl) { + return; + } + + /////////////////////////////////////////////////////////////////////////// + + gl.viewport(0, 0, canvas.width, canvas.height); + gl.clearColor(0.0, 0.0, 0.0, 1.0); + gl.enable(gl.DEPTH_TEST); + + var persp = mat4.create(); + mat4.perspective(45.0, canvas.width/canvas.height, 0.1, 100.0, persp); + + var radius = 5.0; + var azimuth = Math.PI; + var elevation = 0.0001; + + var eye = sphericalToCartesian(radius, azimuth, elevation); + var center = [0.0, 0.0, 0.0]; + var up = [0.0, 1.0, 0.0]; + var view = mat4.create(); + mat4.lookAt(eye, center, up, view); + + var positionLocation; + var normalLocation; + var texCoordLocation; + var u_InvTransLocation; + var u_ModelLocation; + var u_ViewLocation; + var u_PerspLocation; + var u_CameraSpaceDirLightLocation; + var u_DayDiffuseLocation; + var u_NightLocation; + var u_CloudLocation; + var u_CloudTransLocation; + var u_EarthSpecLocation; + var u_BumpLocation; + var u_timeLocation; + + (function initializeShader() { + var vs = getShaderSource(document.getElementById("vs")); + var fs = getShaderSource(document.getElementById("fs")); + + var program = createProgram(gl, vs, fs, message); + positionLocation = gl.getAttribLocation(program, "Position"); + normalLocation = gl.getAttribLocation(program, "Normal"); + texCoordLocation = gl.getAttribLocation(program, "Texcoord"); + u_ModelLocation = gl.getUniformLocation(program,"u_Model"); + u_ViewLocation = gl.getUniformLocation(program,"u_View"); + u_PerspLocation = gl.getUniformLocation(program,"u_Persp"); + u_InvTransLocation = gl.getUniformLocation(program,"u_InvTrans"); + u_DayDiffuseLocation = gl.getUniformLocation(program,"u_DayDiffuse"); + u_NightLocation = gl.getUniformLocation(program,"u_Night"); + u_CloudLocation = gl.getUniformLocation(program,"u_Cloud"); + u_CloudTransLocation = gl.getUniformLocation(program,"u_CloudTrans"); + u_EarthSpecLocation = gl.getUniformLocation(program,"u_EarthSpec"); + u_BumpLocation = gl.getUniformLocation(program,"u_Bump"); + u_timeLocation = gl.getUniformLocation(program,"u_time"); + u_CameraSpaceDirLightLocation = gl.getUniformLocation(program,"u_CameraSpaceDirLight"); + + 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(); + + function initLoadedTexture(texture){ + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + gl.bindTexture(gl.TEXTURE_2D, null); + } + + var numberOfIndices; + + (function initializeSphere() { + function uploadMesh(positions, texCoords, indices) { + // Positions + var positionsName = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, positionsName); + gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW); + gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(positionLocation); + + // Normals + var normalsName = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, normalsName); + gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW); + gl.vertexAttribPointer(normalLocation, 3, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(normalLocation); + + // TextureCoords + var texCoordsName = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, texCoordsName); + gl.bufferData(gl.ARRAY_BUFFER, texCoords, gl.STATIC_DRAW); + gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(texCoordLocation); + + // Indices + var indicesName = gl.createBuffer(); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesName); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW); + } + + var WIDTH_DIVISIONS = NUM_WIDTH_PTS - 1; + var HEIGHT_DIVISIONS = NUM_HEIGHT_PTS - 1; + + var numberOfPositions = NUM_WIDTH_PTS * NUM_HEIGHT_PTS; + + var positions = new Float32Array(3 * numberOfPositions); + var texCoords = new Float32Array(2 * numberOfPositions); + var indices = new Uint16Array(6 * (WIDTH_DIVISIONS * HEIGHT_DIVISIONS)); + + var positionsIndex = 0; + var texCoordsIndex = 0; + var indicesIndex = 0; + var length; + + for( var j = 0; j < NUM_HEIGHT_PTS; ++j ) + { + var inclination = Math.PI * (j / HEIGHT_DIVISIONS); + for( var i = 0; i < NUM_WIDTH_PTS; ++i ) + { + var azimuth = 2 * Math.PI * (i / WIDTH_DIVISIONS); + positions[positionsIndex++] = Math.sin(inclination)*Math.cos(azimuth); + positions[positionsIndex++] = Math.cos(inclination); + positions[positionsIndex++] = Math.sin(inclination)*Math.sin(azimuth); + texCoords[texCoordsIndex++] = i / WIDTH_DIVISIONS; + texCoords[texCoordsIndex++] = j / HEIGHT_DIVISIONS; + } + } + + for( var j = 0; j < HEIGHT_DIVISIONS; ++j ) + { + var index = j*NUM_WIDTH_PTS; + for( var i = 0; i < WIDTH_DIVISIONS; ++i ) + { + indices[indicesIndex++] = index + i; + indices[indicesIndex++] = index + i+1; + indices[indicesIndex++] = index + i+NUM_WIDTH_PTS; + indices[indicesIndex++] = index + i+NUM_WIDTH_PTS; + indices[indicesIndex++] = index + i+1; + indices[indicesIndex++] = index + i+NUM_WIDTH_PTS+1; + } + } + + uploadMesh(positions, texCoords, indices); + numberOfIndices = indicesIndex; + })(); + + var time = 0; + var mouseLeftDown = false; + var mouseRightDown = false; + var lastMouseX = null; + var lastMouseY = null; + + function handleMouseDown(event) { + if( event.button == 2 ) { + mouseLeftDown = false; + mouseRightDown = true; + } + else { + mouseLeftDown = true; + mouseRightDown = false; + } + lastMouseX = event.clientX; + lastMouseY = event.clientY; + } + + function handleMouseUp(event) { + mouseLeftDown = false; + mouseRightDown = false; + } + + function handleMouseMove(event) { + if (!(mouseLeftDown || mouseRightDown)) { + return; + } + var newX = event.clientX; + var newY = event.clientY; + + var deltaX = newX - lastMouseX; + var deltaY = newY - lastMouseY; + + if( mouseLeftDown ) + { + azimuth += 0.01 * deltaX; + elevation += 0.01 * deltaY; + elevation = Math.min(Math.max(elevation, -Math.PI/2+0.001), Math.PI/2-0.001); + } + else + { + radius += 0.01 * deltaY; + radius = Math.min(Math.max(radius, 2.0), 10.0); + } + eye = sphericalToCartesian(radius, azimuth, elevation); + view = mat4.create(); + mat4.lookAt(eye, center, up, view); + + lastMouseX = newX; + lastMouseY = newY; + } + + canvas.onmousedown = handleMouseDown; + canvas.oncontextmenu = function(ev) {return false;}; + document.onmouseup = handleMouseUp; + document.onmousemove = handleMouseMove; + + + function animate() { + /////////////////////////////////////////////////////////////////////////// + // Update + + var model = mat4.create(); + mat4.identity(model); + mat4.rotate(model, 23.4/180*Math.PI, [0.0, 0.0, 1.0]); + mat4.rotate(model, Math.PI, [1.0, 0.0, 0.0]); + mat4.rotate(model, -time, [0.0, 1.0, 0.0]); + var mv = mat4.create(); + mat4.multiply(view, model, mv); + + var invTrans = mat4.create(); + mat4.inverse(mv, invTrans); + mat4.transpose(invTrans); + + var lightdir = vec3.create([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]); + vec3.normalize(lightdir); + + /////////////////////////////////////////////////////////////////////////// + // 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.uniform3fv(u_CameraSpaceDirLightLocation, lightdir); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, dayTex); + gl.uniform1i(u_DayDiffuseLocation, 0); + gl.activeTexture(gl.TEXTURE1); + gl.bindTexture(gl.TEXTURE_2D, bumpTex); + gl.uniform1i(u_BumpLocation, 1); + gl.activeTexture(gl.TEXTURE2); + gl.bindTexture(gl.TEXTURE_2D, cloudTex); + gl.uniform1i(u_CloudLocation, 2); + gl.activeTexture(gl.TEXTURE3); + gl.bindTexture(gl.TEXTURE_2D, transTex); + gl.uniform1i(u_CloudTransLocation, 3); + gl.activeTexture(gl.TEXTURE4); + gl.bindTexture(gl.TEXTURE_2D, lightTex); + gl.uniform1i(u_NightLocation, 4); + gl.activeTexture(gl.TEXTURE5); + gl.bindTexture(gl.TEXTURE_2D, specTex); + gl.uniform1i(u_EarthSpecLocation, 5); + gl.drawElements(gl.TRIANGLES, numberOfIndices, gl.UNSIGNED_SHORT,0); + gl.uniform1f(u_timeLocation, time); + 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, "assets/earthmap1024.png"); + initializeTexture(bumpTex, "assets/earthbump1024.png"); + initializeTexture(cloudTex, "assets/earthcloud1024.png"); + initializeTexture(transTex, "assets/earthtrans1024.png"); + initializeTexture(lightTex, "assets/earthlight1024.png"); + initializeTexture(specTex, "assets/earthspec1024.png"); +}()); diff --git a/result/part11.gif b/result/part11.gif new file mode 100644 index 0000000..f8cf316 Binary files /dev/null and b/result/part11.gif differ diff --git a/result/part12.gif b/result/part12.gif new file mode 100644 index 0000000..50b2061 Binary files /dev/null and b/result/part12.gif differ diff --git a/result/pic1.gif b/result/pic1.gif new file mode 100644 index 0000000..db1341b Binary files /dev/null and b/result/pic1.gif differ diff --git a/result/pic1noshadow.gif b/result/pic1noshadow.gif new file mode 100644 index 0000000..60eb747 Binary files /dev/null and b/result/pic1noshadow.gif differ diff --git a/result/project5_webGL.wmv b/result/project5_webGL.wmv new file mode 100644 index 0000000..6f7d844 Binary files /dev/null and b/result/project5_webGL.wmv differ diff --git a/result/withoutshadow.jpg b/result/withoutshadow.jpg new file mode 100644 index 0000000..6000330 Binary files /dev/null and b/result/withoutshadow.jpg differ diff --git a/result/withshadow.jpg b/result/withshadow.jpg new file mode 100644 index 0000000..afaac91 Binary files /dev/null and b/result/withshadow.jpg differ diff --git a/vert_wave.html b/vert_wave.html index 5c7495b..fd7db15 100644 --- a/vert_wave.html +++ b/vert_wave.html @@ -18,11 +18,19 @@ uniform mat4 u_modelViewPerspective; + uniform float u_time; + uniform vec3 u_mincolor; + uniform vec3 u_maxcolor; + + varying vec3 fs_color; //input void main(void) { // NOTE : according to the WebGL standard, 0.0f is not accepted - float height = 0.0; - + 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; + float alpha = (height+1.0)/2.0; + fs_color = mix(u_mincolor/255.0, u_maxcolor/255.0,alpha ); // NOTE : gl_Position is always a vec4 gl_Position = u_modelViewPerspective * vec4(vec3(position, height), 1.0); } @@ -30,13 +38,12 @@ @@ -53,51 +60,48 @@ 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 NUM_WIDTH_PTS = 32; var NUM_HEIGHT_PTS = 32; - var message; var canvas; var context; - var persp = mat4.create(); var view = mat4.create(); - + //Added + var time = 0.0; + var u_timeLocation; + var u_mincolorLocation; + var u_maxcolorLocation; + var Colors = { + mincolor : [100, 100, 255], + maxcolor : [255, 100, 100] + }; // Function called when the window is loaded - window.onload = function() { - // Add GUI component - var gui = new dat.GUI(); - - init(); - - animate(); + window.onload = function () { + // Add GUI component + var gui = new dat.GUI(); + gui.addColor(Colors, 'mincolor'); + gui.addColor(Colors, 'maxcolor'); + init(); + animate(); }; - function init() { message = document.getElementById("message"); canvas = document.getElementById("canvas"); context = createWebGLContext(canvas, message); - if (!context) { return; } - // SET UP WEBGL CONTEXT context.viewport(0, 0, canvas.width, canvas.height); context.clearColor(1.0, 1.0, 1.0, 1.0); context.enable(context.DEPTH_TEST); - mat4.perspective(45.0, 0.5, 0.1, 100.0, persp); - mat4.lookAt(eye, center, up, view); initializeShader(); - initializeGrid(); + initializeGrid(); } - - function animate(){ // Update var model = mat4.create(); @@ -107,29 +111,35 @@ mat4.multiply(view, model, mv); var mvp = mat4.create(); mat4.multiply(persp, mv, mvp); - + //Added + time = time + 0.01; + if (time == 3.14159 * 100.0) + time = 0.0; // Render context.clear(context.COLOR_BUFFER_BIT | context.DEPTH_BUFFER_BIT); - - context.uniformMatrix4fv(u_modelViewPerspectiveLocation, false, mvp); - context.drawElements(context.LINES, numberOfIndices, context.UNSIGNED_SHORT,0); - + context.uniformMatrix4fv(u_modelViewPerspectiveLocation, false, mvp); + context.drawElements(context.LINES, numberOfIndices, context.UNSIGNED_SHORT, 0); + //Added + context.uniform1f(u_timeLocation, time); + + context.uniform3f(u_mincolorLocation, Colors.mincolor[0], Colors.mincolor[1], Colors.mincolor[2]); + context.uniform3f(u_maxcolorLocation, Colors.maxcolor[0], Colors.maxcolor[1], Colors.maxcolor[2]); window.requestAnimFrame(animate); } - function initializeShader() { var program; var vs = getShaderSource(document.getElementById("vs")); var fs = getShaderSource(document.getElementById("fs")); - var program = createProgram(context, vs, fs, message); context.bindAttribLocation(program, positionLocation, "position"); u_modelViewPerspectiveLocation = context.getUniformLocation(program,"u_modelViewPerspective"); u_colorLocation = context.getUniformLocation(program, "u_color"); - + //Added + u_timeLocation = context.getUniformLocation(program, "u_time"); + u_mincolorLocation = context.getUniformLocation(program, "u_mincolor"); + u_maxcolorLocation = context.getUniformLocation(program, "u_maxcolor"); context.useProgram(program); } - function initializeGrid() { function uploadMesh(positions, heights, indices) { // Positions @@ -138,7 +148,6 @@ context.bufferData(context.ARRAY_BUFFER, positions, context.STREAM_DRAW); context.vertexAttribPointer(positionLocation, 2, context.FLOAT, false, 0, 0); context.enableVertexAttribArray(positionLocation); - if (heights){ // Heights var heightsName = context.createBuffer(); @@ -148,66 +157,52 @@ 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; } - - + \ No newline at end of file diff --git a/vert_wave_custom.html b/vert_wave_custom.html new file mode 100644 index 0000000..e55f058 --- /dev/null +++ b/vert_wave_custom.html @@ -0,0 +1,209 @@ + + + +Vertex Wave + + + + + +
+ + + + + + + + + + + + + + \ No newline at end of file