Render.ru

Вопросы по Max Script (всего понемногу)

3DВитяй

Пользователь сайта
Рейтинг
2
#41
Господа, есть вопрос, который так или иначе мучает многих, при создании анимации. Допустим я создаю управляющий элемент - кнопку. При нажатии, заданные объекты располагаются в определенном месте пространства. С глобальными координатами все понятно. Вопрос такой - как задать им координаты и ориентацию относительно родительского объекта?
 

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

Активный участник
Рейтинг
7
#43
Здравствуйте!
Напишу тут, чтобы не флудить мелкими вопросами в темах.
Подскажите пожалуйста, можно ли ставить на паузу выполнение скрипта? Но не просто на паузу, в общем при переборе объектов в сцене надо к каждому объекту применить действия и подождать пока slider пробежит определенное количесво кадров и запишутся ключи анимации.

Как-то так:



Код:
(

---------fn
fn CurentFrames tempFrame obj1 =
(		
		
		global theObj = obj1
		global tempFrame2=tempFrame
		rollout CFrames "Frames"
		(
			timer tclock "Timer" interval:20
			label var01 ""

			on tclock tick do
				(
				var01.text = slidertime as string
					if slidertime >= tempFrame2 do
					(
					print slidertime
					stopAnimation()
					max time end
					max tool animmode
					convertToMesh theObj

					destroydialog CFrames
					)
				)
				
				
			
		)
		createdialog CFrames
)
-----------fn

						for i in objects do
						(
							local FR = 98f
							addModifier  i (edit_mesh())
							max time start
							max tool animmode
							playAnimation immediateReturn:true
							CurentFrames FR i
							)
	
							
							)
Для одного объекта прекрасно все работает. Если объектов больше одного - то полный треш. Пытался с разных сторон проблему решить, но не силен в максскрипте.

Пытался функцию sleep использовать, но вешает не только запись анимации и таймер, но и сам макс в том числе.
Через глобальную переменную и while - тоже самое.

Может быть вообще не стой стороны надо заходить?
Помогите плз разобраться.
 

igorznag

Мастер
Рейтинг
103
#44
Код:
global theObj_index, theObjs, obj_init=0
rollout CFrames "Frames" 
( 
timer tclock "Timer" interval:20 active:false
label var01 "" 
on CFrames open do
(
theObj_index=1; theObjs=objects as array
if(theObjs.count>0)then tclock.active=true
else destroydialog CFrames
)--on CFrames open do
on tclock tick do 
(
FR = 98f
if(obj_init==0)then
(
addModifier theObjs[theObj_index] (edit_mesh()) 
max time start 
max tool animmode 
playAnimation immediateReturn:true
obj_init=1
)--if(obj_init==0)then
else--if(obj_init==0)then
(
var01.text = theObjs[theObj_index].name;
var01.text +=" "+(slidertime as string)
if slidertime >= FR do 
( 
stopAnimation(); max time end 
max tool animmode; convertToMesh theObjs[theObj_index]
theObj_index+=1;obj_init=0;
if(theObj_index>theObjs.count)then destroyDialog CFrames
)--if slidertime >= FR do 
)--else--if(obj_init==0)then
)--on tclock tick do 
); createdialog CFrames
 

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

Активный участник
Рейтинг
7
#45
igorznag спасибо! Ты просто волшебник! работает! Продолжу написание с вашей помощью). Как закончу обязательно поделюсь.
 

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

Активный участник
Рейтинг
7
#46
Вроде оформился код, есть чем поделиться.
У скрипта довольно узкая специализация - преобразование людей анимы в эдит меш с поинткэшем для экономии ресурсов.
Всем спасибо за помощь, реально выручили.


Код:
---------fn
fn RecordKeys =
(
max time start
max tool animmode 	
playAnimation immediateReturn:true 

	rollout CFrames "Frames"
	(
	timer tclock "Timer" interval:20 
	label var01 ""

				on tclock tick do
				(
				var01.text = slidertime as string
				if slidertime >= (animationRange.end-20) do
								(
								stopAnimation()
								
								max tool animmode
								animationRange = interval animationRange.start (animationRange.end - 20)
								max time start
								destroydialog CFrames
								) 
							)--end tclock tick
						)--end rollout CFrames
						CreateDialog CFrames

					) --end fn
---------fn

rollout An "Anima"
( --start rollout 
	local  All_Anima = #()
	local theFolderPathPC

	--interfeis	
	group "Point Cache Options (SEl OBJ only):"
	(
			label lbl01 "   ---------    Custom Range    --------   "
			spinner thePC_Start "Start" range:[-10000,10000,0] fieldwidth:55 align:#right type:#integer across:2
			spinner thePC_End "End" range:[-10000,10000,100] fieldwidth:55 align:#right  type:#integer
			spinner rand_thePC_Start "Random" range:[0,10000,0] fieldwidth:55 align:#right type:#integer across:2
			spinner rand_thePC_End "Random" range:[0,10000,0] fieldwidth:55 align:#right  type:#integer		
			button EnableCustomRanges "Enable Custom Ranges" width:220
		
			spinner ShiftRange "Shift" range:[-10000,10000,0] fieldwidth:55 align:#right type:#integer across:2
			spinner randShift "Random" range:[0,10000,0] fieldwidth:55 align:#right  type:#integer
			button ShiftCustomRanges "Shift Custom Ranges" width:220
		
			label lbl02 "   ---------    Original Range    --------   "
			button EnableOriginalRanges "Enable Original Ranges" width:220

		)				

	group "Output Path:"
	(
		button BrowsePC "Browse" width:100  height:20 align:#left  across:2
		editText PathPC text:"PointCache path..." align:#left  readOnly:true 
		)	
		
		button AddEditMesh_Record "step 1: Add Edit Mesh and record keys" width:220  height:30 align:#center border:false 
		button SavePC1 "step 2: Save PoinCache local" width:220  height:30 align:#center border:false enabled:false
		button SavePC2 "step 3: Save PoinCache global" width:220  height:30 align:#center border:false enabled:false
		button DelStuff "step 4: Delete stuff" width:220  height:30 align:#center border:false enabled:false
		button VisEdges "step 5: All Edges True" width:220  height:30 align:#center border:false enabled:false
		progressbar DoIt_prog color:orange  height:5

		on BrowsePC pressed do
		(
			theFolderPathPC= getSavePath caption: "Pick folder" initialDir:"C:\\" 
			PathPC.text = theFolderPathPC as string
			)

		on AddEditMesh_Record pressed do
		(
				animationRange = interval animationRange.start (animationRange.end + 20)	
				SavePC1.enabled = true
			
				All_Anima = #()
				
			
				for i in objects do -- add anima objects to "all_anima"
				(
					if classOf i == AnimaObjectSubMesh do 
																(
																	append All_Anima i
																	i.name = uniquename "Actor_"
																)
					)--end add anima objects to "all_anima" 
				
				for i in All_Anima do  -- add edit_mesh
				(
					local count_AObj = All_Anima.count	
					local theProgressBarCount =1
					
					addModifier  i (edit_mesh())
					
					DoIt_prog.value = 100.*theProgressBarCount/count_AObj
					theProgressBarCount = theProgressBarCount + 1						
					)	--end add edit_mesh
				RecordKeys()					
				DoIt_prog.value = 0
					)--end AddEditMesh_Record pressed
			
		on SavePC1 pressed do
		(
			local count_AObj = All_Anima.count	
			local theProgressBarCount =1
			
			if theFolderPathPC != undefined then
				(
				for i in All_Anima do
										(
											addModifier i (Point_Cache ())
											
											local thePC =  i.modifiers["Point Cache"]
												
											try(deleteFile (theFolderPathPC  + "\\" + i.name + ".pc2"))catch()
												
											thePC.filename = theFolderPathPC  + "\\" + i.name + ".pc2"
													
											cacheOps.RecordCache thePC

											DoIt_prog.value = 100.*theProgressBarCount/count_AObj
											theProgressBarCount = theProgressBarCount + 1	
											)--end for i in All_Anima
				)else messageBox "Path is undefined!"
			
				SavePC2.enabled = true
				DoIt_prog.value = 0
				)--end SavePC1
			
		on SavePC2 pressed do
		(
			local count_AObj = All_Anima.count	
			local theProgressBarCount =1			
			
			if theFolderPathPC != undefined then
				(
				for i in All_Anima do
										(
											maxOps.CollapseNodeTo i 2 true
											addModifier i (Point_CacheSpacewarpModifier ())
											
											local thePC_WSM =   i.modifiers["Point Cache Binding"]
											
											try(deleteFile (theFolderPathPC  + "\\" + i.name + "_WSM" + ".pc2"))catch()
												
											thePC_WSM.filename = theFolderPathPC  + "\\" + i.name + "_WSM" + ".pc2"	
													
											cacheOps.RecordCache thePC_WSM
											
											DoIt_prog.value = 100.*theProgressBarCount/count_AObj
											theProgressBarCount = theProgressBarCount + 1	
											)--end for i in All_Anima
											
											
				)else messageBox "Path is undefined!"
			
				DelStuff.enabled = true	
				DoIt_prog.value = 0
				)--end SavePC2	
			
		on DelStuff pressed do
		(
			deleteKeys All_Anima #allKeys
				for i in All_Anima do
										(
											maxOps.CollapseNodeTo i 2 true
											)
			VisEdges.enabled = true
			)-- end on DelStuff pressed do
		
		on VisEdges pressed do
		(
			for i in All_Anima do try(i.allEdges = true)catch()
			)--end on VisEdges pressed do

		on EnableCustomRanges pressed do
		(
			for i in selection do
			(
				try(
							i.modifiers["Point Cache"].playbackType = 2
							i.modifiers["Point Cache"].playbackStart = thePC_Start.value + (random -rand_thePC_Start.value rand_thePC_Start.value)
							i.modifiers["Point Cache"].playbackEnd = thePC_End.value + (random -rand_thePC_End.value rand_thePC_End.value)
						)catch()
							
					try(
							i.modifiers["Point Cache Binding"].playbackType = 2
							i.modifiers["Point Cache Binding"].playbackStart = thePC_Start.value + (random -rand_thePC_Start.value rand_thePC_Start.value)
							i.modifiers["Point Cache Binding"].playbackEnd = thePC_End.value + (random -rand_thePC_End.value rand_thePC_End.value)
						)catch()
				)
			) -- end on EnableCustomRanges pressed do
			
		on ShiftCustomRanges pressed do
		(
			for i in selection do
			(
				try(
							i.modifiers["Point Cache"].playbackType = 2
					
							local thePB_Start = i.modifiers["Point Cache"].playbackStart
							local thePB_End = i.modifiers["Point Cache"].playbackEnd
							
							i.modifiers["Point Cache"].playbackStart = thePB_Start + ShiftRange.value + (random -randShift.value randShift.value)
							i.modifiers["Point Cache"].playbackEnd = thePB_End + ShiftRange.value + (random -randShift.value randShift.value)
						)catch()
							
					try(
							i.modifiers["Point Cache Binding"].playbackType = 2

							local thePB_Start = i.modifiers["Point Cache Binding"].playbackStart
							local thePB_End = i.modifiers["Point Cache Binding"].playbackEnd
						
							i.modifiers["Point Cache Binding"].playbackStart = thePB_Start + ShiftRange.value + (random -randShift.value randShift.value)
							i.modifiers["Point Cache Binding"].playbackEnd = thePB_End + ShiftRange.value + (random -randShift.value randShift.value)
						)catch()
				)
			) -- end on ShiftCustomRanges do
			
		on EnableOriginalRanges pressed do
		(
			for i in selection do
			(
				try(
							i.modifiers["Point Cache"].playbackType = 0
						)catch()
							
					try(
							i.modifiers["Point Cache Binding"].playbackType = 0
						)catch()
				)
			) -- end on EnableOriginalRanges pressed do	
)--end rollout



