本文原創 如轉載請註明出處!!! 本博客地址http://www.cnblogs.com/we-jack 本文原創,如果有同樣需求的小伙伴請第一時間聯繫我 或者在留言區留言 上次為大家提供了3D模型的展示之後 發現網上有很多想要計算3D模型錶面積和體積的需求 那麼經過掉了幾百根頭髮的艱辛歷程之後 終 ...
本文原創 如轉載請註明出處!!!
本博客地址http://www.cnblogs.com/we-jack
本文原創,如果有同樣需求的小伙伴請第一時間聯繫我 或者在留言區留言
上次為大家提供了3D模型的展示之後 發現網上有很多想要計算3D模型錶面積和體積的需求 那麼經過掉了幾百根頭髮的艱辛歷程之後 終於為大家解決了這一需求 按照慣例先上圖為證
當然我這樣寫 有的人認為我在忽悠 你說你的體積 錶面積是這就是這啊 沒有可驗證性麽
那好~ 沒有對比就沒有傷害 下麵是某3D列印網站上傳同樣模型後給出的數據 各位看官們看好了
實打實的講道理 他給出的體積還是負值 我都給轉正了[:斜眼笑]
好了 閑話少絮 直接給大家上代碼 (JS代碼如果有需要的直接留言找我)
1 <head> 2 <meta charset="UTF-8" /> 3 <title>WebGL</title> 4 <script type="text/javascript" charset="utf-8" src="js/three.js"></script> 5 <script src="js/STLLoader.js"></script> 6 <script src="js/TrackballControls.js"></script> 7 <script src="js/AsciiEffect.js"></script> 8 <style>body{overflow:hidden;background:#eee}</style> 9 </head>
先引入我們幾個必須的JS (之前有人問OBJ模型怎麼上傳 這個問題可以直接百度three.js的使用方法)
接下來用JS定義一個畫布
1 var WIDTH,HEIGHT; 2 var renderer;
定義好了之後 我們初始化一下我們的three
1 function initThree() { 2 WIDTH = document.documentElement.clientWidth/2;<!--{foreach from=$recommended_goods item=rgoods}--> <!-- {/foreach} --> 3 HEIGHT = document.documentElement.clientHeight/2; 4 /* 渲染器 */ 5 renderer = new THREE.WebGLRenderer(); 6 renderer.setSize(WIDTH , HEIGHT); 7 renderer.setClearColor(new THREE.Color(0x66666)); 8 9 renderer.gammaInput = true; 10 renderer.gammaOutput = true; 11 12 document.body.appendChild(renderer.domElement); 13 }
下來是攝像頭定義
1 /* 攝像頭 */ 2 var camera; 3 function initCamera() { 4 var VIEW_ANGLE = 45, 5 ASPECT = WIDTH / HEIGHT, 6 NEAR = 0.1, 7 FAR = 10000; 8 camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR); 9 camera.position.set(20, 0, 0); 10 //設置視野的中心坐標 11 camera.lookAt(scene.position); 12 }
場景植入
1 /* 場景 */ 2 var scene; 3 function initScene() { 4 scene = new THREE.Scene(); 5 }
燈光定義
1 /* 燈光 */ 2 var light,light2,light3; 3 function initLight() { 4 //平行光 5 light = new THREE.DirectionalLight(0xFFFFFF); 6 light.position.set(0, 99, 0).normalize(); 7 scene.add(light); 8 //環境光 9 light2 = new THREE.AmbientLight(0x999999); 10 scene.add(light2); 11 //點光源 12 light3 = new THREE.PointLight(0x00FF00); 13 light3.position.set(300, 0, 0); 14 scene.add(light3); 15 }
動畫定義
1 function animate() { 2 requestAnimationFrame( animate ); 3 controls.update(); 4 effect.render( scene, camera ); 5 }
調用所有方法開始執行
1 function threeStart() { 2 initThree(); 3 initScene(); 4 initCamera(); 5 initLight(); 6 initObject(); 7 initControl(); 8 animate(); 9 }
顯示對象
/* 顯示對象 */ var cube; function initObject(){ // ASCII file var loader = new THREE.STLLoader(); loader.addEventListener( 'load', function ( event ) { var loading = document.getElementById("Loading"); loading.parentNode.removeChild(loading); var geometry = event.content; var Area = 0.0; var volumes = 0.0; for(var i = 0; i < geometry.faces.length; i++){ var Pi = geometry.faces[i].a; var Qi = geometry.faces[i].b; var Ri = geometry.faces[i].c; var P = new THREE.Vector3(geometry.vertices[Pi].x, geometry.vertices[Pi].y, geometry.vertices[Pi].z); var Q = new THREE.Vector3(geometry.vertices[Qi].x, geometry.vertices[Qi].y, geometry.vertices[Qi].z); var R = new THREE.Vector3(geometry.vertices[Ri].x, geometry.vertices[Ri].y, geometry.vertices[Ri].z); // volumes += volumeOfT(P, Q, R); 會產生負數.............. volumes += volumeOfT(R, Q, P); Area += AreaOfTriangle(R, Q, P); } SurfaceArea = (Area / 100).toFixed(2); console.log('錶面積:'+SurfaceArea); loadedObjectVolume = (volumes / 1000).toFixed(2); console.log('體積:'+loadedObjectVolume); //磚紅色 var material = new THREE.MeshPhongMaterial( { ambient: 0xff5533, color: 0xff5533, specular: 0x111111, shininess: 200 } ); //純黑色 // var material = new THREE.MeshBasicMaterial( { envMap: THREE.ImageUtils.loadTexture( 'http://localhost:8080/textures/metal.jpg', new THREE.SphericalReflectionMapping() ), overdraw: true } ) ; //粉色 帶陰影 // var material = new THREE.MeshLambertMaterial( { color:0xff5533, side: THREE.DoubleSide } ); //灰色 // var material = new THREE.MeshLambertMaterial({color: 000000}); //材質設定 (顏色) var mesh = new THREE.Mesh( geometry, material ); var center = THREE.GeometryUtils.center(geometry); var boundbox=geometry.boundingBox; var vector3 = boundbox.size(null); var vector3 = boundbox.size(null); console.log(vector3); var scale = vector3.length(); camera.position.set(scale, 0, 0); camera.lookAt(scene.position); scene.add(camera); //利用一個軸對象以可視化的3軸以簡單的方式。X軸是紅色的。Y軸是綠色的。Z軸是藍色的。這有助於理解在空間的所有三個軸的方向。要添加這個幫手,使用下麵的代碼: var axisHelper = new THREE.AxisHelper(800); scene.add(axisHelper); //周圍邊框 bboxHelper = new THREE.BoxHelper(); bboxHelper.visible = true; var meshMaterial = material; mainModel = new THREE.Mesh(geometry, meshMaterial); bboxHelper.update(mainModel); bboxHelper.geometry.computeBoundingBox(); scene.add(bboxHelper); //它吸引的特定對象3D對象(它看起來像金字塔)與線幾何,這有助於可視化什麼指定攝像機包含在它的視錐。 // var cameraParObj = new THREE.Object3D(); // cameraParObj.position.y = 200; // cameraParObj.position.z = 700; // scene.add(cameraParObj); // perspectiveCamera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 0.01, 1500); // cameraParObj.add(perspectiveCamera); // var cameraHelper = new THREE.CameraHelper(perspectiveCamera); // scene.add(cameraHelper); //地板網格 //var gridHelper = new THREE.GridHelper(500, 40); // 500 is grid size, 20 is grid step //gridHelper.position = new THREE.Vector3(0, 0, 0); //gridHelper.rotation = new THREE.Euler(0, 0, 0); //scene.add(gridHelper); //var gridHelper2 = gridHelper.clone(); //gridHelper2.rotation = new THREE.Euler(Math.PI / 2, 0, 0); //scene.add(gridHelper2); //var gridHelper3 = gridHelper.clone(); //gridHelper3.rotation = new THREE.Euler(Math.PI / 2, 0, Math.PI / 2); //scene.add(gridHelper3); //var grid = new THREE.GridHelper(300, 40, 25, [0, 0, 1], 0x000055, 0.2, true, "#FFFFFF", "left"); //scene.add(grid); mesh.position.set(0,0,0); // mesh.position.x = scene.position.x; // mesh.position.y = scene.position.y ; // mesh.position.z = scene.position.z; scene.add(mesh); renderer.clear(); renderer.render(scene, camera); } ); // loader.load( '3dfile/莫比烏斯環.STL' ); loader.load( '3dfile/狼人.STL' ); } //控制 var effect; var controls; function initControl(){ effect = new THREE.AsciiEffect( renderer ); effect.setSize( WIDTH, HEIGHT ); controls = new THREE.TrackballControls( camera,renderer.domElement); }
代碼上面的註釋都非常清楚了,根據這些我們很清楚的會看到在求體積的時候 我們必須先要得到一個四面體的有符號體積 - 基於你的三角形併在原點處排在最前面。音量的標誌來自您的三角形是否指向原點的方向。(三角形的法線本身取決於頂點的順序,這就是為什麼你在下麵看不到它的原因。)
這一點大家要是不懂的話 可以去搜索一下 一種計算任意非凸多面體積分性質的符號方法 這個方法詳細的講解了 多面體的體積演算法
在代碼的77行處我們可以看到 我在拿到多面體的每一個面之後進行了遍歷從而求出中心點到每個面的距離 再根據THREE提供的方法 得到三個有效點 然後將所有的點進行組合 使用 (-v321 + v231 + v312 - v132 - v213 + v123)/6.0; 求得體積
在計算錶面積的時候出現了一點問題 如果模型出現在網格下麵那麼就會出現負值 但是數字的值是沒有問題的 所以我們可以去將組合重新排序從而使負值轉正 當然也可以使用絕對值的方法使數值轉正
最後聲明 如需轉載請註明出處!!!
本文原創,如果有同樣需求的小伙伴請第一時間聯繫我 或者在留言區留言