понедельник, 28 марта 2016 г.

Выравнивание объектов друг относительно друга.

Очень редко, но требуется точно выровнять одинаковые объекты со сбитыми пивотами и с разной трансформацией.


Это можно сделать этим скриптом:

--------------------------------------------------------
(  
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
)

fn localMatrix p1 p2 p3 =
(
    v1 = p1 - p3
    v2 = p2 - p3
    e1 = normalize( cross 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
    )
   
   
fn AlignObjects mainObj tempObj numberFace =
(
--zapishem masshtab objectov
ScaleMainObj = mainObj.scale
ScaleTempObj = tempObj.scale
--vistavim 100pr masshtab
mainObj.scale = [1,1,1]
tempObj.scale = [1,1,1]   
   
   
VertUseFacesT = ((meshop.getVertsUsingFace tempObj numberFace) as array)
VertUseFacesM = ((meshop.getVertsUsingFace mainObj numberFace) as array)
----------------------------------------------   
NumV = tempObj.numverts
t1 = VertUseFacesT[1]
t2 = VertUseFacesT[2]
t3 = VertUseFacesT[3]
m1 = VertUseFacesM[1]
m2 = VertUseFacesM[2]
m3 = VertUseFacesM[3]
----------------------------------------------
theMt = localMatrix (getVert tempObj t1) (getVert tempObj t2) (getVert tempObj t3)
theMm = localMatrix (getVert mainObj m1) (getVert mainObj m2) (getVert mainObj m3)
AlignPivotTo tempObj theMt
tempObj.transform = theMm
tempObj.pivot = mainObj.pivot

--vistavim stariy masshtab
mainObj.scale = ScaleMainObj
tempObj.scale = ScaleTempObj
    )

   
fn roundNum A B  =     floor (10000.0*sqrt((A-B)^2))
   
   
fn compareObjByAreas MainObj CompareObj =
(
--zapishem masshtab objectov
ScaleMainObj = MainObj.scale
ScaleCompareObj = CompareObj.scale
--vistavim 100pr masshtab
MainObj.scale = [1,1,1]
CompareObj.scale = [1,1,1]   

tempMainObj = snapshot  MainObj  --zaskrinshotim objecty
tempCompObj = snapshot  CompareObj
   
numFacesM = tempMainObj.numFaces   
numFacesC = tempCompObj.numFaces

if numFacesM == numFacesC then
(
    local theSummAreas = 0.0
    for i = 1 to 10 do --viberem 10 proizvolnih fasov dlya sravneniya
    (
        randFace = random 1 numFacesM
        Sqare_mf = meshop.getFaceArea tempMainObj randFace
        Sqare_cf = meshop.getFaceArea tempCompObj randFace
        theSummAreas = theSummAreas + (Sqare_mf - Sqare_cf)
        )
    if theSummAreas <= 0.1 then CompareIndex = 1 else CompareIndex = 0
    ) else CompareIndex = 0

delete tempMainObj
delete tempCompObj

--vistavim stariy masshtab
MainObj.scale = ScaleMainObj
CompareObj.scale = ScaleCompareObj
   
return  CompareIndex   
    )   
   
   
   
   
if (compareObjByAreas $1 $2) == 1 do AlignObjects $1 $2 1   
   
    )
--------------------------------------------------------


Для выполнения необходимо базовый объект переименовать в "1", а совмещаемый в "2".

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


среда, 23 марта 2016 г.

Скрипты для упрощения работы с VrayProxy и CoronaProxy.

Скрипты умеют:
-  искать proxy по указанному пути;
- отображать список ненайденных proxy;
-  составлять список proxy в сцене;
- собирать proxyв указанную папку;
- менять способ отображения в сцене;
- перебивать пути (только для CoronaProxy).






Код для VrayProxy:

------------------------------------------------start
 --------------- start ProxySimplifier
--ScriptProxySimplifier_v3
--tested in Max 2013

-- optimized version 2013-05-23 (Black Sphinx)

