diff --git a/.gitignore b/.gitignore
index e43b0f9..96f05f1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
 .DS_Store
+old/
+new/
diff --git a/RTXoff.svg b/RTXoff.svg
new file mode 100644
index 0000000..80488f7
--- /dev/null
+++ b/RTXoff.svg
@@ -0,0 +1,103 @@
+
+
+
+
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+	 
+	 
+	 
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+ 
diff --git a/RTXon.svg b/RTXon.svg
new file mode 100644
index 0000000..d3124d7
--- /dev/null
+++ b/RTXon.svg
@@ -0,0 +1,105 @@
+
+
+
+
+ 
+
+	 
+	 
+	 
+	 
+	 
+	 
+	 
+	 
+	 
+	 
+	 
+	 
+	 
+	 
+	 
+	 
+	 
+	 
+	 
+ 
+
+	 
+	 
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+
+ 
+ 
diff --git a/index.html b/index.html
index 03424f2..6cde78c 100644
--- a/index.html
+++ b/index.html
@@ -21,6 +21,7 @@
  
 
 
+   
  
  
 
@@ -56,7 +57,19 @@ Solar RTX
 In this homework, I implemented Global illumination w/ 
    Realtime Recursive Ray Tracing! 
 
-Here is how it works: 
+Usage:  
+
+   Ctrl+Alt/Option+T: Toggle Texture. 
+   Ctrl+S: Download fragment shader. 
+   Ctrl+Alt/Option+R: Toggle Recursive Ray Tracing. 
+   Ctrl+Alt/Option+N: Reset ViewPoint. 
+   Ctrl+Alt/Option+P: Toggle Pause/Resume. 
+   Please unfocus the Editing area (click somewhere else on the page) to use hotkeys. 
+   Click on canvas (WITHOUT key modifiers): Toggle Pause/Resume. 
+   SHIFT+Alt/Option+MOUSE DRAG/WHEEL ZOOM: Changing Viewing point. 
+
+ 
+How it works: 
 
    First, I started with what I've already done in homework 1. Which already included complete Phong shading with 
       Specular light and much more (spherical texture mapping, simple interactions, improved UI/shader editor).
@@ -65,10 +78,19 @@ Solar RTX
      I modified the ray tracing algorithm so that when hitting an object, instead of returning color calculated from 
       Phong model: 
       
-         I recursively traced the light reflected and refract from the object. 
-          
+         It recursively bounces and/or refract(NOT IMPLEMENTED YET) itself spawning new rays. 
+         The color of this pixel equals to Ambient + Diffuse + ks*color[Reflected] + kt*color[Refracted]. 
+            (Turner Whitted Model ) 
+         The tracing will stop when a ray was reflected/refracted n_ref times.   
+         The color of the final light is computed via specular component from the Phong model. 
+         You may increase n_ref for more iterations, but please proceed with caution, because it may halt the computer.  
+          
        
-        
+   I added more interactions, you can now change the viewpoint by 
+      holding shift and alt key while dragging on canvas to rotate,
+      or holding shift and alt while scrolling on canvas to change focal length.
+      This is implemented by applying a transformation matrix to the viewpoint and projection surface.
+       
    Finally, I used super sampling via doubling the render dimensions of the canvas to reduce aliasing. 
    Repo on Github . 
    
