关于three.js入门和制作3D地球(第六部分:装饰地球、点等)等)这一章,让我们给我们孤独的地线加点装饰吧(太阳系后面会画)。1.星空背景我们地球的背景一直都是黑色的,这次我们就用星空的图片作为地球的背景。星空背景也是3D的,地球被包裹在其中。你可以把星空想象成一个球体内部的纹理,而我们的“相机”就在球体内。在网上找一张星空的背景图。图片的宽度要大于高度,否则显示不清晰:/cc_map_3d_pro/src/config/earth.config.jsexportdefault{r:80,//radiusbg:require("../assets/images/starrysky.jpg"),//背景图(新)earthBg:require("../assets/images/mapwithtext.png"),//texturepath}在生命周期函数里面我们添加了初始化后台函数mounted(){//...this.initBg();},我们这里要做的就是画一个大球,把我们的地球和相机包裹起来,设置它的贴图Internal。initBg(){//加载星形纹理consttexture=this.textureLoader.load(envConifg.bg);//生成一个球体constsphereGeometry=newTHREE.SphereGeometry(1000,50,50);//反转正负sphereGeometry。规模(-1、1、1);//分配纹理贴图constsphereMaterial=newTHREE.MeshBasicMaterial({map:texture});//生成几何球体this.sphere=newTHREE.Mesh(sphereGeometry,sphereMaterial);//放入场景this.scene.add(this.sphere);},注意newTHREE.SphereGeometry(1000,50,50)第一个参数是球体的半径,这个半径一定不能大于我们的远视点,否则球体会看不见。球体的半径不能太小,否则会有星星离地球很近的现象,后面我们会尝试画太阳系。球体太小,无法绘制。接下来,我将展示设置太小的效果。sphereGeometry.scale(-1,1,1)你可以把它想象成从里到外翻转一个球。不同角度的法线效果:外球体大小超过远视角:外球体大小等于地球半径:2.地球透光?上面有显示问题效果图,也就是我们的地图是镂空的,透过一面可以看到另一面。我们想让地球看起来更坚固。现在我们需要在地球内部放一个球体,通过控制球体的透明度来控制地球的透明度。initInside(){constsphereGeometry=newTHREE.SphereGeometry(envConifg.r-1,50,50);constsphereMaterial=newTHREE.MeshBasicMaterial({color:this.bgColor,opacity:0.9,transparent:true,});这个.InsideSphere=newTHREE.Mesh(sphereGeometry,sphereMaterial);this.scene.add(this.InsideSphere);},注意需要设置transparent:true来设置透明度。之所以将内球体的半径设置为envConifg.r-1,是怕覆盖我国的连接线。如果你想改变内球的颜色,你可以使用this.InsideSphere.material.color.set(this.bgColor)方法。我们来看看两个效果:3.地球光晕(sprite)??????????????????????????????????????????????????无论我们从哪个角度看模型,它始终是面对我们的屏幕,而精灵不会投射任何阴影。newTHREE.Sprite在本质上与newTHREE.BoxGeometry相似,不同之处在于它将创建一个始终面向屏幕的精灵几何体。三、SpriteMaterial是使用Sprite的材质。它与THREE.Sprite是一对。您可以调整颜色、透明度等。首先准备一个类似下面的光环贴图:initSprite(){consttexture=this.textureLoader.load(envConifg.haloBg);constspriteMaterial=newTHREE.SpriteMaterial({map:texture,transparent:true,opacity:0.7,});constsprite=newTHREE.Sprite(spriteMaterial);sprite.scale.set(envConifg.r*Math.PI,envConifg.r*Math.PI,1);这个.scene.add(精灵);},一如既往地介绍“纹理贴图”。只是他需要使用THREE.SpriteMaterial和THREE.Sprite来分配纹理贴图。设置sprite.scale是因为sprite图片一般比较小,所以需要按比例增大。这个数不一定是π,根据你的实际情况输入。比如射击游戏的瞄准星可以使用精灵贴图,又比如3D游戏中,游戏角色的头上会有自己的名字。如果名字不对着我们的屏幕,肯定看不清楚。4.用ps修改精灵图的颜色如果觉得我的光晕不好看可以自己打开ps修改:导入图片点击替换颜色选择自己喜欢的颜色有大有小小,不同的颜色,不同的形状。重要的是这个图形需要与地球中心发射的半径线平行,才能完整显示地球表面。准备一张点图,最好是白色的,这样以后我们可以给它赋予其他颜色:我们在Earth组件中添加一个markSpot方法。此方法支持处理多个和单个对象,接受数组或对象,并在外部使用ref调用此方法如下:markSpot(obj){if(objinstanceofArray){obj.forEach((item)=>{this.object.add(spot(item));});}else{这个对象。添加(点(对象));}},this.object是newTHREE.Object3D生成的容器,可以将多个Mesh存储为一组,形成一个整体。spot是我们接下来要实现的点方法。接收到的obj是一个配置项,包括点颜色、大小、透明度、形状等的配置。使用组件时这样写://...initMarks(){constarr=[{longitude:116.2,latitude:39.56,color:"red",},{经度:76.2,纬度:49.56,颜色:"蓝色",},];这个.$refs.map.markSpot(arr);},开始写标记方法/cc_map_3d_pro/src/utils/sport.config.js的一些默认属性dotconstconfig={size:7,opacity:.8,color:'yellow',url:require('../assets/images/dot.png')}exportdefault(options)=>{return{...config,...options}}/cc_map_3d_pro/src/utils/spot.js,先导入配置项,设置默认值值。从“三”导入*作为三;从“../config/earth.config”导入envConifg;从“./lon2xyz”导入lon2xyz;从“./sport.config”导入mergeConfig;constgeometry=newTHREE.PlaneBufferGeometry(1,1);consttextureLoader=newTHREE.TextureLoader();导出默认函数spot(options){const{经度、纬度、颜色、不透明度、大小、url}=mergeConfig(options);consttexture=textureLoader.load(url);constmaterial=newTHREE.MeshBasicMaterial({color,opacity,map:texture,transparent:true,});constmesh=newTHREE.Mesh(geometry,material);constcoord=lon2xyz(envConifg.r*1.01,longitude,latitude)mesh.scale.set(size,size,size);mesh.position.set(coord.x,coord.y,coord.z);returnmesh;}我们设置默认配置属性,并与用户传入的配置合并。将传入的经纬度转换成直角坐标系的x、y、z值。大小是通过放大和缩小图形来实现的。THREE.PlaneBufferGeometry(1,1)生成平面几何。里面的参数是width和height。这里之所以没有使用宽高来操作图片的大小,是因为这里的设置没有scale那么灵活。获取经纬度时,envConifg.r*1.01是怕和地球上的线重合。效果如下:翻转点虽然位置正确,但是角度肯定不好。现在我们需要计算垂直于半径线需要旋转多少度。这里我们开始涉及一些数学知识。第一步:归一化比如从圆心开始有两条线段,不管这两条线段有多长,它们之间夹角的度数是不会改变的,所以有时候计算一些比例或者角度的时候,如果数据的长度不影响计算结果,那么我们将其归一化,然后计算。归一化的作用就是把你的向量变成一个长度为1的向量。比如你有一个三维向量,长宽高分别为x、y、z,那么它就会变成x*x+y*y+处理后z*z=1console.log(newTHREE.Vector3(10,10,10))console.log(newTHREE.Vector3(1,1,1).normalize())如图图中,红色为x,y和z值都为6的向量归一化后就变成了蓝色线段表示的向量。第二步:XOY平面的法线》法线(normalline)是指始终垂直于某个平面的直线,直线就是z轴,比如直线(0,0,z),z多少无所谓,比如可以写newTHREE.Vector3(0,0,999).normalize(),这里建议直接写newTHREE.Vector3(0,0,1)可以节省一些计算性能第三步:用四元数翻转平面c度'围绕某个向量,它的概念很像复数(i*i=-1),四元数在几何上可以写成i*i=j*j=k*k=i*j*k=-1,通过数学计算可以得到一组旋转坐标的公式。使用四元数设置四元数的旋转角度。setFromUnitVectors('Vector1','Vector2')参数需要归一化。如果向量1旋转到方向向量2所需的旋转角度为n,则目标将旋转n度。刚才我们了解到我们的点图形的法线是(0,0,1),圆心到点的坐标是(x,y,z),那么我们控制它的法线旋转,使得法线与(x,y,z)向量重合,则(x,y,z)向量也将垂直于虚线平面,从而使虚线图形与地球相切。constcoordVec3=newTHREE.Vector3(coord.x,coord.y,coord.z).normalize();constmeshNormal=newTHREE.Vector3(0,0,1);mesh.quaternion.setFromUnitVectors(meshNormal,coordVec3);全部代码import*asTHREEfrom"three";importenvConifgfrom'../config/earth.config';importlon2xyzfrom'./lon2xyz';importmergeConfigfrom'./sport.config';constgeometry=newTHREE.PlaneBufferGeometry(1,1);consttextureLoader=newTHREE.TextureLoader();exportdefaultfunctionspot(options){const{经度、纬度、颜色、不透明度、大小、url}=mergeConfig(选项);consttexture=textureLoader.load(url);constmaterial=newTHREE.MeshBasicMaterial({color,opacity,map:texture,transparent:true,});constmesh=newTHREE.Mesh(geometry,material);constcoord=lon2xyz(envConifg.r*1.01,longitude,latitude)mesh.scale.set(size,size,size);mesh.position.set(coord.x,coord.y,coord.z);缺点tcoordVec3=newTHREE.Vector3(coord.x,coord.y,coord.z).normalize();constmeshNormal=newTHREE.Vector3(0,0,1);mesh.quaternion.setFromUnitVectors(meshNormal,coordVec3);returnmesh;}只需编写一个计时器并不断更改点的大小和颜色即可创建动态点效果。后面这一章专门讲动画,届时我们会统一样式6.地球光束‖‖‖有时我们需要在上的某个坐标点亮一束光,光束的高度代表这里资产的密度,或者销售额商品的体积。THREE.CylinderGeometryconstgeometry=newTHREE.CylinderGeometry(1.5,2,5,100,100);constmaterial=newTHREE.MeshBasicMaterial({color:'red'})constmesh=newTHREE.Mesh(geometry,material);CylinderGeometry的第一个参数是圆的半径,也就是圆锥体的顶部。将其设置为0以获得尖锐的尖锥。CylinderGeometry的第一个参数下的圆的半径是圆锥的底面。第三个参数是圆锥体的高度。第四个圆柱体边沿的线段数,默认为8。第五个圆柱体边沿其高度的线段数,默认为1。注意,圆柱体的默认中心线在y轴上,即用四元数翻转时很有用。封装到函数/cc_map_3d_pro/src/utils/column.config.jsconstconfig={size:7,opacity:.8,color:'yellow',}exportdefault(options)=>{return{...config,...选项}}/cc_map_3d_pro/src/utils/column.jsimport*作为“三”中的三个;从'../config/earth.config'导入envConifg;从'./lon2xyz'导入lon2xyz;从'导入mergeConfig./column.config';exportdefaultfunctioncolumn(options){const{longitude,latitude,color,opacity,size,url}=mergeConfig(options);constmaterial=newTHREE.MeshBasicMaterial({color,opacity,transparent:true,side:THREE.DoubleSide,});constcoord=lon2xyz(envConifg.r*1.01,longitude,latitude)constcoordVec3=newTHREE.Vector3(coord.x,coord.y,coord.z).normalize();constgeometry=newTHREE.CylinderGeometry(0,3,size);constmesh=newTHREE.Mesh(geometry,material);returnmesh}再次利用四元数之间的圆锥特征,我们需要使圆锥的中心线与球面向量重合,所以圆锥的归一化向量你可以选择(0,1,0):mesh.quaternion.setFromUnitVectors(newTHREE.Vector3(0,1,0),coordVec3);效果图:所有代码import*asTHREEfrom"three";从'.importenvConifg./config/earth.config';从'./lon2xyz'导入lon2xyz;从'./column.config'导入mergeConfig;导出默认函数列(选项){const{经度,纬度,颜色,不透明度,大小,url}=mergeConfig(选项);constmaterial=newTHREE.MeshBasicMaterial({color,opacity,transparent:true,side:THREE.DoubleSide,});constcoord=lon2xyz(envConifg.r*1.01,经度,纬度)constcoordVec3=newTHREE.Vector3(coord.x,coord.y,coord.z).normalize();constgeometry=newTHREE.CylinderGeometry(0,3,size);constmesh=newTHREE.Mesh(geometry,material);mesh.position.set(coord.x,coord.y,coord.z);mesh.quaternion.setFromUnitVectors(新三.Vector3(0,1,0),coordVec3);returnmesh}写个定时器就可以了,不断改变柱子的颜色和高度就可以做出动态的锥形闪光效果,下一章会讲到章节专门讲动画的时候,大地飞线的统一风格需要后面单独讨论,因为涉及到的知识有点难,需要详细规划。出现当前国家的提示框。虽然里面会有很多数学概念,但是不要害怕。我会详细描述从0开始理解这些概念的过程,希望和大家一起进步。