
    8j                    V   S r SSKJr  SSKrSSKrSSKJr  \S   r\S   r	\S   r
\S	   r\S
   r\S   r\S   r\S   r\S   r\S   r\S   r\S   r\S   r\S   rSS jr S     SS jjrSS jr    S       SS jjr    S        S!S jjr    S"       S#S jjrg)$ac  Natural eye motion: blinks + subtle iris tremor.

Final-pass post-processor for compiled blendshape targets. Adds:
  1. Periodic blinks (Poisson-distributed, suppressed during emotional eye peaks)
  2. Subtle iris drift (low-frequency smoothed noise on eye-look channels)

Deterministic per scenario: same scenario_id always produces the same eye motion.
    )annotationsN   )NAME_TO_IDXeyeBlinkLefteyeBlinkRighteyeLookDownLefteyeLookDownRighteyeLookInLefteyeLookInRighteyeLookOutLefteyeLookOutRighteyeLookUpLefteyeLookUpRighteyeSquintLefteyeSquintRighteyeWideLefteyeWideRightc                    [         R                  " U R                  S5      5      R                  5       n[        R
                  R                  [        USS S5      5      $ )z;Deterministic RNG from arbitrary string (e.g. scenario_id).zutf-8N   )hashlibmd5encode	hexdigestnprandomdefault_rngint)seed_strhs     _/home/ubuntu/service/kemix-engine/package/face/animasync-face-v3/scripts/compiler/eye_motion.py_seeded_rngr!   !   sC    HOOG,-779A99  QsVR11    c                F   [        S[        X2-  5      5      nUR                  X-   5      n[        R                  " [        R
                  " USS5      5      nXdS USU*  -
  U-  nUSU  nUR                  5       nUS:  a  Xx-  nUR                  [        R                  5      $ )u   Generate length-T noise band-limited around freq_hz.

Method: white noise → moving average whose window matches the period.
Result drifts smoothly at ~freq_hz, no high-frequency jitter.
   r   Ngư>)	maxr   standard_normalr   cumsuminsertstdastypefloat32)	Trngfreq_hzfpswindowrawcssmoothedss	            r    _smoothed_noiser5   '   s     C&'F


aj
)C	299S!Q'	(B7b6'l*f4H|HA4x<??2::&&r"   c                 L    [         R                  " / SQ[         R                  S9$ )u/  5-frame triangular blink shape, peak 0.70 at center frame.

Was 0.95 (ARKit-standard "fully closed eye"). Visual review on the
Ready Player Me / Wolf3D avatar showed 0.95 looked like squeezing the
eyes shut tightly — not a natural blink. The avatar's visible blink
lives on the `eyesClosed` morph; at 0.95 that morph is near its tight-
closure end of travel. Peak 0.70 gives a relaxed natural blink shape
that reads correctly on this avatar.

Values scaled proportionally from the original [0.30, 0.75, 0.95,
0.75, 0.30] by 0.70/0.95 = 0.737, then rounded.
))\(?皙?gffffff?r8   r7   )dtype)r   arrayr+    r"   r    _blink_kernelr<   ;   s     882"**EEr"   c                  ^^^^^^ U R                  5       mTR                  S   m[        US-   5      n[        5       m[	        T5      nUS-  mX2-  n[        [        ST-  5      [        SU-  5      5      n	[        UR                  T[        TS-   [        TT-
  S-
  U	5      5      5      5      n
SnS
UUUUUU4S jjnU
TT-
  :  ac  U" U
