基础环境搭建:
点阵创建:
- 创建立方体几何体对象
let boxGeometry = new THREE.BoxGeometry(50, 50, 50, 1, 1, 1)
console.log(boxGeometry)
- 相同属性顶点合并
position.count==24:立方体共六个面,四个点决定一个面,6*4=24个点,其中8个不重叠的点。
BufferGeometryUtils:一个包含 BufferGeometry 实例的实用方法的类。
.mergeVertices ( geometry : BufferGeometry, tolerance : Number ) : BufferGeometry
geometry – 用于合并顶点的 BufferGeometry 实例。
tolerance – 要合并的顶点属性之间允许的最大差异。 默认为 1e-4。
返回一个新的 BufferGeometry ,其中包含将所有(在容差范围内的)具有相似属性的顶点合并而成的顶点。
// if normal and uv attributes are not removed, mergeVertices() can't consolidate indentical vertices with different normal/uv data
boxGeometry.deleteAttribute('normal')
boxGeometry.deleteAttribute('uv')
boxGeometry = BufferGeometryUtils.mergeVertices(boxGeometry)
console.log(boxGeometry)
- 为合并后的每个不重叠顶点创建color、size属性,保存在相应属性数组中,并将属性添加到新创建的BufferGeometry()上
Color.toArray ( array : Array, offset : Integer ) : Array
array - 存储颜色的可选数组;offset - 数组的可选偏移量
返回一个格式为[ r, g, b ] 数组。
源码理解:
const positionAttribute = boxGeometry.getAttribute('position')
const colors = []
const sizes = []
const color = new THREE.Color()
for (let i = 0; i < positionAttribute.count; i++) {
color.setHSL(0.01 + 0.1 * (i / positionAttribute.count), 1.0, 0.5)
color.toArray(colors, i * 3)
sizes[i] = PARTICLE_SIZE * 0.5
}
const geometry=new THREE.BufferGeometry()
geometry.setAttribute('position',positionAttribute)
geometry.setAttribute('customColor',new THREE.Float32BufferAttribute(colors,3))
geometry.setAttribute('size',new THREE.Float32BufferAttribute(sizes,1))
- 创建着色器材质对象
const material = new THREE.ShaderMaterial({
uniforms: {
color: { value: new THREE.Color(0xffffff) },
pointTexture: { value: new THREE.TextureLoader().load('textures/sprites/disc.png') },
alphaTest: { value: 0.9 }
}
})
material.vertexShader = `
attribute float size;
attribute vec3 customColor;
varying vec3 vColor;
void main() {
vColor = customColor;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_PointSize = size * ( 300.0 / -mvPosition.z );
gl_Position = projectionMatrix * mvPosition;
}
`
material.fragmentShader = `
uniform vec3 color;
uniform sampler2D pointTexture;
uniform float alphaTest;
varying vec3 vColor;
void main() {
gl_FragColor = vec4( color * vColor, 1.0 );
gl_FragColor = gl_FragColor * texture2D( pointTexture, gl_PointCoord );
if ( gl_FragColor.a < alphaTest ) discard;
}
`
- 场景中添加网格模型
Points( geometry : BufferGeometry, material : Material )
geometry —— (可选)是一个BufferGeometry的实例,默认值是一个新的BufferGeometry。
material —— (可选) 是一个对象,默认值是一个PointsMaterial。
particles = new THREE.Points(geometry, material)
scene.add(particles)
- 为达到实例中效果,扩大立方体几何对象大小并添加段数(增加构成几何体的顶点数),并添加旋转效果
let boxGeometry = new THREE.BoxGeometry(200, 200, 200, 16, 16, 16)
...
particles = new THREE.Points(geometry, material)
scene.add(particles)
...
particles.rotation.x += 0.0005
particles.rotation.y += 0.001
交互实现:
- 捕获鼠标坐标
window.addEventListener('pointermove', function (event) {
pointer.x = (event.clientX / window.innerWidth) * 2 - 1
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1
})
- 创建光线投射器raycaster,获取交叉物体数组
raycaster.setFromCamera(pointer, camera)
intersects = raycaster.intersectObject(particles)
- 如果返回的交叉物体数量大于0,取第一个交叉物体(鼠标指到的物体)使其体积变大
if (intersects.length > 0) {
INTERSECTED = intersects[0].index
attributes.size.array[INTERSECTED] = PARTICLE_SIZE * 1.5
attributes.size.needsUpdate = true
}
4.鼠标移开后原点缩小一部分
if (intersects.length > 0) {
// console.log(intersects[0])
if (INTERSECTED !== intersects[0].index) {
attributes.size.array[INTERSECTED] = PARTICLE_SIZE
INTERSECTED = intersects[0].index
attributes.size.array[INTERSECTED] = PARTICLE_SIZE * 1.5
attributes.size.needsUpdate = true
}
} else {
if (INTERSECTED !== null) {
attributes.size.array[INTERSECTED] = PARTICLE_SIZE
attributes.size.needsUpdate = true
INTERSECTED = null
}
}