我使用 p5.js 在 javascript 中编写了一个超立方体并且工作正常,但我想知道如何使用矩阵旋转在 X 轴上旋转这个超立方体。我知道我们可以使用 p5.js 中的标准函数来做到这一点,比如 rotateX(在第 84 行),但我想使用矩阵旋转来做到这一点,但行不通。
代码如下:
<head>
<meta charset = "utf-8">
<title>Hypercube</title>
</head>
<body>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>
<script>
var points = [];
var distance = 2; //distance in w axis
var angle = 0;
//4D vector
class vector4D
{
constructor(x, y, z, w)
{
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}
}
var rotatedVector = new vector4D();
var projectedVector = new vector4D();
//All points of a hypercube.
points[0] = new vector4D([-1], [-1], [-1], [1]);
points[1] = new vector4D([1], [-1], [-1], [1]);
points[2] = new vector4D([1], [1], [-1], [1]);
points[3] = new vector4D([-1], [1], [-1], [1]);
points[4] = new vector4D([-1], [-1], [1], [1]);
points[5] = new vector4D([1], [-1], [1], [1]);
points[6] = new vector4D([1], [1], [1], [1]);
points[7] = new vector4D([-1], [1], [1], [1]);
points[8] = new vector4D([-1], [-1], [-1], [-1]);
points[9] = new vector4D([1], [-1], [-1], [-1]);
points[10] = new vector4D([1], [1], [-1], [-1]);
points[11] = new vector4D([-1], [1], [-1], [-1]);
points[12] = new vector4D([-1], [-1], [1], [-1]);
points[13] = new vector4D([1], [-1], [1], [-1]);
points[14] = new vector4D([1], [1], [1], [-1]);
points[15] = new vector4D([-1], [1], [1], [-1]);
function setup()
{
createCanvas(600, 400, WEBGL);
}
//Multiply a 4x4 or 3x3 matrix with a vector
function multiply(a, b, size)
{
var vector = new vector4D();
if (size == 4)
{
vector.x = (a[0][0] * b.x) + (a[0][1] * b.y) + (a[0][2] * b.z) + (a[0][3] * b.w);
vector.y = (a[1][0] * b.x) + (a[1][1] * b.y) + (a[1][2] * b.z) + (a[1][3] * b.w);
vector.z = (a[2][0] * b.x) + (a[2][1] * b.y) + (a[2][2] * b.z) + (a[2][3] * b.w);
vector.w = (a[3][0] * b.x) + (a[3][1] * b.y) + (a[3][2] * b.z) + (a[3][3] * b.w);
}
else
{
vector.x = (a[0][0] * b.x) + (a[0][1] * b.y) + (a[0][2] * b.z);
vector.y = (a[1][0] * b.x) + (a[1][1] * b.y) + (a[1][2] * b.z);
vector.z = (a[2][0] * b.x) + (a[2][1] * b.y) + (a[2][2] * b.z);
vector.w = 1;
}
return vector;
}
//Connect all points of a hypercube
function connectDots(i, j, j2, projected)
{
line(projected[j + i].x, projected[j + i].y, projected[j + i].z, projected[j2 + i].x, projected[j2 + i].y, projected[j2 + i].z);
}
function draw()
{
background('blue');
translate(0, 0);
stroke(255);
<!-- rotateX(-PI / 2); -->
strokeWeight(1);
//X, Y and Z are not used, but I put here to test rotations in all these axis
var rotationMatrixX = [[1, 0, 0],
[0, cos(angle), -sin(angle)],
[0, sin(angle), cos(angle)]];
var rotationMatrixY = [[cos(angle), 0, sin(angle)],
[0, 1, 0],
[-sin(angle), 0, cos(angle)]];
var rotationMatrixZ = [[cos(angle), -sin(angle), 0],
[sin(angle), cos(angle), 0],
[0, 0, 1]];
var rotationMatrixXY = [[cos(angle), -sin(angle), 0, 0],
[sin(angle), cos(angle), 0, 0],
[0, 0, 1,0],
[0, 0, 0, 1]];
var rotationMatrixZW = [[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, cos(angle), -sin(angle)],
[0, 0, sin(angle), cos(angle)]];
//All points rotated and projected to connect
var projected = [16];
for (i in points)
{
rotatedVector = multiply(rotationMatrixXY, points[i], rotationMatrixXY.length);
rotatedVector = multiply(rotationMatrixZW, rotatedVector, rotationMatrixZW.length);
//w perspective
var w = 2 / (distance - rotatedVector.w);
var projectionMatrix = [[w, 0, 0, 0],
[0, w, 0, 0],
[0, 0, w, 0]];
projectedVector = multiply(projectionMatrix, rotatedVector, projectionMatrix.length);
projectedVector.x *= 25;
projectedVector.y *= 25;
projectedVector.z *= 25;
projected[i] = projectedVector;
point(projectedVector.x, projectedVector.y, projectedVector.z);
}
//Connecting all dots
for (i = 0; i < 8; i++)
{
if (i < 4)
{
connectDots(0, i, i + 4, projected);
connectDots(0, i, i + 8, projected);
connectDots(0, i, (i + 1) % 4, projected);
connectDots(0, i + 4, ((i + 1) % 4) + 4, projected);
connectDots(8, i, i + 4, projected);
connectDots(8, i, (i + 1) % 4, projected);
connectDots(8, i + 4, ((i + 1) % 4) + 4, projected);
}
connectDots(0, i, i + 8, projected);
}
angle += 0.025;
}
</script>
</body>
</html>