createDialog  An 250 445
 

Savin Denis

Модератор форума
Команда форума
Рейтинг
138
#48
Как альтернатива maxscript'a python не рассматривается
поскольку нет системной интеграции.
 

Доктор Дрэдд

Пользователь сайта
Рейтинг
2
#49
а есть возможность мерджить объекты в сцену по порядку, рендерить,удалять этот объект,ставить новый?
или хотя бы просто как замерджить объект в сцену
 
Рейтинг
31
#50
кстати, как оцениваете перспективы python - как альтернативу maxscript'a???
Вопрос поставлен не совсем корректно, если имеется ввиду разработка Blur Studio. В данном случае Питон - не альтернатива (в смысле "замена"), а некое расширение MaxScript. Причём, судя по описанию на сайте разработчиков, достаточно корявое (по крайней мере пока).

Далее, вопрос можно разделить на две составляющие: техническую и идеологическую.

С технической стороной всё достаточно ясно. Из плюсов имеем: (1) более продвинутый, по сравнению с MaxScript, язык программирования и (2) богатую питонью библиотеку. Из минусов: достаточно корявая интеграция с 3ds max, со многими нигде не документированными подводными камнями. Мне также не понравилась привязка к Python 2.x. Логичнее было бы новую разработку привязывать к более новой (и синтаксически несовместимой с 2.х) версии 3.х.

