闲聊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。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容