【问题标题】:Functionality of html5 matrix transformhtml5矩阵变换的功能
【发布时间】:2016-01-19 20:11:53
【问题描述】:

我目前正在尝试了解如何在 html5 中绘制对象时进行矩阵转换,但在多个不同信息源中发现的不同解释导致了一些混乱。我发现信息说,为了在 html5 中为绘制的对象设置动画,如 here 所示,而我还看到可以通过转换绘制点将转换应用于页面上的单个对象,但我不太确定这个怎么运作。

我找到了一个代码示例,它实现了腿部动画(两行),但它在没有对画布应用变换的情况下使用其他文件中定义的变换矩阵的函数对象来制作动画。该代码提供了自己的moveTo()lineTo() 实现(通常与画布对象一起使用),其中它转换传入的点,根据视口重新调整其位置,然后调用画布的移动版本传递转换点。

所以这里有几点混淆: 1. setTransform() 只能在画布上使用时,在变换矩阵对象上实现一个新的变换函数的目的是什么? 2. 在矩阵对象上调用rotate()translate() 之类的方法,而没有传入点,那么这些操作是如何实际应用的? 3. 何时应将转换应用于整个画布(如提供的链接中所做的那样),而不是应用于绘制的特定对象,因为两者似乎都可以工作?

我通常只是在寻找对此的一般概述,因为我对它的工作原理感到相当困惑。示例代码如下供参考:

<head>
<script src=g.js></script>
<script src=matrix4x4.js></script>
</head>
<body onload=g_start()>
<canvas id=myCanvas1 width=480 height=480></canvas>
<script>
   var w, h, g;

   function viewport(p) {
      return [ w/2 * p[0] + w/2, h/2 - p[1] * w/2 ];
   }

   function moveTo(p) {
      var q = m.transform(p);  // APPLY 3D MATRIX TRANFORMATION
      var xy = viewport(q);    // APPLY VIEWPORT TRANSFORM
      g.moveTo(xy[0], xy[1]);
   }

   function lineTo(p) {
      var q = m.transform(p);  // APPLY 3D MATRIX TRANFORMATION
      var xy = viewport(q);    // APPLY VIEWPORT TRANSFORM
      g.lineTo(xy[0], xy[1]);
   }

   myCanvas1.animate = function(_g) {
      g = _g;
      w = g.canvas.width;
      h = g.canvas.height;

      g.fillStyle = 'rgb(200,140,255)';
      g.beginPath();
      g.moveTo(0, 0);
      g.lineTo(w, 0);
      g.lineTo(w, h);
      g.lineTo(0, h);
      g.lineTo(0, 0);
      g.stroke();

      g.fillStyle = 'rgb(128,0,0)';
      g.strokeStyle = 'rgb(0,0,0)';

      var legBend = .4;

      var t = 3 * time;

      for (var leg = 0 ; leg < 2 ; leg++) {
     var angle = -Math.PI/2 * (1 + Math.sin(time));
     console.log(angle);
         var sign = (leg == 0) == (angle < -Math.PI/2) ? -1 : 1;

         m.identity();
         m.rotateY(-Math.PI/2 * (1 + Math.sin(time)));

         g.beginPath();

         m.translate(0, .5, .1 * sign);
         moveTo([0,0,0]);             // HIP

         m.rotateZ(-.5 * legBend + sign * legBend * Math.cos(t));

         m.translate(0, -.5, 0);

         lineTo([0,0,0]);             // HIP

         m.rotateZ(2 * legBend + 2 * legBend * sign * Math.sin(t));
         m.translate(0, -.5, 0);
         lineTo([0,0,0]);             // KNEE

         m.translate(-.1, 0, 0);
         lineTo([0,0,0]);             // KNEE

         g.strokeStyle = 'rgb(0,0,0)';
         g.lineWidth = 30;
         g.stroke();

         g.strokeStyle = 'rgb(255,0,0)';
         g.lineWidth = 20;
         g.stroke();
      }
   }

</script>
</body>

【问题讨论】:

  • 看不到 src=g.js 周围的引号让我感到很痛苦。

标签: javascript html canvas matrix


【解决方案1】:

重要的 html5 画布转换概念:

  • 所有画布转换方法(以及.transform)都相对于当前画布原点进行操作,并且该原点的坐标为 [0,0]。起始原点位于画布的左上角。 .setTransform 将重置当前画布原点,然后相对于该重置原点进行转换。

  • 转换不影响现有图纸。所以 fillRect(0,0) 后跟 translate(5,0) 不会移动已经绘制的矩形。现有的矩形仍将显示在画布的左上角。

  • 转换确实会影响新图纸。

  • translate 方法将原点移动指定的 x,y 距离。因此 translate(5,0) 将导致画布绘图原点 [0,0] 距画布左侧 5 个像素。所以 translate(5,0) 后跟 fillRect(0,0) 将导致新的矩形显示距离画布左侧 5 个像素。

  • 变换实际上平移(移动)、旋转、缩放整个画布绘图表面。因此,新图纸不会单独移动、旋转或缩放。 新绘图出现移动、旋转或缩放,因为整个画布绘图表面已被移动、旋转或缩放。

  • 转换是累积的。因此,如果您先翻译(5,0),然后再翻译(0,50),画布原点 [0,0] 将位于距左侧 5 像素和距顶部 50 像素的位置。所以fillRect(0,0)会从左边5像素,从顶部50像素绘制。

所以,回答您的问题:

  1. 顺序转换很有用,因为转换是累积的。因此,要使人物图像“移动”,您可以使用转换的累积效果,而无需记住他们的最后位置或计算他们的新位置。

    // the person image will move across the canvas in 5px increments over time
    // No need to remember its last location
    // No need to calculate its new position
    // That's because the canvas internally remembers & calculates its own origin.
    for(var i=0;i<20;i++){
        context.clearRect(0,0,canvas.width,canvas.height);
        context.translate(5,0);
        context.drawImage(person,0,0);
        // wait 1 second
    }
    
  2. 由于所有变换都相对于当前画布原点坐标,因此您不必为任何变换方法重新指定该坐标——画布会为您“记住”其当前原点。

  3. 单个画布绘图不受变换的影响。转换移动整个画布和新图纸只是“顺其自然”。在转换之前存在的任何图形都不会受到这些后续转换的影响 - 预先存在的图形仍保留在它们最初绘制的位置。

【讨论】:

  • 感谢您的回答!所以你是说任何时候你在 html5 中进行转换,你只能将转换应用于整个画布而不是特定对象(即不使用setTransform())?在我看来,在示例中,transform() 函数可能正在应用它自己的不使用 setTransform() 的转换,因为该函数仅适用于 2D 线,而该程序适用于 3d。
  • 另外,如果使用setTransform() 是实现Transform() 方法的唯一方法,你怎么能将它与3d 形状一起使用,b/c 我目前正在使用jquery 来获取上下文canvas.getContext("2d") 但我不知道是否有办法在 3d 中做到这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-16
  • 1970-01-01
  • 2015-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多