Войти
ПрограммированиеФорумГрафика

Реализация тулов редактора

Страницы: 1 2 3 Следующая »
#0
20:21, 17 ноя. 2011

У большинства редакторов есть стандартные тулы Select, Move, Rotate, Scale.
В данный момент интересует реализация Move Tool.

Вот я выбираю например стрелочку которая двигает объект по X, объект должен за мышкой бегать.
Сначала я сделал тупо апнроджект позиции клика и делаю анпроджект при движении мыши, всё двигается, но с мышкой не совпадает.
Тогда я сделал XZ плоскость с которой делаю рейкаст, при определённых углах камеры всё зашибись, но если смотреть например сбоку, то уже поведение неадекватное (наверное надо делать XY плоскость уже).
Как правильно это реализовать?

И второй вопрос. Это рендер. Как отрендерить так, чтобы тул находился всегда на объекте и при этом не менял своих размеров? Чтото мутить с орто матрицей? Как?


#1
20:46, 17 ноя. 2011

1) Не совсем понял в чем проблема: не получается определить пересечение курсора с тулом или что?
2) Полагаю можно просто брать origin у мировой матрицы объекта и рисовать тул начиная от этой точки в направлении на соотв ось координат (конечно если при поворотах тул не должен поворачиваться вместе с объектом).

А вообще было бы круто если бы ты привел пример тулов, которые хочешь реализовать (например аля 3dsMax или как-то еще).

#2
21:06, 17 ноя. 2011

nes
> 1) Не совсем понял в чем проблема: не получается определить пересечение курсора с тулом или что?

Нет. Движение объекта не совпадает с движением мышки.

> 2) Полагаю можно просто брать origin у мировой матрицы объекта и рисовать тул
> начиная от этой точки в направлении на соотв ось координат (конечно если при
> поворотах тул не должен поворачиваться вместе с объектом).

И как это поможет не менять размер тула?

> А вообще было бы круто если бы ты привел пример тулов, которые хочешь
> реализовать (например аля 3dsMax или как-то еще).

Maya

#3
21:32, 17 ноя. 2011


>Нет. Движение объекта не совпадает с движением мышки.
Запустил майку, покрутил немного имхо там просто если выбрали тул x или тул z то перемещение объекта происходит при смещении мыши вправо-влево, по оси y - соотв вверх-вниз.

>И как это поможет не менять размер тула?
Не вижу необходимости менять размер тула если выбрали масштабирование или перемещение, если же выбрали вращение, то никто не запрещает устанавливать размер равный радиусу ограничивающей сферы объекта.

#4
22:00, 17 ноя. 2011

Executor
Я  у себя делал так: переводил координату мышки в 3Д-координату на оси, по которой двигаем. Какую координату переводить (X или Y) определял из простого условия - если ось, по которой мы перемещаем, переведённая в 2Д будет под углом -45 - 45 градусов, тогда пользовался Х, если больше - тогда Y.
Получилось очень неплохо.

Вот когда-то даже снял:)
http://www.youtube.com/watch?v=WItBoeMD6Io&feature=feedu

#5
22:38, 17 ноя. 2011

nes
> Запустил майку, покрутил немного имхо там просто если выбрали тул x или тул z
> то перемещение объекта происходит при смещении мыши вправо-влево, по оси y -
> соотв вверх-вниз.

Нет, там не так.

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

Дык мне та и не надо, чтобы размер менялся.
Надо чтобы он НЕ менялся, то есть улетаешь камерой за километр от объекта, объект пиксель на экране, а стрелочки какие были, такие и остались.

haper
> переводил координату мышки в 3Д-координату на оси, по которой двигаем.

Можно поподробнее? Как именно переводил?
Вот есть у меня координаты мыши X, Y
Соответственно делаю анпроджект, так?
Z у чем будет равна? 0? То есть на плоскости near plane? Потом что? Или не правильно?

> Вот когда-то даже снял:)

Во, тоже самое надо.
А рендерил стрелочки как? Их размер ведь не зависит от того насколько далеко камера от объекта?
А выбор стрелочки или плоскости как реализовал? Я пока делаю каст с ббоксом каждой стрелочки, может как-то проще делаешь?

#6
22:48, 17 ноя. 2011

