帆布3D图形 [英] Canvas 3d graph

查看:156
本文介绍了帆布3D图形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经做了3D图形在其绘制点。我得出的x,y和z轴。你也可以旋转轴由pressing箭头keys.Now我的问题,这标志着轴为x,y和z。我想在画布上用filltext.But被添加到画布上的文字,但它不是旋转添加文本。那是因为我没有设置旋转的效果,因为我guess.So我怎么能设置旋转文本,以便当轴旋转的文字也旋转together.Below是我的code。

 <!DOCTYPE HTML>



  < HTML>

  < HEAD>

 <冠军>帆布面旋转< /标题>

 <风格>

  体 {

    文本对齐:中心;

  }



  帆布 {

    边界:1px的纯黑色;

  }

  < /风格>

  <脚本>

  VAR常量= {

    canvasWidth:600,//在像素。

    canvasHeight:600,//在像素。

    LEFTARROW:37,

    UPARROW:38,

    向右键:39,

    DownArrow中文:40,

    XMIN:-10,//这四个最大/最小值限定在xy平面,该表面将被绘制在一个正方形。

    XMAX:10,

    YMIN:-10,

    YMAX:10,

    xDelta:0.01,//使较小的更多的表面点。

    yDelta:0.01,//使较小的更多的表面点。

    颜色表:[#060],//有11种不同的垂直颜色值的表面上,根据最后一排http://www.cs.siena.edu/~lederman/truck/AdvanceDesignTrucks/html_color_chart .gif注意:

    pointWidth:2,//渲染表面点(即,矩形宽度和高度),以像素的大小。

    dTheta:0.05,//角度增量,以弧度,由旋转每个键preSS表面。

    surfaceScale:24 //根据经验的恒定,使表面为给定的画布尺寸大小适中。

  };



  //这些常数太多,但我从字面上来缓解打字和提高清晰度的上述参数删除它们。

  变种X = 0;

  变种Y = 1;

  变种Z = 2;



  // -----------------------------------------------------------------------------------------------------



  VAR controlKey pressed = FALSE; // processKeyDown()和processKeyUp之间共享()。

  VAR面=新的表面(); //一组点(矢量格式)重新presenting表面。



  // -----------------------------------------------------------------------------------------------------



  函数点(x,Y,Z)

  / *

    给定一个(X,Y,Z)的表面点,返回点的3×1向量形式。

  * /

  {

    返回[X,Y,Z]; //返回一个3×1矢量重新presenting传统的(X,Y,Z)表面点。这种载体形式简化矩阵乘法。

  }



  // -----------------------------------------------------------------------------------------------------



  功能面()

  / *

    的表面是(X,Y,Z)点列表,在3×1向量格式。这是一个构造函数。

  * /

  {

    this.points = []; //表面点矢量格式的数组。即,该数组的每个元素是一个3×1阵列,如在[[X1,Y1,Z1],[X2,Y2,Z2],[X3,Y3,Z3],...]

  }



  // -----------------------------------------------------------------------------------------------------



  Surface.prototype.equation =功能(X,Y)

  / *

    给出的点​​(x,y)时,返回关联z坐标基于所提供的表面方程,形式Z =的F(X,Y)。

  * /

  {

    变种D =的Math.sqrt(X * X + Y * Y); //在xy点从z轴的距离d。



    返回4 *(Math.sin(D)/天); //返回z坐标为点(x,Y,Z)。

  }



  // -----------------------------------------------------------------------------------------------------



  Surface.prototype.generate =功能()

  / *

    创建的(X,Y,Z)点列表(以3×1的矢量格式)重新presenting的表面上。

  * /

  {

    变种I = 0;



    对于(VAR X = constants.xMin,X< = constants.xMax; X + = constants.xDelta)

    {

      对于(VAR Y = constants.yMin; Y< = constants.yMax; Y + = constants.yDelta)

      {

        this.points [I] =点(X,Y,this.equation(X,Y)); //存储表面点(矢量格式)转换成表面点的名单。

        ++我;

      }

    }

  }



  // -----------------------------------------------------------------------------------------------------



  Surface.prototype.color =功能()

  / *

    一表面点的颜色是其z坐标高度的函数。

  * /

  {

    变种Z者除外; // z坐标对给定表面点(x,Y,Z)。



    this.zMin = this.zMax = this.points [0] [Z]。 //初始值。需要注意的是ZMIN和ZMAX是自定义属性,如果这code为后来延长可能可能是有益的。

    对于(VAR I = 0; I< this.points.length;我++)

    {

      Z = this.points [I] [Z]。

      如果(Z< this.zMin){this.zMin = Z; }

      如果(Z> this.zMax){this.zMax = Z; }

    }



    VAR zDelta = Math.abs(this.zMax  -  this.zMin)/ constants.colorMap.length;



    对于(VAR I = 0; I< this.points.length;我++)

    {

      this.points [I]。颜色= constants.colorMap [Math.floor((this.points [I] [Z] -this.zMin)/ zDelta)];

    }



    / *注意现有FOR循环功能上等同于后续的(少得多优雅)循环:

    对于(VAR I = 0; I< this.points.length;我++)

    {

      如果(this.points [I] [Z]< = this.zMin + zDelta){this.points [I]。颜色=#060;}

      否则,如果(this.points [I] [Z]< = this.zMin + 2 * zDelta){this.points [I]。颜色=#090;}

      否则,如果(this.points [I] [Z]< = this.zMin + 3 * zDelta){this.points [I]。颜色=#0C0;}

      否则,如果(this.points [I] [Z]< = this.zMin + 4 * zDelta){this.points [I]。颜色=#0F0;}

      否则,如果(this.points [I] [Z]< = this.zMin + 5 * zDelta){this.points [I]。颜色=#9F0;}

      否则,如果(this.points [I] [Z]< = this.zMin + 6 * zDelta){this.points [I]。颜色=#9C0;}

      否则,如果(this.points [I] [Z]< = this.zMin + 7 * zDelta){this.points [I]。颜色=#990;}

      否则,如果(this.points [I] [Z]< = this.zMin + 8 * zDelta){this.points [I]。颜色=#960;}

      否则,如果(this.points [I] [Z]< = this.zMin + 9 * zDelta){this.points [I]。颜色=#930;}

      否则,如果(this.points [I] [Z]< = this.zMin + 10 * zDelta){this.points [I]。颜色=#900;}

      其他{this.points [I]。颜色=#C00;}

    }

    * /

  }



  // -----------------------------------------------------------------------------------------------------



  功能appendCanvasElement()

  / *

    创建并再追加myCanvascanvas元素的DOM。

  * /

  {

    VAR canvasElement = document.createElement方法('画布');



    canvasElement.width = constants.canvasWidth;

    canvasElement.height = constants.canvasHeight;

    canvasElement.id =myCanvas;



    。canvasElement.getContext('二维')翻译(constants.canvasWidth / 2,constants.canvasHeight / 2); //翻译表面的原点到画布的中心。



    document.body.appendChild(canvasElement); //使canvas元素body元素的一个孩子。

  }



  //------------------------------------------------------------------------------------------------------



  Surface.prototype.sortByZIndex =功能(A,B)

  {

    返回A [Z]  -  B [Z]。 //确定是否A点是后面,前面,或在相同的水平点B(相对于所述z轴)。

  }



  // -----------------------------------------------------------------------------------------------------



  Surface.prototype.draw =功能()

  {

    变种myCanvas =的document.getElementById(myCanvas); //所需的Firefox浏览器。

    VAR CTX = myCanvas.getContext(2D);



    this.points = surface.points.sort(surface.sortByZIndex); //排序集合基于相对z轴位置的点。如果点是明显小,可以排序逃脱除去这一步。

  变种C =的document.getElementById(myCanvas);
 VAR CTX = c.getContext(2D);
  ctx.font =宋体20px的;
  ctx.fillText(X,250,0)​​;

    对于(VAR I = 0; I< this.points.length;我++)

    {

      ctx.fillStyle = this.points [I]。颜色;

      ctx.fillRect(this.points [I] [X] * constants.surfaceScale,this.points [I] [Y] * constants.surfaceScale,constants.pointWidth,constants.pointWidth);

    }

  }



  // -----------------------------------------------------------------------------------------------------



  Surface.prototype.multi =功能(R)

  / *

    假定R是3×3矩阵和this.points(即P)为一个3 XN矩阵。此方法执行P = R * P。

  * /

  {

    变种Px的= 0,芘= 0,Pz的= 0; //变量来保存临时结果。

    VAR P = this.points; // P是一个指向组表面点(即,该组的3×1向量)。

    VAR总和; //总和为每行/列矩阵积。



    对于(VAR V = 0; V< P.length; V ++)//对于点列表中的所有3×1向量。

    {

      像素= P [V] [X],芘= P [V] [Y],Pz的= P [V] [Z];

      为(变种Rrow = 0; Rrow 3;; Rrow ++)//对于在R矩阵的每一行。

      {

        总和=(R [Rrow] [X] * Px)的+(R [Rrow] [Y] * PY)+(R [Rrow] [Z] * PZ);

        P [V] [Rrow] =总和;

      }

    }

  }



  // -----------------------------------------------------------------------------------------------------



  Surface.prototype.erase =功能()

  {

    变种myCanvas =的document.getElementById(myCanvas); //所需的Firefox浏览器。

    VAR CTX = myCanvas.getContext(2D);



    ctx.clearRect(-constants.canvasWidth / 2,-constants.canvasHeight / 2,myCanvas.width,myCanvas.height);

  }



  // -----------------------------------------------------------------------------------------------------



  Surface.prototype.xRotate =功能(符号)

  / *

    假定为标志是1或-1,这是用来可旋转顺时针的表面或逆时针。

  * /

  {

    变种的Rx = [[0,0,0],

               [0,0,0],

               [0,0,0]]; //创建一个初始化的3×3的旋转矩阵。



    接收[0] [0] = 1;

    接收[0] [1] = 0; //多余的,但清晰的帮助。

    接收[0] [2] = 0;

    RX [1] [0] = 0;

    RX [1] [1] = Math.cos(符号* constants.dTheta);

    RX [1] [2] = -Math.sin(符号* constants.dTheta);

    接收[2] [0] = 0;

    接收[2] [1] = Math.sin(符号* constants.dTheta);

    接收[2] [2] = Math.cos(符号* constants.dTheta);



    this.multi器(Rx); //如果P是一组表面点,那么此方法进行矩阵multiplcation:接收* P

    this.erase(); //注意,人们可以使用两个画布来加快速度,这也省去了清除。

    this.draw();

  }



  // -----------------------------------------------------------------------------------------------------



  Surface.prototype.yRotate =功能(符号)

  / *

    假定为标志是1或-1,这是用来可旋转顺时针的表面或逆时针。

  * /

  {

    变种中R y = [[0,0,0],

               [0,0,0],

               [0,0,0]]; //创建一个初始化的3×3的旋转矩阵。



    RY [0] [0] = Math.cos(符号* constants.dTheta);

    RY [0] [1] = 0; //多余的,但清晰的帮助。

    RY [0] [2] = Math.sin(符号* constants.dTheta);

    RY [1] [0] = 0;

    RY [1] [1] = 1;

    RY [1] [2] = 0;

    RY [2] [0] = -Math.sin(符号* constants.dTheta);

    RY [2] [1] = 0;

    RY [2] [2] = Math.cos(符号* constants.dTheta);



    this.multi(RY); //如果P是一组表面点,那么此方法进行矩阵multiplcation:接收* P

    this.erase(); //注意,人们可以使用两个画布来加快速度,这也省去了清除。

    this.draw();

  }



  // -----------------------------------------------------------------------------------------------------



  Surface.prototype.zRotate =功能(符号)

  / *

    假定为标志是1或-1,这是用来可旋转顺时针的表面或逆时针。

  * /

  {

    变种RZ = [[0,0,0],

               [0,0,0],

               [0,0,0]]; //创建一个初始化的3×3的旋转矩阵。



    RZ [0] [0] = Math.cos(符号* constants.dTheta);

    RZ [0] [1] = -Math.sin(符号* constants.dTheta);

    RZ [0] [2] = 0; //多余的,但清晰的帮助。

    RZ [1] [0] = Math.sin(符号* constants.dTheta);

    RZ [1] [1] = Math.cos(符号* constants.dTheta);

    RZ [1] [2] = 0;

    RZ [2] [0] = 0

    RZ [2] [1] = 0;

    RZ [2] [2] = 1;



    this.multi(RZ); //如果P是一组表面点,那么此方法进行矩阵multiplcation:接收* P

    this.erase(); //注意,人们可以使用两个画布来加快速度,这也省去了清除。

    this.draw();

  }



  // -----------------------------------------------------------------------------------------------------



  功能processKeyDown(EVT)

  {

    如果(evt.ctrlKey)

    {

      开关(evt.k​​ey code)

      {

        案例constants.upArrow:

          //无操作超过preventing箭头键的默认行为等。

          。EVT preventDefault(); //这个prevents方向键,这是滚动浏览器窗口时滚动条是present的默认行为。用户仍然可以滚动使用鼠标的窗口。

          打破;

        案例constants.downArrow:

          //无操作超过preventing箭头键的默认行为等。

          。EVT preventDefault();

          打破;

        案例constants.leftArrow:

          //执行console.log(CTRL + LEFTARROW);

          surface.zRotate(-1); //符号决定如果表面旋转顺时针或逆时针。

          。EVT preventDefault();

          打破;

        案例constants.rightArrow:

          //执行console.log(CTRL +向右键);

          surface.zRotate(1);

          。EVT preventDefault();

          打破;

      }

      返回; //当控制键pssed $ P $,只有左,右箭头有内涵,不需要处理任何其他键击(即现在的保释)。

    }



    //断言:控制关键不是pressed。



    开关(evt.k​​ey code)

    {

      案例constants.upArrow:

        //执行console.log(UPARROW);

        surface.xRotate(1);

        。EVT preventDefault();

        打破;

      案例constants.downArrow:

        //执行console.log(DownArrow中文);

        surface.xRotate(-1);

        。EVT preventDefault();

        打破;

      案例constants.leftArrow:

        //执行console.log(LEFTARROW);

        surface.yRotate(-1);

        。EVT preventDefault();

        打破;

      案例constants.rightArrow:

        //执行console.log(向右键);

        surface.yRotate(1);

        。EVT preventDefault();

        打破;

    }

  }



  // -----------------------------------------------------------------------------------------------------
  Surface.prototype.plot =功能(X,Y,Z)
  / *
    点(x,Y,Z)(以3×1的矢量格式)添加到表面。
  * /
  {
        this.points.push(点(x,Y,Z)); //存储表面点
        变种X = 0;
        对于(VAR X = constants.xMin,X< = constants.xMax; X + = constants.xDelta)
        {
        this.points.push(点(x,0,0));

        }

        / *为(VAR X = constants.xMax + 1; X< = constants.xMax + 2 X + = constants.xDelta)
        {
        this.points.push(点(11,0,0))
        } * /
        对于(VAR X = constants.xMin,X< = constants.xMax; X + = constants.yDelta)
        {
        this.points.push(点(0,X,0));
        }
        对于(VAR X = constants.xMin,X< = constants.xMax; X + = constants.yDelta)
        {
        this.points.push(点(0,0,X));
        }
  }


  函数调用onLoadInit()

  {

    appendCanvasElement(); //创建并添加canvas元素到DOM。

    surface.draw(); //绘制面在画布上。

    document.addEventListener('的keydown,processKeyDown,假); //用来检测控制键已经pssed $ P $。

  }



  // -----------------------------------------------------------------------------------------------------




  //surface.generate(); //创建设定点reprsenting表面。颜色之前必须调用()。
   surface.plot(1,1,1);
  surface.color(); //基于最小和最大z坐标值,选择颜色,基于点的Z ccordinate值(即,高度)每个点。

  window.addEventListener('负荷'器onLoadInit,假); //执行必须发生后,页面完全加载处理。

  < / SCRIPT>

  < /头>

  <身体GT;


  &其中; P>将z轴从屏幕的中心延伸出来&所述; BR>

    绕x轴,preSS的向上/向下箭头键。
    绕y轴,preSS的左/右箭头键。
    绕Z轴,preSS按Ctrl +左/ Ctrl +向下箭头键。
     需要注意的是pressing箭头键,连续不会旋转表面。表面旋转一次,每个键preSS< / P>

  <! - 画布元素添加到DOM这里。 - >

    < /身体GT;

  < / HTML>
 

解决方案

文本上绘制一个矩形平面。让坐标左上角的是(XTL,YTL,ZTL) 到右角落(XTR,YTR,ZTR)和左下是(XBL,YBL,ZBL)然后任何转换都被应用到这些坐标,然后将coordoinates用于2D投影到画布必须计算。这将产生一个平行四边形到其中的文本可以得出,但还需要进行改造。

最简单的是将计算左上角改造,并在该点绘制标准文本,也许减少因在z文本大小。

I have done a 3d graph to plot points in it. I have drawn x,y and z axis. Also you can rotate the axis by pressing arrow keys.Now my problem marking the axis as x,y and z .I tried to add text in canvas by using filltext.But the text gets added to canvas but its not rotating.It is because i have not set rotation effect for it i guess.So how can i set the rotation to text so that when axis rotates the text also rotates together.Below is my code.

  <!DOCTYPE html>



  <html>

  <head>

 <title>Canvas Surface Rotation</title>

 <style>

  body {

    text-align: center;

  }



  canvas {

    border: 1px solid black;

  }

  </style>

  <script>   

  var constants = {

    canvasWidth: 600, // In pixels.

    canvasHeight: 600, // In pixels.

    leftArrow: 37,

    upArrow: 38,

    rightArrow: 39,

    downArrow: 40,

    xMin: -10, // These four max/min values define a square on the xy-plane that the surface will be plotted over.

    xMax: 10,

    yMin: -10,

    yMax: 10, 

    xDelta: 0.01, // Make smaller for more surface points. 

    yDelta: 0.01, // Make smaller for more surface points. 

    colorMap: ["#060"], // There are eleven possible "vertical" color values for the surface, based on the last row of http://www.cs.siena.edu/~lederman/truck/AdvanceDesignTrucks/html_color_chart.gif

    pointWidth: 2, // The size of a rendered surface point (i.e., rectangle width and height) in pixels.

    dTheta: 0.05, // The angle delta, in radians, by which to rotate the surface per key press.

    surfaceScale: 24 // An empirically derived constant that makes the surface a good size for the given canvas size.

  };



  // These are constants too but I've removed them from the above constants literal to ease typing and improve clarity.

  var X = 0;

  var Y = 1;

  var Z = 2;



  // -----------------------------------------------------------------------------------------------------  



  var controlKeyPressed = false; // Shared between processKeyDown() and processKeyUp().

  var surface = new Surface(); // A set of points (in vector format) representing the surface.



  // -----------------------------------------------------------------------------------------------------



  function point(x, y, z)

  /*

    Given a (x, y, z) surface point, returns the 3 x 1 vector form of the point.

  */

  {       

    return [x, y, z]; // Return a 3 x 1 vector representing a traditional (x, y, z) surface point. This vector form eases matrix multiplication.

  }



  // -----------------------------------------------------------------------------------------------------



  function Surface()

  /*

    A surface is a list of (x, y, z) points, in 3 x 1 vector format. This is a constructor function.

  */

  {

    this.points = []; // An array of surface points in vector format. That is, each element of this array is a 3 x 1 array, as in [ [x1, y1, z1], [x2, y2, z2], [x3, y3, z3], ... ]

  }



  // -----------------------------------------------------------------------------------------------------  



  Surface.prototype.equation = function(x, y)

  /*

    Given the point (x, y), returns the associated z-coordinate based on the provided surface equation, of the form z = f(x, y).

  */

  {

    var d = Math.sqrt(x*x + y*y); // The distance d of the xy-point from the z-axis.



    return 4*(Math.sin(d) / d); // Return the z-coordinate for the point (x, y, z). 

  }



  // -----------------------------------------------------------------------------------------------------  



  Surface.prototype.generate = function()

  /*

    Creates a list of (x, y, z) points (in 3 x 1 vector format) representing the surface.

  */

  {

    var i = 0;



    for (var x = constants.xMin; x <= constants.xMax; x += constants.xDelta)

    {

      for (var y = constants.yMin; y <= constants.yMax; y += constants.yDelta)

      {

        this.points[i] = point(x, y, this.equation(x, y)); // Store a surface point (in vector format) into the list of surface points.              

        ++i;

      }

    }

  }



  // -----------------------------------------------------------------------------------------------------



  Surface.prototype.color = function()

  /*

    The color of a surface point is a function of its z-coordinate height.

  */

  {

    var z; // The z-coordinate for a given surface point (x, y, z).



    this.zMin = this.zMax = this.points[0][Z]; // A starting value. Note that zMin and zMax are custom properties that could possibly be useful if this code is extended later.

    for (var i = 0; i < this.points.length; i++)

    {            

      z = this.points[i][Z];

      if (z < this.zMin) { this.zMin = z; }

      if (z > this.zMax) { this.zMax = z; }

    }   



    var zDelta = Math.abs(this.zMax - this.zMin) / constants.colorMap.length; 



    for (var i = 0; i < this.points.length; i++)

    {

      this.points[i].color = constants.colorMap[ Math.floor( (this.points[i][Z]-this.zMin)/zDelta ) ];

    }



    /* Note that the prior FOR loop is functionally equivalent to the follow (much less elegant) loop:       

    for (var i = 0; i < this.points.length; i++)

    {

      if (this.points[i][Z] <= this.zMin + zDelta) {this.points[i].color = "#060";}

      else if (this.points[i][Z] <= this.zMin + 2*zDelta) {this.points[i].color = "#090";}

      else if (this.points[i][Z] <= this.zMin + 3*zDelta) {this.points[i].color = "#0C0";}

      else if (this.points[i][Z] <= this.zMin + 4*zDelta) {this.points[i].color = "#0F0";}

      else if (this.points[i][Z] <= this.zMin + 5*zDelta) {this.points[i].color = "#9F0";}

      else if (this.points[i][Z] <= this.zMin + 6*zDelta) {this.points[i].color = "#9C0";}

      else if (this.points[i][Z] <= this.zMin + 7*zDelta) {this.points[i].color = "#990";}

      else if (this.points[i][Z] <= this.zMin + 8*zDelta) {this.points[i].color = "#960";}

      else if (this.points[i][Z] <= this.zMin + 9*zDelta) {this.points[i].color = "#930";}

      else if (this.points[i][Z] <= this.zMin + 10*zDelta) {this.points[i].color = "#900";}          

      else {this.points[i].color = "#C00";}

    }

    */

  }



  // -----------------------------------------------------------------------------------------------------



  function appendCanvasElement()

  /*

    Creates and then appends the "myCanvas" canvas element to the DOM.

  */

  {

    var canvasElement = document.createElement('canvas');



    canvasElement.width = constants.canvasWidth;

    canvasElement.height = constants.canvasHeight;

    canvasElement.id = "myCanvas";



    canvasElement.getContext('2d').translate(constants.canvasWidth/2, constants.canvasHeight/2); // Translate the surface's origin to the center of the canvas.



    document.body.appendChild(canvasElement); // Make the canvas element a child of the body element.

  }



  //------------------------------------------------------------------------------------------------------



  Surface.prototype.sortByZIndex = function(A, B) 

  {

    return A[Z] - B[Z]; // Determines if point A is behind, in front of, or at the same level as point B (with respect to the z-axis).

  }



  // -----------------------------------------------------------------------------------------------------



  Surface.prototype.draw = function()

  {

    var myCanvas = document.getElementById("myCanvas"); // Required for Firefox.

    var ctx = myCanvas.getContext("2d");



    this.points = surface.points.sort(surface.sortByZIndex); // Sort the set of points based on relative z-axis position. If the points are visibly small, you can sort of get away with removing this step.

  var c=document.getElementById("myCanvas");
 var ctx=c.getContext("2d");
  ctx.font="20px Arial";
  ctx.fillText("X",250,0);

    for (var i = 0; i < this.points.length; i++)

    {

      ctx.fillStyle = this.points[i].color; 

      ctx.fillRect(this.points[i][X] * constants.surfaceScale, this.points[i][Y] * constants.surfaceScale, constants.pointWidth, constants.pointWidth);  

    }    

  }



  // -----------------------------------------------------------------------------------------------------



  Surface.prototype.multi = function(R)

  /*

    Assumes that R is a 3 x 3 matrix and that this.points (i.e., P) is a 3 x n matrix. This method performs P = R * P.

  */

  {

    var Px = 0, Py = 0, Pz = 0; // Variables to hold temporary results.

    var P = this.points; // P is a pointer to the set of surface points (i.e., the set of 3 x 1 vectors).

    var sum; // The sum for each row/column matrix product.



    for (var V = 0; V < P.length; V++) // For all 3 x 1 vectors in the point list.

    {

      Px = P[V][X], Py = P[V][Y], Pz = P[V][Z];

      for (var Rrow = 0; Rrow < 3; Rrow++) // For each row in the R matrix.

      {

        sum = (R[Rrow][X] * Px) + (R[Rrow][Y] * Py) + (R[Rrow][Z] * Pz);

        P[V][Rrow] = sum;

      }

    }     

  }



  // -----------------------------------------------------------------------------------------------------



  Surface.prototype.erase = function()

  {

    var myCanvas = document.getElementById("myCanvas"); // Required for Firefox.

    var ctx = myCanvas.getContext("2d");



    ctx.clearRect(-constants.canvasWidth/2, -constants.canvasHeight/2, myCanvas.width, myCanvas.height);

  }



  // -----------------------------------------------------------------------------------------------------



  Surface.prototype.xRotate = function(sign)

  /*

    Assumes "sign" is either 1 or -1, which is used to rotate the surface "clockwise" or "counterclockwise".

  */

  {

    var Rx = [ [0, 0, 0],

               [0, 0, 0],

               [0, 0, 0] ]; // Create an initialized 3 x 3 rotation matrix.



    Rx[0][0] = 1;

    Rx[0][1] = 0; // Redundant but helps with clarity.

    Rx[0][2] = 0; 

    Rx[1][0] = 0; 

    Rx[1][1] = Math.cos( sign*constants.dTheta );

    Rx[1][2] = -Math.sin( sign*constants.dTheta );

    Rx[2][0] = 0; 

    Rx[2][1] = Math.sin( sign*constants.dTheta );

    Rx[2][2] = Math.cos( sign*constants.dTheta );



    this.multi(Rx); // If P is the set of surface points, then this method performs the matrix multiplcation: Rx * P

    this.erase(); // Note that one could use two canvases to speed things up, which also eliminates the need to erase.

    this.draw();

  }



  // -----------------------------------------------------------------------------------------------------



  Surface.prototype.yRotate = function(sign)

  /*

    Assumes "sign" is either 1 or -1, which is used to rotate the surface "clockwise" or "counterclockwise".

  */      

  {

    var Ry = [ [0, 0, 0],

               [0, 0, 0],

               [0, 0, 0] ]; // Create an initialized 3 x 3 rotation matrix.



    Ry[0][0] = Math.cos( sign*constants.dTheta );

    Ry[0][1] = 0; // Redundant but helps with clarity.

    Ry[0][2] = Math.sin( sign*constants.dTheta );

    Ry[1][0] = 0; 

    Ry[1][1] = 1;

    Ry[1][2] = 0; 

    Ry[2][0] = -Math.sin( sign*constants.dTheta );

    Ry[2][1] = 0; 

    Ry[2][2] = Math.cos( sign*constants.dTheta );



    this.multi(Ry); // If P is the set of surface points, then this method performs the matrix multiplcation: Rx * P

    this.erase(); // Note that one could use two canvases to speed things up, which also eliminates the need to erase.

    this.draw();

  }



  // -----------------------------------------------------------------------------------------------------



  Surface.prototype.zRotate = function(sign)

  /*

    Assumes "sign" is either 1 or -1, which is used to rotate the surface "clockwise" or "counterclockwise".

  */      

  {

    var Rz = [ [0, 0, 0],

               [0, 0, 0],

               [0, 0, 0] ]; // Create an initialized 3 x 3 rotation matrix.



    Rz[0][0] = Math.cos( sign*constants.dTheta );

    Rz[0][1] = -Math.sin( sign*constants.dTheta );        

    Rz[0][2] = 0; // Redundant but helps with clarity.

    Rz[1][0] = Math.sin( sign*constants.dTheta );

    Rz[1][1] = Math.cos( sign*constants.dTheta );

    Rz[1][2] = 0;

    Rz[2][0] = 0

    Rz[2][1] = 0;

    Rz[2][2] = 1;



    this.multi(Rz); // If P is the set of surface points, then this method performs the matrix multiplcation: Rx * P

    this.erase(); // Note that one could use two canvases to speed things up, which also eliminates the need to erase.

    this.draw();

  }



  // -----------------------------------------------------------------------------------------------------



  function processKeyDown(evt)

  {                    

    if (evt.ctrlKey)

    {

      switch (evt.keyCode)

      {

        case constants.upArrow: 

          // No operation other than preventing the default behavior of the arrow key.

          evt.preventDefault(); // This prevents the default behavior of the arrow keys, which is to scroll the browser window when scroll bars are present. The user can still scroll the window with the mouse.              

          break;

        case constants.downArrow:

          // No operation other than preventing the default behavior of the arrow key.

          evt.preventDefault();

          break;

        case constants.leftArrow:

          // console.log("ctrl+leftArrow");

          surface.zRotate(-1); // The sign determines if the surface rotates "clockwise" or "counterclockwise". 

          evt.preventDefault(); 

          break;

        case constants.rightArrow:

          // console.log("ctrl+rightArrow");

          surface.zRotate(1);

          evt.preventDefault(); 

          break;

      }

      return; // When the control key is pressed, only the left and right arrows have meaning, no need to process any other key strokes (i.e., bail now).

    }



    // Assert: The control key is not pressed.



    switch (evt.keyCode)

    {

      case constants.upArrow:

        // console.log("upArrow");

        surface.xRotate(1);

        evt.preventDefault(); 

        break;

      case constants.downArrow:

        // console.log("downArrow");

        surface.xRotate(-1); 

        evt.preventDefault(); 

        break;

      case constants.leftArrow:

        // console.log("leftArrow");

        surface.yRotate(-1);  

        evt.preventDefault(); 

        break;

      case constants.rightArrow:

        // console.log("rightArrow");

        surface.yRotate(1);   

        evt.preventDefault(); 

        break;

    }

  }



  // -----------------------------------------------------------------------------------------------------
  Surface.prototype.plot = function(x, y, z)
  /*
    add the point (x, y, z)  (in 3 x 1 vector format) to the surface.
  */
  {
        this.points.push(point(x, y, z)); // Store a surface point
        var x=0;
        for (var x = constants.xMin; x <= constants.xMax; x += constants.xDelta)
        {
        this.points.push(point(x, 0, 0));

        }

        /*for (var x = constants.xMax+1; x <= constants.xMax+2; x += constants.xDelta)
        {
        this.points.push(point(11, 0, 0))
        }*/
        for (var x = constants.xMin; x <= constants.xMax; x += constants.yDelta)
        {
        this.points.push(point(0, x, 0));   
        }
        for (var x = constants.xMin; x <= constants.xMax; x += constants.yDelta)
        {
        this.points.push(point(0,0,x)); 
        }
  }


  function onloadInit()

  {

    appendCanvasElement(); // Create and append the canvas element to the DOM.

    surface.draw(); // Draw the surface on the canvas.

    document.addEventListener('keydown', processKeyDown, false); // Used to detect if the control key has been pressed.

  }



  // -----------------------------------------------------------------------------------------------------




  //surface.generate(); // Creates the set of points reprsenting the surface. Must be called before color().
   surface.plot(1,1,1);
  surface.color(); // Based on the min and max z-coordinate values, chooses colors for each point based on the point's z-ccordinate value (i.e., height).

  window.addEventListener('load', onloadInit, false); // Perform processing that must occur after the page has fully loaded.

  </script>

  </head>

  <body>


  <p>The z-axis extends out from the center of the screen.<br>

    To rotate about the x-axis, press the up/down arrow keys.
    To rotate about the y-axis, press the left/right arrow keys.
    To rotate about the z-axis, press the ctrl+left/ctrl+down arrow keys.
     Note that pressing an arrow key down continuously will not rotate the surface. The surface is rotated once per key press.</p>

  <!-- The canvas element is append to the DOM here. -->

    </body>

  </html>

解决方案

Text is drawn on a rectangular plane. Let the co-ordinates of top left be (xtl,ytl,ztl) to right corner be (xtr,ytr,ztr) and bottom left be (xbl,ybl,zbl) then any transformations have to be applied to these coordinates and then the coordoinates for the 2D projection onto the canvas have to be calculated. This will produce a parallelogram into which the text can be drawn but would also need to be transformed.

The simplest would be to calculate the top left corner transformation and draw standard text at that point, perhaps reducing text size depending on z.

这篇关于帆布3D图形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