欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

利用threejs實(shí)現(xiàn)一個(gè)簡易的泊車功能

 更新時(shí)間:2024年01月29日 09:11:34   作者:_lucas  
這篇文章主要為大家詳細(xì)介紹了如何利用threejs實(shí)現(xiàn)一個(gè)簡易的泊車功能,文中的示例代碼講解詳細(xì),對大家的學(xué)習(xí)和工作有一定的幫助,感興趣的小伙伴可以動手嘗試一下

簡易版小車

因?yàn)橹坝玫哪P捅容^大,加載很慢,這里就先自己簡單實(shí)現(xiàn)一輛小車(后面統(tǒng)稱自車),如下圖:

將車輪、車體和邊框組合成一個(gè) Group,便于后面做自車的一些操作,實(shí)現(xiàn)代碼如下:

 // 自車車體
const geometry = new THREE.BoxGeometry(2, 0.6, 3);
const material = new THREE.MeshBasicMaterial({
  color: 0x00ffff,
  side: THREE.DoubleSide,
});
const vehicle = new THREE.Mesh(geometry, material);
vehicle.position.set(0, 1, 0);
scene.add(vehicle);
// 增加自車邊框
const box = geometry.clone();
const edges = new THREE.EdgesGeometry(box);
const edgesMaterial = new THREE.LineBasicMaterial({
  color: 0x333333,
});
const line = new THREE.LineSegments(edges, edgesMaterial);
line.position.x = 0;
line.position.y = 1;
line.position.z = 0;
scene.add(line);
// 組成一個(gè)Group
const egoCar = new THREE.Group();
egoCar.name = "自車";
egoCar.add(vehicle, line);
scene.add(egoCar);
// 車輪
const axlewidth = 0.7;
const radius = 0.4;
const wheels: any[] = [];
const wheelObjects: any[] = [];
wheels.push({ position: [axlewidth, 0.4, -1], radius });
wheels.push({
  position: [-axlewidth, 0.4, -1],
  radius,
});
wheels.push({ position: [axlewidth, 0.4, 1], radius });
wheels.push({ position: [-axlewidth, 0.4, 1], radius });
wheels.forEach(function (wheel) {
  const geometry = new THREE.CylinderGeometry(
    wheel.radius,
    wheel.radius,
    0.4,
    32
  );
  const material = new THREE.MeshPhongMaterial({
    color: 0xd0901d,
    emissive: 0xee0000,
    side: THREE.DoubleSide,
    flatShading: true,
  });
  const cylinder = new THREE.Mesh(geometry, material);
  cylinder.geometry.rotateZ(Math.PI / 2);
  cylinder.position.set(
    wheel.position[0],
    wheel.position[1],
    wheel.position[2]
  );
  egoCar.add(cylinder);
  // 后面修改車輪方向會用到
  wheelObjects.push(cylinder);
});

跟車相機(jī)

讓相機(jī)一直跟著自車,體驗(yàn)更好一點(diǎn)

// ...
const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 800);
// 設(shè)置攝像機(jī)位置,并將其朝向場景中心
camera.position.x = 0;
// camera.position.y = 10;
// camera.position.z = 20;
// camera.lookAt(scene.position);
camera.lookAt(egoCar.position);
// ...
function animate() {
  stats.begin();
  controls.update();
  // 相機(jī)跟隨自車
  camera.position.y = egoCar.position.y + 15;
  camera.position.z = egoCar.position.z + 25;
  camera.lookAt(egoCar.position);
  renderer.render(scene, camera);
  stats.end();
  requestAnimationFrame(animate);
}
// ...

自車行駛

實(shí)現(xiàn)自車前行后退和左右轉(zhuǎn)向

