Як мені реалізувати камеру на основі кватерніона?


14

ОНОВЛЕННЯ Помилка тут була досить простою. Я пропустив перетворення радіану в градуси. Не потрібно читати всю справу, якщо у вас є якісь інші проблеми.

Я переглянув кілька навчальних посібників з цього приводу, і коли я подумав, що зрозумів, я намагався реалізувати камеру на основі кватерніона. Проблема в тому, що вона не працює належним чином, після обертання протягом прибл. 10 градусів він стрибає назад до -10 градусів. Я поняття не маю, що не так. Я використовую openTK, і він вже має клас кватерніона. Я нобій в opengl, я роблю це просто для розваги, і не дуже розумію кватерніонів, тому, напевно, тут роблю щось дурне. Ось такий код: (Насправді майже весь код, за винятком методів, що завантажують та малюють vbo (він взято із зразка OpenTK, який демонструє vbo-s))

Я завантажую куб у vbo і ініціалізую четвертинку для камери

protected override void OnLoad(EventArgs e) {
    base.OnLoad(e);

    cameraPos = new Vector3(0, 0, 7);
    cameraRot = Quaternion.FromAxisAngle(new Vector3(0,0,-1), 0);

    GL.ClearColor(System.Drawing.Color.MidnightBlue);
    GL.Enable(EnableCap.DepthTest);

    vbo = LoadVBO(CubeVertices, CubeElements);
}

Я завантажую сюди перспективну проекцію. Це завантажується на початку і кожен раз, коли я змінюю розмір вікна.

protected override void OnResize(EventArgs e) {
    base.OnResize(e);

    GL.Viewport(0, 0, Width, Height);

    float aspect_ratio = Width / (float)Height;

    Matrix4 perpective = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspect_ratio, 1, 64);
    GL.MatrixMode(MatrixMode.Projection);
    GL.LoadMatrix(ref perpective);
}

Тут я отримую останнє значення обертання і створюю новий кватерніон, який представляє лише останнє обертання, і помножую його на кватерніон камери. Після цього я перетворюю це на кут осі, щоб opengl міг ним користуватися. (Ось як я зрозумів це з кількох підручників онлайн-кватерніона)

protected override void OnRenderFrame(FrameEventArgs e) {
    base.OnRenderFrame(e);

    GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

    double speed = 1;
    double rx = 0, ry = 0;

    if (Keyboard[Key.A]) {
        ry = -speed * e.Time;
    }

    if (Keyboard[Key.D]) {
        ry = +speed * e.Time;
    }

    if (Keyboard[Key.W]) {
        rx = +speed * e.Time;
    }

    if (Keyboard[Key.S]) {
        rx = -speed * e.Time;
    }

    Quaternion tmpQuat = Quaternion.FromAxisAngle(new Vector3(0,1,0), (float)ry);
    cameraRot = tmpQuat * cameraRot;
    cameraRot.Normalize();

    GL.MatrixMode(MatrixMode.Modelview);
    GL.LoadIdentity();

    Vector3 axis;
    float angle;

    cameraRot.ToAxisAngle(out axis, out angle);
    //////////////////////////////////////////////////////////////////////
    // THIS IS WHAT I DID WRONG: I NEED TO CONVERT FROM RADIANS TO DEGREES
    //////////////////////////////////////////////////////////////////////
    //BEFORE
    //GL.Rotate(angle, axis);
    //AFTER
    GL.Rotate(angle * (float)180.0/(float)Math.PI, axis);
    GL.Translate(-cameraPos);

    Draw(vbo);
    SwapBuffers();
}

Ось 2 зображення, щоб пояснити краще: я обертаюсь деякий час і з цього:

це

вона стрибає в це

введіть тут опис зображення

Будь-яка допомога вдячна.

Update1 : я додаю їх до сценарію, який записує у файл:

    sw.WriteLine("camerarot: X:{0} Y:{1} Z:{2} W:{3} L:{4}", cameraRot.X, cameraRot.Y, cameraRot.Z, cameraRot.W, cameraRot.Length);
    sw.WriteLine("ry: {0}", ry);

