在过去的几天中,我一直在尝试为类似3D图形的程序的用户界面实现虚拟轨迹球的有效实现。但是我有麻烦了。
查看数字和许多测试,问题似乎是四元数的实际串联,但我不知道或不这么认为。我以前从未使用过四元数或虚拟轨迹球,这对我来说是全新的。我正在使用JOGL提供的Quaternion类。我尝试制作自己的作品,并且奏效了(或者至少据我所知),但是那完全是一团糟,所以我选择了JOGL。
当我不连接四元数时,我所看到的似乎只是轻微的旋转,但是,当它仅向任何方向移动一点时,这当然很困难。此代码基于OpenGL Wiki上的Trackball Tutorial
当我使用Quaternion类的mult (Quaternion q)方法时,图形几乎不会移动(甚至比不尝试连接四元数还少)。
当我尝试使用Quaternion class's add(Quaternion q)方法来获得乐趣时,我得到的东西至少可以旋转图形,但不会以任何连贯的方式进行。当我移动鼠标时,它会闪出并随机旋转。有时,我会得到完全充满NaN的四元数。
在我的代码中,我不会显示任何一个,我不知道如何处理四元数。我知道我想乘以它们,因为据我所知,这就是它们的级联方式。但是就像我说我没有成功一样,我假设错误还在代码中。
无论如何,我的设置都有一个带有Trackball方法的public Point3f projectMouse (int x, int y)类和一个public void rotateFor (Point3f p1, Point3f p2),其中Point3f是我制作的一个类。另一个名为Camera的类具有public void transform (GLAutoDrawable g)方法,该方法将调用OpenGL方法根据轨迹球的四元数旋转。
这是代码:

public Point3f projectMouse (int x, int y)
{
    int off = Screen.WIDTH / 2;  // Half the width of the GLCanvas

    x = x - objx_ - off;         // obj being the 2D center of the graph
    y = off - objy_ - y;

    float t = Util.sq(x) + Util.sq(y); // Util is a class I made with
    float rsq = Util.sq(off);          // simple some math stuff
                                       // off is also the radius of the sphere
    float z;

    if (t >= rsq)
        z = (rsq / 2.0F) / Util.sqrt(t);
    else
        z = Util.sqrt(rsq - t);

    Point3f result = new Point3f (x, y, z);
    return result;
}
这是旋转方法:
public void rotateFor (Point3f p1, Point3f p2)
{
    // Vector3f is a class I made, I already know it works
    // all methods in Vector3f modify the object's numbers
    // and return the new modify instance of itself
    Vector3f v1 = new Vector3f(p1.x, p1.y, p1.z).normalize();
    Vector3f v2 = new Vector3f(p2.x, p2.y, p2.z).normalize();

    Vector3f n = v1.copy().cross(v2);
    float theta = (float) Math.acos(v1.dot(v2));

    float real = (float) Math.cos(theta / 2.0F);
    n.multiply((float) Math.sin(theta / 2.0F));

    Quaternion q = new Quaternion(real, n.x, n.y, n.z);

    rotation = q;  // A member that can be accessed by a getter

    // Do magic on the quaternion
}
编辑:
我越来越近了,我发现了一些简单的错误。
1:JOGL实现将W视为实数,而不是X,我使用X进行实数
2:我不是从四元数1 + 0i + 0j + 0k开始
3:我没有将四元数转换为opengl的轴/角度
4:我没有将opengl的角度转换为度
就像马库斯指出的那样,我没有规范正常,当我这样做时,我看不到太多变化,以为很难说,他是对的。
现在的问题是,当我完成整个操作时,图形会像您永远不会相信的那样剧烈晃动。它会向您想要的方向移动,但癫痫发作太猛,无法从中取出任何东西。
这是我的新代码,其中有一些名称更改:
public void rotate (Vector3f v1, Vector3f v2)
{
    Vector3f v1p = v1.copy().normalize();
    Vector3f v2p = v2.copy().normalize();
    Vector3f n = v1p.copy().cross(v2p);

    if (n.length() == 0) return; // Sometimes v1p equals v2p

    float w = (float) Math.acos(v1p.dot(v2p));

    n.normalize().multiply((float) Math.sin(w / 2.0F));
    w = (float) Math.cos(w / 2.0F);

    Quaternion q = new Quaternion(n.x, n.y, n.z, w);
    q.mult(rot);

    rot_ = q;
}
这是OpenGL代码:
    Vector3f p1 = tb_.project(x1, y1); // projectMouse [changed name]
    Vector3f p2 = tb_.project(x2, y2);
    tb_.rotate (p1, p2);

    float[] q = tb_.getRotation().toAxis(); // Converts to angle/axis
    gl.glRotatef((float)Math.toDegrees(q[0]), q[1], q[2], q[3]);
名称更改的原因是因为我删除了Trackball类中的所有内容并重新开始。可能不是最好的主意,但是很好。
编辑2:
我可以肯定地说,投射到球体上没有错。
我还可以说,就整个问题而言,似乎是VECTOR才是问题所在。角度看起来很好,但是矢量似乎在跳来跳去。
编辑3:
问题是两个四元数的乘法,我可以确认所有其他四元数都能正常工作。乘法过程中轴发生异常变化!

最佳答案

问题是两个四元数的乘积,我可以确认其他所有工作都按预期进行。乘法过程中轴发生异常变化!

你是绝对正确的!我刚刚提交了正确的乘法运算,Jogamp接受了我的更改。他们对mult(四元数)的乘法不正确。

我敢肯定,如果您获得最新的Jogl版本,它将具有正确的多重(Quaternion)

关于java - 虚拟轨迹球实现,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11314384/

10-09 08:35