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

Работа с VrayProxy.

Тема в разделе "MAXScript", создана пользователем Александр Якушев, 21 май 2013.

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

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

    С нами с:
    13.08.2009
    Сообщения:
    77
    Симпатии:
    1
    Баллы:
    7
    Скрипт должен уметь находить, коллектить и переключать врэй прокси.
    Потестируйте, пожалуйста. Может быть поможете улучшить.

    Код:
    (--------------- start ProxySimplifier
    --ScriptProxySimplifier_v1
    --tested in Max 2013
    rollout ProxySimplifier "ProxySimplifier"
    ( --start rollout ProxySimplifier
    group "Finder:"
    	(
    	editText thePathText text:"Path is undefined" width:208 align:#left readOnly:true 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:"Path is undefined" width:120 align:#center readOnly:true across: 4
    	button btn_browse2 "<---- Browse" width:100  height:18 align:#center 
    	Checkbox chBox_update "Relink" width:60 align:#center checked:true
    	button DoIt2 "Collect Proxy..." width:120  height:18 align:#center color:red	
    	)
    group "Switcher:"
    	(
    		button btn3 "On" width:100  height:18 align:#center across: 3
    		button btn4 "Off" width:100  height:18 align:#center
    		Checkbox chBox2 "Selected only" width:60 align:#center checked:true
    		)
    
    local theFolderPathCollector = undefined
    local misProxyPathes = #()
    local all_dir = #()
    local theFolderPath = undefined
    local theBooleanSwitch = true
    	
    	
    --fn
    fn exist_f the_path = try((getFiles the_path).count == 1)catch(undefined)
    
    fn getFolderPathes root = 
    		(	
    			local dir_array = GetDirectories (root+"*")
    			join all_dir dir_array
    			
    			if dir_array.count != 0 do
    			(
    				for the_path in dir_array do
    					(
    						join dir_array (GetDirectories the_path)
    						getFolderPathes the_path
    						)
    				)
    			return all_dir
    			)	
    			
    fn KillMisProxies theProxy	=
    (
    	local	theProxyPath = try(theProxy.filename)catch(undefined)
    	if theProxyPath != undefined and exist_f theProxyPath == false do 
    	(
    		local theProxyName = fileNameFromPath theProxyPath
    		for folder in all_dir do
    		(
    			local theFiles = getFiles (folder + "*")
    			for file in theFiles do if (fileNameFromPath file) == theProxyName do theProxy.filename = file
    			)
    		)		
    	)
    --fn
    --Switcher
    on btn3 pressed do	
    (
    	if chBox2.state == true then for i in selected where classOf i == VrayProxy do (i.display = 1) else for i in objects where classOf i == VrayProxy do (i.display = 1)
    	)
    on btn4 pressed do	
    (
    	if chBox2.state == true then for i in selected where classOf i == VrayProxy do (i.display = 0) else for i in objects where classOf i == VrayProxy do (i.display = 0)
    	)	
    --Switcher	
    	
    --collector
    on btn_browse2 pressed do
    	(
    		theFolderPathCollector= getSavePath  caption: "Pick folder" initialDir:"C:\\"
    		thePathText2.text = theFolderPathCollector as string
    		)		
    	
    on DoIt2 pressed do
    	(--start DoIt pressed
    			local theAllGoodProxy = #()
    
    			for i in objects do if classOf i == VRayProxy do
    			(
    				if exist_f i.filename == true do append theAllGoodProxy i 
    				)
    			
    			if theFolderPathCollector != undefined then
    			(
    				for i in theAllGoodProxy do
    				(
    					local theP1 = i.filename
    					local theP2 =theFolderPathCollector + "\\" + (filenameFromPath theP1)
    					try(copyFile theP1 theP2) catch(print ("don't copy - " + i.filename as string) )
    					if chBox_update.state == true do try(i.filename = theP2)catch()
    					)
    				)else messageBox "Please specify path."
    		)--end DoIt pressed
    --end collector	
    	
    on btn_browse pressed do
    	(
    		theFolderPath = getSavePath  caption: "Pick folder" initialDir:"C:/"
    		thePathText.text = theFolderPath as string
    		)			
    
    on findMisProxy pressed do
    (
    	misProxyPathes = #()
    	
    	lbl_01.text = "Reading proxy..."
    	for i in objects do if classOf i == VRayProxy do
    	(
    		if exist_f i.filename == false do	append misProxyPathes i.filename
    		try(lbl_01.text = i.name)catch()	
    		)
    	mP.items = misProxyPathes
    	lbl_01.text = "please use DoubleClick for getting proxy"
    	)
    	
    on mP doubleClicked itm do	
    (
    	local the_obj = #(), the_array = #()
    	print misProxyPathes[itm] as string
    	for i in objects do if classOf i == VRayProxy do
    	(
    		if exist_f i.filename == false and misProxyPathes[itm] == i.filename do append the_obj i
    		try(lbl_01.text = i.name)catch()	
    		)
    	select the_obj
    	lbl_01.text = "please use DoubleClick for getting proxy"
    	)	
    	
    on DoIt pressed do
    (
    	all_dir = #()
    	if theFolderPath != undefined then
    	(
    			lbl_01.text = "Reading pathes..."
    			getFolderPathes theFolderPath
    			for i in objects do
    				(
    					KillMisProxies i
    					try(lbl_01.text = i.name)catch()
    					)
    			lbl_01.text = "please use DoubleClick for getting proxy"
    		)
    		else messageBox "Please pick path..."
    	)
    	
    )--end rollout ProxySimplifier
    CreateDialog ProxySimplifier 500 350
    )------------- end ProxySimplifier
    
     
  2. Александр Якушев

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

    С нами с:
    13.08.2009
    Сообщения:
    77
    Симпатии:
    1
    Баллы:
    7
    Нечто подобное есть и для текстур. Столкнулся с такой проблемой - немного долго производит перебор материалов или объектов(особенно в больших проектах). Возможно ли как-то ускорить этот процесс? И возможно ли убрать "зависание" 3d макса во время поиска или перебора?
     
  3. Александр Якушев

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

    С нами с:
    13.08.2009
    Сообщения:
    77
    Симпатии:
    1
    Баллы:
    7
    Немного поменял функцию получения массива путей к папкам по указанному пути:
    Код:
    fn getFolderPathes root = 
    (
    	local dir_array = GetDirectories (root+"*")
    	if dir_array.count != 0 do
    	(
    		for i in dir_array do
    		(
    			append all_dir i
    			getFolderPathes i
    			)
    		)
    	return all_dir
    	)
    
    Не подскажете, может быть можно как-то ускорить процесс сканирования и получения массива папок?
     
  4. Александр Якушев

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

    С нами с:
    13.08.2009
    Сообщения:
    77
    Симпатии:
    1
    Баллы:
    7
    http://files.mail.ru/0A7F1D559CDC4147A77BF130348A940E - много ошибок нашел, поправил, здесь последняя тестовая, вроде рабочая, версия.
    Помогите, пожалуйста, ускорить перебор и замену путей в блоке:
    Код:
    on DoIt pressed do
    (
    	all_dir = #()
    	if theFolderPath != undefined then
    	(
    			lbl_01.text = "Reading pathes..."
    			getFolderPathes theFolderPath
    			for i in objects do
    			(
    				if classOf i == VrayProxy do
    				(
    					if i.filename != undefined and i.filename != getFiles (i.filename) do 
    					(
    						local theProxyName = fileNameFromPath i.filename
    						for p in all_dir do
    						(
    							local theFiles = getFiles (p + "*")
    							for f in theFiles do 
    							(
    								if theProxyName == (fileNameFromPath f) do i.filename = f
    								) 
    							)
    						)		
    						
    					try(lbl_01.text = i.name)catch()
    					)
    				)
    			lbl_01.text = "please use DoubleClick for getting proxy"
    		)
    		else messageBox "Please pick path..."
    	)
    
    Уж больно долго, особенно, если в сцене несколько тысяч проксей. И еще, после N-го объекта макс виснет и перестает отображать текст
    Код:
     try(lbl_01.text = i.name)catch() 
    , как можно это побороть без использования прогресс бара?
     
  5. Александр Якушев

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

    С нами с:
    13.08.2009
    Сообщения:
    77
    Симпатии:
    1
    Баллы:
    7
  6. Black Sphinx

    Black Sphinx Знаток

    С нами с:
    05.09.2003
    Сообщения:
    234
    Симпатии:
    1
    Баллы:
    29
    Александр, я сделал кое-какую оптимизацию твоего скрипта (версия из поста #4). Результат можно забрать здесь. Вроде стало работать немного побыстрее. К сожалению у меня сцены с "несколько тысяч проксей", а делать специально - лениво. Так что протестируй по скорости и отпишись по результатам - мне самому интересно.

    Мои комментарии на английском во избежание глюков. Английский наверное плохой, но транслит я вообще не перевариваю :confused:

    Несколько попутных замечаний по скрипту.

    1. Я бы ещё поработал над общей логикой. Некоторые вещи не очевидны. Всё становится понятным только после анализа кода, а это неправильно.

    2. Не надо без особой нужды использовать try...catch. Это дорогая конструкция в плане производительности.

    3. При анализе программы мне очень не хватало комментариев. Комментарии - это благо.
     
  7. Александр Якушев

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

    С нами с:
    13.08.2009
    Сообщения:
    77
    Симпатии:
    1
    Баллы:
    7
    Black Sphinx спасибо!
    Не ожидал такой прыти, но реальное ускорение в 10-ки раз!!! Старая версия вешает макс, примерно, на 15-20 мин. Твоя оптимизированная - за минуту! Поиск проблемных прокси тоже ускорился, стал, считай, мгновенным, даже в тяжелых проектах.
    Спасибо за советы!
     
  8. Black Sphinx

    Black Sphinx Знаток

    С нами с:
    05.09.2003
    Сообщения:
    234
    Симпатии:
    1
    Баллы:
    29
    Нашёл ещё одну оптимизацию:
    Код:
    	/*
    	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"
    		)
    	)
    
    В предыдущей версии просматривался весь список папок в поисках меш-файла для прокси и в прокси подставлялся последний найденный.
    Здесь поиск идёт только до первого найденного файла.

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

    Можно сделать ещё одну оптимизацию, при условии, что дерево папок для поиска меш-файлов не изменяется в течение рабочей сессии 3ds max. (А дерево папок может измениться вследствие внешних, по отношению к Максу, причин.) Поскольку массив all_dir у тебя объявлен глобальным, то он существует от первого вызова этого скрипта до выхода из Макса. Можно его не обновлять каждый раз при нажатии на кнопку "Find Proxy", а использовать существующий. Понятно, что при изменении корня дерева папок, массив придётся сбросить и перечитать информацию с диска заново.

    Есть в этом скрипте одна пакость, которую, видимо, просто побороть не удастся. Если в качестве корня для Finder'а указать, например, "C:\", то Макс виснет наглухо. Похоже, что скрипт при заполнении массива all_dir полностью расходует всю доступную ему память, после чего Макс виснет.
     
  9. Александр Якушев

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

    С нами с:
    13.08.2009
    Сообщения:
    77
    Симпатии:
    1
    Баллы:
    7
    Да тоже замечал нечто подобное. Кстати, не знаете как можно эту самую память увеличить?

    Спасибо за советы. Сейчас немного занят, но обязательно постараюсь доделать и отписаться. К тому же тут друзья посоветовали бесплатный скрипт relink bitmaps - он оказывается и прокси умеет находить. Очень шустрый, как говорится лучшее враг хорошего). Дело только за коллектором прокси, но это уже можно архивом создавать, потом поиском по типу выбирать.

    Есть еще одна идея оптимизации - использовать collect для выборки проблемных проксей и потом работать ТОЛЬКО с ними. Т.е. избавится от перебора ВСЕХ объектов и проверки classOf i == VrayProxy. Но это тоже попозже, сейчас по работе загрузили.

    Может быть потом нечто подобное и для поинт кэшей реализовать и прочего)
     
  10. Black Sphinx

    Black Sphinx Знаток

    С нами с:
    05.09.2003
    Сообщения:
    234
    Симпатии:
    1
    Баллы:
    29
    Почитай в справке по МаксСкрипту раздел Memory Allocation and Garbage Collection.

    Есть и встроенная фича. Asset Tracking называется (Application Menu > References > Asset Tracking).

    Я собственно это и сделал, если ты анализировал код скрипта после оптимизации. Только без применения collect, поскольку в этом же цикле делается ещё одно действие.
     
  11. Александр Якушев

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

    С нами с:
    13.08.2009
    Сообщения:
    77
    Симпатии:
    1
    Баллы:
    7
    Код только смотрел, но не анализировал) Может быть ошибаюсь, но хочу попробовать использовать преимущественно collect. В начале коллектом создать массив данных, убрать все лишнее и только потом работать без лишних действий. Опят же повторюсь, код еще не анализировал, может быть ваша оптимизация лучшая. Тот же релинк битмапс работает на тех же проектах все-таки быстрее, есть куда стремиться) Думаю еще таймстампом время выполнения сравнивать. Потом буду анализировать подробнее и отпишусь.

    Спасибо, но встроенную фичу тоже юзаем и ресурколлектором пользуемся и прочее. Asset Tracking не умеет искать. Ручками перебивать в нем неудобно.
     
  12. Александр Якушев

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

    С нами с:
    13.08.2009
    Сообщения:
    77
    Симпатии:
    1
    Баллы:
    7
    Проанализировал. Спасибо у вас очень круто написано. По скорости collect проигрывает.
    Единственное внес небольшое изменение в логику. Поменял функцию:
    вер 3-01:
    Код:
    	fn findMissingProxy = (
    		misProxyPathes = #()
    		wrongProxyObjects = #()
    		
    		lbl_01.text = "Reading proxy..."
    		for i in objects where classOf i == VRayProxy do (
    			if doesFileExist i.filename == false do (
    				appendIfUnique misProxyPathes i.filename
    				append wrongProxyObjects i
    			-- lbl_01.text = i.name -- comment for performanse reasons
    			)
    		)
    		sort misProxyPathes
    		mP.items = misProxyPathes
    		lbl_01.text = "please use DoubleClick for getting proxy"
    	)
    
    новая версия:
    Код:
    	fn findMissingProxy = (
    		misProxyPathes = #()
    		wrongProxyObjects = #()
    		
    		lbl_01.text = "Reading proxy..."
    			 for i in objects where classOf i == VrayProxy  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"
    	)
    
    На больших проектах, более 7000 тысяч объектов удалось время сократить более чем в двое (с ~14 сек до ~6). Смысл в том, что отсекаются из перебора инстансные прокси с одинаковыми путями.

    Это да. У меня тоже, если, к примеру, целиком папку с проектами указать, то виснет напрочь. Пока не удалось решить проблему. Что удивительно, тот же релинк битмапс, прекрасно папку с проектами переваривает целиком и довольно шустро.
     
  13. Александр Якушев

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

    С нами с:
    13.08.2009
    Сообщения:
    77
    Симпатии:
    1
    Баллы:
    7
    Если отдельно функцию getFolderPathes тестить, то прекрасно и быстро работает :)
    Код:
    clearlistener()
    all_dir = #()
    
    fn getFolderPathes root = 
    	(
    		dir_array = #(root)
    		for d in dir_array do
    			join dir_array (getDirectories (d+"/*"))
    		dir_array
    	)
    	
    start = timestamp()
    --test code
    all_dir = getFolderPathes ("C:\\")
    --test code
    end = timestamp()
    
    format " % seconds\n" ((end-start)/1000.0)
    
    Собственно, 44805 папок за 38.9 сек - неплохо и без зависаний.
    Собака, наверное, где-то в последующем коде зарыта.
     
  14. Black Sphinx

    Black Sphinx Знаток

    С нами с:
    05.09.2003
    Сообщения:
    234
    Симпатии:
    1
    Баллы:
    29
    Согласен. Про инстансные прокси я как-то вообще не подумал. Единственно, мне не очень нравится использование функции findItem с массивом строк. Есть у меня подозрение, что она работает не очень быстро. Впрочем, я могу ошибаться. А если не ошибаюсь - это еще один путь к оптимизации ))
    Замена использования в цикле appendIfUnique на makeUniqueArray после цикла дала выигрыш? Я колебался какую функцию использовать.

    А посмотреть что у релинк битмапс в нутре никак не получается?

    Я тоже пробовал отдельно тестить эту функцию. Код почти полностью аналогичен твоему. Но у меня папок на c:\ почти 80 000. Виснет, подлюка. Точнее говоря, task manager показывает некую активность (порядка 13% загрузки CPU у Макса и постоянное увеличение занимаемой памяти), но сам Макс признаков жизни в течение 10-12 минут не подаёт. В результате чего был убиваем из того же task manager.

    Есть у меня, правда, подозрение, что функция спотыкается о линки типа Application Data или, возможно, на циклических линках. (Имеется ввиду, что Win7 установлена на C:). Но это надо отдельно исследовать.
     
  15. Black Sphinx

    Black Sphinx Знаток

    С нами с:
    05.09.2003
    Сообщения:
    234
    Симпатии:
    1
    Баллы:
    29
    Нашёл я багу в функции обхода дерева папок. Причём бага оказалась в MaxScript. В функции getDirectories.

    Оказалось, что если папка-1 содержит папку с именем вида {12345678-1234-1234-1234-1234567890ab}, т.е. GUID в фигурных скобках, то функция getDirectories возвращает в массиве имя родительской папки: #("диск:\путь\папка-1\") вместо #("диск:\путь\папка-1\{12345678-1234-1234-1234-1234567890ab}\").

    В результате в функции getFolderPathes получается мёртвый цикл.
     
  16. Александр Якушев

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

    С нами с:
    13.08.2009
    Сообщения:
    77
    Симпатии:
    1
    Баллы:
    7
    Извините, не мог ответить.
    Непосредственно не тестил, просто подумал, что каждый раз проверять на уникальность возможно дольше, чем в конце разом.

    Неее никак. Закодировано... - если что, вот здесь можно скачать http://www.colinsenner.com/scripts/relink-bitmaps.

    Спасибо! Тоже потестил, - напрочь зависает, даже предусмотренный ESC не срабатывает. Вы не придумали способ обойти этот баг?
    Что-то у меня пока не получается(
     
  17. Black Sphinx

    Black Sphinx Знаток

    С нами с:
    05.09.2003
    Сообщения:
    234
    Симпатии:
    1
    Баллы:
    29
    Есть одно решение на счёт getDirectories. Но через жопу, медленно и неэффективно.
    Код:
    fn getDirs root = (
    	tmpfile = sysInfo.tempdir + "hiddencmdout.tmp"
    	dirs = #()
    	HiddenDOSCommand (@"dir /b/o:n/a:d > " + tmpfile) startpath:root exitCode:&exitcode
    	if exitcode == 0 do (
    		fs = openFile tmpfile mode:"rt"
    		while not eof fs do (
    			dirname = readline fs
    			append dirs (root + dirname + "\\")
    		)
    		close fs
    	)
    	dirs
    )
    
    fn getFolderPathes root = 
    (
    	dir_array = #(root)
    	d_arr = #()
    	for d in dir_array do (
    		join dir_array (getDirs d)
    	)
    	dir_array
    )
    
    root = @"E:\"
    
    start = timestamp() 
    da = getFolderPathes root
    end = timestamp() 
    
    format " % seconds\n" ((end-start)/1000.0) 
    for d in da do print d
    format " % seconds\n" ((end-start)/1000.0) 
    
    2021 папка за 38.411 секунды. Не быстро однако ((

    В принципе на эту тему можно ещё подумать в направлении: (1) читать список папок через getDirectories, (2) поэлементно сравнить возвращённый список с папкой-аргументом, (3) если нет совпадений, то продолжаем, (4) если есть совпадение, то для этой папки применяем функцию getDirs и продолжаем. Может получиться побыстрее, чем только через getDirs.
     
  18. Black Sphinx

    Black Sphinx Знаток

    С нами с:
    05.09.2003
    Сообщения:
    234
    Симпатии:
    1
    Баллы:
    29
    Скачал. Не так уж там и закодировано )) Но разбираться пока времени нет - там больше 50 килобайт исходников.
    Архивчик выложил сюда. Будет жить до 10 июня. Обязательно посмотри.
    А mzp - это обычный zip-архив. Просто расширение поменяли.
     
  19. Александр Якушев

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

    С нами с:
    13.08.2009
    Сообщения:
    77
    Симпатии:
    1
    Баллы:
    7
    Круто!!!) Спасибо.
    Спасибо! Хотя бы такое. Код для меня сложный, не могу сходу разобраться. Попозже обязательно разберусь, может быть удастся ускорить. К тому же релинк битмапс открыли)
     
  20. Black Sphinx

    Black Sphinx Знаток

    С нами с:
    05.09.2003
    Сообщения:
    234
    Симпатии:
    1
    Баллы:
    29
    Нет там ничего сложного. В двух словах:

    1. Вызов системной getDirectories заменён на вызов getDirs.

    2. В getDirs вызывается досовская команда dir с ключами (вывод только папок в коротком формате в алфавитном порядке), вывод которой записывается во временный файл в каталоге %temp%. Этот файл тут же открывается, считывается построчно и каждая папка (т.е. считанная строка) добавляется к массиву.

    У меня очень сильное подозрение, что Relink Bitmaps на папке вида {12345678-1234-1234-1234-1234567890ab} тоже подохнет.
     
Модераторы: Savin Denis

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