Render.ru

UV offset

#1
Не попадался ли кому скрипт для UV редактора, который находит overlap части и сдвигает их на соседние UV-setы? Кпримеру есть UV-мар дома и его UV окон одинакового размера лежат все одно поверх другого. Нужен скрипт который находит эти overlap части и сдвигает по U и V на 1,2 и т.д. не меняя положения фрагмента, ну или хотябы просто сдвигает заданную выделенную группу. Что-то подобное обсуждалось здесь: http://forums.cgsociety.org/archive/index.php/t-599382.html
 

Savin Denis

Модератор форума
Команда форума
Рейтинг
138
#2
Нет не встречал. И написать такой будет сложно если объекты составные как например; Окно где есть рама и стекло отдельно, придется определять кому что принадлежит чтобы сдвинуть UV вместе.
 
#3
Вы видимо не совсем поняли, определять там вообще ничего не надо. UV-развертка уже сделана, все определено и разложено, нужно только одинаковые части с одинаковыми координатоми просто сместить по u и v координатам на соседние сеты, чтобы на каждом сете лежала только одна такая часть. Можно это и в ручную делать (тупо щелкунв на фрагмент и задав офсет), просто если окон, к примеру, много, то муторно каждое сдвигать поотдельности.
 
#4
Поидее там простой совсем алгоритм типа if (какая-то часть лежит сверху другой), then offset (этой части) u=1 или v=1 и так пока не будет overlap частей. Ну или хотябы чтобы выбранные части просто сдвигались по горизонтали на соседние сеты, кроме одной, соответственно на u=1, u=2 u= n, где n=выбранному количеству частей минус одна.
 

igorznag

Мастер
Рейтинг
103
#5
Может быть этот способ чем-то поможет:
1. Выделяем нужные части развертки.
2. В окне Edit UVWs в меню Tools выбираем пункт Pack UVs.
3. В окне Pack отключяем Normalize Clusters и нажимаем кнопку OK.
 

Savin Denis

Модератор форума
Команда форума
Рейтинг
138
#7
Поскольку сама задача интересная для разминки
набросал небольшой скрипт.
На кубиках в рамках задачи вполне себе работает, на реальной геометрии сомневаюсь что особо поможет.

Код:
fn SubArray array1 array2 = 
(
	delIndex = for f in array2 where (ind = findItem array1 f) != 0 collect ind
	sort delIndex
	for i = delIndex .count to 1 by -1 do deleteItem array1 delIndex[i]
	return array1
)

fn comparePoint p1 p2  epsilon = (distance p1 p2) <= epsilon
	
fn compareOverlapUVElements obj channel element1 element2 epsilon  =
(
	 local theVertsEl1 = meshop.getMapVertsUsingMapFace obj channel element1
	 local theVertsEl2 = meshop.getMapVertsUsingMapFace obj channel element2
	
	 for v1 in theVertsEl1 do 
	 (
		 p1 = meshop.getMapVert obj channel v1
		 local fFind = true		
		 for v2 in theVertsEl2 where fFind do 
		 ( 
		    p2 = meshop.getMapVert obj channel v2
		    fFind =  not comparePoint  p1 p2  epsilon 
		 )
		 if fFind do return false
	 )
	 
	 return true
)

fn findOverlap elemets_overlap index =
(
	for i = 1 to elemets_overlap.count where findItem elemets_overlap[i] index != 0 do return i
	return 0
)

fn skipOverlap elemets_overlap index =
(
	i = findOverlap elemets_overlap index
	if i > 1 do return false	return true
)


fn appendOverlap elemets_overlap elemets_array index new_index =
(
	i = findOverlap elemets_overlap index
	if i == 0 then append elemets_overlap #(index, new_index)
	else append elemets_overlap[i] new_index
)

fn offsetElement obj channel elemet1 offset =
(
	local theVertsEl1 = (meshop.getMapVertsUsingMapFace obj channel elemet1 )
	 for v in theVertsEl1 do 
	 (
		p = meshop.getMapVert obj channel v
		p += offset
		meshop.setMapVert obj channel v p
	 )
)


fn offsetOverlap obj channel elemets_overlap elemets_array offset vstep =
(
    
    for elemets in elemets_overlap do 
    (
        if vstep == 0 then vstep = elemets.count
        for i = 1 to elemets.count do 
        (
            ind = elemets[i]
            cnt = i - 1
            cntU = mod cnt vstep
            cntV = floor (cnt / vstep)
            offsetUVW = offset * [ cntU, cntV, cnt]
            offsetElement obj channel elemets_array[ind] offsetUVW
        )
    )
)


