当前位置: 首页 > news >正文

【Three.js基础学习】15.scroll-based-animation

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

 课程要点

        结合html等场景 做滚动动画

        1.遇到的问题, 在向下滚动时,下方会显白(部分浏览器)

            解决:alpha:true ,在WebGLRenderer 中设置alpha : true ; 同时在style.css文件中设置html 背景颜色

        2.添加 圆环,锥型,圆环纠结形状

        3.添加材质 卡通 由于 卡通对光 才能看见 因此 加一个定向光

        4.此时 显示的颜色是两种 ,但是根据文档 可以看到有三种色, 因此可以通过 纹理实现

        gradientTexture.magFilter = THREE.NearestFilter

        5.设置位置,同时转动

        6.向下移动网页 更改camera视角

        7. 视差 :通过不同观察点看到一个物体的行为

            希望能有深度 ,在鼠标移动时,相机视角能有适当的强度变化

        实现: 由于滚动 和 移动鼠标都是 移动camera视角 导致 滚动不生效

            1. 创建组 ,在视差时候 移动组, 而camera在组中, 滚动时 移动相机 解决

       

        8.实现平滑 缓慢 移动 速度不要太快    

        9.实现在不同电脑中 不同屏幕频率相同的移动速度

        let previousTime = 0

        const deltaTime = elapsedTime - previousTime

        previousTime = elapsedTime

        10. GSAP


一、代码

