Vytvoření morfovací 3D koule v Javascriptu pomocí Three.js

Miluji 3D efekty na internetu a jsou stále více všude. Mohou přidat webu další rozměr, který pomůže upoutat pozornost uživatele. Již dříve jsem pokryl 3D efekty pomocí karet WebGL, které jsem vytvořil, ale v této příručce jsem chtěl vytvořit morfující kouli se skvělým drátěným pozadím. Efekt je svým způsobem hypnotizující, takže má všechny šance udržet uživatele na vaší stránce déle!

Prostřednictvím tohoto tutoriálu vám také pomůžu pochopit základy fungování 3D efektů na webu. Začněme.

Zde je ukázka:

Vytvoření 3D morfující koule

Nástroj, který používám pro přístup k funkcím WebGL v prohlížeči, se nazývá three.js. Je to balíček, který zjednodušuje proces provádění 3D práce v prohlížeči – a k tomu používá canvas . Toto připojíme prostřednictvím kódu později.

Je důležité pochopit, že three.js nám jednoduše poskytuje rozhraní pro práci s WebGL, což je API pro vykreslování 2D a 3D objektů na webu. proto budeme jako další importovat tři.js. Můžete to udělat pomocí npm . Dvě věci, které zde budeme chtít nainstalovat, jsou následující:

npm i three
npm i open-simplex-noise
npm install three-orbitcontrols

Po instalaci je importujte do svého kódu. Protože jsem dělal demo na codepen, importoval jsem je pomocí skypack. Tyto tři funkce nám umožní provést tři (nezamýšlená slovní hříčka) věci:

  • použijte 3D tvary na webu (tři)
  • ovládání kamery (ovládání na tři oběžné dráhy)
  • vytvářet šum a náhodnost (open-simplex-noise)
import * as THREE from "https://cdn.skypack.dev/[email protected]";
import { OrbitControls } from "https://cdn.skypack.dev/[email protected]/examples/jsm/controls/OrbitControls.js";
import openSimplexNoise from 'https://cdn.skypack.dev/open-simplex-noise';

Nastavení naší scény pro 3D objekty v three.js

Poté, co jsme importovali naše balíčky, chceme udělat několik věcí:

  • vytvořte novou scénu , aby naše 3D objekty seděly
  • vytvořit kameru , takže se můžeme podívat na naši scénu
  • vytvořte vykreslovací modul , a nastavte jeho velikost, abychom nezískali podivné neostré tvary
  • přidejte naše orbitální ovládací prvky , takže můžeme klikat a přetahovat náš objekt a pohybovat s ním
// Scene
let scene = new THREE.Scene();
// Camera
let camera = new THREE.PerspectiveCamera( 75, innerWidth / innerHeight, 0.1, 1000 );
camera.position.set(1.5, -0.5, 6);
// Renderer
let renderer = new THREE.WebGLRenderer({antialias: true, alpha: true});
renderer.setSize( innerWidth, innerHeight );
// Append our renderer to the webpage. Basically, this appends the `canvas` to our webpage.
document.body.appendChild( renderer.domElement );

new OrbitControls(camera, renderer.domElement);

Nyní může zábava začít a můžeme začít přidávat naše 3D tvary.

Přidání 3D tvarů do naší scény pomocí three.js

Na prvním místě je naše sféra. Každý objekt v three.js se skládá ze dvou částí – geometrie , což jsou vrcholy a trojúhelníky, které tvoří kouli, a síť , což jsou barvy, vzory a vlastnosti těchto vrcholů.

Protože chceme nakonec manipulovat se všemi našimi vrcholy, ukládám je všechny samostatně do positionData pole také. Použijeme bult v Vector3 funkce pro uložení sad 3D souřadnic do three.js.

// Create our geometry
let sphereGeometry = new THREE.SphereGeometry(1.5, 100, 100);

// This section is about accessing our geometry vertices and their locations
sphereGeometry.positionData = [];
let v3 = new THREE.Vector3();
for (let i = 0; i < sphereGeometry.attributes.position.count; i++){
    v3.fromBufferAttribute(sphereGeometry.attributes.position, i);
    sphereGeometry.positionData.push(v3.clone());
}

// A `normal` material uses the coordinates of an object to calculate its color
let sphereMesh = new THREE.MeshNormalMaterial();

// Combine both, and add it to the scene.
let sphere = new THREE.Mesh(sphereGeometry, sphereMesh);
scene.add(sphere);

Místo toho používat vlastní shadery

Nyní jeden Upozornění:rozhodl jsem se, že svou kouli trochu přizpůsobím, a k tomu jsem použil shadery . Když tedy zavoláme MeshNormalMaterial , ve skutečnosti dělá něco pro web trochu neobvyklého. K výpočtu barvy jednotlivých vrcholů používá něco, čemu se říká shadery.

Existují dva typy shaderů, fragment , což jsou v podstatě barvy objektu, a vertex , což je poloha vrcholů na tomto tvaru. Tyto shadery jsou napsány v GLSL nebo OpenGL Shading Language - tedy ne Javascript. Nebudu zabíhat do podrobností o tom, jak tento jazyk funguje, ale je to trochu více jako C než Javascript.