fn shiftOverlapUVElements mesh channel:1 offset:[1,1,0]  vstep:10 epsilon:0.001 =	
(
local obj = copy mesh 
convertToMesh obj 
	
free_faces = #{1 .. obj.numfaces}	 as array
elemets_array	= #()
elemets_overlap = #()	

while free_faces.count > 0 do
(
 face_array = #(free_faces[free_faces.count])
 cnt = 0 


 while cnt < face_array.count do 
 (
  cnt += 1
	 

  theVerts = meshop.getMapVertsUsingMapFace obj channel #(face_array[cnt])
  theFaces = meshop.getMapFacesUsingMapVert obj channel theVerts 

  for f in theFaces do appendIfUnique face_array f

 )--end while cnt

  append elemets_array face_array
 
 fFind = true
 for i = 1 to elemets_array.count - 1 while fFind do --where skipOverlap elemets_overlap i do 
(
	if compareOverlapUVElements obj channel elemets_array[i] face_array epsilon then 
	(
		appendOverlap elemets_overlap elemets_array i (elemets_array.count)
		fFind = false
	)
)
 

SubArray  free_faces  face_array


)--end while numfaces

offsetOverlap obj channel elemets_overlap elemets_array offset vstep

obj
)

 
--Example usage:
obj = shiftOverlapUVElements $ channel:1 offset:[1,1,0]  vstep:10 epsilon:0.001
select obj
--modPanel.addModToSelection (Unwrap_UVW ()) ui:on
 

Вложения

igorznag

Мастер
Рейтинг
103
#8
...ну или хотябы просто сдвигает заданную выделенную группу...
...Ну или хотябы чтобы выбранные части просто сдвигались по горизонтали на соседние сеты, кроме одной...
Простой пример:
1. В новой сцене создаем 3 объекта Plane и конвертируем объекты в Editable Poly.
2. Выделяем один объект и присоединяем (Attach) к нему остальные объекты. Название объекта = "окна".
3. Выделяем объект "окна" и добавляем модификатор Unwrap UVW.
Объект "окна" (Editable Poly) состоит из 3 элементов.
Развертка каждого элемента в данном случае состоит из одного куска-Cluster.
Модификатор Unwrap UVW должен быть активным в режиме Face (на панели Modify).
4. Выделяем нужную группу развертки (одинаковые части-Cluster с одинаковыми координатами).
Можно выделять не всю часть-Cluster, а только один полигон-Face из соответствующей части-Cluster.
5. Запускаем скрипт:
Код:
if($selection.count==1)then
(
obj=$selection[1];
if(obj.modifiers.count>0)then
(
uvw=modPanel.getCurrentObject();
if(classof uvw==Unwrap_UVW)then
(
if(uvw.getTVSubObjectMode()==3)then
(
sf_bit_array=uvw.getSelectedFaces(); sf_array=sf_bit_array as array;
cluster_count=0;
while (sf_array.count>0)do
(
cluster_count=cluster_count+1;
uvw.selectFaces #{sf_array[1]}; uvw.selectElement();
offset_vector=[cluster_count-1,0,0];
if(cluster_count>1)then uvw.moveSelected offset_vector;
sf_bit_array=sf_bit_array-uvw.getSelectedFaces(); sf_array=sf_bit_array as array;

if(cluster_count==200)then exit;
)--loop
)--SubObjectMode=Face
)--Unwrap_UVW
)--have modifiers
)--select one object
Максимальное количество кусков из группы которые сдвигаются сейчас установленно 200.
Скрипт не имеет фунцию Undo (Отмена).
 
#9
Супер! Спасибо! Как раз то что надо! Оба скрипта работают, у Дениса только он расширенный, как раз по начальному варианту - одним запуском скрипта все сразу делается. Единственно, Денис, если не сложно, то можно еще добавить чтобы offset не только по U шел но и по V вверх на 1 смещался с приращение, когда кол-во всех сетов будет 10, т.е. чтобы десятками шли - максимальный сдвиг по U тогда 9 будет равен, так как 10ый - базовый, нулевой , а потом соответственно U=0 V=1;U=1 V=1; U=2 V=1 и так до U=9, потом тоже но с v=2 и т.д. (Если надо, могу модельку простую кинуть, чтоб опробовать). И еще вообщем совершенно несущественная деталь, но просто обращаю внимание, так сказать для завершености логической: скрипт добавляет Unwrap UVW модификатор, но он там получается не нужным, так как все оффсеты сколлапсены до этого получаются, т.е. его можно убрать или тогда (что лучше) не коллапсить оффсеты, чтобы они на этом модификаторе оставались.
 

Savin Denis

Модератор форума
Команда форума
Рейтинг
138
#10
Поправил выше код.
Коллапсить или неколлапсить там нечего, поскольку напрямую работает с координатами.
Unwrap UVW добавлялся чтоб быстро оценить работу скрипта.
 
Сверху