专栏首页图形学与OpenGLCG实验6 交互与动画

CG实验6 交互与动画

1.实验目的和要求

  • 目的:了解交互与动画的基本思想,掌握交互与动画的常见实现方法;
  • 要求:读懂WebGL交互与动画示范代码,实现简单的交互与动画程序。

2. 实验过程

(1) 示范代码1为交互实例:在鼠标点击的位置上绘制出点;示范代码2为动画实例:三角形按照恒定的速度(45度/秒)旋转。结合示范代码,学习理解交互与动画的基本思想与实现; (2) 结合示范代码1,将示范代码2改为根据鼠标来控制三角形的旋转;

3.实验结果

示范代码1的结果如下图所示:

示范代码2如下图所示:

4.实验分析

请根据教材内容、网络资源及示范代码,简单分析下交互与动画的实现原理与方法。

5.实验代码

gl-matrix.js 下载地址:http://oty0nwcbq.bkt.clouddn.com/gl-matrix.js

(1) 鼠标点击交互绘点

(i) ClickedPoints.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Draw a point with a mouse click</title>
    </head>
    <script id="vertex-shader" type="x-shader/x-vertex">
         attribute vec4 a_Position;  
         void main() { 
           gl_Position = a_Position ; 
           gl_PointSize = 10.0; 
         } 
        </script>

        <script id="fragment-shader" type="x-shader/x-fragment">
             void main() { 
                gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 
             } 
        </script>
    <body onload="startup()">
        <canvas id="myGLCanvas" width="600" height="600">
        </canvas>
    </body>
        <script type="text/javascript" src="gl-matrix.js"></script>
    <script type="text/javascript" src="ClickedPoints.js"></script>
</html>

(ii) ClickedPoints.js

var gl;
function startup(){
    var canvas = document.getElementById('myGLCanvas');//获取<canvas>元素
    gl = createGLContext(canvas);
    setupShaders(); 

 // // Get the storage location of a_Position
 var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
 if (a_Position < 0) {
   console.log('Failed to get the storage location of a_Position');
   return;
 }

 // Register function (event handler) to be called on a mouse press
 canvas.onmousedown = function(ev){ click(ev, gl, canvas, a_Position); };

 // Specify the color for clearing <canvas>
 gl.clearColor(0.0, 0.0, 0.0, 1.0);

 // Clear <canvas>
 gl.clear(gl.COLOR_BUFFER_BIT);
 }

 var g_points = []; // The array for the position of a mouse press
 function click(ev, gl, canvas, a_Position) {
   var x = ev.clientX; // x coordinate of a mouse pointer
   var y = ev.clientY; // y coordinate of a mouse pointer
   var rect = ev.target.getBoundingClientRect() ;

   x = ((x - rect.left) - canvas.width/2)/(canvas.width/2);
   y = (canvas.height/2 - (y - rect.top))/(canvas.height/2);
   // Store the coordinates to g_points array
   g_points.push(x); g_points.push(y);

   // Clear <canvas>
   gl.clear(gl.COLOR_BUFFER_BIT);

   var len = g_points.length;
   for(var i = 0; i < len; i += 2) {
     // Pass the position of a point to a_Position variable
     gl.vertexAttrib3f(a_Position, g_points[i], g_points[i+1], 0.0);

     // Draw
     gl.drawArrays(gl.POINTS, 0, 1);
   }
 }

function createGLContext(canvas) {
  var names = ["webgl", "experimental-webgl"];
  var context = null;
  for (var i=0; i < names.length; i++) {
    try {
      context = canvas.getContext(names[i]); //获取webgl context绘图上下文
    } catch(e) {}
    if (context) {
      break;
    }
  }
  if (context) {
    context.viewportWidth = canvas.width;
    context.viewportHeight = canvas.height;
  } else {
    alert("Failed to create WebGL context!");
  }
  return context;
}

function setupShaders() {    
  var vertexShader = loadShader(gl.VERTEX_SHADER, "vertex-shader");
  var fragmentShader = loadShader(gl.FRAGMENT_SHADER, "fragment-shader");

  var shaderProgram = gl.createProgram();
  gl.attachShader(shaderProgram, vertexShader);
  gl.attachShader(shaderProgram, fragmentShader);
  gl.linkProgram(shaderProgram);

  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
    alert("Failed to setup shaders");
  }

  gl.useProgram(shaderProgram);
  gl.program= shaderProgram;
}

function loadShader(type, ShaderId) {
  var shaderScript = document.getElementById( ShaderId );
    var shader = gl.createShader(type);
    gl.shaderSource( shader, shaderScript.text );
    gl.compileShader( shader );

  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
      alert("Error compiling shader" + gl.getShaderInfoLog(shader));
      gl.deleteShader(shader);   
      return null;
  }
  return shader;  
}

(2) 三角形旋转动画

(i) RotatingTriangle.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Continually Rotate A Triangle</title>
    </head>
    <script id="vertex-shader" type="x-shader/x-vertex">
        attribute vec4 a_Position;
        uniform mat4 u_ModelMatrix;  
        void main() { 
            gl_Position = u_ModelMatrix * a_Position; 
        } 
       </script>

       <script id="fragment-shader" type="x-shader/x-fragment">
            void main() { 
               gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 
            } 
       </script>
    <body onload="startup()">
        <canvas id="myGLCanvas" width="600" height="600">
        </canvas>
    </body>
    <script type="text/javascript" src="gl-matrix.js"></script>
    <script type="text/javascript" src="RotatingTriangle.js">
    </script>