import * as THREE from 'three'
import * as dat from 'lil-gui'
import gsap from 'gsap'/*** Debug*/
const gui = new dat.GUI()const parameters = {materialColor: '#ffeded'
}gui.addColor(parameters, 'materialColor').onChange(()=>{material.color.set(parameters.materialColor)particleMaterial.color.set(parameters.materialColor)})/*** Base*/
// Canvas
const canvas = document.querySelector('canvas.webgl')// Scene
const scene = new THREE.Scene()/* Objects
*/
// Texture
const textureLoad = new THREE.TextureLoader()
const gradientTexture =  textureLoad.load('/textures/gradients/3.jpg')
gradientTexture.magFilter = THREE.NearestFilter // 设置最近过滤器 牵扯到WebGL原理// Material
const material = new THREE.MeshToonMaterial({color:parameters.materialColor,gradientMap:gradientTexture, 
}) // 卡通材质 有光的情况才会出现//  Meshs
const objectsDistance = 4
const mesh1 = new THREE.Mesh(new THREE.TorusGeometry(1,0.4,16,60),  // 环形material
)
const mesh2 = new THREE.Mesh(new THREE.ConeGeometry(1,2,32), // 锥material
)
const mesh3 = new THREE.Mesh(new THREE.TorusKnotGeometry(0.8, 0.35, 100, 16), // 环形缓冲material
)
// mesh1.position.y = 2
// mesh1.scale.set(0.5,0.5,0.5)// mesh2.visible = false// mesh3.position.y = -2
// mesh3.scale.set(0.5,0.5,0.5)const sectionMeshes = [mesh1,mesh2,mesh3]mesh1.position.y = - objectsDistance * 0
mesh2.position.y = - objectsDistance * 1
mesh3.position.y = - objectsDistance * 2mesh1.position.x = 2
mesh2.position.x = -2
mesh3.position.x = 2scene.add(mesh1,mesh2,mesh3)/* Particles
*/
// Geometry
const particleCount = 200
const positions = new Float32Array(particleCount * 3)
for(let i = 0; i< particleCount;i++){positions[i * 3 + 0] = (Math.random() - 0.5) * 10positions[i * 3 + 1] = objectsDistance * 0.5 - Math.random() * objectsDistance * 3positions[i * 3 + 2] = (Math.random() - 0.5) * 10
}const particleGeometry = new THREE.BufferGeometry()
particleGeometry.setAttribute('position',new THREE.BufferAttribute(positions,3))const particleMaterial = new THREE.PointsMaterial()
particleMaterial.size = 0.03
particleMaterial.color = new THREE.Color(parameters.materialColor)
particleMaterial.sizeAttenuation = trueconst particle = new THREE.Points(particleGeometry,particleMaterial
)
scene.add(particle)/* ligths
*/
const directionalLight = new THREE.DirectionalLight('#ffffff',1)
directionalLight.position.set(1,1,0)
scene.add(directionalLight)/*** Sizes*/
const sizes = {width: window.innerWidth,height: window.innerHeight
}window.addEventListener('resize', () =>
{// Update sizessizes.width = window.innerWidthsizes.height = window.innerHeight// Update cameracamera.aspect = sizes.width / sizes.heightcamera.updateProjectionMatrix()// Update rendererrenderer.setSize(sizes.width, sizes.height)renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})/* Group
*/
const cameraGroup = new THREE.Group()
scene.add(cameraGroup)/*** Camera*/
// Base camera
const camera = new THREE.PerspectiveCamera(35, sizes.width / sizes.height, 0.1, 100)
camera.position.z = 6
cameraGroup.add(camera)/*** Renderer*/
const renderer = new THREE.WebGLRenderer({canvas: canvas,alpha:true,
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))/* Scroll
*/
let scrollY = window.scrollY
let currentSection = 0
window.addEventListener('scroll',()=>{scrollY = window.scrollYconst newSection = Math.round(scrollY / sizes.height) // 四舍五入判断 几何体旋转的时机if(newSection != currentSection){currentSection = newSectionconsole.log(sectionMeshes[currentSection].rotation)gsap.to(sectionMeshes[currentSection].rotation, // 设置动画 0,1,2的动画效果{duration:1.5, // 时间ease:'power2.inOut', // 进出x:'+=6',y:'+=3',z:'+=1.5',})}
})/* Cursor
*/
const cursor = {}
cursor.x = 0
cursor.y = 0window.addEventListener('mousemove',(event)=>{cursor.x = event.clientX / sizes.width - 0.5cursor.y = event.clientY / sizes.height - 0.5
})/*** Animate*/
const clock = new THREE.Clock()
let previousTime = 0
const tick = () =>
{const elapsedTime = clock.getElapsedTime()const deltaTime = elapsedTime - previousTimepreviousTime = elapsedTime// Aniamte Camera   移动的距离/窗口的高度 等于一个单位, *  objectsDistance 距离camera.position.y = - scrollY / sizes.height * objectsDistanceconst parallaxX = cursor.x * 0.5const parallaxY = -cursor.y * 0.5cameraGroup.position.x += (parallaxX - cameraGroup.position.x) * 5 * deltaTimecameraGroup.position.y += (parallaxY - cameraGroup.position.y) * 5 * deltaTime// Aniamte meshesfor(const mesh of sectionMeshes){ // 每一帧变化时,应该改变mesh.rotation.x +=  deltaTime * 0.1mesh.rotation.y +=  deltaTime * 0.12}// Renderrenderer.render(scene, camera)// Call tick again on the next framewindow.requestAnimationFrame(tick)
}tick()

二、知识点

1.原始代码

html代码

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>20 - Scroll base animation</title><link rel="stylesheet" href="./style.css">
</head>
<body><canvas class="webgl"></canvas><section class="section"><h1>My Portfolio</h1></section><section class="section"><h2>My projects</h2></section><section class="section"><h2>Contact me</h2></section><script type="module" src="./script.js"></script>
</body>
</html>

script.js

import * as THREE from 'three'
import * as dat from 'lil-gui'/*** Debug*/
const gui = new dat.GUI()const parameters = {materialColor: '#ffeded'
}gui.addColor(parameters, 'materialColor')/*** Base*/
// Canvas
const canvas = document.querySelector('canvas.webgl')// Scene
const scene = new THREE.Scene()/* cube
*/
const cube = new THREE.Mesh(new THREE.BoxGeometry(1,1,1),new THREE.MeshBasicMaterial({color:'red'})
)
scene.add(cube)/*** Sizes*/
const sizes = {width: window.innerWidth,height: window.innerHeight
}window.addEventListener('resize', () =>
{// Update sizessizes.width = window.innerWidthsizes.height = window.innerHeight// Update cameracamera.aspect = sizes.width / sizes.heightcamera.updateProjectionMatrix()// Update rendererrenderer.setSize(sizes.width, sizes.height)renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})/*** Camera*/
// Base camera
const camera = new THREE.PerspectiveCamera(35, sizes.width / sizes.height, 0.1, 100)
camera.position.z = 6
// cameraGroup.add(camera)
scene.add(camera)/*** Renderer*/
const renderer = new THREE.WebGLRenderer({canvas: canvas,
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))/*** Animate*/
const clock = new THREE.Clock()
let previousTime = 0
const tick = () =>
{const elapsedTime = clock.getElapsedTime()// Renderrenderer.render(scene, camera)// Call tick again on the next framewindow.requestAnimationFrame(tick)
}tick()

css代码

*
{margin: 0;padding: 0;
}/* html,
body
{overflow: hidden;
} */html{background: #1e1a20;
}
.webgl
{position: fixed;top: 0;left: 0;outline: none;
}.section
{display: flex;align-items: center;height: 100vh;position: relative;font-family: 'Cabin', sans-serif;color: #ffeded;text-transform: uppercase;font-size: 7vmin;padding-left: 10%;padding-right: 10%;
}section:nth-child(odd)
{justify-content: flex-end;
}

2.添加圆环,锥型,圆环扭曲 几何体

// Mesh
const mesh1 = new THREE.Mesh(new THREE.TorusGeometry(1,0.4,16,60),new THREE.MeshBasicMaterial({color:'red'})
)
const mesh2 = new THREE.Mesh(new THREE.ConeGeometry(1,2,32),new THREE.MeshBasicMaterial({color:'red'})
)
const mesh3 = new THREE.Mesh(new THREE.TorusKnotGeometry(0.8, 0.35, 100, 16),new THREE.MeshBasicMaterial({color:'red'})
)
scene.add(mesh1,mesh2,mesh3)

参数可以在three.js文档中查看,挤在一起有点丑,更改位置,添加纹理和卡通材质,由于卡通材质在光下显示 所以要在添加一个定向光 ,

// material
const material = new THREE.MeshToonMaterial({color:'#ffffff'
})// Mesh
const mesh1 = new THREE.Mesh(new THREE.TorusGeometry(1,0.4,16,60),material
)
const mesh2 = new THREE.Mesh(new THREE.ConeGeometry(1,2,32),material
)
const mesh3 = new THREE.Mesh(new THREE.TorusKnotGeometry(0.8, 0.35, 100, 16),material
)
scene.add(mesh1,mesh2,mesh3)/* Lights
*/
const directionalLight = new THREE.DirectionalLight('#ffffff',1)
directionalLight.position.set(1,1,0)
scene.add(directionalLight)

可以看到明暗变化,但是对比官网中 显示的颜色有三种

如何实现 ?

通过纹理设置实现,通过设置这种贴图实现光的变化

不过还需要设置最近过滤器 ,这样能有明显的渐变
对比一下设置 和没设置的图

const textureLoad = new THREE.TextureLoader()
const gradientTexture = textureLoad.load('/textures/gradients/3.jpg')
gradientTexture.magFilter = THREE.NearestFilter // 设置最近过滤器 牵扯到WebGL原理// material
const material = new THREE.MeshToonMaterial({color:parameters.materialColor,gradientMap:gradientTexture  // 卡通色渐变贴图 需要设置这个
})// Mesh
const mesh1 = new THREE.Mesh(new THREE.TorusGeometry(1,0.4,16,60),material
)
const mesh2 = new THREE.Mesh(new THREE.ConeGeometry(1,2,32),material
)
const mesh3 = new THREE.Mesh(new THREE.TorusKnotGeometry(0.8, 0.35, 100, 16),material
)
scene.add(mesh1,mesh2,mesh3)/* Lights
*/
const directionalLight = new THREE.DirectionalLight('#ffffff',1)
directionalLight.position.set(1,1,0)
scene.add(directionalLight)

设置位置,同时让几何体转动,并且 相机随滚动条视角移动,观测不同的几何体状态

import * as THREE from 'three'
import * as dat from 'lil-gui'/*** Debug*/
const gui = new dat.GUI()const parameters = {materialColor: '#ffeded'
}gui.addColor(parameters, 'materialColor')/*** Base*/
// Canvas
const canvas = document.querySelector('canvas.webgl')// Scene
const scene = new THREE.Scene()/* Objects
*/
// Texture
const textureLoad = new THREE.TextureLoader()
const gradientTexture = textureLoad.load('/textures/gradients/3.jpg')
gradientTexture.magFilter = THREE.NearestFilter // 设置最近过滤器 牵扯到WebGL原理// material
const material = new THREE.MeshToonMaterial({color:parameters.materialColor,gradientMap:gradientTexture  // 卡通色渐变贴图 需要设置这个
})// Mesh
const objectsDistance = 4
const mesh1 = new THREE.Mesh(new THREE.TorusGeometry(1,0.4,16,60),material
)
const mesh2 = new THREE.Mesh(new THREE.ConeGeometry(1,2,32),material
)
const mesh3 = new THREE.Mesh(new THREE.TorusKnotGeometry(0.8, 0.35, 100, 16),material
)const sectionMeshes = [mesh1,mesh2,mesh3]mesh1.position.y = - objectsDistance * 0
mesh2.position.y = - objectsDistance * 1
mesh3.position.y = - objectsDistance * 2mesh1.position.x = 2
mesh2.position.x = -2
mesh3.position.x = 2scene.add(mesh1,mesh2,mesh3)/* Lights
*/
const directionalLight = new THREE.DirectionalLight('#ffffff',1)
directionalLight.position.set(1,1,0)
scene.add(directionalLight)/*** Sizes*/
const sizes = {width: window.innerWidth,height: window.innerHeight
}window.addEventListener('resize', () =>
{// Update sizessizes.width = window.innerWidthsizes.height = window.innerHeight// Update cameracamera.aspect = sizes.width / sizes.heightcamera.updateProjectionMatrix()// Update rendererrenderer.setSize(sizes.width, sizes.height)renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})/*** Camera*/
// Base camera
const camera = new THREE.PerspectiveCamera(35, sizes.width / sizes.height, 0.1, 100)
camera.position.z = 6
// cameraGroup.add(camera)
scene.add(camera)/*** Renderer*/
const renderer = new THREE.WebGLRenderer({canvas: canvas,alpha:true,
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))/* Scroll
*/
let scrollY = window.scrollY // 获取滚动条y的数据
let currentSection = 0
window.addEventListener('scroll',()=>{scrollY = window.scrollY
})/*** Animate*/
const clock = new THREE.Clock()
let previousTime = 0
const tick = () =>
{const elapsedTime = clock.getElapsedTime()// Aniamte Camera   // 由于几何体 沿着y轴移动 objectsDistance 单位 所以 scrollY / sizes.height 是一比一的,* objectsDistance 就有了四个单位 camera.position.y = - scrollY / sizes.height * objectsDistance// Aniamte meshesfor(const mesh of sectionMeshes){ // 每一帧变化时,应该改变mesh.rotation.x =  elapsedTimemesh.rotation.y =  elapsedTime + 0.1}// Renderrenderer.render(scene, camera)// Call tick again on the next framewindow.requestAnimationFrame(tick)
}tick()

camera视角

视差 :通过不同观察点看到一个物体的行为

            希望能有深度 ,在鼠标移动时,相机视角能有适当的强度变化

        实现: 由于滚动 和 移动鼠标都是 移动camera视角 导致 滚动不生效

            1. 创建组 ,在视差时候 移动组, 而camera在组中, 滚动时 移动相机 解决

       实现平滑 缓慢 移动 速度不要太快    

实现在不同电脑中 不同屏幕频率相同的移动速度

        let previousTime = 0

        const deltaTime = elapsedTime - previousTime

        previousTime = elapsedTime

import * as THREE from 'three'
import * as dat from 'lil-gui'/*** Debug*/
const gui = new dat.GUI()const parameters = {materialColor: '#ffeded'
}gui.addColor(parameters, 'materialColor')/*** Base*/
// Canvas
const canvas = document.querySelector('canvas.webgl')// Scene
const scene = new THREE.Scene()/* Objects
*/
// Texture
const textureLoad = new THREE.TextureLoader()
const gradientTexture = textureLoad.load('/textures/gradients/3.jpg')
gradientTexture.magFilter = THREE.NearestFilter // 设置最近过滤器 牵扯到WebGL原理// material
const material = new THREE.MeshToonMaterial({color:parameters.materialColor,gradientMap:gradientTexture  // 卡通色渐变贴图 需要设置这个
})// Mesh
const objectsDistance = 4
const mesh1 = new THREE.Mesh(new THREE.TorusGeometry(1,0.4,16,60),material
)
const mesh2 = new THREE.Mesh(new THREE.ConeGeometry(1,2,32),material
)
const mesh3 = new THREE.Mesh(new THREE.TorusKnotGeometry(0.8, 0.35, 100, 16),material
)const sectionMeshes = [mesh1,mesh2,mesh3]mesh1.position.y = - objectsDistance * 0
mesh2.position.y = - objectsDistance * 1
mesh3.position.y = - objectsDistance * 2mesh1.position.x = 2
mesh2.position.x = -2
mesh3.position.x = 2scene.add(mesh1,mesh2,mesh3)/* Lights
*/
const directionalLight = new THREE.DirectionalLight('#ffffff',1)
directionalLight.position.set(1,1,0)
scene.add(directionalLight)/*** Sizes*/
const sizes = {width: window.innerWidth,height: window.innerHeight
}window.addEventListener('resize', () =>
{// Update sizessizes.width = window.innerWidthsizes.height = window.innerHeight// Update cameracamera.aspect = sizes.width / sizes.heightcamera.updateProjectionMatrix()// Update rendererrenderer.setSize(sizes.width, sizes.height)renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})/* Group
*/
const cameraGroup = new THREE.Group()
scene.add(cameraGroup)/*** Camera*/
// Base camera
const camera = new THREE.PerspectiveCamera(35, sizes.width / sizes.height, 0.1, 100)
camera.position.z = 6
cameraGroup.add(camera)/*** Renderer*/
const renderer = new THREE.WebGLRenderer({canvas: canvas,alpha:true,
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))/* Scroll
*/
let scrollY = window.scrollY // 获取滚动条y的数据
let currentSection = 0
window.addEventListener('scroll',()=>{scrollY = window.scrollY
})/* Cursor
*/
const cursor = {}
cursor.x = 0
cursor.y = 0window.addEventListener('mousemove',(event)=>{cursor.x = event.clientX / sizes.width - 0.5cursor.y = event.clientY / sizes.height - 0.5
})/*** Animate*/
const clock = new THREE.Clock()
let previousTime = 0
const tick = () =>
{const elapsedTime = clock.getElapsedTime()const deltaTime = elapsedTime - previousTimepreviousTime = elapsedTime// Aniamte Camera   // 由于几何体 沿着y轴移动 objectsDistance 单位 所以 scrollY / sizes.height 是一比一的,* objectsDistance 就有了四个单位 camera.position.y = - scrollY / sizes.height * objectsDistanceconst parallaxX = cursor.x * 0.5const parallaxY = -cursor.y * 0.5cameraGroup.position.x += (parallaxX - cameraGroup.position.x) * 5 * deltaTimecameraGroup.position.y += (parallaxY - cameraGroup.position.y) * 5 * deltaTime// Aniamte meshesfor(const mesh of sectionMeshes){ // 每一帧变化时,应该改变mesh.rotation.x +=  deltaTime * 0.1mesh.rotation.y +=  deltaTime * 0.12}// Renderrenderer.render(scene, camera)// Call tick again on the next framewindow.requestAnimationFrame(tick)
}tick()

camera 视角移动

添加粒子特效

/* Particles
*/
const particleCount = 200
const positions = new Float32Array(particleCount * 3)
// 设置粒子位置
for(let i = 0; i< particleCount;i++){positions[i * 3 + 0] = (Math.random() - 0.5) * 10positions[i * 3 + 1] = objectsDistance * 0.5 - Math.random() * objectsDistance * 3positions[i * 3 + 2] = (Math.random() - 0.5) * 10
}
const particleGeometry = new THREE.BufferGeometry()
particleGeometry.setAttribute('position',new THREE.BufferAttribute(positions,3))const particleMaterial = new THREE.PointsMaterial()
particleMaterial.size = 0.03
particleMaterial.color = new THREE.Color(parameters.materialColor)
particleMaterial.sizeAttenuation = true // 衰减const particle = new THREE.Points(particleGeometry,particleMaterial
)
scene.add(particle)

3.gsap

实现动画效果,在到达某一个几何体时 进行旋转

npm i gasp@3.5.1

import * as THREE from 'three'
import * as dat from 'lil-gui'
import gsap from 'gsap'/*** Debug*/
const gui = new dat.GUI()const parameters = {materialColor: '#ffeded'
}gui.addColor(parameters, 'materialColor').onChange(()=>{material.color.set(parameters.materialColor)particleMaterial.color.set(parameters.materialColor)})/*** Base*/
// Canvas
const canvas = document.querySelector('canvas.webgl')// Scene
const scene = new THREE.Scene()/* Objects
*/
// Texture
const textureLoad = new THREE.TextureLoader()
const gradientTexture = textureLoad.load('/textures/gradients/3.jpg')
gradientTexture.magFilter = THREE.NearestFilter // 设置最近过滤器 牵扯到WebGL原理// material
const material = new THREE.MeshToonMaterial({color:parameters.materialColor,gradientMap:gradientTexture  // 卡通色渐变贴图 需要设置这个
})// Mesh
const objectsDistance = 4
const mesh1 = new THREE.Mesh(new THREE.TorusGeometry(1,0.4,16,60),material
)
const mesh2 = new THREE.Mesh(new THREE.ConeGeometry(1,2,32),material
)
const mesh3 = new THREE.Mesh(new THREE.TorusKnotGeometry(0.8, 0.35, 100, 16),material
)const sectionMeshes = [mesh1,mesh2,mesh3]mesh1.position.y = - objectsDistance * 0
mesh2.position.y = - objectsDistance * 1
mesh3.position.y = - objectsDistance * 2mesh1.position.x = 2
mesh2.position.x = -2
mesh3.position.x = 2scene.add(mesh1,mesh2,mesh3)/* Particles
*/
const particleCount = 200
const positions = new Float32Array(particleCount * 3)
// 设置粒子位置
for(let i = 0; i< particleCount;i++){positions[i * 3 + 0] = (Math.random() - 0.5) * 10positions[i * 3 + 1] = objectsDistance * 0.5 - Math.random() * objectsDistance * 3positions[i * 3 + 2] = (Math.random() - 0.5) * 10
}
const particleGeometry = new THREE.BufferGeometry()
particleGeometry.setAttribute('position',new THREE.BufferAttribute(positions,3))const particleMaterial = new THREE.PointsMaterial()
particleMaterial.size = 0.03
particleMaterial.color = new THREE.Color(parameters.materialColor)
particleMaterial.sizeAttenuation = true // 衰减const particle = new THREE.Points(particleGeometry,particleMaterial
)
scene.add(particle)/* Lights
*/
const directionalLight = new THREE.DirectionalLight('#ffffff',1)
directionalLight.position.set(1,1,0)
scene.add(directionalLight)/*** Sizes*/
const sizes = {width: window.innerWidth,height: window.innerHeight
}window.addEventListener('resize', () =>
{// Update sizessizes.width = window.innerWidthsizes.height = window.innerHeight// Update cameracamera.aspect = sizes.width / sizes.heightcamera.updateProjectionMatrix()// Update rendererrenderer.setSize(sizes.width, sizes.height)renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})/* Group
*/
const cameraGroup = new THREE.Group()
scene.add(cameraGroup)/*** Camera*/
// Base camera
const camera = new THREE.PerspectiveCamera(35, sizes.width / sizes.height, 0.1, 100)
camera.position.z = 6
cameraGroup.add(camera)/*** Renderer*/
const renderer = new THREE.WebGLRenderer({canvas: canvas,alpha:true,
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))/* Scroll
*/
let scrollY = window.scrollY // 获取滚动条y的数据
let currentSection = 0
window.addEventListener('scroll',()=>{scrollY = window.scrollYconst newSection = Math.round(scrollY / sizes.height) // 四舍五入判断 几何体旋转的时机if(newSection != currentSection){currentSection = newSectionconsole.log(sectionMeshes[currentSection].rotation)gsap.to(sectionMeshes[currentSection].rotation, // 设置动画 0,1,2的动画效果{duration:1.5, // 时间ease:'power2.inOut', // 进出x:'+=6',y:'+=3',z:'+=1.5',})}
})/* Cursor
*/
const cursor = {}
cursor.x = 0
cursor.y = 0window.addEventListener('mousemove',(event)=>{cursor.x = event.clientX / sizes.width - 0.5cursor.y = event.clientY / sizes.height - 0.5
})/*** Animate*/
const clock = new THREE.Clock()
let previousTime = 0
const tick = () =>
{const elapsedTime = clock.getElapsedTime()const deltaTime = elapsedTime - previousTimepreviousTime = elapsedTime// Aniamte Camera   // 由于几何体 沿着y轴移动 objectsDistance 单位 所以 scrollY / sizes.height 是一比一的,* objectsDistance 就有了四个单位 camera.position.y = - scrollY / sizes.height * objectsDistanceconst parallaxX = cursor.x * 0.5const parallaxY = -cursor.y * 0.5cameraGroup.position.x += (parallaxX - cameraGroup.position.x) * 5 * deltaTimecameraGroup.position.y += (parallaxY - cameraGroup.position.y) * 5 * deltaTime// Aniamte meshesfor(const mesh of sectionMeshes){ // 每一帧变化时,应该改变mesh.rotation.x +=  deltaTime * 0.1mesh.rotation.y +=  deltaTime * 0.12}// Renderrenderer.render(scene, camera)// Call tick again on the next framewindow.requestAnimationFrame(tick)
}tick()

camera 视角移动 几何体动画


总结

数学不要记,主要看他怎么用, 在哪里用的!

相关文章:

【Three.js基础学习】15.scroll-based-animation

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 前言 课程要点 结合html等场景 做滚动动画 1.遇到的问题&#xff0c; 在向下滚动时&#xff0c;下方会显白&#xff08;部分浏览器&#xff09; 解决&#xff1a;alpha:true …...

ubantu安装mysql

安装 准备&#xff1a;下载&#xff1a;版本5.1.17的MySQL并上传至Ubuntu系统 #解压 tar -xvf mysql-server_5.7.17-1ubuntu16.10_amd64.deb-bundle.tar #提前安装插件 sudo apt-get install libaio1 libmecab2 #若安装失败使用以下命令 apt --fix-broken install sudo apt-g…...

注意!华为HCIP-Datacom认证考试题有变化!

01 注意 HCIP Datacom H12-831考试变题了&#xff0c;最近要考试的多观望一下&#xff0c;821目前稳定。 华为HCIP考试以后要加难度&#xff0c;增加实验题&#xff0c;还没考完的小伙伴抓紧时间了。 02 华为HCIP认证大更新 未来将增加实验考试&#xff0c;拒绝背题库的Pass&a…...

你是我的荣耀 | 林先生:从酷爱数学到毕业走向数据分析岗位

人物背景&#xff1a; 研究生国家奖学金、本科生国家奖学金、学业奖学金一等奖、上海市优秀毕业生&#xff1b; 应用统计专业 CPDA优秀学员 ## 为什么选择数据分析相关专业 我是应用统计专业的一个应届毕业生&#xff0c;目前在一家上海市属的国企&#xff0c;从事数据分析相关…...

操作系统真象还原-bochs安装

今天读了《操作系统真象还原》这本书&#xff0c;写上比较幽默通俗。书中例子需要安装一个bochs系统&#xff0c;记录一下安装过程。参考了书中1.4&#xff0c;1.5两节&#xff0c;书中尽让有两处问题&#xff0c;也记录了下来。 1.3 操作系统的宿主环境 下载地址&#xff1a…...

windows平台安装labelme

之前写过一篇文章也是关于在windows平台安装labelme的&#xff1a;《windows平台python版labelme安装与使用_labelme下载-CSDN博客》&#xff0c;随着软件与工具的更新换代&#xff0c;按照同样的方法最近在使用的时候出现了错误&#xff0c;出现创建虚拟环境失败&#xff0c;具…...

微服务之SpringCloud AlibabaSeata处理分布式事务

一、概述 1.1背景 一次业务操作需要跨多个数据源或需要跨多个系统进行远程调用&#xff0c;就会产生分布式事务问题 but 关系型数据库提供的能力是基于单机事务的&#xff0c;一旦遇到分布式事务场景&#xff0c;就需要通过更多其他技术手段来解决问题。 全局事务&#xff1a;…...

2005-2021年全国各地级市生态环境注意力/环保注意力数据(根据政府报告文本词频统计)

2005-2021年全国各地级市生态环境注意力/环保注意力数据&#xff08;根据政府报告文本词频统计&#xff09; 2005-2021年全国各地级市生态环境注意力/环保注意力数据&#xff08;根据政府报告文本词频统计&#xff09; 1、时间&#xff1a;2005-2021年 2、范围&#xff1a;2…...

熟悉这些道理可以让人更好地应对各种挑战和困难。

1. 为别人尽最大的力量&#xff0c;最后就是为自己尽最大的力量。——罗斯金 2. 世上有一条永恒不变的法则:当你不在乎&#xff0c;你就得到。当你变好&#xff0c;你才会遇到更好的。只有当你变强大&#xff0c;你才不害怕孤单。当你不害怕孤单&#xff0c;你才能够宁缺毋滥。…...

AI去衣技术在动画制作中的应用

随着科技的发展&#xff0c;人工智能&#xff08;AI&#xff09;已经在各个领域中发挥了重要作用&#xff0c;其中包括动画制作。在动画制作中&#xff0c;AI去衣技术是一个重要的工具&#xff0c;它可以帮助动画师们更加高效地完成工作。 AI去衣技术是一种基于人工智能的图像…...

卷积神经网络要点和难点实际案例和代码解析

卷积神经网络(Convolutional Neural Networks,CNN)是一类包含卷积计算且具有深度结构的前馈神经网络,是深度学习的代表算法之一。卷积神经网络仿造生物的视知觉机制构建,可以进行监督学习和非监督学习,其隐含层内的卷积核参数共享和层间连接的稀疏性使得卷积神经网络能够…...

initramfs及rpm/dracut操作

一、背景 更新bundle包后发现系统异常。 定位发现驱动升级不成功&#xff0c;内核启动后加载的还是更新前的旧驱动。但等内核启动完成后&#xff0c;卸载旧驱动手动insmod新驱动&#xff0c;是可以加载成功的。 驱动的安装目录在/lib/modules/$KERNELVERSION/extra目录下。 …...

Kafka 2.13-3.7.0 在 Windows 上的安装与配置指南

在本文中&#xff0c;我将引导您完成在Windows操作系统上安装Apache Kafka 2.13-3.7.0的全过程&#xff0c;包括下载Scala运行环境、Kafka软件包、配置相关设置&#xff0c;并最终启动Kafka服务。此外&#xff0c;还会简要介绍如何使用客户端工具进行查看和管理。 Kafka的命名…...

C++ 顺序线性表的功能

顺序线性表的功能 //头文件 #pragma once#define LIST_INIT_SIZE 50 #define LIST_INCREMENT 20 #define OK 1 #define ERROR 0typedef int Status;typedef char ElemType;typedef struct list_ {ElemType* elem;int length;int listize; }SqList;// 1 初始化 函数 Status…...

C++面经 每日一问(二)

将引用作为函数参数有什么影响&#xff1f; 传递引用给函数与传递指针的效果相同。这意味着被调函数中的形参变量将成为主调函数中实参的别名&#xff0c;从而直接对目标对象进行操作。相比于传递指针&#xff0c;这种方式消除了对指针的繁琐操作&#xff0c;提高了代码的清晰性…...

最新版Ceph( Reef版本)块存储简单对接k8s

当前ceph 你的ceph集群上执行 1.创建名为k8s-rbd 的存储池 ceph osd pool create k8s-rbd 64 642.初始化 rbd pool init k8s-rbd3 创建k8s访问块设备的认证用户 ceph auth get-or-create client.kubernetes mon profile rbd osd profile rbd poolk8s-rbd部署 ceph-rbd-csi c…...

Vue生命周期都有哪些?

定义 Vue的生命周期就是实例从创建到销毁的一个过程&#xff0c;即从创建、初始化数据、编译模板、挂载Dom($el)->渲染、更新->渲染&#xff0c;卸载等一系列的过程。el是挂载点如<div id"app"></div>。 Vue的生命周期分为八个阶段 1.beforeCreate…...

景源畅信:个人抖音小店怎么开通?

在数字时代的浪潮中&#xff0c;个体创业已不再是遥不可及的梦想。特别是随着短视频平台的崛起&#xff0c;抖音不仅成为人们娱乐消遣的新宠&#xff0c;更是众多创业者眼中的“新大陆”。你是否也曾憧憬过在抖音上开一家属于自己的小店?那么&#xff0c;如何开通个人抖音小店…...

python学习笔记B-16:序列结构之字典--字典的遍历与访问

下面是字典的访问和遍历方法&#xff1a; d {10:"hello",20:"python",30:"world"} print(d[10],"--",d[20],"--",d[30]) print(d.get(10)) print("以上两种访问方式的区别是&#xff0c;d[key]若键是空值&#xff0c…...

《QT实用小工具·四十八》趣味开关

1、概述 源码放在文章末尾 该项目实现了各种样式的趣味开关&#xff1a; 1、爱心形状的switch开关&#xff0c;支持手势拖动、按压效果 2、线条样式的3种开关 项目demo演示如下所示&#xff1a; 使用方式&#xff1a; 1、sapid_switch文件夹加入工程&#xff0c;.pro文件中…...

QML进阶(十四) Model-View-Delegate视图框架

文章目录 数据模型(Model)C++数据模型XmlListModelRepeater模型视图框架(View)ListViewTableViewGridViewPathViewMVC(Model-View-Controller)模式将视图系统拆分为模型、视图、控制器三部分,每个部分都相对独立职责单一。模型(model)负责管理视图的数据并对外提供服务。视图(…...

word:三线表的绘制【攻略】

word&#xff1a;三线表的绘制【攻略】 前言版权推荐word&#xff1a;三线表的绘制效果简单方法另外的方法 最后 前言 2024-5-7 18:25:08 以下内容源自《【攻略】》 仅供学习交流使用 版权 禁止其他平台发布时删除以下此话 本文首次发布于CSDN平台 作者是CSDN日星月云 博客…...

嵌入式物联网系统软硬件基础知识大全(2)

接口技术 1. Flash存储器 (1)Flash存储器是一种非易失性存储器,根据结构的不同可以将其分为NOR Flash和NAND Flash两种。 (2)Flash存储器的特点: A、区块结构:在物理上分成若干个区块,区块之间相互独立。 B、先擦后写:Flash的写操作只能将数据位从1写成0,不能从…...

Origin拟合EIS(电化学阻抗谱),怎么出来圆圈

1.先导入数据&#xff0c;以点图的形式画出来 2.重要的一步Fitting&#xff0c;按照我这个一步一步来就行 3.将其中的Function选择为Elipse&#xff0c;然后点拟合至最佳条件 4.第三步做完就会发现圆圈已经出来了&#xff0c;然后点OK就行 5.搞定...

Android APP转成launcher

一、背景 使用场景&#xff0c;需要开机的时候&#xff0c;自动启动app&#xff0c;解决方案为将Android app转成 launcher app&#xff0c;可实现效果。 二、实现 在app入口activity 的配置文件&#xff08;AndroidManifest.xml&#xff09;对应位置&#xff0c;添加 <cat…...

【副本向】Lua副本逻辑

副本生命周期 OnCopySceneTick() 子线程每次心跳调用 --副本心跳 function x3323_OnCopySceneTick(elapse)if x3323_g_IsPlayerEnter 0 thenreturn; -- 如果没人进入&#xff0c;则函数直接返回endif x3323_g_GameOver 1 thenif x3323_g_EndTick > 0 thenx3323_CountDown…...

ROS机器人实用技术与常见问题解决

问题速查手册&#xff08;时实更新&#xff09;更加全面丰富的问题手册记录 1.机器人使用GPARTED挂载未分配空间 需要在图型界面下操作&#xff0c;建议使用no machine连接 安装gparted磁盘分区工具, sudo apt-get install gparted -y 启动软件 sudo gparted 点击磁盘/内存…...

Linux学习之IP协议

前言&#xff1a; 在学习IP协议i前&#xff0c;我们其实知道网络协议栈是一层层的&#xff0c;上层封装好之后就传给下层&#xff0c;对于我们正要学习到的TCP协议&#xff0c;在对数据进行封装之后&#xff0c;并不是直接就将数据进行传输&#xff0c;而是交给下一层网络层进…...

Python Dash库:一个Web应用只需几行代码

大家好&#xff0c;在数据科学领域&#xff0c;数据可视化是将数据以图形化形式展示出来&#xff0c;帮助我们更直观地理解数据。Python中有一个非常流行的数据可视化库叫做Dash&#xff0c;Dash以其简洁、高效和强大的功能而闻名&#xff0c;它允许开发者快速构建交互式Web应用…...

用Docker 创建并运行一个MySQL容器

可以在DockerHub官网上荡:mysql - Official Image | Docker Hub 指令是:docker pull mysql; 因为文件比较大可能时间比较长&#xff0c;我是跟着黑马的课走的 课程提供的有文件&#xff0c;我就用已有的资源了。 在tmp目录里放入mysql.tar包 然后cd进去 输入指令:docker lo…...

在Java中如何有效地处理内存泄露

在Java中&#xff0c;处理内存泄露有多种方法&#xff0c;以下是其中三种常见的方法及其原理和适用场景&#xff1a; ## 1. 合理使用垃圾回收机制 Java中的垃圾回收机制&#xff08;Garbage Collection&#xff0c;GC&#xff09;是一种自动化的内存管理技术&#xff0c;它可以…...

值得收藏!修复Windows 10/11中找不到输出或输入设备的五种方法

序言 这篇文章主要关注处理声音输出/输入设备未发现的问题。它提供了许多可行的方法,帮助了许多Windows用户。阅读以下内容以找到你的解决方案。 最近,我将Windows 10更新到21H2,发现我的音频无法工作。当我把鼠标放在任务栏上的声音图标(上面有一个十字图标)上时,它会…...

Slurm运行pytorch深度学习模型(小白版)

Slurm背景&#xff1a; Slurm 是一种开源的作业调度系统&#xff0c;它用于管理大型计算集群中的计算资源和作业。你可以把它想象成一个“交通管制员”&#xff0c;负责管理计算集群中的各种任务&#xff0c;确保它们按照用户设定的规则有序地执行。 Slurm 的主要功能包括&…...

SQL如何利用Bitmap思想优化array_contains()函数

目录 0 问题描述 1 位图思想 2 案例实战 3 小结 0 问题描述 在工作中&#xff0c;我们往往使用array_contains()函数来进行存在性问题分析&#xff0c;如判断某个数是否在某个数组中&#xff0c;但是当表数据量过多&#xff0c;存在大量array_contains()函数时&#xff0c;…...

面试官:打开了一个新窗口,怎么知道这个窗口已经被打开过?

前言 我们现在来想这么一个场景&#xff0c;在掘金的文章管理页打开了一篇文章草稿&#xff0c;然后点击编辑&#xff0c;这个时候打开新标签页 A &#xff0c;再点击一次编辑&#xff0c;打开了标签页 B 。 此时如果你在 A 编辑&#xff0c; B 是感知不到 A 的内容变动的&am…...

机器学习项目实践-基础知识部分

环境建立 我们做项目第一步就是单独创建一个python环境&#xff0c;Python新的隔离环境 创建&#xff1a;python -m venv ml 使用&#xff1a;.\Scripts\activate python -m venv ml 是在创建一个名为 ml 的虚拟环境&#xff0c;这样系统会自动创建一个文件夹ml&#xff0c;…...

CNN卷积神经网络,TensorFlow面试题

目录 CNN卷积神经网络 什么是TensorFlow? 张量是什么 TensorFlow有什么优势?...

Android 官网Ota介绍

构建 OTA 软件包 | Android 开源项目 | Android Open Source Project...

Redis(持久化)

文章目录 1.RDB1.介绍2.RDB执行流程3.持久化配置1.Redis持久化的文件是dbfilename指定的文件2.配置基本介绍1.进入redis配置文件2.搜索dbfilename&#xff0c;此时的dump.rdb就是redis持久化的文件3.搜索dir&#xff0c;每次持久化文件&#xff0c;都会在启动redis的当前目录下…...

基于Flask的岗位就业可视化系统(一)

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 前言 本项目综合了基本数据分析的流程&#xff0c;包括数据采集&#xff08;爬虫&#xff09;、数据清洗、数据存储、数据前后端可视化等 推荐…...

嵌入式学习68-C++(运算符重载和虚函数)

知识零碎&#xff1a; cin >> n 相当于scanf C系统提供的6种基本函数 …...

UVA1048/LA3561 Low Cost Air Travel

UVA1048/LA3561 Low Cost Air Travel 题目链接题意输入格式输出格式 分析AC 代码 题目链接 本题是2006年ICPC世界总决赛的A题 题意 很多航空公司都会出售一种联票&#xff0c;要求从头坐&#xff0c;上飞机时上缴机票&#xff0c;可以在中途任何一站下飞机。比如&#xff0c;假…...

学习和分析各种数据结构所要掌握的一个重要知识——CPU的缓存利用率(命中率)

什么是CPU缓存利用率&#xff08;命中率&#xff09;&#xff0c;我们首先要把内存搞清楚。 硬盘是什么&#xff0c;内存是什么&#xff0c;高速缓存是什么&#xff0c;寄存器又是什么&#xff1f; 我们要储存数据就要运用到上面的东西。首先里面的硬盘是可以无电存储的&#…...

IOS自动化—将WDA打包ipa批量安装驱动

前言 CSDN&#xff1a; ios自动化-Xcode、WebDriverAgent环境部署 ios获取原生系统应用的包 如果Mac电脑没有配置好Xcode相关环境,可以参考以上文章。 必要条件 Mac电脑&#xff0c;OS版本在12.4及以上&#xff08;低于这个版本无法安装Xcode14&#xff0c;装不了Xcode14就…...

SAP PP学习笔记12 - 评估MRP的运行结果

上一章讲了MRP的概念&#xff0c;参数&#xff0c;配置等内容。 SAP PP学习笔记11 - PP中的MRP相关概念&#xff0c;参数&#xff0c;配置-CSDN博客 本章来讲 MRP跑完之后呢&#xff0c;要怎么评估这个MRP的运行结果。 1&#xff0c;Stock/Requirements List and MRP List 在…...

AndroidStudio的Iguana版的使用

1.AndroidStudio介绍 Android Studio 是用于开发 Android 应用的官方集成开发环境 (IDE)。Android Studio 基于 IntelliJ IDEA 强大的代码编辑器和开发者工具&#xff0c;还提供更多可提高 Android 应用构建效率的功能&#xff0c;例如&#xff1a; 基于 Gradle 的灵活构建系统…...

通过方法引用获取属性名的底层逻辑是什么?

很多小伙伴可能都用过 MyBatis-Plus&#xff0c;这里边我们构造 where 条件的时候&#xff0c;可以直接通过方法引用的方式去指定属性名&#xff1a; LambdaQueryWrapper<Book> qw new LambdaQueryWrapper<>(); qw.eq(Book::getId, 2); List<Book> list bo…...

自学错误合集--项目打包报错,运行报错持续更新中

java后端自学错误总结 一.项目打包报错2.项目打包之后运行报错 二.项目运行报错 一.项目打包报错 javac: &#xfffd;Ҳ&#xfffd;&#xfffd;&#xfffd;&#xfffd;ļ&#xfffd;: E:\xx\xx\xx\docer-xx\src\main\java\xx\xx\xx\xx\xx\xx.java &#xfffd;&#xff…...

KUKA机器人故障报警信息处理(一)

1、KSS00276 机器人参数不等于机器人类型 ①登录专家模式 ②示教器操作&#xff1a;【菜单】—【显示】—【变量】—【单个】 ③名称输入&#xff1a;$ROBTRAFO[] 新值&#xff1a;TRAFONAME[] ④点击【设定值】。 2、电池报警&#xff1a; ①“充电电池警告-发现老化的蓄电池…...

数仓开发:DIM层数据处理

一、了解DIM层 这个就是数仓开发的分层架构 我们现在是在DIM层&#xff0c;从ods表中数据进行加工处理&#xff0c;导入到dwd层&#xff0c;但是记住我们依然是在DIM层&#xff0c;而非是上面的ODS和DWD层。 二、处理维度表数据 ①先确认hive的配置 -- 开启动态分区方案 -- …...

盘点2024年自动猫砂盆品牌,哪个牌子自动猫砂盆比较好?

养猫之路漫漫&#xff0c;无论是新手还是老手&#xff0c;都需要细心照料猫咪的每一个需求。特别是在选择自动猫砂盆这个问题上&#xff0c;更是让人头疼不已。因为每只猫咪的喜好和习惯都不同&#xff0c;如果猫砂盆选得不对&#xff0c;猫咪可能会拒绝使用&#xff0c;导致家…...

好用的Tipard 蓝光转换器 (Tipard Blu-ray Converter) mac&win

Tipard Blu-ray Converter 是一款令人惊叹的蓝光解决方案软件&#xff0c;可将蓝光光盘/文件夹转换为 1:1 质量的数字格式&#xff0c;速度提高 30 倍&#xff0c;用于 4K UHD 和 1080p 高清视频。它可以将蓝光光盘和文件夹中的蓝光电影转换为MKV、MP4、WMV、MOV、AVI、FLV、VO…...

Originx的创新解法之:应用程序故障篇

Originx并不期望做一个完整覆盖全栈的监控体系&#xff0c;而是利用北极星指标体系标准化找出故障方向&#xff0c;然后联动各种成熟的监控数据形成证据链条&#xff0c;并将各种数据融合在一个故障报告之中。更多信息请参考 Log | Metrics | Trace的联动方式探讨http://mp.wei…...

贷款借钱平台 贷款源码 小额贷款系统 卡卡贷源码 小额贷款源码 贷款平台

贷款平台源码/卡卡贷源码/小贷源码/完美版 &#xff0c; 数据库替换application/database.php 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/89268533 更多资源下载&#xff1a;关注我。...

每天Get一个小技巧:用DolphinScheduler实现隔几天调度

转载自tuoluzhe8521 这篇小短文将教会你如何使用Apache DolphinScheduler实现隔几天调度&#xff0c;有此需求的小伙伴学起来&#xff01; 1 场景分析 DolphinScheduler定时器模块-定时调度时每3秒|每3分钟|每3天这种定时&#xff0c;不能够跨分钟&#xff0c;跨小时&#x…...

卷轴分红商城模式:适用于多种的商业营销模式

卷轴分红商城模式是一种基于区块链技术的去中心化积分商城系统&#xff0c;通过智能合约和数字资产分红实现积分流通和价值回馈&#xff0c;适用于多种场景。 什么是卷轴分红商城模式&#xff1a; 这是一个去中心化的积分商城系统&#xff0c;消费者在商城消费时&#xff0c;可…...