<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      代碼改變世界

      攝像機、投影、3D旋轉、縮放

      2011-09-23 08:18  【當耐特】  閱讀(20841)  評論(64)    收藏  舉報

      簡述

      3D效果分兩種,一種是偽3D骨架,一種是3D實體.

      3D骨架:是通過大量的計算將3D世界中所有點投影到二維平面中。

      3D實體:通過攝像機向投影面發射射線與世界中的物體交匯,把與物體交匯點的顏色渲染到投影面 (光線追蹤的基礎) 。

      本系列的所有演示都是3D骨架,非3D實體。本文將穿插圖片、公式、代碼、演示,讓讀者深刻理解3D的基本概念極其思想。

       

      對象及概念介紹

      對象一:攝像機。

      大家都有一個基本常識,在不同的角度觀看到的物體是不同的。攝像機對象有自己的空間的坐標(vidiconX,vidiconY,vidiconZ)。

      對象二:顯示屏

      任何三維物體,都會以二維的形式投影在顯示屏上,顯示屏垂直于攝像機的觀測方向,所以攝像機的空間坐標變化,會導致顯示屏的坐標系的變換

      對象三:被觀察測物體

      任何物體都是有無數個點構成,每個點有自己的空間坐標(x,y,z),顯示屏介于攝像機和物體之間。

       

      為了降低復雜度,本文將顯示屏和被觀測物體所處的坐標系公用一套(x,y),所有的旋轉都是物體旋轉,攝像機不動!

      縮放原理:攝像機不動,被觀察測物體不動,顯示屏離攝像機越近,縮放比例越小,顯示屏離攝像機越遠,縮放比例越大。


      投影分析

      我們來看下面這張圖:

      3Dp1

       

      因為,我們將顯示屏和被觀測物體共用一個坐標系,所以,我們可以計算出點(x1,y1,z1)投影到顯示屏上的點的縮放比例為:

      h / Math.abs(vidiconZ - z1)

      所以投影后的坐標為:

      x = x1 * h / Math.abs(vidiconZ - z);

      y=  y1 * h / Math.abs(vidiconZ - z);

       

      有了以上這些知識,我們可以輕松的在Canvas里畫一個正方體(再次強調,是根據計算的結果畫,非人類經驗)。

       <canvas id="myCanvas" width="700" height="500" style="border: 1px solid #c3c3c3;">
      Your browser does not support the canvas element.
      </canvas>
      <script type="text/javascript">
          var c = document.getElementById("myCanvas");
          var cxt = c.getContext("2d");
          cxt.lineWidth = 3;
          //正方體8個頂點
          var Point1 = { x: 100, y: 100, z: 100 };
          var Point2 = { x: 100, y: 100, z: -100 };
          var Point3 = { x: -100, y: 100, z: -100 };
          var Point4 = { x: -100, y: 100, z: 100 };
          var Point_1 = { x: 100, y: -100, z: 100 };
          var Point_2 = { x: 100, y: -100, z: -100 };
          var Point_3 = { x: -100, y: -100, z: -100 };
          var Point_4 = { x: -100, y: -100, z: 100 };
          var startX = 250;
          var startY = 250;
          //攝像機到顯示屏的距離
          var distance = 500;
          //攝像機位置
          var eyePosition = { x: 0, y: 0, z: 700 };
          function changeDistance() {
              Point1.x = Point1.x * distance / Math.abs(eyePosition.z - Point1.z);
              Point1.y = Point1.y * distance / Math.abs(eyePosition.z - Point1.z);
              Point2.x = Point2.x * distance / Math.abs(eyePosition.z - Point2.z);
              Point2.y = Point2.y * distance / Math.abs(eyePosition.z - Point2.z);
              Point3.x = Point3.x * distance / Math.abs(eyePosition.z - Point3.z);
              Point3.y = Point3.y * distance / Math.abs(eyePosition.z - Point3.z);
              Point4.x = Point4.x * distance / Math.abs(eyePosition.z - Point4.z);
              Point4.y = Point4.y * distance / Math.abs(eyePosition.z - Point4.z);
              Point_1.x = Point_1.x * distance / Math.abs(eyePosition.z - Point_1.z);
              Point_1.y = Point_1.y * distance / Math.abs(eyePosition.z - Point_1.z);
              Point_2.x = Point_2.x * distance / Math.abs(eyePosition.z - Point_2.z);
              Point_2.y = Point_2.y * distance / Math.abs(eyePosition.z - Point_2.z);
              Point_3.x = Point_3.x * distance / Math.abs(eyePosition.z - Point_3.z);
              Point_3.y = Point_3.y * distance / Math.abs(eyePosition.z - Point_3.z);
              Point_4.x = Point_4.x * distance / Math.abs(eyePosition.z - Point_4.z);
              Point_4.y = Point_4.y * distance / Math.abs(eyePosition.z - Point_4.z);
          }
          var drawCube = function () {
              changeDistance();
              cxt.beginPath();
              cxt.moveTo(startX + Point1.x, startY - Point1.y);
              cxt.lineTo(startX + Point2.x, startY - Point2.y);
              cxt.lineTo(startX + Point3.x, startY - Point3.y);
              cxt.lineTo(startX + Point4.x, startY - Point4.y);
              cxt.lineTo(startX + Point1.x, startY - Point1.y);
              cxt.moveTo(startX + Point_1.x, startY - Point_1.y);
              cxt.lineTo(startX + Point_2.x, startY - Point_2.y);
              cxt.lineTo(startX + Point_3.x, startY - Point_3.y);
              cxt.lineTo(startX + Point_4.x, startY - Point_4.y);
              cxt.lineTo(startX + Point_1.x, startY - Point_1.y);
              cxt.moveTo(startX + Point2.x, startY - Point2.y);
              cxt.lineTo(startX + Point_2.x, startY - Point_2.y);
              cxt.moveTo(startX + Point1.x, startY - Point1.y);
              cxt.lineTo(startX + Point_1.x, startY - Point_1.y);
              cxt.moveTo(startX + Point3.x, startY - Point3.y);
              cxt.lineTo(startX + Point_3.x, startY - Point_3.y);
              cxt.moveTo(startX + Point4.x, startY - Point4.y);
              cxt.lineTo(startX + Point_4.x, startY - Point_4.y);
              cxt.stroke();
          }
      </script>
      <div id="show">
      </div>
      <input type="button" onclick="drawCube();" value="開始畫立方體"
      style="width: 135px" />

      演示

      Your browser does not support the canvas element.

      當然我們可以重構一下,將8個點都放到Array中。

       <script type="text/javascript">
           var c = document.getElementById("myCanvas");
           var cxt = c.getContext("2d");
           cxt.lineWidth = 3;
           //正方體8個頂點
           var Point = new Array();
           Point[0] = { x: 100, y: 100, z: 100 };
           Point[1] = { x: 100, y: 100, z: -100 };
           Point[2] = { x: -100, y: 100, z: -100 };
           Point[3] = { x: -100, y: 100, z: 100 };
           Point[4] = { x: 100, y: -100, z: 100 };
           Point[5] = { x: 100, y: -100, z: -100 };
           Point[6] = { x: -100, y: -100, z: -100 };
           Point[7] = { x: -100, y: -100, z: 100 };
           var startX = 250;
           var startY = 250;
           //攝像機到顯示屏的距離
           var distance = 500;
           //攝像機位置
           var eyePosition = { x: 0, y: 0, z: 700 };
           function changeDistance() {
               for (var i = 0; i < Point.length; i++) {
                   Point[i].x = Point[i].x * distance / Math.abs(eyePosition.z - Point[i].z);
                   Point[i].y = Point[i].y * distance / Math.abs(eyePosition.z - Point[i].z);
               }
           }
           var drawCube = function () {
               changeDistance();
               cxt.beginPath();
               cxt.moveTo(startX + Point[0].x, startY - Point[0].y);
               cxt.lineTo(startX + Point[1].x, startY - Point[1].y);
               cxt.lineTo(startX + Point[2].x, startY - Point[2].y);
               cxt.lineTo(startX + Point[3].x, startY - Point[3].y);
               cxt.lineTo(startX + Point[0].x, startY - Point[0].y);
               cxt.moveTo(startX + Point[4].x, startY - Point[4].y);
               cxt.lineTo(startX + Point[5].x, startY - Point[5].y);
               cxt.lineTo(startX + Point[6].x, startY - Point[6].y);
               cxt.lineTo(startX + Point[7].x, startY - Point[7].y);
               cxt.lineTo(startX + Point[4].x, startY - Point[4].y);
               cxt.moveTo(startX + Point[1].x, startY - Point[1].y);
               cxt.lineTo(startX + Point[5].x, startY - Point[5].y);
               cxt.moveTo(startX + Point[0].x, startY - Point[0].y);
               cxt.lineTo(startX + Point[4].x, startY - Point[4].y);
               cxt.moveTo(startX + Point[2].x, startY - Point[2].y);
               cxt.lineTo(startX + Point[6].x, startY - Point[6].y);
               cxt.moveTo(startX + Point[3].x, startY - Point[3].y);
               cxt.lineTo(startX + Point[7].x, startY - Point[7].y);
               cxt.stroke();
           }
      </script>

      現在,我們看到了正方體正常的顯示在畫布當中,那么我們現在來用演示證明一下縮放原理

      縮放原理:攝像機不動,被觀察測物體不動,顯示屏離攝像機越近,縮放比例越小,顯示屏離攝像機越遠,縮放比例越大。

      <script language="javascript" type="text/javascript" src="lib/uglifyjs-parser.js"></script>
      <script language="javascript" type="text/javascript" src="src/jscex.js"></script>
      <script language="javascript" type="text/javascript" src="src/jscex.builderBase.js"></script>
      <script language="javascript" type="text/javascript" src="src/jscex.async.js"></script>
      <!--[if IE]>
      <script language="javascript" type="text/javascript" src="lib/json2.js"></script>
      <script language="javascript">
      Jscex.config.codeGenerator = function (code) { return "false || " + code; }
      </script>
      <![endif]-->
      <canvas id="myCanvas" width="700" height="500" style="border: 1px solid #c3c3c3;">
      Your browser does not support the canvas element.
      </canvas>
      <script type="text/javascript">
          var c = document.getElementById("myCanvas");
          var cxt = c.getContext("2d");
          cxt.lineWidth = 3;
          var Point = new Array();
          var startX = 250;
          var startY = 250;
          var distance = 500;
          var eyePosition = { x: 0, y: 0, z: 700 };
          function init() {
              Point[0] = { x: 100, y: 100, z: 100 };
              Point[1] = { x: 100, y: 100, z: -100 };
              Point[2] = { x: -100, y: 100, z: -100 };
              Point[3] = { x: -100, y: 100, z: 100 };
              Point[4] = { x: 100, y: -100, z: 100 };
              Point[5] = { x: 100, y: -100, z: -100 };
              Point[6] = { x: -100, y: -100, z: -100 };
              Point[7] = { x: -100, y: -100, z: 100 };
          }
          function changeDistance() {
              for (var i = 0; i < Point.length; i++) {
                  Point[i].x = Point[i].x * distance / Math.abs(eyePosition.z - Point[i].z);
                  Point[i].y = Point[i].y * distance / Math.abs(eyePosition.z - Point[i].z);
              }
          }
          var drawCube = function (increment) {
              cxt.clearRect(0, 0, 1200, 1200);
              init();
              distance += increment;
              changeDistance();
              cxt.beginPath();
              cxt.moveTo(startX + Point[0].x, startY - Point[0].y);
              cxt.lineTo(startX + Point[1].x, startY - Point[1].y);
              cxt.lineTo(startX + Point[2].x, startY - Point[2].y);
              cxt.lineTo(startX + Point[3].x, startY - Point[3].y);
              cxt.lineTo(startX + Point[0].x, startY - Point[0].y);
              cxt.moveTo(startX + Point[4].x, startY - Point[4].y);
              cxt.lineTo(startX + Point[5].x, startY - Point[5].y);
              cxt.lineTo(startX + Point[6].x, startY - Point[6].y);
              cxt.lineTo(startX + Point[7].x, startY - Point[7].y);
              cxt.lineTo(startX + Point[4].x, startY - Point[4].y);
              cxt.moveTo(startX + Point[1].x, startY - Point[1].y);
              cxt.lineTo(startX + Point[5].x, startY - Point[5].y);
              cxt.moveTo(startX + Point[0].x, startY - Point[0].y);
              cxt.lineTo(startX + Point[4].x, startY - Point[4].y);
              cxt.moveTo(startX + Point[2].x, startY - Point[2].y);
              cxt.lineTo(startX + Point[6].x, startY - Point[6].y);
              cxt.moveTo(startX + Point[3].x, startY - Point[3].y);
              cxt.lineTo(startX + Point[7].x, startY - Point[7].y);
              cxt.stroke();
          }
          var reduceDrawCubeAsync = eval(Jscex.compile("async", function () {
              //當攝像機到顯示屏的距離大于750,退出循環·
              while (distance < 750) {
                  drawCube(10);
                  $await(Jscex.Async.sleep(100));
              }
          }));
          var magnifyDrawCubeAsync = eval(Jscex.compile("async", function () {
              //當攝像機到顯示屏的距離小于150,退出循環·
              while (distance > 150) {
                  drawCube(-10);
                  $await(Jscex.Async.sleep(100));
              }
          }));
          var executeAsync = eval(Jscex.compile("async", function () {
              $await(reduceDrawCubeAsync());
              $await(magnifyDrawCubeAsync());
          }));
      </script>
      <div id="show">
      </div>
      <input type="button" onclick="executeAsync().start();" value="開始移動顯示屏" style="width: 135px" />

      可以看到,我們定義了兩個異步任務reduceDrawCubeAsync 和magnifyDrawCubeAsync ,把它們放到executeAsync 隊列當中,

      他們會從上倒下,依次執行。

      演示

      Your browser does not support the canvas element.

      3D旋轉

      上面講了攝像機,投影以及縮放的原理以及實現,下面看旋轉。

      首先,在三維坐標系當中,任何角度的任何旋轉可以拆分成三類:

      a.繞X軸方向的旋轉,此時,y和z發生變化,x不變。

      b.繞Y軸方向的旋轉,此時,x和z發生變化,y不變。

      a.繞Z軸方向的旋轉,此時,x和y發生變化,x不變。

      那么x和z到底變化多少呢?我們可以看一下切面圖,然后計算出坐標的變化!

      3dp2

       

      或者我們也可以直接翻到大學教材書本第七章【三維旋轉矩陣】:

      3Dp3

       

      我們拿繞y軸旋轉為例子,如:

          //旋轉
          function rotate(angle) {
              for (var i = 0; i < Points.length; i++) {
                  var tempX = Points[i].x;
                  Points[i].x = Points[i].x * Math.cos(angle) - Points[i].z * Math.sin(angle);
                  Points[i].z = Points[i].z * Math.cos(angle) + tempX * Math.sin(angle);
              }
          }

      我們要記住,旋轉之后的坐標是在坐標系當中的坐標,我們還要講其投影到顯示屏,所以我們應當先旋轉---再投影,順序不能弄反。

      定義一個角度轉弧度:

          function degToRad(a) {
              return (a / (360 / (2 * Math.PI)));
          }

      立方體顏色變化:

          function randomColor() {
              var arrHex = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"]; var strHex = "#";
              var index;
              for (var i = 0; i < 6; i++) {
                  index = Math.round(Math.random() * 15);
                  strHex += arrHex[index];
              }
              return strHex;
          }

      旋轉控制核心,我們依然用Jscex:

         var currentAngle = 0;
          var drawCube2 = function () {
              cxt2.clearRect(0, 0, 1200, 1200);
              init();
              rotate(degToRad(currentAngle))
              changedistance2();
              cxt2.strokeStyle = randomColor();
              cxt2.beginPath();
              cxt2.moveTo(startX + Points[0].x, startY - Points[0].y);
              cxt2.lineTo(startX + Points[1].x, startY - Points[1].y);
              cxt2.lineTo(startX + Points[2].x, startY - Points[2].y);
              cxt2.lineTo(startX + Points[3].x, startY - Points[3].y);
              cxt2.lineTo(startX + Points[0].x, startY - Points[0].y);
              cxt2.moveTo(startX + Points[4].x, startY - Points[4].y);
              cxt2.lineTo(startX + Points[5].x, startY - Points[5].y);
              cxt2.lineTo(startX + Points[6].x, startY - Points[6].y);
              cxt2.lineTo(startX + Points[7].x, startY - Points[7].y);
              cxt2.lineTo(startX + Points[4].x, startY - Points[4].y);
              cxt2.moveTo(startX + Points[1].x, startY - Points[1].y);
              cxt2.lineTo(startX + Points[5].x, startY - Points[5].y);
              cxt2.moveTo(startX + Points[0].x, startY - Points[0].y);
              cxt2.lineTo(startX + Points[4].x, startY - Points[4].y);
              cxt2.moveTo(startX + Points[2].x, startY - Points[2].y);
              cxt2.lineTo(startX + Points[6].x, startY - Points[6].y);
              cxt2.moveTo(startX + Points[3].x, startY - Points[3].y);
              cxt2.lineTo(startX + Points[7].x, startY - Points[7].y);
              cxt2.stroke();
          }
          drawCube2()
          var rotateAsync = eval(Jscex.compile("async", function () {
              while (true) {
                  currentAngle += 5;
                  drawCube2();
                  $await(Jscex.Async.sleep(100));
              }
          }));

      演示

      Your browser does not support the canvas element.

      我們也可以讓它繞著X軸旋轉:

          for (var i = 0; i < Points4.length; i++) {
              var tempY = Points4[i].y;
              Points4[i].y = Points4[i].z * Math.sin(angle) - Points4[i].y * Math.cos(angle);
              Points4[i].z = tempY * Math.sin(angle) + Points4[i].z * Math.cos(angle);
          }

      演示

      Your browser does not support the canvas element.

      因為任何角度的任何旋轉可以拆分成三類,我們可以同時繞X軸和Y軸旋轉:

          function rotate(angle) {
              for (var i = 0; i < Points2.length; i++) {
                  var tempX = Points2[i].x;
                  var tempZ = Points2[i].z;
                  Points2[i].x = Points2[i].x * Math.cos(angle) - Points2[i].z * Math.sin(angle);
                  Points2[i].z = Points2[i].z * Math.cos(angle) + tempX * Math.sin(angle);
              }
              for (var i = 0; i < Points2.length; i++) {
                  var tempY = Points2[i].y;
                  Points2[i].y = Points2[i].y * Math.cos(angle) - Points2[i].z * Math.sin(angle);
                  Points2[i].z = tempY * Math.sin(angle) + Points2[i].z * Math.cos(angle);
              }
          }

      演示

      Your browser does not support the canvas element.

      總結

      本文介紹了攝像機、投影、旋轉、縮放等概念,并加以實現。本文為了降低復雜度,攝像機的位置不變,在真實的場景當中,比如一些3D游戲,如魔獸世界,攝像機和物體是都可以改變位置。

      主站蜘蛛池模板: 国产91精品调教在线播放| 奇米四色7777中文字幕| 国产麻豆成人精品av| 亚洲中文字幕在线二页| h无码精品动漫在线观看| 自拍第一区视频在线观看| 亚洲av永久无码精品天堂久久| 四虎在线成人免费观看| 四虎精品视频永久免费| av中文字幕一区人妻| 日本一道一区二区视频| 乱子伦视频在线看| 国产亚洲久久久久久久| 久久综合偷拍视频五月天| 午夜视频免费试看| 蜜臀久久综合一本av| 中文字幕国产精品一二区| 国产片av在线观看国语| 国产线播放免费人成视频播放| 亚洲免费成人av一区| 亚洲一区二区中文字幕| 日韩有码中文字幕国产| 亚洲精品一区二区天堂| 久热中文字幕在线| 久久一本人碰碰人碰| 亚洲aⅴ男人的天堂在线观看| 亚洲精品成人综合色在线| 97欧美精品系列一区二区| 人妻饥渴偷公乱中文字幕| 成av人片一区二区久久| 亚洲美免无码中文字幕在线| 日韩亚洲中文图片小说| 婷婷丁香五月激情综合| 精品亚洲综合一区二区三区| 亚洲国产精品久久无人区| 久久久久久久久18禁秘| 999福利激情视频| 国产中文字幕在线一区| 免费看欧美全黄成人片| 国产欧美日韩亚洲一区二区三区| 亚洲av无码牛牛影视在线二区 |