问题
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