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

three.js 如何制作魔方

 更新時(shí)間:2020年07月31日 10:22:37   作者:郭先生  
這篇文章主要介紹了three.js 如何制作魔方,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下

因?yàn)橹暗膸坠?jié)講了一些數(shù)學(xué)方法,例如Vector3、Matrix4、Euler還有Quaternion的知識。所以這篇郭先生就來說說用three.js怎么制作一個魔方。

制作魔方主要運(yùn)用坐標(biāo)變換的知識,制作魔方的方法有很多,建議你先在大腦中構(gòu)思,然后試著做一做,下面我將一種比較簡單的方法。

  1. 制作出魔方各個方塊的位置坐標(biāo)(27個)的數(shù)組,然后制作出魔方各個面的材質(zhì)(6個)
  2. 根據(jù)坐標(biāo)和材質(zhì)制作魔方的方塊,并添加到一個組group
  3. 制作一個標(biāo)志被選面的幾何體(我是用球體),然后隱藏
  4. 使用THREE.Raycaster,給模型綁定事件,并記錄選定的一些數(shù)據(jù),將標(biāo)志顯示并放到合適的位置
  5. 點(diǎn)擊模擬方向鍵盤,根據(jù)之前記錄的數(shù)據(jù),轉(zhuǎn)動魔方(重點(diǎn))

以上是主要的步驟,但是對于新同學(xué),需要注意的仍然很多,下面上主要代碼,按照方法說

1. 定義的變量

posArr = [
  [100,100,100],[100,100,0],[100,100,-100],[100,0,100],[100,0,0],[100,0,-100],[100,-100,100],[100,-100,0],[100,-100,-100],
  [0,100,100],[0,100,0],[0,100,-100],[0,0,100],[0,0,0],[0,0,-100],[0,-100,100],[0,-100,0],[0,-100,-100],
  [-100,100,100],[-100,100,0],[-100,100,-100],[-100,0,100],[-100,0,0],[-100,0,-100],[-100,-100,100],[-100,-100,0],[-100,-100,-100]
],//方塊位置坐標(biāo)
materials,//材質(zhì)數(shù)組
mouse = new THREE.Vector2(),//通過鼠標(biāo)點(diǎn)擊的位置計(jì)算出raycaster所需要的點(diǎn)的位置,以屏幕中心為原點(diǎn),值的范圍為-1到1.
raycaster,//射線對象
group,//存放魔方方塊的數(shù)組
groupTemp,//魔方轉(zhuǎn)動時(shí)臨時(shí)數(shù)組
object3d,//魔方被選擇面的標(biāo)志物對象
currentPos,//魔方被點(diǎn)擊小塊的位置
currentNor,//魔方被點(diǎn)擊小塊面的法向量
currentUp,//魔方被點(diǎn)擊時(shí),相機(jī)up的向量

2. 定義材質(zhì)數(shù)組

initMaterial() {
  var map_red = new THREE.TextureLoader().load('/static/images/color/m_red.jpg', () => this.loadover --);
  var map_orange = new THREE.TextureLoader().load('/static/images/color/m_orange.jpg', () => this.loadover --);
  var map_yellow = new THREE.TextureLoader().load('/static/images/color/m_yellow.jpg', () => this.loadover --);
  var map_blue = new THREE.TextureLoader().load('/static/images/color/m_blue.jpg', () => this.loadover --);
  var map_green = new THREE.TextureLoader().load('/static/images/color/m_green.jpg', () => this.loadover --);
  var map_white = new THREE.TextureLoader().load('/static/images/color/m_white.jpg', () => this.loadover --);
  var map_sprite = new THREE.TextureLoader().load('/static/images/base/direction.png', () => this.loadover --);

  let mater_red = new THREE.MeshBasicMaterial({map: map_red, side: THREE.DoubleSide});
  let mater_orange = new THREE.MeshBasicMaterial({map: map_orange, side: THREE.DoubleSide});
  let mater_yellow = new THREE.MeshBasicMaterial({map: map_yellow, side: THREE.DoubleSide});
  let mater_white = new THREE.MeshBasicMaterial({map: map_white, side: THREE.DoubleSide});
  let mater_blue = new THREE.MeshBasicMaterial({map: map_blue, side: THREE.DoubleSide});
  let mater_green = new THREE.MeshBasicMaterial({map: map_green, side: THREE.DoubleSide});

  materials = [mater_red, mater_orange, mater_yellow,mater_white, mater_blue, mater_green];
}

3. 繪制小方塊并繪制標(biāo)志物(先隱藏)