</html>

(ii) RotatingTriangle.js

var gl;
// Rotation angle (degrees/second)
var ANGLE_STEP = 45.0;
var modelMatrixI = mat4.create();
function startup(){
    var canvas = document.getElementById('myGLCanvas');//获取<canvas>元素
    gl = createGLContext(canvas);
    setupShaders(); 

  // Write the positions of vertices to a vertex shader
  var n = initVertexBuffers(gl);
  if (n < 0) {
    console.log('Failed to set the positions of the vertices');
    return;
  }

  // Specify the color for clearing <canvas>
  gl.clearColor(0.0, 0.0, 0.0, 1.0);

  // Get storage location of u_ModelMatrix
  var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
  if (!u_ModelMatrix) { 
    console.log('Failed to get the storage location of u_ModelMatrix');
    return;
  }

  // Current rotation angle
  var currentAngle = 0.0;
  // Model matrix
  var modelMatrix = mat4.create();

  // Start drawing
  var tick = function() {
    currentAngle = animate(currentAngle);  // Update the rotation angle
    draw(gl, n, currentAngle, modelMatrix, u_ModelMatrix);   // Draw the triangle
    requestAnimationFrame(tick, canvas); // Request that the browser calls tick
  };
  tick();
 }

 function initVertexBuffers(gl) {
    var vertices = new Float32Array ([
      0, 0.5,   -0.5, -0.5,   0.5, -0.5
    ]);
    var n = 3;   // The number of vertices

    // Create a buffer object
    var vertexBuffer = gl.createBuffer();
    if (!vertexBuffer) {
      console.log('Failed to create the buffer object');
      return -1;
    }

    // Bind the buffer object to target
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    // Write date into the buffer object
    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

    // Assign the buffer object to a_Position variable
    var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
    if(a_Position < 0) {
      console.log('Failed to get the storage location of a_Position');
      return -1;
    }
    gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

    // Enable the assignment to a_Position variable
    gl.enableVertexAttribArray(a_Position);

    return n;
  }

  function draw(gl, n, currentAngle, modelMatrix, u_ModelMatrix) {
    // Set the rotation matrix
    //modelMatrix.setRotate(currentAngle, 0, 0, 1); // Rotation angle, rotation axis (0, 0, 1)
    var radian = Math.PI * currentAngle / 180.0; // Convert to radians
    mat4.rotate(modelMatrix, modelMatrixI, radian, [0, 0 , 1]);

    // Pass the rotation matrix to the vertex shader
    gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix);

    // Clear <canvas>
    gl.clear(gl.COLOR_BUFFER_BIT);

    // Draw the rectangle
    gl.drawArrays(gl.TRIANGLES, 0, n);
  }

  // Last time that this function was called
  var g_last = Date.now();
  function animate(angle) {
    // Calculate the elapsed time
    var now = Date.now();
    var elapsed = now - g_last;
    g_last = now;
    // Update the current rotation angle (adjusted by the elapsed time)
    var newAngle = angle + (ANGLE_STEP * elapsed) / 1000.0;
    return newAngle %= 360;
  }

function createGLContext(canvas) {
  var names = ["webgl", "experimental-webgl"];
  var context = null;
  for (var i=0; i < names.length; i++) {
    try {
      context = canvas.getContext(names[i]); //获取webgl context绘图上下文
    } catch(e) {}
    if (context) {
      break;
    }
  }
  if (context) {
    context.viewportWidth = canvas.width;
    context.viewportHeight = canvas.height;
  } else {
    alert("Failed to create WebGL context!");
  }
  return context;
}

function setupShaders() {    
    var vertexShader = loadShader(gl.VERTEX_SHADER, "vertex-shader");
    var fragmentShader = loadShader(gl.FRAGMENT_SHADER, "fragment-shader");

    var shaderProgram = gl.createProgram();
    gl.attachShader(shaderProgram, vertexShader);
    gl.attachShader(shaderProgram, fragmentShader);
    gl.linkProgram(shaderProgram);

    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
      alert("Failed to setup shaders");
    }

    gl.useProgram(shaderProgram);
    gl.program= shaderProgram;
  }

  function loadShader(type, ShaderId) {
    var shaderScript = document.getElementById( ShaderId );
      var shader = gl.createShader(type);
      gl.shaderSource( shader, shaderScript.text );
      gl.compileShader( shader );

    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        alert("Error compiling shader" + gl.getShaderInfoLog(shader));
        gl.deleteShader(shader);   
        return null;
    }
    return shader;  
  }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • WebGL绘制三角形

    步行者08
  • WebGL三角形平移变换

    步行者08
  • WebGL三角形平移变换(矩阵方式)

    步行者08
  • WebGL绘制三角形

    步行者08
  • WebGL三角形平移变换

    步行者08
  • HT for Web基于HTML5的图像操作(三)

    上篇采用了HTML5的Canvas的globalCompositeOperation属性达到了染色效果,其实CSS也提供了一些常规图像变化的设置参数,关于CSS...

    HT for Web
  • HT for Web基于HTML5的图像操作(三)

    HT_hightopo
  • Javascript如何实现GPU加速?

    如果只是通用的计算场景呢?比如处理图片中大量像素信息,我们有办法使用GPU资源吗?这正是本文要讲的,GPU通用计算,简称GPGPU。

    腾讯Bugly

扫码关注云+社区

领取腾讯云代金券