// ...
// 記錄開始按下的時(shí)間
let startTime = 0;
const activeKeys = new Set();
let t = 0;
document.addEventListener("keydown", (e) => {
  activeKeys.add(e.key);
  if (startTime === 0) {
    startTime = Date.now();
  }
  t = (Date.now() - startTime) / 1000;
  if (t > 10) {
    t = 10;
  }
});
document.addEventListener("keyup", (e) => {
  activeKeys.delete(e.key);
  if (activeKeys.size === 0) {
    startTime = 0;
  }
});
function animate() {
  stats.begin();
  controls.update();
  // 相機(jī)跟隨自車
  camera.position.y = egoCar.position.y + 15;
  camera.position.z = egoCar.position.z + 25;
  camera.lookAt(egoCar.position);
  if (activeKeys.has("ArrowUp")) {
    // 估算對應(yīng)方向的移動距離
    egoCar.position.z -= t * 0.1 * Math.cos(egoCar.rotation.y);
    egoCar.position.x -= t * 0.1 * Math.sin(egoCar.rotation.y);
  }
  if (activeKeys.has("ArrowDown")) {
    egoCar.position.z += t * 0.1 * Math.cos(egoCar.rotation.y);
    egoCar.position.x += t * 0.1 * Math.sin(egoCar.rotation.y);
  }
  if (activeKeys.has("ArrowLeft")) {
    egoCar.rotation.y += 0.01;
  }
  if (activeKeys.has("ArrowRight")) {
    egoCar.rotation.y -= 0.01;
  }
  renderer.render(scene, camera);
  stats.end();
  requestAnimationFrame(animate);
}
//...

車輪轉(zhuǎn)動

遍歷車輪對象,動態(tài)修改車輪的偏轉(zhuǎn)角 rotation,以車頭方向?yàn)榛鶞?zhǔn)偏轉(zhuǎn)固定的角度

function animate() {
  // ...
  if (activeKeys.has("ArrowLeft")) {
    egoCar.rotation.y += 0.01;
    wheelObjects.forEach((wheel) => {
      wheel.rotation.y = egoCar.rotation.y + Math.PI / 4;
    });
  }
  if (activeKeys.has("ArrowRight")) {
    egoCar.rotation.y -= 0.01;
    wheelObjects.forEach((wheel) => {
      wheel.rotation.y = egoCar.rotation.y - Math.PI / 4;
    });
  }
  // ...
}

行進(jìn)效果還是有點(diǎn)僵硬(能用就行),這里的問題是行進(jìn)方向應(yīng)該是按車頭方向,而不是固定按某個(gè)坐標(biāo)軸方向,不過這里也只是簡單模擬這個(gè)行進(jìn)效果,后面再引入物理庫 cannon.js優(yōu)化下這塊控制邏輯

泊車功能

車位實(shí)現(xiàn)

做一個(gè)貼地面的矩形框來模擬車位,可以使用 THREE.PlaneGeometry 來創(chuàng)建平面幾何體

createParkingSpace() {
    const plane = new THREE.PlaneGeometry(8, 5);
    const material = new THREE.MeshPhongMaterial({
      color: 0x666666,
      side: THREE.DoubleSide,
    });
    const mesh = new THREE.Mesh(plane, material);
    mesh.rotation.x = -Math.PI / 2;
    mesh.position.set(10, 0.12, -20);
    this.scene?.add(mesh);
    // 增加自定義type,便于后面處理車位的選中邏輯
    mesh.userData.type = "parkingSpace";
}

現(xiàn)在咱們把小車開過去停到那個(gè)位置

自動泊車

需要實(shí)現(xiàn)點(diǎn)擊車位后高亮對應(yīng)的車位,之后小車自動行駛到對應(yīng)的位置并停好。點(diǎn)擊原理是用射線的方式采集第一個(gè)碰到的車位物體,當(dāng)點(diǎn)擊鼠標(biāo)時(shí),會發(fā)生以下步驟:

  • 基于屏幕上的點(diǎn)擊位置創(chuàng)建一個(gè) THREE.Vector3 向量
  • 使用 vector.unproject 方法將屏幕上點(diǎn)擊位置的坐標(biāo)轉(zhuǎn)換成 three.js 場景中的坐標(biāo)
  • 創(chuàng)建 THREE.Raycaster可以從攝像機(jī)的位置向場景中鼠標(biāo)的點(diǎn)擊位置發(fā)出一條射線
  • raycaster.intersectObjects 返回包含了所有被射線穿過的對象信息的數(shù)組(從攝像機(jī)位置開始由短到長)
