Render.ru

Выравнивание одинаковых объектов по вершинам

Александр Якушев

Активный участник
Рейтинг
7
#1
Здравствуйте! Есть два одинаковых объекта, повернутых относительно друг друга. К ним применен resetXform(пример в файле temp1.zip) Как совместить произвольно повернутый объект с оригиналом?
Нашел в нете способ, немного подредактировал (алгоритм, примерно такой - применяем для повернутого объекта что-то вроде Normal Align, затем поворачиваем его на нужный угол в плоскости полигона):
Код:
(   
    fn angle2Vec v1 v2 = acos (dot (normalize v1) (normalize v2))
    fn RotatePivotOnly obj index=
    (
    rot = (matrixFromNormal (getFaceNormal obj index)*obj.transform ) as quat
    rotValInv=inverse rot
    animate off in coordsys local obj.rotation*=RotValInv
    obj.objectoffsetrot*=RotValInv
    obj.objectoffsetpos*=RotValInv
    )
    f = 1
    mainObj = $MainObj
    tempObj = $TempObj
   
    faceNormM = getFaceNormal mainObj f
    faceNormT = getFaceNormal tempObj f
    faceCentM = meshop.getFaceCenter mainObj f
    faceCentT = meshop.getFaceCenter tempObj f
 
    tempObj.pivot = faceCentT
    ResetXForm tempObj
    convertToMesh tempObj
    mainObj.pivot = faceCentM
    ResetXForm mainObj
    convertToMesh mainObj   
   
    RotatePivotOnly tempObj f
    RotatePivotOnly mainObj f
   
    tempObj.transform = matrixFromNormal faceNormM
    tempObj.pos = faceCentM
       
    vecVertT =  getVert tempObj ((meshop.getVertsUsingFace tempObj f) as array)[1]
    vecVertM =  getVert mainObj ((meshop.getVertsUsingFace mainObj f) as array)[1]   
    faceNormM = getFaceNormal mainObj f
    faceNormT = getFaceNormal tempObj f
    faceCentM = meshop.getFaceCenter mainObj f
    faceCentT = meshop.getFaceCenter tempObj f
   
    theCrossV = cross (normalize (vecVertT - faceCentT)) faceNormT -- nujno dlya korrektirovki napravleniya vrasheniya
    ug = angle2Vec (vecVertT - faceCentT) (vecVertM - faceCentM) 
    ugKorYZ = if (dot theCrossV faceNormT) >= 0 then ug else -ug
    tempObj.transform = rotateZmatrix ugKorYZ*tempObj.transform   
    )
но способ не точный получился, чем дальше от совмещаемых треугольников, тем больше разброс (1.jpg) Собственно визуально, кажется простая задача. Надо просто выставить объект по трем точкам. Как это сделать?) Подскажите, пожалуйста!
 

Вложения

  • 650 КБ Просмотров: 345
  • 41,8 КБ Просмотров: 383

Александр Якушев

Активный участник
Рейтинг
7
#4
Вот немного разобрался
Код:
(   
fn AlignPivotTo Obj Trgt =
(
    -- Get matrix from object
    if classOf Trgt != matrix3 then Trgt = Trgt.transform
    -- Store child transforms
    local ChldTms = in coordSys Trgt ( for Chld in Obj.children collect Chld.transform )
    -- Current offset transform matrix
    local TmScale = scaleMatrix Obj.objectOffsetScale
    local TmRot = Obj.objectOffsetRot as matrix3
    local TmPos = transMatrix Obj.objectOffsetPos
    local TmOffset = TmScale * TmRot * TmPos
    -- New offset transform matrix
    TmOffset *= obj.transform * inverse Trgt
    -- Apply matrix
    Obj.transform = Trgt
    -- Restore offsets
    Obj.objectOffsetPos = TmOffset.translation
    Obj.objectOffsetRot = TmOffset.rotation
    Obj.objectOffsetScale = TmOffset.scale
    -- Restore child transforms
    for i = 1 to Obj.children.count do Obj.children[i].transform = ChldTms[i] * inverse Trgt * Obj.transform
)   
 
fn localMatrix p1 p2 p3 =
(
    v1 = p1 - p3 -- вектор по одной стороне треугольника
    v2 = p2 - p3 -- вектор по другой стороне
    e1 = normalize( cross v1 v2) -- первый орт как нормализованное векторное произведение v1 и v2
    e2 = normalize( cross e1 v1)
    e3 = normalize( cross e1 e2)
    mat3 = matrix3 1 -- создание стандартной матрицы
    mat3[1] = e1
    mat3[2] = e2
    mat3[3] = e3
    mat3[4] = p1
    return mat3
    )
mainObj = $MainObj 
tempObj = $TempObj
NumV = tempObj.numverts -- количество вершин объекта
 
-- выберем три разные вершины объекта
p1 = 1
p2 = tempObj.numverts/2 as integer
p3 = tempObj.numverts
 
--строим по ним локальные матрицы
-- можно использовать функцию matrixFromNormal, но она глючит из-за поворотов фэйсов
theMt = localMatrix (getVert tempObj p1) (getVert tempObj p2) (getVert tempObj p3)
theMm = localMatrix (getVert mainObj p1) (getVert mainObj p2) (getVert mainObj p3)
 
AlignPivotTo tempObj theMt -- совмещаем пивот перемещаемого объекта по локальной матрице theMt
tempObj.transform = theMm -- совмещаем перемещаемый объект с локальной матрицей theMm основного объекта
tempObj.pivot = mainObj.pivot
    )
тут, конечно надо еще доработать - исключить случаи, когда локальная матрица может обнуляться.
Функцию AlignPivotTo нарыл в нете. Работает отлично, только вот смысл преобразований в ней немного не понятен. Поясните, знающие люди, пожалуйста. Можно ли эту функцию как-то оптимизировать, убрать лишнее? Зачем в ней scaleMatrix используется и т.д. и т.п???В общем случае, может быть подскажете, как просто совместить пивот с новой матрицей???
Что-то вроде obj1.transform = obj2.transform, только для пивота объекта?
 

Александр Якушев

Активный участник
Рейтинг
7
#6
Может быть не прав, но, по моему, в функции слишком много лишних преобразований. Мне кажется есть путь попроще, что-то вроде obj1.transform = obj2.transform, только для pivot.
Чем меньше преобразований, тем выше точность и скорость. Предполагаю использовать для поиска одинаковой неинстансной геометрии в сцене и замены на инстансную. В сцене может быть несколько десятков тысяч объектов. Важно иметь максимально оптимизированный код для ускорения обработки.
 

Александр Якушев

Активный участник
Рейтинг
7
#7
Постараюсь уточнить вопрос.
Вот оптимизированный код:
Код:
(
fn AlignPivotTo Obj Trgt =
(
    -- New offset transform matrix
    TmOffset = obj.transform -- запоминаем исходное положение
    -- Apply matrix
    Obj.transform = Trgt -- выставляем объект по новой матрице
    -- Restore offsets  -- смещаем только объект в исходное положение (без pivot)
    Obj.objectOffsetPos = TmOffset.translation
    Obj.objectOffsetRot = TmOffset.rotation
    --Obj.objectOffsetScale = TmOffset.scale
)
 
b1 = box pos:(random [-100, -100, -100] [100,100,100]) wirecolor:green
rotate b1 (eulerAngles (random -360 360) (random -360 360) (random -360 360))
b2 = box  pos:(random [-100, -100, -100] [100,100,100]) wirecolor:red
rotate b2 (eulerAngles (random -360 360) (random -360 360) (random -360 360))
AlignPivotTo b1 b2.transform
)
Все прекрасно выполняет на первой итерации. Но если, после создания боксов, pivot Box001 сдвинуть(повернуть) и заново выполнить AlignPivotTo b1 b2.transform, то вместо того, чтобы pivot Box001 вернуться в исходное положение(b2.transform), начинает прыгать сам Box001 непонятным образом. Где подвох???
Извините, ошибку понял, только вот как от этих скачков избавиться????
 

Александр Якушев

Активный участник
Рейтинг
7
#8
Уфф, дошло. Как до утки на третьи сутки o_O. Вот похоже проще уже не написать:
Код:
fn AlignPivotTo Obj Trgt =
(
    -- Current offset transform matrix
    TmScale = scaleMatrix Obj.objectOffsetScale
    TmRot = Obj.objectOffsetRot as matrix3
    TmPos = transMatrix Obj.objectOffsetPos
    TmOffset = TmScale * TmRot * TmPos
    -- New offset transform matrix
    TmOffset *= obj.transform * inverse Trgt
    -- Apply matrix
    Obj.transform = Trgt
    -- Restore offsets
    Obj.objectOffsetPos = TmOffset.translation
    Obj.objectOffsetRot = TmOffset.rotation
    Obj.objectOffsetScale = TmOffset.scale
)
Вот только не очень понятен смысл этого преобразования:
Код:
TmOffset *= obj.transform * inverse Trgt
кто в матрицах понимает, поясните пожалуйста.
И еще - не хватает точности(2014-07-21 19-31.png) Может быть проблема из-за ограничений float? Можно ли как-то повысить точность?
 

Вложения

Сверху