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

标签: ht csg 功能 | 发表时间:2014-12-25 01:45 | 作者:
出处:http://www.iteye.com

构造实体几何 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);
				  
}   

 



已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [ht csg 功能] 推荐:

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

- - ITeye博客
构造实体几何 CSG全称 Constructive solid geometry,是3D计算机图形学中构建模型的常用技术,可通过合并Union、相减Subtraction和相交Intersction的三种取集的逻辑运算,将立方体、圆柱体和棱柱等简单的基础模型,嵌套组合成更复杂三维模型. 回到我们今天要搞的3D书架例子,我们将基于 HT for Web的3D引擎来实现, HT已经内置了CSG功能的模型封装,我们通过构建CSGNode图元对象,该类型图元可对Host吸附的图元进行CSG技术的合集、并集和补集的三种操作,一般运用中裁剪的方式较为常用,因此CSGNode默认对Host图元的操作就是裁剪.

HT实验室:Any.Do 极致简约而强大

- - Tech2IPO
[HT观点] 简单并不意味着欠缺或者低劣,也不意味着不注重装饰或者完全赤裸裸. 而是说装饰应该紧密贴近设计本身,任何无关的要素都应予以剔除. 本期评测:安卓版Any.Do . 简约是Any.Do最大的特点,无论是界面设计,还是功能流程,没有一丝多余的设计. Any.Do简约却并不简单,功能设计的实现效果非常好,操作简单易用,功能实用.

HT for Web自定义3D模型的WebGL应用

- - CSDN博客推荐文章
上图是采用 HT提供的 createRingModel函数,通过编辑2D的多边形生成对应的环状的3D模型,对于花瓶碗杯等环形对称的物体很适合采用该函数构建. 除了 createRingModel外,HT的建模手册中的custommodel自定义模型例子,还采用了createExtrusionModel等更多的自定义模型API构建了一个餐桌椅和墙面的场景,其效果如下:.

基于HT for Web的Web SCADA工控移动应用

- - ITeye博客
最近客户采用 HT for Web图形界面组件,实现了油田燃气管网和供水管网等工控SCADA的HMI人机界面,并将系统运行在平板和手机等Android和iOS移动终端,在此我们在技术支持过程中的一些知识点进行些梳理和分享,希望对有志于Web SCADA领域的伙伴们提供些帮助. 移动终端呈现方面,HMI界面布局应用和游戏领域有类似的问题,一般对横版或者竖版会有更好的布局效果,例如有些游戏只支持横版的玩法,这对于采用Native的App应用来说不成问题,可将App配置成只能横向或者纵向布局,但对于移动终端浏览器就有点尴尬,目前大部分终端你是不能限制用户旋转平面导致布局变化.

BTrace功能

- - zzm
       在生产环境中可能经常遇到各种问题,定位问题需要获取程序运行时的数据信息,如方法参数、返回值、全局变量、堆栈信息等. 为了获取这些数据信息,我们可以 通过改写代码,增加日志信息的打印,再发布到生产环境. 通过这种方式,一方面将增大定位问题的成本和周期,对于紧急问题无法做到及时响应;另一方面重新部 署后环境可能已被破坏,很难重新问题的场景.

DTU 功能 - wilcolin

- - 博客园_首页
      DTU (Data Transfer unit)全称数据传输单元,是专门用于将串口数据转换为IP数据或将IP数据转换为串口数据通过无线通信网络进行传送的无线终端设备.       Winer WCTU 3121主要是运用于物联网通信行业的一种无线数据传输终端,是厦门为那通信科技有限公司自主开发的DTU系列产品之一,WCTU 3121是一款2G GPRS DTU产品,通过利用中国移动、中国联通的GPRS 2G网络为用户提供无线长距离的数据传输功能.

Android核心功能

- - 技术改变世界 创新驱动中国 - 《程序员》官网
Android功能模块的概况,就像看Android的“个人简历”一样,帮助我们对它的能力有整体上的认识,进而在应用开发之前可以更好地评估技术上的可能性和风险性. 每个Android开发者都会关心Android到底能够打造怎样的用户界面(User Interface,UI). Android界面框架中最有特色的部分是资源(Resource)和布局(Layout)体系,通过完善的控件库和简明的接口设计,开发者可以尽快搭建自己需要的界面.

Redis的AOF功能

- - CSDN博客数据库推荐文章
引言:  Redis是基于内存的数据库,同时也提供了若干持久化的方案,允许用户把内存中的数据,写入本地文件系统,以备下次重启或者当机之后继续使用. 本文将描述如何基于Redis来设置AOF功能. AOF是AppendOnly File的缩写,是Redis系统提供了一种记录Redis操作的持久化方案,在AOF生成的文件中,将忠实记录发生在Redis的操作,从而达到在Redis服务器重启或者当机之后,继续恢复之前数据状态的机制.

Phaser功能简述

- - 深入一点,你会更加快乐
    在JAVA 1.7引入了一个新的并发API:Phaser,一个可重用的同步barrier. 在此前,JAVA已经有CyclicBarrier、CountDownLatch这两种同步barrier,但是Phaser更加灵活,而且侧重于“重用”.     1、注册机制:与其他barrier不同的是,Phaser中的“注册的同步者(parties)”会随时间而变化,Phaser可以通过构造器初始化parties个数,也可以在Phaser运行期间随时加入(register)新的parties,以及在运行期间注销(deregister)parties.

专注核心功能

- 小宇 - 互联网的那点事...
当我还小的时候,出了什么毛病都爱用风油精. 无论是虫叮蚊咬,晕车晕船还是感冒发烧,风油精都能派上用场. 因此当我颇为自豪的向我的小伙伴炫耀道“风油精什么都能治”的时候,他的一句“风油精什么都能治,什么都治不好”着实给我泼了一头冷水. 随着我逐渐长大,我遇到了更多“万能”的产品:能刮胡子能双卡双待能遥控电视的手机、能祛痘美白淡斑保湿去黑头的面膜、能交友能婚恋能看视频能做3D特效的网站等等.