math java处理arcball四元数触发器,浮点舍入错误

math java处理arcball四元数触发器,浮点舍入错误,java,math,processing,quaternions,arcball,Java,Math,Processing,Quaternions,Arcball,我正在修改一个arcball类,使其在每次调用rollforward()时旋转1度。 我在阅读代码时遇到困难,但我相信我需要编写一个XY_to_sphere()的替代方案,其中;让点1=v1,点2=v2,这样 pi/180 = (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z) / (abs(v1.x) * abs(v2.x) + abs(v1.y) * abs(v2.y) + abs(v1.z) * abs(v2.z)) 我试着简单地添加一个角度((sin

我正在修改一个arcball类,使其在每次调用rollforward()时旋转1度。 我在阅读代码时遇到困难,但我相信我需要编写一个XY_to_sphere()的替代方案,其中;让点1=v1,点2=v2,这样

pi/180 = (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z) / (abs(v1.x) * abs(v2.x) + abs(v1.y) * abs(v2.y) + abs(v1.z) * abs(v2.z))

我试着简单地添加一个角度((sin(PI/180)*半径)/2,转换成y轴; (在前滚()中)

100次滚动后,它会偏离几度(这可能是浮点舍入错误,我会尝试找到它,但我必须学习一些东西) 这是200次完全旋转时的差异(应该是顶部立方体的镜像)

(新问题) 当它达到完全旋转时,它会消失大约1度,我不知道为什么。(解决了!我在测试时将半径设置为1,谢谢@laancelot)

我不确定我最初的想法,上面的解决方案是否会更好

现在我将尝试设置它,使其在达到360度后重置,以避免浮点错误

弧球类

// Ariel and V3ga's arcball class with a couple tiny mods by Robert Hodgin and smaller mods by cubes

class Arcball {
  float center_x, center_y, radius;
  Vec3 v_down, v_drag;
  Quat q_now, q_down, q_drag;
  Vec3[] axisSet;
  int axis;
  float mxv, myv;
  float x, y;
  
  Arcball(float center_x, float center_y, float radius){
    this.center_x = center_x;
    this.center_y = center_y;
    this.radius = radius;

    v_down = new Vec3();
    v_drag = new Vec3();

    q_now = new Quat();
    q_down = new Quat();
    q_drag = new Quat();

    axisSet = new Vec3[] {new Vec3(1.0f, 0.0f, 0.0f), new Vec3(0.0f, 1.0f, 0.0f), new Vec3(0.0f, 0.0f, 1.0f)};
    axis = -1;  // no constraints...    
  }

  void rollforward(){
    q_down.set(q_now);
    v_down = XY_to_sphere(center_x, center_y);
    q_down.set(q_now);
    q_drag.reset();
    
    v_drag = XY_to_sphere(center_x, center_y - ((sin(PI/180) * radius))/2);
    q_drag.set(Vec3.dot(v_down, v_drag), Vec3.cross(v_down, v_drag)); 
  }

/*
  void mousePressed(){
    v_down = XY_to_sphere(mouseX, mouseY);  
    q_down.set(q_now);
    q_drag.reset();
  }

  void mouseDragged(){
    v_drag = XY_to_sphere(mouseX, mouseY);
    q_drag.set(Vec3.dot(v_down, v_drag), Vec3.cross(v_down, v_drag));
  }
*/
  void run(){
    q_now = Quat.mul(q_drag, q_down);
    applyQuat2Matrix(q_now);
    
    x += mxv;
    y += myv;
    mxv -= mxv * .01;
    myv -= myv * .01;
  }
  
  Vec3 XY_to_sphere(float x, float y){
    Vec3 v = new Vec3();
    v.x = (x - center_x) / radius;
    v.y = (y - center_y) / radius;

    float mag = v.x * v.x + v.y * v.y;
    if (mag > 1.0f){
      v.normalize();
    } else {
      v.z = sqrt(1.0f - mag);
    }

    return (axis == -1) ? v : constrain_vector(v, axisSet[axis]);
  }

  Vec3 constrain_vector(Vec3 vector, Vec3 axis){
    Vec3 res = new Vec3();
    res.sub(vector, Vec3.mul(axis, Vec3.dot(axis, vector)));
    res.normalize();
    return res;
  }

  void applyQuat2Matrix(Quat q){
    // instead of transforming q into a matrix and applying it...

    float[] aa = q.getValue();
    rotate(aa[0], aa[1], aa[2], aa[3]);
  }
}

static class Vec3{
  float x, y, z;

  Vec3(){
  }

  Vec3(float x, float y, float z){
    this.x = x;
    this.y = y;
    this.z = z;
  }

  void normalize(){
    float length = length();
    x /= length;
    y /= length;
    z /= length;
  }

  float length(){
    return (float) Math.sqrt(x * x + y * y + z * z);
  }

  static Vec3 cross(Vec3 v1, Vec3 v2){
    Vec3 res = new Vec3();
    res.x = v1.y * v2.z - v1.z * v2.y;
    res.y = v1.z * v2.x - v1.x * v2.z;
    res.z = v1.x * v2.y - v1.y * v2.x;
    return res;
  }

  static float dot(Vec3 v1, Vec3 v2){
    return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
  }
  
  static Vec3 mul(Vec3 v, float d){
    Vec3 res = new Vec3();
    res.x = v.x * d;
    res.y = v.y * d;
    res.z = v.z * d;
    return res;
  }

  void sub(Vec3 v1, Vec3 v2){
    x = v1.x - v2.x;
    y = v1.y - v2.y;
    z = v1.z - v2.z;
  }
}

static class Quat{
  float w, x, y, z;

  Quat(){
    reset();
  }

  Quat(float w, float x, float y, float z){
    this.w = w;
    this.x = x;
    this.y = y;
    this.z = z;
  }

  void reset(){
    w = 1.0f;
    x = 0.0f;
    y = 0.0f;
    z = 0.0f;
  }

  void set(float w, Vec3 v){
    this.w = w;
    x = v.x;
    y = v.y;
    z = v.z;
  }

  void set(Quat q){
    w = q.w;
    x = q.x;
    y = q.y;
    z = q.z;
  }

  static Quat mul(Quat q1, Quat q2){
    Quat res = new Quat();
    res.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z;
    res.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y;
    res.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z;
    res.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x;
    return res;
  }
  
  float[] getValue(){
    // transforming this quat into an angle and an axis vector...

    float[] res = new float[4];

    float sa = (float) Math.sqrt(1.0f - w * w);
    if (sa < EPSILON){
      sa = 1.0f;
    }

    res[0] = (float) Math.acos(w) * 2.0f;
    res[1] = x / sa;
    res[2] = y / sa;
    res[3] = z / sa;
    return res;
  }
}
//Ariel和V3ga的arcball类,由Robert Hodgin设计的一对微型MOD和由cubes设计的小型MOD
类弧球{
浮动中心x,中心y,半径;
Vec3 v_向下,v_拖动;
夸夸其谈,夸夸其谈,夸夸其谈,夸夸其谈;
Vec3[]轴集;
int轴;
浮动mxv,myv;
浮动x,y;
弧球(浮动中心x、浮动中心y、浮动半径){
this.center_x=center_x;
this.center_y=center_y;
这个半径=半径;
v_down=new Vec3();
v_drag=new Vec3();
q_now=新的Quat();
q_down=新的Quat();
q_drag=新的Quat();
axisSet=new Vec3[]{new Vec3(1.0f,0.0f,0.0f),new Vec3(0.0f,1.0f,0.0f),new Vec3(0.0f,0.0f,1.0f)};
axis=-1;//没有约束。。。
}
void前滚(){
q_down.set(q_now);
v_向下=XY_到_球面(中心x,中心y);
q_down.set(q_now);
q_drag.reset();
v_阻力=XY_至_球体(中心x,中心y-((sin(PI/180)*半径))/2);
q_drag.set(Vec3.dot(v_down,v_drag),Vec3.cross(v_down,v_drag));
}
/*
void mousePressed(){
v_down=XY_到_球体(鼠标X、鼠标Y);
q_down.set(q_now);
q_drag.reset();
}
void mouseDragged(){
v_阻力=XY_至_球体(鼠标X、鼠标Y);
q_drag.set(Vec3.dot(v_down,v_drag),Vec3.cross(v_down,v_drag));
}
*/
无效运行(){
q_now=Quat.mul(q_拖动,q_向下);
应用quat2matrix(q_now);
x+=mxv;
y+=myv;
mxv-=mxv*.01;
myv-=myv*.01;
}
Vec3 XY_到_球体(浮动x,浮动y){
Vec3 v=新的Vec3();
v、 x=(x-中心x)/半径;
v、 y=(y-中心y)/半径;
浮磁=v.x*v.x+v.y*v.y;
如果(磁极>1.0f){
v、 规范化();
}否则{
v、 z=sqrt(1.0f-mag);
}
返回(轴==-1)?v:约束_向量(v,轴集[axis]);
}
Vec3约束向量(Vec3向量,Vec3轴){
Vec3 res=新的Vec3();
res.sub(vector,Vec3.mul(axis,Vec3.dot(axis,vector));
res.normalize();
返回res;
}
无效应用quat2matrix(Quat q){
//而不是将q转换成矩阵并应用它。。。
float[]aa=q.getValue();
旋转(aa[0],aa[1],aa[2],aa[3]);
}
}
静态类Vec3{
浮动x,y,z;
Vec3(){
}
Vec3(浮动x、浮动y、浮动z){
这个.x=x;
这个。y=y;
这个。z=z;
}
void normalize(){
浮动长度=长度();
x/=长度;
y/=长度;
z/=长度;
}
浮动长度(){
返回(浮点)数学sqrt(x*x+y*y+z*z);
}
静态Vec3交叉(Vec3 v1,Vec3 v2){
Vec3 res=新的Vec3();
res.x=v1.y*v2.z-v1.z*v2.y;
res.y=v1.z*v2.x-v1.x*v2.z;
res.z=v1.x*v2.y-v1.y*v2.x;
返回res;
}
静态浮点数(Vec3 v1,Vec3 v2){
返回v1.x*v2.x+v1.y*v2.y+v1.z*v2.z;
}
静态Vec3 mul(Vec3 v,浮动d){
Vec3 res=新的Vec3();
res.x=v.x*d;
res.y=v.y*d;
res.z=v.z*d;
返回res;
}
无效子系统(Vec3 v1、Vec3 v2){
x=v1.x-v2.x;
y=v1.y-v2.y;
z=v1.z-v2.z;
}
}
静态类Quat{
浮动w,x,y,z;
Quat(){
重置();
}
四元(浮点数w、浮点数x、浮点数y、浮点数z){
这个.w=w;
这个.x=x;
这个。y=y;
这个。z=z;
}
无效重置(){
w=1.0f;
x=0.0f;
y=0.0f;
z=0.0f;
}
无效集(浮动w,矢量3 v){
这个.w=w;
x=v.x;
y=v.y;
z=v.z;
}
空集(Quat q){
w=q.w;
x=q.x;
y=q.y;
z=q.z;
}
静态四次多重(四次q1,四次q2){
Quat res=新的Quat();
res.w=q1.w*q2.w-q1.x*q2.x-q1.y*q2.y-q1.z*q2.z;
res.x=q1.w*q2.x+q1.x*q2.w+q1.y*q2.z-q1.z*q2.y;
res.y=q1.w*q2.y+q1.y*q2.w+q1.z*q2.x-q1.x*q2.z;
res.z=q1.w*q2.z+q1.z*q2.w+q1.x*q2.y-q1.y*q2.x;
返回res;
}
float[]getValue(){
//将此四元数转换为角度和轴向量。。。
浮动[]res=新浮动[4];
float sa=(float)Math.sqrt(1.0f-w*w);
if(sa
我的代码,使用w键滚动立方体(循环自动旋转一次)

Arcball-Arcball;
int i;
int test_count=0;
布尔[]键=新布尔[13];
最终int w=0;
无效设置(){
尺寸(900700,P3D);
帧率(90);
仰泳();
弧球=新弧球(宽度/2,高度/2100);//100是半径
}
作废提款(){
灯光();
背景(255160122);
打印(“\n度=”+i);
i++;

如果(i使用我在问题中的想法每2*PI重置一次

  if(keys[w]) { 
    arcball.rollforward(PI/180);
    degreeW_count = degreeW_count + 1;
  }

  if(degreeW_count == 360) {
    arcball = new Arcball(width/2, height/2, 100);
    degreeW_count = 0;
  }

这完全避免了使用无理数和周期函数的任何数据类型所累积的舍入错误!

代码段中有两个小错误必须修复才能运行,但写得很好!我运行了草图,但无法重现问题,这意味着我看不到问题所在
Arcball arcball;

int i;
int test_count = 0;

boolean[] keys = new boolean[13];
    final int w = 0;


void setup() {
  size(900, 700, P3D); 
  frameRate(90);
  noStroke();
  arcball = new Arcball(width/2, height/2, 100);   //100 is radius
}

void draw() {
  lights();
  background(255,160,122);
  
 print(" \n degree = " + i );
  i++;
  if(i <= (360 * 1)) { arcball.rollforward(); }
  else { print(" break"); }
  
  if(keys[w]) { 
    arcball.rollforward(); 
    test_count = test_count + 1;
    print(" " + test_count);
  }

  translate(width/2, height/2-100, 0);
  box(50);
   
  translate(0, 200, 0);
  arcball.run();
  box(50);  
                           
}

void keyPressed() {
  switch(key) {
    case 119: 
        keys[w] = true;
        break;
  }
}
void keyReleased() {
  switch(key) {
    case 119: 
        keys[w] = false;
        break;
    } 
}
  if(keys[w]) { 
    arcball.rollforward(PI/180);
    degreeW_count = degreeW_count + 1;
  }

  if(degreeW_count == 360) {
    arcball = new Arcball(width/2, height/2, 100);
    degreeW_count = 0;
  }