2016-08-05 78 views
9

Planuję siatkę 3D za pomocą metody mayavi's triangular_mesh. Dane opisują sylwetkę człowieka układaną twarzą w dół w przestrzeni 3D (w związku z tym można użyć cmap do określenia odległości od kamery).Mayavi: obracanie wokół osi Y

Oto kod używany do generowania terenu (twarze i wierzchołki pochodzić z zewnętrznego obiektu, i nie są zbyt wiele, aby zobaczyć tutaj):

from mayavi import mlab 

import math 
import numpy as np 
import sys 
import os 


fig = mlab.figure(fgcolor=(0, 0, 0), bgcolor=(1, 1, 1), size=(1920, 980)) 

a = np.array(this_mesh.vertices - refC.conj().transpose()) # this_mesh is an object created from external data files 

this_mesh.faces = this_mesh.faces.astype(int) -1 # mesh data is generated by matlab, which is 1-indexed 

m = mlab.triangular_mesh(x, y, z, this_mesh.faces, opacity=0.75) 

mlab.axes(extent=[-1100, 1100, -1100, 1100, -1100, 1100]) 

bez poruszania aparatem, sylwetka kładzie twarz -na dół. Aby obejrzeć model face-on, zmieniam azymut i elewację kamery, aby spojrzeć na wykres z góry na dół. To pokazuje sylwetkę zgodnie z przeznaczeniem.

mlab.view(azimuth=0, elevation=180) 
mlab.show() 

Moim następnym zadaniem jest stworzenie serii obrazów, gdzie kamera obraca wokół działki, wychodząc z sylwetką skierowaną w prawo, a kończąc ona skierowana w lewo.

Powikłaniem jest to, że aby uzyskać mapę kolorów dla informacji o głębokości, już poruszam azymutem widoku i rzędną widoku (jak pokazano w powyższym kodzie). Mayavi ma więcej możliwości poruszania kamerą niż matplotlib, ale wydaje się, że nie ma możliwości obracania się wokół osi Y, więc zgaduję, że będę musiał przeprowadzić skomplikowane obliczenia na azymucie i elewacji, aby osiągnąć ten sam wynik - ale nie mam pojęcia, od czego zacząć (jestem nowy w pracy w przestrzeni 3D, a mój mózg jeszcze tak nie myśli).

Czy ktoś może wskazać mi właściwy kierunek?

Odpowiedz

1

Okazuje się tam trochę obejście tego.

Można obracać aktorów na ich osiach niezależnie od kamery. (To rzuca wizualizację sprzeczne z etykietowania danych, ale jak ja faktycznie ukrywa osie rysunku nie ma znaczenia w tym przypadku).

Wszystko, co musisz zrobić, to:

m.actor.actor.rotate_y(desired_angle) 

... i jesteś gotowy.

2

Potrzebujesz tu trochę matematyki. Ok, oto jak to zrobić pod względem kodu, nie jest to najlepszy kod, ale chciałem, aby było to zrozumiałe. Używam formuły Rodrigues do rotacji w 3d, aby to osiągnąć, az_new i el_new są Twoimi nowymi kątami patrzenia. Zmień wartość theta aby uzyskać inny kąt widzenia w swoim układzie odniesienia, użyłem 45 stopni w poniższym kodzie:

import numpy as np 
import math 

def rotation_matrix(axis, theta): 
    """ 
    Return the rotation matrix associated with counterclockwise rotation about 
    the given axis by theta radians. 
    """ 
    axis = np.asarray(axis) 
    theta = np.asarray(theta) 
    axis = axis/math.sqrt(np.dot(axis, axis)) 
    a = math.cos(theta/2.0) 
    b, c, d = -axis*math.sin(theta/2.0) 
    aa, bb, cc, dd = a*a, b*b, c*c, d*d 
    bc, ad, ac, ab, bd, cd = b*c, a*d, a*c, a*b, b*d, c*d 
    return np.array([[aa+bb-cc-dd, 2*(bc+ad), 2*(bd-ac)], 
        [2*(bc-ad), aa+cc-bb-dd, 2*(cd+ab)], 
        [2*(bd+ac), 2*(cd-ab), aa+dd-bb-cc]]) 


az = 90 
el = -75 

x = np.cos(np.deg2rad(el))*np.cos(np.deg2rad(az)) 
y = np.cos(np.deg2rad(el))*np.sin(np.deg2rad(az)) 
z = np.sin(np.deg2rad(el)) 

# So your viewing vector in x,y coordinates on unit sphere 
v = [x,y,z] 

# Since you want to rotate about the y axis from this viewing angle, we just increase the 
# elevation angle by 90 degrees to obtain our axis of rotation 

az2 = az 
el2 = el+90 

x = np.cos(np.deg2rad(el2))*np.cos(np.deg2rad(az2)) 
y = np.cos(np.deg2rad(el2))*np.sin(np.deg2rad(az2)) 
z = np.sin(np.deg2rad(el2)) 

axis = [x,y,z] 

# Now to rotate about the y axis from this viewing angle we use the rodrigues formula 
# We compute our new viewing vector, lets say we rotate by 45 degrees 
theta = 45 
newv = np.dot(rotation_matrix(axis,np.deg2rad(theta)), v) 

#Get azimuth and elevation for new viewing vector 
az_new = np.rad2deg(np.arctan(newv[1]/newv[0])) 
el_new = np.rad2deg(np.arcsin(newv[2])) 
+0

Bardzo dziękuję, wygląda to na przydatne. Wypróbuję to w poniedziałek, aby zobaczyć, jak to działa. – MassivePenguin

+0

Hmmm, niezupełnie tam (obraca się na niewłaściwej osi). Być może będę musiał spróbować zupełnie innego podejścia ... – MassivePenguin