`
xhload3d
  • 浏览: 205820 次
社区版块
存档分类
最新评论

基于HTML5 Canvas的CSG构造实体几何书架

阅读更多

CSG 构造实体几何这个概念在工业水利水电施工上、游戏上已经有很多人使用了,最简单的实体表示叫作体元,通常是形状简单的物体,如立方体、圆柱体、棱柱、棱锥、球体、圆锥等。根据每个软件包的不同这些体元也有所不同,在一些软件包中可以使用弯曲的物体进行 CSG 处理,在另外一些软件包中则不支持这些功能。构造物体就是将体元根据集合论的布尔逻辑组合在一起,这些运算包括:并集、交集以及补集。我们一般可以用 CSG 来将简单的模型合在一起生成复杂的模型,这样在构造模型的时候会省很多力。

HT 中的 ht.CSGNode 图元类型就是参考 CSG 封装的一个函数,ht.CSGNode 继承于 ht.Node,当 style 的 shape3d 属性为空时显示为六面体效果,CSGNode如果通过 setHost 吸附到 宿主 CSGNode 或 CSGShape 后,宿主 CSGNode 或 CSGShape 可与吸附的CSGNode图元进行CSG的组合建模。详情请参考 HT for Web 建模手册 CSGNode 章节。这里我用 CSG 的概念写了一个例子,让大家能更好地理解这个概念。

本例 Demo 地址: http://hightopo.com/guide/guide/plugin/modeling/examples/example_bookshelf.html

先来看下效果图:

从上面效果图可以看到,我们将界面分为三个部分,这三个部分先是右边部分上下分割,然后将整个界面左右分割,HT 用封装好的 ht.widget.SplitView 进行界面的分割,然后将分割组件添加进底层 div 中:

dm = new ht.DataModel();// 数据模型            
treeView = new ht.widget.TreeView(dm); //树组件                                                                                                 
gv1 = new ht.graph3d.Graph3dView(dm); //3D 组件  
gv2 = new ht.graph3d.Graph3dView(dm);
splitView = new ht.widget.SplitView(gv1, gv2, 'v', 0.6);//分割组件 
mainSplit = new ht.widget.SplitView(treeView, splitView, 'h', 0.27);   
                
view = mainSplit.getView();  
view.className = 'main';
document.body.appendChild(view);    
window.addEventListener('resize', function (e) {
    mainSplit.invalidate();
}, false); 

 

上面代码是一种非常常见的在 HTML 中添加 HT 组件的方法,详情可参考 HT for Web 入门手册组件章节。这种方法进行添加 HT 组件有一个需要注意的点,因为 HT 一般都以设置 position 为 absolute 的绝对定位方式,必须设置 left、right、top、bottom 等等基础 css 样式,像这样:

.main {
     margin: 0px;
     padding: 0px;
     position: absolute;
     top: 0px;
     bottom: 0px;
     left: 0px;
     right: 0px;
}

所以为了最外层组件加载填充满窗口的方便性,HT 的所有组件都有 addToDOM 函数,其思想逻辑如下,其中 iv 是 invalidate 的缩写:

addToDOM = function(){   
    var self = this,
    view = self.getView(),   
    style = view.style;
    document.body.appendChild(view);            
    style.left = '0';
    style.right = '0';
    style.top = '0';
    style.bottom = '0';      
    window.addEventListener('resize', function () { self.iv(); }, false);            
}  

以后我们在代码中就可以直接调用 addToDOM 函数,而不用写一大堆代码了,上面代码用 addToDOM 取代之后的代码如下,而且不用描绘 css 样式: 

dm = new ht.DataModel();// 数据模型             
treeView = new ht.widget.TreeView(dm); //树组件                                                             
gv1 = new ht.graph3d.Graph3dView(dm); //3D 组件  
gv2 = new ht.graph3d.Graph3dView(dm);
splitView = new ht.widget.SplitView(gv1, gv2, 'v', 0.6);//分割组件 
mainSplit = new ht.widget.SplitView(treeView, splitView, 'h', 0.27);   
mainSplit.addToDOM();

界面分配好之后我们就要对其添加内容了,界面的左边部分是 HT 封装的树组件,我在之前的文章写到过,树组件是一个非常方便的绘制树形关系的组件,开发人员能够轻松地从数据模型 DataModel 中获取数据和节点之间的关系放到树上,只需要在树组件声明的过程中,将对应的数据模型 DataModel 放进树组件的参数即可,当然我们还扩展了很多跟树组件有关的函数,非常方便实用,这里我们只用了 expandAll 函数,将所有对象展开:

treeView = new ht.widget.TreeView(dm); //树组件   
treeView.expandAll();

 

右边部分上下分为两部分,都是 3D 场景,就是设置显示有点不同,其他完全相同,上面的 3D 场景重载了 getVisibleFunc 函数,如果元素的 showMe 属性为 true,则可视;如果节点为 ht.CSGNode 类型并且节点的 getHost 函数的参数为空,则不可视;其他情况均可视:

gv1.setVisibleFunc(function(data){
    if(data.showMe){
        return true;
    }
    if(data instanceof ht.CSGNode && data.getHost()){
        return false;
    }
    return true;
});

 

我们先向 3D 场景中添加元素对象,我们先解释中间的书架,对两边的书架有缺的再进行补充。首先我们添加了一个 ht.CSGNode 节点 shelf,作为书架的主节点,其他的节点都是依附于这个节点的,对这个节点设置了位置、大小、名称以及六个面的颜色,然后添加进数据模型 DataModel: 

var shelf = new ht.CSGNode();
shelf.s3(500, 400, 120);
shelf.p3(0, 200, 0);
shelf.setName('shelf1');
shelf.s({
    'all.color': '#E5BB77'
});
dm.add(shelf);

接着向这个 shelf 中添加 10 个节点,做书架的格子效果,并设置依附关系和父子关系添加进数据模型中:

for(var i=0; i<2; i++){
    for(var j=0; j<5; j++){
        var clipNode = new ht.CSGNode();
        clipNode.setHost(shelf);
        clipNode.s3(80, 100, 120);
        clipNode.p3(-200+j*100, 340-i*120, 20);
        clipNode.setName('substract-'+i+'-'+j);
        clipNode.s('batch', 'tt');
        clipNode.setParent(shelf);
        dm.add(clipNode);
    }
}

 

为了让书架变得更美观一点,我们在书架的上下左右都加上了 ht.CSGNode,最后为了更加具象化,我们还添加了一本书,实现方式也差不多,都非常简单:

var book = new ht.Node();
book.setName('CSS3: The Missing Manual');
book.s3(60, 80, 8);
book.p3(-100, 210, 20);
book.r3(-Math.PI/6, Math.PI/5, 0);
book.setIcon('book');
book.s({
    'front.image': 'book',
    'back.color': 'white',
    'left.color': 'white',
    'all.color': 'gray'
});
book.setHost(shelf);
book.setParent(shelf);
dm.add(book);      

接着左边的书架也是类似的构建方法,有一点不同的是,这边有一个 ht.CSGBox 类型,继承于 ht.CSGNode,其除具备父类 CSGNode 的挖空等功能外,还可对六个面进行旋转展开关闭的操作,这里我们的节点只设置了前面的能够旋转展开,并且设置了一系列的样式:

clipNode = new ht.CSGBox();
clipNode.setName('CSGBox-Expand-Left');
clipNode.s3(100, 100, 120);
clipNode.p3(0, 65, 0.1);
clipNode.setHost(shelf);
clipNode.showMe = true;
clipNode.s({
    'all.visible': false,//6面均不可见
    'front.visible': true,//前面可见
    'front.toggleable': true,//允许前面双击展开                    
    'front.reverse.flip': true,//前面的反面显示正面的内容
    'front.transparent': true,//前面透明
    'front.end': Math.PI * 0.7,//前面展开状态的结束旋转弧度
    'front.color': 'rgba(0, 50, 50, 0.7)'//前面颜色
});

可能你们还想知道下面的地球是怎么做到的?还记得之前的文章写到过 HT 中设置了 shape3d 属性,设置这个属性实际上就是在操作 setShape3dModel(name, model) 和 getShape3dModel(name),可以通过这个属性设置为 box|sphere|cylinder|cone|torus|star|rect|roundRect|triangle|rightTriangle|parallelogram|trapezoid 等等模型,这些模型也都是 HT 封装好的,要使用时直接设置 shape3d 为其中的一个值即可,如这个例子中用到 “shape3d: sphere” 就是设置为球体。我们简单地用一张地图图片包裹在这个球体的外侧,当然,这张地图图片是先通过 ht.Default.setImage 注册过的,然后通过 shape3d.image 将图片附到这个节点上:

earth = new ht.Node();
earth.setName('earth');
earth.s3(70, 70, 70);
earth.p3(0, 50, 0);
earth.s({
    'shape3d': 'sphere',
    'shape3d.image': 'earth'
});
earth.setHost(shelf);  
earth.setParent(shelf);
dm.add(earth);

 

右边的书架,同样也是有一个主节点,其他节点依附于它,但是我们看到这边换了一个新的节点类型 ht.DoorWindow,ht.DoorWindow继承于 ht.CSGNode,其除具备父类 CSGNode 的挖空等功能外,还可进行整体的旋转展开关闭的操作, 常用于作为门或窗的业务对象,吸附于 CSGNode 或 CSGShape 的 host 作为墙面的图元。这个节点类型就是 ht.CSGNode 的延展,相对来说就是区分了实际应用而添加了不同的 style 参数,更多的属性请到 HT for Web 建模手册 DoorWindow 章节 查看然后添加到节点中玩玩:

photos = new ht.DoorWindow();
photos.setName('DoorWindow-Photos');
photos.setIcon('ben12');
photos.s3(110, 100, 130);
photos.p3(5, 180, 0);                
photos.setHost(shelf);  
photos.showMe = true;
photos.s({                    
    'bottom.uv': [1,1, 1,0, 0,0, 0,1],
    'bottom.uv.scale': [1, 1],
    'left.uv.scale': [3, 3],
    'top.uv.scale': [2, 2],
    'dw.s3': [0.8, 0.9, 0.05],
    'dw.t3': [0, -5, 0],
    'dw.axis': 'v',
    'dw.toggleable': false,
    'front.image': 'ben1',
    'back.image': 'ben2',
    'all.color': '#F8CE8B'
});
photos.setParent(shelf);
dm.add(photos);

最后,我们将左侧的地球 earth 和右侧的照片 photo 旋转起来:

var angle = 0;
setInterval(function(){
    angle += Math.PI/40;
    earth.r3(0, angle, 0);
    photos.s('dw.angle', angle);
}, 50);

我们看到,其实虽然 HT 封装了很多不同的 CSG 节点类型,但是实际应用都差不多,而且内容也没有差特别多,差别都是在 style 参数上,但是真的在实际开发中,这种区分就会很大程度上加快开发速度,毕竟名称一目了然,就知道要运用哪些 style 属性了。

 

 

 

 

 

分享到:
评论

相关推荐

    html5 canvas绘制几何图形动画特效

    HTML5 Canvas是一个基于矢量图形的画布,通过JavaScript进行编程操作。它提供了`&lt;canvas&gt;`标签,该标签在页面上创建一个矩形区域,然后可以通过JavaScript的Canvas API在这个区域内绘制各种图形。 2. **绘图上下文...

    canvas拼图游戏,基于html + canvas画布实现

    canvas拼图游戏,基于html + canvas画布实现

    基于HTML5 canvas实现图片马赛克特效

    至此,我们就实现了基于HTML5 canvas的图片马赛克特效。用户可以通过修改`blockSize`变量来调整马赛克的模糊程度,以达到不同的视觉效果。这个特效适用于创建动态的、个性化的H5页面,尤其在隐私保护或艺术设计中...

    基于html2canvas生成带二维码的活动海报

    本项目"基于html2canvas生成带二维码的活动海报"提供了一个纯前端解决方案,使得开发者无需后端支持也能快速实现此类功能。html2canvas是一个JavaScript库,它能够将网页的DOM(文档对象模型)渲染为图片,从而解决...

    html5 canvas几何模型3D运动动画效果

    在这个“html5 canvas几何模型3D运动动画效果”项目中,我们将探讨如何利用HTML5 Canvas API构建一个引人入胜的3D模型动画。 1. **Canvas API基础** HTML5 Canvas是一个基于矢量图形的画布,通过JavaScript进行...

    一个基于 html5 canvas 的流程图demo..zip

    这个"一个基于html5 canvas的流程图demo.zip"文件很可能包含了一个使用HTML5 Canvas技术实现的流程图示例项目。下面将详细探讨HTML5 Canvas以及其在多媒体和游戏开发中的应用。 HTML5 Canvas是一个基于矢量图形的...

    html5 canvas绘制线条组合几何体动画特效

    在这个“html5 canvas绘制线条组合几何体动画特效”中,我们将会探讨如何利用Canvas API来创建2D彩色线条花环几何体的变换动画。 首先,要创建任何Canvas元素,你需要在HTML中添加一个`&lt;canvas&gt;`标签,并为其设置id...

    基于html2canvas将当前页面保存为图片Demo

    在"基于html2canvas将当前页面保存为图片Demo"的项目中,你将找到html2canvas的插件脚本和一个简单的示例Demo。这个Demo可以帮助开发者快速理解和使用html2canvas。下面我们将详细讨论这个知识点: 1. **...

    基于html5 canvas实现聚宝盆接金币游戏特效源码.zip

    在这个“基于html5 canvas实现聚宝盆接金币游戏特效源码.zip”中,我们可以看到HTML5的Canvas元素被巧妙地用于构建一个有趣的接金币游戏。 Canvas是HTML5中的一个画布元素,它允许开发者通过JavaScript来绘制2D图形...

    基于HTML5 Canvas和jQuery 的画图工具的实现

    在博文《基于HTML5 Canvas和jQuery 的画图工具的实现》中,作者可能详细介绍了如何结合使用这两个技术来构建一个简单的画图应用。这可能包括以下步骤: 1. **初始化Canvas**:在HTML中创建一个`&lt;canvas&gt;`元素,并...

    基于html5 canvas实现的动态文字特效代码

    在这个“基于html5 canvas实现的动态文字特效代码”项目中,我们将探讨如何利用Canvas API来创建引人注目的文字动画效果。 Canvas API提供了一系列方法,如`fillText()`和`strokeText()`,用于在画布上绘制文本,而...

    HTML5 Canvas核心技术源码技术代码

    HTML5 Canvas核心技术源码技术代码、图形、动画与游戏开发。 Canvas开发、入门学习Canvas技术代码。 HTML5 Canvas核心技术源码技术代码、图形、动画与游戏开发。 Canvas开发、入门学习Canvas技术代码。 HTML5 Canvas...

    html5在线编辑器基于canvas实现

    基于Canvas实现的HTML5编辑器,更进一步地利用了HTML5的Canvas元素,这是一种用于在网页上绘制图形的JavaScript API。Canvas提供了一种动态、灵活的方式来创建和修改图像,使其成为构建富媒体应用和复杂交互式编辑...

    html5绘图工具 基于 HTML5 的 Canvas 技术,拓扑图是电力

    基于 HTML5 的 Canvas 技术,我们可以开发出专门用于绘制拓扑图的工具。这些工具通常包含一系列的绘图组件,如线条、形状、文字等,帮助用户轻松构建和编辑拓扑结构。例如,JTopo 就是一个流行的选择,它是一个开源...

    html5 canvas实现的小游戏

    通过以上这些技术,我们可以构建出一个基于HTML5 Canvas的简单小游戏。这不仅涉及到前端开发的基本技能,还需要对游戏设计和用户体验有深入的理解。不断实践和迭代,你将能够创作出更加复杂和有趣的游戏。

    基于HTML5 Canvas和Rebound动画的Loading加载动画特效

    在本项目中,"基于HTML5 Canvas和Rebound动画的Loading加载动画特效"利用了Canvas的强大功能,为用户展示了一种创新且吸引人的加载指示器。 首先,Canvas是一个基于矢量图形的API,它通过JavaScript代码控制,可以...

    基于HTML5 canvas的简单抽奖轮盘

    在这个基于HTML5 Canvas的简单抽奖轮盘项目中,我们可以通过Canvas API来实现动态的视觉效果,例如旋转和动画,为用户提供一种交互式的抽奖体验。 首先,`index.html`是项目的主页面,它将包含HTML结构,包括canvas...

    基于html5 canvas实现的飘动的爱心心形动画特效

    标签“动画”提示我们关注的是动态效果,而“canvas”和“html5”则强调了这个效果是基于Web技术实现的。这样的动画效果不仅美观,而且具有良好的跨平台性,可以在支持HTML5的现代浏览器中运行。 在实际项目中,...

    Zebkit基于HTML5Canvas的UI框架

    **Zebkit:基于HTML5 Canvas的UI框架** Zebkit 是一个强大的JavaScript库,它专为构建富交互式用户界面而设计。该框架利用HTML5的Canvas元素,提供了高效且可定制的UI组件,使得开发者能够创建出极具视觉吸引力的...

Global site tag (gtag.js) - Google Analytics