#1 2020-06-01 12:30:57

Nic
Участник
Зарегистрирован: 2020-04-09
Сообщений: 6

Актер на сфере.

Здравствуйте. Как что бы объект ходил по сфере.
И по кубу по всем сторонам, а не только с верху?

Offline

#2 2020-06-02 08:09:54

Gecko
Админ
Из РФ, Казань
Зарегистрирован: 2018-06-02
Сообщений: 164
Сайт

Re: Актер на сфере.

В общем случае нужно получить нормаль поверхности под ногами персонажа и присвоить ее вектору Up:

ux = ObjectGetAbsoluteUp(character, 0);
uy = ObjectGetAbsoluteUp(character, 1);
uz = ObjectGetAbsoluteUp(character, 2);
if (ObjectRaycast(characterPointerDown, planet))
{
    ux = ObjectGetCollisionNormal(0);
    uy = ObjectGetCollisionNormal(1);
    uz = ObjectGetCollisionNormal(2);
}
ObjectSetAbsoluteUp(character, ux, uy, uz);

characterPointerDown в данном случае - это даммикуб, привязанный к персонажу и повернутый вниз на 90 градусов:

characterPointerDown = DummycubeCreate(character);
ObjectPitch(characterPointerDown, -90);

Для сферы это будет работать хорошо, как и для любых гладких тел, но вот с кубами сложнее. Самое простое, думаю, использовать куб со скругленными краями (чем больше радиус скругления, тем лучше).

Также в случае с кубами скорее всего нужно будет как-то смягчать резкие переходы нормали, тут все зависит от того, как реализуется механика движения. Если есть гравитация, и все построено на физике, то возможно и не надо будет смягчать.

Offline

#3 2020-06-02 11:21:47

Nic
Участник
Зарегистрирован: 2020-04-09
Сообщений: 6

Re: Актер на сфере.

Спасибо получилось со сферой. Но высоту от центра не соблюдает. А на кубе не переходит на другие стороны.

И возник вопрос, Вы говорите:

Gecko пишет:

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

То есть можно указать центр гравитации сам объект, а точнее его центр?

Редактировался Nic (2020-06-02 14:59:04)

Offline

#4 2020-06-02 17:08:33

Gecko
Админ
Из РФ, Казань
Зарегистрирован: 2018-06-02
Сообщений: 164
Сайт

Re: Актер на сфере.

Чтобы высота соблюдалась, как раз и должна быть гравитация)

Nic пишет:

То есть можно указать центр гравитации сам объект, а точнее его центр?

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

Ну и конечно, тут не обойтись без физического движка, так как надо обрабатывать столкновения с планетой. ODE самый простой вариант, хотя теоретически можно сделать на любом. Правда, я сам такую механику не пробовал делать.

Offline

#5 2020-06-02 17:19:32

Gecko
Админ
Из РФ, Казань
Зарегистрирован: 2018-06-02
Сообщений: 164
Сайт

Re: Актер на сфере.

Кстати, вспомнил, что была статья на тему механики как в Mario Galaxy: https://www.gamasutra.com/view/feature/ … mario_.php

Там даже демка есть для Blitz, можно посмотреть, как в ней сделано для несферических планет.

Offline

#6 2020-06-02 18:16:24

Gecko
Админ
Из РФ, Казань
Зарегистрирован: 2018-06-02
Сообщений: 164
Сайт

Re: Актер на сфере.

Сделал пример с физикой: http://xtreme3d.ru/files/examples/planet_gravity.zip
Заметно, что переходы слишком резкие без смягчения нормалей, как я и ожидал.

Offline

#7 2020-06-05 08:29:25

Nic
Участник
Зарегистрирован: 2020-04-09
Сообщений: 6

Re: Актер на сфере.

Gecko пишет:

Сделал пример с физикой: http://xtreme3d.ru/files/examples/planet_gravity.zip
Заметно, что переходы слишком резкие без смягчения нормалей, как я и ожидал.

Спасибо за полный пример, сразу отпало много вопросов. Вы мне даже настроение подняли на полдня.

Возник вопрос в основном с манекенами, почему их три.

character - сам персонаж
character_caster - ноги персонажа для определения низа
character_model - ??? что-то персонажа


