簡體   English   中英

3D透視2D旋轉缺乏精度

[英]3D coordinate rotation lacking Precision in perspective 2D

所以我編寫了一個程序來繪制和顯示一個3D立方體,使用等軸測圖中使用的這些簡單的轉換公式:

x2 = x*cos(30) - y*cos(30)
y2 = x*sin(30) + y*sin(30) + z

坐標轉換很好,一切都是透視。

問題是旋轉,大程度的旋轉擾亂了所有的坐標並給了我一個完整的形狀。 並且以很小的角度旋轉許多次(即,1000度旋轉或更多旋轉)減小了立方體的尺寸。

public void rotateX(double dg) //cube is shrinking along y and z  
{
    y = (y*Math.cos(dg)-z*Math.sin(dg));  
    z = (y*Math.sin(dg)+z*Math.cos(dg));  
}
public void rotateY(double dg) //cube is shrinking along x and z  
{  
    x = x*Math.cos(dg)-z*Math.sin(dg);  
    z = x*Math.sin(dg)+z*Math.cos(dg);  
}  
public void rotateZ(double dg) //cube is shrinking along x and y  
{  
    x = x*Math.cos(dg)-y*Math.sin(dg);  
    y = x*Math.sin(dg)+y*Math.cos(dg);  
}

多次使用后,我怎樣才能解決cos和sin精度的缺失?

這是用3個seperat類編寫的整個代碼:
主要課程:

import java.awt.*;
import javax.swing.*;
import java.util.Random;
public class Frame extends JFrame
{
    private Random rnd = new Random();
    private cubeGUI cube;
    public Frame()
    {
        super();
    }

    public void paint(Graphics g)
    {
        cube = new cubeGUI(75,300.0,300.0);
        cube.convertall();
        double dg = 0.5; // The Smaller the degree, the less the error after long rotations.
        int sl = 5;
        int turns, axe;  
        while (1 == 1)
        {
            turns = rnd.nextInt(200)-100;
            axe = rnd.nextInt(3);
            for(int i = 0; i<turns; i++)
            {
                switch (axe)
                {
                    case 0: cube.rotatx(dg); break;
                    case 1: cube.rotaty(dg); break;
                    case 2: cube.rotatz(dg); break;
                }
                g.clearRect(0,0,600,600);
                g.drawLine(cube.a.x2,cube.a.y2,cube.b.x2,cube.b.y2);
                g.drawLine(cube.a.x2,cube.a.y2,cube.c.x2,cube.c.y2);
                g.drawLine(cube.c.x2,cube.c.y2,cube.d.x2,cube.d.y2);
                g.drawLine(cube.b.x2,cube.b.y2,cube.d.x2,cube.d.y2);
                g.drawLine(cube.e.x2,cube.e.y2,cube.f.x2,cube.f.y2);
                g.drawLine(cube.e.x2,cube.e.y2,cube.g.x2,cube.g.y2);
                g.drawLine(cube.g.x2,cube.g.y2,cube.h.x2,cube.h.y2);
                g.drawLine(cube.f.x2,cube.f.y2,cube.h.x2,cube.h.y2);
                g.drawLine(cube.a.x2,cube.a.y2,cube.e.x2,cube.e.y2);
                g.drawLine(cube.b.x2,cube.b.y2,cube.f.x2,cube.f.y2);
                g.drawLine(cube.c.x2,cube.c.y2,cube.g.x2,cube.g.y2);
                g.drawLine(cube.d.x2,cube.d.y2,cube.h.x2,cube.h.y2);
                try
                {
                    Thread.sleep(sl); //Rotation Speed, In relation with Angle of rotation.
                } catch(InterruptedException ex)
                {
                    Thread.currentThread().interrupt();
                }
            }
        }
}
public static void main(String[] args)
{
    Frame cube = new Frame();
        cube.setSize(600,600);
        cube.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        cube.setVisible(true);
    }
}

立方體類:

public class cubeGUI
{
    public Point center,a,b,c,d,e,f,g,h;
    private double x, y;
    public cubeGUI(int m, double x, double y)
    {
        this.x = x;
        this.y = y;
        a = new Point(-m,-m,-m);
        b = new Point(m,-m,-m);
        c = new Point(-m,m,-m);
        d = new Point(m,m,-m);
        e = new Point(-m,-m,m);
        f = new Point(m,-m,m);
        g = new Point(-m,m,m);
        h = new Point(m,m,m);
    }
    public void rotatx(double dg)
    {
        a.rotateX(Math.toRadians(dg));
        b.rotateX(Math.toRadians(dg));
        c.rotateX(Math.toRadians(dg));
        d.rotateX(Math.toRadians(dg));
        e.rotateX(Math.toRadians(dg));
        f.rotateX(Math.toRadians(dg));
        g.rotateX(Math.toRadians(dg));
        h.rotateX(Math.toRadians(dg));
        convertall();
    }
    public void rotaty(double dg)
    {
        a.rotateY(Math.toRadians(dg));
        b.rotateY(Math.toRadians(dg));
        c.rotateY(Math.toRadians(dg));
        d.rotateY(Math.toRadians(dg));
        e.rotateY(Math.toRadians(dg));
        f.rotateY(Math.toRadians(dg));
        g.rotateY(Math.toRadians(dg));
        h.rotateY(Math.toRadians(dg));
        convertall();
    }
    public void rotatz(double dg)
    {
        a.rotateZ(Math.toRadians(dg));
        b.rotateZ(Math.toRadians(dg));
        c.rotateZ(Math.toRadians(dg));
        d.rotateZ(Math.toRadians(dg));
        e.rotateZ(Math.toRadians(dg));
        f.rotateZ(Math.toRadians(dg));
        g.rotateZ(Math.toRadians(dg));
        h.rotateZ(Math.toRadians(dg));
        convertall();
    }
    public void convertall()
    {
        a.convert(x,y);
        b.convert(x,y);
        c.convert(x,y);
        d.convert(x,y);
        e.convert(x,y);
        f.convert(x,y);
        g.convert(x,y);
        h.convert(x,y);
    }
}

Point類(計算所有坐標):

public class Point
{
    private double x, y, z, F;
    public int x2, y2;
    public Point(double a, double b, double c)
    {
        x = a;
        y = b;
        z = c;
    }
    public int getX()
    {
        return (int)x;
    }
    public int getY()
    {
        return (int)y;
    }
    public int getZ()
    {
        return (int)z;
    }
    public void rotateX(double dg) //cube is shrinking along y and z
    {
        y = (y*Math.cos(dg)-z*Math.sin(dg));
        z = (y*Math.sin(dg)+z*Math.cos(dg));
    }
    public void rotateY(double dg) //cube is shrinking along x and z
    {
        x = x*Math.cos(dg)-z*Math.sin(dg);
        z = x*Math.sin(dg)+z*Math.cos(dg);
    }
    public void rotateZ(double dg) //cube is shrinking along x and y
    {
        x = x*Math.cos(dg)-y*Math.sin(dg);
        y = x*Math.sin(dg)+y*Math.cos(dg);
    }
    public void convert(double xx, double yy)
    {
        x2 = (int)(-(Math.cos(Math.toRadians(30))*x - Math.cos(Math.toRadians(30))*y) + xx);
        y2 = (int)(-(Math.sin(Math.toRadians(30))*x + Math.sin(Math.toRadians(30))*y + z) + yy);
    }
    public String toString()
    {
        return ("Y = " + y + ", Z = " + z);
    }
}

通常的方法是將多維數據集表示為點配置和當前轉換。 旋轉時,更新轉換但不更新點本身。 只有在需要點坐標時(用於渲染,顯示坐標值等),才應將變換應用於點。 這些點本身永遠不應該被修改。

這將消除在按順序應用多次旋轉時累積的誤差。 但是,重要的是將變換矩陣保持為旋轉(行列式1)。 否則,轉換仍將引入隨機偽像(縮放,偏斜或其他失真)。 因此,在應用每個旋轉之后,應該將變換矩陣重新歸一化,以使其保持純粹的變換。 歸一化可以像將每個條目除以行列式一樣簡單。

你使用的x已經改變了:x = x * Math.cos(dg)-y * Math.sin(dg);
y = x * Math.sin(dg)+ y * Math.cos(dg);

這是正確的變種。 double xx = x; x = x * Math.cos(dg)-y * Math.sin(dg); y = xx * Math.sin(dg)+ y * Math.cos(dg);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM