20

three.js 制作属于自己的动态二维码

 3 years ago
source link: http://www.cnblogs.com/vadim-web/p/13335081.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

今天郭先生说一下用canvas解析图片流,然后制作一个动态二维码的小案例,话不多说先上图,在线案例点击 博客原文 。这是郭先生的微信二维码哦!

EJRVZv2.png!web

1. 解析图片流

canvas = document.createElement('canvas');//创建canvas画布
content = canvas.getContext('2d');//获取画布的上下文
canvas.width = 310;//设置尺寸
canvas.height = 310;
img = new Image();//创建一张图片
img.src = require("../assets/images/base/wechat.png");//设置图片地址
img.onload = () => {
        //在图片加载后
    content.drawImage(img, 0, 0, canvas.width, canvas.height);//将图片添加到画布,并设置宽高
    imgData = content.getImageData(0, 0, canvas.width, canvas.height).data;//获取画布数据
};

imgData是什么样的呢?如下图

VJnaIzY.png!web

这是一个Uint8ClampedArray的类型化数组,这个数组出现最多的也是在imgData上。它会将负数归入0,大于255的数归入255,所以取模就不用了。我们再来看这个数组的长度是384400是怎么来的呢?因为我们设置了画布长宽为310,而imgData四位代表一个rgba像素点,也就是imgData[0]是红色通道,imgData[1]是绿色通道,imgData[2]是蓝色通道,imgData[3]是透明通道…依次循环,所以310 * 310 * 4 = 384400。

2. 处理像素点,画出二维码

for (var i = 0; i < 31 * 31; i++) {
        //random_position为各个小平面块打乱时的位置信息,我设置小平面一共有31 * 31个
    random_position.push([Math.floor(Math.random() * 300 - 150), Math.floor(Math.random() * 300 - 150), Math.floor(Math.random() * 300 - 150)])
}
var color = new Array(310).fill('').map(d => []);//color设置成310个数组
for (var i = 0; i < 310; i++) {
    for (var j = 0; j < 310; j++) {
        let clr = imgData[(i * 310 + j) * 4] + imgData[(i * 310 + j) * 4 + 1] + imgData[(i * 310 + j) * 4 + 2];
        clr = clr > 382 ? 'light' : 'black'; //因为颜色是有深色块和浅色块组成,他们的分界就是rgb通道颜色值之和小于等于127+127+127之和。
        color[i].push(clr)//每个数组有310项,每项的值为'light'或者'black'
    }
}
var color1 = [];//设置color1为小平面颜色数组31 * 31。
color.filter((d, i) => (i + 6) % 10 == 0).forEach((dd, ii) => color1[ii] = dd.filter((d, i) => (i + 6) % 10 == 0));//每10个像素,筛选出1个像素作为小平面的颜色,选取的位置尽量在10个的中间选择,毕竟有的图片比较模糊。
for (var i = 0; i < color1.length; i++) {//31 * 31的循环
    for (var j = 0; j < color1[i].length; j++) {
        var geometry = new THREE.PlaneGeometry(10, 10);
        var material = new THREE.MeshBasicMaterial({
            color: 0xffffff,
            side: THREE.DoubleSide,
            transparent: true,
            opacity: color1[i][j] == 'black' ? 0 : 1,
        });
        var mesh = new THREE.Mesh(geometry, material);//小方块网格
        origin_position.push([j * 10 - 15 * 10, 15 * 10 - i * 10, 0]);//保存序列换后小方块的位置
        mesh.position.set(random_position[j + i * j][0], random_position[j + i * j][1], random_position[j + i * j][2]);//先将小方块的位置设置成打乱的位置,便于动画播放。
        mesh.name = 'plane';
        group.add(mesh);//将所有小平面放到数组,便于操作。
    }
}
scene.add(group);

这部分代码主要是计算部分,没什么技术含量。

3. 实现tween动画

var pos = { time: 0 };
tween1 = new TWEEN.Tween(pos).to({ time: 1 }, 3000);
tween2 = new TWEEN.Tween(pos).to({ time: 0 }, 3000);
tween1.easing(TWEEN.Easing.Quadratic.In);
tween2.easing(TWEEN.Easing.Quadratic.Out);
tween1.onUpdate(onUpdate);
tween2.onUpdate(onUpdate);
tween1.start();

function onUpdate() {
    let time = this._object.time;
    group.children.forEach((d, i) => {
        d.position.set(time * origin_position[i][0] + (1 - time) * random_position[i][0], time * origin_position[i][1] + (1 - time) * random_position[i][1], (1 - time) * random_position[i][2]);
    })
}

这部分只是用了tween的基础功能,请自行查看tween文档。

转载请注明地址: 郭先生的博客


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK