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.
    Début   Index
précédentScript Python/Envmap (3/4)
Script Python/split mesh: Suivant

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 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)
 


 
 
précédentScript Python/Envmap (3/4)
Script Python/Split mesh: Suivant
Vers le   Haut de page

Les questions concernant cette page  peuvent être posées sur  :
 news://news.zoo-logique.org/3D.Blender


 

 

Livre en français
Blender : apprenez, pratiquez, Créez, livre, Ed. Campus Press, coll. Starter Kit
Blender Starter Kit

Forum
FAQ
Lexique
Didacticiels
Compilations
Blender2KT
Débuter
Modelage
Blender python
Materiaux
Lumière
Animation
API python (eng)
Archives nzn
Statistiques
Doc flash Sculptris
Galerie Sculptris

mon site de démos sur youtube