Hasan Alp Güngör

· Hasan Alp Güngör

Hvordan jeg gjorde logoen min om til 3D-glass som går i biter når du scroller

Hva som ligger bak glasslogoen på porteføljen min: å tegne opp logoen, dele den i sju biter, få glasset til å fungere og få det til å gå jevnt på svake mobiler.

Porteføljen min startet med en 3D-spillkontroller. Så bestemte jeg meg for å bruke min egen logo i stedet, og jeg ville ha det sånn: når siden åpnes, er logoen hel, når du scroller, sprekker den først og går så i biter, og hver bit viser én av ferdighetene mine. I dette innlegget forteller jeg hvordan jeg lagde det.

1. Fra bilde til form

Alt jeg hadde, var et bilde av logoen, og 3D trenger hjørnepunkter. Jeg gjorde bildet svart-hvitt med OpenCV, hentet ut konturene, forenklet bort unødvendige punkter og skalerte alt til 2,6 enheter høyt. Igjen satt jeg med én ytre kontur og de åtte hullene inni logoen.

Å kutte logoen med rette linjer så kunstig ut, så jeg tegnet takkete "sprekk"-linjer og delte logoen langs dem med shapely. Det ga sju biter som faktisk ser knust ut: web, C# og Java, 3D, Python, spillutvikling, maskinvare og backend.

Jeg ga hver bit dybde med ExtrudeGeometry fra three.js og la til en bevel på kantene. Det er de avrundede kantene som fanger lyset i glasseffekten.

2. Glass uten noe bak seg

Til glasset brukte jeg MeshTransmissionMaterial fra drei, som etterligner glass ved å bøye scenen bak seg. Men det var et problem: den sølvfargede bakgrunnen på siden ligger ikke i 3D-scenen, den er tegnet med CSS. 3D-scenen bak logoen var tom, så glasset hadde ingenting å bøye, og det så ut som flat, grå plast.

Løsningen ble å tegne en kopi av bakgrunnen på nytt med en shader. Hver frame skjuler jeg logoen, tegner bakgrunnen inn i en buffer utenfor skjermen (en FBO) og gir bufferen til materialet som det som ligger bak. Nå bøyer glasset det sølvfargede lyset bak siden. Oppå det la jeg til en egen fresnel-shader som får kantene til å lyse hvitt.

3. Historien i scrollingen

Jeg koblet stillingen til logoen til scrollposisjonen med GSAP ScrollTrigger. Det er noen faste stillinger (hel, sprukket, sprengt, snudd), og når du scroller, glir den mellom dem. Etikettene på bitene er vanlig HTML: hver frame projiserer jeg 3D-posisjonen til biten ned på skjermen og flytter etiketten dit.

Den mest irriterende buggen dukket opp her: når jeg scrollet helt tilbake til toppen, forsvant logoen. Grunnen var at jeg hadde satt start på ScrollTrigger til "top top". Ved scroll 0 ble ikke triggeren regnet som aktiv, og jeg stoppet renderingen når den ikke var aktiv. Det løste seg da jeg endret start til "top bottom".

4. Svake mobiler

Glasseffekten er tung, så når siden åpnes, sjekker den enheten og velger ett av tre kvalitetsnivåer:

  • Høy: full glasseffekt med skarpere oppløsning
  • Middels: for mobiler og enheter med 4 GB minne eller mindre; glasset bruker færre samples
  • Lett: når datasparing er på eller enheten er veldig svak; et enkelt, gjennomskinnelig materiale i stedet for glasseffekten

I tilfelle gjetningen er feil, begynner siden å følge med på bildefrekvensen etter noen sekunder, og hvis den ligger under 30 bilder per sekund, går den ned et nivå av seg selv.

tsfunction detect(): Quality {
  const nav = navigator as Navigator & { deviceMemory?: number; connection?: { saveData?: boolean } };
  const memory = nav.deviceMemory ?? 8;
  const cores = nav.hardwareConcurrency ?? 8;
  if (nav.connection?.saveData || memory <= 2 || cores <= 2) return 'lite';
  if (matchMedia('(pointer: coarse)').matches || memory <= 4 || cores <= 4) return 'medium';
  return 'high';
}

5. Glass som bølger under musepekeren

Til slutt ville jeg at glasset skulle bølge seg når musepekeren er over logoen. Jeg sender en stråle fra pekeren og sjekker om den treffer logoen. Gjør den det, forskyver jeg koordinatene rundt pekeren med en sinusbølge i bakgrunns-shaderen. Siden glasset bryter lyset fra den forvrengte bakgrunnen, dukker bølgen opp inni glasset.

glslvec2 toMouse = (uv - uMouse) * vec2(uAspect, 1.0);
float dist = length(toMouse);
float wave = sin(dist * 70.0 - uTime * 7.0) * exp(-dist * 7.0) * uHover;
uv += normalize(toMouse + 1e-5) * wave * 0.03;

Vil du se resultatet, er det bare å åpne forsiden og scrolle ned. All koden ligger åpent på GitHub.

Flere innlegg