闲聊js8: 创建一个演示用的渲染库6(图像显示)

本篇的目的是要了解:

  • 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的部分区域绘制到画布的指定区域

看一下原始图像和绘制后的图像:

原始图:


doom3.png

drawImage后的图:

drawImage_3_times_result.png

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容