热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

基于HT的CSG功能构建HTML5的3D书架

构造实体几何CSG全称Constructivesolidgeometry,是3D计算机图形学中构建模型的常用技术,可通过合并Union、相减Subtraction和相交Intersction的三种

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

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

Screen Shot 2014-12-25 at 12.19.17 AM

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

上图的例子效果可看出我们构建了一个DataModel数据模型,该模型绑定了一个TreeView树组件和两个Graph3dView的三维组件,上部分的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的操作效果,玻璃门开关以及相册效果都是直接利用HT for Web的3D引擎提供的模型,通过设置透明度、相片贴图和旋转动画等呢只功能参数即可。

以下是该HT for Web的3D例子的所有Javascript代码供参考:http://v.youku.com/v_show/id_XODU2MTQ4NjI4.html

ht.Default.setImage('ben12', {
width: 100,
height: 50,
comps: [
{
type: 'image',
name: 'ben1',
rect: [0, 0, 50, 50]
},
{
type: 'image',
name: 'ben2',
rect: [50, 0, 50, 50]
}
]
});

function init(){
dm = new ht.DataModel();
treeView = new ht.widget.TreeView(dm);
gv1 = new ht.graph3d.Graph3dView(dm);
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);

gv1.setMoveStep(30);
gv1.setGridVisible(true);
gv1.setEye(0, 100, 1000);
gv1.setCenter(0, 200, 0);
gv1.pan(0, 100, true);
gv1.getLabel = function(){
return null;
};
gv1.getBrightness = function(data){
return null;
};
gv1.setVisibleFunc(function(data){
if(data.showMe){
return true;
}
if(data instanceof ht.CSGNode && data.getHost()){
return false;
}
return true;
});

gv2.setMoveStep(30);
gv2.setEditable(true);
gv2.setGridVisible(true);
gv2.setEditable(true);
gv2.pan(0, 200, true);
gv2.getLabel = function(){
return null;
};

initShelf1();
initShelf2();
initShelf3();

treeView.expandAll();

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

function initShelf1(){
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);

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);
}
}

var leftNode = new ht.CSGNode();
leftNode.setHost(shelf);
leftNode.s3(23, 380, 100);
leftNode.p3(-255, 200, 0);
leftNode.setName('substract left');
leftNode.setParent(shelf);
dm.add(leftNode);

var rightNode = new ht.CSGNode();
rightNode.setHost(shelf);
rightNode.s3(23, 380, 100);
rightNode.p3(255, 200, 0);
rightNode.setName('substract right');
rightNode.setParent(shelf);
dm.add(rightNode);

var bottomNode = new ht.CSGNode();
bottomNode.setHost(shelf);
bottomNode.s3(480, 140, 140);
bottomNode.p3(0, 80, 0);
bottomNode.setName('substract bottom');
bottomNode.setParent(shelf);
dm.add(bottomNode);

var topNode = new ht.CSGNode();
topNode.setHost(shelf);
topNode.s3(480, 10, 100);
topNode.p3(0, 400, 0);
topNode.setName('union top');
topNode.s('attach.operation', 'union');
topNode.setParent(shelf);
dm.add(topNode);

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);

}

function initShelf2(){
var shelf = new ht.CSGNode();
shelf.s3(120, 240, 120);
shelf.p3(0, 120, 0);
shelf.setName('shelf2');
shelf.s({
'all.color': '#805642',
'csg.color': 'yellow',
'csg.reverse.flip': true
});
dm.add(shelf);

var clipNode = new ht.CSGNode();
clipNode.setName('shelf2-substract-up');
clipNode.s3(100, 100, 130);
clipNode.p3(0, 180, 0);
clipNode.setHost(shelf);
clipNode.s('attach.cull', true);
clipNode.setParent(shelf);
dm.add(clipNode);

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,
'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)'
});
clipNode.setParent(shelf);
clipNode.setFaceExpanded('front', true, true);
dm.add(clipNode);

