关注初识Threejs与小编一起学习成长
在上一篇案例中实现了几何体-球体旋转效果,今天继续丰富这个案例效果,在球体的周围添加光圈及旋转模块(图片+文字组成),均匀的分布在球体周围,围绕着球体逆时针旋转,最终效果如图:
知识点
1、基础线条材料、线条模型;
2、矩形平面模型;
3、射线拾取;
01
绘制光圈
围绕着球体绘制光圈。定义好参数(大小、透明度、颜色等),循环绘制四个大小不一,不同透明度的椭圆,调整好位置,效果如图:
代码如下:
_this.drawCircle=function(){
//光圈参数(大小、透明度)
var param = [
{ size: 7, opacity: '.3' },
{ size: 8, opacity: '.5' },
{ size: 9.5, opacity: '1' },
{ size: 11, opacity: '.2' }
];
var line;
for (var j = 0; j < param.length; j++) {
//基础线条材料
var lineMaterial = new THREE.LineBasicMaterial({
transparent: true, // 开启透明
opacity: param[j].opacity,// 透明度
color: 'rgb(129,146,255)'//线段颜色
});
//椭圆曲线
var ellipse = new THREE.EllipseCurve(
0,0, //椭圆的中心的x、y坐标
param[j].size,param[j].size, //椭圆在x,y轴的半径
0,//以弧度来表示,从正X轴算起曲线开始的角度
2* Math.PI, //以弧度来表示,从正X轴算起曲线终止的角度
false,//椭圆是否按照顺时针方向来绘制
0//以弧度表示,椭圆从X轴正方向逆时针的旋转角度(可选)
);
var ellipsePath = new THREE.CurvePath();//曲线路径
ellipsePath.add(ellipse);
var ellipseGeometry = ellipsePath.createPointsGeometry(100);//返回几何体对象
//线条模型对象
line = new THREE.Line(ellipseGeometry, lineMaterial);
scene.add(line);//将光圈添加到场景中
line.rotation.x = Math.PI / 2;
line.position.y = -1;
}
}
02
绘制球体周围模块
在球体周围绘制可点击模块,我们这里使用默认图片与业务名称合并生成一张新图片,然后通过矩形平面模型、基础网孔材料设置纹理贴图的方式。核心代码:
_this.drawModel=function(){
var that=this;
//创建一个月亮模型分组
var moons = window.moons = new THREE.Mesh();
/*添加xyz坐标轴*/
// var axesHelper = new THREE.AxesHelper(30);
// moons.add(axesHelper);
//矩形平面模型(x轴宽度、y轴高度、x方向的分段数、y方向的分段数)
//要与map贴图比例成正比,否则图片会变形
var bufferGeometry = new THREE.PlaneBufferGeometry(4, 2, 2, 2);
//基础网孔材料
var basicMaterial = new THREE.MeshBasicMaterial({
// map: textureLoader.load(modelBg),//设置纹理贴图
depthWrite: false,
transparent: true,
alphaTest: 0,
side: 2
});
var planeMesh = new THREE.Mesh(bufferGeometry, basicMaterial);
planeMesh.position.z = 9.5;//球体周围物体的z轴
var moonsBox = new THREE.Mesh();
moonsBox.add(planeMesh);
//循环球体周围的数据
for (var i = 0; i < roundData.length; i++) {
//解决异步循环
(function (i) {
//生成带文字的图片
that.cenerateImages(i,function (d) {
var newMoonBox = moonsBox.clone();//克隆一个网格模型
newMoonBox.children[0].material = newMoonBox.children[0].material.clone();
// console.log(JSON.stringify(roundData[i].imgh));
//更新带文字的图片,保存模块数据(id、索引等)
newMoonBox.children[0].material.map = textureLoader.load(roundData[i].img);
newMoonBox.children[0].roundData = roundData[i].id;
newMoonBox.children[0].roundData_index = i;
//旋转位置,均匀分布球体周围
newMoonBox.rotation.y = Math.PI * 2 / roundData.length * i;
//渲染之后直接执行
newMoonBox.onBeforeRender = function (renderer, scene, camera, geometry, material) {
this.children[0].lookAt(this.children[0].getWorldPosition(new THREE.Vector3()).add(camera.position));
}
moons.add(newMoonBox);
});
})(i)
}
scene.add(moons);//将周围旋转模块添加到场景中
}
在周期性渲染场景方法中添加:
moons.rotation.y += Math.PI / 180 / delay * intc;//球体周围模块旋转
方可围绕球体旋转。
03
触发点击事件
通过使用Raycaster对象来实现(射线拾取)点击效果:
代码如下:
_this.onDocumentClick=function(event) {
var raycaster = new THREE.Raycaster();
var mouseVector = new THREE.Vector3();
event.preventDefault();//防止冒泡
mouseVector.x = (event.offsetX / canvasWidth) * 2 - 1;
mouseVector.y = -(event.offsetY / canvasHeight) * 2 + 1;
raycaster.setFromCamera(mouseVector, camera); // 设置射线拾取的参数
selectObject = raycaster.intersectObjects(moons.children, true)[0];
if (selectObject&&selectObject.object) {
//初始化选中的样式
var clickThat = selectObject.object.parent.children;
if (clickThat.length > 0) {
//清空之前选中样式
for (var i = 0; i < moons.children.length; i++) {
var tempobj=moons.children[i].children[0];
tempobj.material.map = textureLoader.load(roundData[tempobj.roundData_index].img);
}
var idcont = selectObject.object.roundData;//当前选中的值
var idcontIndex = idcont - 1 < 0 ? 0 : idcont - 1;
selectObject.object.material.map = textureLoader.load(roundData[idcontIndex].imgh);//更新当前选中模块样式
}
else {
}
}
else {
}
}
可以通过射线拾取达到与鼠标交互的效果,大家就可以根据自身的业务做出处理,比如弹框等。
04
写在最后
至此这个案例就结束了,在绘制周围模块的方案上不是很友好,要每个模块生成两种状态的图片,大家也可以想想有没有更好的解决方案,期待与您交流学习,快去动手实践吧~
如果你对本文内容有任何建议,欢迎与小编沟通交流,一起学习成长!关注公众号回复three.js,获取完整案例代码。