3D模型展示以及體積、錶面積計算

来源:https://www.cnblogs.com/we-jack/archive/2018/03/20/8608623.html
-Advertisement-
Play Games

本文原創 如轉載請註明出處!!! 本博客地址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; 求得體積

在計算錶面積的時候出現了一點問題 如果模型出現在網格下麵那麼就會出現負值 但是數字的值是沒有問題的 所以我們可以去將組合重新排序從而使負值轉正 當然也可以使用絕對值的方法使數值轉正

最後聲明 如需轉載請註明出處!!!

本文原創,如果有同樣需求的小伙伴請第一時間聯繫我 或者在留言區留言 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 多行溢出 僅作為記錄方便查找 ...
  • 1、看下代碼,在函數中無論在哪裡聲明變數,都會自動提到函數頂部,這就是函數變數提升,它的作用於為當前函數中。 瀏覽器解析時 所以不用關心bool是否為true or false。實際上,無論如何test都會被創建聲明。 2、當使用let 和 const 時它們的作用域為{} let的作用域是在它所在 ...
  • <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width"> <title>css畫圓</title> <style> #test { width:30 ...
  • DOM操作:創建元素、查找元素、添加新元素、替換、移除、複製、移動 ...
  • <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scal ...
  • 一、script引入(聯繫使用,小型項目) 直接下載並用 <script> 標簽引入,Vue 會被註冊為一個全局變數。 <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script> 二、Vue 提供一個官方命令 ...
  • $("body").on("click", ".submit_btn", function() { if (!$("#tel").val()) { alert("手機號不能為空"); $(this).attr("disabled", true); $(this).css({ background: ...
  • 最近閱讀《高性能JavaScript》時,在書中的“達夫設備“ 。 對此,有些感悟,同時有些疑問,希望看到的朋友,能幫忙解釋下,在此先提前感謝了。 1. 先說自己的理解吧: ”達夫設備“的目的是減少迭代次數,提高迴圈的效率,減少時間,提升性能。 感受:感覺代碼的優化,真的需要用工匠精神來雕琢,代碼的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...