С идеологической стороной - больше вопросов, чем ответов. Вопрос первый: "а оно надо?" Очевидный ответ: надо, если кто-то об этом не только задумался, но и даже реализовал. А если, как говорил Чапаю Петька, "посмотреть в мировом масштабе"? Imho - не надо. Сейчас, практически, ни кто не знает одного языка программирования (MaxScript), а тогда не будут знать два языка. И что толку? Используют MaxScript - сотни, пишут на нём - десятки, а знают досконально - единицы. Это при том, что используют 3ds max многие тысячи людей.

Вопрос второй: а так ли нужны те плюсы, которые мы получаем от Питона в Максе? Лично для меня ответ не очевиден. Регулярные выражения, доступ к базам данных, доступ к интернет-ресурсам, доступ к ресурсам ОС, многопоточные вычисления... Это всё круто, но зачем это в Максе? Нет, я допускаю, что кому-то (одному) понадобится импортировать в Макс некие данные из БД, но в остальных 99.9% случаев это не нужно. То же относится и к "продвинутости" самого языка: для задач, выполняемых MaxScript, его синтаксических конструкций и библиотеки функций вполне достаточно.

Следующее соображение: есть люди, которым не нравится MaxScript и они бы не отказались от альтернативы. (Я сам не в восторге от него.) Но жопа уже случилась. И причин две: (1) недостаточно качественное проектирование самого 3ds max, как программного продукта, и (2) решение принять в качестве скриптового языка MaxScript, а не встроить в Макс уже существующий язык (Perl, JavaScript, Ruby или тот же Python, хотя последнего, кажется, тогда ещё не было) со специфическими "максовскими" библиотеками. Эти две проблемы надо было решать тогда, а сейчас мы имеем то, что имеем. И выбраться из этого положения без полной переработки 3ds max, практически, невозможно. (И я очень сомневаюсь, что Autodesk пойдёт на такое.) Поэтому костыли в виде Питона погоды не сделают.

Так что на мой взгляд, разработка интересна только с академической точки зрения. А практические перспективы - сомнительны.
 

Игорь70

Пользователь сайта
Рейтинг
2
#51
Я увлёкся MaxScript не так давно. Раньше писал на С++. Но разобраться с ним до мелочей жизни не хватит. Вот пишу я скрипт и произвожу булеву операцию. Вычитаемый объект исчезает, а оставшийся
объект теряет такие свойства как length, width. Теперь что изменять эти величины невозможно,
кроме как преобразования масштабированием? Но масштабирование (допустим полого ящика) увеличивает и толщину его стенок.Да и scale грубый метод, даже если я оперирую float. Есть ли у объекта какие ещё свойства для изменения размеров, а то я ничего не могу найти через инструкцию show.
 

igorznag

Мастер
Рейтинг
103
#52
произвожу булеву операцию
оставшийся объект теряет такие свойства как length, width
Есть ли у объекта какие ещё свойства для изменения размеров
У объекта boolean есть такие свойства. Пример:
Код:
try destroydialog test catch()
rollout test "Test"
(
    spinner sp_length "Length" type:#worldunits range:[0,1e9,0]
    on test open do
    (
        b=box();b.length=51;b.width=100;b.height=50
        s=sphere();s.radius=25;s.pos=[0,-25,0]
        b.name="box_igorznag";s.name="sphere_igorznag"
        bo=boolObj.createBooleanObject b
        boolObj.setOperandB bo s 4 1
        bo.box_igorznag.length.controller=bezier_float()
        sp_length.controller=bo.box_igorznag.length.controller
        select bo; completeRedraw();
    )--on test open
); createdialog test
 

CryopS

Активный участник
Рейтинг
9
#53
Здравствуйте. Подскажите как попроще сделать проверку и разделение элементов из одного массива по нескольким на основе каких либо условий, в данном случае по имени объекта? Ну или поправьте меня пжл, если я совсем неправильно это делаю, а то все мои познания в максскрипте до этого, да и в общем во всем связанном с программированием ограничивались простыми макросами в пару строк.

