本文原创 如转载请注明出处!!!

本博客地址http://www.cnblogs.com/we-jack

本文原创,如果有同样需求的小伙伴请第一时间联系我 或者在留言区留言

上次为大家提供了3D模型的展示之后 发现网上有很多想要计算3D模型表面积和体积的需求 那么经过掉了几百根头发的艰辛历程之后 终于为大家解决了这一需求 按照惯例先上图为证

当然我这样写 有的人认为我在忽悠 你说你的体积 表面积是这就是这啊 没有可验证性么

那好~ 没有对比就没有伤害 下面是某3D打印网站上传同样模型后给出的数据 各位看官们看好了

实打实的讲道理 他给出的体积还是负值 我都给转正了[:斜眼笑]

好了 闲话少絮 直接给大家上代码 (JS代码如果有需要的直接留言找我)

 <head>
<meta charset="UTF-8" />
<title>WebGL</title>
<script type="text/javascript" charset="utf-8" src="js/three.js"></script>
<script src="js/STLLoader.js"></script>
<script src="js/TrackballControls.js"></script>
<script src="js/AsciiEffect.js"></script>
<style>body{overflow:hidden;background:#eee}</style>
</head>

先引入我们几个必须的JS (之前有人问OBJ模型怎么上传 这个问题可以直接百度three.js的使用方法)

接下来用JS定义一个画布

     var WIDTH,HEIGHT;
var renderer;

定义好了之后 我们初始化一下我们的three

 function initThree() {
WIDTH = document.documentElement.clientWidth/2;<!--{foreach from=$recommended_goods item=rgoods}--> <!-- {/foreach} -->
HEIGHT = document.documentElement.clientHeight/2;
/* 渲染器 */
renderer = new THREE.WebGLRenderer();
renderer.setSize(WIDTH , HEIGHT);
renderer.setClearColor(new THREE.Color(0x66666)); renderer.gammaInput = true;
renderer.gammaOutput = true; document.body.appendChild(renderer.domElement);
}

下来是摄像头定义

 /* 摄像头 */
var camera;
function initCamera() {
var VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 0.1,
FAR = 10000;
camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
camera.position.set(20, 0, 0);
//设置视野的中心坐标
camera.lookAt(scene.position);
}

场景植入

 /* 场景 */
var scene;
function initScene() {
scene = new THREE.Scene();
}

灯光定义

 /* 灯光 */
var light,light2,light3;
function initLight() {
//平行光
light = new THREE.DirectionalLight(0xFFFFFF);
light.position.set(0, 99, 0).normalize();
scene.add(light);
//环境光
light2 = new THREE.AmbientLight(0x999999);
scene.add(light2);
//点光源
light3 = new THREE.PointLight(0x00FF00);
light3.position.set(300, 0, 0);
scene.add(light3);
}

动画定义

 function animate() {
requestAnimationFrame( animate );
controls.update();
effect.render( scene, camera );
}

调用所有方法开始执行

 function threeStart() {
initThree();
initScene();
initCamera();
initLight();
initObject();
initControl();
animate();
}

显示对象

/* 显示对象 */
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; 求得体积

在计算表面积的时候出现了一点问题 如果模型出现在网格下面那么就会出现负值 但是数字的值是没有问题的 所以我们可以去将组合重新排序从而使负值转正 当然也可以使用绝对值的方法使数值转正

最后声明 如需转载请注明出处!!!

本文原创,如果有同样需求的小伙伴请第一时间联系我 或者在留言区留言

3D模型展示以及体积、表面积计算的更多相关文章

  1. three.js实现3D模型展示

    由于项目需要展示3d模型,所以对three做了点研究,分享出来 希望能帮到大家 先看看效果: three.js整体来说 不是很难 只要你静下心来研究研究 很快就会上手的 首先我们在页面上需要创建一个能 ...

  2. 基于playcanvas的3d模型展示

    1.使用基于playcanvas的离线编辑器制作模型效果 2.使用基于playcanvas的开发包读取编辑好的3d模型进行在线3d展示 效果如下:

  3. ANDROID嵌入式应用Unity3D视图(画廊3D模型)

    转载请注明来自大型玉米的博客文章(http://blog.csdn.net/a396901990),谢谢支持! 效果展示:   watermark/2/text/aHR0cDovL2Jsb2cuY3N ...

  4. 在SAP UI中使用纯JavaScript显示产品主数据的3D模型视图

    在Jerry写这篇文章时,通过Google才知道,SAP其实是有自己的3D模型视图显示解决方案的. 故事要从Right Hemisphere说起,这是一家专业的企业级2D/3D模型浏览及转换的软件供应 ...

  5. 基于 webGL 的元素周期表 3D 交互展示

    前言 之前在网上看到别人写的有关元素周期表的文章,深深的勾起了一波回忆,记忆里初中时期背的“氢氦锂铍硼,碳氮氧氟氖,钠镁铝硅磷,硫氯氩钾钙”.“养(氧)龟(硅)铝铁盖(钙),哪(钠)家(钾)没(镁)青 ...

  6. 扒几个 3D 模型备用

    前言 在上一篇中,我展示了 OpenGL 开发的基本过程,算是向 3D 世界迈出的一小步吧.对于简单的 3D 物体,比如立方体.球体.圆环等等,我们只需要简单的计算就可以得到他们的顶点的坐标.但是仅仅 ...

  7. Mask裁切UI粒子特效或者3D模型

    刚好前几天有人问我这个问题,再加上新项目也可能用,所以这两天就研究了一下.其实如果粒子特效 和3D模型 都用RenderTexture来做的话就不会有裁切的问题,但是粒子特效用RenderTextur ...

  8. 如何让NGUI的对象在3D模型之上

    假设场景中有两台摄像机, 一台是NGUI的摄像机, 另外一台是投影摄像机. 投影摄像机看的是3D模型, Depth比NGUI的摄像机要大, Clear Flags设置的是Depth only. 现在想 ...

  9. 【Android界面实现】可旋转的汽车3D模型效果的实现

    转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 今天要给大家介绍的是怎样实现可旋转的汽车3D模型. 先看实现效果 这仅仅是静态图,实际上,这个模型是能够依据 ...

随机推荐

  1. 在Centos环境下安装兼容Apache2.4高版本SVN服务

    在阿里云Centos环境下,搭建PHP运行环境,PHP选择了php7版本,Mysql选择了5.7版本,Apache选择了2.4版本,在搭建SVN版本控制服务过程中出现了不兼容问题,当前环境下Apach ...

  2. UVALive - 4329 Ping pong 树状数组

    这题不是一眼题,值得做. 思路: 假设第个选手作为裁判,定义表示在裁判左边的中的能力值小于他的人数,表示裁判右边的中的能力值小于他的人数,那么可以组织场比赛. 那么现在考虑如何求得和数组.根据的定义知 ...

  3. NJU 1010 Air

    思路:把那张图打表(吐血...),然后就按照规则输出就行. AC代码 #include <cstdio> #include <cmath> #include <cctyp ...

  4. mysql打不开表问题解决方案

    做开发时候某一表怎么也打不开,数据也不多,网上查了按下面这篇文章完美解决,但是要记得用root登录mysql: 记一次MySQL中Waiting for table metadata lock的解决方 ...

  5. Winform中TextBox控件开启自动提示补全功能

    问题:Winform开发中,有一个TextBox控件用以输入姓名,现希望在输入名字时能够自动提示所有可能的名字. 解答:winform中的TextBox控件含有如下三个属性:   ① AutoComp ...

  6. linux系统 initrd.img中init启动脚本分析

    概述:这篇文章主体内容来源于网上转载.前面几篇文章倾向于制作initrd.img,这篇文章更倾向于initrd.img的运行过程:加载framebuff驱动 ide驱动和文件系统驱动,最后进入到真正的 ...

  7. python︱Anaconda安装、简介(安装报错问题解决、Jupyter Notebook)

    每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 安装完anaconda,就相当于安装了Pyth ...

  8. 错误:readline/readline.h:没有那个文件或目录解决方法

    curl -R -O http://www.lua.org/ftp/lua-5.3.0.tar.gz tar zxf lua-5.3.0.tar.gz cd lua-5.3.0 make linux ...

  9. Nginx学习笔记3--Nginx和PHP(fastCGI)的配置和优化

    php和nginx的配置 server{ root html; listen 80; server_name a.com; index index.php index.html ; location ...

  10. Linux显示内存统计最大和最小的详情

    Linux显示内存统计最大和最小的详情 youhaidong@youhaidong-ThinkPad-Edge-E545:~$ free -l total used free shared buffe ...