пятница, 4 декабря 2015 г.

Настройка анимации ступеней эскалатора посредством maxscript

Имеем анимированную по сплайну ступеньку эскалатора. Задаем скорость движения ступеньки около 0.5 м/c.
Далее необходимо накопировать ступеньки по пути с заданным сдвигом:

------------------------------------------------------------
for i = 1 to 10 do
(
    asd = instance $
    moveKeys asd.pos.controller.percent.controller 20f
    select asd
    )
------------------------------------------------------------

Соответственно эта строчка регулирует количество копий(10 шт):

for i = 1 to 10 do

 А эта строка - сдвиг на 20 кадров:

moveKeys asd.pos.controller.percent.controller 20f

Величина 20f подбиралась опытным путем, таким образом, чтобы ступени были на максимально корректном расстоянии друг от друга. 
Можно и в другую сторону сдвигать: -20f



Тонкую настройку - подгонку ступеней можно провести небольшой реглировкой их скорости, т.е. углом наклона анимационной линии:
 Этой строчкой меняем угол наклона (работает только с выделенными ступенями):
-----------------------------------------------------------------------
for i in selection  do i.pos.controller.percent.controller.keys[2].value = i.pos.controller.percent.controller.keys[2].value - 0.001
------------------------------------------------------------------------
Смысл в том, что верхний ключ немного смещается вверх или вниз сразу для всех ступеней.
После, примерно, двадцатикратного применения этой строки (Ctrl+E) удалось точно подогнать ступени эскалатора.

Спасибо за внимание.

Поворот в локальных координатах вокруг выбранной оси.

for i in selection do i.transform = (rotateZmatrix (random 0 100))*i.transform

К примеру, таким образом, все эти окна  были открыты на угол от 0 до 100 градусов за время нажатия клавиш Ctrl+E.

пятница, 27 ноября 2015 г.

Один из способов анимации меха, например, гармошки.

 Есть некая заготовка мехов:
 Создаем FFD(Box) немного бОльших размеров, чем габариты заготовки. 
Create -> Space Warps -> Geometric/Deformable -> FFD(Box)
Подгонять надо именно по размерам FFD, а не подтягиванием вершин!
Далее создаем два хелпера для будущего управления мехами:
Выделяем нужные вершины на FFD и линкуем их к хелперу с помощью модификатора Linked XForm:
Также линкуем другие вершины(меняем выделение с помощью модификатора FFD Select ) к другому хелперу:




С помощью Bind to Space Warp привязываем нашу заготовку к FFD(Box):

Все готово. Это результат:
Таким же образом можно анимировать, например, сцепление поездов и т.п.:
Спасибо за внимание!

среда, 11 ноября 2015 г.

Простой и быстрый способ выравнивания чертежей с помощью Normal Align.

Это заимпортированные исходники:

 Выделяем ось и применяем экструд:
 Создаем вспомогательный объект, - box и, с помощью Normal Align, выравниваем по плоскости:


Осталось только привязать все чертежи к вспомогательному боксу и сбросить ему вращение на 0:



Наслаждаемся результатом и продожаем работать)

пятница, 6 ноября 2015 г.

Возможности float script


-----------------------------------------------------------------
delete objects
b = box height:0.5 length:5 width:5
for i = 0 to 30 do(
    for j = 0 to 30 do(
        instance b pos: [b.length*i, b.length*j, 0]
        )
    )
s = sphere radius:5 name:"ms" pos:[-10,-10,0] wirecolor:red

for i in $box* do(
        i.rotation.controller.X_Rotation.controller = float_script ()
        i.rotation.controller.X_Rotation.controller.script =     "dependsOn $ms.transform.controller\n" +
                                            "dependsOn $"+i.name+".transform.controller\n"+
                                            "p1 = $ms.transform.controller.Position\n" +
                                            "p2 = $"+i.name+".transform.controller.Position\n" +
                                            "if (length (p1 - p2)) < 50 then degtorad ((length (p1 - p2))*3.6) else degtorad 180"
    )           