Вот такое пытаюсь использовать, но в итоге получаю многократное повторение одних и тех же элементов в полученных массивах. Так понимаю, что это из-за многократной проверки исходного массива с выделенными объектами, а другие способы пока у меня отказываются работать даже так.
Код:
        aSelection = selection as array
for i = 1 to aSelection.count do
            (
                if matchPattern aSelection[i].name pattern:"*1x*" == true then
                    append aSingle aSelection[i]
                else
                if matchPattern aSelection[i].name pattern:"*2x*" == true then
                    append aDouble aSelection[i]
                else
                if matchPattern aSelection[i].name pattern:"*3x*" == true then
                    append aTriple aSelection[i]
                else
                if matchPattern aSelection[i].name pattern:"*4x*" == true then
                    append aQuarter aSelection[i]
                else
                if matchPattern aSelection[i].name pattern:"*cx*" == true then
                    append aCorner aSelection[i]
 
Последнее редактирование:

igorznag

Мастер
Рейтинг
103
#54
Вот такое пытаюсь использовать, но в итоге получаю многократное повторение одних и тех же элементов в полученных массивах.
У меня работает нормально.
Как вы проверили, что элементы повторяются?
Выделенные объекты имеют уникальные названия?
 

CryopS

Активный участник
Рейтинг
9
#55
похоже, это моя ошибка, особенно, если у Вас оно работает как надо) похоже где то я случайно эту функцию в цикл пустил, но никак не пойму где, перепроверю. В крайнем случае, просто обрежу полученные массивы после определенного индекса и буду использовать как есть.
А проверял банально, через вызов полученных массивов, ровно пять раз и повторялись...

Дополнение:
Ну да... Так и оказалось, и сразу все упростилось, спасибо за помощь, буду пытаться дописать эту штуковину, но возможно, до очередной глупой ошибки)
 
Последнее редактирование:

CryopS

Активный участник
Рейтинг
9
#56
Снова приветствую, опять с проблемой
В общем пытаюсь написать функцию, которая должна выстраивать комбинации элементов (объектов) из заданного массива в порядке элементов этого массива и значение элементов, которого означает номер набора, содержащего элементы подходящего типа.
Каждая комбинация должна записываться в ключи анимации, чтобы потом можно было срендерить все сразу.
Сложность заключается в проверках какой элемента в массиве является угловым, после которого все последующие элементы поворачиваются на 90 градусов и выстраиваются уже вдоль оси y.
не знаю, насколько понятно я объяснил, чего добиваюсь
если в кратце переменная aCombIndexes - массив с массивами, в котором каждый содержит комбинацию, состоящую из набора порядковых номеров элементов.
aAllElem - главный массив, содержащий упорядоченные по типу наборы элементов
aCopyIndx - массив содержащий неиспользуемые в текущей комбинации элементы, которые удвигаются за пределы камеры
Проблема в том, что нужные координаты присваиваются только угловому элементу.
Код:
fn PositionInCombination aCombIndexes =
(
    if aCombIndexes.count > 1 then
    (
        animationRange = interval animationRange.start (aCombIndexes.count-1) --set Time Range
        animate on
        for i = 1 to aCombIndexes.count do --for every combinations do
        (
            at time i-1 --loop for every frame starting from 0
            (
                CompArrays aCombIndexes[i]
                for iId = 1 to aCopyIndx.count do
                (
                    for f in aAllElem[aCopyIndx[iId]] do
                    (
                        f.pos = [-1000,-1000,0]
                    )
                )
                --fndItm = findItem aCombIndexes[i] 5
                for iCmb = 1 to aCombIndexes[i].count do
                (
                    if aCombIndexes[i][iCmb] == 5 and iCmb == 1 then
                    (
                        for f in aAllElem[aCombIndexes[i][iCmb]] do
                        (
                            f.pos = [72.5,72.5,0]
                            break
                        )
                    )
                    else
                    (
                        if iCmb == 1 then
                        (  
                            for f in aAllElem[aCombIndexes[i][iCmb]] do
                            (
                                f.pos = [-128.0,72.5,0]
                            )
                        )
                        else
                        (
                            if aCombIndexes[i][iCmb] == 5 then
                            (
                                for f in aAllElem[aCombIndexes[i][iCmb]] do
                                (
                                    f.pos.x = ((aAllElem[aCombIndexes[i][iCmb-1]][1].pos.x)+(GetLinearDimensions f 1)+(random -0.3 0.5))
                                    f.pos.y = ((aAllElem[aCombIndexes[i][iCmb-1]][1].pos.y))
                                    f.pos.z = 0
                                )
                                for iCmb = iCmb+1 to aCombIndexes[i].count do
                                (
                                    for f in aAllElem[aCombIndexes[i][iCmb]] do
                                        (
                                            rotate f (angleAxis 90 z_axis)
                                            f.pos.x = ((aAllElem[aCombIndexes[i][iCmb-1]][1].pos.x))
                                            f.pos.y = ((aAllElem[aCombIndexes[i][iCmb-1]][1].pos.y)+(GetLinearDimensions f 2)+(random -0.3 0.5))
                                            f.pos.z = 0
                                        )
                                )
                            )
                        )
                    )
                )
            )
        )
    )
)
Ощущение, что я как то совсем не с той стороны подхожу к задаче.
 

