04 2025-2026
In dit onderdeel herhalen we de basisprincipes van React Three Fiber, zodat we vertrouwd raken met de belangrijkste concepten van 3D-rendering in React. Zo bouwen we een stevig fundament om nadien zelf interactieve en visueel indrukwekkende 3D-ervaring te maken.
SETUP
01
01
SETUP
Hoe zetten we React Three Fiber op?
Voer volgende uit in de terminal
npm create vite@latestVolg deze stappen:
Vervolgens voer je deze install uit
npm install three @react-three/fiber01
SETUP
In het install-commando zie je een @ teken. Dit geeft aan dat de package deel uitmaakt van een groter geheel, namelijk React Three. De installatie is dus succesvol voltooid, en we kunnen nu verder met het opzetten van onze eerste scène.
SYNTAX
02
02
SYNTAX
Three Fiber maakt het werken met 3D in React een stuk eenvoudiger: in plaats van alles zelf te moeten opbouwen zoals in native Three.js, kun je hier gewoon gebruikmaken van bestaande componenten.
Native Three.js
const mesh = new THREE.Mesh()
mesh.geometry = new THREE.BoxGeometry(1, 1, 1)
mesh.material = new THREE.MeshBasicMaterial({ color: 'red' })
scene.add(mesh)R3F (React Three Fiber)
<mesh>
<boxGeometry />
<meshBasicMaterial color="red" />
</mesh>Omdat de geometry en het materiaal binnen onze mesh zitten, koppelt Fiber ze automatisch aan elkaar. De syntax is bovendien korteren overzichtelijker.
02
SYNTAX
In vanilla Three.js was het aanpassen van positie en rotatie wat ingewikkelder, maar in Fiber kunnen we dit gewoon rechtstreeks via props doen.
Native Three.js
const mesh = new THREE.Mesh()
mesh.position.set(1, 2, 3)
mesh.rotation.x = 0.5
mesh.geometry = new THREE.BoxGeometry(1, 1, 1)
mesh.material = new THREE.MeshBasicMaterial({ color: 'red' })
scene.add(mesh)R3F (React Three Fiber)
<mesh position={ [ 1, 2, 3 ] } rotation-x={ 0.5 }>
<boxGeometry />
<meshBasicMaterial color="red" />
</mesh>02
SYNTAX
Het is nu ook veel eenvoudiger om objecten in elkaar te nesten of te groeperen, zodat je makkelijk complexe 3D-structuren kunt opbouwen.
Native Three.js
const group = new THREE.Group()
scene.add(group)
const mesh1 = new THREE.Mesh()
mesh1.geometry = new THREE.BoxGeometry(1, 1, 1)
mesh1.material = new THREE.MeshBasicMaterial({ color: 'red' })
const mesh2 = new THREE.Mesh()
mesh2.geometry = new THREE.SphereGeometry(0.5)
mesh2.material = new THREE.MeshBasicMaterial({ color: 'orange' })
group.add(mesh1, mesh2)02
SYNTAX
R3F (React Three Fiber)
<group>
<mesh>
<boxGeometry />
<meshBasicMaterial color="red" />
</mesh>
<mesh>
<sphereGeometry />
<meshBasicMaterial color="orange" />
</mesh>
</group>Door de component-based aanpak zal je minder fouten maken of iets vergeten toe te voegen aan de scene.
02
SYNTAX
Werk je in React en wil je 3D toevoegen? Dan is R3F absoluut de makkelijkste keuze.
Gebruik je liever native Three.js, dan heb je wel meer vrijheid, maar ook veel meer werk — je moet namelijk alles zelf opbouwen.
OUR FIRST SCENE
03
03
OUR FIRST SCENE
Net zoals een schilder een canvas nodig heeft om zijn kunstwerk te creëren, hebben wij een Canvas nodig om onze 3D-ervaringen op te “schilderen”. Dit doen we met behulp van de Canvas-component.
Importeer Canvas via import en voeg daarna de component toe aan je index.tsx
import { Canvas } from '@react-three/fiber'
//...
createRoot(document.getElementById('root')!).render(
<StrictMode>
<Canvas></Canvas>
</StrictMode>,
)03
OUR FIRST SCENE
Mogelijks zie je nog niets (light mode) maar kijk eens naar de inspector?
We hebben effectief een html canvas-element in onze DOM-staan.
TIP: Bij het opstarten van een React project verwijder je best alle premade content en styling
03
OUR FIRST SCENE
Tijd om iets in onze canvas te plaatsen en te kijken of ze doet wat we verwachten!
Plaats tussen het Canvas element een mesh op volgende manier.
<Canvas>
<mesh>
<torusKnotGeometry />
<meshNormalMaterial />
</mesh>
</Canvas>03
OUR FIRST SCENE
We merken dat onze canvas niet het volledige scherm vult. Dit kunnen we oplossen met behulp van CSS.
Voeg volgende toe aan index.css
html,
body,
#root
{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}Onze canvas neemt nu het volledige scherm in. Dit is ideaal wanneer je een volledige 3D-ervaring wilt creëren. Als dat niet het geval is, kun je de CSS aanpassen aan de behoeften van je applicatie.
03
OUR FIRST SCENE
In plaats van alles in main.tsx te plaatsen, werken we met overzichtelijke componenten. Maak een Experience-component aan waarin onze 3D-ervaring zal komen.
In onze main.tsx zou je dus enkel volgende moeten zien.
import Experience from './Experience'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<Canvas>
<Experience />
</Canvas>
</StrictMode>,
)03
OUR FIRST SCENE
Plaats de 3D elementen in je Experience tussen een fragment (<> </>)
import './Experience.css'
function Experience() {
return (
<>
<mesh>
<torusKnotGeometry />
<meshNormalMaterial />
</mesh>
</>
)
}
export default ExperienceExperience.tsx ziet er als volgt uit.
MESHES
04
04
MESHES
In Three.js (en dus ook in R3F) hebben we verschillende soorten geometries en materials.
04
MESHES
We hoeven onze meshes niet telkens handmatig te importeren. Deze manier van werken heet declarative. React Three Fiber (R3F) begrijpt automatisch welk element we willen gebruiken en voegt het toe aan onze scene.
Verander de mesh van Torus naar Sphere in Experience.tsx
<mesh>
<sphereGeometry />
<meshBasicMaterial />
</mesh>Weet je niet welke props deze geometry aanvaard? Bekijk dan zeker de documentatie
Met args kunnen we de eigenschappen van onze objecten aanpassen. Laten we bijvoorbeeld de sphere vergroten.
<mesh>
<sphereGeometry args={ [ 1.5, 32, 32 ] } />
<meshBasicMaterial />
</mesh>De volgorde van de args zijn degene die in de originele three.js class staan.
04
MESHES
Een andere optie in R3F is om properties los van elkaar te definiëren. Dit maakt de code overzichtelijker: we geven simpelweg de propertynaam en de gewenste waarde op.
Verander de kleur van de material en activeer 'wireframe'.
<mesh>
<sphereGeometry args={ [ 1.5, 32, 32 ] } />
<meshBasicMaterial color="royalblue" wireframe />
</mesh>Wanneer je wireframe toevoegt, wordt dit automatisch op true gezet. Wil je het uitschakelen, dan kun je false meegeven, maar dat is standaard al het geval en kan dus worden weggelaten.
<mesh>
<sphereGeometry args={ [ 1.5, 32, 32 ] } />
<meshBasicMaterial color="royalblue" wireframe={false} />
</mesh>04
MESHES
We veranderen onze mesh naar een boxGeometry en bekijken hoe we de properties afzonderlijk kunnen instellen.
Verander de code in Experience.tsx naar volgende
<mesh>
<boxGeometry />
<meshBasicMaterial color="royalblue" wireframe />
</mesh>Net zoals bij het aanpassen van de kleur of het inschakelen van wireframe, kunnen we ook de scale, position en rotation van onze mesh eenvoudig wijzigen.
<mesh scale={ [ 3, 2, 1 ] }>
<boxGeometry />
<meshBasicMaterial color="royalblue" wireframe />
</mesh>04
MESHES
Als we een mesh uniform willen schalen, roteren of positioneren, hoeven we slechts één waarde op te geven. Deze wordt dan voor x, y en z gebruikt.
Verander de scale van de mesh naar volgende
<mesh scale={ 1.5 }>Verander de position van de mesh door volgende uit te voeren
<mesh position={ [ 2, 0, 0 ] } scale={ 1.5 }>Stel dat je enkel de x-as wil veranderen dan kan je volgende doen
<mesh position-x={ 2 } scale={ 1.5 }>04
MESHES
Hetzelfde geldt voor rotation. Houd er rekening mee dat je bij rotaties altijd gebruikmaakt van Math.PI.
Roteer de Cube op de y-as door volgende aan te passen.
<mesh rotation-y={ Math.PI * 0.25 } position-x={ 2 } scale={ 1.5 }>Hier komt uitleg over MATH.PI en de waarden (tabel?)
04
MESHES
Probeer nu zelf eens volgende scene te maken in R3F.
"Creëer een scene met drie planes. Op elke plane plaats je een verschillende vorm: bijvoorbeeld een cirkel, een driehoek en een vierkant — de keuze van de geometry is aan jou. Geef elke vorm een eigen kleur, maar houd de planes uniform van kleur."
ANIMATION
05
05
ANIMATION
Een statische kubus is leuk, maar het wordt pas interessant als hij kan bewegen. Daarvoor gebruiken we de useFrame-hook van R3F.
React tekent elk frame, waardoor onze kubus zichtbaar blijft. In gamingtermen noemen we dit FPS (Frames per Second). Met de useFrame-hook kun je code uitvoeren bij elke frame, oftewel bij elke “tick”.
Voer volgende code uit in Experience.tsx en kijk naar de console.
import { useFrame } from '@react-three/fiber'
export default function Experience()
{
useFrame(() =>
{
console.log('tick')
})
// ...
}05
ANIMATION
Omdat een tick bij elk frame loopt, kunnen we nu de kubus laten roteren. Om dit te doen, hebben we eerst een referentie naar de kubus nodig.
Plaats een ref op de mesh zodat we deze kunnen aanspreken
import { useRef } from 'react'
import * as THREE from 'three'
export default function Experience()
{
const cubeRef = useRef<THREE.Mesh>(null)
// ...
}
<mesh ref={ cubeRef } rotation-y={ Math.PI * 0.25 } position-x={ 2 } scale={ 1.5 }>Vervolgens kunnen we onze ref gebruiken in de useFrame hook.
useFrame(() =>
{
cubeRef.current.rotation.y += 0.01
})05
ANIMATION
Misschien valt het je op dat de kubus van je buur sneller of langzamer draait dan die van jou. Dat komt doordat apparaten verschillende framerates hebben. Door delta te gebruiken in plaats van een vaste rotatiewaarde, maak je de beweging framerate-onafhankelijk.
Voeg volgende code in Experience.tsx
useFrame((state, delta) =>
{
console.log(delta)
cubeRef.current.rotation.y += delta
})05
ANIMATION
Je kunt niet alleen losse elementen animeren, maar ook hele groepen tegelijk. Zet de meshes in een group en maak een referentie naar die group om ze gezamenlijk te manipuleren.
Plaats de elementen in een group wrapper
<group>
<mesh position-x={ - 2 }>
<sphereGeometry />
<meshBasicMaterial color="orange" />
</mesh>
<mesh ref={ cubeRef } rotation-y={ Math.PI * 0.25 } position-x={ 2 } scale={ 1.5 }>
<boxGeometry />
<meshBasicMaterial color="royalblue" />
</mesh>
</group>05
ANIMATION
Maak een groupRef aan en plaats deze op de group.
export default function Experience()
{
const cubeRef = useRef<THREE.Mesh>(null)
const groupRef = useRef<THREE.Group>(null)
// ...
<group ref={ groupRef }>
}Animeer nu de groupRef door ook zijn rotatie aan te spreken.
useFrame((_, delta) =>
{
if(!cubeRef.current || !groupRef.current) return
cubeRef.current.rotation.y += delta
groupRef.current.rotation.y += delta
})CONTROLS
06
We stappen nu over op een package die ons extra “powers” geeft: Drei.
Voer volgende install in de terminal
npm install @react-three/drei06
CONTROLS
We zien onze scene verschijnen, maar voorlopig kunnen we er niet in rondbewegen of omheen draaien. Dat lossen we op met controls — en daarvan zijn er verschillende types:
06
CONTROLS
De OrbitControls laten ons met de muis vrij rondkijken in onze scene. Normaal gezien is dat best wat werk om zelf op te zetten, maar met Drei gaat het supersimpel.
Importeer OrbitControls en plaats het in de jsx rendering (bovenaan)
import { OrbitControls } from '@react-three/drei'
export default function Experience()
{
return <>
<OrbitControls />
{/* ... */}
</>
}06
CONTROLS
Als je met de muis rond de scene draait en loslaat, merk je dat de beweging nog even zachtjes doorgaat. Dat effect heet damping. In de 3D-wereld zorgt het voor een vloeiendere ervaring, maar je kunt het ook uitschakelen als je liever directe controle hebt.
Verander volgende in de OrbitControls component.
<OrbitControls enableDamping={ false } />06
CONTROLS
We houden damping aan, want we willen dat vloeiende gevoel behouden. De eigenschap enableDamping kunnen we gerust weglaten — die staat standaard al op true.
<OrbitControls />Met dit soort controls kunnen we echt “spelen” met onze objecten in de 3D-omgeving. Het doet een beetje denken aan Blender, waar je objecten kunt verplaatsen langs de assen. Let op: je plaatst deze controls niet bovenaan in je scene, maar binnen de component die de objecten bevat die je wilt manipuleren.
Importeer de TransformControls en plaats hierin de mesh.
import { TransformControls, OrbitControls } from '@react-three/drei'
<TransformControls>
<mesh position-x={ 2 } scale={ 1.5 }>
<boxGeometry />
<meshStandardMaterial color="mediumpurple" />
</mesh>
</TransformControls>06
CONTROLS
Er vallen meteen twee dingen op:
De gizmo bevindt zich niet op ons object, maar in het midden van de scene.
Bewegen is nogal onhandig, want de camera draait mee terwijl we het object willen verplaatsen.
Er zijn twee manieren om dit probleem aan te pakken. De ene oplossing is iets eenvoudiger, de andere wat uitgebreider.
Oplossing 1: Plaats de offset van de mesh op de controls.
<TransformControls position-x={ 2 }>
<mesh scale={ 1.5 }>
<boxGeometry />
<meshStandardMaterial color="royalblue" />
</mesh>
</TransformControls>06
CONTROLS
Oplossing 2: Gebruik ref's om zo de positie aan te passen (best). Plaats de position-x terug op de mesh en verplaats de TransformControls onderaan.
<mesh position-x={ 2 } scale={ 1.5 }>
<boxGeometry />
<meshStandardMaterial color="royalblue" />
</mesh>
<TransformControls />De tweede oplossing is om een ref toe te voegen aan onze mesh — wat we doorgaans toch al doen — en die vervolgens door te geven aan de controls als het focusobject.
Maak een reference aan en plaats deze op de mesh.
import { useRef } from 'react'
export default function Experience()
{
const cube = useRef()
// ...
}
<mesh ref={ cube } position-x={ 2 } scale={ 1.5 }>06
CONTROLS
Assigneer nu de reference aan de TransformControls door de 'object' prop.
<TransformControls object={ cube } />Er is nog één klein probleem: terwijl we onze objecten verplaatsen, beweegt de camera nog steeds mee. Dankzij de handige functies van Drei kunnen we dat makkelijk oplossen. Door één control als default te markeren, krijgt die voorrang op de rest.
Geef onze OrbitControls de prop 'makeDefault'.
<OrbitControls makeDefault />06
CONTROLS
Klik je nu op de TransformControls, dan schakelen de OrbitControls automatisch uit. Op die manier beweegt de camera niet meer mee wanneer je een object wilt manipuleren — veel handiger!
De TransformControls hebben meerdere modi. Standaard staat deze op translate, maar je kunt net als in Blender ook kiezen voor rotate of scale.
Verander de TransformControls naar rotate en test uit.
<TransformControls object={ cube } mode="rotate" />06
CONTROLS
Verander de TransformControls naar scale en test uit.
<TransformControls object={ cube } mode="scale" />We zullen de controls terug naar translate plaatsen (of we laten het weg)
<TransformControls object={ cube } mode="translate" />Eigenlijk is PivotControls gewoon een alles-in-één versie van TransformControls. Het ziet er bovendien stijlvol uit, waardoor het minder “debugging-achtig” voelt en je het gerust in een productieproject kunt gebruiken.
Importeer de PivotControls en wrap onze sphere binnen deze controls.
import { PivotControls, TransformControls, OrbitControls } from '@react-three/drei'
<PivotControls>
<mesh position-x={ - 2 }>
<sphereGeometry />
<meshStandardMaterial color="orange" />
</mesh>
</PivotControls>06
CONTROLS
Anders dan TransformControls, ondersteunt PivotControls geen groepen. Daarom verplaatsen we de origin naar het midden van de mesh door de anchor aan te passen.
Verander de anchor naar de sphere locatie.
<PivotControls anchor={ [ 0, 0, 0 ] }>
{/* ... */}
</PivotControls>06
CONTROLS
Ehh… niets te zien! Dat komt omdat de anchor binnen de sphere zit. Gelukkig kun je dit eenvoudig oplossen door depthTest={false} toe te voegen, zodat het object altijd zichtbaar is.
<PivotControls
anchor={ [ 0, 0, 0 ] }
depthTest={ false }
>
{/* ... */}
</PivotControls>Je kunt diverse eigenschappen van de controls aanpassen:
lineWidth: De dikte van de lijnen.
axisColors: Geef een array [x, y, z] op om de assen in eigen kleuren weer te geven.
scale: Bepaalt hoe groot de controls visueel zijn.
fixed: Normaal reageren controls op zoom; met fixed={true} blijven ze altijd even groot.
Speel even met de settings en kijk welke invloed die hebben.
<PivotControls
anchor={ [ 0, 0, 0 ] }
depthTest={ false }
lineWidth={ 4 }
axisColors={ [ '#9381ff', '#ff4d6d', '#7ae582' ] }
scale={ 100 }
fixed={ true }
>
{/* ... */}
</PivotControls>06
CONTROLS
LIGHTS
07
In Three.js — en eigenlijk in elke 3D-software — bepaalt licht in grote mate hoe je objecten waarneemt. Vooral de combinatie van materiaaltype en lichtsoort heeft hier veel invloed op.
Binnen R3F heb je keuze uit verschillende materialen, zoals:
07
LIGHTS
Net zoals je kunt kiezen uit diverse materialen, kun je in R3F ook uit verschillende soorten lichten kiezen, bijvoorbeeld:
07
LIGHTS
Laten we beginnen met Ambient, Directional en PointLight. Andere lichtsoorten komen later waarschijnlijk nog voorbij. Voel je vrij om ze alvast zelf te ontdekken en uit te proberen!
We starten met het zonlicht in onze scene, oftewel DirectionalLight.
Voeg een DirectionalLight toe
07
LIGHTS
export default function Experience()
{
// ...
return <>
<directionalLight />
{/* ... */}
</>
}We zien geen verandering in onze scene, hoe komt dit?
Het effect van ons licht is nog niet zichtbaar omdat we MeshBasicMaterial gebruiken. Dit materiaal reageert niet op licht en blijft altijd zichtbaar, ongeacht de verlichting in de scene.
Verander de materials naar meshStandardMaterial (meest gebruikt)
07
LIGHTS
<group ref={ groupRef }>
<mesh position-x={ - 2 }>
<sphereGeometry />
<meshStandardMaterial color="orange" />
</mesh>
<mesh ref={ cubeRef } rotation-y={ Math.PI * 0.25 } position-x={ 2 } scale={ 1.5 }>
<boxGeometry />
<meshStandardMaterial color="mediumpurple" />
</mesh>
</group>
<mesh position-y={ - 1 } rotation-x={ - Math.PI * 0.5 } scale={ 10 }>
<planeGeometry />
<meshStandardMaterial color="grey" />
</mesh>Bij het aanmaken van een licht wordt het standaard boven het midden van de scene geplaatst. Wil je dat het ergens anders schijnt? Pas dan de position aan.
Verander de position naar volgende.
07
LIGHTS
<directionalLight position={ [ 1, 2, 3 ] } />We kunnen ook (de kleur) en intensiteit aanpassen als we dat willen.
<directionalLight position={ [ 1, 2, 3 ] } intensity={ 4.5 } />De schaduwen onderaan zijn nu vrij donker en niet zo realistisch. In de echte wereld wordt licht verspreid en weerkaatst door oppervlakken. Met een AmbientLight kunnen we dit effect in R3F eenvoudig simuleren.
Voeg een ambientLight toe aan de scene en pas de intensiteit ook aan.
07
LIGHTS
<directionalLight />
<ambientLight intensity={ 1 } />Er valt nog veel te ontdekken over licht, zoals schaduwen, shadow maps, environment maps, en meer. Voorlopig is dit echter genoeg om verder te gaan met onze scene.
Tot slot voegen we een PointLight toe. Dit licht verspreidt zich in alle richtingen en staat bekend als een “duur” licht, omdat het veel prestaties vraagt. Daarom gebruiken we het liever zo min mogelijk.
Zet de directionalLight in comment en plaats een pointLight om te zien wat voor effect we krijgen.
07
LIGHTS
<pointLight position={[0.5,2,0.5]} intensity={10}/>
<ambientLight intensity={ 1.5 } />Dat een licht veel rekenkracht kost, betekent niet dat je het niet kunt gebruiken. Zorg er wel voor dat je scene niet overvol raakt met zware objecten en lichten, want een trage, haperende ervaring is voor niemand prettig.
SETTINGS (CANVAS)
08
Ons Canvas bevat meerdere onderdelen: de scene, camera, renderer, colorSpace, en meer. Af en toe willen we deze instellingen aanpassen. Laten we beginnen bij de camera.
Plaats in de camera prop een leeg object.
<Canvas camera={ {} }>
<Experience />
</Canvas>08
SETTINGS (CANVAS)
Wat we kunnen aanpassen in de camera is volgende:
fov (field of view): bepaalt hoe breed de kijkhoek van de camera is.
near: geeft de minimale afstand aan waarop de camera objecten nog kan zien.
far: geeft de maximale afstand aan waarop de camera objecten nog kan zien.
position: bepaalt de locatie van de camera in de 3D-ruimte.
Probeer eens verschillende waardes en kijk hoe dit de camera beïnvloedt in de scene.
Verander de camera settings naar volgende
<Canvas camera={ { fov: 45, near: 0.1, far: 200 } }>De camera staat nu te dicht dus veranderen we de positie.
<Canvas camera={ { fov: 45, near: 0.1, far: 200, position: [ 3, 2, 6 ] } }>08
SETTINGS (CANVAS)
Hoe meer props des te moeilijker het te lezen is op een lijn. Refactor dit naar volgende
<Canvas
camera={ {
fov: 45,
near: 0.1,
far: 200,
position: [ 3, 2, 6 ]
} }
>
<Experience />
</Canvas>
Een orthografische camera laat geen perspectief zien. Gewoonlijk stel je hiervoor top, right, bottom en left in, maar in R3F wordt dit vaak automatisch afgehandeld.
Verander de camera naar orthographic.
<Canvas
orthographic
camera={ {
...
} }
>
<Experience />
</Canvas>08
SETTINGS (CANVAS)
Fov is nu nutteloos maar bij een orthographic camera maken we gebruik van 'zoom'
camera={ {
fov: 45,
zoom: 100,
near: 0.1,
far: 200,
position: [ 3, 2, 6 ]
} }Instellingen voor objecten zetten we vaak buiten de component, zodat de code overzichtelijk blijft en makkelijker te beheren is.
Maak een object aan met de settings.
const cameraSettings = {
fov: 45,
zoom: 100,
near: 0.1,
far: 200,
position: [ 3, 2, 6 ]
}Geef het object mee met de camera.
<Canvas
orthographic
camera={ cameraSettings }
>
<Experience />
</Canvas>08
SETTINGS (CANVAS)
Verwijder de orthographic alsook de zoom (hier gaan we niet mee verder)
Onze camera kan weleens in beweging komen! Bijvoorbeeld door hem continu rond een object te laten draaien in een loop. Hiervoor gebruiken we een paar eenvoudige wiskundige berekeningen.
Comment de OrbitControls want we gaan de camera laten draaien.
{/* <orbitControls /> */}08
SETTINGS (CANVAS)
Wil je dat de camera rond een object draait? Dan gebruiken we sin() en cos() voor de cirkelbeweging. De benodigde angle halen we uit de state met de methode getElapsedTime() of clock.elapsedTime.
In onze useFrame zullen we eens zien wat in state zit.
useFrame((state, delta) =>
{
console.log(state.clock)
// ...
})08
SETTINGS (CANVAS)
Sla nu de elapsedTime in een variable.
useFrame((state, delta) =>
{
const angle = state.clock.elapsedTime
console.log(angle)
// ...
})Verander nu de x en z positie van de camera a.d.h.v de sin() en cos()
useFrame((state, delta) =>
{
const angle = state.clock.elapsedTime
state.camera.position.x = Math.sin(angle)
state.camera.position.z = Math.cos(angle)
// ...
})08
SETTINGS (CANVAS)
Maak de cirkel nu groter door dit te vermenigvuldigen met een bepaald aantal
useFrame((state, delta) =>
{
const angle = state.clock.elapsedTime
state.camera.position.x = Math.sin(angle) * 8
state.camera.position.z = Math.cos(angle) * 8
// ...
})Onze camera draait netjes rond het object, maar richt zich nog niet op het object zelf. Met lookAt() zorgen we dat de camera continu naar het object kijkt.
useFrame((state, delta) =>
{
const angle = state.clock.elapsedTime
state.camera.position.x = Math.sin(angle) * 8
state.camera.position.z = Math.cos(angle) * 8
state.camera.lookAt(0, 0, 0)
// ...
})08
SETTINGS (CANVAS)
Onze camera cirkelt mooi rond en blijft gericht op het middelpunt van de scene — gaaf! Zet de animatie even in comment, zodat we terug met OrbitControls kunnen werken.
<Canvas
gl={ {
antialias: false
} }
camera={ {
fov: 45,
near: 0.1,
far: 200,
position: [ 3, 2, 6 ]
} }
>08
SETTINGS (CANVAS)
Normaal staat antialiasing aan, maar laten we het eens uitzetten. Dat gebeurt via de gl-prop, die verwijst naar de onderliggende WebGLRenderer, waar je nog veel meer instellingen kunt aanpassen.
Anti-aliasing helpt om die vervelende kartelige randen weg te werken. Het doet dit door de kleuren van omliggende pixels te mengen, waardoor lijnen en vormen veel vloeiender ogen.
We zullen deze weer op true plaatsen of wegdoen, dat is veel mooier :)
<Canvas
flat
gl={ {
antialias: true
} }
camera={ {
fov: 45,
near: 0.1,
far: 200,
position: [ 3, 2, 6 ]
} }
>08
SETTINGS (CANVAS)
Om tonemapping weg te halen van de scene plaatsen we 'flat' op onze Canvas
In essentie zet tone mapping de brede variatie aan lichtintensiteiten in een HDR-beeld om naar een kleiner bereik, zonder belangrijke details in schaduwen of hooglichten te verliezen.
Dit plaatst 'NoToneMapping' op onze scene en dat ziet er ... lelijk uit.
//Optie 1
import * as THREE from 'three'
//Optie 2
import { CineonToneMapping } from 'three'08
SETTINGS (CANVAS)
Importeer de CineonToneMapping van Three
Als je bepaalde tone mappings wilt gebruiken voor je scene, voeg je deze toe via gl. Vergeet niet eerst de juiste tone mapping uit Three.js te importeren.
Afhankelijk van de import die je gebruikt moet je nog THREE plaatsen vooraf.
gl={ {
antialias: true,
toneMapping: THREE.CineonToneMapping
} }08
SETTINGS (CANVAS)
Voeg de tonemapping toe aan gl.
Laten we twee tone mappings toevoegen en het effect ervan bekijken. Er zijn nog veel andere tone mappings beschikbaar, die je in de Three.js-documentatie kunt vinden.
Importeer nu ook ACESFilmicToneMapping en vervang de toneMapping met deze.
gl={ {
antialias: true,
toneMapping: THREE.ACESFilmicToneMapping
} }html,
body,
#root
{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
background: LightSkyBlue;
}08
SETTINGS (CANVAS)
Voeg css toe om een achtergrond te geven en dit in actie te zien.
De achtergrond van het Canvas is standaard transparant, waardoor je elementen of styling achter de canvas kunt tonen en ze nog steeds zichtbaar blijven.
<Canvas
dpr={ [ 1, 2 ] }
gl={ {
antialias: true,
toneMapping: THREE.ACESFilmicToneMapping,
outputColorSpace: THREE.LinearSRGBColorSpace
} }
>08
SETTINGS (CANVAS)
Voeg dpr toe aan de canvas (standaard staat deze al zo) [min,max]
Op high-DPI schermen past de renderer zich automatisch aan. Om te voorkomen dat je applicatie traag wordt op apparaten met een zeer hoge pixelratio, kun je beter zelf een limiet instellen via de dpr-prop van het <Canvas>.
HTML & TEXT
09
Met de HTML-component van Drei kun je gewoon HTML-elementen toevoegen die aan een mesh vastzitten en automatisch mee bewegen in de 3D-scene.
Importeer HTML component van drei
import { Html } from '@react-three/drei'09
HTML & TEXT
Gebruik nu HTML en schrijf iets
export default function Experience()
{
// ...
return <>
{/* ... */}
<Html>Hello!</Html>
</>
}Het HTML-element staat nu nog in het midden van de scene, maar door het in een mesh te plaatsen, volgt het automatisch de origin van dat object.
Plaats een nieuw Html element in onze mesh
<mesh position-x={ - 2 }>
<sphereGeometry />
<meshStandardMaterial color="orange" />
<Html>This sphere is lit! 🔥</Html>
</mesh>09
HTML & TEXT
We kunnen de offset veranderen door de position aan te passen.
<mesh position-x={ - 2 }>
<sphereGeometry />
<meshStandardMaterial color="orange" />
<Html position={ [ 1, 1, 0 ] }>This sphere is lit! 🔥</Html>
</mesh>Nu staat er een DOM-element in de 3D-scene, maar hoe style je dat? Gewoon een class toewijzen en in je CSS de gewenste stijlen instellen.
Gebruik de prop wrapperClass en geef een class name mee
<Html
wrapperClass="label"
>09
HTML & TEXT
Nu kan je in index.css de gewenste stijl toevoegen.
.label > div
{
font-family: Helvetica, Arial;
position: absolute;
background: #00000088;
color: white;
padding: 15px;
white-space: nowrap;
overflow: hidden;
border-radius: 30px;
user-select: none;
}Je kunt een HTML-element centreren op zichzelf en een distanceFactor instellen. Zo lijkt het alsof het element diepte heeft en mee schaalt als je in- of uitzoomt in de scene.
Plaats center en een distanceFactor van 6 op het HTML component
<Html
position={ [ 1, 1, 0 ] }
wrapperClass="label"
center
distanceFactor={ 6 }
>09
HTML & TEXT
Wat betekent occlusion? Als je een HTML-element in de scene hebt en er een mesh vóór plaatst, zie je dat het element normaal gesproken gewoon erboven blijft. Met occlude zorg je ervoor dat het element achter de mesh verdwijnt, alsof het echt geblokkeerd wordt.
Om een occlude toe te voegen moet je eerst references plaatsen op de meshes en deze meegeven me in de array
<Html
position={ [ 1, 1, 0 ] }
wrapperClass="label"
center
distanceFactor={ 6 }
occlude={ [ sphere, cube ] }
>09
HTML & TEXT
HTML in de scene werkt, maar voor echte 3D-tekst gebruiken we de Text-component. Die maakt het eenvoudig om tekst als onderdeel van je 3D-scene weer te geven.
Importeert de helper van drei in je project
import { Text } from '@react-three/drei'09
HTML & TEXT
Voeg deze nu toe aan je project en plaats een stukje tekst ertussen.
export default function Experience()
{
// ...
return <>
{/* ... */}
<Text>TECH3 IS AWESOME!</Text>
</>
}Standaard krijg je een font bij de Text-component, maar je kunt net zo goed je eigen lettertypen toevoegen en gebruiken in de 3D-scene.
Kies een font, download het en zet het pad in de font-prop. De component ondersteunt .woff, .ttf en .otf, maar .woff is aan te raden omdat het minder zwaar is.
<Text
font="./HussarBoldWeb.woff"
>
TECH3 IS AWESOME!
</Text>09
HTML & TEXT
Ook de fontSize als color zijn aanpasbaar.
<Text
font="./HussarBoldWeb.woff"
fontSize={ 2 }
color="pink"
>
TECH3 IS AWESOME!
</Text>Wil je de tekst een eigen look geven? Je kunt een custom material meegeven, precies zoals je dat bij een mesh zou doen.
Verander de material van de tekst naar een meshNormalMaterial
<Text
font="./bangers-v20-latin-regular.woff"
fontSize={ 2 }
color="salmon"
>
TECH3 IS AWESOME!
<meshNormalMaterial />
</Text>09
HTML & TEXT
Nu we weten dat dit mogelijk is zullen we terug keren zonder NormalMaterial.
Net als andere objecten kun je een Text verplaatsen, van grootte veranderen en roteren om het precies te positioneren zoals je wilt.
Verander de positie naar boven (y-as) met 2
<Text
font="./HussarBoldWeb.woff"
fontSize={ 2 }
color="pink"
position-y={2}
>09
HTML & TEXT
Een MaxWidth , TextAlign en dergelijke zijn ook allemaal mogelijk op een Text element.
<Text
font="./HussarBoldWeb.woff"
fontSize={ 1 }
color="pink"
position-y={ 2 }
maxWidth={ 5 }
textAlign="center"
scale={ .5}
>VARIA
10
Drei heeft een hoop leuke kant-en-klare componenten. Check de documentatie om ze allemaal te ontdekken!
Met Float laat je een element zachtjes zweven, net alsof het een ballon is. Het werkt als een wrapper rond je objecten.
Importeer Float van Drei en gebruik deze rond onze text.
<Float>
<Text
font="./bangers-v20-latin-regular.woff"
fontSize={ 1 }
color="salmon"
position-y={ 2 }
maxWidth={ 2 }
textAlign="center"
>
TECH3 IS AWESOME!
</Text>
</Float>10
VARIA
De tekst zweeft al prachtig, maar we hebben nog meer controle! Pas de speed en float-intensity aan om het effect sneller, langzamer of sterker te maken.
Pas de speed en intenstity aan en speel wat met de waarden.
<Float
speed={ 5 }
floatIntensity={ 2 }
>
{/* ... */}
</Float>10
VARIA
Altijd al een 3D-spiegel willen maken? Dankzij Drei is het nu supermakkelijk: gewoon een MeshReflectorMaterial toepassen op je object en you're done!
Importeer MeshReflectorMaterial van Drei en vervang de material van de plane.
import { MeshReflectorMaterial } from '@react-three/drei'
//...
<mesh position-y={ - 1 } rotation-x={ - Math.PI * 0.5 } scale={ 10 }>
<planeGeometry />
<MeshReflectorMaterial />
</mesh>10
VARIA
Het MeshReflectorMaterial heeft verschillende instelbare opties. Je kunt onder andere resolution, blur, mixBlur, mirror en color aanpassen om het gewenste effect te bereiken.
Plaats deze waarden in onze Material
<MeshReflectorMaterial
resolution={ 512 }
blur={ [ 1000, 1000 ] }
mixBlur={ 1 }
mirror={ 0.5 }
color="grey"
/>10
VARIA
Gefeliciteerd! Je eerste stap in React Three Fiber en Drei is gezet. Er valt nog veel meer te leren, maar hiermee heb je al een stevige basis.
10
VARIA