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

Как выровнять объект по осям? (2 стр)

Страницы: 1 2
#15
23:59, 11 дек. 2011

Если  я правильно понял, то тебе просто нужно обнулить вращение.
Находишь скейл по осям, длинна вектора строки матрицы(1 строка X, 2 - Y, 3 - Z).
Строишь новую матрицу без вращения


#16
0:17, 12 дек. 2011

Согласен, это мощьный метод получения матрицы, но не еденичной. Код корявый потомучто в этом месте побывала туча вариантов, привел один из рабочих (хоть както рабочих) вариантов, как определюсь с операциями - буду думать о красоте и скорости))

>>Ага, а смещение оттуда убирать кто будет. Ведь ты говорил, что нужно только выравнивание
тут есть несколько смещений:
1 - новая позиция зеленой ручки объекта одно убирается\возвращается minusd, plusd соответственно в начале и конце процедуры. Матрицы в процедуру приходят правильные, проверено.
2 - смещение зеленой ручки от начала объекта (оно остается в матрице после minusd), его как я понимаю убирать ненадо - вращаем вокруг ручки а не вокруг начала объекта. именно изза него мощьный метод получения еденичной матрицы получает не еденичную, а чуток перемещенную (хотелось бы еще чтоб и масштабированную). Косяк судя по всему в этом смещении, но если его убрать - объект крутится вокруг точки вставки, а не зеленой ручки

Вариант с построением новой матрицы от еденичной косячить начинает уже в 2d, т.к. он не учитывает что второе смещение в матрице лежит в локальной системе координат

procedure processobject(pobj:PGDBObjEntity;minusd,plusd,rm:DMatrix4D;x,y,z:GDBVertex);
var i: GDBInteger;
  m,oplus,ominus:DMatrix4D;
  tv,P_insert_in_OCS,P_insert_in_WCS:gdbvertex;
begin
  pobj^.Transform(minusd);

  m:=PGDBObjWithMatrix(pobj)^.ObjMatrix;
  P_insert_in_OCS:=PGDBVertex(@m[3])^;
  m:=onematrix;
  PGDBVertex(@m[3])^:=P_insert_in_OCS;
  PGDBObjWithMatrix(pobj)^.ObjMatrix:=m;

  pobj^.Transform(rm);

  pobj^.Transform(plusd);
  PGDBObjWithMatrix(pobj)^.ReCalcFromObjMatrix;
  PGDBObjWithMatrix(pobj)^.Format;
end; 

upd: если ручку разместить в начале системы координат перетаскиваемого объекта, работают оба варианта

#17
1:45, 12 дек. 2011

zmatmn
Что же, сделаем новый заход :)
Опишу задачу так, как понял по картинке. У тебя есть объект. У которого есть точка крепежа, заданная в системе координат объекта.
Ты таскаешь его по сцене, в которой есть объекты приемники. В тот момент, когда мышка попадает на объект приемник объект должен прилипнуть к приемнику в указанной точке.
При этом точка крепежа должна совпасть с точкой приемника указанной мышкой, а оси выровняться по осям приемника.

Для начала еще раз рекомендую перейти с чистых матриц на исходное описание положения объекта (положение, базис) и сделать соответствующий класс :)
Продолжим :) Если все же у тебя стоит задача подготовить матрицу, которая сделает все за одно умножение на исходную матрицу объекта, то идем дальше.
Итак нам надо подготовить матрицу M такую, чтобы pobj^.Transform(M) дало нужный результат. Я так понял что эта функция умножает матрицу объекта на M.
Поехали:)
1) Делаем M единичной.
2) Сдвигаем в начало координат. Для этого выдираем из матрицы объекта элементы отвечающие за смещение, и строим на них матрицу сдвига в начало координат - minus и вторую, для сдвига обратно - plus.Умножаем М на матрицу сдвига в начало системы координат. M = M*minus (это если у тебя вектора строки, если столбцы, то M = munus*M)
3) Выравниваем оси по глобальной СКО. Берем матрицу из объекта Mobj и удаляем у нее элементы сдвига, потом инвертируем (или транспонируем, для матриц вращения это одно и то же). M = M*Mobj_inv
4) Выравниваем оси по СКО приемника. Выдираем матрицу из приемника - Mdest, обнуляем ей элементы сдвига и умножаем на M: M = M*Mdest
5) Двигаем объект обратно. M = M*plus
6) Двигаем объект в точку крепежа на приемнике. Составляем матрицу сдвига Мpick на основе вектора Vpick - Vobj (точка крепежа минус положение объекта). M = M*Mpck.
7) Двигаем объект с учетом смещения точки крепежа исходного объекта внутри его локальной системы координат. Ну думаю сообразишь.
Теперь obj^.Transform(M); Вуаля :)

