本篇的目的是要了解:
- canvas2d中的drawImage函数绘制图像(还可以视频/内存canvas)
- canvas2d中的Pattern贴图到非规则几何形体上(Pattern还可以是视频/内存canvas)
1. canvas2d drawImage绘制图像:
我们对canvas2d中的drawImage进行封装,具体代码如下:
drawImage(image, srcRect = null, destRect = null) {
//如果image不存在,直接退出函数
if (image == null)
return;
//如果srcRect为null,则设置srcRect为输入参数image的width/height
if (srcRect == null) {
srcRect = new Rect(0, 0, image.width, image.height);
}
//如果destRect为null,则设置destRect为画布本身的width/height
if (destRect == null) {
destRect = new Rect(0, 0, this.getCanvasWidth(), this.getCanvasHeight());
}
let context = this.context;
//进行bitblt操作(位块传输),根据src/dest的rect的大小,自动进行缩放或拉伸
context.drawImage(image, srcRect.x, srcRect.y, srcRect.width, srcRect.height, destRect.x, destRect.y, destRect.width, destRect.height);
}
canvas2d的drawImage方法非常灵活强大。
该方法可以将一副image,一个canvas(内存或离屏画布)对象或一段video的整体或部分区域绘制到目标canvas的全部或部分区域中去。在绘制这些图像,视频或内存canvas时,可以指定任意的位置,大小,canvas内部会根据需求,自动进行缩放或拉伸操作。
我们来看一下测试效果:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>随风而行之青衫磊落险峰行JSDemo</title>
<script src="BLFES6Lib.js"></script>
</head>
<body>
<canvas id="myCanvas" width="800" height="600" style="border: 1px solid black">你的浏览器还不支持哦</canvas>
<script>
let canvas = document.getElementById("myCanvas");
let context = canvas.getContext('2d');
let render = new BLFRender(context);
let image = new Image();
image.src = "./data/doom3.png";
image.onload = function(e) {
render.drawImage(image);
render.drawImage(image, null, new Rect(10, 400, 100, 100));
render.drawImage(image, new Rect(0, 0, image.width * 0.5, image.height * 0.5), new Rect(500, 100, 200, 100));
}
</script>
</body>
</html>
render.drawImage(image): 没有规定srcRect/destRect,则将整个image绘制到整个画布上
render.drawImage(image, null, new Rect(10, 400, 100, 100)): 没有指定srcRect,但指定了destRect,则将整个image绘制到画布的指定区域
render.drawImage(image, new Rect(0, 0, image.width * 0.5, image.height * 0.5), new Rect(500, 100, 200, 100)): 指定了srcRect/destRect,则将image的部分区域绘制到画布的指定区域
看一下原始图像和绘制后的图像:
原始图:
drawImage后的图:
演示效果如下:
htmlpreview.github.io/?https://github.com/jackyblf/BLF_JS_Demos/blob/master/drawImage.html
2. 使用Pattern进行贴图:
上一篇实现了drawXXX基础几何体的方法,default情况下,style使用颜色进行填充。实际上style还支持纹理(图像)填充,具体用法我们来看一下:
先封装一个生成Pattern的成员方法:
//type='repeat'/'repeat-x'/'repeat-y'/'no-repeat'
//目前来说,很多浏览器只支持repeat方式
createPattern(image, type = "repeat") {
if (image == null)
return null;
let ret = this.context.createPattern(image, type);
return ret;
}
测试一下: 载入两张image,分别贴在一个圆形,圆弧和矩形上
let image = new Image();
let image1 = new Image();
image.src = "./data/doom3.png";
image1.src = "./data/ardunio_nano.jpg";
image.onload = function(e) {
let pattern = render.createPattern(image);
if (pattern) {
//贴图绘制圆
render.drawCircle(new Circle(200, 200, 100), pattern);
//贴图绘制圆弧
render.drawArc(new Arc(500, 200, 100, 30, 180), pattern);
}
}
image1.onload = function(e) {
let pattern = render.createPattern(image1);
if (pattern) {
//贴图绘制矩形
render.drawRect(new Rect(0, 400, 800, 200), pattern);
}
}
- 目前测试下来,pattern的贴图方式,很多浏览器仅仅支持repeat方式
- pattern和drawImage最大区别在于:pattern可以贴到任意形状,而drawImage只能是矩形
- drawImage和pattern实现原理完全不同:drawImage是位块传输,像素搬运工(纯像素操作)。pattern更像是3D api中的纹理贴图,纹理坐标与空间顶点的映射操作(图形光栅化图像过程中进行纹理坐标映射操作,当然3D api中的贴图比pattern强多了)
演示效果如下:
htmlpreview.github.io/?https://github.com/jackyblf/BLF_JS_Demos/blob/master/drawShape.html
附录:
演示demo中使用了我研究unity3d引擎的一些demo截图。
在untiy3d中,为了了解Mesh/MeshRender/SkinnedMeshRender等这几个关键类,我将Doom3的地图和md5骨骼动画在unity3d中实现了一遍,花了将近半个月的空闲时间。整体来说untiy3d还是很好用的。但是引擎太高层了,封装了很多细节和关键的东西,而且unity3d也不开源。但是如果有图形学及引擎的基础知识,对于这种未开源的引擎把握起来还是很容易的。而骨骼动画,可以说完全是数学操作,因此数学是最最基础的东西。
说了这么多,就是想说,在js学习的webgl篇,我们最终效果就是实现doom3地图和骨骼动画的渲染效果,并做一个3D 第一/三人称的小游戏。当然如果要达到效果,数学是避不开的门槛。
关于简书上的博文,除非是源码分析之类的。其他的基本都有可运行demo。