initsquare() {
  var sphereGeom = new THREE.SphereGeometry(10, 30, 20);
  var sphereMate = new THREE.MeshPhongMaterial({color: 0x333333});
  object3d = new THREE.Mesh(sphereGeom, sphereMate);
  object3d.name = 'object3d';
  object3d.visible = false;
  scene.add(object3d);

  group = new THREE.Group();
  group.name = 'group';

  var geometry = new THREE.BoxGeometry(100, 100, 100);
  var mesh = new THREE.Mesh(geometry, materials);
  posArr.forEach((d,i) => {
    let meshCopy = mesh.clone();
    meshCopy.position.set(d[0], d[1], d[2])
    meshCopy.name = 'box-' + i;
    group.add(meshCopy);
  })

  scene.add(group);

  this.render();
  document.getElementById("loading").style.display = "none";
}

4. 監(jiān)聽模型的點(diǎn)擊事件

initEventListener() {
  raycaster = new THREE.Raycaster();
  document.addEventListener('mousemove', function (event) {
    event.preventDefault();
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
  }, false)
  document.addEventListener('mousedown', () => {
    if (scene.children && scene.getObjectByName('group')) {
      raycaster.setFromCamera(mouse, camera);
      let intersects = raycaster.intersectObjects(scene.getObjectByName('group').children);
      if (intersects[0] && intersects[0].object.name != 'object3d') {
        let index = intersects[0].faceIndex;
        let point = intersects[0].point;
        currentUp = this.computedUp(camera);
        currentNor = this.computedNor(point)
        currentPos = intersects[0].object.position;
        let pos = this.computedPos(point);
        object3d.position.copy(pos);
        object3d.visible = true;
      }
    }
  })
}

5. 監(jiān)聽方向軟鍵盤的點(diǎn)擊,根據(jù)點(diǎn)擊鍵的不同,生成旋轉(zhuǎn)軸

handleRotate(num) {
  if(!rotateFlag || !currentPos) return ;
  rotateFlag = false;
  groupTemp = new THREE.Group();
  groupTemp.name = 'group-temp';
  let axis;
  let tempMeshArr = [];
  switch (num) {
    case 1:
      axis = currentNor.clone().cross(currentUp);
      break;
    case 2:
      axis = currentNor.clone().cross(currentUp).negate();
      break;
    case 3:
      axis = currentUp.clone().negate();
      break;
    case 4:
      axis = currentUp;
      break;
  }
  let plane = new THREE.Plane().setFromNormalAndCoplanarPoint(axis, currentPos);
  scene.getObjectByName('group').children.forEach(d => Math.abs(plane.distanceToPoint(d.position)) < 1 && tempMeshArr.push(d))
  tempMeshArr.forEach(d => {
    group.remove(d);
    groupTemp.add(d);
  })
  // object3d.visible = false;
  scene.remove(scene.getObjectByName('group-temp'));
  scene.add(groupTemp);
  this.handleTween(axis);
}

6. 加一點(diǎn)tween的補(bǔ)間動畫,效果更好哦

handleTween(axis) {
  let start = {angle: 0, axis};
  let end = {angle: Math.PI/2, axis};
  tween = new TWEEN.Tween(start).to(end, 500);
  tween.easing(TWEEN.Easing.Linear.None);
  tween.onUpdate(function () {
    let quaternion = new THREE.Quaternion().setFromAxisAngle(axis, this._object.angle);
    groupTemp.rotation.setFromQuaternion(quaternion);
  });
  tween.onComplete(() => {
    let matrix = this.standerMatrix(groupTemp.matrix);
    groupTemp.children.forEach(d => {
      let mesh = d.clone();
      mesh.applyMatrix4(matrix)
      mesh.position.copy(this.standarPos(mesh.position))
      group.add(mesh);
    })
    scene.remove(groupTemp)
    rotateFlag = true;
  })
  tween.start();
}

郭先生制作魔方的主要思路就是先做出27個方塊添加到組A,6個面分別添加不同顏色的貼圖(自己p的哦),然后使用raycaster選擇點(diǎn)擊的面,并確定當(dāng)時(shí)的up方向和法向量方向以備后用,點(diǎn)擊上下左右并結(jié)合u方向和法向量方向計(jì)算出旋轉(zhuǎn)矩陣,根據(jù)已有條件計(jì)算出是那一排方塊改變,并將這9個塊添加到組B中,從組A中刪除這9個,根據(jù)旋轉(zhuǎn)矩陣旋轉(zhuǎn)組B,并且在旋轉(zhuǎn)完之后將組B中的方塊添加到組A中,旋轉(zhuǎn)完畢(這里比較難的就是根據(jù)上下左右判斷旋轉(zhuǎn)軸向量)。

以上就是一種制作魔方的方法,綜合了很多矩陣向量四元數(shù)歐拉角和平面的知識,希望對新來的同游有些幫助

到此這篇關(guān)于three.js 如何制作魔方的文章就介紹到這了,更多相關(guān)three.js 制作魔方內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論