Blender (jusqu'à 2.49)
|
Python
et EnvMap (4/4)
Description:
lier un script pour déterminer automatiquement
la position relative
de la caméra à un plan:
un peu de géométrie.
|
|
Cette page détaille
les différent éléments nécessaires à
la réalisation et au bon fonctionnement du script, c'est-à-dire:
-- calculer le symétrique
orthogonal de la caméra par rapport au plan-miroir.
-- repositionner
les sommets du plan de manière absolue dans l'espace de Blender
et trouver les vrais coefficients
Ce que vous devez
savoir pour aborder ce tutoriel:
-- récupérer
la copie d'un objet blender
au travers de l'API python
-- connaître
la structure de cet objet pour y puiser les
bons paramètres.
Symétrique
orthogonal par rapport à un plan
C'est le point qui
se trouve à l'opposé du plan sur un axe perpendiculaire à
ce plan et à une distance identique à celle qui sépare
le plan de la caméra. Dans le script, il est défini par la
variable EmptyObCibleName. La variable qui désigne le nom
du plan miroir est PlaneObName. La camera est tout simplement CameraName.
Ces variables doivent être documentées avec les noms des objets
correspondant dans la scène en cours de réalisation.
Si l'un d'entre eux n'est pas correctement identifié alors le script
ne fonctionne pas et renvoie une erreur dans la console.
(cette partie du
tutoriel fut fournie par Didier Laffont)
Soient P un plan d'équation
cartésienne
u*x+v*y+w*z+h=0 avec quatre constantes u,v,w,h:
(u,v,w) différents de (0.0,0.0,0.0) et M° (x°,y°,z°)
un point en dehors du plan.
Alors les coordonnées (x°',y°',z°')
du point M'° symétrique orthogonal de M° par
rapport au plan P devraient être sauf erreur de calcul (calculs
qui sont épargnés au lecteur) :
x°' = ( -2( u*x°+v*y°+w*z°+h)
* u ) / (u²+v²+w²) + x°
y°' = ( -2( u*x°+v*y°+w*z°+h)
* v ) / (u²+v²+w²) + y°
z°' = ( -2( u*x°+v*y°+w*z°+h)
* w ) / (u²+v²+w²) + z°
D'où
x°' = A*u + x°
y°' = A*v + y°
avec
A=(-2(
u*x°+v*y°+w*z°+h) ) / (u²+v²+w²)
z°' = A*w + z°
(Fin de la contribution fondamentale sans
laquelle ce script ne fonctionnerait pas.) |
Dans le script qui
est proposé en accompagnement ces résultats ont été
transformés en une fonction très courte:
def point_miroite(nx,ny,nz,k,p):
A= -2*(nx*p[0]+ny*p[1]+nz*p[2]+k)/(nx*nx+ny*ny+nz*nz)
return [nx*A+p[0], ny*A+p[1], nz*A+p[2]] |
et u, v,
w et
h ont été remplacés par nx,ny,nz
et k.
Variation sur
ce script, projection orthogonale : py_trimvertex2plane.htm
Trouver les coefficients
du plan
nx,ny,nz correspondraient
au vecteur normal du plan, sachant cela, il suffirait de substituer n'importe
quel point du plan pour obtenir k. En fait l'API Python de blender
offre la possibilité de récupérer le vecteur normal
associé à n'importe quel sommet. Mais cela ne servirait à
rien car le vecteur en question serait calculé dans le repère
local du plan lui-même et non pas le repère de l'espace global
de blender où se situe la caméra.
A cause de ce problème
il faut d'abord transposer les sommets du plan dans l'espace global
de blender avant de les utiliser pour calculer les vrais coefficients.
Pour cela il faut faire interbvenir trois transformations qui sont la localisation,
la rotation et la mise à l'échelle. On peut les connaître
en utilisant la touche n. L'API python 1.80a offre le module
Object pour avoir accés à ces informations (avoir
un exemple d'utilisation du module). Cependant si on effectue successivement
la rotation puis le déplacement et enfin la mise à l'echelle,
on obtient des positions plutôt fantaisistes qui ne correspondent
pas aux coordonnées visibles des sommets du rectangle.
Utilisation
de matrice homogène
Par contre si on
multiplie la position du sommet par la matrice de l'objet on obtient un
résultat beaucoup plus convaincant. Cependant, sous windows **
, l'utilisation directe de cette matrice dans l'API python de Blender 1.80a
plante irrémédiablement le logiciel. Mais le fonctionnement
est correct, encore une fois a ma grande surprise, si on récupère
chaque liste de 4 cellules pour recomposer ensuite une nouvelle matrice.
La position d'un
point 3D est définie par la matrice :
|
x |
| y |
| z |
| 1 |
La matrice de transformation
est de la forme:
| M11
M21 M31 M41 |
| M12
M22 M32 M42 |
| M13
M23 M33 M43 |
| M14
M24 M34 M44 |
| M11 M21 M31 M41 |
| x |
| M12 M22 M32 M42 |
| y |
| M13 M23 M33 M43 |
* | z |
| M14 M24 M34 M44 |
| 1 |
Pour effectuer une
multiplication de matrice, chaque ligne de la première matrice est
associée à la chaque colonne de la seconde de la manière
suivante:
x1 =
M11*x + M21*y +M31*z+1* M41
Donc ici il n'y a
qu'une seule colonne ce qui rend les choses beaucoup plus simple à
écrire, il n'est pas nécessaire de réaliser une fonction
de traitement général des matrices. Par contre la numérotation
des cellules commence à 0 il faut donc adapter un peu pour que cela
fonctionne dans python. On obtient la présentation suivante:
x1 = (x * M[0][0])
+ (y * M[1][0]) + (z * M[2][0]) + M[3][0]
y1 = (x * M[0][1])
+ (y * M[1][1]) + (z * M[2][1]) + M[3][1]
z1 = (x * M[0][2])
+ (y * M[1][2]) + (z * M[2][2]) + M[3][2]
w1 = (x * M[0][3])
+ (y * M[1][3]) + (z * M[2][3]) + M[3][3]
Pour ce projet, la
dernière ligne n'est pas utile.
Exemple d'utilisation:
...
x,y,z=0.0,0.0,0.0
def multmat(M):
global x,y,z
x1 = (x * M[0][0]) + (y * M[1][0]) + (z * M[2][0])
+ M[3][0]
y1 = (x * M[0][1]) + (y * M[1][1]) + (z * M[2][1])
+ M[3][1]
z1 = (x * M[0][2]) + (y * M[1][2]) + (z * M[2][2])
+ M[3][2]
#w1 = (x * M[0][3]) + (y * M[1][3]) + (z * M[2][3])
+ M[3][3]
x=x1;y=y1;z=z1
...
#appel de l'objet
ob=Blender.Object.Get('Mirror')
#récupération des différents fragment de la matrice
mat1=ob.mat[0]
mat2=ob.mat[1]
mat3=ob.mat[2]
mat4=ob.mat[3]
#reconstitution de la matrice
mat0=[mat1,mat2,mat3,mat4]
# récupèration des données de l'objet
me=ob.data
# Comme le rectangle n'a qu'une face
# on prend la première qui se présente
f = me.faces[0]
# pour les besoins de l'exemple on se contente d'un
# seul sommet emprunté à la liste 'faces.v'.
dv=f.v
v1=dv[0]
#recupère les coordonnées du sommet dans l'espace local
de l'objet
x =v1.co[0]
y =v1.co[1]
z =v1.co[2]
#calcule la position du sommet dans l'espace global de blender
multmat(M)
#etc.
... |
Pour en revenir
aux coefficients du plan on peut écrire la fonction suivante:
def EquationPlan (v1,v2,v3,M):
global a,b,c,d,x,y,z
x =v1.co[0] ; y =v1.co[1];
z =v1.co[2]
multmat(M)
X1=x; Y1=y; Z1=z;
x =v2.co[0]; y =v2.co[1];
z =v2.co[2]
multmat(M)
X2=x; Y2=y; Z2=z;
x =v3.co[0] ; y =v3.co[1];
z =v3.co[2]
multmat(M)
X3=x; Y3=y; Z3=z;
a = Y1 * (Z2 - Z3) + Y2 * (Z3 - Z1) + Y3 *
(Z1 - Z2)
b = -X1 * (Z2 - Z3) + X2 * (Z1 - Z3) - X3
* (Z1 - Z2)
c = X1 * (Y2 - Y3) - X2 * (Y1 - Y3) + X3 *
(Y1 - Y2)
d = -X1*(Y2*Z3-Y3*Z2)+X2*(Y1*Z3-Y3*Z1)-X3*(Y1*Z2-Y2*Z1)
|
Les questions concernant cette page
peuvent être posées sur :
news://news.zoo-logique.org/3D.Blender
|