@@ -49,7 +49,6 @@ function VisibilityOptimizer({
4949 onVisibilityChange ?: ( visible : boolean ) => void ;
5050} ) {
5151 const { gl, invalidate } = useThree ( ) ;
52- const animationLoopRef = useRef < ( ( time : number ) => void ) | null > ( null ) ;
5352
5453 useEffect ( ( ) => {
5554 const handleVisibilityChange = ( ) => {
@@ -111,13 +110,18 @@ const EMOTION_LIGHT_COLORS: Record<string, string> = {
111110function CyberAvatar ( ) {
112111 const group = useRef < THREE . Group > ( null ) ;
113112 const headGroupRef = useRef < THREE . Group > ( null ) ;
114- const bodyGroupRef = useRef < THREE . Group > ( null ) ;
115113 const headRef = useRef < THREE . Mesh > ( null ) ;
116114 const leftEyeRef = useRef < THREE . Mesh > ( null ) ;
117115 const rightEyeRef = useRef < THREE . Mesh > ( null ) ;
118116 const mouthRef = useRef < THREE . Mesh > ( null ) ;
119117 const leftBrowRef = useRef < THREE . Mesh > ( null ) ;
120118 const rightBrowRef = useRef < THREE . Mesh > ( null ) ;
119+ const leftIrisRef = useRef < THREE . Mesh > ( null ) ;
120+ const rightIrisRef = useRef < THREE . Mesh > ( null ) ;
121+ const leftPupilRef = useRef < THREE . Mesh > ( null ) ;
122+ const rightPupilRef = useRef < THREE . Mesh > ( null ) ;
123+ const leftHighlightRef = useRef < THREE . Mesh > ( null ) ;
124+ const rightHighlightRef = useRef < THREE . Mesh > ( null ) ;
121125 const ringsRef = useRef < THREE . Group > ( null ) ;
122126 const bodyRef = useRef < THREE . Mesh > ( null ) ;
123127 const leftArmRef = useRef < THREE . Group > ( null ) ;
@@ -146,6 +150,8 @@ function CyberAvatar() {
146150 leftArmRotX : 0 ,
147151 rightArmRotX : 0 ,
148152 bodyScale : 1 ,
153+ eyeLookX : 0 ,
154+ eyeLookY : 0 ,
149155 } ) ;
150156
151157 const {
@@ -159,9 +165,9 @@ function CyberAvatar() {
159165
160166 useFrame ( ( state ) => {
161167 const t = state . clock . elapsedTime ;
162- const dt = state . clock . getDelta ( ) ;
163168 const intensity = Math . max ( 0 , Math . min ( 1 , expressionIntensity ?? 1 ) ) ;
164169 const lerp = THREE . MathUtils . lerp ;
170+ const clamp = THREE . MathUtils . clamp ;
165171 const anim = animState . current ;
166172
167173 // ---- 目标值初始化 ----
@@ -328,6 +334,36 @@ function CyberAvatar() {
328334 if ( leftEyeRef . current ) leftEyeRef . current . scale . y = anim . leftEyeScaleY ;
329335 if ( rightEyeRef . current ) rightEyeRef . current . scale . y = anim . rightEyeScaleY ;
330336
337+ const targetEyeLookX = clamp ( mouse . current . x * 0.05 + Math . sin ( t * 1.7 ) * 0.01 , - 0.06 , 0.06 ) ;
338+ const targetEyeLookY = clamp ( mouse . current . y * 0.035 + Math . sin ( t * 1.3 ) * 0.008 , - 0.045 , 0.045 ) ;
339+ anim . eyeLookX = lerp ( anim . eyeLookX , targetEyeLookX , 0.12 ) ;
340+ anim . eyeLookY = lerp ( anim . eyeLookY , targetEyeLookY , 0.12 ) ;
341+
342+ if ( leftIrisRef . current ) {
343+ leftIrisRef . current . position . x = - 0.24 + anim . eyeLookX ;
344+ leftIrisRef . current . position . y = anim . eyeLookY ;
345+ }
346+ if ( rightIrisRef . current ) {
347+ rightIrisRef . current . position . x = 0.24 + anim . eyeLookX ;
348+ rightIrisRef . current . position . y = anim . eyeLookY ;
349+ }
350+ if ( leftPupilRef . current ) {
351+ leftPupilRef . current . position . x = - 0.24 + anim . eyeLookX ;
352+ leftPupilRef . current . position . y = anim . eyeLookY ;
353+ }
354+ if ( rightPupilRef . current ) {
355+ rightPupilRef . current . position . x = 0.24 + anim . eyeLookX ;
356+ rightPupilRef . current . position . y = anim . eyeLookY ;
357+ }
358+ if ( leftHighlightRef . current ) {
359+ leftHighlightRef . current . position . x = - 0.22 + anim . eyeLookX * 0.8 ;
360+ leftHighlightRef . current . position . y = 0.02 + anim . eyeLookY * 0.8 ;
361+ }
362+ if ( rightHighlightRef . current ) {
363+ rightHighlightRef . current . position . x = 0.26 + anim . eyeLookX * 0.8 ;
364+ rightHighlightRef . current . position . y = 0.02 + anim . eyeLookY * 0.8 ;
365+ }
366+
331367 // ---- 眉毛动画 ----
332368 let targetLeftBrowY = 0 ;
333369 let targetRightBrowY = 0 ;
@@ -531,16 +567,16 @@ function CyberAvatar() {
531567
532568 // 共享材质
533569 const skinMat = useMemo ( ( ) => (
534- < meshPhysicalMaterial color = "#e8edf5" metalness = { 0.3 } roughness = { 0.2 } clearcoat = { 1 } clearcoatRoughness = { 0.05 } envMapIntensity = { 2.5 } />
570+ < meshPhysicalMaterial color = "#e8edf5" metalness = { 0.25 } roughness = { 0.18 } clearcoat = { 1 } clearcoatRoughness = { 0.05 } envMapIntensity = { 2.8 } />
535571 ) , [ ] ) ;
536572 const armorMat = useMemo ( ( ) => (
537- < meshPhysicalMaterial color = "#1a2332 " metalness = { 0.9 } roughness = { 0.1 } clearcoat = { 1 } clearcoatRoughness = { 0.03 } envMapIntensity = { 2 } />
573+ < meshPhysicalMaterial color = "#151f2e " metalness = { 0.95 } roughness = { 0.08 } clearcoat = { 1 } clearcoatRoughness = { 0.025 } envMapIntensity = { 2.3 } />
538574 ) , [ ] ) ;
539575 const frameMat = useMemo ( ( ) => (
540- < meshStandardMaterial color = "#3a4a5c " metalness = { 0.85 } roughness = { 0.15 } />
576+ < meshStandardMaterial color = "#3f5266 " metalness = { 0.8 } roughness = { 0.18 } />
541577 ) , [ ] ) ;
542578 const glowCyan = useMemo ( ( ) => (
543- < meshStandardMaterial color = "#22d3ee" emissive = "#22d3ee" emissiveIntensity = { 3 } toneMapped = { false } />
579+ < meshStandardMaterial color = "#22d3ee" emissive = "#22d3ee" emissiveIntensity = { 3.2 } toneMapped = { false } />
544580 ) , [ ] ) ;
545581
546582 return (
@@ -598,29 +634,29 @@ function CyberAvatar() {
598634 < meshStandardMaterial color = "#e2e8f0" metalness = { 0.1 } roughness = { 0.3 } />
599635 </ mesh >
600636 { /* 虹膜 */ }
601- < mesh position = { [ - 0.24 , 0 , 0.12 ] } scale = { [ 1 , 1 , 0.3 ] } >
637+ < mesh ref = { leftIrisRef } position = { [ - 0.24 , 0 , 0.12 ] } scale = { [ 1 , 1 , 0.3 ] } >
602638 < sphereGeometry args = { [ 0.065 , 24 , 24 ] } />
603639 < meshStandardMaterial color = "#38bdf8" emissive = "#38bdf8" emissiveIntensity = { 2 } toneMapped = { false } />
604640 </ mesh >
605- < mesh position = { [ 0.24 , 0 , 0.12 ] } scale = { [ 1 , 1 , 0.3 ] } >
641+ < mesh ref = { rightIrisRef } position = { [ 0.24 , 0 , 0.12 ] } scale = { [ 1 , 1 , 0.3 ] } >
606642 < sphereGeometry args = { [ 0.065 , 24 , 24 ] } />
607643 < meshStandardMaterial color = "#38bdf8" emissive = "#38bdf8" emissiveIntensity = { 2 } toneMapped = { false } />
608644 </ mesh >
609645 { /* 瞳孔 */ }
610- < mesh position = { [ - 0.24 , 0 , 0.14 ] } scale = { [ 1 , 1 , 0.2 ] } >
646+ < mesh ref = { leftPupilRef } position = { [ - 0.24 , 0 , 0.14 ] } scale = { [ 1 , 1 , 0.2 ] } >
611647 < sphereGeometry args = { [ 0.035 , 16 , 16 ] } />
612648 < meshStandardMaterial color = "#0284c7" emissive = "#22d3ee" emissiveIntensity = { 5 } toneMapped = { false } />
613649 </ mesh >
614- < mesh position = { [ 0.24 , 0 , 0.14 ] } scale = { [ 1 , 1 , 0.2 ] } >
650+ < mesh ref = { rightPupilRef } position = { [ 0.24 , 0 , 0.14 ] } scale = { [ 1 , 1 , 0.2 ] } >
615651 < sphereGeometry args = { [ 0.035 , 16 , 16 ] } />
616652 < meshStandardMaterial color = "#0284c7" emissive = "#22d3ee" emissiveIntensity = { 5 } toneMapped = { false } />
617653 </ mesh >
618654 { /* 高光点 */ }
619- < mesh position = { [ - 0.22 , 0.02 , 0.15 ] } >
655+ < mesh ref = { leftHighlightRef } position = { [ - 0.22 , 0.02 , 0.15 ] } >
620656 < sphereGeometry args = { [ 0.012 , 8 , 8 ] } />
621657 < meshBasicMaterial color = "#ffffff" />
622658 </ mesh >
623- < mesh position = { [ 0.26 , 0.02 , 0.15 ] } >
659+ < mesh ref = { rightHighlightRef } position = { [ 0.26 , 0.02 , 0.15 ] } >
624660 < sphereGeometry args = { [ 0.012 , 8 , 8 ] } />
625661 < meshBasicMaterial color = "#ffffff" />
626662 </ mesh >
0 commit comments