Executor
>Надо чтобы он НЕ менялся, то есть улетаешь камерой за километр от объекта, объект пиксель на экране, а стрелочки какие были, такие и остались.
Вижу два варианта:
1 - масштабировать тул пропорционально удалению объекта от камеры.
2 - установить камеру в конечную позицию, нарисовать объект, установить камеру в начальную позицию, нарисовать тул (или в обратном порядке).

#7
22:53, 17 ноя. 2011

nes
Не думаю, что это хорошие варианты.

#8
23:03, 17 ноя. 2011

Executor
Ну первый может не совсем удачный, а второй вроде ничего, если не используется какой-то сторонний движок.
Код будет достаточно простым если использовать голый АПИ (например ОГЛ):

glMatrixMode(GL_PROJECTION);
glLoadMatrix(finalCameraTransform);
glMatrixMode(GL_MODELVIEW);
drawSceneObjects();
glMatrixMode(GL_PROJECTION);
glLoadMatrix(initialCameraTransform);
glMatrixMode(GL_MODELVIEW);
drawTool();
#9
23:51, 17 ноя. 2011

Executor
Смотри, переводил так:
Брал координату мышки, например Х, и проецировал её на ось, по которой двигаем (ось тоже у нас в 2Д переведена), а потом полученную точку снова переводил в 3Д - кажется, поиском наикратчайшего расстояния от луча, пущеного из этой точки и осью, по которой двигаем объект.

Завтра будет время, я обязательно посмотрю, как делал...
Там оно всё топорно и наверное неоптимально, но любого проца хватает за глаза, чтобы такую ерунду просчитать)

А размеры пивота всё время одинаковые были, как-то там высчитывал. После получения 3Д центра координат объекта (допустим мы один объект двигаем) переводил его в 2Д, а потом получал снова в 3Д координату пивота на фиксированном расстоянии. Так  он у меня получался всегда одного размера.

Завтра всё точно гляну и обязательно напишу, как делал. Уже не помню, как там выбор, но до предела простой.
Кажется, переводил все точки своего пивота (он же у меня из линий состоит) в 2Д, а там проверял координаты мышки на близость к линиям +/- 5 пикселей.... что-то вроде того.
Повторюсь, что там нифига не оптимизировано, но оно всё работало и меня устраивало вполне.


ЗЫ: подкорректировал ответы.

#10
0:03, 18 ноя. 2011

Executor, я как-то давным давно делал редактор, делал все эти инструменты, все делаются очень просто, вращение как в максе только делается чуть сложнее

допустим модель системы координат это такая моделька с осями в 3 стороны, с длиной 1, ее положение в мире задается какой-то матрицей. Что бы размер не изменялся на любых расстояниях нужно чтобы размер СК зависил линейно от расстояния до глаза.
есть вектор направления мыши и глаз камеры, умножаем вектор направления на обратную трансформацию СК (без участия перемещения офк) и глаз тоже (но с перемещением), далее полученный луч проверяем на пересечение с плоскостями XY, YZ, XZ, как только получается нужная точка (в случае XY: ((Y < 1) && abs(X)) < e || (X < 1 && abs(Y) < e), для остальных плоскостей соответственно), то считаем эту ось главной в движении, красим ее если нужно, и двигаем по ней, если точка не найдена, то ищем другую точку, чтобы (X < s && Y < s) (где s это число меньше 1, которая представляет маленький квадратик который есть в максе за который можно ухватится чтобы двигать по плоскости), вот и все.
движение по плоскасти:
запоминаемым первоначальный офсет в 3d вектор, уравнение плоскости (одно из трех), и дальше делаем все тоже самое, но полученную точку выбираем без условий на этой плоскости, и переводим обратно умножением на трансформацию СК
движение по оси:
тоже самое что по плоскости только перед умножением зануляем какое-то две компоненты

#11
1:57, 18 ноя. 2011

Executor
> Вот я выбираю например стрелочку которая двигает объект по X, объект должен за
> мышкой бегать.
> Сначала я сделал тупо апнроджект позиции клика и делаю анпроджект при движении
> мыши, всё двигается, но с мышкой не совпадает.
> Тогда я сделал XZ плоскость с которой делаю рейкаст, при определённых углах
> камеры всё зашибись, но если смотреть например сбоку, то уже поведение
> неадекватное (наверное надо делать XY плоскость уже).
> Как правильно это реализовать?
проверку попадания я делал, переводя линию в экранные координаты, дальше задача 2д - попадание в линию

