Three.js - Scroll Based Animation: Unterschied zwischen den Versionen
Aus Wikizone
| Zeile 154: | Zeile 154: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| + | === Scroll Trigger === | ||
| + | Wir nutzen GSAP aber nur für die Animation, nicht für den Trigger: | ||
| + | <syntaxhighlight lang="javascript"> | ||
| + | /** | ||
| + | * Sizes | ||
| + | */ | ||
| + | const sizes = { | ||
| + | width: window.innerWidth, | ||
| + | height: window.innerHeight | ||
| + | } | ||
| − | + | window.addEventListener('resize', () => | |
| − | + | { | |
| − | + | // Update sizes | |
| − | + | sizes.width = window.innerWidth | |
| − | + | sizes.height = window.innerHeight | |
| + | //... | ||
| + | }) | ||
| + | // ... | ||
| + | |||
| + | /** | ||
| + | * Scroll | ||
| + | */ | ||
| + | let scrollY = window.scrollY | ||
| + | let currentSection = 0 | ||
| + | |||
| + | window.addEventListener('scroll', () => | ||
| + | { | ||
| + | scrollY = window.scrollY | ||
| + | const newSection = Math.round(scrollY / sizes.height) //liefert 0,1,2... | ||
| + | if(newSection != currentSection) | ||
| + | { | ||
| + | console.log('changed', currentSection) | ||
| + | currentSection = newSection | ||
| + | // Section Trigger | ||
| + | gsap.to( | ||
| + | sectionMeshes[currentSection].rotation, | ||
| + | { | ||
| + | duration: 1.5, | ||
| + | ease: 'power2.inOut', | ||
| + | x: '+=6', | ||
| + | y: '+=3', | ||
| + | z: '+=1.5' | ||
| + | } | ||
| + | ) | ||
| + | } | ||
| + | }) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| + | |||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Version vom 11. Februar 2022, 20:58 Uhr
Snippets
Check Scroll Position
let scrollY = window.scrollY
window.addEventListener('scroll', () =>
{
scrollY = window.scrollY
console.log(scrollY)
})
Scroll objects in sync to html scroll
// position objects
const objectsDistance = 4
mesh1.position.y = - objectsDistance * 0
mesh2.position.y = - objectsDistance * 1
mesh3.position.y = - objectsDistance * 2
//...
// Calc sizes (HINT-no resize event in this example)
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}
//...
// Base camera
const camera = new THREE.PerspectiveCamera(35, sizes.width / sizes.height, 0.1, 100)
camera.position.z = 6
scene.add(camera)
// Control Scrolling
let scrollY = window.scrollY
window.addEventListener('scroll', () => { scrollY = window.scrollY })
// ...
// tick function
const tick = () =>
{
// ...
// Animate camera
camera.position.y = - scrollY / sizes.height * objectsDistance // scroll objects in sync to html
// ...
}
tick()
Cursor based Parallax
// ...
/**
* Camera
*/
// Group (used to apply camara parallax without interfering the camera scroll)
const cameraGroup = new THREE.Group()
scene.add(cameraGroup)
// Base camera
const camera = new THREE.PerspectiveCamera(35, sizes.width / sizes.height, 0.1, 100)
camera.position.z = 6
cameraGroup.add(camera)
// ...
const tick = () =>
{
// Animate camera
// scroll objects in sync to html
camera.position.y = - scrollY / sizes.height * objectsDistance
// cameraGroup parallax on cursor movement
const parallaxX = cursor.x
const parallaxY = - cursor.y
cameraGroup.position.x = parallaxX
cameraGroup.position.y = parallaxY
}
// ...
Parallax with easing
Variation von oben
// ...
/**
* Animate
*/
const clock = new THREE.Clock()
let previousTime = 0
const tick = () =>
{
const elapsedTime = clock.getElapsedTime()
// we need deltaTime to calc correct timbased (not fps based) movement for our easing
const deltaTime = elapsedTime - previousTime
previousTime = elapsedTime
//...
// Animate camera
// scroll objects in sync to html
camera.position.y = - scrollY / sizes.height * objectsDistance
// camera parallax on cursor movement
const parallaxX = cursor.x * 0.5
const parallaxY = - cursor.y * 0.5
//cameraGroup.position.x = parallaxX
//cameraGroup.position.y = parallaxY
// add some easing
cameraGroup.position.x += (parallaxX - cameraGroup.position.x) * 5 * deltaTime
cameraGroup.position.y += (parallaxY - cameraGroup.position.y) * 5 * deltaTime
// Render
renderer.render(scene, camera)
// Call tick again on the next frame
window.requestAnimationFrame(tick)
}
tick()
Partikel für zusätzliche Räumlichkeit einsetzen
/**
* Particles
*/
const particlesCount = 200
const positions = new Float32Array(particlesCount * 3)
for(let i = 0; i < particlesCount; i++)
{
positions[i * 3 + 0] = (Math.random() - 0.5) * 10
positions[i * 3 + 1] = objectsDistance * 0.5 - Math.random() * objectsDistance * sectionMeshes.length
positions[i * 3 + 2] = (Math.random() - 0.5) * 10
}
// Geometry
const particlesGeometry = new THREE.BufferGeometry()
particlesGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
// Material
const particlesMaterial = new THREE.PointsMaterial({
color: parameters.materialColor,
sizeAttenuation: true,
size: 0.03
})
// Points
const particles = new THREE.Points(particlesGeometry, particlesMaterial)
scene.add(particles)
Scroll Trigger
Wir nutzen GSAP aber nur für die Animation, nicht für den Trigger:
/**
* Sizes
*/
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}
window.addEventListener('resize', () =>
{
// Update sizes
sizes.width = window.innerWidth
sizes.height = window.innerHeight
//...
})
// ...
/**
* Scroll
*/
let scrollY = window.scrollY
let currentSection = 0
window.addEventListener('scroll', () =>
{
scrollY = window.scrollY
const newSection = Math.round(scrollY / sizes.height) //liefert 0,1,2...
if(newSection != currentSection)
{
console.log('changed', currentSection)
currentSection = newSection
// Section Trigger
gsap.to(
sectionMeshes[currentSection].rotation,
{
duration: 1.5,
ease: 'power2.inOut',
x: '+=6',
y: '+=3',
z: '+=1.5'
}
)
}
})