gpt4 book ai didi

math - p5.j​​s 如何正确计算点相对于原点的 3D 旋转

转载 作者:行者123 更新时间:2023-12-05 03:28:41 28 4
gpt4 key购买 nike

我真的在这里苦苦挣扎,我做不对,甚至不知道为什么。我在 WEBGL 模式下使用 p5.js,我想计算在原点周围的 3 个轴上旋转的点的位置,以便跟踪通过 p5.js 给对象的平移和旋转, translationrotatation on X axisY axisZ axis

事实是,用p5.js在3d空间中绘制球体是通过平移和旋转获得的,因为球体是在原点的中心创建的,并且有没有内部模型给出 3d 坐标。

经过几个小时的数学学习,我的知识太高了,我明白了 3 轴上的旋转并不像我想象的那么简单,我最终使用了 Quaternion.js 。但是我仍然无法将 3d 世界中球体的视觉位置与我从 2d 平面上的原始点 (150, 0, [0]) 计算出的坐标相匹配。

例如,这里球体在 3 轴上旋转。一开始坐标很好(如果我忽略 Z 被否定的事实)但在某些时候它完全不同步。球体的计算位置似乎完全不相关:

wrong coordinates

我真的花了几个小时来解决这个问题,但没有结果,我错过了什么?

这里是我的代码:

//font for WEBGL
var robotoFont;
var dotId = 0;

var rotating = true;

var orbits = [];
var dotsData = [];

function preload() {
robotoFont = loadFont('./assets/Roboto-Regular.ttf');
}

function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
textFont(robotoFont);
background(0);

let orbit1 = new Orbit(0, 0, 0, 0.5, 0.5, 0.5);
orbit1.obj.push(new Dot(0, 0));
orbits.push(orbit1);
// let orbit2 = new Orbit(90, 45, 0);
// orbit2.obj.push(new Dot(0, 0));
// orbits.push(orbit2);
}

function draw() {
angleMode(DEGREES);
background(0);
orbitControl();

let len = 200;
fill('white');
stroke('white');
sphere(2);
stroke('red');
line(0, 0, 0, len, 0, 0);
text('x', len, 0)
stroke('green');
line(0, 0, 0, 0, len, 0);
text('y', 0, len)
push();
rotateX(90);
stroke('yellow');
line(0, 0, 0, 0, len, 0);
text('z', 0, len)
pop();

dotsData = [];

orbits.forEach(o => o.draw());

textSize(14);
push();
for (let i = 0; i < 2; i++) {
let yPos = -(windowHeight / 2) + 15;
for (let i = 0; i < dotsData.length; i++) {
let [id, pos, pos3d] = dotsData[i];
let [x1, y1, z1] = [pos[0].toFixed(0), pos[1].toFixed(0), pos[2].toFixed(0)];
let [x2, y2, z2] = [pos3d.x.toFixed(0), pos3d.y.toFixed(0), pos3d.z.toFixed(0)];
text(`${id}: (${x1}, ${y1}, ${z1}) -> (${x2}, ${y2}, ${z2})`, -windowWidth / 2 + 5, yPos);
yPos += 18;
}

rotateX(-90);
}
pop();

}

function mouseClicked() {
// controls.mousePressed();
}

function keyPressed() {
// controls.keyPressed(keyCode);
if (keyCode === 32) {
rotating = !rotating;
}
}

class Orbit {
constructor(x, y, z, xr, yr, zr) {
this.obj = [];
this.currentRot = [
x ? x : 0,
y ? y : 0,
z ? z : 0
]
this.rot = [
xr ? xr : 0,
yr ? yr : 0,
zr ? zr : 0
]
}

draw() {
push();

if (rotating) {
this.currentRot[0] += this.rot[0];
this.currentRot[1] += this.rot[1];
this.currentRot[2] += this.rot[2];
}

rotateY(this.currentRot[1]);
rotateX(this.currentRot[0]);
rotateZ(this.currentRot[2]);

noFill();
stroke('white');
ellipse(0, 0, 300, 300);

for (let i = 0; i < this.obj.length; i++) {
let o = this.obj[i];
o.draw();
dotsData.push([o.id, o.getPosition(), this.#get3DPos(o)]);
}

pop();
}

#get3DPos(o) {
let [x, y, z] = o.getPosition();
let w = 0;
let rotX = this.currentRot[0] * PI / 180;
let rotY = this.currentRot[1] * PI / 180;
let rotZ = this.currentRot[2] * PI / 180;

let rotation = Quaternion.fromEuler(rotZ, rotX, rotY, 'ZXY').conjugate();
[x, y, z] = rotation.rotateVector([x, y, z]);

return createVector(x, y, z);
}
}


class Dot {

constructor(angle) {
this.id = ++dotId;
this.x = cos(angle) * 150;
this.y = sin(angle) * 150;
}

draw() {
push();
fill('gray');
translate(this.x, this.y);
noStroke();
sphere(15);
pop();
}

getPosition() {
return [this.x, this.y, 0];
}
}

它在 stackoverflow 中不起作用,因为我需要像字体这样的本地资源。

这里是工作代码:https://editor.p5js.org/cigno5/sketches/_ZVq0kjJL

最佳答案

我终于解决了。我真的不明白为什么要这样工作,但我根本不需要四元数,而且我使用矩阵乘法在 3 轴上应用旋转的第一个直觉是正确的。

我首先错过的(并让我的生活变得悲惨)是矩阵乘法不可交换。这意味着在 x、y 和 z 轴上应用旋转不等同于在 z、y 和 x 上应用相同的旋转角度。

工作解决方案已通过 3 个简单步骤实现:

