1. Пользоваться форумом на планшетах и телефонах стало удобнее благодаря Tapatalk

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

Тема в разделе "MAXScript", создана пользователем Александр Якушев, 12 июл 2014.

Модераторы: Savin Denis
  1. Александр Якушев

    Александр Якушев Активный участник

    С нами с:
    13.08.2009
    Сообщения:
    77
    Симпатии:
    1
    Баллы:
    7
    Здравствуйте! Есть два одинаковых объекта, повернутых относительно друг друга. К ним применен 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) Собственно визуально, кажется простая задача. Надо просто выставить объект по трем точкам. Как это сделать?) Подскажите, пожалуйста!
     

    Вложения:

    • temp01.zip
      Размер файла:
      650 КБ
      Просмотров:
      54
    • 1.jpg
      1.jpg
      Размер файла:
      41,8 КБ
      Просмотров:
      103
  2. igorznag

    igorznag Знаток

    С нами с:
    23.04.2010
    Сообщения:
    1.256
    Симпатии:
    173
    Баллы:
    65
    Cкрипт 3-Point-Align.
     
  3. Александр Якушев

    Александр Якушев Активный участник

    С нами с:
    13.08.2009
    Сообщения:
    77
    Симпатии:
    1
    Баллы:
    7
    Спасибо igorznag! Офигенная штука, похоже то, что нужно! Надо разбираться)
     
  4. Александр Якушев

    Александр Якушев Активный участник

    С нами с:
    13.08.2009
    Сообщения:
    77
    Симпатии:
    1
    Баллы:
    7
    Вот немного разобрался
    Код:
    (   
    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, только для пивота объекта?
     
  5. igorznag

    igorznag Знаток

    С нами с:
    23.04.2010
    Сообщения:
    1.256
    Симпатии:
    173
    Баллы:
    65
    Почему вы хотите эту функцию оптимизировать?
     
  6. Александр Якушев

    Александр Якушев Активный участник

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

    Александр Якушев Активный участник

    С нами с:
    13.08.2009
    Сообщения:
    77
    Симпатии:
    1
    Баллы:
    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 непонятным образом. Где подвох???
    Извините, ошибку понял, только вот как от этих скачков избавиться????
     
  8. Александр Якушев

    Александр Якушев Активный участник

    С нами с:
    13.08.2009
    Сообщения:
    77
    Симпатии:
    1
    Баллы:
    7
    Уфф, дошло. Как до утки на третьи сутки 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? Можно ли как-то повысить точность?
     

    Вложения:

Модераторы: Savin Denis

Поделиться этой страницей