抛玉引砖
我正在参加「掘金·启航计划」,最新闲来无事,决定学习一下新技术,丰富一下自身(实在是无鱼可摸了,jym发小故事的频率不太行啊),所以就让我来给jym创造一点话题吧.最近看了几篇threejs的教学文章,决定动手实现一个3d版的坤坤(不喜勿喷?).
原图长这个样子
经过大佬的处理之后变成了酱紫,大佬的文章链接我放这里啦juejin.cn/post/717867…
Show Time!
好了,下面轮到我们表演啦,如何把这张图片变成360度无死角环绕,让你充分体会kunkun的魅力,最终加入我们ikun呢,那就需要用到threejs了.先看一下最终的效果吧:
怎么样,是不是被我们kunkun迷住了,那还犹豫什么呢,加入我们ikun吧,坤流无所不在?.
实现过程
实现起来还是挺容易的,简单来说就是利用threejs创建了一个立方集合体(BoxGeometry),然后对立方体进行贴图(注意这里只能是静态图片,动图是不行的),那如何让我们的kunkun动起来,充分展示舞蹈魅力呢,我们只需要循环渲染,每一帧贴不同的图片就可以了.
具体的threejs教程我就不写了,因为我也是刚学,就放一下大佬写的教程文章吧
juejin.cn/post/698098…
第一步,对立方体进行贴图
createModel() {
this.canvas = document.createElement('canvas');
this.ctx = this.canvas.getContext('2d');
this.canvas.width = 500;
this.canvas.height = 529;
const img = new Image();
img.src = `/test/2.png`;
this.ctx.drawImage(img, 0, 0)//绘制图片
const geometry = new THREE.BoxGeometry(2, 2, 2);
this.texture = new THREE.Texture(this.canvas);
this.texture.needsUpdate = true;
const material = new THREE.MeshBasicMaterial({ map: this.texture, side: THREE.BackSide })
const cube = new THREE.Mesh(geometry, material)
this.cube = cube;
this.scene.add(cube);
}
效果如下
第二步,让我们的kunkun动起来
值得注意的是,为了让贴图动起来,需要不断的更新贴图的图像,这里我用的是canvas,然后不断改变canvas里渲染的图片
getMaterial() {
this.current++;
if (this.current > 86) this.current = 2;
return `/test/${this.current}.png`;
}
createCanvas() {
this.canvas = document.createElement('canvas');
this.ctx = this.canvas.getContext('2d');
this.canvas.width = 500;
this.canvas.height = 529;
this.timer = setInterval(() => {
const img = new Image(); // 创建一个<img>元素
img.onload = () => {
this.ctx.drawImage(img, 0, 0)//绘制图片
}
img.src = this.getMaterial(); // 设置图片源地址
}, 100);
}
createModel() {
this.createCanvas();
const geometry = new THREE.BoxGeometry(2, 2, 2);
this.texture = new THREE.Texture(this.canvas);
this.texture.needsUpdate = true;
const material = new THREE.MeshBasicMaterial({ map: this.texture, side: THREE.BackSide })
const cube = new THREE.Mesh(geometry, material)
this.cube = cube;
this.scene.add(cube);
}
到这里我们的kunkun就动起来啦.
完整代码放下面啦,欢迎大佬们指教,我很菜,但我不改.
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
export class KunKun {
constructor({ container, width, height }) {
this.dom = container || document.body;
this.width = width || window.innerWidth;
this.height = height || window.innerHeight;
}
current = 2;
init() {
// 第一步新建一个场景
this.scene = new THREE.Scene();
this.setCamera();
this.setRenderer();
this.createModel();
this.initControls();
this.animate();
}
initControls() {
this.orbitControls = new OrbitControls(this.camera, this.renderer.domElement)
}
getMaterial() {
this.current++;
if (this.current > 86) this.current = 2;
return `/test/${this.current}.png`;
}
createCanvas() {
this.canvas = document.createElement('canvas');
this.ctx = this.canvas.getContext('2d');
this.canvas.width = 500;
this.canvas.height = 529;
this.timer = setInterval(() => {
const img = new Image(); // 创建一个<img>元素
img.onload = () => {
this.ctx.drawImage(img, 0, 0)//绘制图片
}
img.src = this.getMaterial(); // 设置图片源地址
this.img = img;
}, 100);
}
createModel() {
this.createCanvas();
const geometry = new THREE.BoxGeometry(2, 2, 2);
this.texture = new THREE.Texture(this.canvas);
this.texture.needsUpdate = true;
const material = new THREE.MeshBasicMaterial({ map: this.texture, side: THREE.BackSide })
const cube = new THREE.Mesh(geometry, material)
this.cube = cube;
this.scene.add(cube);
}
animate() {
this.texture.needsUpdate = true;
requestAnimationFrame(this.animate.bind(this))
this.renderer.render(this.scene, this.camera)
}
// 新建透视相机
setCamera() {
// 第二参数就是 长度和宽度比 默认采用浏览器 返回以像素为单位的窗口的内部宽度和高度
this.camera = new THREE.PerspectiveCamera(
75,
this.width / this.height,
0.1,
1000
);
this.camera.position.set(1, 1, 4);
}
// 设置渲染器
setRenderer() {
this.renderer = new THREE.WebGLRenderer({
antialias: true,//抗锯齿
})
// 设置画布的大小
this.renderer.setSize(this.width, this.height)
//这里 其实就是canvas 画布 renderer.domElement
this.dom.appendChild(this.renderer.domElement)
}
// 设置环境光
setLight() {
this.ambientLight = new THREE.AmbientLight(0xffffff) // 环境光
this.scene.add(this.ambientLight)
}
// 销毁画布
destroy() {
this.renderer.domElement.remove();
clearInterval(this.timer);
}
}
import React, { useEffect, useRef } from 'react';
import { KunKun } from './class';
const Demo = () => {
const domRef = useRef();
useEffect(() => {
const map = new KunKun({
container: domRef.current,
width: 600,
height: 800
});
map.init();
return () => {
map.destroy();
};
}, []);
return <div ref={domRef}></div>;
};
export default Demo;
我这里是用工具把gif图解析成每一帧,存在本地来进行展示的,网上有很多库可以做到这点,你们就不必参考我这种方式啦,原谅我很菜?.
© 版权声明
文章版权归作者所有,未经允许请勿转载,侵权请联系 admin@trc20.tw 删除。
THE END