用三角形绘制金字塔 [英] Drawing a Pyraminx with triangles

查看:40
本文介绍了用三角形绘制金字塔的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个金字塔,它是由多个三角形组成的四面体.我这样做的方式一定不是很准确.这是我的代码,也可以在 https://codepen.io/jeffprod/pen/XWbBZLN .

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 .

问题是我正在编写 facesVectors 坐标.黄色和蓝色的一面似乎没问题.但是很难设置红色和绿色三角形的位置.

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.

有什么简单的方法吗?

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>

推荐答案

四面体的 4 个角点 是:

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) 
];

使用 THREE.Vector3().lerpVectors 计算边上的一个点:

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>

这篇关于用三角形绘制金字塔的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