Render.ru

Gizmo allign

Сергей Попов 144982

Пользователь сайта
Рейтинг
2
#1
Подскажите как можно поворачивать и выравнивать гизмо контейнер. На рисунке показана моя модель, вокруг неё расположен гизмо. Нужно наложить модификатор ffd box. Он позиционируется по гизмо. внутри самого модификатора можно вращать контейнер, но у меня не получилось с помощью привязок расположить ffd точно вдоль той системы координат, которая там показана.
 

Вложения

igorznag

Мастер
Рейтинг
103
#2
внутри самого модификатора можно вращать контейнер, но у меня не получилось с помощью привязок расположить ffd точно вдоль той системы координат, которая там показана.
В списке Reference Coordinate System выбираем World.
На панели Display нажимаем кнопку Unhide By Name и выбираем shift_plane_igorznag.
На панели Display нажимаем кнопку Unfreeze By Name и выбираем shift_plane_igorznag.
Выделяем нужный объект.
На панели Utilities нажимаем кнопку Reset XForm > Reset Selected.
Добавляем модификатор FFD Box и активируем под-объект Lattice.
Нажимаем кнопку Align (Alt+A).
Нажимем кнопку Select By Name (H) и выбираем shift_plane_igorznag.
В окне Align: Align Orientation (Local): Включаем X Axis, Y Axis, Z Axis.
В списке Reference Coordinate System выбираем shift_plane_igorznag.
 

Сергей Попов 144982

Пользователь сайта
Рейтинг
2
#3
В очередной раз спасибо. Вопрос решен. Не могли бы вы пояснить, есть ли вообще возможность вращать и алигнить гизмо контейнер объекта, а не габаритный контейнер модификатора? Если есть reset xform, которая сбрасывает его ориентацию, то наверное должна быть возможность располагать его произвольным образом?
 

igorznag

Мастер
Рейтинг
103
#4
есть ли вообще возможность вращать и алигнить гизмо контейнер объекта
Не знаю, но можно создать временный объект и вращать-алигнить его, а потом "украсть" у него контейнер.

На панели Display нажимаем кнопку Unhide By Name и выбираем shift_plane_igorznag.
На панели Display нажимаем кнопку Unfreeze By Name и выбираем shift_plane_igorznag.
Выделяем объект shift_plane_igorznag и создаем копию (Ctrl+V) с названием "temp".
Конвертируем объект temp в Editable Poly.
Выделяем все полигоны объекта temp (Ctrl+A) и удаляем их (Delete).
В свитке Edit Geometry нажимаем кнопку Attach и выбираем нужный объект.
Выделяем объект temp и добавляем модификатор FFD Box.
 

Сергей Попов 144982

Пользователь сайта
Рейтинг
2
#5
Вы уже написали мне скрипт, который прекрасно работает, и за что отдельное Спасибо. У меня тут идея возникла, а можете написать скрипт, который будет вращать модель по 3 осям, и находить её положение в BB, при котором она занимает в нем наибольший объем, а потом эти углы поворота применять к повороту BB, и модель возвращать в изначальное положение? Тогда, на первый взгляд, BB оптимально будет описывать модель.
 

igorznag

