Threejs - 案例学习 - Deep Sea

425 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

学习一下Threejs 粒子是如何创建的,还有修改一下案例参数!效果很棒!

学习链接

codepen.io/YusukeNakay…

002.gif

功能实现

  • 由点建立的圆形
  • 鼠标移动,移动视角
  • 蓝色是因为 加了 雾 - fog

代码细节

基础搭建

  • camera
  • scene
  • renderer
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 20000)
camera.position.z = 500
			
scene = new THREE.Scene()
scene.fog = new THREE.FogExp2(0x000088, 0.001) // 蓝色的雾

renderer = new THREE.WebGLRenderer() // 渲染器
// Sets device pixel ratio. This is usually used for HiDPI device to prevent blurring output canvas.
renderer.setPixelRatio(window.devicePixelRatio) 
renderer.setSize(window.innerWidth, window.innerHeight) // 窗口大小变化,重新渲染
document.body.appendChild(renderer.domElement) // 添加进body

image.png

如何创建圆形

  • 图形 = 几何(各种点集合 - xyz表示) + 材质
  • const particles = new THREE.Points(geometry, material) // 创建图形 (几何 + 材质)
const geometry = new THREE.BufferGeometry() // 几何体
const vertices = [] // 保存变量(x,y,z) - 用于设置 geometry 的位置!
const size = 2000

// 散布于空中的点 - 尘埃效果!
for (let i = 0; i < 2000; i ++) {
	const x = (Math.random() * size + Math.random() * size) / 2 - size / 2
	const y = (Math.random() * size + Math.random() * size) / 2 - size / 2
	const z = (Math.random() * size + Math.random() * size) / 2 - size / 2
	vertices.push(x, y, z)
}

// 这里是画圆了,具体不了解,不过,改起来还是挺好看的!
// 这里画的 点 - 点多了就成 体了  - 点线面体。。。球体
for (let j = 0; j < 100; j++) {
	const positionX = Math.random() * 3000 - 1500
	const positionY = Math.random() * 3000 - 1500
	const positionZ = Math.random() * 3000 - 1500
	const r = Math.random() * 300 + 50
			
	for (let i = 0; i < 20000; i++) {
		const radian1 = Math.PI / Math.random() * 360
		const radian2 = Math.PI / Math.random() * 360
                let x = Math.cos(radian1) * Math.cos(radian2) * r + positionX
		let y = Math.cos(radian1) * Math.sin(radian2) * r + positionY
		let z = Math.sin(radian1) * r + positionZ
		vertices.push(x, y, z)
	}
}

// .setAttribute ( name : String, attribute : BufferAttribute ) : this
// Sets an attribute to this geometry. Use this rather than the attributes property, 
// because an internal hashmap of .attributes is maintained to speed up iterating over attributes.
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3)) // 几何
material = new THREE.PointsMaterial({ // 材质(点材质)
    size: 2,
    color: 0xffffff,
})
			
const particles = new THREE.Points(geometry, material) // 创建图形 (几何 + 材质)
scene.add(particles) // 添加进场景!

如何移动

  • 在animation函数中设置移动的数据 - 累加!
document.body.addEventListener('pointermove', onPointerMove) // 响应事件!鼠标移动 + 触碰移动!

function onPointerMove (event) {
    // 鼠标当前位置(根据视口位置) - 窗口一半的宽度
    mouseX = event.clientX - windowHalfX 
    mouseY = event.clientY - windowHalfY
}
			
function animate () {
    requestAnimationFrame(animate)
    render()
}
			
function render () {
// 鼠标距离边界移动速度快(mouseX值大), 距离中间,移动速度慢
// 视角聚焦在原点 - camera.lookAt(scene.position)
// 移动位置 - X 轴 和 Y 轴
    camera.position.x += (mouseX * 4 - camera.position.x) * 0.02
    camera.position.y += (-mouseY * 4 - camera.position.y) * 0.02
    camera.lookAt(scene.position)
    renderer.render(scene, camera)
    scene.rotation.x += 0.001 // 场景转动!
    scene.rotation.y += 0.002
}

修改内容!

主要在画圆的地方做了一些修改,效果就很酷!

案例代码

for (let j = 0; j < 100; j++) {
	const positionX = Math.random() * 3000 - 1500
	const positionY = Math.random() * 3000 - 1500
	const positionZ = Math.random() * 3000 - 1500
	const r = Math.random() * 300 + 50
			
	for (let i = 0; i < 20000; i++) {
		const radian1 = Math.PI / Math.random() * 360
		const radian2 = Math.PI / Math.random() * 360
                let x = Math.cos(radian1) * Math.cos(radian2) * r + positionX
		let y = Math.cos(radian1) * Math.sin(radian2) * r + positionY
		let z = Math.sin(radian1) * r + positionZ
		vertices.push(x, y, z)
	}
}

修改代码01

// 都设置为1,位置不变 - 同心圆效果!
    const positionX = 1
    const positionY = 1
    const positionZ = 1

002.gif

修改代码02

// 把两个cos 改为tan - 效果也不错啊!
let x = Math.tan(radian1) * Math.cos(radian2) * r + positionX
let y = Math.tan(radian1) * Math.sin(radian2) * r + positionY
let z = Math.sin(radian1) * r + positionZ

002.gif

修改代码03

// 把两个cos 改为sin - 好多沙漏的感觉。。
let x = Math.sin(radian1) * Math.cos(radian2) * r + positionX
let y = Math.sin(radian1) * Math.sin(radian2) * r + positionY
let z = Math.sin(radian1) * r + positionZ

002.gif

修改代码04


// 保持圆形 - y 轴压缩 - 有点像星系!
let x = Math.cos(radian1) * Math.cos(radian2) * r  + positionX
let y = Math.cos(radian1) * Math.sin(radian2) * r % 2  + positionY
let z = Math.sin(radian1) * r + positionZ

002.gif

修改代码05

// 所有都换成了cos - 像蝴蝶!
let x = Math.cos(radian1) * Math.cos(radian2) * r  + positionX
let y = Math.cos(radian1) * Math.cos(radian2) * r  + positionY
let z = Math.cos(radian1) * r + positionZ

002.gif

修改代码06

修改的是 vertices 放入的值! - 最后整个椭圆吧。。。
vertices.push(x + y, y + z, z + x)

002.gif

总结

改改参数,效果就不一样了,数学好神奇。。。

西湖美景三月天哪,春雨如酒柳如烟哪~