2016-07-03 48 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