lufy's legend
标题: HTML5高级编程之图形扭曲及其应用 [打印本页]
作者: lufy 时间: 2013-2-25 22:56
标题: HTML5高级编程之图形扭曲及其应用
HTML5中的几种变形HTML5中的变形,共有以下几种方法
scale() 缩放
rotate() 旋转
translate() 平移
transform() 矩阵变形
setTransform() 重设矩阵
这几个方法,对图片一共能完成下面几种处理
但是,如果要实现下面这种不规则的变形,就不行了
那咱们一步步,先来看HTML5的这几个方法。
1,缩放方法如下
- <!DOCTYPE html>
- <html>
- <body>
- <canvas id="myCanvas" width="800" height="280"></canvas>
- <script type="text/javascript">
- var c=document.getElementById('myCanvas');
- var ctx=c.getContext('2d');
- var img = new Image();
- img.src="face.jpg";
- img.onload = function(){
- ctx.drawImage(img,0,0);
- ctx.scale(0.5,0.5);
- ctx.drawImage(img,500,0);
- };
- </script>
- </body>
- </html>
复制代码效果
2,旋转代码
- <!DOCTYPE html>
- <html>
- <body>
- <canvas id="myCanvas" width="800" height="400"></canvas>
- <script type="text/javascript">
- var c=document.getElementById('myCanvas');
- var ctx=c.getContext('2d');
- var img = new Image();
- img.src="face.jpg";
- img.onload = function(){
- ctx.rotate(20*Math.PI/180);
- ctx.drawImage(img,200,0);
- };
- </script>
- </body>
- </html>
复制代码
效果
3,平移代码- <!DOCTYPE html>
- <html>
- <body>
- <canvas id="myCanvas" width="800" height="400"></canvas>
- <script type="text/javascript">
- var c=document.getElementById('myCanvas');
- var ctx=c.getContext('2d');
- var img = new Image();
- img.src="face.jpg";
- img.onload = function(){
- ctx.drawImage(img,0,0);
- ctx.translate(100,100);
- ctx.drawImage(img,0,0);
- };
- </script>
- </body>
- </html>
复制代码效果
4,倾斜代码
- <!DOCTYPE html>
- <html>
- <body>
- <canvas id="myCanvas" width="800" height="400"></canvas>
- <script type="text/javascript">
- var c=document.getElementById('myCanvas');
- var ctx=c.getContext('2d');
- var img = new Image();
- img.src="face.jpg";
- img.onload = function(){
- ctx.setTransform(1.3,0.1,-0.2,1,80,40);
- ctx.drawImage(img,0,0);
- };
- </script>
- </body>
- </html>
复制代码效果
不规则变形前面提到,HTML5没办法直接实现不规则变形,但是,可以通过一系列组合来实现不规则变形,比如将下面的这个变形做一下分解
分解后变成
那继续看,它其实可以看做是两个变形的组合,如下图
其实就是将多个变形组合到了一起,这样讲几个变形的其中的一部分拿出来,再拼凑成新的图形,就变成了刚才的特殊图形了
顺着这个思路,我仿照AS3,将一张图分解成多个小的三角形,效果如下
就这样,很轻松的实现了drawtriangles函数,用来扭曲图形,它与AS3的drawtriangles函数功能基本一致,区别就是,第4个之后的参数的含义不同,在这里它第4个参数表示分割线的线粗,第5个参数则表示分割线的颜色,如果不设定,则不显示分割线,这个函数效果如下,你可以实现任何变形,甚至3D变形也可以
这面是测试连接,你可以拖动图中的红点,来让图片发生任意的扭曲变形
使用这个drawtriangles函数,你需要下载HTML5开源引擎lufylegend的1.5版或以上版本,lufylegend1.5版发布地址如下
下面来详细讲解一下drawtriangles函数的使用方法。并且使用drawtriangles函数实现下面这种处理效果
因为这个方法是从AS3移植而来,所以它的使用方法和AS3基本一致,这里是AS3的drawtriangles函数API,大家可以参照一下
上次也说明过,移植后的drawtriangles函数,第4个之后的参数的含义不同,在这里它第4个参数表示分割线的线粗,第5个参数则表示分割线的颜色,如果不设定,则不显示分割线
drawTriangles函数的定义
- drawTriangles(vertices, indices, uvtData,thickness,color)
- vertices:由数字构成的矢量,其中的每一对数字将被视为一个坐标位置(一个 x, y 对)。vertices 参数是必需的。
- indices:一个由整数或索引构成的矢量,其中每三个索引定义一个三角形。如果 indexes 参数为 null,则每三个顶点(vertices 矢量中的 6 对 x,y)定义一个三角形。否则,每个索引将引用一个顶点,即 vertices 矢量中的一对数字。例如,indexes[1] 引用 (vertices[2], vertices[3])。
- uvtData:由用于应用纹理映射的标准坐标构成的矢量。每个坐标引用用于填充的位图上的一个点。每个顶点必须具有一个 UV 或一个 UVT 坐标。对于 UV 坐标,(0,0) 是位图的左上角,(1,1) 是位图的右下角。
- thickness:分割三角形的边框的线粗
- color:分割三角形的边框的颜色
复制代码 直接看上面的文字,恐怕不太容易理解,下面来举几个例子,最后两个参数比较简单,先来说说这两个参数,下面是最后两个参数线宽设置为2,颜色为白色的效果
可以看到,上图中显示了三角形的边框。
好了,接下来说说其他三个参数的用法,
1,第一个参数vertices,其实就是定义每个顶点的坐标,这几个顶点的顺序依次为下图
vertices参数中储存的就是上面的9个顶点的坐标,代码如下
- vertices = new Array();
- vertices.push(0, 0);
- vertices.push(0, 120);
- vertices.push(0, 240);
- vertices.push(120, 0);
- vertices.push(120, 120);
- vertices.push(120, 240);
- vertices.push(240, 0);
- vertices.push(240, 120);
- vertices.push(240, 240);
复制代码 2,第二个参数indices是定义三角形,数组vertices中每三个顶点可以组成一个三角形,indices就是来定义这些三角形,这些三角形的顶点顺序是有规定的,其实从前面的图中可以看到,每两个三角形是一个矩形,定义这些三角形的时候,要以这些矩形的四个顶点为基准,三角形的顶点顺序分别是(左上,右上,左下)和(右上,左下,右下),如下图所示
对应图中的三角形,代码如下
- indices = new Array();
- indices.push(0, 3, 1);
- indices.push(3, 1, 4);
- indices.push(1, 4, 2);
- indices.push(4, 2, 5);
- indices.push(3, 6, 4);
- indices.push(6, 4, 7);
- indices.push(4, 7, 5);
- indices.push(7, 5, 8);
复制代码 2,第三个参数uvtData是定义上面的每个顶点相对于整张图片的比例,比如上面的图中的9个顶点的坐标,他们相对于原图片中的位置分别为下图所示
换算成代码如下
- uvtData = new Array();
- uvtData.push(0, 0);
- uvtData.push(0, 0.5);
- uvtData.push(0, 1);
- uvtData.push(0.5, 0);
- uvtData.push(0.5, 0.5);
- uvtData.push(0.5, 1);
- uvtData.push(1, 0);
- uvtData.push(1, 0.5);
- uvtData.push(1, 1);
复制代码有了上面这些参数的定义,然后通过LSprite对象的graphics属性的beginBitmapFill和drawTriangles两个函数,就可以绘制多样化的图形了
beginBitmapFill是用位图图像填充绘图区,参数是LBitmapData对象
如果,在vertices参数中定义的坐标位置就是原图片中所对应的位置,那么图片是没有什么变化的,但是,如果改变这些坐标的位置,比如下面的代码
- vertices = new Array();
- vertices.push(0, 0);
- vertices.push(0-50, 120);//这里将原坐标的x坐标左移50
- vertices.push(0, 240);
- vertices.push(120, 0);
- vertices.push(120, 120);
- vertices.push(120, 240);
- vertices.push(240, 0);
- vertices.push(240+50, 120);//这里将原坐标的x坐标右移50
- vertices.push(240, 240);
- indices = new Array();
- indices.push(0, 3, 1);
- indices.push(3, 1, 4);
- indices.push(1, 4, 2);
- indices.push(4, 2, 5);
- indices.push(3, 6, 4);
- indices.push(6, 4, 7);
- indices.push(4, 7, 5);
- indices.push(7, 5, 8);
- uvtData = new Array();
- uvtData.push(0, 0);
- uvtData.push(0, 0.5);
- uvtData.push(0, 1);
- uvtData.push(0.5, 0);
- uvtData.push(0.5, 0.5);
- uvtData.push(0.5, 1);
- uvtData.push(1, 0);
- uvtData.push(1, 0.5);
- uvtData.push(1, 1);
- backLayer.graphics.beginBitmapFill(bitmapData);
- backLayer.graphics.drawTriangles(vertices, indices, uvtData);
复制代码效果如图
上面的变形是将图片分割成了8个三角形,要实现更多种变形,那只需要将图片分割成更多的小三角形就可以了
比如我利用这个函数,制作了一个简陋的图片修饰工具,效果如下
大家可以点击下面的连接,来测试一下它的效果
备注:
使用drawtriangles函数,你需要下载HTML5开源引擎lufylegend的1.5版或以上版本,lufylegend1.5版发布地址如下
下面来看看drawtriangles函数的扩展。利用drawtriangles函数来实现一个旋转的3D地球,效果如下
因为lufylegend1.5.0版的drawtriangles函数有个bug,所以我悄悄的更新了lufylegend1.5.1版,大家可以到官网下载,地址如下
其实绘制3d球体效果的话,首先就是绘制一个平面,然后将这个平面分成一个一个的小三角形,然后再用这些小三角形拼凑成一个圆球就可以了
现在,我先创建一个空白的LBitmapData对象,然后将这个对象分割成N个小三角形,具体做法看下面代码
- earthBitmapData = new LBitmapData("#ffffff", 0, 0, 500, 300);
- var i, j;
- vertices = new Array();
- for(i=0;i<=cols;i++){
- for(j=0;j<=rows;j++){
- vertices.push(i*15,j*15);
- }
- }
- indices = new Array();
- for (i = 0; i < cols; i++) {
- for (j = 0; j < rows; j++) {
- indices.push(i * (rows + 1) + j, (i + 1) * (rows + 1) + j, i * (rows + 1) + j + 1);
- indices.push((i + 1) * (rows + 1) + j, i * (rows + 1) + j + 1, (i + 1) * (rows + 1) + j + 1);
- }
- }
- uvtData = new Array();
- for (i = 0; i <= cols; i++) {
- for (j = 0; j <= rows; j++) {
- uvtData.push(i / cols, j / rows);
- }
- }
复制代码接着,利用drawtriangles函数将LBitmapData对象绘制到画面上
- backLayer = new LSprite();
- addChild(backLayer);
- backLayer.graphics.clear();
- backLayer.graphics.beginBitmapFill(earthBitmapData);
- backLayer.graphics.drawTriangles(vertices, indices, uvtData, 2);
复制代码得到效果如下图。
要想将这个平面编程一个圆,就需要计算图中每个小三角形的坐标,先来看看y坐标应该如何计算,看下面一张图,是一个球的垂直切面
利用三角函数,计算图中的y坐标,和y坐标所在位置的球的水平切面圆的半径r1
- var a = Math.sin(angle);
- if((90-180*j/rows)%90==0 && (90-180*j/rows)%180!=0)a=(90-180*j/rows)>0?1:-1;
- var y = -r*a;
- var sa = Math.cos(angle);
- var r1 = Math.abs(r*sa);
复制代码于是,首先将计算好的y坐标带入到vertices数组中
- for(i=0;i<=cols;i++){
- for(j=0;j<=rows;j++){
- var angle = (90-180*j/rows)*Math.PI/180;
- var a = Math.sin(angle);
- if((90-180*j/rows)%90==0 && (90-180*j/rows)%180!=0)a=(90-180*j/rows)>0?1:-1;
- if((90-180*j/rows)%180==0)a=0;
- var sy = -r*a;
- vertices.push(i*15,sy);
- }
- }
复制代码因为还没有计算x的坐标,所以得到一个特殊图形,如下
接着,看看x的坐标如何计算,首先将半径为r1的平面切面拿出来,如下图
利用三角函数,计算图中的x坐标
- var b = Math.cos(angle*Math.PI/180);
- var x = r1*b;
复制代码这时,如果只将计算好的x坐标带入到vertices数组中的话
- for(i=0;i<=cols;i++){
- for(j=0;j<=rows;j++){
- var sa = Math.cos(angle);
- if((90-180*j/rows)%180==0)sa=1;
- var sr = Math.abs(r*sa);
- var angle2 = 360*(i+1)/cols;
- var b = Math.cos(angle2*Math.PI/180);
- if(angle2%360==0)b=1;
- else if(angle2%180==0)b=-1;
- var sx = sr*b;
- vertices.push(sx,j*15);
- }
- }
复制代码因为没有计算y的坐标,所以得到一个很有意思的图形,如下
如果将计算好的x坐标和y坐标,同时带入到vertices数组中的话
- for(i=0;i<=cols;i++){
- for(j=0;j<=rows;j++){
- var angle = (90-180*j/rows)*Math.PI/180;
- var a = Math.sin(angle);
- if((90-180*j/rows)%90==0 && (90-180*j/rows)%180!=0)a=(90-180*j/rows)>0?1:-1;
- if((90-180*j/rows)%180==0)a=0;
- var sy = -r*a;
- var sa = Math.cos(angle);
- if((90-180*j/rows)%180==0)sa=1;
- var sr = Math.abs(r*sa);
- var angle2 = 360*(i+1)/cols;
- var b = Math.cos(angle2*Math.PI/180);
- if(angle2%360==0)b=1;
- else if(angle2%180==0)b=-1;
- var sx = sr*b;
- vertices.push(sx, sy);
- }
- }
复制代码得到一个完整的球体图形,如下
接下来就简单了,将空白图片换成地球的平面图,代码如下
- earthBitmapData = new LBitmapData(imglist["earth"]);
复制代码再次运行代码,就可以得到下面的3D图形了
下面,该让这个地球转动起来了,根据上一篇介绍的内容,传入drawtriangles函数的uvtData数组中的元素是每个小三角形在原图片中的相对位置,它们决定了绘制图片的开始位置,如果将一组位置比如0123,变换其中的位置成为1230,再继续变换成2301,这样不断的进行位置变换,那么从视觉上,其实就已经实现了旋转了,那么在代码中,只需要将分割完的数组的按照每一列进行移动,每次都将第一列的两组三角形移到最后一列,这样第二列的两组三角形就变为了第一列,这样不停的变换就能让一个地球转动起来
- for (i = 0; i <= rows; i++) {
- uvtData.push(uvtData.shift());
- uvtData.push(uvtData.shift());
- }
复制代码如果要改变这个地球的大小的话,就更简单了,改变LSprite对象的scaleX和scaleY属性就可以改变它的大小了,大家可以点击下面的连接,来测试一下它的效果
备注:
再次说明一下,本篇所介绍的内容需要HTML5开源引擎lufylegend的1.5.1版或以上版本的支持,lufylegend1.5.1版发布地址如下
作者: wangcheng800718 时间: 2013-3-12 22:01
图片挂了。
作者: leonly0224 时间: 2013-12-10 21:11
请问下,我想用你这个框架做个“长廊”效果
就是“网格”形状的“地板”,感觉是人在往前走,地板在往后退,
其实就是矩形图片,做了个梯形的缩放,然后平铺,滚动
应该怎么实现呢?望赐教
作者: lufy 时间: 2013-12-10 23:28
leonly0224 发表于 2013-12-10 21:11
请问下,我想用你这个框架做个“长廊”效果
就是“网格”形状的“地板”,感觉是人在往前走,地板在往后退 ...
就用这个帖子里讲的drawTriangles函数就可以实现啊,
控制好座标,让座标按照梯形轨道移动就可以了
作者: leonly0224 时间: 2013-12-11 11:50
本帖最后由 leonly0224 于 2013-12-11 15:56 编辑
lufy 发表于 2013-12-10 23:28
就用这个帖子里讲的drawTriangles函数就可以实现啊,
控制好座标,让座标按照梯形轨道移动就可以了 ...
你好,感谢回复!
我现在是这么弄的
首先图片按照你上面三国人物的划分方法来划分9个定点
0 3 6
1 4 7
2 5 8
那么uvtData里面顺序是0 1 2 3 4 5 6 7 8
如果我想沿着y轴水平往下“滚动”,
是不是我把划分点最下面一行挪上来即可(变成下面这样)
2 5 8
0 3 6
1 4 7
那么uvtData里面顺序是2 0 1 5 3 4 8 6 7 ?
是不是这么个意思?
=============目前我这么弄,已经成功了
但是运行一小会,速度就会越来越卡。。。。到最后明显卡的一塌糊涂
请问有没有更高效的方法推荐下,谢谢
作者: lufy 时间: 2013-12-11 22:19
leonly0224 发表于 2013-12-11 11:50
你好,感谢回复!
我现在是这么弄的
首先图片按照你上面三国人物的划分方法来划分9个定点
这种方法,要么从一开始就卡,要么就一直不卡
你说的越来越卡的话,应该是用法上哪里出了问题了
能不能把代码贴上来看看?
或者把代码打包用邮件发给我
作者: 总会花开 时间: 2014-1-19 19:22
关注下~~~
作者: macdaddy 时间: 2014-2-3 09:25
请问怎样实现贴图效果?贴在杯子上,或者贴在衣服上的立体效果。还有用你这个引擎做的地球实例,可以去掉上面很多条一圈圈的白线吗?谢谢
作者: lufy 时间: 2014-2-3 23:06
macdaddy 发表于 2014-2-3 09:25
请问怎样实现贴图效果?贴在杯子上,或者贴在衣服上的立体效果。还有用你这个引擎做的地球实例,可以去掉上 ...
就用该帖子说的方法就可以吧。
白线的问题是根据浏览器而定的,比如我的Mac版chrome就完全没有白线的
作者: tomastong 时间: 2014-12-11 15:14
讲解的非常好,水平不够,需要慢慢理解!不过我想问一下楼主,这个lufylegend只能从你发布的那本书进行学习吗,有没其他的资源?
作者: lufy 时间: 2014-12-11 21:09
tomastong 发表于 2014-12-11 15:14
讲解的非常好,水平不够,需要慢慢理解!不过我想问一下楼主,这个lufylegend只能从你发布的那本书进行学习 ...
可以看官方的API文档
http://lufylegend.com/api/zh_CN/out/index.html
作者: ffx0s 时间: 2015-3-3 16:23
图片变形的例子打不开了。。求新链接。
作者: lufy 时间: 2015-3-5 10:02
ffx0s 发表于 2015-3-3 16:23
图片变形的例子打不开了。。求新链接。
多谢了
最近有点忙,等有时间了会把旧连接整理一下的
作者: ffx0s 时间: 2015-3-9 15:16
lufy 发表于 2015-3-5 10:02
多谢了
最近有点忙,等有时间了会把旧连接整理一下的
嗯。还发现了一个bug。jpg格式的没有问题,但是用png的图片去编辑就有bug了。会出现像素重复的现象。这个是什么原因呢?最近项目正好需要实现这个功能。。
作者: lufy 时间: 2015-3-9 15:26
ffx0s 发表于 2015-3-9 15:16
嗯。还发现了一个bug。jpg格式的没有问题,但是用png的图片去编辑就有bug了。会出现像素重复的现象。这个 ...
没有遇到过啊
有测试连接吗?我看一下
作者: ffx0s 时间: 2015-3-9 15:43
lufy 发表于 2015-3-9 15:26
没有遇到过啊
有测试连接吗?我看一下
http://webfed.cn/static/1/test/_test.html 这个是测试链接。图片是PNG格式的。拖动右下角的触点会比较明显的看到图片重复了。。
作者: lufy 时间: 2015-3-9 16:00
1.5.0??
现在最新版本是1.9.7,请使用最新版本,问题就解决了
作者: ffx0s 时间: 2015-3-9 16:13
lufy 发表于 2015-3-9 16:00
1.5.0??
现在最新版本是1.9.7,请使用最新版本,问题就解决了
感谢lufy,,换了1.9.7的版本真的可以了。好厉害!已收藏了你的博客和论坛。以后常来!
作者: yizh1211 时间: 2015-6-23 10:30
lufy 发表于 2014-2-3 23:06
就用该帖子说的方法就可以吧。
白线的问题是根据浏览器而定的,比如我的Mac版chrome就完全没有白线的 ...
我的chrome也会 啊,window版chrome,请问有什么解决方法
作者: sunjian 时间: 2015-8-5 16:37
macdaddy 发表于 2014-2-3 09:25
请问怎样实现贴图效果?贴在杯子上,或者贴在衣服上的立体效果。还有用你这个引擎做的地球实例,可以去掉上 ...
我用的时候。也发现这个问题。很多window端浏览器和手机浏览器.都有白线
作者: zzz220918 时间: 2018-9-21 06:19
lufy 发表于 2013-12-10 23:28
就用这个帖子里讲的drawTriangles函数就可以实现啊,
控制好座标,让座标按照梯形轨道移动就可以了 ...
你好我想问一下 LBitmapData(img,0,0,100,100),这里的宽度和高度要怎么样才可以是缩放后的状态,我发现是裁剪一部分显示的
作者: lufy 时间: 2019-2-25 08:00
zzz220918 发表于 2018-9-21 06:19
你好我想问一下 LBitmapData(img,0,0,100,100),这里的宽度和高度要怎么样才可以是缩放后的状态,我发现是 ...
LBitmapData不支持缩放啊,只能用LBitmap才可以
作者: Rain_Golden 时间: 2019-3-21 16:20
虽然是浏览器问题,但我不能叫客户换电脑啊。windows上的浏览器,好像都有白线问题。如果才能解决呢
作者: lufy 时间: 2019-3-22 06:08
Rain_Golden 发表于 2019-3-21 16:20
虽然是浏览器问题,但我不能叫客户换电脑啊。windows上的浏览器,好像都有白线问题。如果才能解决呢 ...
我也没有办法,下面是我的一个优化,但是有局限性,你试一下看看
http://lufylegend.com/forum/foru ... hread&tid=18722
作者: ymboy 时间: 2024-1-9 10:29
http://lufylegend.com/html5/lufylegend/ps.html
lufy 这个页面打不开啦
欢迎光临 lufy's legend (http://lufylegend.com/forum/) |
Powered by Discuz! X2.5 |