@@ -104,6 +126,9 @@ let vs = my_vertex_shader.innerHTML;
    client.send();
 document.body.innerHTML = [''
    ,'' + my_title.innerHTML
+   ,' ' 
+   ,'
' 
    ,''
    ,'
 '
    ,' '
@@ -111,7 +136,8 @@ document.body.innerHTML = [''
    ,' '
    ,''
    ,'
'
-   ,' ' + document.body.innerHTML  + '' + my_instructions.innerHTML + '
' + ' '
+   ,'' + document.body.innerHTML
+   ,'' + my_instructions.innerHTML + '
' + ' '
    ,' 
'
    ,''
    ].join('');
@@ -137,52 +163,148 @@ editor.setAutoScrollEditorIntoView(true);
 delete editor.KeyBinding;
 let lastTime = Date.now();
 let animating = true;
-let ctrl = false;
-canvas1.addEventListener('click',function(ev){
+let ctrl = false, alt = false, shift = false, fpson = true, moving = false;
+let mousedx = 0, mousedy = 0, mousedz = 0;
+let mouselastX, mouselastY;
+let pause_resume = function(){
    if(animating)
-      lastTime = Date.now();
+         lastTime = Date.now();
+      else
+         startTime += Date.now() - lastTime;   
+      animating = !animating;
+};
+canvas1.addEventListener('click',function(ev){
+   if(!(shift && alt))
+      pause_resume();
+   //moving = false;
+});
+canvas1.addEventListener('mousedown', function(e){
+   if(shift && alt){
+      moving = true
+      mouselastX = mouselastY =  undefined;
+   }
    else
-      startTime += Date.now() - lastTime;   
-   animating = !animating;
+      moving = false;
 });
+canvas1.addEventListener('mousemove', function(e){
+   if(shift && alt && moving){
+      if(!(mouselastX==undefined || mouselastY == undefined)){
+         mousedx += (mouselastX - e.offsetX)/60;
+         mousedy += (mouselastY - e.offsetY)/60;
+         setUniform('4f', 'rot', Math.cos(mousedx), Math.sin(mousedx), Math.cos(mousedy), Math.sin(mousedy));
+      }
+      mouselastX = e.offsetX;
+      mouselastY = e.offsetY;
+   }
+   else
+      moving = false;
+});
+canvas1.addEventListener('mouseup', function(e){
+   // if(ctrl && alt && moving){
+   // }
+   moving = false;
+});
+canvas1.addEventListener('mouseout', function(e){
+   // if(ctrl && alt && moving){
+   // }
+   moving = false;
+});
+canvas1.addEventListener('wheel', function(e){
+   if(shift && alt){
+      mousedz += e.wheelDelta/600;
+      setUniform('1f', 'dFL', mousedz);
+   }
+});
+rtx.style.cursor="pointer";
+let rtswitch = function(){
+   const mask = 0x2;
+   let rtstatus = !(flags&mask);
+   if (rtstatus)
+      rtx.src='./RTXoff.svg';
+   else
+      rtx.src='./RTXon.svg';
+   flags = flags&!mask | (rtstatus?mask:0);
+   setUniform('1i', 'flags', flags);
+}
+rtx.addEventListener('click', rtswitch);
+var requestAnimationFrame = window.requestAnimationFrame ||
+ window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
+let fpscounter = function(time){
+      if (start === undefined)
+         start = time;
+      else
+         fps.innerHTML = Math.round(10000/(time-start))/10 + ' fps';
+      start = time;
+      if(fpson)
+         requestAnimationFrame(fpscounter);
+      else{
+         start = undefined;
+         fps.innerHTML = '';
+      }
+   };
 document.addEventListener('keydown',(e)=>{
+   if(e.code.startsWith('Shift'))
+      shift = true;
    if(e.code.startsWith('Control'))
-   {
       ctrl = true;
-   }
-   else if(ctrl && e.code == 'KeyT')
-   {
-      mask = 0x1;
+   if(e.code.startsWith('Alt'))
+      alt = true;
+   else if(ctrl && alt && e.code == 'KeyT'){
+      const mask = 0x1;
       flags = flags&!mask | (!(flags&mask)?mask:0);
       setUniform('1i', 'flags', flags);
    }
-   else if (ctrl && e.code == 'KeyS')
-   {
+   else if (ctrl &&e.code == 'KeyS'){
       let a = document.createElement('a');
       a.href = "data:text/plain,"+encodeURIComponent(editor.getSession().getValue());
       a.download = 'shader.frag';
       a.click();
    }
+   else if(ctrl && alt&&e.code == 'KeyR')
+      rtswitch();
+   else if(ctrl && alt&&e.code == 'KeyN')
+   {
+      flags = 0;
+      moving = false;
+      mousedx = mousedy = mousedz = 0;
+      setUniform('4f', 'rot', Math.cos(mousedx), Math.sin(mousedx), Math.cos(mousedy), Math.sin(mousedy));
+      setUniform('1f', 'dFL', mousedz);
+      setUniform('1i', 'flags', flags);
+   }
+   else if(ctrl && alt&&e.code == 'KeyP')
+      pause_resume();
+   else if(ctrl && alt&&e.code == 'KeyF')
+      if(!fpson)
+      {
+         fpson = true;
+         requestAnimationFrame(fpscounter);
+      }
+      else
+         fpson = false;
+   // else if(e.code =='KeyV')
+   //    alert(' '+ mousedx+ ' ' + mousedy + ' '+mousedz)
+
 });
 
 document.addEventListener('keyup',(e)=>{
    if(e.code.startsWith('Control'))
-   {
       ctrl = false;
-   }
+   if(e.code.startsWith('Alt'))
+      alt = false;
+   if(e.code.startsWith('Shift'))
+      shift = false;
 });
 // SET THE CURRENT TIME IN SECONDS BEFORE RENDERING EACH FRAME.
 
 let startTime = Date.now();
-
+let lastFrameTime = 0;
 function animate(gl) {
    if(animating)
       setUniform('1f', 'uTime', (Date.now() - startTime) / 1000);
    else
       setUniform('1f', 'uTime', (lastTime - startTime) / 1000);
-
 }
-
-
+let start;
+requestAnimationFrame(fpscounter);
 
 
diff --git a/lib2.js b/lib2.js
index 3247002..196053f 100644
--- a/lib2.js
+++ b/lib2.js
@@ -90,7 +90,7 @@ function gl_start(canvas, vertexShader, fragmentShader) {           // START WEB
 
    setTimeout(function () {
       try {
-         canvas.gl = canvas.getContext('webgl2');              // Make sure WebGl is supported. IT WOULD BE GREAT TO USE WEBGL2 INSTEAD.
+         canvas.gl = canvas.getContext('experimental-webgl');              // Make sure WebGl is supported. IT WOULD BE GREAT TO USE WEBGL2 INSTEAD.
       } catch (e) { throw 'Sorry, your browser does not support WebGL.'; }
 
       canvas.setShaders = function (vertexShader, fragmentShader) {         // Add the vertex and fragment shaders:
@@ -151,7 +151,7 @@ function gl_start(canvas, vertexShader, fragmentShader) {           // START WEB
             textures[i] = i;
          }
          gl.uniform1iv(gl.getUniformLocation(program, 'uSampler'), textures);
-
+         setUniform('4f', 'rot', Math.cos(mousedx), Math.sin(mousedx), Math.cos(mousedy), Math.sin(mousedz));
          gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());                     // Create a square as a triangle strip
          gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(                       //    consisting of two triangles.
             [-1, 1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0]), gl.STATIC_DRAW);
diff --git a/shader.frag b/shader.frag
index ee12c36..04fa609 100644
--- a/shader.frag
+++ b/shader.frag
@@ -4,23 +4,35 @@ vec3 groundColor = vec3(.2, .3, .5);
 vec4 groundSpecular = vec4(.71, .71, .71, 10.);
 uniform float uTime;// TIME, IN SECONDS
 uniform int flags;
-//FLAGS 0-RT, 1-TEX, 2-
+uniform vec4 rot;
+uniform float dFL;
+//FLAGS 0-TEX, 1-RT, 2-CLOUD, 3-TEX_ROT
 varying vec3 vPos;// -1 < vPos.x < +1
 // -1 < vPos.y < +1
 //      vPos.z == 0
 
 float fl=3.;
 const float pi=3.14159265359;
-const int n_ref=2;
+const int n_ref=6;
 const int ns=2;
 vec4 Sph[ns];
 uniform sampler2D uSampler[ns];
 vec3 Ambient[ns];
 vec3 Diffuse[ns];
 vec4 Specular[ns];
+struct Sphere{
+   vec4 Pos;
+   vec3 Ambient;
+   vec3 Diffuse;
+   vec4 Specular;
+   int textureid;
+   float ks, kt;
+};
 struct RT{
    vec3 color;
    float ks;
+   // vec3 colorr;
+   // float kt;
    // vec3 ptr;
    // vec3 normal;
 } stack[n_ref];
@@ -62,13 +74,20 @@ void main(){
    // INITIALIZE TO A BACKGROUND COLOR
    
    vec3 color=vec3(.2, .3, .5);
-   
+   float ca=rot.x, sa = rot.y, cb=rot.z, sb=rot.w;
    // COMPUTE THE RAY ORIGIN AND DIRECTION
-   float x=vPos.x;
-   float y=vPos.y;
-   
-   vec3 V=vec3(0.,0.,fl);
-   vec3 W=normalize(vec3(x,y,-fl));
+   mat3 transformation, invTr;
+   transformation[0] = vec3(ca, sb*sa, sa*cb);
+   transformation[1] = vec3(0, cb, -sb);
+   transformation[2] = vec3(-sa,ca*sb,ca*cb);
+   invTr[0] = vec3(ca, 0, -sa);
+   invTr[1] = vec3(sa*sb, cb, ca*sb);
+   invTr[2] = vec3(cb*sa, -sb, ca*cb);
+
+   vec3 trPos = transformation*vec3(vPos.xy, -2);
+
+   vec3 V=transformation*vec3(0.,0.,fl+dFL);
+   vec3 W=normalize(trPos-V);
    // RAY TRACE TO ALL OBJECTS IN THE SCENE
    bool rtxoff = getflag(flags, 1);
    int cnt_ref = n_ref;
@@ -99,7 +118,7 @@ void main(){
             if(i == iMin)
             {
                //*TEXTURE MAPPING
-               vec3 tex_sph=S-Sph[i].xyz;
+               vec3 tex_sph=invTr*(S-Sph[i].xyz);
                float R=Sph[i].w;
                float tex_x=acos(abs(tex_sph.x)/sqrt(R*R-tex_sph.y*tex_sph.y));
                if(tex_sph.x>0.)
@@ -124,7 +143,7 @@ void main(){
                ;
                // + SPECULAR COMPONENT GOES HERE
                if(rtxoff || j == n_ref - 1)
-                  color += float(j) * Specular[i].xyz*pow(max(0.,dot(2.*dot(N,realLDir)*N-realLDir,-W)),Specular[i].w);
+                  color += sqrt(float(j+1)) * Specular[i].xyz*pow(max(0.,dot(2.*dot(N,realLDir)*N-realLDir,-W)),Specular[i].w);
                stack[j] = RT(color, 0.15);
                V = S;
                W = -normalize(2. * dot(N, W) * N - W);
@@ -134,7 +153,7 @@ void main(){
       else {
       // TO SIMIPIFY THINGS UP, I'LL ASSUME THAT EVERYTHING 
       // IS INSIDE THE BOUNDING BOX [(-1,-1,-1), (1,1,1)]
-      // AND THERE'S A INFINITE FLOOR [y = -1]
+      // AND THERE'S A FLOOR at [y = -1]
 
          float t = -(.2+V.y)/W.y;
          float sx = V.x + t* W.x, sz = V.z + t * W.z;
@@ -150,7 +169,7 @@ void main(){
             ;
             // + SPECULAR COMPONENT GOES HERE
             if(rtxoff || j == n_ref - 1)
-               color += float(j)*groundSpecular.xyz*
+               color += sqrt(float(j+1))*groundSpecular.xyz*
                   pow(max(0., dot(vec3(-realLDir.x, realLDir.y,-realLDir.z),-W)),groundSpecular.w);
             stack[j] = RT(color, 0.1);
             V = S;
@@ -159,7 +178,7 @@ void main(){
          else{
             if(j > 0)
             {
-               stack[j] = RT(vec3(12.,12.,12.)*pow(max(0.,dot(W, normalize(LDir - V))), 10.), 0.);
+               stack[j] = RT(sqrt(float(j+1))*vec3(4.,4.,4)*pow(max(0.,dot(W, normalize(LDir - V))), 10.), 0.);
                cnt_ref = j + 1;
             }
             else