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

本博客地址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. hdu1061(2015-N1):1.快速幂;2.找规律

    1.快速幂 原理:求a的b次方,将b转化为二进制数,该二进制位第i位的权是2^(i-1), 例如 11的二进制是1011 11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1 因此,我们将a¹ ...

  2. Java集合框架(一)—— Collection、Iterator和Foreach的用法

    1.Java集合概述 在编程中,常常需要集中存放多个数据.当然我们可以使用数组来保存多个对象.但数组长度不可变化,一旦在初始化时指定了数组长度,则这个数组长度是不可变的,如果需要保存个数变化的数据,数 ...

  3. HDU - 2102 A计划 (BFS) [kuangbin带你飞]专题二

    思路:接BFS判断能否在限制时间内到达公主的位置,注意如果骑士进入传送机就会被立即传送到另一层,不会能再向四周移动了,例如第一层的位置(x, y, 1)是传送机,第二层(x, y, 2)也是传送机,这 ...

  4. Hive分区和桶

    SMB 存在的目的主要是为了解决大表与大表间的 Join 问题,分桶其实就是把大表化成了“小表”,然后 Map-Side Join 解决之,这是典型的分而治之的思想.在聊 SMB Join 之前,我们 ...

  5. 思科ASA5520防火墙telnet、SSH及DHCP设置

    ASA5520远程登录telnet 注:最低安全级别的接口不支持telnet登陆,如OutsideASA(config)# telnet 172.16.0.0 255.255.0.0 inside   ...

  6. linux yum源配置及vim运用

    redhat7默认没有yum模板,需要自己创建[root@localhost ~]# mount /dev/cdrom /root/iso/(挂载镜像)mount: /dev/sr0 写保护,将以只读 ...

  7. R语言︱用excel VBA把xlsx批量转化为csv格式

    笔者寄语:批量读取目前看到有以下几种方法:xlsx包.RODBC包.批量转化成csv后读入.本章来自博客:http://www.cnblogs.com/weibaar/p/4506144.html 在 ...

  8. Linux显示所有输出域自动缩小到最短三数字单元和显示单元的打印

    Linux显示所有输出域自动缩小到最短三数字单元和显示单元的打印 youhaidong@youhaidong-ThinkPad-Edge-E545:~$ free -h total used free ...

  9. Hibernate【映射】知识要点

    前言 前面的我们使用的是一个表的操作,但我们实际的开发中不可能只使用一个表的...因此,本博文主要讲解关联映射 集合映射 需求分析:当用户购买商品,用户可能有多个地址. 数据库表 我们一般如下图一样设 ...

  10. Coursera DeepLearning.ai Logistic Regression逻辑回归总结

    既<Machine Learning>课程后,Andrew Ng又推出了新一系列的课程<DeepLearning.ai>,注册了一下可以试听7天.之后每个月要$49,想想还是有 ...