Three.js的入门案例(下)

共 8965字,需浏览 18分钟

 ·

2021-03-03 02:17

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


“在看”我吗?


浏览 38
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报