提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
课堂知识点
1.粒子
2.PointsMaterial 点材质 ; 可以设置点材质的
size 大小 , sizeAttenuation 设置这个可以 可以实现缩放粒子 近处的大 远处小,设置false 远近都一样大
3. Points() 点网格 ,和Mesh()类似 参数接收几何体 和 材质
注意:使用缓冲几何体 你在画面中什么也看不到;可以先从ShpereGeomatry观看一下效果
4. 想要随机的粒子
https://www.kenney.nl/assets/particle-pack
需要Float32Array 获取数组长度 ,由于一个粒子是 x,y,z 数据 因此在数组中占三位
如果要500个粒子 则 要 500 * 3
const position = new Float32Array(count * 3)
这个时候position 就是相当于500 个 粒子的位置信息
position[i] = Math.random() // 设置粒子位置的随机
// 和上一节对比 都是设置属性 位置, 创建缓冲属性 设置位置数据 和 3
particleGeometry.setAttribute(
'position',
new THREE.BufferAttribute(position,3)
)
添加纹理
可以看到粒子生成 ,但是仔细看背景 是有黑色的背景 要解决
解决方法:
aplhaMap 属性 设置
1. aplhaTest = 0.01 // 阿尔法 测试
但是不是很完美
2. depthTest = false // 深度测试 它会判断当前粒子前方是否有东西 有测渲染 不然不渲染
会有问题 ,有其他的颜色 会很糟糕
3.depthWrite = false // 深度缓冲区
当绘画这些东西时候 他会判断 在这个物体前还是后 ,会有这些信息
可以高度网格 不要在深度缓冲区进行绘画
前三个对于性能不会影响
4.blending 混合 对于性能有点影响
depthWrite = false
blending = THREE.AdditiveBlending
设置粒子颜色不同
1.color 存储不同颜色信息
2.vertexColors = true // 通知
但是particleMaterial.color = new THREE.Color('#ff88cc') 会影响设置的颜色 。有一种混合色的柑橘
动画效果
控制每个粒子如何做
关键在于存储的粒子信息 particleGeometry。attribute.position.array
particleGeometry.attributes.position.needsUpdate = true
自定义着色器
更好的性能
上述进行动画 会有更大的性能消耗 不好
如果想要正确 必须创建自己的材质 ,创建自己的着色器
一、代码
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import * as dat from 'lil-gui'
import { Mesh } from 'three'
/**
* Base
*/
// Debug
const gui = new dat.GUI()
// Canvas
const canvas = document.querySelector('canvas.webgl')
// Scene
const scene = new THREE.Scene()
/**
* Textures
*/
const textureLoader = new THREE.TextureLoader()
const particlesTexture = textureLoader.load('/textures/particles/2.png')
/*
* Particles 粒子
*/
const particleGeometry = new THREE.BufferGeometry(1,32,32)
const count = 50000
const position = new Float32Array(count * 3)
const color = new Float32Array(count * 3)
for(let i=0;i<count * 3;i++){
position[i] = (Math.random() - 0.5) * 10
color[i] = Math.random()
}
particleGeometry.setAttribute(
'position',
new THREE.BufferAttribute(position,3)
)
particleGeometry.setAttribute(
'color',
new THREE.BufferAttribute(color,3)
)
const particleMaterial = new THREE.PointsMaterial()
particleMaterial.size = 0.1
particleMaterial.sizeAttenuation = true
particleMaterial.color = new THREE.Color('#ff88cc')
// particleMaterial.map = particlesTexture
particleMaterial.transparent = true
particleMaterial.alphaMap = particlesTexture
// particleMaterial.alphaTest = 0.01
// particleMaterial.depthTest = false
particleMaterial.depthWrite = false
particleMaterial.blending = THREE.AdditiveBlending
particleMaterial.vertexColors = true
const particles = new THREE.Points(
particleGeometry,
particleMaterial
)
scene.add(particles)
/*
cube
*/
const cube = new THREE.Mesh(
new THREE.BoxGeometry(),
new THREE.MeshBasicMaterial()
)
// scene.add(cube)
/**
* Sizes
*/
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}
window.addEventListener('resize', () =>
{
// 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)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})
/**
* Camera
*/
// Base camera
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)
camera.position.z = 3
scene.add(camera)
// Controls
const controls = new OrbitControls(camera, canvas)
controls.enableDamping = true
/**
* 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()
const tick = () =>
{
const elapsedTime = clock.getElapsedTime()
// Update particles
// particles.rotation.y = elapsedTime * 0.2
for(let i =0 ;i<count ; i++){
const i3 = i * 3
const x = particleGeometry.attributes.position.array[i3] // 粒子 x的位置
particleGeometry.attributes.position.array[i3 + 1] = Math.sin(elapsedTime + x)
}
particleGeometry.attributes.position.needsUpdate = true // 告诉three.js设置好了 要更新
// Update controls
controls.update()
// Render
renderer.render(scene, camera)
// Call tick again on the next frame
window.requestAnimationFrame(tick)
}
tick()
二、知识点
1.PointsMaterial 点材质
size 大小 , sizeAttenuation 设置这个可以 可以实现缩放粒子 近处的大 远处小,设置false 远近都一样大
particleMaterial.size = 0.1
particleMaterial.sizeAttenuation = true
设置颜色和纹理
particleMaterial.color = new THREE.Color('#ff88cc')
particleMaterial.map = particlesTexture
为什么可以生成多个粒子
Float32Array 获取数组长度 由于一个粒子是 x,y,z 数据 因此在数组中占三位
如果要500个粒子 则 要 500 * 3
其中变量position 的位置 可以设置 然后 每三个数组元素组成一个粒子
然后就需要设置几何体的属性 如 颜色 和 位置
particleGeometry.setAttribute(
'position',
new THREE.BufferAttribute(position,3)
)
particleGeometry.setAttribute(
'color',
new THREE.BufferAttribute(color,3)
)
同样生成不同颜色的粒子也是这样
不过要设置vertexColors = true 通知 不然不会渲染上去
const particleGeometry = new THREE.BufferGeometry(1,32,32)
const count = 50000
const position = new Float32Array(count * 3)
const color = new Float32Array(count * 3)
for(let i=0;i<count * 3;i++){
position[i] = (Math.random() - 0.5) * 10
color[i] = Math.random()
}
particleGeometry.setAttribute(
'position',
new THREE.BufferAttribute(position,3)
)
particleGeometry.setAttribute(
'color',
new THREE.BufferAttribute(color,3)
)
const particleMaterial = new THREE.PointsMaterial()
particleMaterial.size = 0.1
particleMaterial.sizeAttenuation = true
particleMaterial.color = new THREE.Color('#ff88cc') // 这里颜色可以去掉 不去掉会影响设置的颜色 ,混合色
particleMaterial.vertexColors = true
让我们再把纹理添加上
仔细看有背景 纯黑色的 ,但是我想要去掉,因为这样效果不是很好
这个时候有很多方法可以去除
解决方法
1.aplhaMap 将纹理设置成阿尔法,同时设置alphaTest
const particleGeometry = new THREE.BufferGeometry(1,32,32)
const count = 50000
const position = new Float32Array(count * 3)
const color = new Float32Array(count * 3)
for(let i=0;i<count * 3;i++){
position[i] = (Math.random() - 0.5) * 10
color[i] = Math.random()
}
particleGeometry.setAttribute(
'position',
new THREE.BufferAttribute(position,3)
)
particleGeometry.setAttribute(
'color',
new THREE.BufferAttribute(color,3)
)
const particleMaterial = new THREE.PointsMaterial()
particleMaterial.size = 0.1
particleMaterial.sizeAttenuation = true
particleMaterial.color = new THREE.Color('#ff88cc')
particleMaterial.transparent = true
particleMaterial.alphaMap = particlesTexture
particleMaterial.alphaTest = 0.01 // 属于缩小 边缘范围 得到类似的效果
particleMaterial.vertexColors = true
const particles = new THREE.Points(
particleGeometry,
particleMaterial
)
scene.add(particles)
效果不是很好 仔细看圆圈重叠处有黑色的边界。
2.同上 不过将阿尔法测试属性 换成 depthTest = false
particleMaterial.depthTest = false // 深度测试 它会判断当前粒子前方是否有东西 有测渲染 不然不渲染
看起来边缘什么的还可以 ,不过在其他颜色会有问题
可以看到颜色有种透视的感觉!
3.depthWrite
因此我们可以设置另一个属性深度缓冲区,可以看到在白色后面的颜色没有显示
const particleGeometry = new THREE.BufferGeometry(1,32,32)
const count = 50000
const position = new Float32Array(count * 3)
const color = new Float32Array(count * 3)
for(let i=0;i<count * 3;i++){
position[i] = (Math.random() - 0.5) * 10
color[i] = Math.random()
}
particleGeometry.setAttribute(
'position',
new THREE.BufferAttribute(position,3)
)
particleGeometry.setAttribute(
'color',
new THREE.BufferAttribute(color,3)
)
const particleMaterial = new THREE.PointsMaterial()
particleMaterial.size = 0.1
particleMaterial.sizeAttenuation = true
particleMaterial.color = new THREE.Color('#ff88cc') // 这里可以去掉
particleMaterial.transparent = true
particleMaterial.alphaMap = particlesTexture
/*
当绘画这些东西时候 他会判断 在这个物体前还是后 ,会有这些信息
可以高度网格 不要在深度缓冲区进行绘画
*/
particleMaterial.depthWrite = false // 这里
const particles = new THREE.Points(
particleGeometry,
particleMaterial
)
scene.add(particles)
前三个对于性能不会影响
4.blending
const particleGeometry = new THREE.BufferGeometry(1,32,32)
const count = 50000
const position = new Float32Array(count * 3)
const color = new Float32Array(count * 3)
for(let i=0;i<count * 3;i++){
position[i] = (Math.random() - 0.5) * 10
color[i] = Math.random()
}
particleGeometry.setAttribute(
'position',
new THREE.BufferAttribute(position,3)
)
particleGeometry.setAttribute(
'color',
new THREE.BufferAttribute(color,3)
)
const particleMaterial = new THREE.PointsMaterial()
particleMaterial.size = 0.1
particleMaterial.sizeAttenuation = true
particleMaterial.color = new THREE.Color('#ff88cc')
particleMaterial.transparent = true
particleMaterial.alphaMap = particlesTexture
particleMaterial.depthWrite = false // 这里 结合depthWrite 使用 效果完美 性能可能有问题
particleMaterial.blending = THREE.AdditiveBlending
particleMaterial.vertexColors = true
const particles = new THREE.Points(
particleGeometry,
particleMaterial
)
scene.add(particles)
2.实现波浪
下面代码主要是数学,头大了! 结合js 和中设置属性的方法
const elapsedTime = clock.getElapsedTime()
// Update particles
particles.rotation.y = elapsedTime * 0.2
for(let i =0 ;i<count ; i++){
const i3 = i * 3
const x = particleGeometry.attributes.position.array[i3] // 粒子 x的位置
//让x的位置随时间上下波动
particleGeometry.attributes.position.array[i3 + 1] = Math.sin(elapsedTime + x)
}
particleGeometry.attributes.position.needsUpdate = true // 告诉three.js设置好了 要更新
波动
总结
点点点。。。