24 июля 2011 г.

Walking camera для Alternativa3D 8

После большого количества вопросов о том, как сделать перемещаемую пользователем камеру для Альтернативы, а иногда и такую, которая не "проходит сквозь стены", я решил всё же написать простенький пример. Для облегчения понимания максимально упростил логику и оставил только показательный функционал — "навернуть" всегда можно.

Также, пример рассчитан на новую, 8-ю версию "движка" Альтернативы, который поддерживает аппаратное ускорение графики. Но так как Flash Player 11 еще не вышел, то для функционирования примера и его тестирования необходим Flash Player 11 Incubator. Как всё это дело настроить можно посмотреть в предыдущих моих записях в блоге.

Итак, для примера нам нужен уровень и камера. Уровень можно подготовить в любом трехмерном редакторе с поддержкой экспорта в формат Collada (*.dae). API Alternativa3D 8 предоставляет функционал для парсинга этого формата. Также в "движке" существует камера alternativa.engine3d.core.Camera3D, которую мы и будем крутить-вертеть. После инициализации сцены и контекста рисования мы определяем камеру и настраиваем её первоначальное местоположение:

camera = new Camera3D(10, 10000);
camera.view = new View(stage.stageWidth, stage.stageHeight);
addChild(camera.view);
   
camera.rotationX = -90 * Math.PI / 180;
camera.rotationZ = -90 * Math.PI / 180;
camera.z = 60;
scene.addChild(camera);

Затем подгружаем наш трехмерный объект уровня. Процедура стандартна и массу раз описана во многих источниках. Далее подписываемся на нужные события. Нам понадобятся обработчики:

  • перерисовки кадра onEnterFrame;
  • изменения размеров кадра onResize;
  • событие нажатия на кнопку клавиатуры _keyDownListener;
  • событие отпускания кнопки клавиатуры _keyUpListener.

Назначения обработчиков события изменения размеров сцены, нажатия и отпускания кнопок клавиатуры понятны и банальны для платформы Flash. Достаточно посмотреть код.

Целью данного примера служит передвигаемая камера. Вся обработка пользовательского ввода с клавиатуры для управления камерой сосредоточена в методе onEnterFrame, который вызывается каждый кадр. Мы вычисляем предполагаемое смещение камеры и помещаем данные в Vector3D.

var delta:Vector3D = new Vector3D();
if (_keyUp) {
    delta.y = Math.cos(camera.rotationZ) * _directSpeed;
    delta.x = -Math.sin(camera.rotationZ) * _directSpeed;
} else
if (_keyDown) {
    delta.y = -Math.cos(camera.rotationZ) * _directSpeed;
    delta.x = Math.sin(camera.rotationZ) * _directSpeed;
}

Затем, созданный нами объект определения столкновений collider класса EllipsoidCollider вычисляет для нас разрешенное новое местоположение и получившиеся величины мы присваиваем камере.

ar destination:Vector3D = collider.calculateDestination(position, delta, level);
camera.x = destination.x;
camera.y = destination.y;

Далее — перерисовываем сцену.

Вот так, все достаточно не сложно.

Исходный код примера вы можете взять здесь (*.rar, 517 Kb).

12 комментариев:

Cannibalistic@yandex.ru комментирует...

доброго времени суток)
вопрос не совсем в тему, но тем не менее..

есть сделанная в 3d Max модель. я экспортирую её в два файла: ".3ds" и ".DAE". Далее я вставляю эти файлы во флеш. результат следующий:

3ds - модель находится в нужных координатах и в правильном положении, но текстуры лежат очень криво.
DAE - текстуры лежат как нужно, но сама модель перевёрнута непонятным образом.

подскажите, пожалуйста, в чем может быть дело?
// если посчитаете мой пост флудом, прошу удалить его и ответить мне на почту. Заранее Спасибо:)

Иван комментирует...

Cannibalistic@yandex.ru, думаю, вариантов может быть очень много: от ошибки в парсере (менее вероятно) до неправильной подготовки модели в 3d редакторе (более вероятно). Сложно сделать конкретный вывод из абстрактных данных. Могу попробовать порекомендовать упростить модель в редакторе например до куба и поэкспериментировать с его местоположением и текстурированием в разных форматах, и если ошибки повторяются - можно делать какой-то вывод.