5      (       a  US-  nUR                  U5      n[        [        R                  " USU-  S	U-  5      5      nU
[        U5      -  n
U
TT-
  :  a  Mc  US:X  a[  T[        SU-  5      :  aI  UR                  [        R                  " TTT-
  5      5       H  nU" [        U5      5      (       d  M    T$    T$ )zAdd Poisson-distributed blinks. Only suppressed when the preset is
holding the eyes very wide (strong surprise) or hard-squinted (peak
anger/laughter). Moderate squint (anger ~0.6) still allows blinks.r   z::blink   333333?g       @r   c                &  > [        SU T	-
  5      [        TU T	-   S-   5      p![        TX2[        4   R                  5       TX2[        4   R                  5       5      n[        TX2[        4   R                  5       TX2[
        4   R                  5       5      nUT:  ar  UT:  al  [        T
5       H\  u  pVU T	-
  U-   nSUs=::  a  T:  d  M  O  M   [        TU[        4   U5      TU[        4'   [        TU[        4   U5      TU[        4'   M^     gg)Nr   r   TF)	r%   min
IDX_WIDE_L
IDX_WIDE_RIDX_SQUINT_LIDX_SQUINT_R	enumerateIDX_BLINK_LIDX_BLINK_R)centerlohiwidesquintikfir,   halfkerneloutsquint_suppresswide_suppresss           r    
_try_blinkadd_blinks.<locals>._try_blinka   s   Q&Av}q/@(AB3ruj()--/RUJ5F1G1K1K1MNS,-113S9L5M5Q5Q5ST-F_$<!&)d]Q&;Q;;+.s2{?/CQ+GCK(+.s2{?/CQ+GCK(	 *
 r"         ?g       @)rI   r   returnbool)copyshaper!   r<   lenr%   r   integersrA   exponentialfloatr   clippermutationarange)targetr   r/   mean_interval_srU   rT   r-   klenmean_frames	first_maxtblink_countrV   gaprI   r,   rQ   rR   rS   s       ``         @@@@r    
add_blinksrl   K   sh    ++-C		!A
h*
+C_Fv;D19D!'KCaL#cCi.1ICLLs4!8STAy-IJKLAK  a$h,a==1Kook*BGGCsC#I67	SX a$h, aAS3Y/oobiia$h&?@F#f+&&J	 A Jr"   c                   U R                  5       nUR                  S   n[        US-   5      n[        XxXRS9U-  n	[        XxXRS9U-  n
[        R
                  " U	SS5      n[        R
                  " U	* SS5      n[        R
                  " U
SS5      n[        R
                  " U
* SS5      n[        R                  " USS2[        4   U5      USS2[        4'   [        R                  " USS2[        4   U5      USS2[        4'   [        R                  " USS2[        4   U5      USS2[        4'   [        R                  " USS2[        4   U5      USS2[        4'   [        R                  " USS2[        4   U5      USS2[        4'   [        R                  " USS2[        4   U5      USS2[        4'   [        R                  " USS2[        4   U5      USS2[        4'   [        R                  " USS2[        4   U5      USS2[        4'   [        R
                  " USS5      R                  [        R                   5      $ )zAdd subtle continuous iris drift on the eyeLook channels.

Both eyes stay synchronized (no cross-eyed). Amplitude is intentionally
small (~0.04 of [0,1] range) so it reads as life, not as looking around.
r   z::iris)r.   r/   Ng        g      ?)r[   r\   r!   r5   r   ra   maximumIDX_LOOK_IN_LIDX_LOOK_OUT_RIDX_LOOK_OUT_LIDX_LOOK_IN_RIDX_LOOK_UP_LIDX_LOOK_UP_RIDX_LOOK_DOWN_LIDX_LOOK_DOWN_Rr*   r+   )rd   r   r/   	horiz_ampvert_ampdrift_hzrS   r,   r-   r   vh_posh_negv_posv_negs                  r    add_iris_tremorr      s    ++-C		!A
h)
*C:YFA:XEAGGAq$EGGQB4 EGGAq$EGGQB4 E
 JJs1m+;'<eDC=ZZA~,=(>FC>ZZA~,=(>FC>JJs1m+;'<eDC= JJs1m+;'<eDC=JJs1m+;'<eDC= jjQ-?)@%HC? jjQ-?)@%HC?773S!((44r"   c                0    [        XX#S9n[        XaUXES9nU$ )z6Convenience wrapper: blinks + iris tremor in one pass.)r/   re   )r/   rw   rx   )rl   r   )rd   r   r/   blink_interval_siris_horiz_ampiris_vert_amprS   s          r    apply_eye_motionr      s'    
 V3
QC
#S$2LCJr"   )r   strrY   np.random.Generator)rX      )
r,   r   r-   r   r.   r`   r/   r   rY   
np.ndarray)rY   r   )r         @333333?r   )rd   r   r   r   r/   r   re   r`   rU   r`   rT   r`   rY   r   )r   ~jt?Mb?r?   )rd   r   r   r   r/   r   rw   r`   rx   r`   ry   r`   rY   r   )r   r   r   r   )rd   r   r   r   r/   r   r   r`   r   r`   r   r`   rY   r   )__doc__
__future__r   r   numpyr   	constantsr   rG   rH   ru   rv   ro   rr   rq   rp   rs   rt   rD   rE   rB   rC   r!   r5   r<   rl   r   r   r;   r"   r    <module>r      s   #   " .)/*/001O,,--../O,,-?++,'
(
2 79'#'03'=G'(F  >@(+&*(,3 %3#3 !&3 2<3l CE',&+&)#5$#5##5 $#5 /9#5L DF03.3-2(-&+ &+ 8Br"   