Как видишь, возни много, и так будет и дальше, ты будешь ломать голову над преобразованиями, искать ошибки, тратить время. Поверь мне :)
А теперь представь, что все можно сделать примерно так.

class Object3D
{

......
Transform trans;
};

class Transform
{
void MoveTo(Vertex v); // двигаем в новую точку
void Move(Veretex dv); // сдвигаем на вектор
void RotateAxis(Vertex axis, float angle); // поворачиваем вокруг оси
void Align(Transform tr, AlignType at); // выравниваем относительно другого базиса
void Mult(Transform tr) // умножаем на другой базис (все равно, что умножит на другую матрицу
Matrix GetMatrix() // возвращаем матрицу соответствующую трансформации
// и т. д.
};

obj1.trans.MoveTo(point);
obj1.trans.Align(obj2.trans, AlignAxis);
...

Но лучше так.
obj1.MoveTo(point);
obj1.Align(obj2, AlignAxis);
...
(внутри этих функций прежняя трансформация будет записываться в стек, для undo)

#18
2:42, 12 дек. 2011

Tolanay
По поводу отказа от доминирования матриц еще раз отсоветуюсь)) у меня так уже было. и было еще хуже, все матричные головняки с таким подходом всеравно остаются, просто переносятся в другие места - туда где из описания положения считаются матрицы.
>>А теперь представь, что все можно сделать примерно так.
на матрицах можно такойже интерфейс забацать, щас разберемся и будет у меня pobj^.алигн)). Зато без матриц не сделать выделение\редактирование внутри объектов с локальными системами координат неограниченой вложенности. Вернее сделать конечно, но головняки будут побольше чем у меня сейчас
>>Поехали:)
Скоро утро, быстро ехать я уже не могу(( проверю завтра.

вот помоему стопроцентный вариант (без учета масштаба)... но не рабочий.. таже как в самом первом, в 2d всё ок, в 3d непонятный сдвиг

procedure processobject(pobj:PGDBObjEntity;minusd,plusd,rm:DMatrix4D;x,y,z:GDBVertex);
var i: GDBInteger;
  m,oplus,ominus:DMatrix4D;
  tv,P_insert_in_OCS,P_insert_in_WCS:gdbvertex;
begin
  pobj^.Transform(minusd);//переносим точку зеленой ручки в начало мировой ск

  m:=PGDBObjWithMatrix(pobj)^.ObjMatrix;//тащим матрицу на трепанацию
  P_insert_in_OCS:=PGDBVertex(@m[3])^;//достаем смещение от ручки до начала объекта
  PGDBVertex(@m[3])^:=nulvertex;//херим это смещение
  matrixinvert(m);//перещитываем смещение в мировые координаты
  P_insert_in_WCS:=VectorTransform3D(P_insert_in_OCS,m);//перещитываем смещение в мировые координаты
  m:=onematrix;//строим новую матрицу объекта, с такойже точкой вставки, но без поворота
  PGDBVertex(@m[3])^:=P_insert_in_WCS;//строим новую матрицу объекта, с такойже точкой вставки, но без поворота
  PGDBObjWithMatrix(pobj)^.ObjMatrix:=m;//возвращаем матрицу
  pobj^.Transform(rm);//поворачиваем как надо

  pobj^.Transform(plusd);//возвращаем
  PGDBObjWithMatrix(pobj)^.ReCalcFromObjMatrix;
  PGDBObjWithMatrix(pobj)^.Format;
end;


upd:
проверил, с небольшой редакцией:

procedure processobject(pobj:PGDBObjEntity;minusd,plusd,rm:DMatrix4D;x,y,z:GDBVertex);
var i: GDBInteger;
  m,m2,oplus,ominus:DMatrix4D;
  tv,P_insert_in_OCS,P_insert_in_WCS:gdbvertex;
begin
  pobj^.Transform(minusd);

  //1) Делаем M единичной
  m:=onematrix;
  //2) Сдвигаем в начало координат. Для этого выдираем из матрицы объекта элементы
  //отвечающие за смещение, и строим на них матрицу сдвига в начало координат - minus
  //и вторую, для сдвига обратно - plus.Умножаем М на матрицу сдвига в начало системы
  m:=PGDBObjWithMatrix(pobj)^.ObjMatrix;
  P_insert_in_OCS:=PGDBVertex(@m[3])^;
  ominus:=geometry.CreateTranslationMatrix(geometry.MinusVertex(P_insert_in_OCS));
  oplus:=geometry.CreateTranslationMatrix(P_insert_in_OCS);
  m:=geometry.MatrixMultiply(m,ominus);

  //3) Выравниваем оси по глобальной СКО. Берем матрицу из объекта Mobj и удаляем
  //у нее элементы сдвига, потом инвертируем (или транспонируем, для матриц
  //вращения это одно и то же). M = M*Mobj_inv
  m2:=PGDBObjWithMatrix(pobj)^.ObjMatrix;
  PGDBVertex(@m2[3])^:=nulvertex;
  matrixinvert(m2);
  m:=geometry.MatrixMultiply(m,m2);

  //4) Выравниваем оси по СКО приемника. Выдираем матрицу из приемника - Mdest,
  //обнуляем ей элементы сдвига и умножаем на M: M = M*Mdest
  m:=geometry.MatrixMultiply(m,rm);

  //5) Двигаем объект обратно. M = M*plus
  m:=geometry.MatrixMultiply(m,oplus);


  //6) Двигаем объект в точку крепежа на приемнике. Составляем матрицу сдвига
  //Мpick на основе вектора Vpick - Vobj (точка крепежа минус положение объекта).
  //M = M*Mpck.
  //7) Двигаем объект с учетом смещения точки крепежа исходного объекта внутри
  //его локальной системы координат. Ну думаю сообразишь.

  pobj^.Transform(m);

  pobj^.Transform(plusd);
  PGDBObjWithMatrix(pobj)^.ReCalcFromObjMatrix;
  PGDBObjWithMatrix(pobj)^.Format;
end;
[code]
не работает, примерно также как и другие варианты - таская за точку вставки объекта всё ок (второй объект в мультике), за произвольную - непонятные сдвиги (первый объект в мультике).
мультик - http://i29.fastpic.ru/big/2011/1212/cd/57d1725acc66eda134c4d28372bfe1cd.gif
6,7 пункты не применимы, т.к. на входе процедуры объект уже находится "зеленой" ручкой в новой точке вставки, но есть minusd,plusd - которые переносят эту ручку (не точку вставки объекта) в 0 и обратно.

еще upd:
походу косяк гдето в другом месте((

#19
9:22, 12 дек. 2011

zamtmn
Я тут обратил вдруг обратил внимание на эту строчку
P_insert_in_OCS:=PGDBVertex(@m[3])^;
Что она делает? Похоже совсем не то, что ожидается. Если у тебя вектор столбец, то это 3, это не правильный адрес нужно 3*4 (это если индексы от 0 до 4)
А если вектор это строка, то тоже не верно; в этом случае вообще взятием адреса не обойтись.

#20
19:56, 12 дек. 2011

>>P_insert_in_OCS:=PGDBVertex(@m[3])^;
"обычный" для паскаля обман контроля типов (ну или обычный для меня, не для паскаля)) ). В матрице вектора строки, "^" - "разименование" указателя, т.е. берется 3 флоата с адреса третьей строки, какраз компоненты перемещения.

Я вроде допер в чем косяк - в формировании minusd,plusd участвуют смещения заданые в разных СК, это выплывает какраз когда объект 3Д ориентирован

#21
20:34, 12 дек. 2011

zamtmn
Если m это массив флоатов, то такой способ получения смещения - неправильный. Прочитай еще раз что я написал выше.
Если ты вектор умножаешь на матрицу слева, то твое смещение - GDBVertex(@m[4*3]), если справа, то GDBVertex(m[3], m[4 + 3], m[8 + 3]); (инициализация вектора тремя значениями)

#22
20:55, 12 дек. 2011

матрица объявлена
DMatrix4D=array[0..3]of Vector4D;
т.е. @m[3] в четырехмерных вектрах всеравно что @m[4*3] в просто флоатах

Страницы: 1 2
ПрограммированиеФорумГрафика

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