Chinaunix首页 | 论坛 | 博客
  • 博客访问: 938393
  • 博文数量: 110
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1997
  • 用 户 组: 普通用户
  • 注册时间: 2013-12-15 22:39
个人简介

HT for Web 3D. HT for modern web and mobile app development. www.hightopo.com

文章分类

全部博文(110)

文章存档

2020年(1)

2018年(28)

2017年(21)

2016年(10)

2015年(28)

2014年(19)

2013年(3)

我的朋友

分类: HTML5

2014-12-25 01:54:37

构造实体几何全称,是3D计算机图形学中构建模型的常用技术,可通过合并Union、相减Subtraction和相交Intersction的三种取集的逻辑运算,将立方体、圆柱体和棱柱等简单的基础模型,嵌套组合成更复杂三维模型。

CSG的算法这些年来已有各种语言平台版本实现,C++版主流的是  已有众多基于该开源类库的应用案例,JavaScript语言较早版实现  影响较广,很多其他js衍生版都是基于该版本进行改进完善,包括Java版的实现  ,可参考基于JavaFX的3D打印IDE  ,提起JavaFX视乎这些年完全消失在程序员视野毫无声息,但还是有一群拥护者持续在使用着如今地位有点尴尬的JavaFX。

Screen Shot 2014-12-25 at 12.19.17 AM

回到我们今天要搞的3D书架例子,我们将基于的3D引擎来实现,已经内置了CSG功能的模型封装,我们通过构建CSGNode图元对象,该类型图元可对Host吸附的图元进行CSG技术的合集、并集和补集的三种操作,一般运用中裁剪的方式较为常用,因此CSGNode默认对Host图元的操作就是裁剪。

上图的例子效果可看出我们构建了一个数据模型,该模型绑定了一个树组件和两个的三维组件,上部分的Graph3dView组件添加了VisibleFunc的可见过滤器,隐藏了如下部分的Graph3dView中蓝色立方体图元,这些蓝色立方体图元就是CSGNode,其作用就是用来裁剪其吸附的书架Shelf对象,因此一般在3D编辑器状态下才需要出现,运行时科如上部分Graph3dView组件那样,通过添加可见过滤器将其隐藏,这样就实现了有凹槽可摆放书籍内容的3D书架效果,本例我们作为示例仅放了一本《CSS3  The Missing Manual》,这本书其实是由一个六面体,front面显示了书籍贴图,然后旋转一定角度进行摆放,btw《CSS3  The Missing Manual》第三版是本很不错的CSS书籍,强烈推荐!

Screen Shot 2014-12-25 at 12.22.57 AM

书架两边分别摆放了两个不同风格的小书台,通过上图我拖拽改变了蓝色CSGNode图元的位置,大家通过两张图的对比能更直观的体会到CSG的操作效果,玻璃门开关以及相册效果都是直接利用的3D引擎提供的模型,通过设置透明度、相片贴图和旋转动画等呢只功能参数即可。

以下是该的3D例子的所有JavaScript代码供参考:

