@@ -30,13 +30,14 @@ def __init__(self, base, scene, settings):
3030
3131 # 1. Configuration de la Lentille Orthographique
3232 self .lens = OrthographicLens ()
33- self .lens .setFilmSize (20 , 20 )
33+ self .lens .setFilmSize (20 )
3434 self .base .cam .node ().setLens (self .lens )
3535
3636 # 2. Hiérarchie : focal_node (Pivot) -> camera
3737 self .focal_node = self .base .render .attachNewNode ("camera_pivot" )
38+ self .focal_node .setHpr (0 , - 90 , 0 )
3839 self .base .camera .reparentTo (self .focal_node )
39- self .base .camera .setPos (0 , - 100 , 0 )
40+ self .base .camera .setPos (0 , 0 , 0 )
4041 # 3. Marqueur de pivot (la croix)
4142 self .marker = self .create_marker ()
4243 self .marker .reparentTo (self .base .render )
@@ -52,7 +53,7 @@ def __init__(self, base, scene, settings):
5253 self .key_pan_speed = 2.0
5354
5455 # Task pour maintenir le marqueur et le gizmo
55- self .taskMgr .add (self .update_task , "CameraUpdateTask" )
56+ self .base . taskMgr .add (self .update_task , "CameraUpdateTask" )
5657 # Configure la camera par rapport au contenu de la scene
5758 self .refresh_scene ()
5859
@@ -76,7 +77,7 @@ def refresh_scene(self):
7677 self .model_center = center
7778 # 3. Ajuster la lentille avec une MARGE (ex: 1.2 pour 20% d'espace vide autour)
7879 view_size = radius * 2.2
79- self .lens .setFilmSize (view_size , view_size )
80+ self .lens .setFilmSize (view_size )
8081
8182 # 4. Adujst the limits of automatic zoom
8283 self .min_zoom = self .model_radius * 0.05
@@ -88,9 +89,9 @@ def refresh_scene(self):
8889
8990 # 6. Ajuster la profondeur de rendu (Near/Far)
9091 # Très important pour ne pas que l'objet soit "tronçonné"
91- limit = max (100000 , self .model_radius * 1000 )
92- self .lens .setNear (0.1 )
93- self .lens .setFar (limit * 2 )
92+ limit = max (100.0 , self .model_radius * 5 )
93+ self .lens .setNear (- limit )
94+ self .lens .setFar (limit )
9495
9596 def create_marker (self ):
9697 """
@@ -101,7 +102,7 @@ def create_marker(self):
101102 """
102103 ls = LineSegs ()
103104 ls .setThickness (2 )
104- for i , col in enumerate ([(1 , 0 , 0 , 1 ), (0 , 1 , 0 , 1 ), ( 0 , 0 , 1 , 1 ) ]):
105+ for i , col in enumerate ([(1 , 0 , 0 , 1 ), (0 , 1 , 0 , 1 )]):
105106 ls .setColor (col )
106107 v = LVector3 (0 , 0 , 0 )
107108 v [i ] = 0.5
@@ -147,8 +148,10 @@ def handle_pan(self, dx, dy):
147148 move_x = - dx * (fs * 0.5 )
148149 move_z = - dy * (fs * 0.5 )
149150
150- # On déplace par rapport à la caméra pour respecter l'orientation de l'écran
151- self .focal_node .setPos (self .base .camera , LVector3 (move_x , 0 , move_z ))
151+ # NOTE: Calcul dans l'espace local puis conversion dans le monde
152+ cam_vec = LVector3 (move_x , 0 , move_z )
153+ world_vec = self .base .render .getRelativeVector (self .base .camera , cam_vec )
154+ self .focal_node .setPos (self .focal_node .getPos () + world_vec )
152155
153156 def handle_zoom (self , factor ):
154157 """
@@ -163,19 +166,19 @@ def handle_zoom(self, factor):
163166 if self .is_animating :
164167 return
165168
166- # 1. Calculer la nouvelle taille de vue
167169 current_size = self .lens .getFilmSize ().getX ()
168170 new_size = current_size * factor
169171
170- # 2. Lever la restriction de taille (on garde une sécurité minimale)
171172 if 0.00001 < new_size < 100000 :
172- self .lens .setFilmSize (new_size , new_size )
173+ self .lens .setFilmSize (new_size )
173174
174175 # 3. LEVIER DE RESTRICTION : On pousse les plans de coupe très loin
175176 # On s'assure que la profondeur de vue est 10x plus grande que l'objet
176177 # pour éviter tout "clipping" (disparition)
177178
178- limit = max (new_size * 1000 , self .model_radius * 1000 )
179+ # NOTE: J'ai réduit le max pour résoudre un problème de précision mathématique des Float32.
180+ # La taille de limit d'origine était beaucoup trop grande max(10000.0, self.model_radius * 100.0)
181+ limit = max (100.0 , self .model_radius * 5 )
179182 self .lens .setNear (- limit )
180183 self .lens .setFar (limit )
181184
@@ -207,6 +210,10 @@ def recenter(self):
207210 def _unlock (self ):
208211 """Release the animation lock so user input is accepted again."""
209212 self .is_animating = False
213+ current_size = self .lens .getFilmSize ().getX ()
214+ if getattr (self , "_last_film_size" , None ) != current_size :
215+ self ._last_film_size = current_size
216+ self .base .messenger .send ("zoom_changed" , [current_size ])
210217
211218 def align_to_plane (self , axis ):
212219 """
@@ -285,4 +292,11 @@ def update_task(self, task):
285292 # Mise à jour du Gizmo (orientation de la caméra vers le monde)
286293 if hasattr (self .scene , "gizmo" ):
287294 self .scene .gizmo .update (self .base .camera .getQuat (self .base .render ))
295+
296+ # Émission de l'événement de zoom uniquement si on n'anime pas
297+ current_size = self .lens .getFilmSize ().getX ()
298+ if getattr (self , "_last_film_size" , None ) != current_size :
299+ self ._last_film_size = current_size
300+ if not self .is_animating :
301+ self .base .messenger .send ("zoom_changed" , [current_size ])
288302 return task .cont
0 commit comments