Я взял смелость прокомментировать Ваш код у себя в платформе разработки DevelNext, и прошу поправить меня где я не совсем правильно это сделал или вообще пропустил так как не понял что там происходить. Особенно это связано с вычислениями.

        #<!--Получаем размер окна-->
        $screen   = UXScreen::getPrimary();#Получаем парамметры данного окна
        $screenW  = $screen->bounds['width'];#Получаем длину окна
        $screenH  = $screen->bounds['height'];#Получаем высоту окна

        $x = new xtreme3d; #Инцилизация обекта движка        
        $x->EngineCreate();#Запуск 3D-движка
        
        $matlib = $x->MaterialLibraryCreate();#Создание библиотеки матерялов
        $x->MaterialLibraryActivate($matlib);#Активация библиотеки матерялов
        
        #<!--Окно-->
        $handle = $x->FindWindow($this->title);#Находим данное окно где будет вид игры
        
        $view1 = $x->ViewerCreate(0, 0, $this->width, $this->height, $handle);#создаем первый вид, в котором будет отображаться пространство в 3D;
        $x->ViewerSetBackgroundColor($view1, $x->MakeColorRGB(127,127,127));#выбираем цвет фона для вида
        $x->ViewerSetLighting($view1, true);#включаем освещение
        $x->ViewerEnableFog($view1, false);#Включить туман для вида
        $x->ViewerSetFogColor($view1, $x->MakeColorRGB(127,127,127));#цвет тумана
        $x->ViewerSetFogDistance($view1, 8, 50);#дальность тумана мини, макс
        $x->ViewerSetAntiAliasing($view1, 0); #Сглаживание
        #<!--Окно-->

        $back = $x->DummycubeCreate(0);#Задний небесный купол
        $scene = $x->DummycubeCreate(0);#Сцена
        $front = $x->DummycubeCreate(0);#Передний текстовой план

        #<!--Источника света-->
        $light = $x->LightCreate('lsOmni', $scene);#Создаем источник света
        $x->LightSetAmbientColor($light, $x->MakeColorRGB(127,127,127), 1.0);#Назвачаем цвеи тени
        $x->LightSetDiffuseColor($light, $x->MakeColorRGB(255,255,255), 1.0);#Назначаем цвет материала
        $x->LightSetSpecularColor($light, $x->MakeColorRGB(255,255,255), 1.0);#Назначаем цвет блика
        $x->ObjectSetPosition($light, 10, 10, 10);#Даем координаты позиции
        #<!--/Создание источника света-->
        
        $x->OdeManagerCreate();#Создание движка физики
        $x->OdeManagerSetGravity(0, 0, 0);#Установка сили и направления гравитации
        
        $planetoid = $x->FreeformCreate("planetoid.obj", $matlib, $matlib, $scene);#Добавляем объект из файла (планетоид)
        $x->FreeformBuildOctree($planetoid);#Строит октарное дерево для объекта свободной формы для проверки столкновений
        $x->MaterialCreate("planetoid", "");#Созжаем материал
        $x->MaterialSetAmbientColor("planetoid", $x->MakeColorRGB(0,255,0), 1.0);#Назвачаем цвеи бликака
        $x->MaterialSetDiffuseColor("planetoid", $x->MakeColorRGB(0,255,0), 1.0);#Назначаем цвет материала
        $x->ObjectSetMaterial($planetoid, "planetoid");#Назначаем материал на объект
        $x->OdeStaticCreate($planetoid);#говорим физдвижку что планетоид статический объект (т.е. на планетоид)
        for ($i = 0; $i < $x->FreeformMeshObjectsCount($planetoid); $i = $i + 1)#Считаем меши объекта для добавление телу полигональной сетки
        {
          $x->OdeAddTriMesh($planetoid, $i);#Добавляет телу геометрию полигональной сетки (меш)
        }
        
        $character = $x->DummycubeCreate($scene);#Создаем манекен для кубика (персонаж)
        $x->ObjectSetPosition($character, 0, 1.5, 0);#Даем координат
        $x->OdeDynamicCreate($character);#говорим физдвижку что кубил динамический объект
        $x->OdeAddSphere($character, 0, 0, 0, 0.2);#назначаем коллайдер виде сферы на кубик
        $x->OdeSurfaceSetMu($character, 0);#Устанавливает коэффициент трения 
        $x->OdeSurfaceSetMu2($character, 0);#Устанавливает μ2 - необязательный коэффициент трения для второго направления трения поверхности тела.
        
        $character_model = $x->CubeCreate(0.4, 0.4, 0.4, $scene);#Создаем куб
        $x->MaterialCreate("character", "");#Созжаем материал
        $x->MaterialSetAmbientColor("character", $x->MakeColorRGB(255,0,0), 1.0);#Назвачаем цвеи бликака
        $x->MaterialSetDiffuseColor("character", $x->MakeColorRGB(255,0,0), 1.0);#Назначаем цвет материала
        $x->ObjectSetMaterial($character_model, "character");#Назначаем материал на объект (т.е. на куб)
        
        $character_caster = $x->DummycubeCreate($character_model);#Манекен для определения низа у персонажа
        $x->ObjectPitch($character_caster, -90);#Поворачиваем его 
        
        $camPos = $x->DummycubeCreate($character_model);#Создаем манекен для позиции камеры
        $x->ObjectSetPosition($camPos,0,0,0);#Определяем его локальные коордмнаты
        
        $camera = $x->CameraCreate($camPos);#Создаем камеру
        $x->ObjectPitch($camera, -20);#Поворачиваем камеру чуть вниз
        $x->ObjectSetPosition($camPos, 0, 1, 2);#Определяем её координаты как от 3-го лица
        $x->CameraSetViewDepth($camera, 500);#Задам дальность обзора камеры 
        $x->CameraSetFocal($camera, 60);#Задаем угол зрения камеры 
        $x->CameraSetNearPlaneBias($camera, 0.2);#Задаем коэффициент ближней плоскости отсечения камеры.
        $x->ViewerSetCamera($view1, $camera);#Определяем камеру, которую должен использовать вид для отрисовки проекции на сцену.
        
        $mx = ($screenW) / 2;#Высчитываем центр окноа по горизонту
        $my = ($screenH) / 2;#Высчитываем центр окноа по вертикали
        $x->MouseSetPosition($mx, $my);#Устанавливаем курсор в эту точку
        
        #Устанавливаем таймер-цикл с параметрами которые буду изменяться в цикле
        $this->timer = new UXAnimationTimer(function() use (
            $x, $zm, $view1, $camPos, $mx, $my, $camera, $light, $character, $planetoid, $character_caster, $character_model){
        
        $x->OdeDynamicSetRotationQuaternion($character, 0, 0, 0, 1);#Задает поворот динамического тела, выраженный кватернионом

        #Получаем абсолутный вектор направление модели персонажа
        $dirX = $x->ObjectGetAbsoluteDirection($character_model, 0);#X
        $dirY = $x->ObjectGetAbsoluteDirection($character_model, 1);#Y
        $dirZ = $x->ObjectGetAbsoluteDirection($character_model, 2);#Z
        
        #Получаем абсолутный вектор "права" направление персонажа
        $rightX = $x->ObjectGetAbsoluteRight($character_model, 0);#X
        $rightY = $x->ObjectGetAbsoluteRight($character_model, 1);#Y
        $rightZ = $x->ObjectGetAbsoluteRight($character_model, 2);#Z
        #Высчитываем 
        $movX = $dirX * 2;
        $movY = $dirY * 2;
        $movZ = $dirZ * 2;
        #Высчитываем 
        $strX = $rightX * 2;
        $strY = $rightY * 2;
        $strZ = $rightZ * 2;
        
        #Сбрасываем переменные для правильного указания скорость объекта (Персонажа)
        $vx = 0;
        $vy = 0;
        $vz = 0;
        
        #Указываем скорость направления при нужно нажатой клавишой
        if ($x->KeyIsPressed(38) || $x->KeyIsPressed(87)) # Клавиша верх или "W"
        {
          $vx = $vx + $movX;
          $vy = $vy + $movY;
          $vz = $vz + $movZ;
        }
        else if ($x->KeyIsPressed(40) || $x->KeyIsPressed(83)) # Клавиша вниз или "S"
        {
          $vx = $vx - $movX;
          $vy = $vy - $movY;
          $vz = $vz - $movZ;
        }
        
        if ($x->KeyIsPressed(39) || $x->KeyIsPressed(68))#Клавиша вправо или "D"
        {
          $vx = $vx + $strX;
          $vy = $vy + $strY;
          $vz = $vz + $strZ;
        } 
        else if ($x->KeyIsPressed(37) || $x->KeyIsPressed(65))#Клавиша влево или "A"
        {
          $vx = $vx - $strX;
          $vy = $vy - $strY;
          $vz = $vz - $strZ;
        } 
        
        $x->OdeDynamicSetVelocity($character, $vx, $vy, $vz);#Назначение скорости объекта в нужном направлении (персонажа)
        
        $x->ObjectPointToObject($character_caster, $planetoid);#Направлять объект в сторону дургого объекта (Ноги персонажа к планетоиду)
        
        #Получаем абсолутный вектор "верха" персонажа
        $ux = $x->ObjectGetAbsoluteUp($character, 0);#X
        $uy = $x->ObjectGetAbsoluteUp($character, 1);#Y
        $uz = $x->ObjectGetAbsoluteUp($character, 2);#Z
        
        #Если есть пересечения (соприкосновения) Ног персонажа с планетоидом
        if ($x->ObjectRaycast($character_caster, $planetoid))
        {
            #То получить координаты нормали полигона последнего пересечения
            $ux = $x->ObjectGetCollisionNormal(0);#X
            $uy = $x->ObjectGetCollisionNormal(1);#Y
            $uz = $x->ObjectGetCollisionNormal(2);#Z
        }
        $x->ObjectSetPositionOfObject($character_model, $character);#Синхронизируем абсолютные координаты объекта 1(Модели персонажа) с абсолютными координатами объекта 2(персонажем).
        $x->ObjectSetAbsoluteUp($character_model, $ux, $uy, $uz);#Назначить абсолютный единичный вектор Up объекта(Модели персонажа)
        $x->OdeDynamicAddForce($character, -$ux * 15, -$uy * 15, -$uz * 15);#Прикладывает силу в абсолютных координатах к центру массы динамического тела(персонажа с 15).
        
        $x->OdeManagerStep(0.01);#вычисления новых состояний тел ODE.
        $x->Update(0.01);#Обновление объектов сцены
        $x->ViewerRender($view1);#отрисовка указаного вида (экрана)
             
        });#конец цикла-таймера
        
        $this->timer->start(); // запускаем таймер 

    }

