Spaces:
Running
Running
SamiKoen commited on
Commit ·
6b7e121
1
Parent(s): be74369
Trek logosu artik 3D plane mesh, Spine bone'a attach edili — avatar ile birlikte hareket eder. SVG runtime canvas->beyaza cevriliyor
Browse files- static/index.html +86 -14
static/index.html
CHANGED
|
@@ -46,19 +46,6 @@
|
|
| 46 |
border-color: rgba(52,211,153,0.7);
|
| 47 |
box-shadow: 0 0 30px rgba(52,211,153,0.35);
|
| 48 |
}
|
| 49 |
-
.trek-logo {
|
| 50 |
-
position: absolute;
|
| 51 |
-
bottom: 17%;
|
| 52 |
-
left: 50%;
|
| 53 |
-
transform: translateX(-50%);
|
| 54 |
-
width: clamp(70px, 22%, 110px);
|
| 55 |
-
height: auto;
|
| 56 |
-
/* SVG'yi siyahtan beyaza cevir + drop shadow */
|
| 57 |
-
filter: brightness(0) invert(1) drop-shadow(0 1px 2px rgba(0,0,0,0.5));
|
| 58 |
-
pointer-events: none;
|
| 59 |
-
z-index: 5;
|
| 60 |
-
user-select: none;
|
| 61 |
-
}
|
| 62 |
.loading {
|
| 63 |
position: absolute;
|
| 64 |
inset: 0;
|
|
@@ -135,7 +122,6 @@
|
|
| 135 |
<div class="stage">
|
| 136 |
<canvas id="avatarCanvas"></canvas>
|
| 137 |
<div id="ring" class="ring"></div>
|
| 138 |
-
<img class="trek-logo" src="/static/trek-logo.svg" alt="Trek" />
|
| 139 |
<div id="loading" class="loading">
|
| 140 |
<div class="spinner"></div>
|
| 141 |
<div>Avatar yukleniyor...</div>
|
|
@@ -169,6 +155,7 @@ let scene, camera, renderer, clock;
|
|
| 169 |
let avatar = null;
|
| 170 |
let morphMeshes = []; // Morph target'i olan TUM mesh'ler
|
| 171 |
let headBone = null;
|
|
|
|
| 172 |
|
| 173 |
// ----- Audio state -----
|
| 174 |
let ws = null;
|
|
@@ -293,11 +280,15 @@ async function loadAvatar() {
|
|
| 293 |
|
| 294 |
console.log('[avatar] bone sayisi:', allBones.length, '— head bone:', headBone?.name || 'YOK');
|
| 295 |
console.log('[avatar] morph mesh sayisi:', morphMeshes.length);
|
|
|
|
| 296 |
|
| 297 |
if (morphMeshes.length === 0) {
|
| 298 |
console.warn('[avatar] HIC morph target yok — bu avatar lip sync icin uygun degil');
|
| 299 |
}
|
| 300 |
|
|
|
|
|
|
|
|
|
|
| 301 |
// Avatar'i sahneye yerlestir (bel-yukari gorunum)
|
| 302 |
avatar.position.set(0, 0, 0);
|
| 303 |
scene.add(avatar);
|
|
@@ -305,6 +296,87 @@ async function loadAvatar() {
|
|
| 305 |
return true;
|
| 306 |
}
|
| 307 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 308 |
// ============================================================
|
| 309 |
// Animasyon dongusu — lip sync, blink, idle
|
| 310 |
// ============================================================
|
|
|
|
| 46 |
border-color: rgba(52,211,153,0.7);
|
| 47 |
box-shadow: 0 0 30px rgba(52,211,153,0.35);
|
| 48 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
.loading {
|
| 50 |
position: absolute;
|
| 51 |
inset: 0;
|
|
|
|
| 122 |
<div class="stage">
|
| 123 |
<canvas id="avatarCanvas"></canvas>
|
| 124 |
<div id="ring" class="ring"></div>
|
|
|
|
| 125 |
<div id="loading" class="loading">
|
| 126 |
<div class="spinner"></div>
|
| 127 |
<div>Avatar yukleniyor...</div>
|
|
|
|
| 155 |
let avatar = null;
|
| 156 |
let morphMeshes = []; // Morph target'i olan TUM mesh'ler
|
| 157 |
let headBone = null;
|
| 158 |
+
let logoMesh = null; // Avatar gogsune attach edilen Trek logosu
|
| 159 |
|
| 160 |
// ----- Audio state -----
|
| 161 |
let ws = null;
|
|
|
|
| 280 |
|
| 281 |
console.log('[avatar] bone sayisi:', allBones.length, '— head bone:', headBone?.name || 'YOK');
|
| 282 |
console.log('[avatar] morph mesh sayisi:', morphMeshes.length);
|
| 283 |
+
console.log('[avatar] tum bone isimleri:', allBones);
|
| 284 |
|
| 285 |
if (morphMeshes.length === 0) {
|
| 286 |
console.warn('[avatar] HIC morph target yok — bu avatar lip sync icin uygun degil');
|
| 287 |
}
|
| 288 |
|
| 289 |
+
// Trek logosunu avatar gogsune attach et (3D, avatar ile birlikte hareket eder)
|
| 290 |
+
await attachTrekLogo();
|
| 291 |
+
|
| 292 |
// Avatar'i sahneye yerlestir (bel-yukari gorunum)
|
| 293 |
avatar.position.set(0, 0, 0);
|
| 294 |
scene.add(avatar);
|
|
|
|
| 296 |
return true;
|
| 297 |
}
|
| 298 |
|
| 299 |
+
// ============================================================
|
| 300 |
+
// Trek logosunu avatar gogsune ekle (3D, bone'a attach)
|
| 301 |
+
// ============================================================
|
| 302 |
+
async function loadLogoTexture() {
|
| 303 |
+
return new Promise((resolve) => {
|
| 304 |
+
const img = new Image();
|
| 305 |
+
img.crossOrigin = 'anonymous';
|
| 306 |
+
img.onload = () => {
|
| 307 |
+
const canvas = document.createElement('canvas');
|
| 308 |
+
const aspect = img.height / img.width;
|
| 309 |
+
canvas.width = 1024;
|
| 310 |
+
canvas.height = Math.round(1024 * aspect);
|
| 311 |
+
const ctx = canvas.getContext('2d');
|
| 312 |
+
// SVG'yi cizdir, sonra source-in ile beyaz fill — siyah logoyu beyaza cevirir
|
| 313 |
+
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
| 314 |
+
ctx.globalCompositeOperation = 'source-in';
|
| 315 |
+
ctx.fillStyle = '#ffffff';
|
| 316 |
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
| 317 |
+
const texture = new THREE.CanvasTexture(canvas);
|
| 318 |
+
texture.colorSpace = THREE.SRGBColorSpace;
|
| 319 |
+
texture.anisotropy = 16;
|
| 320 |
+
texture.needsUpdate = true;
|
| 321 |
+
resolve({ texture, aspect });
|
| 322 |
+
};
|
| 323 |
+
img.onerror = (e) => { console.error('[logo] yukleme hatasi:', e); resolve(null); };
|
| 324 |
+
img.src = '/static/trek-logo.svg';
|
| 325 |
+
});
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
+
async function attachTrekLogo() {
|
| 329 |
+
const result = await loadLogoTexture();
|
| 330 |
+
if (!result || !avatar) return;
|
| 331 |
+
const { texture, aspect } = result;
|
| 332 |
+
|
| 333 |
+
// Avatar'in gogus bone'unu bul (Spine2 > Spine1 > Spine > Chest > vb)
|
| 334 |
+
const candidates = ['Spine2', 'Spine1', 'Spine', 'Chest', 'spine2', 'spine1', 'spine'];
|
| 335 |
+
let chestBone = null;
|
| 336 |
+
for (const name of candidates) {
|
| 337 |
+
chestBone = avatar.getObjectByName(name);
|
| 338 |
+
if (chestBone) break;
|
| 339 |
+
}
|
| 340 |
+
// Mixamo prefix'i de dene
|
| 341 |
+
if (!chestBone) {
|
| 342 |
+
avatar.traverse((obj) => {
|
| 343 |
+
if (chestBone) return;
|
| 344 |
+
if (obj.isBone) {
|
| 345 |
+
const n = obj.name.toLowerCase();
|
| 346 |
+
if (n.includes('spine2') || n.includes('chest')) chestBone = obj;
|
| 347 |
+
}
|
| 348 |
+
});
|
| 349 |
+
}
|
| 350 |
+
console.log('[logo] gogus bone:', chestBone?.name || 'YOK');
|
| 351 |
+
|
| 352 |
+
if (!chestBone) {
|
| 353 |
+
console.warn('[logo] gogus bone bulunamadi, logo eklenmedi');
|
| 354 |
+
return;
|
| 355 |
+
}
|
| 356 |
+
|
| 357 |
+
const logoWidth = 0.13;
|
| 358 |
+
const logoGeometry = new THREE.PlaneGeometry(logoWidth, logoWidth * aspect);
|
| 359 |
+
const logoMaterial = new THREE.MeshBasicMaterial({
|
| 360 |
+
map: texture,
|
| 361 |
+
transparent: true,
|
| 362 |
+
side: THREE.DoubleSide,
|
| 363 |
+
depthTest: true,
|
| 364 |
+
depthWrite: false,
|
| 365 |
+
});
|
| 366 |
+
logoMesh = new THREE.Mesh(logoGeometry, logoMaterial);
|
| 367 |
+
|
| 368 |
+
// Bone local space'inde gogus on tarafina yerlestir
|
| 369 |
+
// (bone tipik olarak omurga boyunca yukari uzanir, +Z genelde on tarafa bakar)
|
| 370 |
+
logoMesh.position.set(0, 0.08, 0.085);
|
| 371 |
+
// Plane bone'a paralel olsun diye rotation
|
| 372 |
+
logoMesh.rotation.set(0, 0, 0);
|
| 373 |
+
// Tisirtin yuzeyinden cok hafif onde dursun (z-fight onleme)
|
| 374 |
+
logoMesh.renderOrder = 10;
|
| 375 |
+
|
| 376 |
+
chestBone.add(logoMesh);
|
| 377 |
+
console.log('[logo] yerlestirildi:', chestBone.name);
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
// ============================================================
|
| 381 |
// Animasyon dongusu — lip sync, blink, idle
|
| 382 |
// ============================================================
|