实现原理
利用SphereGeometry先随机生成一个大点的类圆球,取其顶点。
根据顶点数量,生成小球个数,每个小球的位置定位为顶点数据,至此所有小球生成完毕。
两点一线,同理,两个小球的定位位置相连,既是小球相连。根据特定设计算法,设置小球相连关系。
步骤一 生成小球
根据顶点数据生成一系列的小球
addSingleSphereGeometry(position) {
var geometry = new THREE.SphereBufferGeometry( 7, 32, 32 );
var material = new THREE.MeshBasicMaterial( {color: '#949494'} );
var sphere = new THREE.Mesh( geometry, material );
sphere.name = position.name;
sphere.isLine = position.isLine;
sphere.position.set(position.x, position.y, position.z)
this.scene.add( sphere );
}
步骤二 两个小球相连--连线
根据两个小球定位的位置,两个顶点相连
addSingleLineGeometry(points) {
let vectors = [];
points.forEach(item => {
vectors = vectors.concat([item.x, item.y, item.z])
})
const lineGeometry = new THREE.BufferGeometry();
lineGeometry.setAttribute( 'position', new THREE.Float32BufferAttribute( vectors, 3 ) );
const lineMaterial = new THREE.LineBasicMaterial( {
color: 0xffffff,
// lineWidth: 3 由于OpenGL Core Profile与 大多数平台上WebGL渲染器的限制,无论如何设置该值,线宽始终为1。
});
let object = new THREE.Line( lineGeometry, lineMaterial );
this.scene.add(object)
// this.group.add(object);
}
步骤三 设计小球顶点数据格式,小球间连接关系
以下是设计的部分数据,
x,y,z--顶点信息,既是生成小球的定位位置
origin: 小球连线的起始位置。表示数据是该顶点再顶点数组中的下标。
end: 小球连接的终端位置,如有多个,既表示该小球与多个小球相连。表示数据是终端位置顶点再顶点数组中的下标。
isLine: true--表示画线, false--表示不画线
name: 顶点名称,亦可表示其他数据,用作记录小球的特性,方便做一些操作。
vectors_data = [{x: -0, y: 120, z: 0, origin: 0, end: [1,2,3,4,5,6,7,8], isLine: true, name: '0-0'},
{x: -45.92201232910156, y: 110.86554718017578, z: 0, origin: 1, end: [2, 9], isLine: true, name: '0-1'},
{x: -32.47176742553711, y: 110.86554718017578, z: 32.47176742553711, origin: 2, end: [3, 10], isLine: true, name: '0-2'},
{x: -2.811912215659046e-15, y: 110.86554718017578, z: 45.92201232910156, origin: 3, end: [4, 11], isLine: true, name: '0-3'},
{x: 32.47176742553711, y: 110.86554718017578, z: 32.47176742553711, origin: 4, end: [5, 12], isLine: true, name: '0-4'},
{x: 45.92201232910156, y: 110.86554718017578, z: 5.623824431318092e-15, origin: 5, end: [6, 13], isLine: true, name: '0-5'},
{x: 32.47176742553711, y: 110.86554718017578, z: -32.47176742553711, origin: 6, end: [7, 14], isLine: true, name: '0-6'},
{x: 8.435736646977138e-15, y: 110.86554718017578, z: -45.92201232910156, origin: 7, end: [8, 15], isLine: true, name: '0-7'},
{x: -32.47176742553711, y: 110.86554718017578, z: -32.47176742553711, origin: 8, end: [1, 16], isLine: true, name: '0-8'},
{x: -84.85281372070312, y: 84.85281372070312, z: 0, origin: 9, end: [10, 17], isLine: true, name: '0-9'},
{x: -60, y: 84.85281372070312, z: 60, origin: 10, end: [11, 18], isLine: true, name: '0-10'},
{x: -5.19573652087461e-15, y: 84.85281372070312, z: 84.85281372070312, origin: 11, end: [12, 19], isLine: true, name: '0-11'},
{x: 60, y: 84.85281372070312, z: 60, origin: 12, end: [13, 20], isLine: true, name: '0-12'},
{x: 84.85281372070312, y: 84.85281372070312, z: 1.039147304174922e-14, origin: 13, end: [14, 21], isLine: true, name: '0-13'},
{x: 60, y: 84.85281372070312, z: -60, origin: 14, end: [15, 22], isLine: true, name: '0-14'},
{x: 1.5587208715590883e-14, y: 84.85281372070312, z: -84.85281372070312, origin: 15, end: [16, 23], isLine: true, name: '0-15'},
{x: -60, y: 84.85281372070312, z: -60, origin: 16, end: [9, 24], isLine: true, name: '0-16'}]
initSphereAndLine() {
vectors_data.forEach(item => {
this.addSingleSphereGeometry(item)
})
vectors_data.forEach(item => {
if(item.isLine) {
item.end.forEach(i => {
let tempArr = [];
tempArr.push(vectors_data[item.origin])
tempArr.push(vectors_data[i])
console.log(tempArr)
this.addSingleLineGeometry(tempArr)
})
}
})
}
步骤四 监听点击事件,被点击小球,设置成红色
document.addEventListener( 'click', this.mouseClick, false );
mouseClick(event) {
var mouse = new THREE.Vector2();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
this.raycaster.setFromCamera( mouse, this.camera );
var intersects = this.raycaster.intersectObjects( this.scene.children, false );
for ( var i = 0; i < intersects.length; i++ ) {
if(intersects[i].face) {
intersects[ i ].object.material.color.set( 0xff0000 );
}
}
}
备注:基本交互已经实现,点击可以知道选中的小球,做出对应的操作即可。代码非完整的,整体思路既是这样实现的。