bool Axis::select(const vec3 &click, const Camera &c) {
  Line prj(c.getFrustum().project(src), c.getFrustum().project(dst));
  prj.src.z = 0;
  prj.dst.z = 0;

  vec3 dir = normalize(prj.getDirection());
  if (dot(click, dir) - dot(prj.src, dir) > 0.0f && dot(click, dir) - dot(prj.dst, dir) < 0.0f && distance(prj, click) < 5.0f) {
    return true;
  }
  return false;
}

чтобы получить смещение по оси - пересекал selection ray с плоскостью, повернутой к камере, далее - проекция позиции пересечения на ось(предполагаем, что оси вегда выровнены по мировым осям - а значит, просто берем нужную координату).
дальше много матана

bool Manipulator::mouseMove(const Camera &c, int x, int y, bool test, bool alt) {
  if (!node) return false;
  if (type == MANIPULATE_TRANSLATE) {
    if (axisTarget != AXIS_NONE) {
      Line ray = c.getRay(x, y);
      // здесь главная формула. getAxisDir возвращает вектор выбранной оси      
      vec3 n = cross(cross(-c.getDirection(), getAxisDir(axisTarget)), getAxisDir(axisTarget)); 

      vec3 pos = node->getPos(true);
      Plane p(n, pos);
      p.normalize();

      TracePoint i;
      if (p.trace(ray, i, true, false)) {

        vec3 dll = getAxisDir(axisTarget);
        vec3 nodePos = node->getPos(true);
        vec3 nodeSnapPos = nodePos;

        // shift - наше смещение по оси        
        float shift = (getAxisDir(axisTarget) * (i.point - moveBase)).v[axisTarget]; 
        // видимо, в этой строчке автор (то есть я) хотел сказать, что он задолбался искать решение
        // меняя тип шифт то на вектор, то обратно, в итоге запутался и соорудил такую конструкцию
        // и она сработала, и от этой радости автор забыл, что ее надо бы привести в человеческий вид )
        // должно быть видимо
        // float shift = (i.point - moveBase).v[axisTarget]; 
        // а лучше
        // float shift = i.point.v[axisTarget] - moveBase.v[axisTarget]; 


        dll = dll * shift;

        if (snapPos > EPSILON && snapPosEnabled) {
          nodeSnapPos = snap(nodePos + dll, snapPos);
          dll = nodeSnapPos - nodePos;
        } else {
          nodeSnapPos = nodePos + dll;
        }

        if (dll != vec3(0, 0, 0)) {
          if (!test) {
            node->setPos(nodeSnapPos, true);
            moveBase += dll;
          }
          return true;
        }

      }
    }
  }
}

> И второй вопрос. Это рендер. Как отрендерить так, чтобы тул находился всегда на
> объекте и при этом не менял своих размеров? Чтото мутить с орто матрицей? Как?

рисуем и выделяем манипуляторы(тулы редактора) вот в таких координатах

vec3 Manipulator::toCameraPlane(const vec3 &pos, const Camera &c) const {
  vec3 prj = c.getFrustum().project(pos);
  Line ray = c.getRay(prj.x, prj.y);
  return c.pos + normalize(ray.dst - ray.src) * (c.minZ + size * 5.0f);
}

#12
10:32, 18 ноя. 2011

Executor
> Нет. Движение объекта не совпадает с движением мышки.
случаем смещение не накапливаешь каждое движение мыши?

#13
11:01, 18 ноя. 2011

Aroch
> случаем смещение не накапливаешь каждое движение мыши?

Нет. Это из-за того, что позиция курсора берётся в near plane.

#14
22:28, 18 ноя. 2011

EvilSpirit
> vec3 n = cross(cross(-c.getDirection(), getAxisDir(axisTarget)), getAxisDir(axisTarget));

Спасибо, это то что мне было нужно.
С первым вопросом разобрался.
Остался второй.

Страницы: 1 2 3 Следующая »
ПрограммированиеФорумГрафика

Тема в архиве.