mirror of
https://github.com/R0m1k3/EveFlow.git
synced 2026-10-18 04:38:54 +02:00
Améliore le visuel de l'avatar Eve — lissage géométrique et couvertures de jointures
- Fusion de vertices plus agressive (corps 0.08, bras 0.07, tête 0.08) - Matériau laque blanche unifié : emissiveIntensity 0.16, clearcoat 1.0 - Matériau tête dédié : emissiveIntensity 0.28 pour effacer les ombres aux seams - Collar élargi (tube 0.14), cylindre de cou ajouté, épaulières agrandies (scale Z 0.56) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
d77ace03cd
169 files changed
+83033
No files matched your search
@@ -0,0 +1,97 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { useFrame, useLoader } from '@react-three/fiber';
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
import * as THREE from 'three';
|
||||
import { EveModel } from './EveModel';
|
||||
import { EveAvatar, EveEmotion, EmotionService } from '../services/emotionService';
|
||||
|
||||
interface AvatarModelLoaderProps {
|
||||
avatarId: EveAvatar;
|
||||
emotion: EveEmotion;
|
||||
isSpeaking: boolean;
|
||||
}
|
||||
|
||||
type AvatarManifest = Partial<Record<Exclude<EveAvatar, 'eve'>, string | null>>;
|
||||
|
||||
const AVATAR_MANIFEST_PATH = '/avatars/avatar-manifest.json';
|
||||
|
||||
const LoadedGlbAvatar: React.FC<{
|
||||
path: string;
|
||||
avatarId: EveAvatar;
|
||||
emotion: EveEmotion;
|
||||
isSpeaking: boolean;
|
||||
}> = ({ path, avatarId, emotion, isSpeaking }) => {
|
||||
const gltf = useLoader(GLTFLoader, path);
|
||||
const scene = useMemo(() => gltf.scene.clone(true), [gltf.scene]);
|
||||
|
||||
useEffect(() => {
|
||||
const style = EmotionService.getEmotionStyle(emotion, avatarId);
|
||||
scene.traverse((child) => {
|
||||
if (!(child instanceof THREE.Mesh)) return;
|
||||
child.castShadow = false;
|
||||
child.receiveShadow = false;
|
||||
|
||||
const materialName = Array.isArray(child.material)
|
||||
? child.material.map((material) => material.name).join(' ')
|
||||
: child.material?.name || '';
|
||||
|
||||
if (/eye|led|visor|screen|emissive/i.test(`${child.name} ${materialName}`)) {
|
||||
const eyeMaterial = new THREE.MeshBasicMaterial({
|
||||
color: new THREE.Color(style.eyeColor),
|
||||
transparent: true,
|
||||
opacity: 0.96
|
||||
});
|
||||
child.material = eyeMaterial;
|
||||
}
|
||||
});
|
||||
}, [avatarId, emotion, scene]);
|
||||
|
||||
useFrame((state) => {
|
||||
const t = state.clock.getElapsedTime();
|
||||
scene.position.y = Math.sin(t * 1.4) * 0.05 - 0.28;
|
||||
scene.rotation.y = Math.sin(t * 0.45) * 0.05;
|
||||
|
||||
if (isSpeaking) {
|
||||
scene.rotation.z = Math.sin(t * 8) * 0.025;
|
||||
} else {
|
||||
scene.rotation.z = THREE.MathUtils.lerp(scene.rotation.z, 0, 0.12);
|
||||
}
|
||||
});
|
||||
|
||||
return <primitive object={scene} scale={1} />;
|
||||
};
|
||||
|
||||
export const AvatarModelLoader: React.FC<AvatarModelLoaderProps> = ({ avatarId, emotion, isSpeaking }) => {
|
||||
const [assetPath, setAssetPath] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
setAssetPath(null);
|
||||
|
||||
if (avatarId === 'eve') return;
|
||||
|
||||
fetch(AVATAR_MANIFEST_PATH, { cache: 'no-store' })
|
||||
.then((response) => {
|
||||
if (!response.ok) return null;
|
||||
return response.json() as Promise<AvatarManifest>;
|
||||
})
|
||||
.then((manifest) => {
|
||||
if (cancelled || !manifest) return;
|
||||
const nextAssetPath = manifest[avatarId];
|
||||
setAssetPath(typeof nextAssetPath === 'string' && nextAssetPath.trim() ? nextAssetPath : null);
|
||||
})
|
||||
.catch(() => {
|
||||
if (!cancelled) setAssetPath(null);
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [avatarId]);
|
||||
|
||||
if (avatarId !== 'eve' && assetPath) {
|
||||
return <LoadedGlbAvatar path={assetPath} avatarId={avatarId} emotion={emotion} isSpeaking={isSpeaking} />;
|
||||
}
|
||||
|
||||
return <EveModel emotion={emotion} isSpeaking={isSpeaking} avatarId="eve" />;
|
||||
};
|
||||
Reference in new issue
Block a user