Ну и собственно Ваш перенесенный проект в DevelNext. Скачать>>>

Я это сделал в основном для себя что бы лучше понять Ваш код. И очень Вас прошу дописать, мною пропушенные, комментарии в коде.

Заранее благодарен.

Редактировался Nic (2020-06-05 08:35:45)

Offline

#8 2020-06-05 21:07:56

Gecko
Админ
Из РФ, Казань
Зарегистрирован: 2018-06-02
Сообщений: 164
Сайт

Re: Актер на сфере.

Разделение на character и character_model потому что физическую модель (character) нельзя использовать для поворотов, она используется только для вычисления позиции. Поворот персонажа (ObjectTurn) надо задавать через графическую модель (character_model), которая привязана к позиции character, но вращается независимо. К сожалению, в X3D сильно ограничена обратная связь между объектами и их ODE-телами - объект с динамическим телом контролируется только через ODE и начисто игнорирует ObjectTurn и пр. В противном случае можно было бы упростить механику и обойтись только одним объектом.

Конкретно в примере поворот не используется, но его легко добавить.

Nic пишет:

И очень Вас прошу дописать, мною пропушенные, комментарии в коде.

Код почитал, комменты вроде везде правильные. По поводу этой части:

#Высчитываем 
$movX = $dirX * 2;
$movY = $dirY * 2;
$movZ = $dirZ * 2;

#Высчитываем 
$strX = $rightX * 2;
$strY = $rightY * 2;
$strZ = $rightZ * 2;

Это просто компоненты скорости в двух перпендикулярных направлениях, которые в зависимости от нажатой клавиши добавляются или отнимаются от vx, vy, vz. Вместо 2 можно поставить любой желаемый модуль скорости.

Offline

Подвал доски

Под управлением FluxBB