Základy jsou:

  • Namísto použití MeshNormalMaterial , můžeme použít ShaderMaterial a vytvářet naše vlastní shadery.
  • Použijeme Normální materiál shadery – dojde tedy ke stejnému efektu, ale mít je v našem kódu znamená, že jej můžeme později aktualizovat – například změnit barvy.
  • Proměnné Javascriptu můžeme předávat do shaderu v reálném čase pomocí uniforms , které jsou speciálním typem proměnných v GLSL.

To znamená, že definujeme naši GLSL v HTML a vtáhneme ji pomocí selektoru Javascriptu. Poznámka :V porovnání s MeshNormalMaterial jsem v těchto shaderech neprovedl žádné skutečné změny - jediný rozdíl je, že předávám barvu jako uniformu . To znamená, že pokud chceme, můžeme tuto hodnotu změnit z Javascriptu. Zde ukážu pouze fragment shader, ale oba lze nalézt v sekci HTML na codepen. Upozornění že definuji uniform vec3 colorA - to je proměnná, kterou budeme používat z našeho Javascriptu!

Nakonec shadery provádějí manipulaci s každým pixelem našeho 3D objektu na základě toho, co jim řekneme, aby udělali. Jsou výpočetně drahé, ale mohou vytvořit docela skvělé efekty.

<script id="fragment" type="text/glsl">
uniform vec3 colorA;
#define NORMAL
#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )
    varying vec3 vViewPosition;
#endif

#include <packing>
#include <uv_pars_fragment>
#include <normal_pars_fragment>
#include <bumpmap_pars_fragment>
#include <normalmap_pars_fragment>
#include <logdepthbuf_pars_fragment>
#include <clipping_planes_pars_fragment>

void main() {
    #include <clipping_planes_fragment>
    #include <logdepthbuf_fragment>
    #include <normal_fragment_begin>
    #include <normal_fragment_maps>

    gl_FragColor = vec4( normalize( normal ) * colorA + 0.5, 1.0 );

    #ifdef OPAQUE
        gl_FragColor.a = 1.0;
    #endif 
}
</script>

Jak fungují normální shadery

Normální shader vypočítá barvu pixelu výpočtem normalize( normal ) * 0.5 + 0.5 . Jako takový můžeme vyměnit první 0.5 pro vlastní barvu, což je naše uniforma colorA . Oba tyto vertexové a fragmentové shadery pak můžeme přidat do našeho Javascriptu takto:

let sphereMesh = new THREE.ShaderMaterial({
    uniforms: {      
        colorA: {type: 'vec3', value: new THREE.Vector3(0.5, 0.5, 0.5)},

    },
    vertexShader: document.getElementById('vertex').textContent,
    fragmentShader: document.getElementById('fragment').textContent,
});

Při učení WebGL je důležité vědět, že to takhle funguje pod kapotou. Shadery jsou pro dělání věcí ve 3D opravdu důležité – je tedy dobré vědět, jak je definovat a manipulovat s nimi.

Manipulace s geometrií naší sféry

Poté můžeme vytvořit hodiny three.js pro sledování času. Tento čas využíváme k vytváření šumu pomocí naší importované funkce šumu. Šum je jen náhodnost, která pomůže vytvořit efekt náhodně se měnící koule. Poté nám three.js také poskytuje funkci pro přidání klíčových snímků animace a k animaci této koule můžeme použít výše uvedené hodiny three.js.

let noise = openSimplexNoise.makeNoise4D(Date.now());
let clock = new THREE.Clock();

renderer.setAnimationLoop( () => {
    // Get the time
    let t = clock.getElapsedTime();
    sphereGeometry.positionData.forEach((p, idx) => {
        // Create noise for each point in our sphere
        let setNoise = noise(p.x, p.y, p.z, t * 1.05);
        // Using our Vector3 function, copy the point data, and multiply it by the noise
        // this looks confusing - but it's just multiplying noise by the position at each vertice
        v3.copy(p).addScaledVector(p, setNoise);
        // Update the positions
        sphereGeometry.attributes.position.setXYZ(idx, v3.x, v3.y, v3.z);
    })
    // Some housekeeping so that the sphere looks "right"
    sphereGeometry.computeVertexNormals();
    sphereGeometry.attributes.position.needsUpdate = true;
    // Render the sphere onto the page again.
    renderer.render(scene, camera);
})

Nyní se naše koule začne morfovat! Zopakoval jsem to i pro rovinu za koulí. Použil jsem BoxGeometry tady, jen se základní sítí, to vypadá jako drátěný model. Kód pro tento bit je spolu se vším ostatním dostupný na CodePen.

Závěr

Vytváření 3D tvarů na webu je skvělá dovednost frontendu. Přestože v CSS a HTML lze udělat mnoho, některých efektů lze dosáhnout pouze prostřednictvím 3D a three.js poskytuje perfektní platformu, na které to lze udělat. Doufám, že se vám tento rychlý průvodce vytvořením 3D morfovací koule v three.js a Javascriptu líbil. Pokud byste chtěli více obsahu Javascript, můžete si přečíst všechny mé další věci zde.


No