rollout ProxySimplifier "ProxySimplifier"
( --start rollout ProxySimplifier

    local pathPrompt =  "Select path please..."
    local wrongProxyObjects = #()    -- array for collect proxy objects with broken links

    group "Finder:"
    (
        button ListMisProxy "List Missing Proxies" width:230  height:18 align:#right color:red across:2
        button ListProxy "List Proxies" width:230  height:18 align:#right color:red
        label lbl_01 "------------------------------------------------------------" align:#centere
        listbox mP "List proxies:"  height:10
        editText thePathText text:pathPrompt width:120 align:#left readOnly:true across:3
        button btn_browse "<---- Browse" width:100  height:18 align:#right
        button DoIt "Find Proxy..." width:120  height:18 align:#center
    )
    group "Collector:"
    (
        editText thePathText2 text:pathPrompt width:120 align:#center readOnly:true across: 4
        button btn_browse2 "<---- Browse" width:100  height:18 align:#center
        button DoIt2 "Collect Proxy..." width:120  height:18 align:#center color:red  
        Checkbox chBox3 "Selected only" width:60 align:#center checked:true
        )
    group "Display:"
    (
        button btn3 "Preview from file" width:100  height:18 align:#center across: 3
        button btn4 "Bounding box" width:100  height:18 align:#center
        Checkbox chBox2 "Selected only" width:60 align:#center checked:true
    )
  
  
    local theFolderPathCollector = undefined
    local ProxyPathes = #()
    local all_dir = #()
    local theFolderPath = undefined
    local theBooleanSwitch = true
    local wrongProxyObjects = #()
    local ProxyObjects = #()
  
  
    /*
    Return string array of root folder and all it's subfolders
    */
    fn getFolderPathes root =
    (
        dir_array = #(root)
        for d in dir_array do
            join dir_array (getDirectories (d+"/*"))
        dir_array
    )

    -- Display group section
  
    /*
    Function setProxyDisplay set display mode for proxies.
        sel - when true apply to selection. Otherwise to all proxies in scene
        disp_mode - display mode: 0 - boundary box, 1 - preview from file, 2 - point, 3 - preview from file (faces)
    */
    fn setProxyDisplay sel disp_mod = (
        if sel then
            objSet = selection
        else
            objSet = objects
      
        for i in objSet where classOf i == VrayProxy do (
                i.display = disp_mod
            )
    )
      
    on btn3 pressed do    (
        setProxyDisplay chBox2.state 1
    )

    on btn4 pressed do    (
        setProxyDisplay chBox2.state 0
    )  
    -- end Display section


    -- Collector group section
  
    on btn_browse2 pressed do (
        theFolderPathCollector = getSavePath  caption: "Pick folder" initialDir:"C:\\"
        if theFolderPathCollector != undefined then
            thePathText2.text = theFolderPathCollector as string
        else
            thePathText2.text = pathPrompt
    )      
      
    /*
    Copy all linked mesh files to folder theFolderPathCollector.
    After successful copying link in proxy updated by new file location.
    */
    on DoIt2 pressed do
    (
      
        local theAllGoodProxy = #()
      
        if chBox3.state == true then
        (
                for i in selection where classOf i == VRayProxy do if doesFileExist i.filename  do appendIfUnique theAllGoodProxy i
            )
        else (for i in objects where classOf i == VRayProxy do if doesFileExist i.filename  do appendIfUnique theAllGoodProxy i )
      
      
        local theP1 = undefined
        local theP2 = undefined
      
        if theFolderPathCollector != undefined then (
            for i in theAllGoodProxy do (
                theP1 = i.filename
                theP2 = theFolderPathCollector + "\\" + (filenameFromPath theP1)
                if (copyFile theP1 theP2) then
                    i.filename = theP2
                else
                    print ("don't copy - " + i.filename as string)
            )
        )
        else
            messageBox "Please specify path."
    )    -- end DoIt2 pressed

    --end Collector section
      
    -- Finder group section
          
    on btn_browse pressed do (
        theFolderPath = getSavePath  caption: "Pick folder" initialDir:"C:\\"
        if theFolderPath != undefined then
            thePathText.text = theFolderPath as string
        else
            thePathText.text = pathPrompt
    )          

    /*
    findMissingProxy
    Collect proxy objects with broken links (the mesh file not exists).
    Array misProxyPathes contains only broken paths and use for listbox "Wrong proxies".
    Array wrongProxyObjects use for further work.
    */
    fn findMissingProxy = (
        ProxyPathes = #()
        wrongProxyObjects = #()
      
        lbl_01.text = "Reading proxy..."
             for i in objects where classOf i == VrayProxy  do
             (    
                 if findItem ProxyPathes i.filename == 0 and doesFileExist i.filename == false do
                 (
                        append wrongProxyObjects i
                        append ProxyPathes  i.filename
                     )
                )
        --makeUniqueArray misProxyPathes
        --sort misProxyPathes
        mP.items = ProxyPathes
        lbl_01.text = "please use DoubleClick for getting proxy"
    )
  
    fn findProxy = (
        ProxyPathes = #()
        ProxyObjects = #()
      
        lbl_01.text = "Reading proxy..."
            local arObj = objects as array
            local arObjCount = arObj.count
            progressstart ("Reading proxy...")
             for i = 1 to arObjCount where classOf arObj[i] == VrayProxy  do
             (    
                 progressupdate (i*100.0/arObjCount)
                 if findItem ProxyPathes arObj[i].filename == 0 and doesFileExist arObj[i].filename == true do
                 (
                        append ProxyObjects arObj[i]
                        append ProxyPathes  arObj[i].filename
                     )
                )
      
        --makeUniqueArray ProxyPathes
        --sort ProxyPathes
        mP.items = ProxyPathes
        lbl_01.text = "please use DoubleClick for getting proxy"
        progressend ()
    )  
  
    on ListMisProxy pressed do findMissingProxy()
    on ListProxy pressed do findProxy()
    /*
    mP doubleClicked
    Select in scene proxy objects with mesh file name that double clicked in "Wrong proxies" listbox.
    */
    on mP doubleClicked itm do     (
                                                local theAllProxy = for i in objects where classOf i == VrayProxy collect i
                                                try( select (for i in theAllProxy where ProxyPathes[itm] == i.filename collect i) )catch()
                                                lbl_01.text = "please use DoubleClick for getting proxy"
                                            )  
  
    /*
    Subroutine finds missing mesh file for all proxies in array wrongProxyObjects in folder tree started from theFolderPath.
    */
on DoIt pressed do (
    if wrongProxyObjects.count != 0 do (

            if theFolderPath == undefined do (
            messageBox "Please pick path..."
            return 0
            )

            lbl_01.text = "Reading pathes..."
            all_dir = getFolderPathes theFolderPath

            local testFileName = undefined
            local theProxyName = undefined

            lbl_01.text = "Finding mesh files..."
            fileNotFound = true
          
                    for i in wrongProxyObjects do (
                    theProxyName = fileNameFromPath i.filename
                    fileNotFound = true
                            for p in all_dir while fileNotFound do (
                            testFileName = p + "\\" + theProxyName
                                    if doesFileExist testFileName do (
                                    i.filename = testFileName
                                    fileNotFound = false
                                    )
                            )
                    -- lbl_01.text = i.name -- comment for performanse reasons
                    )
            findMissingProxy() -- refresh array wrongProxyObjects and listbox "Wrong proxies"
            lbl_01.text = "please use DoubleClick for getting proxy"
    )
)
    --end finder
      
)--end rollout ProxySimplifier