点击(此处)折叠或打开

  1. ht.Default.setImage('ben12', {
  2.     width: 100,
  3.     height: 50,
  4.     comps: [
  5.         {
  6.             type: 'image',
  7.             name: 'ben1',
  8.             rect: [0, 0, 50, 50]
  9.         },
  10.         {
  11.             type: 'image',
  12.             name: 'ben2',
  13.             rect: [50, 0, 50, 50]
  14.         }
  15.     ]
  16. });
  17.             
  18. function init(){
  19.     dm = new ht.DataModel();
  20.     treeView = new ht.widget.TreeView(dm);
  21.     gv1 = new ht.graph3d.Graph3dView(dm);
  22.     gv2 = new ht.graph3d.Graph3dView(dm);
  23.     splitView = new ht.widget.SplitView(gv1, gv2, 'v', 0.6);
  24.     mainSplit = new ht.widget.SplitView(treeView, splitView, 'h', 0.27);
  25.     
  26.     view = mainSplit.getView();
  27.     view.className = 'main';
  28.     document.body.appendChild(view);
  29.     window.addEventListener('resize', function (e) {
  30.         mainSplit.invalidate();
  31.     }, false);
  32.   
  33.     gv1.setMoveStep(30);
  34.     gv1.setGridVisible(true);
  35.     gv1.setEye(0, 100, 1000);
  36.     gv1.setCenter(0, 200, 0);
  37.     gv1.pan(0, 100, true);
  38.     gv1.getLabel = function(){
  39.         return null;
  40.     };
  41.     gv1.getBrightness = function(data){
  42.         return null;
  43.     };
  44.     gv1.setVisibleFunc(function(data){
  45.         if(data.showMe){
  46.             return true;
  47.         }
  48.         if(data instanceof ht.CSGNode && data.getHost()){
  49.             return false;
  50.         }
  51.         return true;
  52.     });
  53.     
  54.     gv2.setMoveStep(30);
  55.     gv2.setEditable(true);
  56.     gv2.setGridVisible(true);
  57.     gv2.setEditable(true);
  58.     gv2.pan(0, 200, true);
  59.     gv2.getLabel = function(){
  60.         return null;
  61.     };
  62.     
  63.     initShelf1();
  64.     initShelf2();
  65.     initShelf3();
  66.     
  67.     treeView.expandAll();
  68.     
  69.     var angle = 0;
  70.     setInterval(function(){
  71.         angle += Math.PI/40;
  72.         earth.r3(0, angle, 0);
  73.         photos.s('dw.angle', angle);
  74.     }, 50);
  75. }

  76. function initShelf1(){
  77.     var shelf = new ht.CSGNode();
  78.     shelf.s3(500, 400, 120);
  79.     shelf.p3(0, 200, 0);
  80.     shelf.setName('shelf1');
  81.     shelf.s({
  82.         'all.color': '#E5BB77'
  83.     });
  84.     dm.add(shelf);
  85.     
  86.     for(var i=0; i<2; i++){
  87.         for(var j=0; j<5; j++){
  88.             var clipNode = new ht.CSGNode();
  89.             clipNode.setHost(shelf);
  90.             clipNode.s3(80, 100, 120);
  91.             clipNode.p3(-200+j*100, 340-i*120, 20);
  92.             clipNode.setName('substract-'+i+'-'+j);
  93.             clipNode.s('batch', 'tt');
  94.             clipNode.setParent(shelf);
  95.             dm.add(clipNode);
  96.         }
  97.     }
  98.     
  99.     var leftNode = new ht.CSGNode();
  100.     leftNode.setHost(shelf);
  101.     leftNode.s3(23, 380, 100);
  102.     leftNode.p3(-255, 200, 0);
  103.     leftNode.setName('substract left');
  104.     leftNode.setParent(shelf);
  105.     dm.add(leftNode);
  106.     
  107.     var rightNode = new ht.CSGNode();
  108.     rightNode.setHost(shelf);
  109.     rightNode.s3(23, 380, 100);
  110.     rightNode.p3(255, 200, 0);
  111.     rightNode.setName('substract right');
  112.     rightNode.setParent(shelf);
  113.     dm.add(rightNode);
  114.     
  115.     var bottomNode = new ht.CSGNode();
  116.     bottomNode.setHost(shelf);
  117.     bottomNode.s3(480, 140, 140);
  118.     bottomNode.p3(0, 80, 0);
  119.     bottomNode.setName('substract bottom');
  120.     bottomNode.setParent(shelf);
  121.     dm.add(bottomNode);
  122.     
  123.     var topNode = new ht.CSGNode();
  124.     topNode.setHost(shelf);
  125.     topNode.s3(480, 10, 100);
  126.     topNode.p3(0, 400, 0);
  127.     topNode.setName('union top');
  128.     topNode.s('attach.operation', 'union');
  129.     topNode.setParent(shelf);
  130.     dm.add(topNode);
  131.     
  132.     var book = new ht.Node();
  133.     book.setName('CSS3: The Missing Manual');
  134.     book.s3(60, 80, 8);
  135.     book.p3(-100, 210, 20);
  136.     book.r3(-Math.PI/6, Math.PI/5, 0);
  137.     book.setIcon('book');
  138.     book.s({
  139.         'front.image': 'book',
  140.         'back.color': 'white',
  141.         'left.color': 'white',
  142.         'all.color': 'gray'
  143.     });
  144.     book.setHost(shelf);
  145.     book.setParent(shelf);
  146.     dm.add(book);
  147.     
  148. }

  149. function initShelf2(){
  150.     var shelf = new ht.CSGNode();
  151.     shelf.s3(120, 240, 120);
  152.     shelf.p3(0, 120, 0);
  153.     shelf.setName('shelf2');
  154.     shelf.s({
  155.         'all.color': '#805642',
  156.         'csg.color': 'yellow',
  157.         'csg.reverse.flip': true
  158.     });
  159.     dm.add(shelf);
  160.     
  161.     var clipNode = new ht.CSGNode();
  162.     clipNode.setName('shelf2-substract-up');
  163.     clipNode.s3(100, 100, 130);
  164.     clipNode.p3(0, 180, 0);
  165.     clipNode.setHost(shelf);
  166.     clipNode.s('attach.cull', true);
  167.     clipNode.setParent(shelf);
  168.     dm.add(clipNode);
  169.     
  170.     clipNode = new ht.CSGBox();
  171.     clipNode.setName('CSGBox-Expand-Left');
  172.     clipNode.s3(100, 100, 120);
  173.     clipNode.p3(0, 65, 0.1);
  174.     clipNode.setHost(shelf);
  175.     clipNode.showMe = true;
  176.     clipNode.s({
  177.         'all.visible': false,
  178.         'front.visible': true,
  179.         'front.toggleable': true,
  180.         'front.reverse.flip': true,
  181.         'front.transparent': true,
  182.         'front.end': Math.PI * 0.7,
  183.         'front.color': 'rgba(0, 50, 50, 0.7)'
  184.     });
  185.     clipNode.setParent(shelf);
  186.     clipNode.setFaceExpanded('front', true, true);
  187.     dm.add(clipNode);
  188.     
  189.     earth = new ht.Node();
  190.     earth.setName('earth');
  191.     earth.setIcon('earth');
  192.     earth.s3(70, 70, 70);
  193.     earth.p3(0, 50, 0);
  194.     earth.s({
  195.         'shape3d': 'sphere',
  196.         'shape3d.image': 'earth'
  197.     });
  198.     earth.setHost(shelf);
  199.     earth.setParent(shelf);
  200.     dm.add(earth);
  201.     
  202.     shelf.t3(-360, 0, 50);
  203.     shelf.r3(0, Math.PI/7, 0);
  204. }

  205. function initShelf3(){
  206.     var shelf = new ht.CSGNode();
  207.     shelf.s3(120, 240, 120);
  208.     shelf.p3(0, 120, 0);
  209.     shelf.setName('shelf3');
  210.     shelf.setIcon('ben');
  211.     shelf.s({
  212.         'all.image': 'brick',
  213.         'all.uv.scale': [2, 4],
  214.         'top.uv.scale': [2, 2],
  215.         'bottom.uv.scale': [2, 2],
  216.         'csg.image': 'ben',
  217.         'csg.blend': 'yellow'
  218.     });
  219.     dm.add(shelf);
  220.     
  221.     photos = new ht.DoorWindow();
  222.     photos.setName('DoorWindow-Photos');
  223.     photos.setIcon('ben12');
  224.     photos.s3(110, 100, 130);
  225.     photos.p3(5, 180, 0);
  226.     photos.setHost(shelf);
  227.     photos.showMe = true;
  228.     photos.s({
  229.         'bottom.uv': [1,1, 1,0, 0,0, 0,1],
  230.         'bottom.uv.scale': [1, 1],
  231.         'left.uv.scale': [3, 3],
  232.         'top.uv.scale': [2, 2],
  233.         'dw.s3': [0.8, 0.9, 0.05],
  234.         'dw.t3': [0, -5, 0],
  235.         'dw.axis': 'v',
  236.         'dw.toggleable': false,
  237.         'front.image': 'ben1',
  238.         'back.image': 'ben2',
  239.         'all.color': '#F8CE8B'
  240.     });
  241.     photos.setParent(shelf);
  242.     dm.add(photos);
  243.     
  244.     var clipNode = new ht.CSGBox();
  245.     clipNode.setName('CSGBox-Expand-Top');
  246.     clipNode.s3(100, 100, 120);
  247.     clipNode.p3(0, 65, 0.1);
  248.     clipNode.setHost(shelf);
  249.     clipNode.showMe = true;
  250.     clipNode.s({
  251.         'all.visible': false,
  252.         'front.visible': true,
  253.         'front.color': 'red',
  254.         'front.transparent': true,
  255.         'front.opacity': 0.7,
  256.         'front.reverse.flip': true,
  257.         'front.toggleable': true,
  258.         'front.axis': 'top',
  259.         'front.end': Math.PI * 0.4
  260.     });
  261.     clipNode.setParent(shelf);
  262.     clipNode.setFaceExpanded('front', true, true);
  263.     dm.add(clipNode);
  264.                     
  265.     shelf.t3(360, 0, 50);
  266.     shelf.r3(0, -Math.PI/7, 0);
  267.                 
  268. }


阅读(2949) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~