日期:2014-05-16  浏览次数:20361 次

答复: JavaScript 图片3D展示空间(3DRoom)
cloudgamer 写道
一般的平面效果,通过改变水平和垂直坐标就能实现,再加上深度,就能在视觉上的产生3D(三维)的效果。
程序就是模拟这样一个三维空间,里面的图片会根据三维坐标显示在这个空间。
很久以前就看过一个3DRoom效果,是用复杂的计算实现的。
在上一篇图片变换研究过css3的transform之后,就想到一个更简单的方法来实现。





在线效果预览

完整实例下载


程序说明

【实现原理】

3D效果的关键,是深度的实现。
把3D容器看成一个由多个不同深度的层组成的空间,这些层的尺寸默认跟容器一样。
层里面放了该深度的图片,并且各个层会根据深度的变化做缩放变换,从视觉上产生深度差。
缩放变换的比例按照最近点为1,最远点为0,逐渐变化。
关键的地方是层里面图片的尺寸和坐标必须跟着层同时变换,这个通过css3的transform很简单就能实现。
这样图片只需设置好尺寸再相对层定好位就行了,避免了随深度变化要不断调整图片尺寸和定位的麻烦。


【图片加载】

在程序初始化之后,就可以调用add方法来添加图片。
add方法有两个参数:图片地址和参数对象,还会返回一个图片操作对象。
操作对象包含以下属性和方法,方便对图片进行操作:
img: 图片元素
src: 图片地址
options: 参数对象
show: 显示图片方法
remove: 移除图片方法
其中options可以设置如下属性:
属性:    默认值//说明
x: 0,//水平位移
y: 0,//垂直位移
z: 0,//深度
width: 0,//宽度
height: 0,//高度
scaleW: 1,//宽度缩放比例
scaleH: 1//高度缩放比例
其中x、y分别是水平和垂直坐标的位移参数,坐标原点在容器底部中间,水平坐标向右,纵坐标向上,单位是px。
而z是深度,用于比例的计算,方向由近点到原点。
坐标系如下图:


图片加载成功后,就会执行_load图片加载程序。
首先根据参数设置图片样式:
img.style.cssText = "position:absolute;border:0;padding:0;margin:0;-ms-interpolation-mode:nearest-neighbor;"
	+ "z-index:" + (99999 - z) + ";width:" + width + "px;height:" + height + "px;"
	+ "left:" + (((clientWidth - width) / 2 + opt.x) / clientWidth * 100).toFixed(5) + "%;"
	+ "top:" + ((clientHeight - height - opt.y) / clientHeight * 100).toFixed(5) + "%;";
绝对定位是必须的,宽度和高度根据参数设置就行。
left和top根据坐标参数计算,这里需要用百分比的形式表示,后面再详细说明。
还要给图片增加一个_z属性记录深度,方便调用。
最后插入对应z的层,并重新显示该层。


【层变换】

图片加载后,会用_insertLayer程序把图片插入到对应的层中。
_insertLayer有两个参数:图片元素和z深度。
程序用_layers对象,以z为关键字记录对应的层元素。
如果在该深度还没有创建层,会自动创建一个:
layer = document.createElement("div");
layer.style.cssText = "position:absolute;border:0;padding:0;margin:0;left:0;top:0;visibility:hidden;background:transparent;width:" + this._clientWidth + "px;height:" + this._clientHeight + "px;";
层的坐标和尺寸要跟容器一致,因为插入图片的坐标是相对容器来定义的,这样使用起来比较方便。
还会添加一个_count属性,记录层包含的图片数,最后插入到容器并记录到_layers对象中。
获取层对象后,就把图片插入层中,并把_count计数加1。

接着就可以通过_showLayer程序根据深度显示对应的层。
程序包含三个坐标属性:_x、_y、_z,表示容器的三维坐标的偏移量。
首先通过_getScale获取比例方法得到z深度的缩放比例scale。
比例大于1,说明图片在视觉深度的后面,理论上应该看不到,所以隐藏;小于0,就是小到看不到了也隐藏。

而_x和_y偏移量也需要根据深度来重新计算,程序有两种偏移方式:远点固定和近点固定。
远点固定的意思是平面位移偏移量随着深度逐渐变小,产生以最远点为固定点移动方向的效果,近点固定就刚好相反。
要实现这个效果,只要位移偏移量也跟着比例变化就行了,即远点固定时偏移量跟比例成正比,远点固定时是反比:
var moveScale = this.fixedFar ? scale : (1 - scale);


然后把这些参数交给_show程序来处理,并显示效果。

为了最大限度地利用层元素,程序会在_remove图片移除程序中,把没有图片的层放到_invalid废弃层集合中,在需要插入层时,优先从_invalid中获取。


【缩放比例】

上面已经说了,缩放比例应该按照最近点为1,最远点为0,逐渐变化。
程序默认是通过下面的公式计算:
function(z){ return 1 - z / 1000; }

但用这个公式实现3DRoom效果的时候,会发现比例变化太急速,并不像这个3DRoom那样平稳。

研究代码后发现,原来它用的公式是这样的:
this.r = FL / (FL + (z * Z));

其中FL和Z是一个常量来的,即公式可表示成:
function(z){ return 1/(1+z/常量); }

那按照这个公式,深度为0时比例为1,深度为常量时比例为0.5,深度为无穷大时比例为0。

变化效果可以参考这里的公式演示程序。
可以看出,缩放比例在默认公式是均匀变化的,而3DRoom公式是先快后慢,而且是逐渐变慢,所以有那种平稳的感觉。
那按照实际,还可以自己设计适合的公式,只要符合从1到0变化就行。


【css3模式】

程序中有三种缩放变换方式:css3、zoom和base,模式的程序结构跟上一篇图片变换类似。
缩放变换的目的是根据传递过来的比例和位置偏移量,把缩放效果显示出来,实现最终的3D效果。

css3模式使用的是css3的transform,在上一篇已经介绍过用transform的matr