escapeEnable = true

CreateDialog ProxySimplifier 500 370
------------- end ProxySimplifier
--By Alex Yakushev
------------------------------------------------end




Код для CoronaProxy:

----------------------------------------------start
 --------------- start ProxySimplifier
--ScriptProxySimplifier_v3
--tested in Max 2013

-- optimized version 2013-05-23 (Black Sphinx)

rollout ProxySimplifierC "ProxySimplifierCorona"
( --start rollout ProxySimplifier

    local pathPrompt =  "Select path please..."
    local wrongProxyObjects = #()    -- array for collect proxy objects with broken links

    group "Finder:"
    (
        editText thePathText text:pathPrompt width:208 align:#left across:3
        button btn_browse "<---- Browse" width:100  height:18 align:#right
        button findMisProxy "Find Missing Proxies..." width:150  height:18 align:#right color:red
        listbox mP "Wrong proxies:"  height:10
        label lbl_01 "------------------------------------------------------------" align:#center
        button DoIt "Find Proxy..." width:150  height:18 align:#center
    )
    group "Collector:"
    (
        editText thePathText2 text:pathPrompt width:120 align:#center  across: 4
        button btn_browse2 "<---- Browse" width:100  height:18 align:#center
        button DoIt2 "Collect Proxy..." width:100  height:18 align:#center
        button DoIt3 "Change Pathes..." width:100  height:18 align:#center  
        )
      
      
    --group "Display:"
    --(
    --    button btn3 "Preview from file" width:100  height:18 align:#center across: 2
    --    button btn4 "Bounding box" width:100  height:18 align:#center
    --)
  
  
    local theFolderPathCollector = undefined
    local misProxyPathes = #()
    local all_dir = #()
    local theFolderPath = undefined
    local theBooleanSwitch = true
    local wrongProxyObjects = #()
  
  
    /*
    Return string array of root folder and all it's subfolders
    */
    fn getFolderPathes root =
    (
        dir_array = #(root)
        for d in dir_array do
            join dir_array (getDirectories (d+"/*"))
        dir_array
    )

    -- Display group section
      
    --on btn3 pressed do    for i in selection where classOf i == CoronaProxy do i.previzType = 3
    --on btn4 pressed do    for i in selection where classOf i == CoronaProxy do i.previzType = 0
    -- end Display section


    -- Collector group section
  
    on btn_browse2 pressed do
        (
            if pathPrompt == "Select path please..." then
            (
                theFolderPathCollector = getSavePath  caption: "Pick folder" initialDir:"C:\\"
                if theFolderPathCollector != undefined do
                    (
                    thePathText2.text = theFolderPathCollector as string
                    pathPrompt = theFolderPathCollector as string
                        )
                )else
                (
                    theFolderPathCollector = getSavePath  caption: "Pick folder" initialDir:pathPrompt
                    if theFolderPathCollector != undefined do
                        (
                        thePathText2.text = theFolderPathCollector as string
                        pathPrompt = theFolderPathCollector as string
                            )
                    )
            )  
      
    /*
    Copy all linked mesh files to folder theFolderPathCollector.
    After successful copying link in proxy updated by new file location.
    */
    on DoIt3 pressed do
    (
        if theFolderPathCollector != undefined do
        (
          
            for i in (getClassInstances CoronaProxy) do
                    (
                        local theP1 = i.filename
                        i.filename = (theFolderPathCollector + "\\" + (filenameFromPath theP1))
                        )          
            )
        )
  
    on DoIt2 pressed do (
        local theAllGoodProxy = #()

        for i in objects where classOf i == CoronaProxy do (
            if doesFileExist i.filename  do appendIfUnique theAllGoodProxy i
        )
      
        local theP1 = undefined
        local theP2 = undefined
      
        if theFolderPathCollector != undefined then (
            for i in theAllGoodProxy do (
                local theP1 = i.filename
                local theP2 = theFolderPathCollector + "\\" + (filenameFromPath theP1)
                if (copyFile theP1 theP2) then
                    i.filename = theP2
                else
                    print ("don't copy - " + i.filename as string)
            )
        )
        else
            messageBox "Please specify path."
    )    -- end DoIt2 pressed

    --end Collector section
      
    -- Finder group section
          
                  
    on btn_browse pressed do
        (
            if pathPrompt == "Select path please..." then
            (
                theFolderPath = getSavePath  caption: "Pick folder" initialDir:"C:\\"
                if theFolderPath != undefined do
                    (
                    thePathText.text = theFolderPath as string
                    pathPrompt = theFolderPath as string
                        )
                )else
                (
                    theFolderPath = getSavePath  caption: "Pick folder" initialDir:pathPrompt
                    if theFolderPath != undefined do
                        (
                        thePathText.text = theFolderPath as string
                        pathPrompt = theFolderPath as string
                            )
                    )
            )      
                  

    /*
    findMissingProxy
    Collect proxy objects with broken links (the mesh file not exists).
    Array misProxyPathes contains only broken paths and use for listbox "Wrong proxies".
    Array wrongProxyObjects use for further work.
    */
    fn findMissingProxy = (
        misProxyPathes = #()
        wrongProxyObjects = #()
      
        lbl_01.text = "Reading proxy..."
             for i in objects where classOf i == CoronaProxy  do
             (    
                 if findItem misProxyPathes i.filename == 0 and doesFileExist i.filename == false do
                 (
                        append wrongProxyObjects i
                        append misProxyPathes  i.filename
                     )
                )
        makeUniqueArray misProxyPathes
        sort misProxyPathes
        mP.items = misProxyPathes
        lbl_01.text = "please use DoubleClick for getting proxy"
    )
  
    on findMisProxy pressed do (
        findMissingProxy()
    )
  
    /*
    mP doubleClicked
    Select in scene proxy objects with mesh file name that double clicked in "Wrong proxies" listbox.
    */
    on mP doubleClicked itm do     (
      
        if misProxyPathes.count == 0 do
            return 0
      
        the_obj = #()
        -- print misProxyPathes[itm] as string -- comment for performanse reasons
        for i in wrongProxyObjects do (
            if misProxyPathes[itm] == i.filename do
                append the_obj i
            -- lbl_01.text = i.name -- comment for performanse reasons
        )
        select the_obj
        lbl_01.text = "please use DoubleClick for getting proxy"
    )  
  
    /*
    Subroutine finds missing mesh file for all proxies in array wrongProxyObjects in folder tree started from theFolderPath.
    */
on DoIt pressed do (
    if wrongProxyObjects.count != 0 do (

            if theFolderPath == undefined do (
            messageBox "Please pick path..."
            return 0
            )

            lbl_01.text = "Reading pathes..."
            all_dir = getFolderPathes theFolderPath

            local testFileName = undefined
            local theProxyName = undefined

            lbl_01.text = "Finding mesh files..."
            fileNotFound = true
          
                    for i in wrongProxyObjects do (
                    theProxyName = fileNameFromPath i.filename
                    fileNotFound = true
                            for p in all_dir while fileNotFound do (
                            testFileName = p + "\\" + theProxyName
                                    if doesFileExist testFileName do (
                                    i.filename = testFileName
                                    fileNotFound = false
                                    )
                            )
                    -- lbl_01.text = i.name -- comment for performanse reasons
                    )
            findMissingProxy() -- refresh array wrongProxyObjects and listbox "Wrong proxies"
            lbl_01.text = "please use DoubleClick for getting proxy"
    )
)
    --end finder
      
)--end rollout ProxySimplifier

