3D вращение в 2 направлениях? - PullRequest
0 голосов
/ 05 декабря 2018

Фон

Я пытаюсь создать FPS-игру на Java с использованием LWJGL 3.0.Я установил класс камеры, который имеет высоту и рыскание (рулон не используется).Сама камера расширяет Entity, так как у нее есть модель.Я хотел бы, чтобы эта модель всегда находилась «перед» камерой, куда бы она ни указывала.У каждой сущности есть метод getTransformationMatrix(), который возвращает Matrix4f, который затем передается в шейдер сущности.

Задача

Модель должна указывать в направлении камеры, а также вращаться вокруг камеры так, чтобы она всегда была впереди.Объект в этой ситуации - руки с пистолетом, как показано на фотографии ниже.

enter image description here

Моя попытка

Мне известна базовая тригонометрия, поэтому я получил объект для правильного вращения по высоте и рысканию по отдельности.Это моя текущая реализация:

Тяга

@Override
public Matrix4f getTransformationMatrix() {
    modelX = getPosition().x + (radius * (float)Math.sin(Math.toRadians(getYaw())));
    modelZ = getPosition().z + (radius * (float)Math.cos(Math.toRadians(getYaw())));

    return Transform.createTransformationMatrix(new Vector3f(modelX, getPosition().y - 5, modelZ), new Vector3f(0, getYaw(), 0), getScale());
}

Высота

@Override
public Matrix4f getTransformationMatrix() {
    modelZ = getPosition().z + (radius * (float)Math.sin(Math.toRadians(getPitch())));
    modelY = (getPosition().y - 5) + (radius * (float)Math.cos(Math.toRadians(getPitch())));

    return Transform.createTransformationMatrix(new Vector3f(getPosition().x, modelY, modelZ), new Vector3f(getPitch(), 0, 0), getScale());
}

Я провел некоторые исследования, ноЯ боюсь, что застрял на этом слишком долго и мне нужны свежие глаза.Когда я пытаюсь объединить эти два вычисления, модель, кажется, движется в форме графика, когда смотрит под любым углом рыскания, кроме 0. Ниже моя попытка объединить их:

@Override
public Matrix4f getTransformationMatrix() {
    float zAxis = (radius * (float)Math.sin(Math.toRadians(getPitch())));
    modelY = (getPosition().y - 5) + (radius * (float)Math.cos(Math.toRadians(getPitch())));
    modelZ = getPosition().z + (zAxis * (float)Math.cos(Math.toRadians(getYaw())));
    modelX = getPosition().x + (radius * (float)Math.sin(Math.toRadians(getYaw())));

    return Transform.createTransformationMatrix(new Vector3f(modelX, modelY, modelZ), new Vector3f(getPitch(), getYaw(), 0), getScale());
}

Transform.createTransformationMatrix() выглядит следующим образом:

public static Matrix4f createTransformationMatrix(Vector3f translation, Vector3f rotation, Vector3f scale) {
    transform3d = new Matrix4f();
    transform3d.setIdentity();
    Matrix4f.translate(translation, transform3d, transform3d);
    Matrix4f.rotate((float) Math.toRadians(rotation.x), new Vector3f(1, 0, 0), transform3d, transform3d);
    Matrix4f.rotate((float) Math.toRadians(rotation.y), new Vector3f(0, 1, 0), transform3d, transform3d);
    Matrix4f.rotate((float) Math.toRadians(rotation.z), new Vector3f(0, 0, 1), transform3d, transform3d);
    Matrix4f.scale(scale, transform3d, transform3d);
    return transform3d;
}

Мысли

Друг предложил создать единичный вектор, который указывает в направлении вверх (т.е. new Vector3f(0, 1, 0))вращение вектора на высоту и отклонение, затем умножение вектора на радиус и добавление его в положение камеры.Я попробовал это, но я не знаю, как повернуть Вектор на угол, и, похоже, в классе slick-utils Vector3f нет метода Vector3f.rotate().Любая помощь очень ценится, потому что в последние несколько дней у меня болит голова.Спасибо!

1 Ответ

0 голосов
/ 19 декабря 2018

Что мы обычно делаем, так это да, берем вектор единичной длины и используем его в качестве нашей «оси».В 2D-вращении мы все время используем ось - ось Z.

3D-вращение

Если вы посмотрите на ось, как в 2D, выбудет выглядеть примерно так:

2D-вращение

Итак, чтобы повернуть точку в 3D, вы можете использовать матрицу или вектор.Сначала я рекомендую вектор, чтобы вы могли понять, как работает трехмерное вращение.Это поражает воображение!

Я скину код из класса Vector3f из theBennyBox.Если вы заинтересованы в этом, посмотрите theBennyBox на Youtube.

Vector3f

    public Vector3F rotate(float angle, Vector3F axis) {
    double a = Math.toRadians(angle / 2f);
    float hs = (float) Math.sin(a);
    float hc = (float) Math.cos(a);
    Vector4F r = new Vector4F(axis.getX() * hs, axis.getY() * hs, axis.getZ() * hs, hc);
    Vector4F rc = r.conjugate();
    r = r.multiplyAsQuat(this).multiplyAsQuat(rc);

    return new Vector3F(r.getX(), r.getY(), r.getZ());
    }

Vector 4f

    public Vector4F multiplyAsQuat(Vector3F v) {
    float o = -x * v.getX() - y * v.getY() - z * v.getZ();
    float a = w * v.getX() + y * v.getZ() - z * v.getY();
    float b = w * v.getY() + z * v.getX() - x * v.getZ();
    float c = w * v.getZ() + x * v.getY() - y * v.getX();

    return new Vector4F(a, b, c, o);
}

    public Vector4F conjugate() {
    return new Vector4F(-x, -y, -z, w);
}

    public Vector4F multiplyAsQuat(Vector4F qt) {

    float o = w * qt.getW() - x * qt.getX() - y * qt.getY() - z * qt.getZ();
    float a = x * qt.getW() + w * qt.getX() + y * qt.getZ() - z * qt.getY();
    float b = y * qt.getW() + w * qt.getY() + z * qt.getX() - x * qt.getZ();
    float c = z * qt.getW() + w * qt.getZ() + x * qt.getY() - y * qt.getX();

    return new Vector4F(a, b, c, o);
}
...