Cannibalistic@yandex.ru комментирует...

спасибо за внимание:)

я так и сделал... прилагаю пару скринов... на сцене два параллелепипеда. один из .DAE файла, второй из .3DS. эти файлы экспортированы с одной сцены макса. К примитиву применён модификатор UVWMapping с параметром Box. Причем, если границы гизмо совпадают с размерами модели, то всё нормально. Но если сжать/растянуть гизмо, происходит то, что на скрине. Если вместо масштабирования гизмо использовать тайлинг, получается тоже самое...

текстура в формате .jpg. Пробовал .BMP - альтернатива ругается, что не знает такого формата, и .PNG - результат идентичен JPG'овскому.

скрины и код:
http://rghost.ru/18354511

Иван комментирует...

Я, конечно, не претендую на экспертное мнение, но...

То что объекты позиционируются по-разному - это скорее работа экспортера из макса в dae или 3ds. Т.е. на самом деле, объект находится в одних координатах (0, 0, 0), только повернут по оси x или y. Выставите пивот в максе в центр объекта и поймете.

После картирования объекта в максе я лично предпочитаю конвертировать объект в меш (можно поли). Но это на уровне предположения и, вполне возможно, что и без этого текстурные координаты ложатся аналогично - не проверял - попробуйте.

С тем, что текстура не повторяется (как должна) тоже можно поковыряться. Например, выставить для меша свойство его текстурематериала repeat в true.

Отпишитесь по результату - интересно.

Cannibalistic@yandex.ru комментирует...

Pixel, спасибо))
дело было как раз в свойстве repeat. Когда разобрался с текстурами, в колладе ковыряться не стал - хватает 3DS :)

насчёт моделей - все их конвертирую в поли.

возник ещё вопрос. теперь ближе к теме столкновений... есть объект, управляемый контроллером. есть Sprite. можно ли определить момент прохождения объекта через спрайт? я делаю так...

if (collider.getCollision(begining, // текущая позиция
displacement,
resPoint,
resPlane,
sprite)) // спрайт, с которым определяется столкновение
trace("true");

не происходит вообще ничего...

Иван комментирует...

Спрайт - вряд ли. Думаю, можно сделать невидимый меш, связать его по координатам со спрайтом и определять столкновение с ним, а не со спрайтом.

Анонимный комментирует...

А такой вопрос,загрузи модель, model.z ++ ; model.rotatinZ ++ ;
я смещаю вместе с пивотом ... как этого избежать...

Анонимный комментирует...

то есть поворот идет вокруг
x:0,y:0,z:0
а мне надо что бы модель вокруг своей оси крутилась ...

Иван комментирует...

> я смещаю вместе с пивотом
- это значит вместе с камерой?
> то есть поворот идет вокруг x:0,y:0,z:0
- это координаты чего? модели?
> что бы модель вокруг своей оси крутилась
а крутится?

Вообще данных для ответа мало. Например, модель грузится в какой контейнер? В рут?

Анонимный комментирует...

modl1(Mesh),mod2(Mesh),mod3(Mesh) в одном
( class Obj extends Object3d ) класcе,в 'том же классе mod1.y++ ;mod2.y++ ;mod3.y++;
в главном классе (Main extends Sprite)
Obj.RotationX ++ ;
эффект спирали ,
как смещать точку вокруг которой происходит RotationX. при .y++ я удаляюсь от нее, если
не поняли о чем речь то это можна увидеть
в 3dMax - рядом с кнопкой для скалирования обьэктов
есть окошко System Coordinate мне нужно по системе Viev а у меня как Local....

Иван комментирует...

Можно использовать матричные преобразования. Для каждого объекта строите единичную матрицу и на каждом кадре добавляете все трансформации. Для вложенных объектов они накапливаются и из родителя. Всё достаточно просто и расписано в литературе по 3д-программированию подробнейше и не раз. Например здесь: http://www.ozon.ru/context/detail/id/1633721/

Анонимный комментирует...

спасибо...

Отправить комментарий