2016-07-03 51 views
1

我已經建立了這個snake game其中蛇用的是一堆立方體網格和THREE.BoxGeometry動畫周圍:three.js所:動畫箱狀的幾何

snake game

我寧願每個蛇包括只有一個網格和一個幾何圖形,以便我可以輕鬆添加紋理,圓角邊緣等。

我試圖帶一組3d點並將它們轉換爲類似演示中的盒狀蛇的單個幾何圖形(如幾個THREE.BoxGeometry附在一起)。

我試圖實現,使用THREE.CurvePathTHREE.ExtrudeGeometry

_makeSnakeGeometry(positions) { 
    const vectors = positions.map(p => new THREE.Vector3(...p)); 
    const curvePath = new THREE.CurvePath(); 
    const first = vectors[1]; 
    const last = vectors[vectors.length - 1]; 

    let curveStart = vectors[0]; 
    let previous = curveStart; 
    let previousDirection; 

    // Walk through the positions. If there is a change in direction, add 
    // a new curve to the curve path. 
    for (let vector of vectors.slice(1)) { 
    let direction = previous.clone().sub(vector); 

    if (vector.equals(first)) { 
     curveStart.sub(direction.clone().divideScalar(2)); 
    } 

    if (vector.equals(last)) { 
     previous.sub(previousDirection.clone().divideScalar(2)); 
    } 

    if ((previousDirection && !previousDirection.equals(direction)) || vector.equals(last)) { 
     curvePath.add(new THREE.LineCurve3(curveStart, previous)); 
     curveStart = previous; 
    } 

    previous = vector; 
    previousDirection = direction; 
    } 

    const p = Const.TILE_SIZE/2; 
    const points = [[-p, -p], [-p, p], [p, p], [p, -p]]; 
    const shape = new THREE.Shape(points.map(p => new THREE.Vector2(...p))); 
    const geometry = new THREE.ExtrudeGeometry(shape, { 
    steps: 20, 
    extrudePath: curvePath, 
    amount: 20 
    }); 

    return geometry; 
} 

不幸的是,它看起來很醜陋,我們結束了圓角所在的路徑方向的變化:

ugly snake game

如果我增加steps選項,生成的網格看起來不那麼難看,但由於光滑的彎曲邊緣,幾何體具有大量的頂點。我擔心大的頂點數,因爲我可能不得不在每個動畫幀上重新創建這個幾何。

要給幾何體設置動畫效果,我嘗試使用geometry.morphTargets,但收效甚微。變形發生了,但它也看起來很難看。也許我需要手動動畫幾何的頂點?

總之,我的問題是:

  • 我如何可以創建類似於拼湊幾箱的幾何形狀最小的頂點幾何?
  • 當底層頂點數可以改變時,動畫幾何的正確方法是什麼?
+0

我想你需要每次更新時重計算鏈中的三角 - 除非你需要一個平滑的動畫? –

+0

理想情況下,一個流暢的動畫。我希望獲得與鏈接演示中相同的結果,但使用單個幾何體。 –

+2

只需使用未優化的幾何圖形就可以簡化該問題(即每個框具有其自己的幾何圖形) –

回答

0

要構建蛇形狀,我結束了合併的幾何形狀:

_makeSnakeGeometry(positions) { 
    positions = positions.map(p => new THREE.Vector3(...p)); 
    const geometry = new THREE.Geometry(); 

    for (let i = 0; i < positions.length; i += 1) { 
    const position = positions[i]; 
    const mesh = makeVoxelMesh(Const.TILE_SIZE, { position }); 
    mesh.updateMatrix(); 
    geometry.merge(mesh.geometry, mesh.matrix); 
    } 

    return geometry; 
} 

makeVoxelMesh返回蛇的一個位置一個多維數據集的網格。我使用geometry.merge將它們加在一起,並在每個動畫幀上重複該過程。這並不完美,因爲幾何學最終會得到額外的頂點和麪,它不需要具有這種簡單的形狀。事實之後,可能有辦法減少它們嗎?

爲了讓蛇動畫,我找到了構成頭部臉部的四個頂點。我這樣做是通過看頂點位置和麪法線:

_findHeadFaceVertices() { 
    const direction = this._direction.clone().multiplyScalar(1 + (Const.TILE_SIZE/10)); 
    const headFacePosition = new THREE.Vector3(...this.head).add(direction); 
    const { vertices, faces } = this.mesh.geometry; 

    // Sort vertices by distance to a point near the snake head and only keep 
    // the first few that are equidistant. 
    const closest = vertices 
    .map(v => [v.distanceTo(headFacePosition), v]) 
    .sort((a, b) => a[0] - b[0]) 
    .filter((pair, i, sorted) => pair[0] === sorted[0][0]) 
    .map(pair => pair[1]); 

    const result = []; 
    const seen = {}; 

    // Filter the remaining vertices by keeping only ones which belong to faces 
    // that point in the same direction as the snake. 
    for (let face of faces) { 
    for (let vertex of [vertices[face.a], vertices[face.b], vertices[face.c]]) { 
     const key = vertex.toArray().toString(); 
     if (!seen[key] && closest.includes(vertex) && face.normal.equals(this._direction)) { 
     seen[key] = true; 
     result.push(vertex); 
     } 
    } 
    } 

    return result; 
} 

對於動畫的工作,我有每個動畫幀後設置this.mesh.geometry.verticesNeedUpdate = true;

snake game