Мастер
Рейтинг
103
#6
Если для вас подходит скрипт minOBB, тогда:
Выделяем все объекты Editable Poly без модификаторов.
Запускаем скрипт. В новом окне нажимаем кнопку Apply.
Создаем копию сцены перед тем, как использовать скрипт.
Код:
try(destroydialog igorznag_minOBB)catch()
rollout igorznag_minOBB "Min OBB"
(
--gui
button btn_apply "Apply"
--variables
local obj
--functons
-- The Jacobi Method for Finding the Eigenvalue and Eigenvectors
-- of Symmetric Matrices.
 
 fn Jacobi  n &a &d &v  = 
( 
	local i, j, p, q, rot, sm, g, theta, t, tresh, c, s, tau, h
	local z=#()
	local b=#()
	for i =1 to n do
	(
		z[i] =0.0
		b[i] = a[i][i]
		d[i] = a[i][i]
		for j=1 to n do
		 if (i == j) then v[i][j] = 1.0
		 	       else v[i][j] = 0.0
	)

	rot =0
	for i =1 to 50 do
	(
		sm = 0.0
		for p = 1 to n-1 do
		 for q=p+1 to n do sm += abs( a[p][q] )
		 
		if ( sm == 0 ) then exit()
		tresh = case ( i<4 ) of
		(
			true: 0.2*sm/(n*n)
			false: 0.0
		)
		for p =1 to n-1 do
		(
			for q = p+1 to n do 
			(
				g = 1e12 * abs ( a[p][q] )
				if ((i>4) and ( abs(d[p])>g ) and ( abs(d[q])>g )) then (a[p][q] = 0.0)
				else 
				if ( abs( a[p][q] ) > tresh ) then
				(
					theta = 0.5 * ( d[q] - d[p] ) / a[p][q]
					t = 1.0 / ( abs(theta) + sqrt(1.0+theta*theta) )
					if ( theta < 0 ) then t = - t
					c = 1.0 / sqrt ( 1.0 + t*t )
                    			s = t * c
                    			tau = s / ( 1.0 + c )
                    			h = t * a[p][q]
					z[p] -= h
					z[q] += h
					d[p] -= h
                    			d[q] += h
                    			a[p][q] = 0.0
					for j=1 to p-1 do   
					(
						g = a[j][p]
						h = a[j][q]
						a[j][p] = g - s * ( h + g * tau )
						a[j][q] = h + s * ( g - h * tau )
					)
					for j=p+1 to q-1 do
					(
						g = a[p][j]
						h = a[j][q]
						a[p][j] = g - s * ( h + g * tau )
						a[j][q] = h + s * ( g - h * tau )
					)
					for j=q+1 to n do
					(
						g = a[p][j]
						h = a[q][j]
						a[p][j] = g - s * ( h + g * tau )
						a[q][j] = h + s * ( g - h * tau )
					)
					for j=1 to n do
					(
						g = v[j][p]
						h = v[j][q]
						v[j][p] = g - s * ( h + g * tau )
						v[j][q] = h + s * ( g - h * tau )
					)
					rot += 1
				)				
			)
		)
		for p =1 to n do
		(
			b[p] += z[p] 
			d[p] = b[p]			
			z[p] = 0.0
		)
	)--for i =1 to 50
	return rot
)--fn Jacobi


fn GetBestFitVectors &v &dir &norm  =
(
	local n = v.count
	if (n<2) then return false
	local point = v[1]
	for i = 2 to n do (point += v[i])
	point /= n
	local xx, xy, xz, yy, yz, zz
	xx = xy = xz = yy = yz = zz = 0.0
	for i = 1 to n do
	(
		local u = v[i] - point
		xx += u.x * u.x
		xy += u.x * u.y
		xz += u.x * u.z
		yy += u.y * u.y
		yz += u.y * u.z
		zz += u.z * u.z
	)
	
	--Symmetric Matrix
	local a = #([ xx, xy, xz ],
		 	 [ xy, yy, yz ],
		 	 [ xz, yz, zz ])
		 
	--Eigenvalue
	local d = #(0.0, 0.0, 0.0)
	
	--Eigenvectors	 
	local u = #([ 0, 0, 0 ],
		 	 [ 0, 0, 0 ],
		 	 [ 0, 0, 0 ])

	--finding the Eigenvalue and Eigenvectors
	jacobi  3 &a &d &u

	-- calc direction ray
	if ( d[1] >= d[2] ) then
	(
		if ( d[1] >= d[3] ) then (dir = [ u[1].x, u[2].x, u[3].x ])
        				 	else  (dir = [ u[1].z, u[2].z, u[3].z ])
	)
	else
	(
		if ( d[2] >= d[3] ) then (dir = [ u[1].y, u[2].y, u[3].y ])
					 else	 (dir = [ u[1].z, u[2].z, u[3].z ])
	)
	-- calc normal fit plane
	if ( d[1] <= d[2] ) then 
    	(
        		if ( d[1] <= d[3] ) then norm = [ u[1].x, u[2].x, u[3].x ]
        					else  norm = [ u[1].z, u[2].z, u[3].z ]
    	)
    	else
    	(
        		if ( d[2] <= d[3] ) then norm = [ u[1].y, u[2].y, u[3].y ]
        					else  norm = [ u[1].z, u[2].z, u[3].z ]
    	)
	return true
)--fn GetBestFitVectors

on btn_apply pressed do
(
undo off
(
	max modify mode
	objs=selection as array
	for i=1 to objs.count do
	(
	obj = objs[i]
	if(classOf(obj)==Editable_Poly)then
	(
	-- get cloud points from object
  cloud_points = #()
		for i=1 to obj.NumVerts do append cloud_points (polyOp.getVert obj i)
	-- calc fit dir and normal fit plane
getBestFitVectors &cloud_points &dir &norm
-- calc and draw box
arr=#(); join arr cloud_points
	local upVector = normalize ( cross dir norm )
	local T = matrix3 upVector norm dir [0,0,0]
	local iT = inverse T
	for i=1 to arr.count do arr[i] = arr[i] * iT

	local qmin = copy arr[1]
	local qmax = copy arr[1]
	
	for i in arr do (
		for j=1 to 3 do (
			if i[j] < qmin[j] do qmin[j]=i[j]
			if i[j] > qmax[j] do qmax[j]=i[j]
		)
	)
	
	local _diag = qmax-qmin
	local l = abs _diag.x
	local w = abs _diag.y
	local h = abs _diag.z
	local b = box length:w width:l height:h
	b.pivot = b.center
	b.transform = T
	b.pos = (qmax+qmin)/2.0 * T
	b.wirecolor = obj.wirecolor
	b.name=obj.name
	b.parent=obj.parent
	b.pivot=obj.pos
	for obj_child in obj.children do append b.children obj_child
	b=converttopoly b
	polyOp.deleteFaces b #{1..(polyop.getNumFaces b)}
	polyOp.attach b obj
	selectmore b
	)--if(classOf(obj)==Editable_Poly)then
)--for i=1 to selection.count do
)--undo off
redrawViews()
)--on btn_apply pressed do
); createdialog igorznag_minOBB 100 30
 

