路徑跟隨

開講以前,先上個案例
演示地址: http://www.yxyy.name/example/...
下載地址:https://github.com/buglas/exa... > supPath.htmlhtml

一,原理

1.路徑跟隨必備對象:移動物體和路徑git

  • 如飛機和飛機移動路線

clipboard.png

2.須要考慮的狀況:github

  • 物體移動方向和位置必須受路徑約束
  • 物體的旋轉方向是否受路徑約束

旋轉方向不受路徑約束canvas

圖片描述

旋轉方向受路徑約束less

圖片描述

3.物體的旋轉方向若要受路徑約束,有兩種實現方式:動畫

  • 硬旋轉:物體旋轉角度和其所在線段的方向匹配(假設路徑是由線段組成的)。spa

    • 物體在拐點處的旋轉比較僵硬。如上圖。
  • 軟旋轉:物體在路徑的轉折處,圓滑過分。code

    • 物體在拐點處的旋轉是有過分的,轉折圓滑。以下圖:

圖片描述

4.實現軟旋轉的思路有兩種:htm

  • 預先圓滑拐點:在動畫以前,就對路徑作圓滑處理。就像上圖那樣。
  • 實時圓滑拐點:物體在移動過程當中,對本身的下一個位置進行圓滑處理。見下圖。

5.預先圓滑中,物體跟隨的路徑是已經被修改過的,因此它的移動軌跡也會和最初的路徑不吻合。對象

6.實時圓滑能夠將物體的旋轉屬性和位置屬性分離的,如圖

  • 只圓滑旋轉角度,物體跟隨原始路徑移動

clipboard.png

  • 圓滑旋轉角度和移動位置。物體的位置會根據兩點的位置作插值計算。後面案例會詳解。

clipboard.png

二,示例:用實時圓滑的方式實現路徑跟隨

此示例須要three.js 基礎,對於three.js 環節,我只作簡單概述。

1.搭建場景:

//獲取html 裏的canvas
const canvas = document.querySelector('#c');
const width = canvas.clientWidth;
const height = canvas.clientHeight;
//渲染器
const renderer = new THREE.WebGLRenderer({canvas});
renderer.setSize(width, height, false);
//相機
const fov = 45;
const aspect = width / height;
const near = 0.01;
const far = 10;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 2, 0);
camera.updateProjectionMatrix();
//場景
const scene = new THREE.Scene();

2.繪製路徑

let curve;
let curveObject;
{
  const points = [
      [0.5,0,0.5],
      [-0.5,0,0.5],
      [-0.5,0,-0.5],
  ];
  curve = new THREE.CatmullRomCurve3(
      points.map((p, ndx) => {
          return (new THREE.Vector3()).set(...p);
      }),
      true,
      'catmullrom',
      0.01
  );
  {
      const points = curve.getPoints(6);
      const geometry = new THREE.BufferGeometry().setFromPoints(points);
      const material = new THREE.LineBasicMaterial({color: 0xff0000});
      curveObject = new THREE.Line(geometry, material);
      scene.add(curveObject);
  };
}
  • THREE.CatmullRomCurve3 是一種數學概念上的曲線,它若想被顯示出來,還要被細分紅n 條線段。
  • curve.getPoints(6) 就是獲取將曲線細分紅六段後的頂點集合。
  • BufferGeometry().setFromPoints(points) 是用頂點建模,後面的線性材質和網格就不細說了。

clipboard.png

3.創建運動物體。
先用一個簡單的box 表示汽車。飛機的話,還得導入模型進來。先講重點。

let car;
{
    const geometry =new THREE.BoxBufferGeometry(.1,.1,.2);
    const material = new THREE.MeshBasicMaterial( {color: 0xcccccc} );
    car = new THREE.Mesh( geometry, material );
    scene.add(car);
}

clipboard.png

4.路徑跟隨動畫

//汽車位置
const carPosition = new THREE.Vector3();
//汽車目標點
const carTarget = new THREE.Vector3();
function render(time) {
    //將遞增的時間轉化爲距離
    let distance = time*0.0002;  // convert to seconds
    {
        //目標點到目標的距離
        const targetOffset = 0.1;
        //從曲線上獲取汽車點位。getPointAt 詳情查手冊。
        curve.getPointAt(distance % 1, carPosition);
        //從曲線上獲取汽車目標點位
        curve.getPointAt((distance + targetOffset) % 1, carTarget);
        //汽車定位
        car.position.copy(carPosition);
        //實現軟旋轉
        car.lookAt(carTarget);
        //圓滑位置
        //car.position.lerpVectors(carPosition, carTarget, 0.5);
    }
    renderer.render(scene, camera);
    requestAnimationFrame(render);
}
requestAnimationFrame(render);

注:{} 包裹代碼的寫法是跟let const 命令的塊級做用域有關,如此能夠避免變量污染上層對象的命名空間。

實例效果演示: http://www.yxyy.name/funk/路...

實例源文件:https://github.com/buglas/fun... > 路徑跟隨.html

參考網址:https://threejsfundamentals.o...

相關文章
相關標籤/搜索