Three.js的入门案例(下)

 关注初识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,获取完整案例代码。

你“在看”我吗?

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值