1 完整代码下载
https://pan.baidu.com/s/1JJyVcP2KqXsd5G6eaYpgHQ
提取码 3fzt (压缩包名: 2020-3-24-demo.zip)
由于是初探3D,对3d对象的构建不太了解, 用此应用试着做了一个马车几何体。。。结果不敢看
不在更新此应用 。 结束时间 2020-4-1
2 图片展示
3 主要代码
布尔运算后的物体的几何体会自动 导入到 几何体列表选项中, 可自由选配材质 纹理
挺简单, 都是中文
1 "use strict" 2 3 var View = (function (){ 4 5 var _View = function (){ 6 7 if(this.__proto__.size === undefined){this.__proto__.size = this.getSize();} 8 9 } 10 11 _View.prototype = { 12 13 constructor: _View, 14 15 //创建html元素 16 add: function (fel, elemName, id, cls){ 17 let el = document.createElement(elemName); 18 if(id){el.setAttribute('id',id);} 19 if(cls){el.className = cls;} 20 if(fel){fel.appendChild(el);} 21 return el; 22 }, 23 24 //删除html元素 25 remove: function (){ 26 let k, arg = arguments, err = []; 27 for(k = 0; k < arg.length; k++){ 28 if(this.isEl(arg[k]) === false){err.push(arg[k]); continue;} 29 arg[k].parentNode.removeChild(arg[k]); 30 } 31 if(err.length > 0){return {err:'这里有一些删除失败的元素', arr:err};} 32 return true; 33 }, 34 35 //id获取html元素 36 get: function (id){ 37 return document.getElementById(id); 38 }, 39 40 //获取可视宽高 41 getSize: function (){ 42 let w = window.innerWidth || document.body.clientWidth || document.documentElement.clientWidth; 43 let h = window.innerHeight || document.body.clientHeight || document.documentElement.clientHeight; 44 return {w:w, h:h}; 45 }, 46 47 //通过parentNode检查元素是否存在于页面中 48 isEl: function (el){ 49 if(typeof(el) !== 'object'){return false;} 50 //被删除之后的html元素object的 parentNode等于null 51 if(!el.parentNode){return false;} 52 return true; 53 }, 54 55 //元素绑定事件 56 addEvent: function (target, ev, callback){ 57 target.addEventListener(ev, function(e){/* e.preventDefault(); */ if(callback){callback(e);}}, false); 58 return callback; 59 }, 60 61 removeEvent: function (target, ev, func){ 62 target.removeEventListener(ev, func); 63 }, 64 65 initBody: function (){ 66 document.body.style.width = this.size.w + "px"; 67 document.body.style.height = this.size.h + "px"; 68 document.body.style.overflow = "hidden"; 69 return this; 70 } 71 72 } 73 74 return _View; 75 76 })() 77 78 79 80 /** 81 限 谷歌 或 火狐 浏览器 82 依赖 View 类 83 */ 84 var Gui = (function (){ 85 86 //申明新的gui 87 var _Gui = function (obj, a, b, c, d){ 88 this.timer = 0; 89 this.info = new Map(); 90 //this.info.set(this.timer, this); 91 if(this.__proto__.timerAll_old.length !== 0){ 92 this.timerAll = this.__proto__.timerAll_old[0]; 93 this.__proto__.timerAll_old.splice(0, 1); 94 }else{ 95 this.__proto__.timerAll++; 96 this.timerAll = this.__proto__.timerAll; 97 } 98 this.elem = addBindMove(document.body, 'div', null, 'Gui box-shadown box-scroll-block'); 99 this.__proto__.objAll.set(this.timerAll, this); 100 let dis = this.autoChangeStartPosition === false ? 1 : this.timerAll; 101 this.setPos(15 * dis, 5 * dis, "right"); 102 if(typeof(obj) === "object" && Array.isArray(obj) === false){this.create(obj, a, b, c, d);} 103 else{/* console.warn("_Gui: 参数中的对象 格式错误"); */} 104 } 105 106 _Gui.prototype.objAll = new Map(); 107 108 _Gui.prototype.timerAll = 0; 109 110 _Gui.prototype.timerAll_old = []; 111 112 _Gui.prototype.autoChangeStartPosition = true; //自动改变初始位置 113 114 //创建新的块 115 _Gui.prototype.create = function (obj, a, b, c, d){ 116 this.timer++; 117 _start(obj, a, b, c, d, this.timer, this.elem, this.info, this.timerAll, this.objAll); 118 return this; 119 } 120 121 //往块里添加新的控件 122 _Gui.prototype.add = function (obj, a, b, c, d){ 123 _start(obj, a, b, c, d, this.timer, this.elem, this.info, this.timerAll, this.objAll); 124 return this; 125 } 126 127 //添加 内容变动 回调(change 事件) 128 _Gui.prototype.change = function (){//arr.concat(arr_a, arr_b) 129 var arg = arguments, o = this.info.get(this.timer), tar = o.par.target; 130 var arr = tar.bs.concat(tar.fs, tar.ns, tar.ss, tar.ts, tar.cs), len = arr.length; 131 var arg_t_0 = typeof(arg[0]), call = o.objs.get(o.obj).callback; 132 if(arg_t_0 === "function" && len === 1){ 133 call[arr[0]] = arg[0]; 134 }else if(arg_t_0 === "string" && typeof(arg[1]) === "function"){ 135 call[arg[0]] = arg[1]; 136 }else if(arg_t_0 === "function" && len > 1){ 137 for(let k = 0; k < len; k++){ 138 call[arr[k]] = arg[0]; 139 } 140 }else if(arg_t_0 === "object" && Array.isArray(arg[0]) === false){ 141 for(let k in arg[0]){ 142 call[k] = arg[0][k]; 143 } 144 }else{ 145 console.log("change方法参数错误,添加失败"); 146 } 147 //console.log(this.info.get(this.timer).obj); 148 return this; 149 } 150 151 //修改title 152 _Gui.prototype.title = function (value){ 153 if(!this.info.get(this.timer)){console.log("找不到title"); return;} 154 this.info.get(this.timer).title.innerHTML = ""+this.timerAll+""+"."+""+this.timer+""+" "+(value || ""); 155 return this; 156 } 157 158 //修改name 159 _Gui.prototype.name = function (){ 160 let o = this.info.get(this.timer), objs; 161 let arg = arguments, typ0 = typeof(arg[0]), typ1 = typeof(arg[1]); 162 if(typeof(arg[2]) === "object" && Array.isArray(arg[2]) === false){objs = o.objs.get(arg[2]);}else{objs = o.objs.get(o.obj);} 163 var tar = objs.parameter.target, nameEl = objs.nameEl; 164 var arr = tar.bs.concat(tar.fs, tar.ns, tar.ss, tar.ts, tar.cs), len = arr.length; 165 166 var setVal = (el, val)=>{if(!el){console.warn("_Gui.name: 属性不存在");} if(el.value !== undefined){el.value = val;}else if(el.innerHTML !== undefined){el.innerHTML = val;}else{console.log("name修改失败");}} 167 168 if(typ0 === "string" && typ1 === "undefined" && len === 1){//string 169 setVal(nameEl[arr[0]], arg[0]); 170 171 }else if(typ0 === "object" && Array.isArray(typ0) === false){//object 172 let k; 173 for(k in arg[0]){ 174 setVal(nameEl[k], arg[0][k]); 175 } 176 177 }else if(typ0 === "string" && typ1 === "string" && arg[1] !== "_Gui_func_showStop"){//string, string 178 if(arr.indexOf(arg[0]) === -1 || !nameEl[arg[0]]){console.log("name修改失败,视图结构发生错误,请修复"); return;} 179 setVal(nameEl[arg[0]], arg[1]); 180 181 }else if(typ0 === "string" && arg[1] === "_Gui_func_showStop" && typeof(arg[2]) === "object"){ 182 if(nameEl[arg[0]] === undefined){console.log("showStop_name: 错误"); return;} 183 if(arg[3] === false){ 184 nameEl[arg[0]].style.color = "#2F4F4F"; 185 }else{ 186 nameEl[arg[0]].style.color = "red"; 187 } 188 189 190 }else{ 191 console.log("name方法参数错误,添加失败"); 192 } 193 194 return this; 195 } 196 197 //获取当前view对象 198 _Gui.prototype.getView = function (){ 199 return tar; 200 } 201 202 //设置 gui视图位置 203 _Gui.prototype.setPos = function (x, y, dirX, dirY){ 204 205 let dirx = dirX || "left", diry = dirY || "top"; 206 207 if(dirx === "left" && this.elem.bindMove.style.right !== ""){ 208 this.elem.bindMove.style.right = ""; 209 } 210 else if(dirx === "right" && this.elem.bindMove.style.left !== ""){ 211 this.elem.bindMove.style.left = ""; 212 } 213 214 if(diry === "top" && this.elem.bindMove.style.bottom !== ""){ 215 this.elem.bindMove.style.bottom = ""; 216 } 217 else if(diry === "bottom" && this.elem.bindMove.style.top !== ""){ 218 this.elem.bindMove.style.top = ""; 219 } 220 221 if(x !== undefined) this.elem.bindMove.style[dirx] = x+"px"; 222 if(y !== undefined) this.elem.bindMove.style[diry] = y+"px"; 223 _setElemPos(this.elem); 224 225 return this; 226 227 } 228 229 //隐藏gui 230 _Gui.prototype.display = function (val){ 231 if(!this.elem){console.log("display, elem不存在"); return this;} 232 if(val !== "block" && val !== "none"){console.log("display 参数错误"); return this;} 233 this.elem.bindMove.style.display = val; 234 this.elem.style.display = val; 235 return this; 236 } 237 238 //关闭gui(默认关闭整个Gui) 239 _Gui.prototype.close = function (object){ 240 var o; 241 if(!object){ 242 let k; 243 for(k = 1; k <= this.timer; k++){ 244 o = this.info.get(k); 245 o.hide = true; 246 hide(o.line, o.fel, this.elem, this.info, true); 247 } 248 }else{ 249 o = this.info.get(object.timer); 250 o.hide = true; 251 hide(o.line, o.fel, this.elem, this.info, true); 252 } 253 return this; 254 } 255 256 //标记不可用项 257 _Gui.prototype.showStop = function (){ 258 259 this.name(arguments[0], "_Gui_func_showStop", arguments[1], arguments[2]); 260 261 return this; 262 263 } 264 265 //移除gui 266 _Gui.prototype.remove = function (object){ 267 var o = object ? object : this; 268 this.__proto__.timerAll_old.push(o.timerAll); 269 this.__proto__.objAll.delete(o.timerAll); 270 o.objAll.delete(o.timerAll); 271 tar.remove(o.elem.bindMove, o.elem); 272 delete(o.timerAll); 273 delete(o.elem); 274 delete(o.info); 275 delete(o.timer); 276 return; 277 } 278 279 //使某个gui获得焦点(层级变为最上层) 280 _Gui.prototype.focus = function (object){ 281 let o = object || this; 282 if(!o.elem || !o.elem.bindMove){console.warn("_Gui: 获取焦点失败");} 283 _zIndex(o.elem); 284 return this; 285 } 286 287 288 var tar = new View(), tar_zIndex = {}, _osTitle = null; 289 290 //创建视图 291 var _start = function (obj, a, b, c, d, id, felem, map, timerAll, objAll){ 292 293 var fel, line, title, m = map.get(id), k, len, _name, isNewObj = false; 294 295 //确认追加 obj 296 if(m){ 297 fel = m.fel; 298 if(!obj){ 299 obj = m.obj; 300 }else{ 301 if(m.objs.has(obj) === false) isNewObj = true; 302 m.obj = obj; 303 } 304 } 305 306 if(typeof(obj) !== "object" || !obj){console.log("引用对象错误, 新建块对象为必须"); return;} 307 308 //确认参数 (target, title, isBind, range || select) || a = {target, title, isBind, range || select} 309 var os = {}, nos = []; 310 if(a !== undefined){nos.push(_getispro(obj, a, nos));} 311 if(b !== undefined){nos.push(_getispro(obj, b, nos));} 312 if(c !== undefined){nos.push(_getispro(obj, c, nos));} 313 if(d !== undefined){nos.push(_getispro(obj, d, nos));} 314 len = nos.length; 315 for(k = 0; k < len; k++){ 316 if(nos[k] === undefined){ 317 if(typeof(a) === "object" && Array.isArray(a) === false){os = a;} 318 }else{ 319 let val; 320 switch(k){ 321 case 0 : val = a; break; 322 case 1 : val = b; break; 323 case 2 : val = c; break; 324 case 3 : val = d; break; 325 default : break; 326 } 327 if(val !== undefined){os[nos[k]] = val;} 328 } 329 } 330 //console.log(Object.getOwnPropertyDescriptor(obj, "x")); 331 //确认对象属性 os.target (target 如果为obj 则表示 只设置gui, 不添加控件) 332 var arr = [], T = typeof(os.target), A = Array.isArray(os.target); 333 if(!os.target){for(k in obj){arr.push(k);}} 334 else if(A === true){arr = os.target;} 335 else if(T !== "object"){arr.push(os.target);} 336 else{return;} 337 //boolean, function, number, text, select, color 338 var bs = [], fs = [], ns = [], ts = [], cs = [], ss = []; 339 if(Array.isArray(os.select) == true && arr.length === 1){ 340 ss.push(arr[0]); 341 }else if(typeof(os.select) === "object" && Array.isArray(os.select) == false){ 342 let ks; 343 for(ks in os.select){ 344 len = arr.length; 345 for(k = 0; k < len; k++){ 346 if(ks === arr[k]){ss.push(arr[k]); arr.splice(k, 1);} 347 } 348 } 349 } 350 len = arr.length; 351 for(k = 0; k < len; k++){ 352 T = typeof(obj[arr[k]]); 353 if(T === "boolean"){bs.push(arr[k]);} 354 else if(T === "function"){fs.push(arr[k]);} 355 else if(T === "number"){ns.push(arr[k]);} 356 else if(T === "string"){ 357 if(obj[arr[k]].length === 7 && obj[arr[k]].charAt(0) === "#"){cs.push(arr[k]);}//color 358 else{ts.push(arr[k]);}//string 359 } 360 } 361 var bs_len = bs.length, fs_len = fs.length, ns_len = ns.length, ts_len = ts.length, ss_len = ss.length, cs_len = cs.length; 362 var lens = bs_len + fs_len + ns_len + ts_len + ss_len + cs_len; 363 364 //确认 绑定 365 var isB = false; 366 if(typeof(os.isBind) === "boolean"){isB = os.isBind;} 367 368 //确认 _name 369 if(os.title && lens === 1){_name = os.title; delete(os.title);} 370 371 //确认 新的块 372 var par = {target:{bs:bs, fs:fs, ns:ns, ts:ts, cs:cs, ss:ss}, select:os.select, range:os.range, title:os.title, isBind:os.isBind}; 373 if(!m){ 374 isNewObj = false; 375 line = _line(id, felem); 376 fel = _cons(line, id, felem, map); 377 title = _title(timerAll, id, _osTitle || os.title, fel);//os.title 378 _osTitle = null; 379 map.set(id, { 380 hide : false, 381 line : line, 382 fel : fel, 383 title : title, 384 obj : obj, 385 par : par, 386 objs : new Map([[obj, { 387 parameter : par, 388 callback : {}, 389 nameEl : {} 390 }]]) 391 }); 392 m = map.get(id); 393 } 394 395 //更新 obj 396 if(isNewObj === true){ 397 m.objs.set(obj, { 398 parameter : par, 399 callback : {}, 400 nameEl : {} 401 }); 402 } 403 404 //更新参数 405 m.par = par; 406 var objs_g = m.objs.get(obj), pars = objs_g.parameter; 407 for(k in os){if(k !== "target"){pars[k] = os[k];}} 408 for(k = 0; k < bs_len; k++){if(pars.target.bs.indexOf(bs[k]) === -1){pars.target.bs.push(bs[k]);}} 409 for(k = 0; k < fs_len; k++){if(pars.target.fs.indexOf(fs[k]) === -1){pars.target.fs.push(fs[k]);}} 410 for(k = 0; k < ns_len; k++){if(pars.target.ns.indexOf(ns[k]) === -1){pars.target.ns.push(ns[k]);}} 411 for(k = 0; k < ts_len; k++){if(pars.target.ts.indexOf(ts[k]) === -1){pars.target.ts.push(ts[k]);}} 412 for(k = 0; k < ss_len; k++){if(pars.target.ss.indexOf(ss[k]) === -1){pars.target.ss.push(ss[k]);}} 413 for(k = 0; k < cs_len; k++){if(pars.target.cs.indexOf(cs[k]) === -1){pars.target.cs.push(cs[k]);}} 414 415 //console.log(objs_g.callback); 416 //创建视图//os.select os.range os.isBind 417 let che, cli, ran, tex, col, sel; 418 if(bs_len > 0){ che = _check(obj, bs, fel, isB, objs_g.callback, _name); for(k in che.nameEl){objs_g.nameEl[k] = che.nameEl[k];} } 419 if(ts_len > 0){ tex = _text(obj, ts, fel, isB, objs_g.callback, _name); for(k in tex.nameEl){objs_g.nameEl[k] = tex.nameEl[k];} } 420 if(cs_len > 0){ col = _color(obj, cs, fel, isB, objs_g.callback, _name); for(k in col.nameEl){objs_g.nameEl[k] = col.nameEl[k];} } 421 if(ss_len > 0){ sel = _select(obj, ss, os.select, fel, isB, objs_g.callback, _name); for(k in sel.nameEl){objs_g.nameEl[k] = sel.nameEl[k];} } 422 if(ns_len > 0){ ran = _range(obj, ns, os.range || {}, fel, isB, objs_g.callback, timerAll, id, _name); for(k in ran.nameEl){objs_g.nameEl[k] = ran.nameEl[k];} } 423 if(fs_len > 0){ cli = _click(obj, fs, fel, objs_g.callback, _name); for(k in cli.nameEl){objs_g.nameEl[k] = cli.nameEl[k];} } 424 return {nowObject:obj}; 425 } 426 427 //验证 并 获取 _start 参数 428 var _getispro = function (obj, cons, nos){ 429 var o_t = typeof(cons), o_a = Array.isArray(cons), r; 430 if(o_t === "string"){ 431 if(obj[cons] !== undefined){ 432 r = "target"; 433 }else{ 434 r = "title"; 435 } 436 437 }else if(o_t === "boolean"){ 438 r = "isBind"; 439 440 }else if(o_t === "object"){ 441 let k, len, isT = (arr, type)=>{ 442 let ct = true; 443 len = cons.length; 444 for(k = 0; k < len; k++){if(typeof(cons[k]) !== type){ct = false; break;}} 445 return ct; 446 } 447 if(o_a === true){ 448 if(isT(cons, "string") === true){r = "target";} 449 else if(isT(cons, "number") === true && (cons.length === 3 || cons.length === 0) && cons[0] < cons[1] && /* cons[2] < cons[1] && */cons[2] > 0){r = "range";} 450 else{console.log("忽略了参数");} 451 }else{ 452 let isArr = true; 453 for(k in cons){if(Array.isArray(cons[k]) === false){isArr = false; break;}} 454 if(isArr === true){ 455 let ka, isN; 456 for(k in cons){ 457 len = cons[k].length; 458 if(len === 0 || len === 3){ 459 for(ka = 0; ka < len; ka++){ 460 if(typeof(cons[k][ka]) !== "number" || isNaN(cons[k][ka]) === true){isN = false; break;} 461 } 462 if(typeof(obj[k]) !== "number"){isN = false;} 463 464 if(isN !== false && len === 3 && (obj[k] < cons[k][0] || obj[k] > cons[k][1] || cons[k][0] > cons[k][1] || cons[k][2] > cons[k][1] || cons[k][2] < 0)){isN = false;} 465 }else{ 466 isN = false; 467 break; 468 } 469 } 470 if(isN === false){r = "select";}else{r = "range";}//数组长度为空也判定为 range, 因为range 有默认值 471 }else{ 472 let isSel = true; 473 for(k in cons){if(obj[k] === undefined){isSel = false; break;}} 474 if(isSel === true){r = "select";}else{console.log("忽略了参数");} 475 } 476 } 477 } 478 479 if(nos.indexOf(r) !== -1){console.log("重复了参数"); return;} 480 481 return r; 482 } 483 484 //隐藏视图 485 var hide = function (l, f, elem, map, isHide){ 486 elem.bindMoveIsHideAll = false; 487 if(isHide === false){ 488 l.className = "line-block"; 489 f.style.display = "block"; 490 elem.className = "Gui box-shadown box-scroll-block"; 491 elem.bindMove.className = "bindMove_elemCla-up"; 492 }else{ 493 l.className = "line-none"; 494 f.style.display = "none"; 495 let isAll = true, con, k, len = map.size; 496 for(k = 1; k <= len; k++){ 497 con = map.get(k).fel.style.display; 498 if(con === "" || con === "block"){isAll = false; break;} 499 } 500 if(isAll === true){ 501 elem.bindMoveIsHideAll = true; 502 elem.className = "Gui-none box-shadown box-scroll-block"; 503 elem.bindMove.className = "bindMove_elemCla-hidden"; 504 } 505 } 506 _setElemPos(elem); 507 } 508 509 //调整 son(this.elem)的位置 510 var _setElemPos = function (son, father){ 511 if(!father){father = son.bindMove;} 512 let s = 0; 513 if(son.bindMoveIsHideAll === true) s = 10; 514 //son.style.zIndex = "2"; father.style.zIndex = "1"; 515 son.style.left = father.offsetLeft-(son.clientWidth || son.offsetWidth)+(father.clientWidth || father.offsetWidth) +"px"; 516 son.style.top = father.offsetTop+(father.clientHeight || father.clientHeight)+ s -1 +"px"; 517 } 518 519 //添加 内容 容器 520 var _cons = function (line, id, fel, map){ 521 var f = tar.add(fel, "div", null, "Gui-content"), di; 522 tar.addEvent(line, 'click', (e)=>{ 523 di = map.get(id); 524 di.hide = !di.hide; 525 hide(line, f, fel, map, di.hide); 526 }); 527 return f; 528 } 529 530 //添加 标题 ← ↑ → ↓ ↖ ↙ ↗ ↘ ↕ 531 var _title = function (timerAll, id, title, fel){ 532 var tf = tar.add(fel, "div"); 533 var t = tar.add(tf, "p"); 534 //var ts = tar.add(tf, "p"); 535 t.innerHTML = ""+timerAll+""+"."+""+id+""+" "+(title || ""); 536 //ts.style = "height:5px;"; 537 return t; 538 } 539 540 //添加 分块线 541 var _line = function (id, fel){ 542 var toper = id === 1 ? 0 : 10; 543 var l = tar.add(fel, 'p', null, "line-block"); 544 l.style= "cursor:pointer; margin-top:" + toper + "px"; 545 return l; 546 } 547 548 var _zIndex = function (son, father){ 549 let f = father || son.bindMove; 550 if(tar_zIndex.move && tar_zIndex.elem){tar_zIndex.move.style.zIndex = "1"; tar_zIndex.elem.style.zIndex = "1";} 551 tar_zIndex.move = f; tar_zIndex.elem = son; 552 tar_zIndex.move.style.zIndex = "2"; tar_zIndex.elem.style.zIndex = "2"; 553 } 554 555 //创建 绑定 可移动 的html元素 556 var addBindMove = function (fel, elemName, id, cls){ 557 var father = tar.add(fel, "div", null, "bindMove_elemCla-up"); 558 var son = tar.add(fel, elemName, id, cls); 559 560 var isMove = false, sx, sy, tar_input, k, len, path; 561 562 //初始化 father 位置 563 var getFatherPosition = function (){ 564 if(!son.offsetLeft || !(son.clientWidth || son.offsetWidth) || !(father.clientWidth || father.offsetWidth)){ 565 setTimeout(()=>{getFatherPosition(); _setElemPos(son);}, 500); 566 console.log("调整father位置"); 567 return; 568 } 569 father.style.left = son.offsetLeft + (son.clientWidth || son.offsetWidth) - (father.clientWidth || father.offsetWidth) +"px"; 570 } 571 572 //更新 zIndex 573 var setzIndex = function (e){ 574 path = e.path || (e.composedPath && e.composedPath()); 575 len = path.length; 576 for(k = 0; k < len; k++){ 577 if(path[k].className === "bindMove_elemCla-up" || path[k].className === "bindMove_elemCla-down" || path[k].className === "bindMove_elemCla-hidden" || path[k].className === "Gui box-shadown box-scroll-block" || path[k].className === "Gui-none box-shadown box-scroll-block"){ 578 _zIndex(son, father); 579 break; 580 } 581 } 582 } 583 tar.addEvent(son, 'click', (e)=>{ 584 setzIndex(e); 585 //if(e.target.type !== undefined){tar_input = e.target; e.target.focus();}else if(tar_input){tar_input.blur();} 586 }); 587 588 //移动 589 var down = tar.addEvent(father, 'mousedown', (e)=>{ 590 setzIndex(e); 591 if(e.target.className === "bindMove_elemCla-up" || e.target.className === "bindMove_elemCla-hidden"){ 592 sx = e.offsetX; sy = e.offsetY; 593 if(father.className === "bindMove_elemCla-up") father.className = "bindMove_elemCla-down"; 594 isMove = true; 595 } 596 }); 597 var up = tar.addEvent(father, 'mouseup', (e)=>{ 598 isMove = false; 599 if(father.className === "bindMove_elemCla-down") father.className = "bindMove_elemCla-up"; 600 tar.removeEvent(father, 'mousedown', down); 601 tar.removeEvent(document.body, 'mousemove', move); 602 tar.removeEvent(father, 'mouseup', up); 603 }); 604 var move = tar.addEvent(document.body, 'mousemove', (e)=>{ 605 if(isMove === true){ 606 father.style.left = e.clientX - sx +"px"; 607 father.style.top = e.clientY - sy +"px"; 608 _setElemPos(son, father); 609 } 610 }); 611 612 son.bindMove = father; 613 son.bindMoveIsHideAll = false; 614 //getFatherPosition(); 615 return son; 616 } 617 618 var _view = function (obj, arr, fel, isBind, type, name, clas, event_fun, bind_fun){ 619 620 var p = tar.add(fel, 'p'), info = {p:p, nameEl:{}}, k, len = arr.length, vn = "value", cla = clas || "p-float-"+type; 621 var nameer; 622 if(type === "checkbox"){vn = "checked";} 623 624 var create = (val)=>{ 625 let _val = obj[val]; 626 let f = tar.add(p, 'p', null, cla); 627 let i = tar.add(f, 'input'); 628 let fgx = tar.add(f, 'input', null, "gui-mesh-fgx"); fgx.readOnly = "true"; 629 let s = tar.add(f, 'span'); 630 fgx = tar.add(f, 'input', null, "gui-mesh-fgx"); fgx.readOnly = "true"; 631 nameer = val; 632 if(type === "color"){nameer = _val;} 633 i.type = type; 634 i[vn] = _val; 635 636 s.innerHTML = name || nameer+""; 637 638 tar.addEvent(i, 'change', (e)=>{ 639 _val = e.target[vn]; 640 if(!isBind) obj[val] = _val; 641 if(type === "color") s.innerHTML = _val; 642 if(typeof(event_fun[val]) === "function") event_fun[val](e); 643 }); 644 645 //bind(obj, arr[k], _val, (now)=>{el_f.i.checked = now;}); 646 if(isBind === true){ 647 Object.defineProperty(obj, val, { 648 get(){return _val;}, 649 set(v){ 650 _val = v; 651 i[vn] = v; 652 if(typeof(bind_fun) === "function"){bind_fun(v);} 653 } 654 }); 655 } 656 657 info.nameEl[val] = s; 658 } 659 660 for(k = 0; k < len; k++){create(arr[k]);} 661 662 return info; 663 } 664 665 //添加 text输入框(string) 666 var _text = function (obj, arr, fel, isBind, callbacks, name){ 667 return _view(obj, arr, fel, isBind, "text", name, "p-text", callbacks); 668 } 669 670 //添加 复选框(boolean) 671 var _check = function (obj, arr, fel, isBind, callbacks, name){ 672 return _view(obj, arr, fel, isBind, "checkbox", name, null, callbacks); 673 } 674 675 //添加 下拉选项框() 676 var _select = function (obj, arr, info, fel, isBind, callbacks, name){ 677 // 678 var infos = {nameEl:{}}, k, len = arr.length; 679 680 var create = (val, cons)=>{ 681 let _val = obj[val]; 682 let p = tar.add(fel, 'p'); 683 let f = tar.add(p, 'p', null, "p-float-select"); 684 let i = tar.add(f, "select"); 685 let fgx = tar.add(f, 'input', null, "gui-mesh-fgx"); fgx.readOnly = "true"; 686 let s = tar.add(f, 'span'); s.innerHTML = name || val; 687 fgx = tar.add(f, 'input', null, "gui-mesh-fgx"); fgx.readOnly = "true"; 688 let ka, lena, T = typeof(cons), A = Array.isArray(cons); 689 if(T === "object" && A === false){ 690 for(ka in cons){ 691 let opt = tar.add(i, "option"); 692 opt.value = cons[ka]; 693 opt.innerHTML = ka; 694 } 695 }else if(A === true){ 696 lena = cons.length; 697 for(ka = 0; ka < lena; ka++){ 698 if(Array.isArray(cons[ka]) === true && cons[ka].length === 2){ 699 let opt = tar.add(i, "option"); 700 opt.value = cons[ka][1]; 701 opt.innerHTML = cons[ka][0]; 702 continue; 703 } 704 let opt = tar.add(i, "option"); 705 opt.value = cons[ka]; 706 opt.innerHTML = cons[ka]; 707 } 708 } 709 tar.addEvent(i, 'change', (e)=>{ 710 if(typeof(callbacks[val]) === "function") callbacks[val](e); 711 }); 712 713 infos.nameEl[val] = s; 714 } 715 716 if(len === 1){ 717 if(typeof(info) === "object"){ 718 create(arr[0], info[arr[0]]); 719 }else{ 720 create(arr[0], info); 721 } 722 }else{ 723 for(k = 0; k < len; k++){ 724 create(arr[k], info[arr[k]]); 725 } 726 } 727 728 return infos; 729 } 730 731 //添加 颜色选择器 732 var _color = function (obj, arr, fel, isBind, callbacks, name){ 733 return _view(obj, arr, fel, isBind, "color", name, null, callbacks); 734 } 735 736 //添加 按钮(function) 737 var _click = function (obj, arr, fel, callbacks, name){ 738 var p = tar.add(fel, 'p'), info = {p:p, nameEl:{}}, k, len = arr.length, ends = []; 739 var create = (val)=>{ 740 let f = tar.add(p, 'p', null, "p-float-button"); 741 let i = tar.add(f, 'input'); 742 i.type = "button"; 743 i.value = name || val; 744 tar.addEvent(i, 'click', ()=>{ 745 obj[val](); 746 if(typeof(callbacks[val]) === "function"){callbacks[val](e);} 747 }); 748 info.nameEl[val] = i; 749 } 750 for(k = 0; k < len; k++){create(arr[k]);} 751 return info; 752 } 753 754 //添加 计量控制器(number) info: object 可选 默认[min, max, step] 755 //注意: number属性的初始值不能 小于min 和 大于max; step不能大于max-min 否则会被判定为 下拉选项框 的参数 756 var _range = function (obj, arr, info, fel, isBind, callbacks, timerAll, id, name){ 757 var create = (val)=>{ 758 let c = info[val] || di; 759 if(obj[val] < c[0] || obj[val] > c[1] || typeof(obj[val]) !== "number" || isNaN(obj[val]) === true){return;} 760 let p = tar.add(fel, 'p'), i = tar.add(p, 'input'); 761 i.type = "range"; i.value = obj[val]; i.min = c[0]; i.max = c[1]; i.step = c[2]; 762 let nul = tar.add(p, 'span'); nul.innerHTML = " "; 763 let is = tar.add(p, 'input'); is.type = "tel"; is.value = obj[val]; 764 let key = false, x, xs, spva = name || val, s = tar.add(p, 'span'); s.innerHTML = "" + spva; 765 let _val = obj[arr[k]]; 766 767 let getNum = (num)=>{ 768 //if(num === _val){return _val;} 769 if(typeof(num) !== "number" || isNaN(num) === true){ 770 return _val; 771 } 772 if(num > c[0] && num < c[1]){ 773 return num; 774 }else if(num > c[0]){ 775 return c[1]; 776 }else if(num < c[1]){ 777 return c[0]; 778 } 779 return _val; 780 } 781 782 let setNum = (num, e)=>{ 783 if(num !== undefined){ 784 i.value = num; 785 is.value = num; 786 _val = num; 787 if(!isBind){obj[val] = _val;} 788 if(typeof(callbacks[val]) === "function"){callbacks[val](_val);} 789 } 790 } 791 792 tar.addEvent(is, 'blur', (e)=>{setNum(getNum(Math.round(Number(e.target.value)/c[2])*c[2]), e);}); 793 tar.addEvent(i, 'change', (e)=>{ 794 setNum(getNum(e.target.valueAsNumber), e); 795 }); 796 797 if(isBind === true){ 798 Object.defineProperty(obj, arr[k], { 799 get() {return _val;}, 800 set(v) { 801 _val = getNum(Math.round(Number(v)/c[2])*c[2]); 802 i.value = _val; 803 is.value = _val; 804 } 805 }); 806 } 807 infos.nameEl[val] = s; 808 } 809 var di = [0, 100, 1], k, len = arr.length, infos = {p:null, nameEl:{}}; 810 if(Array.isArray(info) === true){di = info;} 811 for(k = 0; k < len; k++){create(arr[k]);} 812 return infos; 813 } 814 815 return _Gui; 816 817 })()
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 Gui.prototype.autoChangeStartPosition = false; //不自动改变初始位置 14 15 var _view = new View().initBody(); 16 var _width = _view.size.w; 17 var _height = _view.size.h; 18 var _minDistance = 0.1; 19 var _maxDistance = 5000; 20 21 22 //three 23 var _Three = function (){} 24 25 Object.assign(_Three.prototype, { 26 27 constructor: _Three, 28 29 depthMaterial: new THREE.MeshDepthMaterial({depthPacking: THREE.RGBADepthPacking}), 30 31 createScene: function (bg, fog){//场景 32 let scene = new THREE.Scene(); 33 if(typeof(bg) === "number"){scene.background = bg;} 34 else if(Array.isArray(bg) === true){ 35 scene.background = new THREE.CubeTextureLoader() 36 .setPath('img/cube/skyboxsun25deg/') 37 .load( [ 'px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg' ] ); 38 } 39 if(fog) scene.fog = new THREE.Fog(fog.color, fog.near, fog.far); 40 return scene; 41 }, 42 43 createCamera: function (fov, width, height, near, far){//相机 44 let w = width === undefined ? _width : width; 45 let h = height === undefined ? _height : height; 46 let camera = new THREE.PerspectiveCamera(fov || 45, w / h, near || _minDistance, far || _minDistance * 1000); 47 camera.position.set(0, 0, _maxDistance * 0.001); 48 camera.lookAt( 0, 0, 0 ); 49 return camera; 50 }, 51 52 createRenderer: function (felem, width, height, antialias, lights, shadow, checkShaderErrors){//渲染器 53 let fel = felem || document.body; 54 let renderer = new THREE.WebGLRenderer({ 55 antialias : antialias || false, //抗割齿 56 powerPreference:"high-performance" //选择高性能GPU渲染 57 }); 58 renderer.setSize(width || _width, height || _height); 59 renderer.setPixelRatio(window.devicePixelRatio); 60 renderer.gammaFactor = 2.2; //着色校正 61 renderer.physicallyCorrectLights = lights || false; //使其精确照明 62 renderer.shadowMap.enabled = shadow || false; //渲染阴影 63 renderer.debug.checkShaderErrors = checkShaderErrors || false; // 64 if(!renderer.extensions.get('WEBGL_depth_texture')){console.log("深度纹理扩展获取失败:WEBGL_depth_texture");} 65 fel.appendChild(renderer.domElement); 66 return renderer; 67 }, 68 69 addLinghts: function (scene, hc){//灯光 70 let a = new THREE.AmbientLight(0x696969);//环境光(无处不在的光,太阳光) 71 72 let b = new THREE.DirectionalLight(0xFFFFFF, 1);//平行光(产生阴影的光) 73 b.position.set(0, 50, 50);//位置 74 b.castShadow = true;// 产生动态阴影 75 //b.target = Object3D; //平行光的方向是从它的位置到目标位置。默认的目标位置为原点 (0,0,0)。 76 b.shadow.radius = 1;//使阴影边缘变模糊 77 b.shadow.bias = 0.0001; 78 b.shadow.mapSize.width = 1024;//阴影质量w 79 b.shadow.mapSize.height = 1024;//阴影质量h 80 81 //下面属性默认不自动更新 82 /* let l_d = 20; //光照区域的大小 100 * 100 83 b.shadow.camera.left = -l_d; 84 b.shadow.camera.right = l_d; 85 b.shadow.camera.top = l_d; 86 b.shadow.camera.bottom = -l_d; */ 87 b.shadow.camera.near = 0.1;//最近 88 b.shadow.camera.far = 100;//最远 89 90 91 /* var helperShadow = new THREE.CameraHelper(b.shadow.camera); 92 scene.add(a, b, helperShadow); 93 var c = ()=>{()=>{helperShadow.update(); hc.update(); }} 94 new Gui(b.position, ["x", "y", "z"], [-2500, 2500, 1]).change(c) 95 .add(b.shadow, "radius", [-1, 1, 0.1]).change(c) 96 .add(b.shadow.mapSize, ["width", "height"], [0, 2048, 1]).change(c) 97 .title("调试灯光"); */ 98 scene.add(a, b); 99 return [a, b]; 100 }, 101 102 addControls: function (scene, camera, renderer, children, hc){//控件 103 104 //拖放控件 105 let drag = new THREE.DragControls(children, camera, renderer.domElement); 106 //drag.addEventListener('hoveron', (e)=>{this.addTarget(e.object);}); 107 drag.enabled = false; 108 //this.dragcontrols = dc; 109 110 //轨道控件 111 let orbit = new THREE.OrbitControls(camera, renderer.domElement); 112 orbit.target = new THREE.Vector3(0, 0, 0);//控件焦点 113 //orbit.minPolarAngle = Math.PI * 0.3;//向上最大角度 114 //orbit.maxPolarAngle = Math.PI * 0.4;//向下最大角度 115 orbit.minDistance = _minDistance;//最小距离 116 orbit.maxDistance = _maxDistance;//最大距离 117 orbit.autoRotateSpeed = 10;//自动旋转速度 118 //orbit.panSpeed = 100;//鼠标旋转速度 119 orbit.enableZoom = true;//是否启用缩放 120 orbit.enableKeys = true;//是否启用键盘 121 orbit.panSpeed = 1;//鼠标平移速度 122 orbit.keyPanSpeed = 100;//按键平移的速度 123 orbit.keys.LEFT = 65;//key a左 124 orbit.keys.UP = 87;//key w前 125 orbit.keys.RIGHT = 68;//key d右 126 orbit.keys.BOTTOM = 83;//key s后 127 orbit.addEventListener("change", ()=>{this.render(scene, camera, renderer);}); 128 129 130 //平移控件 131 var transform = new THREE.TransformControls(camera, renderer.domElement); 132 transform.addEventListener( 'dragging-changed', (e)=>{orbit.enabled = !e.value;}); 133 transform.size = 1; 134 scene.add(transform); 135 136 return {drag: drag, orbit: orbit, transform: transform}; 137 }, 138 139 updateGeometry: function (mesh, geometry){//更换几何体 140 if(!mesh || !geometry){ 141 console.log("_Three: 几何体更换失败"); 142 return; 143 } 144 if(mesh.HandCreate.wireframe){ 145 mesh.HandCreate.wireframe.geometry.dispose(); 146 mesh.HandCreate.wireframe.geometry = new THREE.WireframeGeometry(geometry); 147 } 148 mesh.geometry.dispose(); 149 mesh.geometry = geometry; 150 }, 151 152 updateMaterial: function (mesh, material){//更换材质 153 if(!mesh || !material){ 154 console.log("_Three: 材质更换失败"); 155 return; 156 } 157 let newMat = material.clone(true); 158 //newMat.color.copy(mesh.material.color); 159 newMat.transparent = true; 160 if(mesh.material.map !== null){this.updateTexture(newMat, mesh.material.map);} 161 mesh.material.dispose(); 162 mesh.material = newMat; 163 }, 164 165 updateTexture: function (material, texture){//更换纹理 166 if(!material || !texture){ 167 console.log("_Three: 纹理更换失败"); 168 return; 169 } 170 let map = new THREE.Texture(texture.image); 171 map.wrapS = THREE.RepeatWrapping; 172 map.wrapT = THREE.RepeatWrapping; 173 map.repeat.set(1, 1); 174 map.minFilter = THREE.NearestFilter; 175 map.magFilter = THREE.NearestFilter; 176 if(material.map !== null){ 177 map.wrapS = material.map.wrapS; 178 map.wrapT = material.map.wrapT; 179 map.repeat.copy(material.map.repeat); 180 map.anisotropy = material.map.anisotropy; 181 material.map.dispose(); 182 } 183 material.map = map; 184 material.map.needsUpdate = true; 185 material.needsUpdate = true; 186 }, 187 188 getBox3: function (mesh){//获取Box3 189 mesh.geometry.computeBoundingBox();//计算mesh获取box3对象 190 return mesh.geometry.boundingBox.applyMatrix4(mesh.matrixWorld); 191 }, 192 193 render: function (scene, camera, renderer){//渲染 194 renderer.render(scene, camera); 195 }, 196 197 getBSP: function (meshA, meshB, type){//剪裁 添加 重合 198 if(!meshA || !meshB || !type || meshA === meshB){console.log("getBSP:参数错误, 请选择1至2个物体进行运算"); return;} 199 if(!meshA.geometry || !meshB.geometry) return; 200 if(meshA.geometry.isGeometry !== true || meshB.geometry.isGeometry !== true) return; 201 let bsp_a = new ThreeBSP(meshA);//生成ThreeBSP对象 202 let bsp_b = new ThreeBSP(meshB);//生成ThreeBSP对象 203 let bsp = bsp_a[type](bsp_b);//进行 type 计算 204 let geo = bsp.toGeometry();//console.log(bsp); 205 geo.computeFaceNormals();//更新geo的面 206 geo.computeVertexNormals();//更新geo的顶点 207 return geo; 208 }, 209 210 toBuffer: function (geometry){//几何体 转为缓存几何体 211 if(geometry.isGeometry !== true) return; 212 return new THREE.BufferGeometry().fromGeometry(geometry); 213 }, 214 215 loadingGLTF: function (url, scene){//导入 216 if(!this.loadGLTF){this.__proto__.loadGLTF = new THREE.GLTFLoader();} 217 if(!scene) return; 218 this.loadGLTF.load(url, (gltf)=>{ 219 scene.add(gltf.scene); 220 }); 221 }, 222 223 exporterGLTF: function (mesh, fileType){//导出物体(限谷歌浏览器) 224 if(!this.exportGLTF){this.__proto__.exportGLTF = new THREE.GLTFExporter();} 225 if(!mesh){console.log("mesh 错误"); return;} 226 // 使用MeshBasicMaterial 或 MeshStandardMaterial 材质 效果会更好 227 //使用 BufferGeometry 缓存几何体 文件体积会更小 228 //if(mesh.geometry.isGeometry === true){mesh.geometry = new THREE.BufferGeometry().fromGeometry(mesh.geometry);} 229 var opt = { 230 binary: fileType || this.exportGLTFFileType || false, 231 embedImages: true, 232 onlyVisible: true, 233 truncateDrawRange: true, 234 trs: false 235 }; 236 var download = ( blob, filename )=>{ 237 let link = _view.add(document.body, "a"); 238 link.style.display = 'none'; 239 link.href = URL.createObjectURL( blob ); console.log(link.href); 240 link.download = filename; 241 link.click(); 242 _view.remove(link); 243 } 244 245 this.exportGLTF.parse(mesh, function ( result ){ 246 if(result instanceof ArrayBuffer){ 247 download(new Blob([result], {type: 'application/octet-stream'}), 'scene.glb'); 248 }else{ 249 download(new Blob([JSON.stringify( result, null, 2 )], {type: 'text/plain'}), 'scene.gltf'); 250 } 251 }, opt); 252 }, 253 254 runRaycaster: function (o, w, h){//光线投射 255 o.result.length = 0; 256 o.vector2.set((o.x / w || _width) * 2 - 1, -(o.y / h || _height) * 2 + 1); 257 o.raycaster.setFromCamera(o.vector2, o.camera); 258 o.raycaster.intersectObjects(o.children, o.recursive, o.result); 259 }, 260 261 createClipPlane: function (handCreate){//添加 面 和 点 剪裁面 262 let pa = new THREE.Plane(new THREE.Vector3( 1, 0, 0 ), 1); 263 let pb = new THREE.Plane(new THREE.Vector3( 0, -1, 0 ), 1); 264 let pc = new THREE.Plane(new THREE.Vector3( 0, 0, -1), 1); 265 let pd = new THREE.Plane(new THREE.Vector3( 0, 1, 1), 1); 266 267 let hg = new THREE.Group(); 268 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)); 269 return { 270 planes: [pa, pb, pc, pd], 271 helpers: hg 272 }; 273 var geometry = new THREE.SphereGeometry(1, 48, 24); 274 var material = new THREE.MeshLambertMaterial({ 275 color: new THREE.Color("#666666"), 276 side: THREE.DoubleSide, 277 clippingPlanes: clipPlane, 278 clipIntersection: true 279 }); 280 //console.log(helper0); console.log(material); 281 handCreate.add(new THREE.Mesh(geometry, material), helperGroup); 282 283 handCreate.renderer.localClippingEnabled = true; 284 285 //clipPlane.constant = 0.1; 286 new Gui({constant:0}, [-1, 1, 0.01]) 287 .change((val)=>{ 288 for(let k = 0; k < clipPlane.length; k++){ 289 clipPlane[k].constant = val; 290 } 291 handCreate.update(); 292 }) 293 .add(material, "clipIntersection") 294 .add(helper0, "size", [0, 10, 0.1]) 295 .change(()=>{handCreate.update();}) 296 } 297 298 }); 299 300 301 302 //几何体 303 var _Geometry = function (){ 304 _Three.call(this); 305 //this.width = 100; _width 306 this.height = 100; 307 this.y = this.campos.y; 308 this.dis = 0.5; 309 this.backMesh = {distance: 0, nowDistance: 0}; 310 this.targetChange = null; 311 this.objects = []; 312 } 313 314 _Geometry.prototype = Object.assign(Object.create(_Three.prototype), { 315 316 constructor: _Geometry, 317 318 config: [ 319 new THREE.BoxGeometry(1, 1, 1, 1, 1, 1), 320 new THREE.SphereGeometry(0.5, 8 , 6, 0, Math.PI * 2, 0, Math.PI), 321 new THREE.PlaneGeometry(1, 1, 1, 1), 322 new THREE.CircleGeometry(0.5, 16, 0, Math.PI * 2), 323 new THREE.CylinderGeometry(0.5, 0.5, 1, 8, 1, false, 0, Math.PI * 2) 324 ], 325 326 campos: {x: _width/110, y: 0, z: 1.5}, 327 328 isGoToPosition: true, 329 330 defaultMaterial: new THREE.MeshBasicMaterial({wireframe: true}), 331 332 init: function (){//初始化 333 if(this.scene === undefined) this.addScene(); 334 if(this.show === undefined) this.setShow(); 335 if(this.target === undefined) this.setTarget(); 336 this.renderView(this.config); 337 return this; 338 }, 339 340 addScene: function (){//添加 场景 341 let elem = _view.add(document.body, "div", null, "ShowObject box-scroll-block"); 342 _view.addEvent(elem, 'click', (e)=>{this.addTarget(e);}); 343 344 let scene = this.createScene(0x000000, false); 345 var camera = new THREE.OrthographicCamera(_width/-100, _width/100, this.height/100, this.height/-100, 0.1, 10); 346 camera.lookAt(0, 0, 0); 347 let renderer = this.createRenderer(elem, _width, this.height, true, true, true, true); 348 let linghts = this.addLinghts(scene); 349 let drag = new THREE.DragControls(scene.children, camera, renderer.domElement); 350 drag.enabled = false; 351 this.__proto__.scene = {e: elem, s:scene, c: camera, r: renderer, l: linghts, drag: drag, target: null} 352 drag.enabled = false; 353 drag.addEventListener('drag', (e)=>{ 354 this.update(); 355 }); 356 drag.addEventListener('hoveron', (e)=>{ 357 if(drag.enabled === true) return; 358 this.scene.target = e.object; 359 }); 360 drag.addEventListener('hoveroff', ()=>{ 361 this.scene.target = null; 362 }); 363 364 this.goToPosition(); 365 }, 366 367 addLinghts: function (scene){//重写添加灯光 368 let a = new THREE.AmbientLight(0x696969); 369 let b = new THREE.DirectionalLight(0xFFFFFF, 1); 370 b.position.set(0, 5, 5); 371 scene.add(a, b); 372 return [a, b]; 373 }, 374 375 goToPosition: function (){//跳转到 geometry 坐标 376 if(this.isGoToPosition === false) return; 377 this.scene.c.position.set(this.campos.x, this.campos.y, this.campos.z); 378 this.update(); 379 }, 380 381 setPos: function (mesh, k){//renderView-> 设置物体之间的距离 382 mesh.position.set(this.backMesh.distance, this.y, 0); 383 //let size = box3.getSize(new THREE.Vector3()); 384 let box3 = this.getBox3(mesh); 385 let width = box3.getSize(new THREE.Vector3()).x; 386 let center = box3.getCenter(new THREE.Vector3()).x; 387 388 //let dtp = box3.distanceToPoint(new THREE.Vector3(this.backMesh.distance, this.y, 0)); 389 //console.log(width); 390 this.backMesh.distance += width + this.dis; 391 392 //this.backMesh.left = this.backMesh.distance - width + center; 393 394 //this.backMesh.nowDistance = width / 2 - center + this.backMesh.distance; 395 //var helper = new THREE.Box3Helper(box3, 0xffff00); 396 //helper.position.copy(mesh.position); 397 //this.scene.s.add(helper); 398 399 //console.log(this.backMesh) 400 //console.log(width, center); 401 }, 402 403 addMesh: function (object, key){//renderView-> 添加物体 404 let mesh = new THREE.Mesh(object, this.defaultMaterial); 405 mesh.HandCreate = {type: "_Geometry", index: key, MatIndex: 0} 406 this.scene.s.add(mesh); 407 return mesh; 408 }, 409 410 renderView: function (arr){//渲染场景视图 411 for(let k = 0; k < arr.length; k++){ 412 let mesh = this.addMesh(arr[k], k); 413 this.setPos(mesh, k); 414 this.objects.push(mesh); 415 } 416 this.update(); 417 }, 418 419 setShow: function (){//是否显示场景的html元素 420 let _show = false; 421 Object.defineProperties(this.__proto__, { 422 show: { 423 get:()=>{return _show;}, 424 set:(v)=>{ 425 if(v === true){ 426 this.scene.e.style.display = "block"; 427 }else{ 428 this.scene.e.style.display = "none"; 429 } 430 _show = v; 431 } 432 } 433 }); 434 }, 435 436 addTarget: function (e){//addScene event->场景html元素的事件回调函数 437 if(!this.scene.target) return; 438 this.target = this.scene.target; 439 }, 440 441 setTarget: function (){//配置 target 442 let _target = null; 443 Object.defineProperties(this.__proto__, { 444 target: { 445 get:()=>{return _target;}, 446 set:(v)=>{ 447 if(typeof(this.targetChange) === "function") this.targetChange(v); 448 _target = v; 449 } 450 } 451 }); 452 }, 453 454 exportObject: function (){//导出 几何体 455 456 }, 457 458 importObject: function (object){//导入 几何体 459 if(object.isGeometry !== true) return; 460 let nowKey = this.config.length; 461 let mesh = this.addMesh(object, nowKey); 462 this.setPos(mesh, nowKey); 463 this.config.push(object); 464 this.objects.push(mesh); 465 this.update(); 466 }, 467 468 update: function (){//更新场景 469 this.render(this.scene.s, this.scene.c, this.scene.r); 470 }, 471 472 updateObjectColors: function (color){ 473 for(let k = 0; k < this.objects.length; k++){ 474 this.objects[k].material.color.set(color); 475 } 476 this.update(); 477 }, 478 479 debugCamera: function (){//gui调试 正交相机 480 let c = this.scene.c; 481 let pos = {x: _width/110, y: 0, lookAt: true, position: false}; 482 let upd = ()=>{ 483 if(pos.lookAt) c.lookAt(pos.x, pos.y, 0); 484 if(pos.position) c.position.set(pos.x, pos.y, 5); 485 this.update(); 486 } 487 488 new Gui(pos, [0, 10, 0.1], "调试正交相机") 489 .change({ 490 x: (v)=>{pos.x = v; upd();}, 491 y: (v)=>{pos.y = v; upd();} 492 }) 493 494 } 495 496 }); 497 498 499 500 //材质 501 var _Material = function (){ 502 _Geometry.call(this); 503 } 504 505 _Material.prototype = Object.assign(Object.create(_Geometry.prototype), { 506 507 constructor: _Material, 508 509 config:[ 510 new THREE.MeshBasicMaterial(), 511 new THREE.MeshLambertMaterial(), 512 new THREE.MeshStandardMaterial() 513 ], 514 515 defaultGeometry: new THREE.BoxGeometry(1, 1, 1, 1, 1, 1), 516 517 campos: {x: _width/110, y: 1.5, z: 1.5}, 518 519 addMesh: function (object, key){ 520 let mesh = new THREE.Mesh(this.defaultGeometry, object); 521 mesh.HandCreate = {type: "_Material", index: key}; 522 this.scene.s.add(mesh); 523 return mesh; 524 }, 525 526 goToPosition: function (mesh){ 527 if(!mesh || this.isGoToPosition === false) return; this.mesh = mesh; 528 let geometry = _Geometry.prototype.config[mesh.HandCreate.GeoCI].clone(); 529 for(let k = 0; k < this.objects.length; k++){ 530 this.updateGeometry(this.objects[k], geometry); 531 } 532 this.scene.c.position.set(this.campos.x, this.campos.y, this.campos.z); 533 this.update(); 534 } 535 536 }); 537 538 539 540 //纹理 map 541 var _Texture = function (){ 542 _Material.call(this); 543 this.textureLen = 12; 544 this.setTexture(); 545 } 546 547 _Texture.prototype = Object.assign(Object.create(_Material.prototype), { 548 549 constructor: _Texture, 550 551 config: [], 552 553 campos: {x: _width/110, y: 3, z: 1.5}, 554 555 defaultMaterial: new THREE.MeshBasicMaterial(), 556 557 load: new THREE.TextureLoader(), 558 559 loaded: 0, 560 561 setTexture: function (){ 562 let k, texture; 563 for(k = 0; k < this.textureLen; k++){ 564 texture = this.load.load("img/texture/"+k+".jpg", ()=>{this.__proto__.loaded++;}); 565 texture.wrapS = THREE.RepeatWrapping; 566 texture.wrapT = THREE.RepeatWrapping; 567 texture.repeat.set(1, 1); 568 this.__proto__.config.push(texture); 569 } 570 if(this.loaded !== this.textureLen){this.awaitLoad();} 571 }, 572 573 awaitLoad: function (){ 574 let interval = setInterval(()=>{ 575 if(this.loaded === this.textureLen){ 576 this.update(); 577 clearInterval(interval); 578 console.log("load texture: "+this.loaded+"/"+this.textureLen); 579 }else{ 580 console.log("load texture: "+this.loaded+"/"+this.textureLen); 581 } 582 }, 300); 583 }, 584 585 addMesh: function (object, key){ 586 let mesh = new THREE.Mesh(this.defaultGeometry, new THREE.MeshBasicMaterial({map: object})); 587 //let mesh = new THREE.Mesh(this.defaultGeometry, this.defaultMaterial); 588 //this.updateTexture(mesh, object); 589 mesh.HandCreate = {type: "_Texture", index: key}; 590 this.scene.s.add(mesh); 591 return mesh; 592 }, 593 594 goToPosition: function (mesh){ 595 if(!mesh || this.isGoToPosition === false) return; this.mesh = mesh; 596 let geometry = _Geometry.prototype.config[mesh.HandCreate.GeoCI].clone(); 597 let material = _Material.prototype.config[mesh.HandCreate.MatCI].clone(); 598 for(let k = 0; k < this.objects.length; k++){ 599 this.updateGeometry(this.objects[k], geometry); 600 this.updateMaterial(this.objects[k], material); 601 } 602 this.scene.c.position.set(this.campos.x, this.campos.y, this.campos.z); 603 this.update(); 604 } 605 606 }); 607 608 //物体 609 var _Mesh = function (){} 610 611 //gui 612 var SetView = function (HC, newMesh, oldMesh){ 613 this.HC = HC; 614 this.newMesh = newMesh; 615 this.oldMesh = oldMesh; 616 return this.init(); 617 } 618 619 Object.assign(SetView.prototype, { 620 621 constructor: SetView, 622 623 init: function (){ 624 if(this.globalGui === undefined) this.createGlobal(); 625 if(this.SOG === undefined) this.createSelectObjectGui(); 626 627 this.createMesh(); 628 this.createGeometry(); 629 this.createMaterial(); 630 return this; 631 }, 632 633 createMesh: function (){ 634 let u = (a, v)=>{ 635 if(this.newMesh[a] === undefined) return; 636 this.newMesh[a] = v; 637 this.HC.update(); 638 } 639 let upd = (a, b, v)=>{ 640 this.newMesh[a][b] = v; 641 if(this.newMesh.HandCreate.wireframe) this.newMesh.HandCreate.wireframe[a][b] = v; 642 this.HC.update(); 643 } 644 let m = { 645 visible: this.newMesh.visible, 646 frustumCulled: this.newMesh.frustumCulled, 647 castShadow: this.newMesh.castShadow, 648 receiveShadow: this.newMesh.receiveShadow, 649 } 650 let o = { 651 exportGltf: ()=>{this.HC.Three.exporterGLTF(this.newMesh);}, 652 removeMesh: ()=>{ 653 if(this.newMesh.HandCreate.wireframe){this.HC.remove(this.newMesh.HandCreate.wireframe, this.HC.group);} 654 this.HC.remove(this.newMesh); 655 }, 656 addWireframe: true 657 } 658 659 this.gui = new Gui(m, true).name({visible: "显示物体", castShadow: "投射阴影", receiveShadow: "接收阴影"}) 660 .change({ 661 visible: ()=>{u("visible", m.visible);}, 662 frustumCulled: ()=>{u("frustumCulled", m.frustumCulled);}, 663 castShadow: ()=>{u("castShadow", m.castShadow);}, 664 receiveShadow: ()=>{u("receiveShadow", m.receiveShadow);} 665 }) 666 667 .add(o, true) 668 .name({addWireframe: "辅助网格", exportGltf: "导出物体", removeMesh: "移除物体"}) 669 .change({ 670 addWireframe: (e)=>{ 671 if(!this.newMesh.HandCreate.wireframe) return; 672 this.newMesh.HandCreate.wireframe.visible = o.addWireframe; 673 this.HC.update(); 674 } 675 }) 676 677 678 .add(this.newMesh.HandCreate.position, true, [-(_maxDistance/2), _maxDistance/2, _minDistance]) 679 .name({x: "位置X轴", y: "位置Y轴", z: "位置Z轴"}) 680 .change({ 681 x: (v)=>{upd("position", "x", v);}, 682 y: (v)=>{upd("position", "y", v);}, 683 z: (v)=>{upd("position", "z", v);} 684 }) 685 .add(this.newMesh.HandCreate.rotation, true, [-Math.PI, Math.PI, 0.001]) 686 .name({x: "旋转X轴", y: "旋转Y轴", z: "旋转Z轴"}) 687 .change({ 688 x: (v)=>{upd("rotation", "x", v);}, 689 y: (v)=>{upd("rotation", "y", v);}, 690 z: (v)=>{upd("rotation", "z", v);} 691 }) 692 .add(this.newMesh.HandCreate.scale, true, [0.1, _maxDistance * 0.5, _minDistance]) 693 .name({x: "缩放X轴", y: "缩放Y轴", z: "缩放Z轴"}) 694 .change({ 695 x: (v)=>{upd("scale", "x", v);}, 696 y: (v)=>{upd("scale", "y", v);}, 697 z: (v)=>{upd("scale", "z", v);} 698 }) 699 700 .add(this.newMesh.HandCreate, true, "isSelect", "是否可选取").change(()=>{this.HC.removeTarget(this.newMesh);}) 701 .display("none") 702 .title("物体-"+this.newMesh.type+"-"+this.newMesh.id); 703 }, 704 705 createGeometry: function (){ 706 if(this.oldMesh.geometry.parameters === undefined){console.log("SetView: 忽略了geometry"); return;} 707 let o, p = {}, geo; 708 for(let k in this.oldMesh.geometry.parameters){p[k] = this.oldMesh.geometry.parameters[k];} 709 switch(this.oldMesh.geometry.type){ 710 711 case "BoxGeometry": 712 o = { 713 width:[0.1, 10, 0.1], 714 height:[0.1, 10, 0.1], 715 depth:[0.1, 10, 0.1], 716 widthSegments:[1, 30, 1], 717 heightSegments:[1, 30, 1], 718 depthSegments:[1, 30, 1] 719 } 720 this.gui.create(p, o, true) 721 .name({width: "宽度", height: "高度", depth: "深度", widthSegments: "宽段数", heightSegments: "高段数", depthSegments: "深段数"}) 722 .change(()=>{ 723 geo = new THREE.BoxGeometry(p.width, p.height, p.depth, p.widthSegments, p.heightSegments, p.depthSegments); 724 this.HC.Three.updateGeometry(this.newMesh, geo); 725 this.HC.update(); 726 }); 727 728 break; 729 730 case "SphereGeometry": 731 o = { 732 radius:[0.1, 10, 0.1], 733 widthSegments:[1, 30, 1], 734 heightSegments:[1, 30, 1], 735 phiStart:[0, Math.PI*2, 0.1], 736 phiLength:[0.1, Math.PI*2, 0.1], 737 thetaStart:[0, Math.PI*2, 0.1], 738 thetaLength:[0.1, Math.PI*2, 0.1] 739 } 740 this.gui.create(p, o, true) 741 .name({radius: "半径", widthSegments: "宽段数", heightSegments: "高段数", phiStart: "经线起始角度", phiLength: "经线起始角度大小", thetaStart: "纬线起始角度", thetaLength: "纬线起始角度大小",}) 742 .change(()=>{ 743 geo = new THREE.SphereGeometry(p.radius, p.widthSegments, p.heightSegments, p.phiStart, p.phiLength, p.thetaStart, p.thetaLength); 744 this.HC.Three.updateGeometry(this.newMesh, geo); 745 this.HC.update(); 746 }); 747 748 break; 749 750 case "PlaneGeometry": 751 o = { 752 width: [1, 100, 0.1], 753 height: [1, 100, 0.1], 754 widthSegments: [1, 30, 1], 755 heightSegments: [1, 30, 1] 756 } 757 this.gui.create(p, o, true) 758 .name({width: "宽度", height: "高度", widthSegments: "宽段数", heightSegments: "高段数"}) 759 .change(()=>{ 760 geo = new THREE.PlaneGeometry(p.width, p.height, p.widthSegments, p.heightSegments); 761 this.HC.Three.updateGeometry(this.newMesh, geo); 762 this.HC.update(); 763 }); 764 break; 765 766 case "CircleGeometry": 767 o = { 768 radius: [0.1, 10, 0.1], 769 segments: [1, 30, 1], 770 thetaStart: [0, Math.PI*2, 0.1], 771 thetaLength: [0.1, Math.PI*2, 0.1] 772 } 773 this.gui.create(p, o, true) 774 .name({radius: "半径", segments: "分段数", thetaStart: "纬线起始角度", thetaLength: "纬线起始角度大小"}) 775 .change(()=>{ 776 geo = new THREE.CircleGeometry(p.radius, p.segments, p.thetaStart, p.thetaLength); 777 this.HC.Three.updateGeometry(this.newMesh, geo); 778 this.HC.update(); 779 }); 780 break; 781 782 case "CylinderGeometry": 783 784 o = { 785 radiusTop: [0.1, 10, 0.1], 786 radiusBottom: [0.1, 10, 0.1], 787 height: [0.1, 10, 0.1], 788 radialSegments: [1, 30, 1], 789 heightSegments: [1, 30, 1], 790 thetaStart: [0, Math.PI*2, 0.1], 791 thetaLength: [0.1, Math.PI*2, 0.1] 792 } 793 this.gui.create(p, o, true) 794 .name({openEnded: "不封顶", radiusTop: "顶部半径", radiusBottom: "底部半径", height: "高度", radialSegments: "侧面分段数", heightSegments: "高度分段数", thetaStart: "纬线起始角度", thetaLength: "纬线起始角度大小"}) 795 .change(()=>{ 796 geo = new THREE.CylinderGeometry(p.radiusTop, p.radiusBottom, p.height, p.radialSegments, p.heightSegments, p.openEnded, p.thetaStart, p.thetaLength); 797 this.HC.Three.updateGeometry(this.newMesh, geo); 798 this.HC.update(); 799 }) 800 break; 801 802 default : break; 803 } 804 this.gui.title("几何体-"+this.newMesh.geometry.type+"-"+this.newMesh.id); 805 }, 806 807 createMaterial: function (){ 808 809 let mat = this.newMesh.material; 810 811 let o = { 812 color: "#" + mat.color.getHexString(), 813 emissive: mat.emissive === undefined ? "#000000" : "#" + mat.emissive.getHexString(), 814 updateMaterial: ()=>{this.HC.material.goToPosition(this.newMesh);}, 815 updateTexture: ()=>{this.HC.texture.goToPosition(this.newMesh);} 816 } 817 let m = { 818 wireframe: mat.wireframe, 819 visible: mat.visible, 820 side: mat.side, 821 fog: mat.fog, 822 aoMapIntensity: mat.aoMapIntensity, 823 colorWrite: mat.colorWrite, 824 transparent: mat.transparent, 825 opacity: mat.opacity, 826 alphaTest: mat.alphaTest, 827 flatShading: mat.flatShading, 828 emissiveIntensity: mat.emissiveIntensity === undefined ? 0 : mat.emissiveIntensity, 829 repeatU: 1, 830 repeatV: 1, 831 anisotropy: 1 832 } 833 834 let num = { 835 aoMapIntensity: [0, 1, 0.1], 836 opacity: [0, 1, 0.1], 837 alphaTest: [0, 1, 0.1], 838 emissiveIntensity: [0, 1, 0.1], 839 repeatU: [1, 100, 1], 840 repeatV: [1, 100, 1], 841 anisotropy: [1, this.HC.renderer.capabilities.getMaxAnisotropy() || 2, 1] 842 }; 843 let sel = { 844 side: [["外面", THREE.FrontSide], ["里面", THREE.BackSide], ["双面", THREE.DoubleSide]] 845 }; 846 let name = { 847 wireframe:"网格模式", 848 visible:"显示材质", 849 side: "材质显示那一面", 850 fog: "受雾气影响", 851 aoMapIntensity: "遮挡效果", 852 colorWrite: "渲染颜色", 853 transparent: "渲染透明度", 854 opacity: "透明度", 855 alphaTest: "alpha值", 856 flatShading: "平面着色", 857 emissiveIntensity: "放射光强度", 858 repeatU: "重复量,纹理U面", 859 repeatV: "重复量,纹理V面", 860 anisotropy: "纹理清晰度" 861 }; 862 let c = { 863 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();}, 864 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();}, 865 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();}, 866 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();}, 867 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();}, 868 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();}, 869 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();}, 870 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();}, 871 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();}, 872 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();}, 873 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();}, 874 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();}, 875 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();}, 876 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();}, 877 878 }; 879 880 881 882 this.gui.create(m, num, true, sel).name(name).change(c) 883 884 .add(o, true) 885 .name({color: "材质颜色", emissive: "放射光颜色", updateMaterial: "替换材质", updateTexture: "替换纹理"}) 886 .change({ 887 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();}, 888 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();} 889 }) 890 891 .title("材质-"+this.newMesh.material.type+"-"+this.newMesh.id); 892 }, 893 894 createGlobal: function (){ 895 let o = { 896 setMode: "translate", 897 exportAll: ()=>{this.HC.Three.exporterGLTF(this.HC.intersects.group);}, 898 updateMaterialAll: ()=>{console.log("替换全部材质")}, 899 isgltf: true, 900 dragEnabled: false, 901 addMesh: ()=>{this.HC.geometry.goToPosition();} 902 } 903 904 let gui = new Gui(this.HC.geometry, "show", "显示选项栏") 905 906 .add(o, true, {dragEnabled: [["创建模式", false], ["编辑模式", true]], isgltf: [[".gltf", false], [".glb", true]], setMode: [["平移", "translate"], ["旋转", "rotate"], ["缩放", "scale"]]}) 907 .name({exportAll: "导出全部物体", updateMaterialAll: "替换全部材质", setMode: "控制模式", isgltf: "导出类型", addMesh: "添加物体", dragEnabled: "底部物体选项栏的状态(创建 或 调整其位置)"}) 908 .change({ 909 isgltf: (e)=>{this.HC.Three.exportGLTFFileType = eval(e.target.value);}, 910 setMode: (e)=>{this.HC.control.transform.setMode(e.target.value);}, 911 dragEnabled: (e)=>{ 912 let ty = "geometry"; 913 if(this.HC.geometry.scene.c.position.y === this.HC.material.campos.y){ty = "material";} 914 else if(this.HC.geometry.scene.c.position.y === this.HC.texture.campos.y){ty = "texture";} 915 916 this.HC.geometry.scene.drag.enabled = eval(e.target.value); 917 if(this.HC.geometry.scene.drag.enabled === true){ 918 this.HC.geometry.__proto__.isGoToPosition = false; 919 this.HC[ty].updateObjectColors(0xff0000); 920 }else{ 921 this.HC[ty].updateObjectColors(0xffffff); 922 this.HC.geometry.__proto__.isGoToPosition = true; 923 } 924 925 } 926 }) 927 928 .add(this.HC, true, ["lockTarget", "isSelectTargets"]) 929 .name({lockTarget: "禁用选取", isSelectTargets: "标记物体"}) 930 .change({ 931 isSelectTargets: ()=>{ 932 if(this.HC.isSelectTargets === false){ 933 this.HC.removeTargets(); 934 this.SOG.display("none"); 935 return; 936 } 937 this.SOG.focus().display("block"); 938 }, 939 lockTarget: ()=>{ 940 if(this.HC.lockTarget === false){ 941 this.HC.removeTargets(); 942 } 943 } 944 }) 945 946 .setPos(300, 10) 947 948 .title("global"); 949 950 this.__proto__.globalGui = gui; 951 }, 952 953 createSelectObjectGui: function(){ 954 let fhts = (callback)=>{ 955 for(let k = 0; k < this.HC.targets.length; k++){callback(this.HC.targets, k);} 956 } 957 958 let bsp = { 959 type: "intersect", 960 run: ()=>{ 961 if(this.HC.targets[0] === undefined){console.log("你还没有选择任何物体"); return;} 962 if(this.newMesh === this.HC.targets[0].mesh) return; 963 this.HC.geometry.importObject(this.HC.Three.getBSP(this.newMesh.clone(true), this.HC.targets[0].mesh.clone(true), bsp.type)); 964 } 965 } 966 let o = { 967 deletes: ()=>{ 968 fhts((o, k)=>{ 969 if(o[k].mesh.HandCreate.wireframe){this.HC.remove(o[k].mesh.HandCreate.wireframe, this.HC.group);} 970 this.HC.remove(o[k].mesh); 971 }); 972 if(!this.HC.target.mesh) return; 973 if(this.HC.target.mesh.HandCreate.wireframe){ 974 this.HC.remove(this.HC.target.mesh.HandCreate.wireframe, this.HC.group); 975 } 976 this.HC.remove(this.HC.target.mesh); 977 }, 978 exports: ()=>{ 979 fhts((o, k)=>{ 980 o[k].mesh.material.color.set(o[k].color); 981 this.HC.Three.exporterGLTF(o[k].mesh); 982 o[k].mesh.material.color.set("red"); 983 }); 984 if(!this.HC.target.mesh) return; 985 this.HC.Three.exporterGLTF(this.HC.target.mesh); 986 } 987 } 988 989 this.SOG = new Gui(bsp, true, {type:[["交集", "intersect"], ["并集", "union"], ["差集", "subtract"]]}) 990 .name({run: "开始布尔运算", type: "布尔运算类型"}) 991 .change({type: (e)=>{bsp.type = e.target.value;}}) 992 .title("多物体操作(包含当前目标对象)") 993 994 .create(o).name({deletes: "删除物体", exports: "导出物体"}) 995 996 997 998 .setPos(300, 2) 999 .display("none") 1000 } 1001 1002 }); 1003 1004 1005 1006 //main 1007 var HandCreate = function (){ 1008 this.Three = new _Three(); 1009 this.group = new THREE.Group(); 1010 this.target = {}; 1011 this.isSelectTargets = false; 1012 this.targets = []; 1013 this.backMesh = null; 1014 this.lockTarget = false; 1015 this.scene = this.Three.createScene([], false); 1016 this.renderer = this.Three.createRenderer(document.body, _width, _height, true, true, true, true); 1017 1018 } 1019 1020 Object.assign(HandCreate.prototype, { 1021 1022 constructor: HandCreate, 1023 1024 init: function (){ 1025 this.intersects = { 1026 raycaster: new THREE.Raycaster(), 1027 group: new THREE.Group(), 1028 vector2: new THREE.Vector2(), 1029 result: [], 1030 camera: this.camera, 1031 recursive: true, 1032 x: 0, 1033 y: 0, 1034 }; 1035 this.renderer.domElement.style = "position:absolute; top:0; left:0";//如果不定位, gui的移动块会不正常显示 1036 //this.renderer.localClippingEnabled = true;//是否渲染 平面剪裁 1037 this.camera = this.Three.createCamera(45, _width, _height, _minDistance, _maxDistance * _minDistance * 0.2); 1038 this.camera.position.set(0, _maxDistance * 0.001, _maxDistance * 0.001); 1039 this.linghts = this.Three.addLinghts(this.scene, this); 1040 this.control = this.Three.addControls(this.scene, this.camera, this.renderer, this.intersects.group.children, this); 1041 this.control.drag.addEventListener('hoveron', (e)=>{this.setTarget(e.object);}); 1042 //this.control.drag.transformGroup = true; 1043 this.control.transform.addEventListener('change', ()=>{this.transformChange();}); 1044 1045 this.geometry = new _Geometry().init(); 1046 this.geometry.targetChange = (v)=>{this.createObject(v);}; 1047 this.geometry.show = true; 1048 1049 this.material = new _Material().init(); 1050 1051 this.texture = new _Texture().init(); 1052 1053 this.gridHelper = new THREE.GridHelper(_maxDistance, _maxDistance/1); 1054 this.scene.add(this.group, this.intersects.group, this.camera, this.gridHelper); 1055 1056 1057 //this.clip = this.Three.createClip(); 1058 //this.globalView(); 1059 //this.Three.loadingGLTF("img/gltfs/scene.gltf", this.intersects.group); 1060 //this.Three.loadingGLTF("img/gltfs/scene.glb", this.intersects.group); 1061 return this; 1062 }, 1063 1064 add: function (mesh, group){ 1065 if(!mesh) return; 1066 let gro = group || this.intersects.group; 1067 if(Array.isArray(mesh) === true){ 1068 let k, len = mesh.length; 1069 for(k; k < len; k++){ 1070 if(!mesh[k]) continue; 1071 gro.add(mesh[k]); 1072 } 1073 }else{ 1074 gro.add(mesh); 1075 } 1076 this.update(); 1077 }, 1078 1079 addWireframe: function (mesh, color){ 1080 let col = color || 0x696969, gro = this.group; 1081 let wireframe = new THREE.LineSegments(new THREE.WireframeGeometry(mesh.geometry)); 1082 wireframe.material.color.set(col); 1083 gro.add(wireframe); 1084 return wireframe; 1085 }, 1086 1087 remove: function (mesh, group){ 1088 if(!mesh){console.log("remove: mesh不存在"); return;} 1089 let arr = group || this.intersects.group; 1090 if(!arr.remove){console.log("remove: group错误"); return;} 1091 this.removeTarget(mesh); 1092 //if(mesh.gui) mesh.gui.remove(); 1093 if(mesh.HandCreate) mesh.HandCreate.SV.gui.remove(); 1094 if(mesh.material.map){mesh.material.map.dispose();} 1095 mesh.material.dispose(); 1096 mesh.geometry.dispose(); 1097 arr.remove(mesh); 1098 this.update(); 1099 }, 1100 1101 update: function (){ 1102 this.Three.render(this.scene, this.camera, this.renderer); 1103 }, 1104 1105 setTarget: function (mesh){ 1106 if(mesh.HandCreate.isSelect === false) return; 1107 if(this.isSelectTargets === true) this.setTargets(mesh); 1108 if(this.target.mesh === mesh || this.lockTarget === true) return; 1109 if(mesh.HandCreate === undefined || mesh.HandCreate.SV === undefined){ 1110 mesh.HandCreate.isSelect = false; 1111 this.lockTarget = true; 1112 console.log("setTarget: mesh 错误,取消选择"); 1113 return; 1114 } 1115 1116 this.removeTarget(this.target.mesh); 1117 1118 this.target.mesh = mesh; 1119 this.control.transform.attach(mesh); 1120 mesh.HandCreate.SV.gui.display("block"); 1121 this.geometry.goToPosition(); 1122 this.update(); 1123 }, 1124 1125 removeTarget: function (mesh){ 1126 if(!mesh || this.target.mesh !== mesh) return; 1127 this.control.transform.detach(mesh); 1128 mesh.HandCreate.SV.gui.display("none"); 1129 delete(this.target.mesh); 1130 this.update(); 1131 }, 1132 1133 setTargets: function (mesh){ 1134 if(this.target.mesh && mesh && this.target.mesh === mesh) return; 1135 //if(this.targets.indexOf(mesh) !== -1){return;} 1136 for(let k = 0; k < this.targets.length; k ++){if(this.targets[k].mesh === mesh){return;}} 1137 this.isSelectTargets = true; 1138 this.lockTarget = true; 1139 this.targets.push({mesh: mesh, color: mesh.material.color.getHex()}); 1140 mesh.material.color.set("red"); 1141 this.update(); 1142 }, 1143 1144 removeTargets: function (){ 1145 this.isSelectTargets = false; 1146 this.lockTarget = false; 1147 for(let k = 0; k < this.targets.length; k++){ 1148 this.targets[k].mesh.material.color.set(this.targets[k].color); 1149 } 1150 this.targets.length = 0; 1151 this.update(); 1152 }, 1153 1154 addMeshHandCreate: function (mesh){ 1155 1156 mesh.HandCreate = {}; 1157 let _SV = null, _GeoCI = null, _MatCI = null, _TexCI = null; 1158 let _isSelect = true, _wireframe = null; 1159 let _position = {}, _rotation = {}, _scale = {}; 1160 Object.defineProperties(mesh.HandCreate, { 1161 SV: { 1162 configurable: false, 1163 enumerable: true, 1164 get: ()=>{return _SV;}, 1165 set: (v)=>{_SV = v;} 1166 }, 1167 1168 GeoCI: { 1169 configurable: false, 1170 enumerable: true, 1171 get: ()=>{return _GeoCI;}, 1172 set: (v)=>{_GeoCI = v;} 1173 }, 1174 1175 MatCI: { 1176 configurable: false, 1177 enumerable: true, 1178 get: ()=>{return _MatCI;}, 1179 set: (v)=>{_MatCI = v;} 1180 }, 1181 1182 TexCI: { 1183 configurable: false, 1184 enumerable: true, 1185 get: ()=>{return _TexCI;}, 1186 set: (v)=>{_TexCI = v;} 1187 }, 1188 1189 isSelect: { 1190 configurable: false, 1191 enumerable: true, 1192 get: ()=>{return _isSelect;}, 1193 set: (v)=>{_isSelect = v;} 1194 }, 1195 1196 wireframe: { 1197 configurable: false, 1198 enumerable: true, 1199 get: ()=>{return _wireframe;}, 1200 set: (v)=>{_wireframe = v;} 1201 }, 1202 1203 position: { 1204 configurable: false, 1205 enumerable: true, 1206 get: ()=>{return _position;}, 1207 set: (v)=>{_position = v;} 1208 }, 1209 1210 rotation: { 1211 configurable: false, 1212 enumerable: true, 1213 get: ()=>{return _rotation;}, 1214 set: (v)=>{_rotation = v;} 1215 }, 1216 1217 scale: { 1218 configurable: false, 1219 enumerable: true, 1220 get: ()=>{return _scale;}, 1221 set: (v)=>{_scale = v;} 1222 } 1223 1224 }); 1225 1226 let upd = (v, a, b)=>{mesh[a][b] = v; this.update();} 1227 let _px = mesh.position.x, _py = mesh.position.y, _pz = mesh.position.z; 1228 Object.defineProperties(mesh.HandCreate.position, { 1229 x: { 1230 configurable: false, 1231 enumerable: true, 1232 get: ()=>{return _px;}, 1233 set: (v)=>{upd(v, "position", "x"); _px = v;} 1234 }, 1235 y: { 1236 configurable: false, 1237 enumerable: true, 1238 get: ()=>{return _py;}, 1239 set: (v)=>{upd(v, "position", "y"); _py = v;} 1240 }, 1241 z: { 1242 configurable: false, 1243 enumerable: true, 1244 get: ()=>{return _pz;}, 1245 set: (v)=>{upd(v, "position", "z"); _pz = v;} 1246 } 1247 }); 1248 1249 let _rx = mesh.rotation.x, _ry = mesh.rotation.y, _rz = mesh.rotation.z; 1250 Object.defineProperties(mesh.HandCreate.rotation, { 1251 x: { 1252 configurable: false, 1253 enumerable: true, 1254 get: ()=>{return _rx;}, 1255 set: (v)=>{_rx = v;} 1256 }, 1257 y: { 1258 configurable: false, 1259 enumerable: true, 1260 get: ()=>{return _ry;}, 1261 set: (v)=>{_ry = v;} 1262 }, 1263 z: { 1264 configurable: false, 1265 enumerable: true, 1266 get: ()=>{return _rz;}, 1267 set: (v)=>{_rz = v;} 1268 } 1269 }); 1270 1271 let _sx = mesh.scale.x, _sy = mesh.scale.y, _sz = mesh.scale.z; 1272 Object.defineProperties(mesh.HandCreate.scale, { 1273 x: { 1274 configurable: false, 1275 enumerable: true, 1276 get: ()=>{return _sx;}, 1277 set: (v)=>{_sx = v;} 1278 }, 1279 y: { 1280 configurable: false, 1281 enumerable: true, 1282 get: ()=>{return _sy;}, 1283 set: (v)=>{_sy = v;} 1284 }, 1285 z: { 1286 configurable: false, 1287 enumerable: true, 1288 get: ()=>{return _sz;}, 1289 set: (v)=>{_sz = v;} 1290 } 1291 }); 1292 1293 }, 1294 1295 transformChange: function (mesher, typeer){ 1296 1297 if(!this.target || !this.target.mesh || !this.target.mesh.HandCreate){return;} 1298 1299 let type = typeer || this.control.transform.getMode(), mesh = mesher || this.target.mesh; 1300 let hc = mesh.HandCreate; 1301 1302 switch(type){ 1303 case "translate": 1304 hc.position.x = mesh.position.x; 1305 hc.position.y = mesh.position.y; 1306 hc.position.z = mesh.position.z; 1307 if(hc.wireframe) hc.wireframe.position.set(mesh.position.x, mesh.position.y, mesh.position.z); 1308 break; 1309 1310 case "rotate": 1311 hc.rotation.x = mesh.rotation.x; 1312 hc.rotation.y = mesh.rotation.y; 1313 hc.rotation.z = mesh.rotation.z; 1314 if(hc.wireframe) hc.wireframe.rotation.set(mesh.rotation.x, mesh.rotation.y, mesh.rotation.z); 1315 break; 1316 1317 case "scale": 1318 hc.scale.x = mesh.scale.x; 1319 hc.scale.y = mesh.scale.y; 1320 hc.scale.z = mesh.scale.z; 1321 if(hc.wireframe) hc.wireframe.scale.set(mesh.scale.x, mesh.scale.y, mesh.scale.z); 1322 break; 1323 1324 default: break; 1325 } 1326 1327 this.update(); 1328 }, 1329 1330 createObject: function (v){ 1331 1332 let geo = ()=>{ 1333 let mesh = new THREE.Mesh(v.geometry.clone(), v.material.clone()); 1334 mesh.material.transparent = true; 1335 mesh.castShadow = true; 1336 mesh.receiveShadow = true; 1337 mesh.customDepthMaterial = new THREE.MeshDepthMaterial({depthPacking: THREE.RGBADepthPacking}); 1338 1339 mesh.HandCreate = { 1340 SV: null, //view 1341 GeoCI: v.HandCreate.index, //几何体索引 1342 MatCI: v.HandCreate.MatIndex,//材质索引 1343 TexCI: null, //纹理索引 1344 isSelect: true, //是否可被选取 1345 position: {x: mesh.position.x, y: mesh.position.y, z: mesh.position.z}, //位移 1346 rotation: {x: mesh.rotation.x, y: mesh.rotation.y, z: mesh.rotation.z}, //旋转 1347 scale: {x: mesh.scale.x, y: mesh.scale.y, z: mesh.scale.z}, //缩放 1348 wireframe: this.addWireframe(mesh) //物体辅助网格线 1349 }; 1350 1351 mesh.HandCreate.SV = new SetView(this, mesh, v); 1352 1353 this.backMesh = mesh; 1354 1355 //console.log(this.intersects.group.children.flat(Infinity)); 1356 //if(this.intersects.group.children.length > 0){this.intersects.group.children[0].add(mesh); return;} 1357 1358 this.add(mesh); 1359 this.setTarget(mesh); 1360 } 1361 1362 let mat = ()=>{ 1363 this.Three.updateMaterial(this.material.mesh, v.material); 1364 this.material.mesh.HandCreate.MatCI = v.HandCreate.index; 1365 this.update(); 1366 } 1367 1368 let tex = ()=>{ 1369 this.Three.updateTexture(this.texture.mesh.material, v.material.map); 1370 this.texture.mesh.HandCreate.TexCI = v.HandCreate.index; 1371 this.update(); 1372 } 1373 1374 switch(v.HandCreate.type){ 1375 case "_Geometry": geo(); break; 1376 case "_Material": mat(); break; 1377 case "_Texture": tex(); break; 1378 default: break; 1379 } 1380 1381 } 1382 1383 }); 1384 1385 //代理 1386 /* this.ForCreate = new Proxy(new HandCreate().init(), { 1387 get(o, k){ 1388 return o[k]; 1389 }, 1390 set(o, k, v){ 1391 o[k] = v; 1392 } 1393 }); */ 1394 1395 this.ForCreate = new HandCreate().init(); 1396 1397 }).call(this)