igorznag

Мастер
Рейтинг
103
#57
не знаю, насколько понятно я объяснил, чего добиваюсь
А я знаю.
Проблема в том, что нужные координаты присваиваются только угловому элементу.
Что такой угловой элемент?
Ощущение, что я как то совсем не с той стороны подхожу к задаче.
Ощущение, что вы должны сначала описать общую задачу обычными словами.
 

CryopS

Активный участник
Рейтинг
9
#58
ну ок, попробую. Да все это элементы создания комбинаций для стенок. Есть 36 отдельных объектов в сцене, имеющих каждый уникальное имя, подразделяющихся на пять типов, 4 различающихся по ширине, плюс угловой тип, который служит для создания угловой стенки. Нужно с помощью данной функции разместить объекты, основываясь на координатах первого элемента комбинации и ширине следующего объекта слева, если присутствует угол развернуть все последующие объекты на 90 градусов и продолжить выставлять координаты уже по другой оси. Для каждой комбинации записать ключи положения объектов

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

Дополнение:
Походу я переусложнил, вероятно надо распотрошить эту функцию на пару макросов или даже простых скриптиков в пару строк, да провести всю операцию в полуавтоматическом режиме... правда там еще была вторая часть скрипта, не хуже этой, но пока что с ней все было гладко)
 
Последнее редактирование:

Penter

Пользователь сайта
Рейтинг
4
#59
Кто по массивам шпарит, подскажите раздел в Help-е или черкните как отсортировать массив из Point3 #([x,y,z],[x,y,z],[x,y,z],...) по x или по y или по z. Охота добавить эстетики. А то раскидывает, конечно, как попало:

Код:
--a1 Куб, b1 мелкая Mesh (гора, предположим)
a1=$[1]; b1=$[2]
aGab=(a1.max.x-a1.min.x)
pv_b1=for i=1 to b1.verts.count collect b1.verts[i].pos

xpv_b1=for i=1 to pv_b1.count collect ((pv_b1[i][1]/aGab) as integer)*aGab
ypv_b1=for i=1 to pv_b1.count collect ((pv_b1[i][2]/aGab) as integer)*aGab
zpv_b1=for i=1 to pv_b1.count collect ((pv_b1[i][3]/aGab) as integer)*aGab

npv_b1=for i=1 to b1.verts.count collect [(xpv_b1[i]),(ypv_b1[i]),(zpv_b1[i])]
pa2=makeUniqueArray npv_b1

clearselection(); hide b1

for i=1 to pa2.count do
(
    a2=copy a1 pos:(pa2[i]) parent:b1
    max views redraw
)
unhide b1; select b1
 

Вложения

Последнее редактирование:

Владислав Бодюл

Активный участник
Рейтинг
15
#60
Функцию qsort смотри в хелпе.

как отсортировать массив из Point3 #([x,y,z],[x,y,z],[x,y,z],...) по x или по y или по z
Код:
(
    fn sortPoint3ArrByAxis_fn v1 v2 axis: = -- axis: #x, #y, #z;
    (
        local v = case axis of
        (
            #x:(v1.x - v2.x)
            #y:(v1.y - v2.y)
            #z:(v1.z - v2.z)
        )
       
        case of
        (
            (v < 0):-1
            (v > 0):1
            default:0
        )
    )

    local p3Arr = for i = 1 to 10 collect
    (
        random [-100,-100,-100] [100,100,100]
    )
   
    qsort p3Arr sortPoint3ArrByAxis_fn axis:#x
   
    format "%\n" p3Arr
)
 
Сверху