月饼太贵?那就用Three.js自己制作一个月饼,无死角观看!

·  阅读 12595
月饼太贵?那就用Three.js自己制作一个月饼,无死角观看!

我正在参加「码上掘金挑战赛」详情请看:码上掘金挑战赛来了!

前言

还有两天,就迎来了中国的传统:中秋节,又称祭月节、月光诞、月夕、秋节、仲秋节、拜月节、月娘节、月亮节、团圆节等。是中国四大传统节日之一,其余三个是春节、清明、端午。

一想到中秋节大家想到的肯定就是月饼和月亮,还有与家人团聚。由于今年疫情加重,响应政府号召,少流动。减少学校疫情风险,所以这个中秋就还是在学校过吧。

想吃月饼?看了看淘宝,哦~,还是别想了

image.png

夏天有雪糕刺客,中秋有月饼刺客。

所以!既然吃不到,身为前端小牛马,吃不到总要看得到吧。

在线体验

github: lonely1201.github.io/Juejin/moon…

制作方法

需要用到的软件及工具

  1. 3d模型
  2. Three.js Three.js下载地址:github.com/mrdoob/thre…

模型

由于我不会建模,所以月饼模型是在网络上下载的。Three.js支持大部分外部模型,比如:obj、fbx等等。都在Three.js里面引入对应的js库就行。

我使用的是obj,由于obj没有颜色,所以还需要搭配tga文件,附加上颜色,好在Three.js也支持tga引入。

image.png

制作

引入js库

首先要引入three.js,在根目录下的build文件夹。

<script src="./build/three.js"></script>
复制代码

因为我使用的模型是obj文件,和配套的tga文件,所以在这里还需要引入OBJLoader.js和TGALoader.js。文件在根目录下的examples\js\loaders文件夹下,这里面都是一些加载模型需要引入的js文件,需要引入那个就可以调用哪个。

<script src="./examples/js/loaders/OBJLoader.js"></script>
<script src="./examples/js/loaders/TGALoader.js"></script>
复制代码

QQ录屏20220908192412.gif 看动图,案例是可以使用鼠标进行大小缩放和摄影机位置变化,所以这里还需要引入OrbitControls.js,这个js可以很好的实现这一效果,不需要自己写。文件在根目录下的examples\js\controls文件夹下。

<script src="./examples/js/controls/OrbitControls.js"></script>
复制代码

到这里就把需要引入的js文件引入完成了,接下来就要开始写代码了。

代码

HTML

html只需要写一个div就好了。

<div id="stage"></div>
复制代码

CSS

给html和body设置宽高,取消内外边距,设置背景颜色。

html, body {
    width: 100%;
    height: 100%;
    overflow: hidden;
    margin: 0;
    padding: 0;
    background-color: #000;
}

#stage, canvas {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

canvas {
    z-index: 99;
}
复制代码

JavaScript

最激动,最主要,最多的地方来了!

首先在最开始定义一些名字,为什么要在外面定义呢,因为在函数里面定义的类名在外部获取不到,所以在开头就先定义好。

定义
let stage = document.querySelector('#stage');
let container;
let scene, camera, renderer, controls;
let SCREEN_WIDTH = window.innerWidth;
let SCREEN_HEIGHT = window.innerHeight;
let angle = 90;
let nearest = 1;
let farthest = 1000;
复制代码

定义完这些常用的名字之后,现在就需要开始创建场景了。

scene = new THREE.Scene();
复制代码
相机

创建相机,就是视角的位置。

camera =  new THREE.PerspectiveCamera(angle, SCREEN_WIDTH / SCREEN_HEIGHT, nearest, farthest);
camera.position.set(20, 20, 30);
复制代码
导入obj模型和tga贴纸

这里就可以开始导入我的模型了,我这里使用的是obj格式的模型。

  • new一个OBJLoader对象,如果报错,那就是没有引入OBJLoader.js文件。
  • 设置一下路径,避免后面的路径太长。
  • 在这里先给月饼太难加上一层材质,一共是四个,分别是:map、normalMap、specularMap和bumpMap。
  • map指的是材质。
  • normalMap是让的字和线条看起来更清楚和真实。
  • specularMap是高光贴图。
  • bumpMap是凹凸贴图。
  • 添加上这四个贴图,月饼看起来更立体和真实。
let obj_loader = new THREE.OBJLoader();
obj_loader.setPath('https://lonely1201.github.io/Juejin/mooncake/models/mooncake/');
let tga_loader = new THREE.TGALoader();
// 材质
let material = new THREE.MeshPhongMaterial({
    map: tga_loader.load('./models/mooncake/Sofa_OS_0727_01___Default_Diffuse.tga'),
    normalMap: tga_loader.load('./models/mooncake/Sofa_OS_0727_01___Default_Normal.tga'),
    specularMap: tga_loader.load('./models/mooncake/Sofa_OS_0727_01___Default_S.tga'),
    bumpMap: tga_loader.load('./models/mooncake/Sofa_OS_0727_01___Default_Bump.tga')
});
obj_loader.load('mooncake.obj', function (group) {
    let geometry = group.children[0].geometry;
    geometry.attributes.uv2 = geometry.attributes.uv;
    geometry.center();

    let mesh = new THREE.Mesh(geometry, material);
    mesh.scale.multiplyScalar(.3);
    scene.add(mesh);
});
复制代码

贴纸和模型已经添加上去了,现在只需要把月饼渲染出来就可以了

渲染

创建渲染器,把antialias和alpha改为true,平滑和canvas背景透明。

设置渲染器的像素,添加到网页当中。

renderer = new THREE.WebGLRenderer({
    antialias: true,
    alpha: true
});
renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
container.appendChild(renderer.domElement);
复制代码

new一个OrbitControls方法,这个方法是用来使用鼠标控制摄像机视角用的。

如果报错记得引入ObritControls.js。

执行animate函数

controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
animate();
复制代码

使用requestAnimationFrame重复调用animate函数,就是一直渲染render函数。

function animate() {
    requestAnimationFrame(animate);
    render();
}
function render() {
    renderer.render(scene, camera);
}
复制代码

到这里,月饼就可以看到了,并且可以使用鼠标控制

QQ录屏20220908200255.gif

坏境光

有没有发现,这个月饼没有很暗,没有光线,那现在需要添加光线

在创建相机的位置下方,添加光线。

let light = new THREE.DirectionalLight(16777215, 1);
light.position.set(0, 50, 50);
scene.add(light);
复制代码

大功告成

QQ录屏20220908192412.gif

总结

疫情期间不乱跑,防疫需要你和我。疫情早日结束,学校就不需要封校了,封校真的很难受的,不仅是购买网上东西不方便,呆久了心里也会有点心理疾病的。

在最后祝大家中秋节快乐! 快对着屏幕舔一下,尝下我的月饼吧。

分类:
前端
收藏成功!
已添加到「」, 点击更改