earth = new ht.Node();
earth.setName('earth');
earth.setIcon('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);

shelf.t3(-360, 0, 50);
shelf.r3(0, Math.PI/7, 0);
}

function initShelf3(){
var shelf = new ht.CSGNode();
shelf.s3(120, 240, 120);
shelf.p3(0, 120, 0);
shelf.setName('shelf3');
shelf.setIcon('ben');
shelf.s({
'all.image': 'brick',
'all.uv.scale': [2, 4],
'top.uv.scale': [2, 2],
'bottom.uv.scale': [2, 2],
'csg.image': 'ben',
'csg.blend': 'yellow'
});
dm.add(shelf);

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);

var clipNode = new ht.CSGBox();
clipNode.setName('CSGBox-Expand-Top');
clipNode.s3(100, 100, 120);
clipNode.p3(0, 65, 0.1);
clipNode.setHost(shelf);
clipNode.showMe = true;
clipNode.s({
'all.visible': false,
'front.visible': true,
'front.color': 'red',
'front.transparent': true,
'front.opacity': 0.7,
'front.reverse.flip': true,
'front.toggleable': true,
'front.axis': 'top',
'front.end': Math.PI * 0.4
});
clipNode.setParent(shelf);
clipNode.setFaceExpanded('front', true, true);
dm.add(clipNode);

shelf.t3(360, 0, 50);
shelf.r3(0, -Math.PI/7, 0);

}



推荐阅读
  • 本文介绍了pack布局管理器在Perl/Tk中的使用方法及注意事项。通过调用pack()方法,可以控制部件在显示窗口中的位置和大小。同时,本文还提到了在使用pack布局管理器时,应注意将部件分组以便在水平和垂直方向上进行堆放。此外,还介绍了使用Frame部件或Toplevel部件来组织部件在窗口内的方法。最后,本文强调了在使用pack布局管理器时,应避免在中间切换到grid布局管理器,以免造成混乱。 ... [详细]
  • 如何优化Webpack打包后的代码分割
    本文介绍了如何通过优化Webpack的代码分割来减小打包后的文件大小。主要包括拆分业务逻辑代码和引入第三方包的代码、配置Webpack插件、异步代码的处理、代码分割重命名、配置vendors和cacheGroups等方面的内容。通过合理配置和优化,可以有效减小打包后的文件大小,提高应用的加载速度。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 本文介绍了PhysioNet网站提供的生理信号处理工具箱WFDB Toolbox for Matlab的安装和使用方法。通过下载并添加到Matlab路径中或直接在Matlab中输入相关内容,即可完成安装。该工具箱提供了一系列函数,可以方便地处理生理信号数据。详细的安装和使用方法可以参考本文内容。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • ASP.NET2.0数据教程之十四:使用FormView的模板
    本文介绍了在ASP.NET 2.0中使用FormView控件来实现自定义的显示外观,与GridView和DetailsView不同,FormView使用模板来呈现,可以实现不规则的外观呈现。同时还介绍了TemplateField的用法和FormView与DetailsView的区别。 ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • JavaScript和HTML之间的交互是经由过程事宜完成的。事宜:文档或浏览器窗口中发作的一些特定的交互霎时。能够运用侦听器(或处置惩罚递次来预订事宜),以便事宜发作时实行相应的 ... [详细]
  • 带添加按钮的GridView,item的删除事件
    先上图片效果;gridView无数据时显示添加按钮,有数据时,第一格显示添加按钮,后面显示数据:布局文件:addr_manage.xml<?xmlve ... [详细]
  • 本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ... [详细]
  • {moduleinfo:{card_count:[{count_phone:1,count:1}],search_count:[{count_phone:4 ... [详细]
  • python+selenium十:基于原生selenium的二次封装fromseleniumimportwebdriverfromselenium.webdriv ... [详细]
  • 第一步:PyQt4Designer设计程序界面该部分设计类同VisvalStudio内的设计,改下各部件的objectName!设计 ... [详细]
author-avatar
天使哥特式
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有