for i in $box* do(
        i.visibility = bezier_float()
        i.visibility.controller = float_script ()
        i.visibility.controller.script =     "dependsOn $ms.transform.controller\n" +
                                            "dependsOn $"+i.name+".transform.controller\n"+
                                            "p1 = $ms.transform.controller.Position\n" +
                                            "p2 = $"+i.name+".transform.controller.Position\n" +
                                            "if (length (p1 - p2)) < 100 then ((length (p1 - p2))/100.0) else 1"
    )   
   
   
/*    --return
for i in $box* do(
    i.visibility.controller = bezier_float()
    i.rotation.controller.X_Rotation.controller = bezier_float()
    )        
-----------------------------------------------------------------

Если немного доработать код, то можно поменять ось вращения зависимых объектов следующим образом:
--------------------------------------------------------------------
for i in $box* do(
        i.rotation.controller = rotation_script ()
        i.rotation.controller.script =     "dependsOn $ms.transform.controller\n" +
                                            "dependsOn $"+i.name+".transform.controller\n"+
                                            "p1 = $ms.transform.controller.Position\n" +
                                            "p2 = $"+i.name+".transform.controller.Position\n" +
    "dirVec = normalize(p1-p2)\n"+
    "rotax = cross dirVec [0, 0, 1]\n"+
    "quat (720.0/(length (p1 - p2))) rotax"
    --"if (length (p1 - p2)) < 50 then (quat (720.0/(length (p1 - p2))/3.6) rotax) else (quat 0 0 0 1)"
    )    

--------------------------------------------------------------------




понедельник, 6 июля 2015 г.

Скрипт для выделения сплайнов нужной длины в shape.



(
LengthSeg1 = 8.0
LengthSeg2 = 4.7
LengthSeg3 = 3.4
thresh = 0.1 -- (LengthSeg1 +- thresh)

progressstart "Selection splines by length in shape..."   
   
    sp = if classOf $ == SplineShape then $ else undefined
    ns = numSplines sp
    arSegs = #()
    for i = 1 to ns do(
        ls = getSegLengths sp i
        lsc = ls.count
        ls = ls[lsc]
        if ls > (LengthSeg1-thresh) and ls < (LengthSeg1+thresh) do append arSegs i
        if ls > (LengthSeg2-thresh) and ls < (LengthSeg2+thresh) do append arSegs i
        if ls > (LengthSeg3-thresh) and ls < (LengthSeg3+thresh) do append arSegs i
        progressupdate (((i as float)/(ns as float))*100.0) 
        )
    setSplineSelection sp arSegs
       
progressend ()
)

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

среда, 3 июня 2015 г.

Скрипт по поиску пересечения объектов.

Писался на коленке, имеет очень большой потенциал для оптимизации и, соответственно, ускорения.


----------------------------------------------------------------------------------------------max2014
rollout ObjInt "Objects Intersection" width:400
(
   
    button create01 "Create" width:100 align:#center
    group "Parameters Objects"
    (
        label lblt1 "---------  Object 1  -------------------" align:#center
        spinner obj1x "X:" width:100    range:[-1000.0,1000.0, 8.0] type:#float align:#right across:4
        spinner obj1y "Y:" width:100  range:[-1000.0,1000.0, 0.0] type:#float align:#right
        spinner obj1z "Z:" width:100 range:[-1000.0,1000.0,4.0] type:#float   align:#right
        spinner obj1rad "Rad:" width:100 range:[-1000.0,1000.0,20.0] type:#float   align:#right
        label lblt2 "-----------  Object 2  ------------------" align:#center
        spinner obj2x "X:" width:100    range:[-1000.0,1000.0, 30.0] type:#float align:#right across:4
        spinner obj2y "Y:" width:100  range:[-1000.0,1000.0, 0.0] type:#float align:#right
        spinner obj2z "Z:" width:100 range:[-1000.0,1000.0,0.0] type:#float   align:#right
        spinner obj2rad "Rad:" width:100 range:[-1000.0,1000.0,10.0] type:#float   align:#right
    )       
--**********************
fn CreateSP PointA PointB theCol =
(
    local SP = SplineShape name: (uniquename "spline")
    addNewSpline SP
   
    addKnot SP 1 #corner #line PointA
    addKnot SP 1 #corner #line PointB
    SP.wirecolor = theCol   
    SP.render_displayRenderMesh = true
    SP.render_viewport_thickness = 0.2
    updateShape SP
    )
--**********************
fn createObjects =
(
    try(delete objects)catch()
    local obj1 = GeoSphere pos: [obj1x.value, obj1y.value, obj1z.value] radius: obj1rad.value name:(uniquename "sphere") segs:2,
            obj2 = GeoSphere pos: [obj2x.value, obj2y.value, obj2z.value] radius: obj2rad.value name:(uniquename "sphere") segs:2
    )
--************************   
fn PointInFace P1 P2 P3 P =
(
    local vec1 = P2 - P1
    local vec2 = P3 - P1
    local squareFace = (length(cross vec1 vec2))/2.0
-----
    local vec3 = P1 - P
    local vec4 = P2 - P
    local squareFace1 = (length(cross vec3 vec4))/2.0
-----
    local vec5 = P2 - P
    local vec6 = P3 - P
    local squareFace2 = (length(cross vec5 vec6))/2.0
----
    local vec7 = P3 - P
    local vec8 = P1 - P
    local squareFace3 = (length(cross vec7 vec8))/2.0
   
local sumArea = squareFace1 + squareFace2 + squareFace3
if sumArea <= 1.000001*squareFace then return(true) else return(false)
   
    )   
--************************   
fn findInterLinePlane planeP1 planeP2 planeP3 lineP1 lineP2 =
(
    local n = cross (planeP2-planeP1) (planeP3-planeP1)
    local normalPlane = n/(length n)

local V = planeP1 - lineP1,
        D = dot normalPlane V,
        W = lineP2 - lineP1,
        theE = dot normalPlane W
local thePos = if theE != 0 then lineP1 + W*D/theE else (lineP1 + lineP2)/2.0
   
local LengthPos = length (lineP1 - thePos) + length (lineP2 - thePos)
local lengthLine = 1.000001*length(lineP1 - lineP2)

if (LengthPos <= lengthLine) and (PointInFace planeP1 planeP2 planeP3 thePos == true) then return(thePos) else return(undefined)
    )
--************************   
--************************   
fn findInterFaces planeP1 planeP2 planeP3 lineP1 lineP2 =
(
   
    local n = cross (planeP2-planeP1) (planeP3-planeP1)
    local normalPlane = n/(length n)

local V = planeP1 - lineP1,
        D = dot normalPlane V,
        W = lineP2 - lineP1,
        theE = dot normalPlane W
local thePos = if theE != 0 then
(
    lineP1 + W*D/theE
    )     else (lineP1 + lineP2)/2.0
   
local LengthPos = length (lineP1 - thePos) + length (lineP2 - thePos)
local lengthLine = 1.000001*length(lineP1 - lineP2)

if (LengthPos <= lengthLine) and (PointInFace planeP1 planeP2 planeP3 thePos == true) then return(thePos) else return(undefined)
    )
--************************   
fn findTriagInter faceA faceB =
(
local A = faceA[1],
        B = faceA[2],
        C = faceA[3],
        M1 = faceB[1],
        M2 = faceB[2],
        M3 = faceB[3]
local theArr = #()
if findInterLinePlane A B C M1 M2 != undefined do append theArr (findInterLinePlane A B C M1 M2)
if findInterLinePlane A B C M1 M3 != undefined do append theArr (findInterLinePlane A B C M1 M3)
if findInterLinePlane A B C M2 M3 != undefined do append theArr (findInterLinePlane A B C M2 M3)
----
if findInterLinePlane M1 M2 M3 A B != undefined do append theArr (findInterLinePlane M1 M2 M3 A B)
if findInterLinePlane M1 M2 M3 A C != undefined do append theArr (findInterLinePlane M1 M2 M3 A C)
if findInterLinePlane M1 M2 M3 B C != undefined do append theArr (findInterLinePlane M1 M2 M3 B C)

if theArr.count == 2 do CreateSP theArr[1] theArr[2] red
    )
--************************
fn getObjInter object1 object2 =
(
progressstart "Iteration ..."

    convertToMesh object1
    convertToMesh object2
    local n = 0
    local numf = object1.numfaces
    for i in object1.faces do
    (
        local face1 = #()
        local index1 = (meshop.getVertsUsingFace object1 i.index) as array
        append face1 (getVert object1 index1[1])
        append face1 (getVert object1 index1[2])
        append face1 (getVert object1 index1[3])
        for j in object2.faces do
        (
            local face2 = #()
            local index2 = (meshop.getVertsUsingFace object2 j.index) as array
            append face2 (getVert object2 index2[1])
            append face2 (getVert object2 index2[2])
            append face2 (getVert object2 index2[3])
            findTriagInter face1 face2

            )
progressupdate (100.0*n/numf)
n+=1
        )
progressend ()   
    )   
--************************   
fn theAllFunc =
(
    createObjects()
    getObjInter $sphere001 $sphere002
    )
   
--************************
   
on create01 pressed do theAllFunc()   
--------------------------------   
on obj1x changed val do theAllFunc()
on obj1y changed val do theAllFunc()
on obj1z changed val do theAllFunc()
on obj1rad changed val do theAllFunc()
on obj2x changed val do theAllFunc()
on obj2y changed val do theAllFunc()
on obj2z changed val do theAllFunc()
on obj2rad changed val do theAllFunc()
)--end rollout
createDialog ObjInt  escapeEnable: true

--------------------------------------------------------------------------------------

Test face intesection.




----------------------------------------------------------------------------------
rollout testFaceInt "test Face Intersection" width:400
(
    button create01 "Create" width:100 align:#center
    group "Parameters T1"
    (
        label lblt0 "M1 [x1, y1, z1], M2 [x2, y2, z2], M3 [x3, y3, z3]" align:#center
        label lblt1 "-------------------------------------" align:#center
        spinner x1 "x1  " width:100    range:[-1000.0,1000.0,-5.9] type:#float align:#right across:3
        spinner y1 "y1" width:100  range:[-1000.0,1000.0,-8.5] type:#float align:#right
        spinner z1 "z1 " width:100 range:[-1000.0,1000.0,12.5] type:#float   align:#right
        label lblt2 "-------------------------------------" align:#center
        spinner x2 "x2  " width:100    range:[-1000.0,1000.0,-9.4] type:#float align:#right across:3
        spinner y2 "y2" width:100  range:[-1000.0,1000.0,-12.7] type:#float align:#right
        spinner z2 "z2 " width:100 range:[-1000.0,1000.0,3.8] type:#float   align:#right
        label lblt3 "-------------------------------------" align:#center
        spinner x3 "x3  " width:100    range:[-1000.0,1000.0,-4.3] type:#float align:#right across:3
        spinner y3 "y3" width:100  range:[-1000.0,1000.0,-11.2] type:#float align:#right
        spinner z3 "z3 " width:100 range:[-1000.0,1000.0,10.2] type:#float   align:#right
    )       
    group "Parameters T2"
    (
        label lblt4 "A [a1, b1, c1], B [a2, b2, c2], C [a3, b3, c3]" align:#center
        label lblt5 "-------------------------------------" align:#center
        spinner a1 "a1  " width:100    range:[-1000.0,1000.0,-10.3] type:#float align:#right across:3
        spinner b1 "b1" width:100  range:[-1000.0,1000.0,-3.8] type:#float align:#right
        spinner c1 "c1 " width:100 range:[-1000.0,1000.0,14.0] type:#float   align:#right
        label lblt6 "-------------------------------------" align:#center
        spinner a2 "a2  " width:100    range:[-1000.0,1000.0,-8.8] type:#float align:#right across:3
        spinner b2 "b2" width:100  range:[-1000.0,1000.0,-9.8] type:#float align:#right
        spinner c2 "c2 " width:100 range:[-1000.0,1000.0,7.7] type:#float   align:#right
        label lblt7 "-------------------------------------" align:#center
        spinner a3 "a3  " width:100    range:[-1000.0,1000.0,-2.2] type:#float align:#right across:3
        spinner b3 "b3" width:100  range:[-1000.0,1000.0,-5.5] type:#float align:#right
        spinner c3 "c3 " width:100 range:[-1000.0,1000.0,3.3] type:#float   align:#right
    )   
--**********************
fn createM =
(
    try(delete objects)catch()
    local vert_array = #(), face_array = #(),
            v1 = [x1.value, y1.value, z1.value],
            v2 = [x2.value, y2.value, z2.value],
            v3 = [x3.value, y3.value, z3.value]
    local v11 = [a1.value, b1.value, c1.value],
            v22 = [a2.value, b2.value, c2.value],
            v33 = [a3.value, b3.value, c3.value]   
    vert_array = #(v1,v2,v3,v11,v22,v33)
    face_array = #([1,2,3], [4,5,6])

    local m = mesh vertices:vert_array faces:face_array
    m.name = uniquename "triag"
    )
--*********************
fn createOneVector startV endV theCol =
(
    local theThicness = 0.1
    local theV = endV - startV
    local theDir = normalize theV
    local theH = length theV
    local cyl = cylinder pos:startV dir: theDir height: (0.9*theH) radius:(theThicness/5.0) name: (uniquename "Vector")
    local con = cone pos:(startV + 0.9*theV) dir: theDir height: (0.1*theH) radius1:(theThicness/2.0) name: (uniquename "VectorArrow")
    cyl.wirecolor = theCol
    con.wirecolor = theCol
    )
--*********************   
fn createOneText thePos theText theCol =
(
    local textSize = 0.6
    local theVS = getViewSize()
    local theRay = mapScreenToWorldRay (theVS/2.0)
    local t = text text:theText size:textSize pos: thePos dir: -theRay.dir
    t.wirecolor = theCol
    )
fn createText =
(
    createOneText [x1.value, y1.value, z1.value] "M1" red
    createOneText [x2.value, y2.value, z2.value] "M2" red
    createOneText [x3.value, y3.value, z3.value] "M3" red
   
    createOneText [a1.value, b1.value, c1.value] "A" red
    createOneText [a2.value, b2.value, c2.value] "B" red
    createOneText [a3.value, b3.value, c3.value] "C" red
    )
--************************   
fn PointInFace P1 P2 P3 P =
(
    local vec1 = P2 - P1
    local vec2 = P3 - P1
    local squareFace = (length(cross vec1 vec2))/2.0
-----
    local vec3 = P1 - P
    local vec4 = P2 - P
    local squareFace1 = (length(cross vec3 vec4))/2.0
-----
    local vec5 = P2 - P
    local vec6 = P3 - P
    local squareFace2 = (length(cross vec5 vec6))/2.0
----
    local vec7 = P3 - P
    local vec8 = P1 - P
    local squareFace3 = (length(cross vec7 vec8))/2.0
   
local sumArea = squareFace1 + squareFace2 + squareFace3
if sumArea <= 1.000001*squareFace then return(true) else return(false)
   
    )   
--************************   
fn createVectors =
(
local A = [a1.value, b1.value, c1.value],
        B = [a2.value, b2.value, c2.value],
        C = [a3.value, b3.value, c3.value],
        M1 = [x1.value, y1.value, z1.value],
        M2 = [x2.value, y2.value, z2.value],
        M3 = [x3.value, y3.value, z3.value]
   
local N1 = cross (B-A) (C-A),
        N2 = N1/(length N1),
        cent1 = (A+B+C)/3.0
local N3 = cross (M2-M1) (M3-M1),
        N4 = N3/(length N3),
        cent2 = (M1+M2+M3)/3.0
   
createOneVector cent1 (cent1 + N2) blue
createOneVector cent2 (cent2 + N4) blue
createOneVector [0,0,0] A green
createOneVector [0,0,0] B green
createOneVector [0,0,0] C green
createOneVector [0,0,0] M1 green
createOneVector [0,0,0] M2 green
createOneVector [0,0,0] M3 green
    )
--************************   
fn findInterLinePlane planeP1 planeP2 planeP3 lineP1 lineP2 =
(
    local n = cross (planeP2-planeP1) (planeP3-planeP1)
    local normalPlane = n/(length n)

local V = planeP1 - lineP1,
        D = dot normalPlane V,
        W = lineP2 - lineP1,
        theE = dot normalPlane W
local thePos = if theE != 0 then lineP1 + W*D/theE else (lineP1 + lineP2)/2.0
   
local LengthPos = length (lineP1 - thePos) + length (lineP2 - thePos)
local lengthLine = 1.000001*length(lineP1 - lineP2)

if (LengthPos <= lengthLine) and (PointInFace planeP1 planeP2 planeP3 thePos == true) then return(thePos) else return(undefined)
    )
--************************   
fn findTriagInter =
(
local A = [a1.value, b1.value, c1.value],
        B = [a2.value, b2.value, c2.value],
        C = [a3.value, b3.value, c3.value],
        M1 = [x1.value, y1.value, z1.value],
        M2 = [x2.value, y2.value, z2.value],
        M3 = [x3.value, y3.value, z3.value]
if findInterLinePlane A B C M1 M2 != undefined do point pos: (findInterLinePlane A B C M1 M2) size:1
if findInterLinePlane A B C M1 M3 != undefined do point pos: (findInterLinePlane A B C M1 M3) size:1
if findInterLinePlane A B C M2 M3 != undefined do point pos: (findInterLinePlane A B C M2 M3) size:1
----
if findInterLinePlane M1 M2 M3 A B != undefined do point pos: (findInterLinePlane M1 M2 M3 A B) size:1
if findInterLinePlane M1 M2 M3 A C != undefined do point pos: (findInterLinePlane M1 M2 M3 A C) size:1
if findInterLinePlane M1 M2 M3 B C != undefined do point pos: (findInterLinePlane M1 M2 M3 B C) size:1

local thePoints = $Point* as array
if thePoints.count == 2 do createOneVector thePoints[1].pos thePoints[2].pos red
    )
--************************   
fn theAllFunc =
(
    createM()
    createText()
    createVectors()
    findTriagInter()
    )
   
--************************
   
on create01 pressed do theAllFunc()   
--------------------------------   
on x1 changed val do theAllFunc()
on y1 changed val do theAllFunc()
on z1 changed val do theAllFunc()
on x2 changed val do theAllFunc()
on y2 changed val do theAllFunc()
on z2 changed val do theAllFunc()
on x3 changed val do theAllFunc()
on y3 changed val do theAllFunc()
on z3 changed val do theAllFunc()
---------------------------------
on a1 changed val do theAllFunc()
on b1 changed val do theAllFunc()
on c1 changed val do theAllFunc()
on a2 changed val do theAllFunc()
on b2 changed val do theAllFunc()
on c2 changed val do theAllFunc()
on a3 changed val do theAllFunc()   
on b3 changed val do theAllFunc()
on c3 changed val do theAllFunc()
)--end rollout
createDialog testFaceInt 

----------------------------------------------------------------------------------

пятница, 22 мая 2015 г.

Remove missing maps from scene


--------------------------------------------
fn clearMisMaps mm = (
          numSTM = getNumSubTexmaps  mm
          if numSTM != 0 do  (
           for i = 1 to numSTM do  (
               try(
                          theMAP = getSubTexmap  mm i
                           if theMAP != undefined do(
                                if classOf theMAP == Missing_TextureMap or theMAP.filename == undefined do setSubTexmap mm i undefined
                                clearMisMaps theMAP
                               )
                        )catch()
                                        )
                                    )
 )

fn theAllMat = (
  local allMat = #()
  join allMat (getclassinstances CoronaMtl)
  join allMat (getclassinstances VRayMtl)
  join allMat (getclassinstances Standardmaterial)
  return allMat
 )


for m in theAllMat() do clearMisMaps m
--------------------------------------------
Для выполения Ctrl+E

понедельник, 18 мая 2015 г.

Небольшая хитрость Attachment Constraint.


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


Казалось бы все просто - глазам применяем Attachment Constraint и прилинковываем их к голове, но они тогда улетают(выравниваются по произвонльному полигону):

Самый простой способ корректно их присоединить, это, наверное, сделать копию глаз до Attachment Constraint и после Attachment Constraint первой копии глаз приаттачить вторую:

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

 Полигон, по которому идет выравнивание показан красным:
 При этом важно, что бы этот полигон, не деформировался во время анимации. Выбрать его лучше заранее, нажав Set Position:

вторник, 12 мая 2015 г.

Моделирование перекрученных проводов.


Что-то вроде этого:


Есть заготовка,  в виде сплайна, применяем ей Loft:

 Get Shape указываем небольшой сплайн(см. картинку) и подбираем нужный параемтр Twist.
Далее назначаем EditPoly, на уровне Edge двойными щелчками выделяем грани по всей длине и нажимаем CreateShape:
Дальше все просто, - назначаем модификатор Noise и Sweep:
Да, при необходимости, можно добавить детализации. Вершинам задать тип Smooth и в интерполяции сплайна снять галку Optimize:


среда, 22 апреля 2015 г.

Простое выделение.

Этой простой строчкой можно оставлять выделенными нужное число объектов (в процентном отношении)

-----------------------------------
select (for i in selection where (random 0 100)<50 collect i)
-----------------------------------
полезно, если, к примеру, необходимо прорядить объекты и т.п.

понедельник, 20 апреля 2015 г.

Скрипт AttacheSplines

Скрипт AttacheSplines
Иногда необходимо приаттачить (сшить) сплайны или геометрию, например, - чертежи из автокада (там часто, помимо сплайнов попадается и геометрия), - можно воспользоваться этим скриптом:
----------------------------------------------------------
(
arrShape = for o in objects where superclassOf o == shape collect o
arrMesh = for o in objects where (classOf o == Editable_mesh or classOf o == Editable_poly) collect o

arrShapeC = arrShape.count
arrMeshC = arrMesh.count

convertToSplineShape arrShape[1]
progressstart "Attach shapes..."
for i = 2 to arrShapeC do
(
    convertToSplineShape arrShape[i]
    addAndWeld arrShape[1] arrShape[i] -1
   
    progressupdate (i as float /arrShapeC*100)
   
    gc()
    freescenebitmaps()
    clearUndoBuffer()    
    )
updateShape arrShape[1]
progressend ()

convertToMesh arrMesh[1]   
progressstart "Attach mesh..."
for i = 2 to arrMeshC do
(
    convertToMesh arrMesh[i]
    meshop.attach arrMesh[1] arrMesh[i]
    progressupdate (i as float /arrMeshC*100)
   
    gc()
    freescenebitmaps()
    clearUndoBuffer()    
    )
update arrMesh[1]
progressend ()
)

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



пятница, 10 апреля 2015 г.

Оптимизация геометрии для 3ds max из архикада или rhinoceros с помощью maxscript.



Рассмотрим пару скриптов для оптимизации геометрии.
1. Из архикада часто приходит геометрия в которой включены все ребра и не склеены вершины. Если в исходнике много объектов (несколько десятков тысяч), то это очень сильно тормозит работу во вьюпорте и увеличивает объем максовского файла.
Этот небольшой скрипт склеивает вершины и включает режим  autoEdge:

---------------------------------------------------------------------
(
local theObj = objects as array   
local theCountObj = theObj.count
   
progressstart "Editing Objects..."
    
            for i = 1 to theCountObj do
            (
               
            progressupdate (i as float /theCountObj *100)    
               
            if( isKindOf theObj[i] GeometryClass ) then -- weld only in geometry objects
                (
                    meshOp.weldVertsByThreshold theObj[i].mesh theObj[i].mesh.verts 0.0001
                    meshop.autoEdge theObj[i]   theObj[i].Edges  24
                    )

            )
progressend ()
)
--------------------------------------------------------------------

2. Похожие проблемы бывают и при импорте из rhinoceros.
 Этот скрипт конвертирует всю геометрию в EditMesh, склеивает вершины и "аттачит" по материалам (очень полезно, к примеру, когда рамы отдельными элементами из нескольких тысяч палочек и т.п.):

---------------------------------------------------------------------
(
theObj = geometry as array
theCountObj = theObj.count
   
progressstart "Convert to mesh..."
theP = Edit_Poly()   
for i = 1 to theCountObj do (
    progressupdate (i as float /theCountObj *100)
    --addmodifier theObj[i] theP
    --convertToMesh theObj[i]
    )
progressend ()
 progressstart "Welding..."   
   for i = 1 to theCountObj do
   (
   
   progressupdate (i as float /theCountObj *100) 
   
   if( isKindOf theObj[i] GeometryClass ) then -- weld only in geometry objects
    (
     meshOp.weldVertsByThreshold theObj[i].mesh theObj[i].mesh.verts 0.001
     --meshop.autoEdge theObj[i]   theObj[i].Edges  24
     )

   )
progressend ()
  
  
fn theAllMat =
(       
        local allMat = #()
        allMat = scenematerials
        for i in meditMaterials do appendIfUnique allMat i
        for i in objects do if i.material != undefined do appendIfUnique allMat i.material
        allMat
    )
fn getMeshObjByMat Mat =
(
    arrayObj = #()
    for i in geometry do
    (
        if i.material != undefined do
            if i.material == Mat do append arrayObj i
        )
    arrayObj
    )   
   
   
mainSel = geometry as array
theNumObj = mainSel.count
mainMat = theAllMat()
theNumMat = mainMat.count
progressstart "Attache by material..."
   
for i in mainMat do
(
    ObjByMat = getMeshObjByMat i
    theNum = ObjByMat.count
    for i = 2 to theNum do (
        meshop.attach ObjByMat[1] ObjByMat[i]
        progressupdate (i as float /theNum *100)
       
        --gc()
        --freescenebitmaps()
        --clearUndoBuffer()        
        )
    )
progressend ()    
)
-------------------------------------------------------

среда, 1 апреля 2015 г.

Моделирование дома по спутниковой карте и панораме.


сам дом


С помощью SAS.Планета определяем размер дома и делаем скриншот:




Выставляем правильный масштаб карте в сцене

поворачиваем- выравниваем для удобства моделирования

Обводим контуры
Высоту можно определить с помошью инструмента Perspective Match. Суть в том, чтобы построить модель по перспективе, пусть даже не в маштабе, но в нужных пропорциях. Имея размеры со спутниковой карты, можно подогнать модель по перспективе к размерам со спутника, тем самым, получаем масштабную модель. Одного вида может не хватить. Для лучшей точности желательно построить модели по нескольким перспективам.

первая перспектива

Кидаем перспетиву на бэкграунд и выставляем нужные параметры outsize
Чтобы можно было пользоваться камерой в режиме 2D Pan Zoom Mode надо поменять ее тип на Free
Добавьте подпись

Создаем бокс в нужных пропорциях



То же для другой перспективы
Осталось только подогнать  модель к размерам на спутниковой карте и заготовка нужной высоты  готова

Можно приступать к детализации:





Есть, правда, еще один способ - иногда можно найти серию дома, план и, соответственно, межэтажное расстояние!