Журнал доступний тут: http://www.pasteall.org/26133/text . На лінії 770 куб стрибає справа наліво, коли camerarot.Y змінює знаки. Я не знаю, чи нормально це.

Update2 Ось повний проект.


2
Я не розумію проблеми. Ви спробували роздрукувати кватерніони, якими ви користуєтесь візуалізацією?
Нікол Болас

1
Погоджено, налагоджуйте свої значення rx, ry та Quaternion.
deceleratedcaviar

Чому ви не завантажуєте весь свій проект кудись на rapidshare? Було б простіше.
bobobobo

Гаразд, я завантажу його, коли повернусь додому.
gyozo kudor

Відповіді:


9

Хоча ви не показали необхідний код для підтвердження мого припущення тут, я майже можу гарантувати, що ваша проблема насправді полягає в тому, що ця лінія:

cameraRot.ToAxisAngle(out axis, out angle);

повертає значення кута, виражене в радіанах , а

GL.Rotate(angle, axis);

хоче, щоб кут був передбачений у градусах .

Щоб виправити це, потрібно перетворити значення кута при передачі його в GL.Rotate (), наприклад:

GL.Rotate(angle * 180.0/3.141593, axis);

Так, в цьому і була проблема. :) Дуже дякую. Я знав, що opengl очікує градусів, я припускав, що ToAxisAngle повертає градуси. Я просто подивився на код opentk, і це радіан. До речі, я надав повний вихідний код наприкінці.
gyozo kudor

@ NickCaplinger правильно зазначає, що в C # є Math.Piконстанта доступна, яку слід використовувати на користь буквального значення 3.141593, яке я використовував у цьому остаточному обчисленні.
Тревор Пауелл

1

Не варто. Може здатися, що було б менше роботи мати камеру, якою можна керувати, як іншими об’єктами сцени, але в перспективі краще мати камеру, де можна визначити положення, напрямок ока та вектор вгору. Особливо, коли ви починаєте програмувати рухові моделі, працювати з кватерніонами дуже боляче.


1
Домовились. Я не прихильник методу проектування моїх додатків "якщо важко вимовити це, то краще" =
Патрік Хьюз

Кватерніон важко вимовити?
notlesh

1
Трохи гумору йде довгий шлях = D З висновку я маю на увазі, що питання виникає від того, хто не має уявлення ЧОМУ він хоче камери кватерніона, просто що це акуратне слово та OMG, я хочу його так погано зараз! Це, звичайно, не підлягає вирішенню, коли щось, на кшталт правильної обробки радіанів та параметрів градусів, у зламаному коді вище не розглядається належним чином.
Патрік Х'юз

3
Це питання насправді не стосується камер; мова йде про те, як представити обертання в ігровому коді та як перетворити ці представлення гри в таку форму, щоб OpenGL міг їх використовувати. Це абсолютно законний питання, і я не думаю, що змикати відсутність досвіду роботи домену в ОП жодним чином корисно. Це не так, як ОП зробила дурну помилку; Наполягання OpenGL на використанні градусів при вираженні кутів прямо-таки химерне. Усі роблять цю помилку вперше, використовуючи OpenGL. Тож зійдіть зі своїх високих коней, люди. Гез.
Тревор Пауелл

Мені просто хотілося зрозуміти, як працює камера на кватерніоні, і я зробив цей проект у той день, коли мені більше нічого було робити. У мене немає реальних планів з цим.
gyozo kudor

0

Не знаю багато про внутрішні засоби OpenTK. На моєму досвіді я не бачив математичної бібліотеки з належною реалізацією квату, який підтримує необхідну точність (машина), тому що всі вони впливають на помилки e ^ 2-e ^ 3. Отже, ефект, який ви бачите: точність (і значення epsilon) становить приблизно 10 ^ -5, і вона "стрибає" біля нуля. Це моя здогадка :)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.