function handleParkSpaceClick(event: any) {
  let vector = new THREE.Vector3(
    (event.clientX / window.innerWidth) * 2 - 1,
    -(event.clientY / window.innerHeight) * 2 + 1,
    0.5
  );
  vector = vector.unproject(camera);
  const raycaster = new THREE.Raycaster(
    camera.position,
    vector.sub(camera.position).normalize()
  );
  const intersects = raycaster.intersectObjects(scene.children);
  for (let i = 0; i < intersects.length; i++) {
    const obj = intersects[i];
    // @ts-ignore
    if (obj.object.userData.type === "parkingSpace")
      // @ts-ignore
      obj.object.material.color.set(0x00ff00);
  }
}
document.addEventListener("click", handleParkSpaceClick);

自動泊車的實(shí)現(xiàn)邏輯也比較簡單,這里簡單記住了車位的位置信息,然后讓小車按一定的偏移駛?cè)?,其?shí)實(shí)際場景可能還要考慮躲避障礙物、加減速、偏轉(zhuǎn)角等,一般也不由前端操心這些。實(shí)現(xiàn)代碼參考 three-gta v0.1.1 -- 在線體驗(yàn)

到此這篇關(guān)于利用threejs實(shí)現(xiàn)一個(gè)簡易的泊車功能的文章就介紹到這了,更多相關(guān)threejs泊車功能內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JS 面向?qū)ο笾衿娴膒rototype

    JS 面向?qū)ο笾衿娴膒rototype

    對于初學(xué) JavaScript 的人來說 prototype 是一種很神奇的特性,而事實(shí)上,prototype 對于 JavaScript 的意義重大,prototype 不僅僅是一種管理對象繼承的機(jī)制,更是一種出色的設(shè)計(jì)思想。
    2011-02-02
  • JS隨機(jī)生成不重復(fù)數(shù)據(jù)的實(shí)例方法

    JS隨機(jī)生成不重復(fù)數(shù)據(jù)的實(shí)例方法

    這篇文章介紹了JS隨機(jī)生成不重復(fù)數(shù)據(jù)的實(shí)例方法,有需要的朋友可以參考一下
    2013-07-07
  • 簡單實(shí)現(xiàn)js拖拽效果

    簡單實(shí)現(xiàn)js拖拽效果

    這篇文章主要教大家如何簡單實(shí)現(xiàn)js拖拽效果,很詳細(xì)的js拖拽效果實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • js組件SlotMachine實(shí)現(xiàn)圖片切換效果制作抽獎系統(tǒng)

    js組件SlotMachine實(shí)現(xiàn)圖片切換效果制作抽獎系統(tǒng)

    這篇文章主要介紹了js組件SlotMachine實(shí)現(xiàn)圖片切換效果制作抽獎系統(tǒng)的相關(guān)資料,需要的朋友可以參考下
    2016-04-04
  • 微信小程序支付功能完整流程記錄(前端)

    微信小程序支付功能完整流程記錄(前端)

    微信小程序的商戶系統(tǒng)一般是以接口的形式開發(fā)的,小程序通過調(diào)用與后端約定好的接口進(jìn)行參數(shù)的傳遞以及數(shù)據(jù)的接收,下面這篇文章主要給大家介紹了關(guān)于微信小程序支付功能(前端)的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • javascript引用類型之時(shí)間Date和數(shù)組Array

    javascript引用類型之時(shí)間Date和數(shù)組Array

    引用類型的值(對象)其實(shí)就是引用類型的一個(gè)實(shí)例,接下來,通過本篇文章給大家介紹javascript引用類型之時(shí)間Date和數(shù)組Array,需要的朋友可以參考下
    2015-08-08
  • 淺談Fetch 數(shù)據(jù)交互方式

    淺談Fetch 數(shù)據(jù)交互方式

    這篇文章主要介紹了淺談Fetch 數(shù)據(jù)交互方式,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-12-12
  • 微信小程序中如何計(jì)算距離某個(gè)節(jié)日還有多少天

    微信小程序中如何計(jì)算距離某個(gè)節(jié)日還有多少天

    這篇文章主要給大家介紹了關(guān)于微信小程序中如何計(jì)算距離某個(gè)節(jié)日還有多少天的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用微信小程序具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • 鏈接漸變效果

    鏈接漸變效果

    鏈接漸變效果...
    2006-08-08
  • 不用jQuery實(shí)現(xiàn)的動畫效果代碼

    不用jQuery實(shí)現(xiàn)的動畫效果代碼

    jQuery 框架用的人越來越多了, 無論是性能還是功能強(qiáng)大都不用多說.
    2010-11-11

最新評論