本篇的目的是要了解:
- canvas2d中的drawImage函數(shù)繪制圖像(還可以視頻/內(nèi)存canvas)
- canvas2d中的Pattern貼圖到非規(guī)則幾何形體上(Pattern還可以是視頻/內(nèi)存canvas)
1. canvas2d drawImage繪制圖像:
我們對canvas2d中的drawImage進行封裝,具體代碼如下:
drawImage(image, srcRect = null, destRect = null) {
//如果image不存在,直接退出函數(shù)
if (image == null)
return;
//如果srcRect為null,則設(shè)置srcRect為輸入?yún)?shù)image的width/height
if (srcRect == null) {
srcRect = new Rect(0, 0, image.width, image.height);
}
//如果destRect為null,則設(shè)置destRect為畫布本身的width/height
if (destRect == null) {
destRect = new Rect(0, 0, this.getCanvasWidth(), this.getCanvasHeight());
}
let context = this.context;
//進行bitblt操作(位塊傳輸),根據(jù)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(內(nèi)存或離屏畫布)對象或一段video的整體或部分區(qū)域繪制到目標canvas的全部或部分區(qū)域中去。在繪制這些圖像,視頻或內(nèi)存canvas時,可以指定任意的位置,大小,canvas內(nèi)部會根據(jù)需求,自動進行縮放或拉伸操作。
我們來看一下測試效果:
<!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): 沒有規(guī)定srcRect/destRect,則將整個image繪制到整個畫布上
render.drawImage(image, null, new Rect(10, 400, 100, 100)): 沒有指定srcRect,但指定了destRect,則將整個image繪制到畫布的指定區(qū)域
render.drawImage(image, new Rect(0, 0, image.width * 0.5, image.height * 0.5), new Rect(500, 100, 200, 100)): 指定了srcRect/destRect,則將image的部分區(qū)域繪制到畫布的指定區(qū)域
看一下原始圖像和繪制后的圖像:
原始圖:

drawImage后的圖:

演示效果如下:
htmlpreview.github.io/?https://github.com/jackyblf/BLF_JS_Demos/blob/master/drawImage.html
2. 使用Pattern進行貼圖:
上一篇實現(xiàn)了drawXXX基礎(chǔ)幾何體的方法,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最大區(qū)別在于:pattern可以貼到任意形狀,而drawImage只能是矩形
- drawImage和pattern實現(xiàn)原理完全不同: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等這幾個關(guān)鍵類,我將Doom3的地圖和md5骨骼動畫在unity3d中實現(xiàn)了一遍,花了將近半個月的空閑時間。整體來說untiy3d還是很好用的。但是引擎太高層了,封裝了很多細節(jié)和關(guān)鍵的東西,而且unity3d也不開源。但是如果有圖形學及引擎的基礎(chǔ)知識,對于這種未開源的引擎把握起來還是很容易的。而骨骼動畫,可以說完全是數(shù)學操作,因此數(shù)學是最最基礎(chǔ)的東西。
說了這么多,就是想說,在js學習的webgl篇,我們最終效果就是實現(xiàn)doom3地圖和骨骼動畫的渲染效果,并做一個3D 第一/三人稱的小游戲。當然如果要達到效果,數(shù)學是避不開的門檻。
關(guān)于簡書上的博文,除非是源碼分析之類的。其他的基本都有可運行demo。