Drawing a Pyraminx with triangles

我与影子孤独终老i 提交于 2020-12-06 15:48:51

问题


I'm trying to code a Pyraminx which is a tetrahedon composed with multiples triangles. The way I do it must not be very accurate. Here is my code, also available at https://codepen.io/jeffprod/pen/XWbBZLN .

The problem is that i'im writing the facesVectors coordinates handly. It seems ok for the yellow and blue side. But it is going difficult to set the position of red and green triangles.

Is there a simple way to do ?

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 100);
camera.position.set(-2, 1, 3);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

let controls = new THREE.OrbitControls(camera, renderer.domElement);

// one triangle equilateral
const sideLength = 1
const x = 0
const y = 0
const geometry = new THREE.Geometry()
geometry.vertices.push(new THREE.Vector3(x, (Math.sqrt(3) / 2 * sideLength) - (sideLength / 2), 0))
geometry.vertices.push(new THREE.Vector3(x - (sideLength / 2), y - (sideLength / 2), 0))
geometry.vertices.push(new THREE.Vector3(x + (sideLength / 2), y - (sideLength / 2), 0))
geometry.faces.push(new THREE.Face3(0, 1, 2))

const facesColors = [
  0xFFFF00, // yellow
  0xFF0000, // red
  0x0000FF, // blue
  0x008000 // green
]

// 36 triangles composing the pyraminx
// numbers are indexes of facesColors 
const pos = [
  0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 1, 1, 1, 1, 1, 2, 3, 3, 3, 3, 3
]

// vectors of each triangle composing the tetrahedron
const facesVectors = [
  [0, 0, -1.5],
  [-0.52, 0, -0.6],
  [0, 0, -0.48],
  [0.52, 0, -0.6],
  [-1.04, 0, 0.3],
  [-0.52, 0, 0.42],
  [0, 0, 0.3],
  [0.52, 0, 0.42],
  [1.04, 0, 0.3],
  [-1.2, -0.16, 0.2],
  [-1.04, -0.45, 0.55],
  [-0.52, -0.34, 0.62],
  [0, -0.45, 0.55],
  [0.52, -0.34, 0.62],
  [1.04, -0.45, 0.55],
  [1.2, -0.16, 0.15],
  [-0.6, -0.16, -0.7],
  [-0.9, -0.3, -0.1],
  [-0.5, -0.5, -0.5]
]

for (let i = 0; i < facesVectors.length; i++) {
  material = new THREE.MeshBasicMaterial({ color: facesColors[pos[i]] })
  face = new THREE.Mesh(geometry, material)
  face.position.set(facesVectors[i][0], facesVectors[i][1], facesVectors[i][2])
  // some rotations
  if ([0, 1, 2, 3, 4, 5, 6, 7, 8].includes(i)) {
    face.rotation.x = -(Math.PI / 2)
  }
  if ([2, 5, 7, 10, 12, 14].includes(i)) { // 180
    face.rotation.z = Math.PI
  }
  if ([9, 16, 17, 18, 25, 26, 27, 28, 29].includes(i)) {
    if (i === 17) {
      face.rotation.x = -(1 * Math.PI) / 6
      face.rotation.y = -(2 * Math.PI) / 3
      face.rotation.z = -(1 * Math.PI) / 6
    } else {
      face.rotation.x = -Math.PI / 6
      face.rotation.y = -2 * Math.PI / 3
      face.rotation.z = Math.PI / 6
    }
  }
  if ([15, 22, 23, 24, 31, 32, 33, 34, 35].includes(i)) {
    face.rotation.x = -Math.PI / 6
    face.rotation.y = 2 * Math.PI / 3
    face.rotation.z = -Math.PI / 6
  } else if ([10, 11, 12, 13, 14, 19, 20, 21, 30].includes(i)) {
    face.rotation.x = Math.PI / 6
  }
  scene.add(face)
}

renderer.setAnimationLoop(() => {
  renderer.render(scene, camera);
});
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

回答1:


The 4 corner points of a Tetrahedron are:

let s_8_9 = Math.sqrt(8/9), s_2_9 = Math.sqrt(2/9), s_2_3 = Math.sqrt(2/3);
let v = [
    new THREE.Vector3(0,0,1),
    new THREE.Vector3(s_8_9,0,-1/3),
    new THREE.Vector3(-s_2_9,s_2_3,-1/3),
    new THREE.Vector3(-s_2_9,-s_2_3,-1/3) 
];

Use THREE.Vector3().lerpVectors to compute a point on an edge:

let pointOnEdge = (pt1, pt2, t) => new THREE.Vector3().lerpVectors(pt1, pt2, t);

and the inward offset points, of a triangular face:

let computeOffsetPts = (pts, d) => {
    let offsetPts = [];
    for (let i = 0; i < pts.length; ++i) {
        let va = pointOnEdge(pts[i], pts[(i+1) % 3], d);
        let vb = pointOnEdge(pts[i], pts[(i+2) % 3], d); 
        offsetPts.push(new THREE.Vector3().lerpVectors(va, vb, 0.5)); 
    }
    return offsetPts;
}

Use this points to construct the mesh. e.g.:

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 100);
camera.position.set(-2, 1, 3);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

let controls = new THREE.OrbitControls(camera, renderer.domElement);

const facesColors = [
  0xFFFF00, // yellow
  0xFF0000, // red
  0x0000FF, // blue
  0x008000 // green
]

let s_8_9 = Math.sqrt(8/9), s_2_9 = Math.sqrt(2/9), s_2_3 = Math.sqrt(2/3);
let v = [
    new THREE.Vector3(0,0,1),
    new THREE.Vector3(s_8_9,0,-1/3),
    new THREE.Vector3(-s_2_9,s_2_3,-1/3),
    new THREE.Vector3(-s_2_9,-s_2_3,-1/3) 
];
let faces = [[0, 1, 2], [0, 2, 3], [0, 3, 1], [1, 3, 2]]

let pointOnEdge = (pt1, pt2, t) => new THREE.Vector3().lerpVectors(pt1, pt2, t);

let computeOffsetPts = (pts, d) => {
    let offsetPts = [];
    for (let i = 0; i < pts.length; ++i) {
        let va = pointOnEdge(pts[i], pts[(i+1) % 3], d);
        let vb = pointOnEdge(pts[i], pts[(i+2) % 3], d); 
        offsetPts.push(new THREE.Vector3().lerpVectors(va, vb, 0.5)); 
    }
    return offsetPts;
}

let newTriangle = (pts, color, d) => {
    let innerPts = computeOffsetPts(pts, d);
    let material = new THREE.MeshBasicMaterial({ color: color })
    let geometry = new THREE.Geometry();
    geometry.vertices.push(...innerPts); 
    geometry.faces.push(new THREE.Face3(0, 1, 2));
    return new THREE.Mesh(geometry, material);
}

const d = 0.05;
for (let i=0; i < 4; ++i ) {
    
    let color = facesColors[i]; 
    let pts = [v[faces[i][0]], v[faces[i][1]], v[faces[i][2]]];
    let centerPt = new THREE.Vector3().addVectors(pts[0], pts[1]).add(pts[2]).divideScalar(3);
    let hexagonPts = [];
    for (let j = 0; j < 3; ++j) {
        hexagonPts.push(pointOnEdge(pts[j], pts[(j+1) % 3], 1/3), pointOnEdge(pts[j], pts[(j+1) % 3], 2/3));
    }
    
    for  (let j = 0; j < 3; ++j) {
        let topPts = [pts[j], hexagonPts[j*2], hexagonPts[(j*2+5)%6]];
        let face = newTriangle(topPts, color, d);
        scene.add(face);
    }
    for (let j = 0; j < hexagonPts.length; ++j) {
        innerPts = [centerPt, hexagonPts[j], hexagonPts[(j+1)%hexagonPts.length]];
        let face = newTriangle(innerPts, color, d);
        scene.add(face);
    }
}

renderer.setAnimationLoop(() => {
    renderer.render(scene, camera);
});
<script src="https://rawcdn.githack.com/mrdoob/three.js/r113/build/three.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/r113/examples/js/controls/OrbitControls.js"></script>


来源:https://stackoverflow.com/questions/60774560/drawing-a-pyraminx-with-triangles

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!