import * as THREE from 'three' ; import { VRMFirstPerson } from '../firstperson/VRMFirstPerson' ; import { getWorldQuaternionLite } from '../utils/math' ; import { quatInvertCompat } from '../utils/quatInvertCompat' ; import { VRMLookAtApplyer } from './VRMLookAtApplyer' ; const VECTOR3_FRONT = Object . freeze ( new THREE . Vector3 ( 0.0 , 0.0 , - 1.0 ) ) ; const _v3A = new THREE . Vector3 ( ) ; const _v3B = new THREE . Vector3 ( ) ; const _v3C = new THREE . Vector3 ( ) ; const _quat = new THREE . Quaternion ( ) ; /**
 * A class represents look at of a VRM.
 */ export class VRMLookAtHead { public static readonly EULER_ORDER = 'YXZ' ; /**
     * Associated [[VRMFirstPerson]], will be used for direction calculation.
     */ public readonly firstPerson : VRMFirstPerson ; /**
     * Associated [[VRMLookAtApplyer]], its look at direction will be applied to the model using this applier.
     */ public readonly applyer ? : VRMLookAtApplyer ; /**
     * If this is true, its look at direction will be updated automatically by calling [[VRMLookAtHead.update]] (which is called from [[VRM.update]]).
     *
     * See also: [[VRMLookAtHead.target]]
     */ public autoUpdate = true ; /**
     * The target object of the look at.
     * Note that it does not make any sense if [[VRMLookAtHead.autoUpdate]] is disabled.
     */ public target ? : THREE . Object3D ; protected _euler : THREE . Euler = new THREE . Euler ( 0.0 , 0.0 , 0.0 , VRMLookAtHead . EULER_ORDER ) ; param firstPerson param applyer constructor ( firstPerson , applyer ? ) { this . firstPerson = firstPerson ; this . applyer = applyer ; } param target public getLookAtWorldDirection ( target ) { const rot = getWorldQuaternionLite ( this . firstPerson . firstPersonBone , _quat ) ; return target . copy ( VECTOR3_FRONT ) . applyEuler ( this . _euler ) . applyQuaternion ( rot ) ; } param position public lookAt ( position ) { this . _calcEuler ( this . _euler , position ) ; if ( this . applyer ) { this . applyer . lookAt ( this . _euler ) ; } } param delta public update ( delta ) { if ( this . target && this . autoUpdate ) { this . lookAt ( this . target . getWorldPosition ( _v3A ) ) ; if ( this . applyer ) { this . applyer . lookAt ( this . _euler ) ; } } } protected _calcEuler ( target , position ) { const headPosition = this . firstPerson . getFirstPersonWorldPosition ( _v3B ) ; const lookAtDir = _v3C . copy ( position ) . sub ( headPosition ) . normalize ( ) ; lookAtDir . applyQuaternion ( quatInvertCompat ( getWorldQuaternionLite ( this . firstPerson . firstPersonBone , _quat ) ) ) ; target . x = Math . atan2 ( lookAtDir . y , Math . sqrt ( lookAtDir . x * lookAtDir . x + lookAtDir . z * lookAtDir . z ) ) ; target . y = Math . atan2 ( - lookAtDir . x , - lookAtDir . z ) ; return target ; } }