ThreeJS - Snippets: Unterschied zwischen den Versionen

Aus Wikizone
Wechseln zu: Navigation, Suche
Zeile 2: Zeile 2:
 
  [[ThreeJS]]
 
  [[ThreeJS]]
  
== Viewport Resizing ==
+
== Viewport Settings ==
 +
=== Handle Viewport Resizing ===
 
<syntaxhighlight lang="javascript">
 
<syntaxhighlight lang="javascript">
 
window.addEventListener('resize', () =>{
 
window.addEventListener('resize', () =>{
Zeile 16: Zeile 17:
 
})
 
})
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
=== Pixel Ratio Setting (Retina Displays) ===
 +
Retina Displays haben eine Pixel Ratio von 2. D.h. das Display kann einen "Software"Bildpixel nochmal auf 4 physische Pixel verteilen und damit vor allem Vektoren nochmal '''schärfer''' darstellen. ThreeJS kann diese zusätzlichen Pixel ebenfalls nutzen wenn man dem renderer die Pixel Ratio mitgibt. Allerdings muss der Renderer auch mehr tun.
 +
 +
Moderne Handys haben Ratios bis zu 5, das ist allerdings sinnlos mehr als 2 oder 3 sehen wir bei normalem Betrachtungsabstand eh nicht. Deshalb setzen wir wenn möglich einen Ratio so hoch wie das Gerät kann aber '''nicht höher als 2''' um die Performance zu erhalten.
 +
<syntaxhighlight lang="javascript">
 +
renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) )
 +
</syntaxhighlight>
 +
 
== Animation Basics ==
 
== Animation Basics ==
 
=== Timebased Tick / Loop Function ===
 
=== Timebased Tick / Loop Function ===

Version vom 26. Dezember 2021, 12:48 Uhr

Links

ThreeJS

Viewport Settings

Handle Viewport Resizing

window.addEventListener('resize', () =>{
    console.log('window resized')
    // Update sizes
    sizes.width = window.innerWidth
    sizes.height = window.innerHeight
    // Update camera
    camera.aspect = sizes.width/sizes.height
    camera.updateProjectionMatrix()
    // Update renderer
    renderer.setSize(sizes.width,sizes.height)
})

Pixel Ratio Setting (Retina Displays)

Retina Displays haben eine Pixel Ratio von 2. D.h. das Display kann einen "Software"Bildpixel nochmal auf 4 physische Pixel verteilen und damit vor allem Vektoren nochmal schärfer darstellen. ThreeJS kann diese zusätzlichen Pixel ebenfalls nutzen wenn man dem renderer die Pixel Ratio mitgibt. Allerdings muss der Renderer auch mehr tun.

Moderne Handys haben Ratios bis zu 5, das ist allerdings sinnlos mehr als 2 oder 3 sehen wir bei normalem Betrachtungsabstand eh nicht. Deshalb setzen wir wenn möglich einen Ratio so hoch wie das Gerät kann aber nicht höher als 2 um die Performance zu erhalten.

renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) )

Animation Basics

Timebased Tick / Loop Function

Für Animationen können wir in einem Loop die Szene Rendern, Objekte verändern, Szene erneut Rendern usw. In JavaScript kann man dazu die window.requestAnimationFrame Funktion nutzen. Damit die zeitlichen Abläufe nicht von der Rechnerleistung sondern rein von der Zeit abhängen gibt es einige Möglichkeiten diesen Loop umzusetzen.

Die Beispiele setzen eine Setup mit einem Camera Object 'camera', einer Szene scene, und einem Renderer 'renderer' voraus. Du kannst z.B. das Beispiel auf der Hauptseite nutzen.

Pure JavaScript calculation

let time = Date.now() 
const tick = () =>
{
    // JS based time calculation
    const currentTime = Date.now()
    const deltaTime = currentTime - time
    time = currentTime
    //console.log(deltaTime)
    // Update objects
    mesh.rotation.y += 0.001 * deltaTime
    renderer.render(scene, camera)
    // tell JS to call tick on the next frame
    window.requestAnimationFrame(tick) 
}
// go...
tick()

ThreeJS Clock Object

const clock = new THREE.Clock()
const tick = () =>
{
    // Hint: do NOT use clock.getDelta() - it can cause problems (buggy in end of 2021)
    const elapsedTime = clock.getElapsedTime()
    //console.log(elapsedTime)
    mesh.rotation.y = elapsedTime * Math.PI * 2 // one revolution / s
    camera.lookAt(mesh.position)
    camera.position.z = Math.sin(elapsedTime) // back and forth
    // Render
    renderer.render(scene, camera)
    window.requestAnimationFrame(tick) 
}
tick()

GSAP Animation

// GSAP has it's own requestAnimationFrame, thus no time calculation needed
// we just let gsap update our values and tick does render each frame
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 2 })
gsap.to(mesh.position,{ duration: 1, delay: 1, x: 0 })
const tick = () =>
{
    // Render on each frame
    renderer.render(scene, camera)
    window.requestAnimationFrame(tick) 
}
// GO...
tick()

Nützliche Snippets für Animationen

Kreisbewegung / Circular Movement

myObject.position.y = Math.sin(elapsedTime) //(-1 -> 1 -> -1 -> ...)
myObject.position.x = Math.cos(elapsedTime)

Cursor auswerten

// Sizes
const sizes = { width: 800,  height: 600}
// Cursor
const cursor = {
    x: 0,
    y: 0
}
window.addEventListener('mousemove', (event) => 
{
    //cursor.x = event.clientX / sizes.width // 0 <= x <= 1
    cursor.x = event.clientX / sizes.width - 0.5// -0.5 <= x <= +0.5
    cursor.y = event.clientY / sizes.height - 0.5// -0.5 <= x <= +0.5
    console.log('x: ' + cursor.x)
    console.log('y: ' + cursor.y)
})
// ...
// Update camera with position
    camera.position.x = cursor.x * 10
    camera.position.y = cursor.y * 10

Kamera auf einer Kreisbahn

Das obige Beispiel läßt sich ausbauen. Die Mausbewegung gibt uns nun cursor.x Werte von -0.5 bis 0.5. Wenn wir auf zwei Achsen sinus und cosinus kombinieren bekommen wir eine Kreisbahn um den Mittelpunkt auf der Ebene dieser beiden Achsen. Eine volle Umdrehung bekommen wir wenn wir mit 2xPi multiplizieren. Den Abstand vergrößern wir wenn wir das Ergebnis mit irgendeinem Faktor multiplizieren.

    // Update camera
    camera.position.x = Math.sin(cursor.x * 2 * Math.PI) * 3
    camera.position.z = Math.cos(cursor.x * 2 * Math.PI) * 3
    camera.position.y = cursor.y * 5 // damit wir auch etwas von oben oder unten schauen können
    camera.lookAt(mesh.position) // look at center

Für eine Kreisbahn um ein Objekt das nicht im Mittelpunkt ist, müßten wir noch die Koordinaten des Objekts auslesen und zu den Kamerakoordinaten addieren. So könnten wir den kompletten Kreis verschieben.

Orbit Controls

https://threejs.org/docs/index.html?q=controls#examples/en/controls/OrbitControls

ThreeJS spart mit eigenen Control Klassen eine Menge Arbeit. OrbitControls müssen zusätzlich geladen werden. Also in HTML

<script src="/javascripts/OrbitControls.js"></script>

Oder z.B. in Webpack:

import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'

Dann erstellt man einfach ein OrbitControl Objekt und übergibt die Kamera und ein DOM Objekt (i.d.R. das Canvas).

const controls = new OrbitControls(camera,canvas)