Сергей Попов 144982

Пользователь сайта
Рейтинг
2
#7
Я так понимаю метод Якоби применяется для нахождения собственных векторов и собственных значений матрицы ковариации созданной на основе координат вершин объектов. Вопрос такой, берутся все вершины для анализа, или только вершины выпуклой оболочки объекта?
 

Сергей Попов 144982

Пользователь сайта
Рейтинг
2
#8
Короче проверил скрипт. Оси ищутся для всех точек меша, а это значит, что сгустки точек в каком-то месте меша буду вносить вес в матрицу ковариации и влиять на направления осей. Нужно дополнить скрипт, а именно, перед расчетом матрицы построить выпуклую оболочку. У меня пока что не получилось так сделать...
 

Сергей Попов 144982

Пользователь сайта
Рейтинг
2
#9
Просто если использовать скрипт в таком виде, то происходит такой глюкан из-за неравномерной топологии сетки объекта.
 

Вложения

igorznag

Мастер
Рейтинг
103
#10
перед расчетом матрицы построить выпуклую оболочку. У меня пока что не получилось так сделать...
У меня тоже не получается.
Просто если использовать скрипт в таком виде, то происходит такой глюкан из-за неравномерной топологии сетки объекта.
Для объекта из сообщения 9 попробуйте этот простой вариант.
Создаем копию сцены. Выполняются много вычислений.
Код:
try(destroydialog igorznag_minOBB)catch()
rollout igorznag_minOBB "Min OBB"
(
button btn_apply "Apply"; 
fn AlignPivotTo Obj Trgt = 
( 
-- Get matrix from object 
if classOf Trgt != matrix3 then Trgt = Trgt.transform 
-- Store child transforms 
local ChldTms = in coordSys Trgt ( for Chld in Obj.children collect Chld.transform ) 
-- Current offset transform matrix 
local TmScale = scaleMatrix Obj.objectOffsetScale 
local TmRot = Obj.objectOffsetRot as matrix3 
local TmPos = transMatrix Obj.objectOffsetPos 
local 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 
-- Restore child transforms 
for i = 1 to Obj.children.count do Obj.children[i].transform = ChldTms[i] * inverse Trgt * Obj.transform 
)

on btn_apply pressed do
(
undo off
(
with animate off
(
objs=selection as array;
m=undefined; diag=undefined; vol=1e9
b_min=[1e9,1e9,1e9];b_max=[-1e9,-1e9,-1e9];
for i=1 to objs.count do
(
obj = objs[i]
if(classOf(obj)==Editable_Poly)then
(
for i=1 to (polyop.getNumFaces obj) do
(
ef_a=polyop.getFaceEdges obj i
face_normal=polyop.getFaceNormal obj i
for j=1 to ef_a.count do
(
ve_a=polyop.getEdgeVerts obj ef_a[j]
v1_coord=polyop.getVert obj ve_a[1]
v2_coord=polyop.getVert obj ve_a[2]
v2v1=normalize(v2_coord-v1_coord)
v3=normalize (cross v2v1 face_normal)
m_temp=matrix3 v2v1 face_normal v3 v1_coord
in coordsys m_temp
(
b_min_temp=[1e9,1e9,1e9];b_max_temp=[-1e9,-1e9,-1e9]
for k=1 to (polyop.getnumverts obj) do
(
vert_temp=polyop.getVert obj k
for t=1 to 3 do
(
if vert_temp[t]<b_min_temp[t] then b_min_temp[t]=vert_temp[t]
if vert_temp[t]>b_max_temp[t] then b_max_temp[t]=vert_temp[t]
)--for t=1 to 3 do
)--for k=1 to (polyop.getnumverts obj) do
diag_temp=b_max_temp-b_min_temp
vol_temp=diag_temp.x*diag_temp.y*diag_temp.z
if(vol_temp<vol)then (
diag=diag_temp;vol=vol_temp;b_min=b_min_temp;b_max=b_max_temp;m=m_temp
)
)--in coordsys m
)--for j=1 to ef_a.count do
)--for i=1 to (polyop.getNumFaces obj) do

if(m!=undefined)then
(
b=box length:diag.y width:diag.x height:diag.z
b.pivot=b.center
b.transform=m
in coordsys m b.pos = (b_max+b_min)/2.0
AlignPivotTo b (transMatrix obj.pos)
----
b.wirecolor = obj.wirecolor
b.name=obj.name
b.parent=obj.parent
for obj_child in obj.children do append b.children obj_child
b=converttopoly b
polyOp.deleteFaces b #{1..(polyop.getNumFaces b)}
polyOp.attach b obj
selectmore b
)--if(m!=undefined)then
)--if(classOf(obj)==Editable_Poly)then
)--for i=1 to objs.count do
)--with animate off
)--undo off
redrawViews()
)--on btn_apply pressed do
); createdialog igorznag_minOBB 100 30
 
Сверху