javascript 3d网页 简单的 可视化编辑 图形界面 搭建几何体 带导出物体 示例 ( three.js r114 初探 六)

Posted weihexincode

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了javascript 3d网页 简单的 可视化编辑 图形界面 搭建几何体 带导出物体 示例 ( three.js r114 初探 六)相关的知识,希望对你有一定的参考价值。

1 完整代码下载

  https://pan.baidu.com/s/1JJyVcP2KqXsd5G6eaYpgHQ  

  提取码 3fzt (压缩包名: 2020-3-24-demo.zip)

2 图片展示

技术图片技术图片技术图片

3 主要代码

   1 "use strict"
   2 
   3 ;(function (){
   4     
   5     //是否支持WebGL
   6     if(WEBGL.isWebGLAvailable() === false){
   7         document.body.appendChild(WEBGL.getWebGLErrorMessage());
   8         return;
   9     }
  10     
  11     THREE.Cache.enabled = true;//加载器启用缓存
  12     
  13     var _view = new View().initBody();
  14     var _width = _view.size.w;
  15     var _height = _view.size.h;
  16     var _minDistance = 0.1;
  17     var _maxDistance = 5000;
  18     
  19     //three
  20     var _Three = function (){}
  21     
  22     Object.assign(_Three.prototype, {
  23         
  24         constructor: _Three,
  25         
  26         depthMaterial: new THREE.MeshDepthMaterial({depthPacking: THREE.RGBADepthPacking}),
  27         
  28         createScene: function (bg, fog){//场景
  29             let scene = new THREE.Scene();
  30             if(typeof(bg) === "number"){scene.background = bg;}
  31             else if(Array.isArray(bg) === true){
  32                 scene.background = new THREE.CubeTextureLoader()
  33                 .setPath(‘img/cube/skyboxsun25deg/‘)
  34                 .load( [ ‘px.jpg‘, ‘nx.jpg‘, ‘py.jpg‘, ‘ny.jpg‘, ‘pz.jpg‘, ‘nz.jpg‘ ] );
  35             }
  36             if(fog) scene.fog = new THREE.Fog(fog.color, fog.near, fog.far);
  37             return scene;
  38         },
  39         
  40         createCamera: function (fov, width, height, near, far){//相机
  41             let w = width === undefined ? _width : width;
  42             let h = height === undefined ? _height : height;
  43             let camera = new THREE.PerspectiveCamera(fov || 45, w / h, near || _minDistance, far || _minDistance * 1000);
  44             camera.position.set(0, 0, _maxDistance * 0.001);
  45             camera.lookAt( 0, 0, 0 );
  46             return camera;
  47         },
  48         
  49         createRenderer: function (felem, width, height, antialias, lights, shadow, checkShaderErrors){//渲染器
  50             let fel = felem || document.body;
  51             let renderer = new THREE.WebGLRenderer({
  52                 antialias : antialias || false, //抗割齿
  53                 powerPreference:"high-performance" //选择高性能GPU渲染
  54             });
  55             renderer.setSize(width || _width, height || _height);
  56             renderer.setPixelRatio(window.devicePixelRatio);
  57             renderer.gammaFactor = 2.2; //着色校正
  58             renderer.physicallyCorrectLights = lights || false; //使其精确照明
  59             renderer.shadowMap.enabled = shadow || false; //渲染阴影
  60             renderer.debug.checkShaderErrors = checkShaderErrors || false; //
  61             if(!renderer.extensions.get(‘WEBGL_depth_texture‘)){console.log("深度纹理扩展获取失败:WEBGL_depth_texture");}
  62             fel.appendChild(renderer.domElement);
  63             return renderer;
  64         },
  65         
  66         addLinghts: function (scene, hc){//灯光
  67             let a = new THREE.AmbientLight(0x696969);//环境光(无处不在的光,太阳光)
  68             
  69             let b = new THREE.DirectionalLight(0xFFFFFF, 1);//平行光(产生阴影的光)
  70             b.position.set(0, 50, 50);//位置
  71             b.castShadow = true;// 产生动态阴影
  72             //b.target = Object3D; //平行光的方向是从它的位置到目标位置。默认的目标位置为原点 (0,0,0)。
  73             b.shadow.radius = 1;//使阴影边缘变模糊
  74             b.shadow.bias = 0.0001;
  75             b.shadow.mapSize.width = 1024;//阴影质量w
  76             b.shadow.mapSize.height = 1024;//阴影质量h
  77             
  78             //下面属性默认不自动更新
  79         /*     let l_d = 20; //光照区域的大小 100 * 100
  80             b.shadow.camera.left = -l_d;
  81             b.shadow.camera.right = l_d;
  82             b.shadow.camera.top = l_d;
  83             b.shadow.camera.bottom = -l_d; */
  84             b.shadow.camera.near = 0.1;//最近
  85             b.shadow.camera.far = 100;//最远
  86             
  87             
  88            /* var helperShadow = new THREE.CameraHelper(b.shadow.camera);
  89             scene.add(a, b, helperShadow);
  90             var c = ()=>{()=>{helperShadow.update(); hc.update(); }}
  91             new Gui(b.position, ["x", "y", "z"], [-2500, 2500, 1]).change(c)
  92             .add(b.shadow, "radius", [-1, 1, 0.1]).change(c)
  93             .add(b.shadow.mapSize, ["width", "height"], [0, 2048, 1]).change(c)
  94             .title("调试灯光");*/
  95             scene.add(a, b);
  96             return [a, b];
  97         },
  98         
  99         addControls: function (scene, camera, renderer, children){//控件
 100 
 101             //拖放控件
 102             let drag = new THREE.DragControls(children, camera, renderer.domElement);
 103             //drag.addEventListener(‘hoveron‘, (e)=>{this.addTarget(e.object);});
 104             drag.enabled = false;
 105             //this.dragcontrols = dc;
 106             
 107             //轨道控件
 108             let orbit = new THREE.OrbitControls(camera, renderer.domElement);
 109             orbit.target = new THREE.Vector3(0, 0, 0);//控件焦点
 110             //orbit.minPolarAngle = Math.PI * 0.3;//向上最大角度
 111             //orbit.maxPolarAngle = Math.PI * 0.4;//向下最大角度
 112             orbit.minDistance = _minDistance;//最小距离
 113             orbit.maxDistance = _maxDistance;//最大距离
 114             orbit.autoRotateSpeed = 10;//自动旋转速度
 115             //orbit.panSpeed = 100;//鼠标旋转速度
 116             orbit.enableZoom = true;//是否启用缩放
 117             orbit.enableKeys = true;//是否启用键盘
 118             orbit.panSpeed = 1;//鼠标平移速度
 119             orbit.keyPanSpeed = 100;//按键平移的速度
 120             orbit.keys.LEFT = 65;//key a左
 121             orbit.keys.UP = 87;//key w前
 122             orbit.keys.RIGHT = 68;//key d右
 123             orbit.keys.BOTTOM = 83;//key s后
 124             orbit.addEventListener("change", ()=>{this.render(scene, camera, renderer);});
 125             
 126             
 127             //平移控件
 128             var transform = new THREE.TransformControls(camera, renderer.domElement);
 129             transform.addEventListener( ‘dragging-changed‘, (e)=>{orbit.enabled = !e.value;});
 130             transform.addEventListener(‘change‘, ()=>{this.render(scene, camera, renderer);});
 131             scene.add(transform);
 132             
 133             return {drag: drag, orbit: orbit, transform: transform};
 134         },
 135         
 136         updateGeometry: function (mesh, geometry){//更换几何体
 137             if(!mesh || !geometry){
 138                 console.log("_Three: 几何体更换失败"); 
 139                 return;
 140             }
 141             mesh.geometry.dispose();
 142             mesh.geometry = geometry;
 143         },
 144         
 145         updateMaterial: function (mesh, material){//更换材质
 146             if(!mesh || !material){
 147                 console.log("_Three: 材质更换失败"); 
 148                 return;
 149             }
 150             let newMat = material.clone(true);
 151             //newMat.color.copy(mesh.material.color);
 152             newMat.transparent = true;
 153             if(mesh.material.map !== null){this.updateTexture(newMat, mesh.material.map);}
 154             mesh.material.dispose();
 155             mesh.material = newMat;
 156         },
 157         
 158         updateTexture: function (material, texture){//更换纹理
 159             if(!material || !texture){
 160                 console.log("_Three: 纹理更换失败"); 
 161                 return;
 162             }
 163             let map = new THREE.Texture(texture.image);
 164             map.wrapS = THREE.RepeatWrapping;
 165             map.wrapT = THREE.RepeatWrapping;
 166             map.repeat.set(1, 1);
 167             map.minFilter = THREE.NearestFilter;
 168             map.magFilter = THREE.NearestFilter;
 169             if(material.map !== null){
 170                 map.wrapS = material.map.wrapS;
 171                 map.wrapT = material.map.wrapT;
 172                 map.repeat.copy(material.map.repeat);
 173                 map.anisotropy = material.map.anisotropy;
 174                 material.map.dispose();
 175             }
 176             material.map = map;
 177             material.map.needsUpdate = true;
 178             material.needsUpdate = true;
 179         },
 180         
 181         render: function (scene, camera, renderer){//渲染
 182             renderer.render(scene, camera);
 183         },
 184 
 185         getBSP: function (meshA, meshB, type){//剪裁 添加 重合
 186             if(!meshA || !meshB || !type || meshA === meshB){console.log("getBSP:参数错误, 请选择1至2个物体进行运算"); return;}
 187             if(!meshA.geometry || !meshB.geometry) return;
 188             if(meshA.geometry.isGeometry !== true || meshB.geometry.isGeometry !== true) return;
 189             let bsp_a = new ThreeBSP(meshA);//生成ThreeBSP对象
 190             let bsp_b = new ThreeBSP(meshB);//生成ThreeBSP对象
 191             let bsp = bsp_a[type](bsp_b);//进行 type 计算
 192             let mesh = bsp.toMesh();//转换为mesh模型
 193             mesh.geometry.computeFaceNormals();//更新模型的面
 194             mesh.geometry.computeVertexNormals();//更新模型的顶点
 195             mesh.material = meshA.material;//重赋值纹理
 196             return mesh;
 197         },
 198         
 199         toBuffer: function (geometry){//几何体 转为缓存几何体
 200             if(geometry.isGeometry !== true) return;
 201             return new THREE.BufferGeometry().fromGeometry(geometry);
 202         },
 203         
 204         loadingGLTF: function (url, scene){//导入
 205             if(!this.loadGLTF){this.__proto__.loadGLTF = new THREE.GLTFLoader();}
 206             if(!scene) return;
 207             this.loadGLTF.load(url, (gltf)=>{
 208                 scene.add(gltf.scene);
 209             });
 210         },
 211         
 212         exporterGLTF: function (mesh, fileType){//导出物体(限谷歌浏览器)
 213             if(!this.exportGLTF){this.__proto__.exportGLTF = new THREE.GLTFExporter();}
 214             if(!mesh){console.log("mesh 错误"); return;}
 215             // 使用MeshBasicMaterial 或 MeshStandardMaterial 材质 效果会更好
 216             //使用 BufferGeometry 缓存几何体 文件体积会更小
 217             //if(mesh.geometry.isGeometry === true){mesh.geometry = new THREE.BufferGeometry().fromGeometry(mesh.geometry);}
 218             var opt = {
 219                 binary: fileType || this.exportGLTFFileType || false,
 220                 embedImages: true,
 221                 onlyVisible: true,
 222                 truncateDrawRange: true,
 223                 trs: false
 224             };
 225             var download = ( blob, filename )=>{
 226                 let link = _view.add(document.body, "a");
 227                 link.style.display = ‘none‘;
 228                 link.href = URL.createObjectURL( blob ); console.log(link.href);
 229                 link.download = filename;
 230                 link.click();
 231                 _view.remove(link); 
 232             }
 233             
 234             this.exportGLTF.parse(mesh, function ( result ){
 235                 if(result instanceof ArrayBuffer){
 236                     download(new Blob([result], {type: ‘application/octet-stream‘}), ‘scene.glb‘);
 237                 }else{
 238                     download(new Blob([JSON.stringify( result, null, 2 )], {type: ‘text/plain‘}), ‘scene.gltf‘);
 239                 }
 240             }, opt);
 241         },
 242         
 243         runRaycaster: function (o, w, h){//光线投射
 244             o.result.length = 0;
 245             o.vector2.set((o.x / w || _width) * 2 - 1, -(o.y / h || _height) * 2 + 1);
 246             o.raycaster.setFromCamera(o.vector2, o.camera);
 247             o.raycaster.intersectObjects(o.children, o.recursive, o.result);
 248         },
 249         
 250         createClipPlane: function (handCreate){//添加 面 和 点 剪裁面
 251             let pa = new THREE.Plane(new THREE.Vector3( 1, 0, 0 ), 1);
 252             let pb = new THREE.Plane(new THREE.Vector3( 0, -1, 0 ), 1);
 253             let pc = new THREE.Plane(new THREE.Vector3( 0, 0, -1), 1);
 254             let pd = new THREE.Plane(new THREE.Vector3( 0, 1, 1), 1);
 255             
 256             let hg = new THREE.Group();
 257             hg.add(new THREE.PlaneHelper(pa, 2, 0xff0000), new THREE.PlaneHelper(pb, 2, 0x00ff00), new THREE.PlaneHelper(pc, 2, 0x0000ff), new THREE.PlaneHelper(pd, 2, 0x0000ff));
 258             return {
 259                 planes: [pa, pb, pc, pd],
 260                 helpers: hg
 261             };
 262             var geometry = new THREE.SphereGeometry(1, 48, 24);
 263             var material = new THREE.MeshLambertMaterial({
 264                 color: new THREE.Color("#666666"),
 265                 side: THREE.DoubleSide,
 266                 clippingPlanes: clipPlane,
 267                 clipIntersection: true
 268             });
 269             console.log(helper0); console.log(material);
 270             handCreate.add(new THREE.Mesh(geometry, material), helperGroup);
 271             
 272             handCreate.renderer.localClippingEnabled = true;
 273             
 274             //clipPlane.constant = 0.1;
 275             new Gui({constant:0}, [-1, 1, 0.01])
 276             .change((val)=>{
 277                 for(let k = 0; k < clipPlane.length; k++){
 278                     clipPlane[k].constant = val;
 279                 }
 280                 handCreate.update();
 281             })
 282             .add(material, "clipIntersection")
 283             .add(helper0, "size", [0, 10, 0.1])
 284             .change(()=>{handCreate.update();})
 285         }
 286         
 287     });
 288     
 289     
 290     
 291     //几何体
 292     var _Geometry = function (){
 293         _Three.call(this);
 294         //this.width = 100; _width
 295         this.height = 100;
 296         this.y = this.campos.y;
 297         this.dis = 1.5;
 298         this.targetChange = null;
 299         this.objects = [];
 300     }
 301     
 302     _Geometry.prototype = Object.assign(Object.create(_Three.prototype), {
 303         
 304         constructor: _Geometry,
 305         
 306         config: [
 307             new THREE.BoxGeometry(1, 1, 1, 1, 1, 1), 
 308             new THREE.SphereGeometry(0.5, 8 , 6, 0, Math.PI * 2, 0, Math.PI),
 309             new THREE.PlaneGeometry(1, 1, 1, 1)
 310         ],
 311 
 312         campos: {x: _width/110, y: 0, z: 1.5},
 313 
 314         defaultMaterial: new THREE.MeshBasicMaterial({wireframe: true}),
 315         
 316         init: function (){//初始化
 317             if(this.scene === undefined)  this.addScene();
 318             if(this.show === undefined)  this.setShow();
 319             if(this.target === undefined) this.setTarget();
 320             this.renderView(this.config);
 321             return this;
 322         },
 323         
 324         addScene: function (){//添加 场景
 325             let elem = _view.add(document.body, "div", null, "ShowObject box-scroll-block");
 326             _view.addEvent(elem, ‘click‘, (e)=>{this.addTarget(e);});
 327             
 328             let scene = this.createScene(0x000000, false);
 329             var camera = new THREE.OrthographicCamera(_width/-100, _width/100, this.height/100, this.height/-100, 0.1, 10);
 330             camera.lookAt(0, 0, 0);
 331             let renderer = this.createRenderer(elem, _width, this.height, true, true, true, true);
 332             let linghts = this.addLinghts(scene);
 333             let drag = new THREE.DragControls(scene.children, camera, renderer.domElement);
 334             drag.enabled = false;
 335             this.__proto__.scene = {e: elem, s:scene, c: camera, r: renderer, l: linghts, drag: drag, target: null}
 336             drag.addEventListener(‘hoveron‘, (e)=>{this.scene.target = e.object;});
 337             drag.addEventListener(‘hoveroff‘, ()=>{this.scene.target = null;});
 338             this.goToPosition();
 339         },
 340         
 341         addLinghts: function (scene){//重写添加灯光
 342             let a = new THREE.AmbientLight(0x696969);
 343             let b = new THREE.DirectionalLight(0xFFFFFF, 1);
 344             b.position.set(0, 5, 5);
 345             scene.add(a, b);
 346             return [a, b];
 347         },
 348         
 349         goToPosition: function (){//跳转到 geometry 坐标
 350             this.scene.c.position.set(this.campos.x, this.campos.y, this.campos.z);
 351             this.update();
 352         },
 353         
 354         setPos: function (k, mesh){//renderView-> 设置物体之间的距离
 355             mesh.position.set(k * this.dis, this.y, 0);
 356         },
 357         
 358         addMesh: function (object, key){//renderView-> 添加物体
 359             let mesh = new THREE.Mesh(object, this.defaultMaterial);
 360             mesh.HandCreate = {type: "_Geometry", index: key, MatIndex: 0}
 361             this.scene.s.add(mesh);
 362             return mesh;
 363         },
 364         
 365         renderView: function (arr){//渲染场景视图
 366             for(let k = 0; k < arr.length; k++){
 367                 let mesh = this.addMesh(arr[k], k);
 368                 this.setPos(k, mesh);
 369                 this.objects.push(mesh);
 370             }
 371             this.update();
 372         },
 373         
 374         setShow: function (){//是否显示场景的html元素
 375             let _show = false;
 376             Object.defineProperties(this.__proto__, {
 377                 show: {
 378                     get:()=>{return _show;},
 379                     set:(v)=>{
 380                         if(v === true){
 381                             this.scene.e.style.display = "block";
 382                         }else{
 383                             this.scene.e.style.display = "none";
 384                         }
 385                         _show = v;
 386                     }
 387                 }
 388             });
 389         },
 390         
 391         addTarget: function (e){//addScene event->场景html元素的事件回调函数
 392             if(!this.scene.target) return;
 393             this.target = this.scene.target;
 394         },
 395         
 396         setTarget: function (){//配置 target
 397             let _target = null;
 398             Object.defineProperties(this.__proto__, {
 399                 target: {
 400                     get:()=>{return _target;},
 401                     set:(v)=>{
 402                         if(typeof(this.targetChange) === "function") this.targetChange(v);
 403                         _target = v;
 404                     }
 405                 }
 406             });
 407         },
 408         
 409         exportObject: function (){//导出 几何体
 410             
 411         },
 412         
 413         importObject: function (object){//导入 几何体
 414             if(object.isGeometry !== true) return;
 415             let nowKey = this.config.length;
 416             let mesh = this.addMesh(object, nowKey);
 417             this.setPos(nowKey, mesh);
 418             this.config.push(object);
 419             this.objects.push(mesh);
 420             this.update();
 421         },
 422         
 423         update: function (){//更新场景
 424             this.render(this.scene.s, this.scene.c, this.scene.r);
 425         },
 426         
 427         debugCamera: function (){//gui调试 正交相机
 428             let c = this.scene.c;
 429             let pos = {x: _width/110, y: 0, lookAt: true, position: false};
 430             let upd = ()=>{
 431                 if(pos.lookAt) c.lookAt(pos.x, pos.y, 0); 
 432                 if(pos.position) c.position.set(pos.x, pos.y, 5);
 433                 this.update();
 434             }
 435 
 436             new Gui(pos, [0, 10, 0.1], "调试正交相机")
 437             .change({
 438                 x: (v)=>{pos.x = v; upd();},
 439                 y: (v)=>{pos.y = v;  upd();}
 440             })
 441 
 442         }
 443         
 444     });
 445     
 446     
 447     
 448     //材质
 449     var _Material = function (){
 450         _Geometry.call(this);
 451     }
 452     
 453     _Material.prototype = Object.assign(Object.create(_Geometry.prototype), {
 454         
 455         constructor: _Material,
 456         
 457         config:[
 458             new THREE.MeshBasicMaterial(),
 459             new THREE.MeshLambertMaterial(),
 460             new THREE.MeshStandardMaterial()
 461         ],
 462         
 463         defaultGeometry: new THREE.BoxGeometry(1, 1, 1, 1, 1, 1),
 464         
 465         campos: {x: _width/110, y: 1.5, z: 1.5},
 466         
 467         addMesh: function (object, key){
 468             let mesh = new THREE.Mesh(this.defaultGeometry, object);
 469             mesh.HandCreate = {type: "_Material", index: key};
 470             this.scene.s.add(mesh);
 471             return mesh;
 472         },
 473         
 474         goToPosition: function (mesh){
 475             if(!mesh) return; this.mesh = mesh;
 476             let geometry = _Geometry.prototype.config[mesh.HandCreate.GeoCI].clone();
 477             for(let k = 0; k < this.objects.length; k++){
 478                 this.updateGeometry(this.objects[k], geometry);
 479             }
 480             this.scene.c.position.set(this.campos.x, this.campos.y, this.campos.z);
 481             this.update();
 482         }
 483         
 484     });
 485     
 486     
 487     
 488     //纹理 map
 489     var _Texture = function (){
 490         _Material.call(this);
 491         this.textureLen = 12;
 492         this.setTexture();
 493     }
 494     
 495     _Texture.prototype = Object.assign(Object.create(_Material.prototype), {
 496         
 497         constructor: _Texture,
 498         
 499         config: [],
 500         
 501         campos: {x: _width/110, y: 3, z: 1.5},
 502         
 503         defaultMaterial: new THREE.MeshBasicMaterial(),
 504         
 505         load: new THREE.TextureLoader(),
 506         
 507         loaded: 0,
 508         
 509         setTexture: function (){
 510             let k, texture;
 511             for(k = 0; k < this.textureLen; k++){
 512                 texture = this.load.load("img/texture/"+k+".jpg", ()=>{this.__proto__.loaded++;});
 513                 texture.wrapS = THREE.RepeatWrapping;
 514                 texture.wrapT = THREE.RepeatWrapping;
 515                 texture.repeat.set(1, 1);
 516                 this.__proto__.config.push(texture);
 517             }
 518             if(this.loaded !== this.textureLen){this.awaitLoad();}
 519         },
 520         
 521         awaitLoad: function (){
 522             let interval = setInterval(()=>{
 523                 if(this.loaded === this.textureLen){
 524                     this.update();
 525                     clearInterval(interval);
 526                     console.log("load texture: "+this.loaded+"/"+this.textureLen);
 527                 }else{
 528                     console.log("load texture: "+this.loaded+"/"+this.textureLen);
 529                 }
 530             }, 300);
 531         },
 532 
 533         addMesh: function (object, key){
 534             let mesh = new THREE.Mesh(this.defaultGeometry, new THREE.MeshBasicMaterial({map: object}));
 535             //let mesh = new THREE.Mesh(this.defaultGeometry, this.defaultMaterial);
 536             //this.updateTexture(mesh, object);
 537             mesh.HandCreate = {type: "_Texture", index: key};
 538             this.scene.s.add(mesh);
 539             return mesh;
 540         },
 541         
 542         goToPosition: function (mesh){
 543             if(!mesh) return; this.mesh = mesh;
 544             let geometry = _Geometry.prototype.config[mesh.HandCreate.GeoCI].clone();
 545             let material = _Material.prototype.config[mesh.HandCreate.MatCI].clone();
 546             for(let k = 0; k < this.objects.length; k++){
 547                 this.updateGeometry(this.objects[k], geometry);
 548                 this.updateMaterial(this.objects[k], material);
 549             }
 550             this.scene.c.position.set(this.campos.x, this.campos.y, this.campos.z);
 551             this.update();
 552         }
 553         
 554     });
 555     
 556     //物体
 557     var _Mesh = function (){}
 558     
 559     //gui
 560     var SetView = function (HC, newMesh, oldMesh){
 561         this.HC = HC;
 562         this.newMesh = newMesh;
 563         this.oldMesh = oldMesh;
 564         return this.init();
 565     }
 566     
 567     Object.assign(SetView.prototype, {
 568         
 569         constructor: SetView,
 570         
 571         init: function (){
 572             if(this.globalGui === undefined) this.createGlobal();
 573             this.gui = new Gui().display("none");
 574             
 575             this.createMesh();
 576             this.createGeometry();
 577             this.createMaterial();
 578             return this;
 579         },
 580         
 581         createMesh: function (){
 582             let o = {
 583                 exportGltf: ()=>{this.HC.Three.exporterGLTF(this.newMesh);},
 584                 addMesh: ()=>{this.HC.geometry.goToPosition();},
 585                 removeMesh: ()=>{this.HC.remove(this.newMesh);},
 586                 getBSP: "intersect",
 587                 runGetBSP: ()=>{
 588                     let meshB = this.HC.targets[0].mesh;
 589                     if(this.newMesh === meshB) meshB = this.HC.targets[1].mesh;
 590                     let result = this.HC.Three.getBSP(this.newMesh, meshB, o.getBSP);
 591                     this.HC.geometry.importObject(result.geometry);
 592                     this.HC.isSelectTargets = false;
 593                 }
 594             }
 595             let m = {
 596                 visible: this.newMesh.visible,
 597                 frustumCulled: this.newMesh.frustumCulled,
 598                 castShadow: this.newMesh.castShadow,
 599                 receiveShadow: this.newMesh.receiveShadow,
 600             }
 601             
 602             this.gui.create(m, true).name({visible: "显示物体", castShadow: "投射阴影", receiveShadow: "接收阴影"})
 603             .change({
 604                 visible: ()=>{
 605                     if(this.newMesh.visible === undefined) return;
 606                     this.newMesh.visible = m.visible;
 607                     this.HC.update();
 608                 },
 609                 frustumCulled: ()=>{
 610                     if(this.newMesh.frustumCulled === undefined) return;
 611                     this.newMesh.frustumCulled = m.frustumCulled;
 612                     this.HC.update();
 613                 },
 614                 castShadow: ()=>{
 615                     if(this.newMesh.castShadow === undefined) return;
 616                     this.newMesh.castShadow = m.castShadow;
 617                     this.HC.update();
 618                 },
 619                 receiveShadow: ()=>{
 620                     if(this.newMesh.receiveShadow === undefined) return;
 621                     this.newMesh.receiveShadow = m.receiveShadow;
 622                     this.HC.update();
 623                 }
 624             })
 625             
 626             .add(o, {getBSP:[["交集", "intersect"], ["并集", "union"], ["差集", "subtract"]]}, true)
 627             .name({exportGltf: "导出物体", addMesh: "添加物体", removeMesh: "移除物体", getBSP: "布尔运算类型(选择一个物体)", runGetBSP: "布尔运算"})
 628             .change({
 629                 getBSP: (e)=>{o.getBSP = e.target.value;}
 630             })
 631             
 632             .title("物体-"+this.newMesh.type+"-"+this.newMesh.id);
 633         },
 634         
 635         createGeometry: function (){
 636             if(this.oldMesh.geometry.parameters === undefined){console.log("SetView: 忽略了geometry"); return;}
 637             let o, p = {}, geo;
 638             for(let k in this.oldMesh.geometry.parameters){p[k] = this.oldMesh.geometry.parameters[k];}
 639             switch(this.oldMesh.geometry.type){
 640             
 641                 case "BoxGeometry": 
 642                     o = {
 643                         width:[0.1, 10, 0.1], 
 644                         height:[0.1, 10, 0.1], 
 645                         depth:[0.1, 10, 0.1], 
 646                         widthSegments:[1, 30, 1], 
 647                         heightSegments:[1, 30, 1], 
 648                         depthSegments:[1, 30, 1]
 649                     }
 650                     this.gui.create(p, o, true)
 651                     .name({width: "宽度", height: "高度", depth: "深度", widthSegments: "宽段数", heightSegments: "高段数", depthSegments: "深段数"})
 652                     .change(()=>{
 653                         geo = new THREE.BoxGeometry(p.width, p.height, p.depth, p.widthSegments, p.heightSegments, p.depthSegments);
 654                         this.HC.Three.updateGeometry(this.newMesh, geo);
 655                         this.HC.update();
 656                     });
 657                     
 658                 break;
 659                 
 660                 case "SphereGeometry": 
 661                     o = {
 662                         radius:[0.1, 10, 0.1], 
 663                         widthSegments:[1, 30, 1], 
 664                         heightSegments:[1, 30, 1], 
 665                         phiStart:[0, Math.PI*2, 0.1], 
 666                         phiLength:[0, Math.PI*2, 0.1], 
 667                         thetaStart:[0, Math.PI*2, 0.1], 
 668                         thetaLength:[0, Math.PI*2, 0.1]
 669                     }
 670                     this.gui.create(p, o, true)
 671                     .name({radius: "半径", widthSegments: "宽段数", heightSegments: "高段数", phiStart: "经线起始角度", phiLength: "经线起始角度大小", thetaStart: "纬线起始角度", thetaLength: "纬线起始角度大小",})
 672                     .change(()=>{
 673                         geo = new THREE.SphereGeometry(p.radius, p.widthSegments, p.heightSegments, p.phiStart, p.phiLength, p.thetaStart, p.thetaLength);
 674                         this.HC.Three.updateGeometry(this.newMesh, geo);
 675                         this.HC.update();
 676                     });
 677                     
 678                 break;
 679                 
 680                 case "PlaneGeometry": 
 681                     o = {
 682                         width: [1, 100, 0.1],
 683                         height: [1, 100, 0.1],
 684                         widthSegments: [1, 30, 1],
 685                         heightSegments: [1, 30, 1]
 686                     }
 687                     this.gui.create(p, o, true)
 688                     .name({width: "宽度", height: "高度", widthSegments: "宽段数", heightSegments: "高段数"})
 689                     .change(()=>{
 690                         geo = new THREE.PlaneGeometry(p.width, p.height, p.widthSegments, p.heightSegments);
 691                         this.HC.Three.updateGeometry(this.newMesh, geo);
 692                         this.HC.update();
 693                     });
 694                 break;
 695                     
 696                 default : break;
 697             }
 698             this.gui.title("几何体-"+this.newMesh.geometry.type+"-"+this.newMesh.id);
 699         },
 700         
 701         createMaterial: function (){
 702             let mat = this.newMesh.material;
 703             let o = {
 704                 color: "#" + mat.color.getHexString(),
 705                 emissive: mat.emissive === undefined ? "#000000" : "#" + mat.emissive.getHexString(),
 706                 updateMaterial: ()=>{this.HC.material.goToPosition(this.newMesh);},
 707                 updateTexture: ()=>{this.HC.texture.goToPosition(this.newMesh);}
 708             }
 709             let m = {
 710                 wireframe: mat.wireframe, 
 711                 visible: mat.visible, 
 712                 side: mat.side, 
 713                 fog: mat.fog, 
 714                 aoMapIntensity: mat.aoMapIntensity, 
 715                 colorWrite: mat.colorWrite, 
 716                 transparent: mat.transparent, 
 717                 opacity: mat.opacity, 
 718                 alphaTest: mat.alphaTest, 
 719                 flatShading: mat.flatShading,
 720                 emissiveIntensity: mat.emissiveIntensity === undefined ? 0 : mat.emissiveIntensity,
 721                 repeatU: 1,
 722                 repeatV: 1,
 723                 anisotropy: 1
 724             }
 725             
 726             let num = {
 727                 aoMapIntensity: [0, 1, 0.1], 
 728                 opacity: [0, 1, 0.1], 
 729                 alphaTest: [0, 1, 0.1], 
 730                 emissiveIntensity: [0, 1, 0.1],
 731                 repeatU: [1, 100, 1],
 732                 repeatV: [1, 100, 1],
 733                 anisotropy: [1, this.HC.renderer.capabilities.getMaxAnisotropy() || 2, 1]
 734             };
 735             let sel = {
 736                 side: [["外面", THREE.FrontSide], ["里面", THREE.BackSide], ["双面", THREE.DoubleSide]]
 737             };
 738             let name = {
 739                 wireframe:"网格模式", 
 740                 visible:"显示材质", 
 741                 side: "材质显示那一面", 
 742                 fog: "受雾气影响", 
 743                 aoMapIntensity: "遮挡效果", 
 744                 colorWrite: "渲染颜色", 
 745                 transparent: "渲染透明度", 
 746                 opacity: "透明度", 
 747                 alphaTest: "alpha值", 
 748                 flatShading: "平面着色",
 749                 emissiveIntensity: "放射光强度",
 750                 repeatU: "重复量,纹理U面",
 751                 repeatV: "重复量,纹理V面",
 752                 anisotropy: "纹理清晰度"
 753             };
 754             let c = {
 755                 wireframe: ()=>{if(this.newMesh.material.wireframe === undefined){this.gui.showStop("wireframe", m); return;}else{this.gui.showStop("wireframe", m, false);}  this.newMesh.material.wireframe = m.wireframe; this.HC.update();},
 756                 visible: ()=>{if(this.newMesh.material.visible === undefined){this.gui.showStop("visible", m); return;}else{this.gui.showStop("visible", m, false);}  this.newMesh.material.visible = m.visible; this.HC.update();},
 757                 side: (e)=>{if(this.newMesh.material.side === undefined){this.gui.showStop("side", m); return;}else{this.gui.showStop("side", m, false);}  this.newMesh.material.side = eval(e.target.value); this.HC.update();},
 758                 fog: ()=>{if(this.newMesh.material.fog === undefined){this.gui.showStop("fog", m); return;}else{this.gui.showStop("fog", m, false);}  this.newMesh.material.fog = m.fog; this.HC.update();},
 759                 aoMapIntensity: ()=>{if(this.newMesh.material.aoMapIntensity === undefined){this.gui.showStop("aoMapIntensity", m); return;}else{this.gui.showStop("aoMapIntensity", m, false);}  this.newMesh.material.aoMapIntensity = m.aoMapIntensity; this.HC.update();},
 760                 colorWrite: ()=>{if(this.newMesh.material.colorWrite === undefined){this.gui.showStop("colorWrite", m); return;}else{this.gui.showStop("colorWrite", m, false);}  this.newMesh.material.colorWrite = m.colorWrite; this.HC.update();},
 761                 transparent: ()=>{if(this.newMesh.material.transparent === undefined){this.gui.showStop("transparent", m); return;}else{this.gui.showStop("transparent", m, false);}  this.newMesh.material.transparent = m.transparent; this.HC.update();},
 762                 opacity: ()=>{if(this.newMesh.material.opacity === undefined){this.gui.showStop("opacity", m); return;}else{this.gui.showStop("opacity", m, false);}  this.newMesh.material.opacity = m.opacity; this.HC.update();},
 763                 alphaTest: ()=>{if(this.newMesh.material.alphaTest === undefined){this.gui.showStop("alphaTest", m); return;}else{this.gui.showStop("alphaTest", m, false);}  this.newMesh.material.alphaTest = m.alphaTest; this.HC.update();},
 764                 flatShading: ()=>{if(this.newMesh.material.flatShading === undefined){this.gui.showStop("flatShading", m); return;}else{this.gui.showStop("flatShading", m, false);}  this.newMesh.material.flatShading = m.flatShading; this.HC.update();},
 765                 emissiveIntensity: ()=>{if(this.newMesh.material.emissiveIntensity === undefined){this.gui.showStop("emissiveIntensity", m); return;}else{this.gui.showStop("emissiveIntensity", m, false);}  this.newMesh.material.emissiveIntensity = m.emissiveIntensity; this.HC.update();},
 766                 repeatU: ()=>{if(this.newMesh.material.map === null){this.gui.showStop("repeatU", m); return;}else{this.gui.showStop("repeatU", m, false);} this.newMesh.material.map.repeat.set(m.repeatU, m.repeatV);this.HC.update();},
 767                 repeatV: ()=>{if(this.newMesh.material.map === null){this.gui.showStop("repeatV", m); return;}else{this.gui.showStop("repeatV", m, false);} this.newMesh.material.map.repeat.set(m.repeatU, m.repeatV); this.HC.update();},
 768                 anisotropy: ()=>{if(this.newMesh.material.map === null || (m.anisotropy !== 1 && (m.anisotropy / 2 % 1) !== 0)){this.gui.showStop("anisotropy", m); return;}else{this.gui.showStop("anisotropy", m, false);}this.newMesh.material.map.anisotropy = m.anisotropy;this.HC.update();},
 769                 
 770             };
 771             
 772             this.gui.create(m, num, true, sel).name(name).change(c)
 773             
 774             .add(o, true)
 775             .name({color: "材质颜色", emissive: "放射光颜色", updateMaterial: "替换材质", updateTexture: "替换纹理"})
 776             .change({
 777                 color: (e)=>{if(this.newMesh.material.color === undefined){this.gui.showStop("color", o); return;}else{this.gui.showStop("color", o, false);}  this.newMesh.material.color.set(e.target.value); this.HC.update();},
 778                 emissive: (e)=>{if(this.newMesh.material.emissive === undefined){this.gui.showStop("emissive", o); return;}else{this.gui.showStop("emissive", o, false);} this.newMesh.material.emissive.set(e.target.value); this.HC.update();}
 779             })
 780             
 781             .title("材质-"+this.newMesh.material.type+"-"+this.newMesh.id);
 782         },
 783         
 784         createGlobal: function (){
 785             let o = {
 786                 setMode: "translate",
 787                 exportAll: ()=>{console.log("导出全部物体")},
 788                 updateMaterialAll: ()=>{console.log("替换全部材质")},
 789                 isgltf: true
 790             }
 791 
 792             let gui = new Gui(this.HC.geometry, "show", "显示创建选项")
 793             
 794             .add(o, true, {isgltf: [[".gltf", false], [".glb", true]], setMode: [["平移", "translate"], ["旋转", "rotate"], ["缩放", "scale"]]})
 795             .name({exportAll: "导出全部物体", updateMaterialAll: "替换全部材质", setMode: "控制模式", isgltf:"导出类型"})
 796             .change({
 797                 isgltf: (e)=>{this.HC.Three.exportGLTFFileType = eval(e.target.value);},
 798                 setMode: (e)=>{this.HC.control.transform.setMode(e.target.value);}
 799             })
 800             
 801             .add(this.HC, true, ["lockTarget", "isSelectTargets"])
 802             .name({lockTarget: "锁定物体", isSelectTargets: "选择物体"})
 803             .change({
 804                 isSelectTargets: ()=>{
 805                     if(this.HC.isSelectTargets === false){
 806                         this.HC.removeTargets();
 807                     }
 808                 },
 809                 lockTarget: ()=>{
 810                     if(this.HC.lockTarget === false){
 811                         this.HC.removeTargets();
 812                     }
 813                 }
 814             })
 815             
 816             .title("global");
 817             this.__proto__.globalGui = gui;
 818         }
 819         
 820     });
 821     
 822     
 823     
 824     //main
 825     var HandCreate = function (){
 826         this.Three = new _Three();
 827         this.group = new THREE.Group();
 828         this.target = {};
 829         this.isSelectTargets = false;
 830         this.targets = [];
 831         this.backMesh = null;
 832         this.lockTarget = false;
 833         this.scene = this.Three.createScene([], false);
 834         this.renderer = this.Three.createRenderer(document.body, _width, _height, true, true, true, true);
 835         
 836     }
 837     
 838     Object.assign(HandCreate.prototype, {
 839         
 840         constructor: HandCreate,
 841         
 842         init: function (){
 843             this.intersects = {
 844                 raycaster: new THREE.Raycaster(),
 845                 group: new THREE.Group(),
 846                 vector2: new THREE.Vector2(),
 847                 result: [],
 848                 camera: this.camera,
 849                 recursive: true,
 850                 x: 0,
 851                 y: 0,
 852             };
 853             this.renderer.domElement.style = "position:absolute; top:0; left:0";//如果不定位, gui的移动块会不正常显示
 854             //this.renderer.localClippingEnabled = true;//是否渲染 平面剪裁
 855             this.camera = this.Three.createCamera(45, _width, _height, _minDistance, _maxDistance * _minDistance * 0.2);
 856             this.camera.position.set(0, _maxDistance * 0.001, _maxDistance * 0.001);
 857             this.linghts = this.Three.addLinghts(this.scene, this);
 858             this.control = this.Three.addControls(this.scene, this.camera, this.renderer, this.intersects.group.children);
 859             this.control.drag.addEventListener(‘hoveron‘, (e)=>{this.setTarget(e.object);});
 860             
 861             this.geometry = new _Geometry().init();
 862             this.geometry.targetChange = (v)=>{this.createObject(v);};
 863             this.geometry.show = true;
 864             
 865             this.material = new _Material().init();
 866             
 867             this.texture = new _Texture().init();
 868             
 869             this.gridHelper = new THREE.GridHelper(_maxDistance, _maxDistance/1);
 870             this.scene.add(this.group, this.intersects.group, this.camera, this.gridHelper);
 871             
 872             //this.clip = this.Three.createClip();
 873             //this.globalView();
 874             //this.Three.loadingGLTF("img/gltfs/scene.gltf", this.intersects.group);
 875             //this.Three.loadingGLTF("img/gltfs/scene.glb", this.intersects.group);
 876             return this;
 877         },
 878         
 879         add: function (mesh, group){
 880             if(!mesh) return;
 881             let gro = group || this.intersects.group;
 882             if(Array.isArray(mesh) === true){
 883                 let k, len = mesh.length;
 884                 for(k; k < len; k++){
 885                     if(!mesh[k]) continue;
 886                     gro.add(mesh[k]);
 887                 }
 888             }else{
 889                 gro.add(mesh);
 890             }
 891             this.update();
 892         },
 893         
 894         remove: function (mesh, group){
 895             if(!mesh){console.log("remove: mesh不存在"); return;}
 896             let arr = group || this.intersects.group;
 897             if(!arr.remove){console.log("remove: group错误"); return;}
 898             this.removeTarget();
 899             if(mesh.gui) mesh.gui.remove();
 900             mesh.HandCreate.SV.gui.remove();
 901             if(mesh.material.map){mesh.material.map.dispose();}
 902             mesh.material.dispose();
 903             mesh.geometry.dispose();
 904             arr.remove(mesh);
 905             this.update();
 906         },
 907         
 908         update: function (){
 909             this.Three.render(this.scene, this.camera, this.renderer);
 910         },
 911 
 912         setTarget: function (mesh){
 913             if(this.isSelectTargets === true){this.setTargets(mesh);}
 914             if(this.target.mesh === mesh || this.lockTarget === true){return;}
 915             if(mesh.HandCreate === undefined || mesh.HandCreate.SV === undefined){this.lockTarget = true; console.log("setTarget: mesh 错误,取消选择"); return;}
 916 
 917             this.removeTarget();
 918             
 919             this.target.mesh = mesh;
 920             this.control.transform.attach(mesh);
 921             mesh.HandCreate.SV.gui.display("block");
 922             this.geometry.goToPosition();
 923             this.update();
 924         },
 925         
 926         removeTarget: function (){
 927             if(!this.target.mesh) return;
 928             this.control.transform.detach(this.target.mesh);
 929             this.target.mesh.HandCreate.SV.gui.display("none");
 930             delete(this.target.mesh);
 931             this.update();
 932         },
 933         
 934         setTargets: function (mesh){
 935             //if(this.targets.indexOf(mesh) !== -1){return;}
 936             for(let k = 0; k < this.targets.length; k ++){if(this.targets[k].mesh === mesh){return;}}
 937             this.isSelectTargets = true;
 938             this.lockTarget = true;
 939             this.targets.push({mesh: mesh, color: mesh.material.color.getHex()}); 
 940             mesh.material.color.set("red");
 941             this.update();
 942         },
 943         
 944         removeTargets: function (){
 945             this.isSelectTargets = false;
 946             this.lockTarget = false;
 947             for(let k = 0; k < this.targets.length; k++){
 948                 this.targets[k].mesh.material.color.set(this.targets[k].color);
 949             }
 950             this.targets.length = 0; 
 951             this.update();
 952         },
 953         
 954         createObject: function (v){
 955             
 956             let geo = ()=>{
 957                 let mesh = new THREE.Mesh(v.geometry.clone(), v.material.clone());
 958                 mesh.material.transparent = true;
 959                 mesh.castShadow = true;
 960                 mesh.receiveShadow = true;
 961                 mesh.customDepthMaterial = new THREE.MeshDepthMaterial({depthPacking: THREE.RGBADepthPacking});
 962                 
 963                 mesh.HandCreate = {
 964                     SV: new SetView(this, mesh, v),
 965                     GeoCI: v.HandCreate.index, 
 966                     MatCI: v.HandCreate.MatIndex,
 967                     TexCI: null
 968                 };
 969                 
 970                 this.backMesh = mesh;
 971                 this.add(mesh);
 972                 this.setTarget(mesh);
 973             }
 974             
 975             let mat = ()=>{
 976                 this.Three.updateMaterial(this.material.mesh, v.material);
 977                 this.material.mesh.HandCreate.MatCI = v.HandCreate.index;
 978                 this.update();
 979             }
 980             
 981             let tex = ()=>{
 982                 this.Three.updateTexture(this.texture.mesh.material, v.material.map);
 983                 this.texture.mesh.HandCreate.TexCI = v.HandCreate.index;
 984                 this.update();
 985             }
 986             
 987             switch(v.HandCreate.type){
 988                 case "_Geometry": geo(); break;
 989                 case "_Material": mat(); break;
 990                 case "_Texture": tex(); break;
 991                 default: break;
 992             }
 993 
 994         }
 995         
 996     });
 997     
 998     //代理
 999     /* this.ForCreate = new Proxy(new HandCreate().init(), {
1000         get(o, k){
1001             return o[k];
1002         },
1003         set(o, k, v){
1004             o[k] = v;
1005         }
1006     }); */
1007     
1008     this.ForCreate = new HandCreate().init();
1009     
1010 }).call(this)

 

以上是关于javascript 3d网页 简单的 可视化编辑 图形界面 搭建几何体 带导出物体 示例 ( three.js r114 初探 六)的主要内容,如果未能解决你的问题,请参考以下文章

网页3D编辑器Stone教程:如何在3D场景中添加注解

javascript 3d网页 简单几行代码创建一个动态水潭, 湖面 示例 ( three.js r114 初探 四)

有熟悉quest3d的吗

javascript 3d网页 原创简单的Gui控制视图类 和 ThreeBSP网格组合 ( three.js r114 初探 三)

踏得网发布轻量级网页3D编辑器Stone,可用于快速制作沉浸式网页应用

Unity有啥特点