  1. 使用向量将四元数替换为矩阵乘法(方法 #resize2)
  2. 按Z-Y-X顺序旋转绘图平面
  3. 按 X-Y-Z 顺序计算旋转
//font for WEBGL
var robotoFont;
var dotId = 0;

var rotating = true;

var orbits = [];
var dotsData = [];

function preload() {
robotoFont = loadFont('./assets/Roboto-Regular.ttf');
}

function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
textFont(robotoFont);
background(0);

let orbit1 = new Orbit(0, 0, 0, 0.5, 0.5, 0.5);
orbit1.obj.push(new Dot(0, 0.5));
orbits.push(orbit1);
// let orbit2 = new Orbit(90, 45, 0);
// orbit2.obj.push(new Dot(0, 0));
// orbits.push(orbit2);
}

function draw() {
angleMode(DEGREES);
background(0);
orbitControl();

let len = 200;
fill('white');
stroke('white');
sphere(2);
stroke('red');
line(0, 0, 0, len, 0, 0);
text('x', len, 0)
stroke('green');
line(0, 0, 0, 0, len, 0);
text('y', 0, len)
push();
rotateX(90);
stroke('yellow');
line(0, 0, 0, 0, len, 0);
text('z', 0, len)
pop();

dotsData = [];

orbits.forEach(o => o.draw());

textSize(14);
push();
for (let i = 0; i < 2; i++) {
let yPos = -(windowHeight / 2) + 15;
for (let i = 0; i < dotsData.length; i++) {
let [id, pos, pos3d] = dotsData[i];
let [x1, y1, z1] = [pos[0].toFixed(0), pos[1].toFixed(0), pos[2].toFixed(0)];
let [x2, y2, z2] = [pos3d.x.toFixed(0), pos3d.y.toFixed(0), pos3d.z.toFixed(0)];
text(`${id}: (${x1}, ${y1}, ${z1}) -> (${x2}, ${y2}, ${z2})`, -windowWidth / 2 + 5, yPos);
yPos += 18;
}

rotateX(-90);
}
pop();

}

function mouseClicked() {
// controls.mousePressed();
}

function keyPressed() {
// controls.keyPressed(keyCode);
if (keyCode === 32) {
rotating = !rotating;
}
}

class Orbit {
constructor(x, y, z, xr, yr, zr) {
this.obj = [];
this.currentRot = [
x ? x : 0,
y ? y : 0,
z ? z : 0
]
this.rot = [
xr ? xr : 0,
yr ? yr : 0,
zr ? zr : 0
]
}

draw() {
push();

if (rotating) {
this.currentRot[0] += this.rot[0];
this.currentRot[1] += this.rot[1];
this.currentRot[2] += this.rot[2];
}

rotateZ(this.currentRot[2]);
rotateY(this.currentRot[1]);
rotateX(this.currentRot[0]);

noFill();
stroke('white');
ellipse(0, 0, 300, 300);

for (let i = 0; i < this.obj.length; i++) {
let o = this.obj[i];
o.draw();
dotsData.push([o.id, o.getPosition(), this.#get3DPos(o)]);
}

pop();
}

#get3DPos(o) {
let [x, y, z] = o.getPosition();
let pos = createVector(x, y, z);
pos = this.#rotate2(pos, createVector(1, 0, 0), this.currentRot[0]);
pos = this.#rotate2(pos, createVector(0, 1, 0), this.currentRot[1]);
pos = this.#rotate2(pos, createVector(0, 0, 1), this.currentRot[2]);
return pos;
}

//https://stackoverflow.com/questions/67458592/how-would-i-rotate-a-vector-in-3d-space-p5-js
#rotate2(vect, axis, angle) {
// Make sure our axis is a unit vector
axis = p5.Vector.normalize(axis);

return p5.Vector.add(
p5.Vector.mult(vect, cos(angle)),
p5.Vector.add(
p5.Vector.mult(
p5.Vector.cross(axis, vect),
sin(angle)
),
p5.Vector.mult(
p5.Vector.mult(
axis,
p5.Vector.dot(axis, vect)
),
(1 - cos(angle))
)
)
);
}

}


class Dot {

constructor(angle, speed) {
this.id = ++dotId;
this.angle = angle;
this.speed = speed
}

draw() {
this.angle += this.speed;
this.x = cos(this.angle) * 150;
this.y = sin(this.angle) * 150;

push();
fill('gray');
translate(this.x, this.y);
noStroke();
sphere(15);
pop();
}

getPosition() {
return [this.x, this.y, 0];
}
}

现在它就像一个魅力:

https://editor.p5js.org/cigno5/sketches/PqB9CEnBp

关于math - p5.j​​s 如何正确计算点相对于原点的 3D 旋转,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71197127/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com