1 完整代碼下載 https://pan.baidu.com/s/1JJyVcP2KqXsd5G6eaYpgHQ 提取碼 3fzt (壓縮包名: 2020-3-20-demo.zip) 2 圖片展示 3 主要代碼 1 /** HandCreate 簡單的 圖形界面 搭建幾何體 2 construct ...
1 完整代碼下載 https://pan.baidu.com/s/1JJyVcP2KqXsd5G6eaYpgHQ 提取碼 3fzt (壓縮包名: 2020-3-20-demo.zip) 2 圖片展示 3 主要代碼
1 /** HandCreate 簡單的 圖形界面 搭建幾何體 2 constructor: 3 params: 4 prototype: 5 method: 6 */ 7 class HandCreate{ 8 9 constructor(func, view, three){ 10 this.func = func; 11 this.view = view; 12 this.three = three; 13 this.size = 1; 14 this.color = "#DCDCDC"; 15 this.target = {}; 16 this.isOldAddMesh = false; 17 this.lockTarget = false; 18 this.exportGLTFFileType = false; 19 20 this.group = new THREE.Group(); 21 this.three.scene.add(this.group); 22 this.group.name = "Group_HandCreate"; 23 24 this.raycaster = { 25 raycaster:new THREE.Raycaster(), 26 vector2:new THREE.Vector2(), 27 childrens:[], 28 result:[] 29 } 30 this.raycaster.raycaster.far = 100; 31 32 this.materials = this.initMaterials(); 33 this.geometrys = this.initGeometrys(); 34 this.lands(); 35 this.controls(); 36 this.initGui(); 37 } 38 39 initMaterials(){ 40 let color = new THREE.Color(this.color); 41 return new Map([ 42 [0, new THREE.MeshBasicMaterial({color:color})], 43 [1, new THREE.MeshLambertMaterial({color:color})], 44 [2, new THREE.MeshStandardMaterial({color:color})] 45 ]); 46 } 47 48 initGeometrys(){ 49 50 var geometrys = new Map([ 51 [0, new THREE.BoxGeometry(this.size, this.size, this.size, 1, 1, 1)], 52 [1, new THREE.SphereGeometry(this.size/2, 8, 6, 0, Math.PI * 2, 0, Math.PI)], 53 ]); 54 55 for(let k = 0; k < geometrys.size; k++){ 56 this.createShowMesh(k, new THREE.Mesh(geometrys.get(k), this.materials.get(0))); 57 } 58 59 return geometrys; 60 61 } 62 63 initGui(){ 64 var k, len, upd = ()=>{this.update();} 65 var exportGltf = { 66 exAll:()=>{console.log("導出所有物體")}, 67 extar:()=>{this.exporterGLTF(this.target.mesh, this.exportGLTFFileType);}, 68 ft:false 69 } 70 71 new this.view.Gui({setMode:"translate"}, {setMode:[["平移", "translate"], ["旋轉", "rotate"], ["縮放", "scale"]]}, "控制模式") 72 .change((v)=>{this.transformControl.setMode(v);}).title("控制器") 73 74 .create(this, ["isOldAddMesh", "lockTarget"]) 75 .name({isOldAddMesh:"是否共用材質", lockTarget:"是否鎖定目標"}) 76 .title("其它").change(upd) 77 78 .create(exportGltf, {ft:[[".gltf", false], [".glb", true]]}, "導出物體") 79 .name({exAll:"所有物體", extar:"目標物體", ft:"文件類型"}) 80 .change("ft", (v)=>{this.exportGLTFFileType = v;}) 81 82 } 83 84 addTarget(mesh){//當前目標物體 85 if(this.target.mesh === mesh || this.lockTarget === true) return; 86 this.removeTarget(mesh); 87 this.transformControl.attach(mesh); 88 this.target.gui = this.addTargetGui(mesh); 89 this.target.mesh = mesh; 90 this.update(); 91 } 92 93 removeTarget(mesh){//移除當前目標物體 94 this.transformControl.detach(mesh); 95 if(this.target.gui){this.target.gui.remove(this.target.gui);} 96 for(let k in this.target){delete(this.target[k]);} 97 } 98 99 lands(){//地面 100 var geometry = new THREE.PlaneBufferGeometry(this.three.sceneSize, this.three.sceneSize); 101 geometry.rotateX( - Math.PI / 2 ); 102 var mesh = new THREE.Mesh( 103 geometry, 104 new THREE.MeshLambertMaterial({color:0x00ff00, visible:false}) 105 ); 106 mesh.receiveShadow = true; 107 mesh.matrixAutoUpdate = false; 108 this.gridHelper = new THREE.GridHelper(this.three.sceneSize, this.three.sceneSize/this.size);//每1米為一格 109 this.add(this.gridHelper, false); 110 this.add(mesh, false); 111 } 112 113 controls(){//控制項 114 //平移控制項 115 var tc = new THREE.TransformControls(this.three.camera, this.three.renderer.domElement); 116 tc.addEventListener( 'dragging-changed', (e)=>{this.three.control.enabled = !e.value;}); 117 tc.addEventListener('change', ()=>{this.update();}); 118 tc.addEventListener('mouseDown', ()=>{}); 119 tc.addEventListener('mouseUp', ()=>{}); 120 tc.addEventListener('objectChange', ()=>{}); 121 this.transformControl = tc; 122 this.three.scene.add(tc); 123 124 //拖放控制項 125 var dc = new THREE.DragControls(this.raycaster.childrens, this.three.camera, this.three.renderer.domElement); 126 dc.addEventListener('hoveron', (e)=>{this.addTarget(e.object);}); 127 dc.addEventListener('hoveroff', ()=>{this.update();}); 128 dc.enabled = false; 129 this.dragcontrols = dc; 130 131 //軌道控制項 132 this.three.control.addEventListener("change", ()=>{this.update()}); 133 //this.three.control.addEventListener( 'start', ()=>{}); 134 //this.three.control.addEventListener( 'end', ()=>{}); 135 } 136 137 add(mesh, isChildrens){//添加 138 if(!mesh){return;} 139 this.group.add(mesh); 140 if(isChildrens !== false){this.raycaster.childrens.push(mesh);} 141 this.update(); 142 return mesh; 143 } 144 145 remove(mesh, group){//移除物體 146 if(!mesh){return;} 147 let arr = group || this.group, k = this.raycaster.childrens.indexOf(mesh); 148 if(k !== -1){this.raycaster.childrens.splice(k, 1);} 149 mesh.material.dispose(); 150 mesh.geometry.dispose(); 151 arr.remove(mesh); 152 } 153 154 addMesh(gkey, mkey, isChildrens){//添加物體 155 let g = gkey || 0, m = mkey || 0, mesh; 156 if(this.isOldAddMesh === true){ 157 mesh = new THREE.Mesh(this.geometrys.get(g), this.materials.get(m)); 158 }else{ 159 mesh = new THREE.Mesh(this.geometrys.get(g), this.materials.get(m).clone()); 160 } 161 return this.add(mesh, isChildrens); 162 } 163 164 addWireframe(geometry){//添加網格輔助線 165 var wireframe = new THREE.WireframeGeometry(geometry); 166 var line = new THREE.LineSegments(wireframe); 167 line.material.depthTest = false; 168 line.material.opacity = 0.25; 169 line.material.transparent = true; 170 return line; 171 } 172 173 createShowMesh(elemId, mesh){//物體選項 174 if(!mesh){return;} 175 if(!this.minSceneDom){ 176 this.minSceneDom = this.view.add(document.body, "div", null, "ShowMesh box-scroll-block"); 177 this.view.addEvent(this.minSceneDom, 'mousedown', (e)=>{ 178 let key = parseInt(e.target.id); 179 if(typeof(key) !== "number" || isNaN(key) === true){return;} 180 this.addTarget(this.addMesh(key, 0)); 181 }); 182 } 183 var scene = new THREE.Scene(); 184 scene.background = new THREE.Color("black"); 185 var camera = new THREE.PerspectiveCamera(45, 100/100, 0.1, 10); 186 camera.position.set(0, 1, 2); 187 camera.lookAt(0, 0, 0); 188 var renderer = new THREE.WebGLRenderer({antialias : true}); 189 renderer.setSize(100, 100); 190 renderer.domElement.id = elemId + "_ShowMeshId"; 191 this.minSceneDom.appendChild(renderer.domElement); 192 scene.add(camera, mesh); 193 mesh.material.wireframe = true; 194 mesh.matrixAutoUpdate = false; 195 this.update(scene, camera, renderer); 196 } 197 198 update(scene, camera, renderer){//更新場景 199 this.three.render(scene, camera, renderer); 200 } 201 202 updateGeometry(mesh, geometry){ 203 mesh.geometry.dispose(); 204 mesh.geometry = geometry; 205 } 206 207 //光線投射 208 runRaycaster(x, y, recursive){ 209 var c = this.raycaster; 210 c.result.length = 0; 211 c.vector2.set((x / this.view.client.w) * 2 - 1, -(y / this.view.client.h) * 2 + 1); 212 c.raycaster.setFromCamera(c.vector2, this.three.camera); 213 c.raycaster.intersectObjects(c.childrens, recursive, c.result); 214 //console.log(c.result[0]); 215 } 216 217 //布爾運算 type = intersect 交集、重合的部分 union 並集、組合、相加 subtract 差集、相減 218 getBSP(meshA, meshB, type){ 219 if(!meshA || !meshB || !type){return;} 220 var bsp_a = new ThreeBSP(meshA);//生成ThreeBSP對象 221 var bsp_b = new ThreeBSP(meshB);//生成ThreeBSP對象 222 var bsp = bsp_a[type](bsp_b);//進行 type 計算 223 var mesh = bsp.toMesh();//轉換為mesh模型 224 mesh.geometry.computeFaceNormals();//更新模型的面 225 mesh.geometry.computeVertexNormals();//更新模型的頂點 226 mesh.geometry = new THREE.BufferGeometry().fromGeometry(mesh.geometry);//轉換為 buff緩衝幾何體 227 mesh.material = meshA.material;//重賦值紋理 228 return mesh; 229 } 230 231 //導入物體 .gltf || .glb 232 loadingGLTF(url){ 233 if(!this.loadGLTF){this.loadGLTF = new THREE.GLTFLoader();} 234 this.loadGLTF.load(url, (gltf)=>{ 235 //let model = gltf.scene; 236 this.add(gltf.scene); 237 //modlAnimate(model, gltf.animations) 238 }); 239 } 240 241 //導出物體(限谷歌瀏覽器) 242 exporterGLTF(mesh, fileType){ 243 if(!this.exportGLTF){this.exportGLTF = new THREE.GLTFExporter();} 244 if(!mesh){console.log("mesh 錯誤"); return;} 245 //if(mesh.geometry.isGeometry === true){mesh.geometry = new THREE.BufferGeometry().fromGeometry(mesh.geometry);} 246 var opt = {binary: fileType || false}; 247 var download = ( blob, filename )=>{ 248 let link = this.view.add(document.body, "a"); 249 link.style.display = 'none'; 250 link.href = URL.createObjectURL( blob ); console.log(link.href); 251 link.download = filename; 252 link.click(); 253 this.view.remove(link); 254 } 255 256 this.exportGLTF.parse(mesh, function ( result ){ 257 if(result instanceof ArrayBuffer){ 258 download(new Blob([result], {type: 'application/octet-stream'}), 'scene.glb'); 259 }else{ 260 download(new Blob([JSON.stringify( result, null, 2 )], {type: 'text/plain'}), 'scene.gltf'); 261 } 262 }, opt); 263 } 264 265 //添加目標gui視圖 266 addTargetGui(mesh){ 267 268 var g_rc, pi2 = Math.PI * 2, g_s = mesh.geometry.parameters, upd = ()=>{this.update();}; 269 270 var gui = new this.view.Gui(mesh.material, ["wireframe", "visible"], "修改材質-"+mesh.material.type) 271 .name({wireframe:"顯示網格", visible:"顯示物體"}).change(upd) 272 .add({color:"#"+mesh.material.color.getHexString()}) 273 .change((e)=>{mesh.material.color.set(e.target.value); upd();}) 274 275 switch(mesh.geometry.type){ 276 277 case "BoxGeometry" : 278 g_rc = { 279 width:[0.1, 10, 0.1], 280 height:[0.1, 10, 0.1], 281 depth:[0.1, 10, 0.1], 282 widthSegments:[1, 30, 1], 283 heightSegments:[1, 30, 1], 284 depthSegments:[1, 30, 1] 285 } 286 gui.create(g_s, g_rc, "修改幾何體-"+mesh.geometry.type) 287 .change(()=>{ 288 this.updateGeometry( 289 mesh, 290 new THREE.BoxGeometry(g_s.width, g_s.height, g_s.depth, g_s.widthSegments, g_s.heightSegments, g_s.depthSegments) 291 ); 292 upd(); 293 }) 294 295 break; 296 297 case "SphereGeometry" : 298 g_rc = { 299 radius:[0.5, 10, 0.1], 300 widthSegments:[1, 30, 1], 301 heightSegments:[1, 30, 1], 302 phiStart:[0, pi2, 0.1], 303 phiLength:[0, pi2, 0.1], 304 thetaStart:[0, pi2, 0.1], 305 thetaLength:[0, pi2, 0.1] 306 } 307 gui.create(g_s, g_rc, "修改幾何體-"+mesh.geometry.type) 308 .change(()=>{ 309 this.updateGeometry( 310 mesh, 311 new THREE.SphereGeometry(g_s.radius, g_s.widthSegments, g_s.heightSegments, g_s.phiStart, g_s.phiLength, g_s.thetaStart, g_s.thetaLength) 312 ); 313 upd(); 314 }) 315 316 break; 317 318 default : break; 319 } 320 321 return gui; 322 323 } 324 325 }
1 /** HandCreate 簡單的 圖形界面 搭建幾何體 2 constructor: 3 params: 4 prototype: 5 method: 6 */ 7 class HandCreate{ 8 9 constructor(func, view, three){ 10 this.func = func; 11 this.view = view; 12 this.three = three; 13 this.size = 1; 14 this.color = 0xDCDCDC; 15 this.target = {}; 16 this.isOldAddMesh = true; 17 18 this.group = new THREE.Group(); 19 this.three.scene.add(this.group); 20 this.group.name = "Group_HandCreate"; 21 22 this.raycaster = { 23 raycaster:new THREE.Raycaster(), 24 vector2:new THREE.Vector2(), 25 childrens:[], 26 result:[] 27 } 28 this.raycaster.raycaster.far = 100; 29 30 this.materials = this.initMaterials(); 31 this.geometrys = this.initGeometrys(); 32 this.lands(); 33 this.controls(); 34 this.initGui(); 35 } 36 37 initMaterials(){ 38 return new Map([ 39 [0, new THREE.MeshBasicMaterial({color:this.color})], 40 [1, new THREE.MeshLambertMaterial({color:this.color})], 41 [2, new THREE.MeshStandardMaterial({color:this.color})] 42 ]); 43 } 44 45 initGeometrys(){ 46 47 var geometrys = new Map([ 48 [0, new THREE.BoxGeometry(this.size, this.size, this.size, 1, 1, 1)], 49 [1, new THREE.SphereGeometry(this.size/2, 8, 6, 0, Math.PI * 2, 0, Math.PI)], 50 ]); 51 52 for(let k = 0; k < geometrys.size; k++){ 53 this.createShowMesh(k, new THREE.Mesh(geometrys.get(k), this.materials.get(0))); 54 } 55 56 return geometrys; 57 58 } 59 60 initGui(){ 61 var g_c = ()=>{this.update();} 62 new this.view.Gui( 63 { 64 translate:()=>{this.transformControl.setMode("translate")}, 65 rotate:()=>{this.transformControl.setMode("rotate")}, 66 scale:()=>{this.transformControl.setMode("scale")} 67 }, 68 "控制類型(平移,旋轉,縮放)" 69 ) 70 .create(this, "isOldAddMesh", "是否添加共用物體").change(g_c) 71 } 72 73 addTarget(mesh){//當前物體 74 if(this.target.mesh === mesh) return; 75 76 this.removeTarget(mesh); 77 this.transformControl.attach(mesh); 78 79 var upd = ()=>{this.update();} 80 81 this.target.gui = new this.view.Gui(mesh.material, "wireframe", "修改材質-"+mesh.material.type).change(upd); 82 83 let g_rc, g_s = mesh.geometry.parameters; //克隆的物體沒有 parameters 屬性 84 switch(mesh.geometry.type){ 85 case "BoxGeometry" : 86 //g_s = {g_s.width, g_s.height, g_s.depth, g_s.widthSegments, g_s.heightSegments, g_s.depthSegments} 87 g_rc = {width:[0.1, 10, 0.1], height:[0.1, 10, 0.1], depth:[0.1, 10, 0.1], widthSegments:[1, 30, 1], heightSegments:[1, 30, 1], depthSegments:[1, 30, 1]} 88 this.target.gui.create(g_s, g_rc, "修改幾何體-"+mesh.geometry.type) 89 .change(()=>{ 90 this.updateGeometry(mesh, new THREE.BoxGeometry(g_s.width, g_s.height, g_s.depth, g_s.widthSegments, g_s.heightSegments, g_s.depthSegments)); 91 upd(); 92 }) 93 94 break; 95 96 case "SphereGeometry" : 97 let pi2 = Math.PI * 2; 98 g_rc = {radius:[0.5, 10, 0.1], widthSegments:[1, 30, 1], heightSegments:[1, 30, 1], phiStart:[0, pi2, 0.1], phiLength:[0, pi2, 0.1], thetaStart:[0, pi2, 0.1], thetaLength:[0, pi2, 0.1]} 99 this.target.gui.create(g_s, g_rc, "修改幾何體-"+mesh.geometry.type) 100 .change(()=>{ 101 this.updateGeometry(mesh, new THREE.SphereGeometry(g_s.radius, g_s.widthSegments, g_s.heightSegments, g_s.phiStart, g_s.phiLength, g_s.thetaStart, g_s.thetaLength)); 102 upd(); 103 }) 104 break; 105 106 default : break; 107 } 108 109 this.target.mesh = mesh; 110 } 111 112 removeTarget(mesh){//移除當前物體 113 this.transformControl.detach(mesh); 114 if(this.target.gui){this.target.gui.remove(this.target.gui);} 115 for(let k in this.target){delete(this.target[k]);} 116 } 117 118 lands(){//地面 119 var geometry = new THREE.PlaneBufferGeometry(this.three.sceneSize, this.three.sceneSize); 120 geometry.rotateX( - Math.PI / 2 ); 121 var mesh = new THREE.Mesh( 122 geometry, 123 new THREE.MeshLambertMaterial({color:0x00ff00, visible:false}) 124 ); 125 mesh.receiveShadow = true; 126 mesh.matrixAutoUpdate = false; 127 this.gridHelper = new THREE.GridHelper(this.three.sceneSize, this.three.sceneSize/this.size);//每1米為一格 128 this.add(this.gridHelper, false); 129 this.add(mesh, false); 130 } 131 132 controls(){//控制項 133