escapeEnable = true

CreateDialog ProxySimplifierC width:500
------------- end ProxySimplifier
--By Alex Yakushev
----------------------------------------------end





вторник, 22 марта 2016 г.

Текстурирование плоскостей (например жалюзи в большом жилом здании). Texturing blinds in the building.

 Есть заготовка для жалюзи в виде цельной геометрии:

 Разбиваем все на элементы:







Затем, если необходимо, выравниваем пивоты и масштабируем в произвольном порядке:

for i in selection do (i.pivot = i.center; i.pivot.z = i.max.z)
for i in selection do scale i [1,1,random 0.25 1]





 Выравниваем UVW модификатор по нормали:
Источник здесь:
How do I align the UVW_Modifier's Gizmo to a selected face?

Это выжимка из источника:
 --------------------------------------------------start
for i in selection do(
    local theMod = uvwmap()
    theMod.maptype = 0
    addModifier i theMod
)

fn alignUVGizmo theObj =(
faceNormal = getFaceNormal theObj 1
rightVector = normalize (cross [0,0,1] faceNormal)
upVector = normalize ( cross rightVector faceNormal )

theObj.modifiers[1].gizmo.transform = matrix3 rightVector upVector faceNormal [0,0,0]
)

for i in selection do alignUVGizmo i
--------------------------------------------------end
Это результат, на примере одной плоскости:

Осталось выровнять UVW по вершинам.
Для этого можно воспользоваться готовой функцией:

HOW TO ... FIT THE UVW MAPPING GIZMO
Выполняем ее:
for i in selection do UVWMapFit i  i.modifiers[1] useSel:#none





Это результат:


То же можно было бы применить и для штор, но функция подгонки текстурных координат дает немного некорректный результат:


Можно обойтись и без нее. Вот финальный код, в котором просто нажимается кнопка "Fit" для каждого объекта (в нашем случае этого более чем достаточно):


--------------------------start
for i in selection do(
    local theMod = uvwmap()
    theMod.maptype = 0
    addModifier i theMod
)

fn alignUVGizmo theObj =(
faceNormal = getFaceNormal theObj 1
rightVector = normalize (cross [0,0,-1] faceNormal)
upVector = normalize ( cross rightVector faceNormal )
theObj.modifiers[1].gizmo.transform = matrix3 rightVector upVector faceNormal [0,0,0]
)
for i in selection do alignUVGizmo i

max modify mode
arrPlane = selection as array
for i in arrPlane do (
    select i
    h = windows.getChildHWND #max "Fit"
    hc=windows.getChildrenHwnd h[2]
    UIAccessor.PressButton hc[54][1]  --button  "Fit"  
    )
--------------------------end


Работает такой способ, конечно дольше и для нескольких тысяч объектов может занять приличное время.
Параметром 1 или -1 в строке "rightVector = normalize (cross [0,0,-1] faceNormal)" можно менять направление по z.