Java 中的旋转点问题

Rotation Point Troubles in Java

关于我的项目的一些背景故事(因为你可能会说,"Just use OpenGL.")

a.k.a。我讨厌 OpenGL 的原因

所以,我的电脑大约有 7 年历史,硬件上装有 OpenGL 3.30(使用 ATI Radeon HD 4300/4500),我真的很想使用 OpenGL 制作自己的 3D 游戏引擎。长话短说,着色器对我来说坏了(细节在底部)。所以,我说去他的吧,我要制作自己的 3D 渲染器。我完成了渲染,但我需要旋转方面的帮助。

更无聊的故事为什么会这样

嗯,事实是我开始制作自己的引擎,因为我的笔记本电脑太旧,无法按照教程进行操作,所以我开始使用带有很酷的视差系统的 2D 引擎,然后它击中了我。我之所以说我的电脑老旧的故事是因为那是我真正开始在一个完全不同的层面上思考旋转的时候。

代码

这就是问题开始的地方:

x = (float) ((x * Math.cos(Math.toRadians(main.cameraRot)) - z * Math.sin(Math.toRadians(main.cameraRot))));
    z = (float) (z * Math.sin(Math.toRadians(main.cameraRot)) - x * Math.cos(Math.toRadians(main.cameraRot)));

我想我看到了问题,我想我需要将 zsin(cameraRot) 添加到 xcos(cameraRot)

我什至画出了正弦和余弦函数的工作原理,主要是因为当时我也在研究水效果,我想,"I should be able to use sin (and only sin) to rotate."我错了(很明显)。我还使用图形计算器(1999 年的 TI-83+,而不是 2011 年)来绘制这些函数的图形(它们有点不同,是的,我使用了图形模式,您可以在其中输入 X 和 Y 值)。我现在正在尝试一些东西,我想我看到了主要问题。 Z 旋转使用 X 旋转,但 X 旋转使用 Z 坐标(如果这很复杂,我将其分解:我们需要使用原始 X 值来计算 Z 值的旋转,但我们改为使用变成旋转的X后的X值,会有很大的不同)。

根本不起作用。 cameraRot(旋转)不断增加,但是没有效果。 这是渲染代码:

g.drawRect((int) (x / (z - main.camZ) - 256 / (z - main.camZ) / 2),(int) (0 - 256 / (z - main.camZ) / 2),(int) (256 / (z - main.camZ)),(int) (256 / (z - main.camZ)));

但它搞砸了渲染。是的,我知道我正在画一个正方形,但我之前制作的(在笔记本电脑上)更完整,但使用了相同的渲染算法并且在我尝试添加旋转时损坏,每个对象似乎都为 0, 0,1.

关于如何解决这个问题有什么建议吗? 是来自渲染还是方程式? (我就省事,告诉你旋转方程

顺便提一下,我不小心做了那个渲染算法。

着色器是如何损坏的

我尝试将 uniform 与 VertexShader 一起使用,但它们仅适用于片段着色器。我遵循的教程使用“#version 330”(像我一样),但他们有 OpenGL 4.3 版(他们使用 java)而我有 3.30 版(并使用 java)。

好吧,我只是愚蠢。

x = (float) ((x * Math.cos(Math.toRadians(main.cameraRot)) - z * Math.sin(Math.toRadians(main.cameraRot))));
z = (float) (z * Math.sin(Math.toRadians(main.cameraRot)) - x * Math.cos(Math.toRadians(main.cameraRot)));

我之所以笨是因为你要做的是(简化,使用doubles):

double tempX = x; 
x = tempX * Math.cos(theta) - z * Math.sin(theta);
z = tempX * Math.sin(theta) + z * Math.cos(theta);

两年后,这个方程式我已经写了很多遍,以至于它真的会永远困扰着我。即使我死了。

现在看看我说的话:

I think I see the problem, I think I need to add zsin(cameraRot) to xcos(cameraRot)

还差得远呢。我遇到的整个问题 zx 的顺序对于 z 方程是错误的,而且我在执行之前没有将 x 存储在临时变量中操作。如果你不这样做,它就不会在 z 轴上正确旋转。

我不妨在这个实际上很容易弄清楚的晦涩问题中添加一些注释。如果你有 200 个对象,每个对象调用 Math.sin()Math.cos() 两次,那是非常低效的。您至少可以将结果 Math.sin()Math.cos() 值存储在它们自己的变量中,但这只是表面处理。

不是让每个对象单独计算正弦和余弦,而是制作一个相机class来保存相机的所有位置和旋转数据,以及屏幕尺寸。这样 1.0 x 1.0 大小的矩形与屏幕成比例。在非正方形纵横比(例如 16:9、4:3)中,您可以看到一些拉伸。解决此问题的简单方法是为 screenWidthscreenHeight 传递屏幕的宽度或高度。更难的方法让我们使用任何 FoV,但那是另一天了。

public class Camera {
    
    // Position variables, X is horizontal, Y is vertical, Z is fordical (forward and backward)
    private double x, y, z;
    private double rot;
    
    private double cos;
    private double sin;
    
    // Variables pertaining to the screen
    private int screenWidth;
    private int screenHeight;
    
    public Camera(double x, double y, double z, double rot, int screenWidth, int screenHeight) {
        
        setScreenDimensions(screenWidth, screenHeight);
        setPosition(x, y, z);
        setRotation(rot);
        
    }
    
    public void setScreenDimensions(int screenWidth, int screenHeight) {
        
        this.screenWidth  = screenWidth;
        this.screenHeight = screenHeight;
        
    }
    public int getScreenWidth() {...}
    public int getScreenHeight() {...}
    
    public void setPosition(double x, double y, double z) {...}
    public void setRotation(double rot) {
        
        // Update the rotation variable
        this.rot = rot;
        // Update the trig values
        cos = Math.cos(rot);
        sin = Math.sin(rot);
        
    }
    
    // Position Getters
    public double getX() {...}
    public double getY() {...}
    public double getZ() {...}
    
    // Position Setters
    public void setX(double x) {...}
    public void setY(double y) {...}
    public void setZ(double z) {...}
    
    
    public double getRotation() { return rot; }

    public double getCos() { return cos; }
    public double getSin() { return sin; }
    
}

然后当您从 world-space (3D) 转换为 screen-space (2D) 时,您会这样做(使用 Java Swing,因为那是我当时使用的问这个问题):

// somewhere in a class, probably the base GameObject class. If it's in an util class, make it "public static", and if it's in the Camera class, it would be "public". 
protected Point transform(Camera camera, double x, double y, double z) {
    
    double transX = x - camera.getX();
    double transY = y - camera.getY();
    double transZ = z - camera.getZ();
    
    double rotX   = transX * camera.getCos() - transZ * camera.getSin();
    double rotZ   = transX * camera.getSin() + transZ * camera.getCos();
    
    int pointX = (transX * camera.getScreenWidth() ) / transZ;
    int pointY = (y      * camera.getScreenHeight()) / transZ;
    
    return new Point(pointX, pointY);
    
}

Bam 现在我们已经优化了渲染例程。至少,就一个理智的人而言。如果你真的对优化很虔诚(就像我有时那样),你可能会做一些疯狂的事情。真正疯狂的事情发生在你使用 C++ 并使用指针时,但这超出了这个 Java 问题的范围。地狱,即使进入优化部分也超出了问题的范围,但这是我的问题,我认为我保留在我认为合适的情况下回答它的权利,只要它对阅读我的答案的任何人都有好处。

注意:深夜写的,如有错误,敬请谅解,明天早上修复!

旁注:反正不会有人会读这个:)