閑聊js8: 創(chuàng)建一個演示用的渲染庫6(圖像顯示)

本篇的目的是要了解:

  • 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ū)域

看一下原始圖像和繪制后的圖像:

原始圖:


doom3.png

drawImage后的圖:

drawImage_3_times_result.png

演示效果如下:
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);
            }
        }
drawShape_pattern_result.png
  • 目前測試下來,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。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容