javascript 简单的3d网页应用(3d网页可视化编辑器), 搭建几何体 选配材质 纹理 , 导入 导出 示例 ( three.js 初探 六)
程序员文章站
2022-06-19 10:14:40
1 完整代码下载 https://pan.baidu.com/s/1JJyVcP2KqXsd5G6eaYpgHQ 提取码 3fzt (压缩包名: 2020-3-24-demo.zip) 2 图片展示 3 主要代码 布尔运算后的物体的几何体会自动 导入到 几何体列表选项中, 可*选配 挺简单的 都是 ......
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)
上一篇: 产品-用户体验要素学习
下一篇: 一个运维主管面试题有答案