用三角形绘制金字塔 [英] Drawing a Pyraminx with triangles
问题描述
我正在尝试编写一个金字塔,它是由多个三角形组成的四面体.我这样做的方式一定不是很准确.这是我的代码,也可以在 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屋!