关于前端:拜托使用Threejs让二维图片具有3D效果超酷的好吗-💥

申明:本文波及图文和模型素材仅用于集体学习、钻研和观赏,请勿二次批改、非法流传、转载、出版、商用、及进行其余获利行为。

背景

sketchfab 网站的时候我看到有很多二维立体转 3D 的模型例子,于是仿照他们的例子,应用 Three.js + React 技术栈,将二维漫画图片转化为三维视觉效果。本文蕴含的内容次要包含:THREE.Group 层级模型、MeshPhongMaterial 高光网格材质、正弦余弦函数 创立模型挪动轨迹等。

成果

实现成果如 👇 下图所示:页面次要有背景图、漫画图片主体以及 💥 Boom 爆炸背景图片形成,按住鼠标左键挪动模型能够取得不同视图,让图片在视觉上有 3D 景深成果。

已适配:

  • 💻 PC端
  • 📱 挪动端

👀 在线预览:https://dragonir.github.io/3d…

实现

本文实现比较简单,和我后面几篇文章实现基本上是雷同的,流程也比较简单,次要是素材筹备流程比较复杂。上面看看具体实现办法。

素材制作

筹备一张本人喜爱的图片作为素材原图,图片内容最好能够分成多个层级,以实现 3D 景深成果,本实例中应用的是一张漫画图片,刚好能够切分成多个层级。

Photoshop 中关上图片,依据本人须要的分层数量,创立若干图层,并将地图复制到每个图层上,而后依据对图层景深层级的划分,编辑每个图层,联合应用魔棒工具套索工具删除多余的局部,而后将每个图层独自导出作为素材。我分为 👆 如上 7 个图层,外加一个边框,一共有 8 个图层。

资源引入

其中 OrbitControls 用于镜头轨道控制、TWEEN 用于镜头补间动画。

import React from 'react';
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { TWEEN } from "three/examples/jsm/libs/tween.module.min.js";

场景初始化

初始化渲染容器、场景、摄像机、光源。摄像机初始地位设置为位于偏左方的 (-12, 0, 0),以便于前面应用 TWEEN 实现翻转动画成果。

// 场景
container = document.getElementById('container');
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
scene = new THREE.Scene();
// 增加背景图片
scene.background = new THREE.TextureLoader().load(background);
// 相机
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(-12, 0, 0);
camera.lookAt(new THREE.Vector3(0, 0, 0));
// 直射光
light = new THREE.DirectionalLight(0xffffff, 1);
light.intensity = .2;
light.position.set(10, 10, 30);
light.castShadow = true;
light.shadow.mapSize.width = 512 * 12;
light.shadow.mapSize.height = 512 * 12;
light.shadow.camera.top = 100;
light.shadow.camera.bottom = - 50;
light.shadow.camera.left = - 50;
light.shadow.camera.right = 100;
scene.add(light);
// 环境光
ambientLight = new THREE.AmbientLight(0xdddddd);
scene.add(ambientLight);

创立漫画主体

首先创立一个 Group,用于增加图层网格,而后遍历图层背景图片数组,在循环体中创立每个面的网格,该网格应用立体立方体 PlaneGeometry,材质应用物理材质 MeshPhysicalMaterial,对每个网格地位设置雷同的x轴和y轴值和不同的z轴值以创立景深成果。最初将 Group 增加到场景 Scene 中。

var layerGroup = new THREE.Group();
let aspect = 18;
for (let i=0; i<layers.length; i++) {
  let mesh = new THREE.Mesh(new THREE.PlaneGeometry(10.41, 16), new THREE.MeshPhysicalMaterial({
    map: new THREE.TextureLoader().load(layers[i]),
    transparent: true,
    side: THREE.DoubleSide
  }));
  mesh.position.set(0, 0, i);
  mesh.scale.set(1 - (i / aspect), 1 - (i / aspect), 1 - (i / aspect));
  layerGroup.add(mesh);
  // 文字
  if (i === 5) {
    mesh.material.metalness = .6;
    mesh.material.emissive = new THREE.Color(0x55cfff);
    mesh.material.emissiveIntensity = 1.6;
    mesh.material.opacity = .9;
  }
  // 会话框
  if (i === 6) {
    mesh.scale.set(1.5, 1.5, 1.5);
    animateLayer = mesh;
  }
}
layerGroup.scale.set(1.2, 1.2, 1.2);

到这一步,实现成果如下图所示:

💡 THREE.Group 层级模型

将具备雷同主体的网格能够通过 Group 合并在一起,以便于进步运行效率。Three.js 层级模型 Group 的基类是 Object3D,它是 Three.js 中大部分对象的基类,提供了一系列的属性和办法来对三维空间中的物体进行操纵。如能够通过 .add(object) 办法来将对象进行组合,该办法将对象增加为子对象。

但最好应用 Group 来作为父对象,因为 Group 相比拟Object3D 更语义化,能够应用 Group 作为点、线、网格等模型的父对象,用来构建一个层级模型。

创立Boom背景

为了增强视觉效果,我增加了一个💥 Boom 爆炸图形立体作为背景,用鼠标挪动的时候随着光线的变动,能够看到该图案有金属突变成果,这种成果次要是通过高光材质 MeshPhongMaterialspecularshininess 属性实现的。

const boom = new THREE.Mesh(new THREE.PlaneGeometry(36.76, 27.05), new THREE.MeshPhongMaterial({
  map: new THREE.TextureLoader().load(boomImage),
  transparent: true,
  shininess: 160,
  specular: new THREE.Color(0xff6d00),
  opacity: .7
}));
boom.scale.set(.8, .8, .8);
boom.position.set(0, 0, -3);
layerGroup.add(boom)
scene.add(layerGroup);

增加后成果:

💡 MeshPhongMaterial 高光网格材质

MeshPhongMaterial 是一种用于具备镜面高光的光泽外表的材质。该材质应用非物理的 Blinn-Phong 模型来计算反射率。 与 MeshLambertMaterial 中应用的 Lambertian 模型不同,该材质能够模仿具备镜面高光的光泽外表,如涂漆木材。

构造函数

MeshPhongMaterial(parameters: Object)

parameters:可选,用于定义材质外观的对象,具备一个或多个属性。 材质的任何属性都能够从此处传入(包含从Material继承的任何属性)。

非凡属性

  • .emissive[Color]:材质的喷射光色彩,基本上是不受其余光照影响的固有色彩。默认为 彩色
  • .emissiveMap[Texture]:设置发光贴图。默认值为 null。喷射贴图色彩由喷射色彩和强度所调节。
  • .emissiveIntensity[Float]:喷射光强度。调节发光色彩。默认为 1
  • .envMap[TextureCube]:环境贴图。默认值为 null
  • .isMeshPhongMaterial[Boolean]:用于查看此类或派生类是否为 Phong 网格材质。默认值为 true
  • .lightMap[Texture]:光照贴图。默认值为 null
  • .lightMapIntensity[Float]:烘焙光的强度。默认值为 1
  • .reflectivity[Float]:环境贴图对外表的影响水平。默认值为 1,无效范畴介于 0(无反射)1(齐全反射) 之间。
  • .refractionRatio[Float]:空气的折射率除以材质的折射率。折射率不应超过 1。默认值为 0.98
  • .shininess[Float].specular 高亮的水平,越高的值越闪亮。默认值为 30
  • .skinning[Boolean]:材质是否应用蒙皮。默认值为 false
  • .specular[Color]:材质的高光色彩。默认值为 0x111111 的色彩 Color。这定义了材质的光泽度和光泽的色彩。
  • .specularMap[Texture]:镜面反射贴图值会影响镜面高光以及环境贴图对外表的影响水平。默认值为 null

📌 应用 Phong 着色模型计算着色时,会计算每个像素的暗影,与 MeshLambertMaterial 应用的 Gouraud 模型相比,该模型的后果更精确,但代价是就义一些性能。

镜头管制、缩放适配、动画

镜头补间动画,镜头切换到正确地位。

Animations.animateCamera(camera, controls, { x: 0, y: 0, z: 20 }, { x: 0, y: 0, z: 0 }, 3600, () => { });

镜头管制,本示例中显示了模型平移以及程度垂直旋转的角度,以达到最好的预览成果。

controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
controls.enableDamping = true;
controls.enablePan = false;
// 垂直旋转角度限度
controls.minPolarAngle = 1.2;
controls.maxPolarAngle = 1.8;
// 程度旋转角度限度
controls.minAzimuthAngle = -.6;
controls.maxAzimuthAngle = .6;

屏幕缩放适配。

window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}, false);

对于会话框图层网格,我给它增加了在一条润滑曲线上左右挪动的动画成果,次要是通过批改它在 x 轴和 y 轴上的 position 来实现的 。

function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
  controls && controls.update();
  TWEEN && TWEEN.update();
  // 会话框摆动动画
  step += 0.01;
  animateLayer.position.x = 2.4 + Math.cos(step);
  animateLayer.position.y = .4 + Math.abs(Math.sin(step));
}

💡 正弦余弦函数创立模型挪动轨迹

应用 step 变量并在函数 Math.cos()Math.sin() 的帮忙下 ,创立出一条润滑的轨迹。step+= 0.01 定义的是球的弹跳速度。

到此,本示例的残缺实现都形容结束了,大家感兴趣的话,能够入手试着把本人喜爱的图片革新成 3D 视图。托付,应用 Three.js 这样展现图片超酷的好吗! 😂

🔗 残缺代码:https://github.com/dragonir/3…

总结

本文知识点次要蕴含的的新常识:

  • THREE.Group 层级模型
  • MeshPhongMaterial 高光网格材质
  • 正弦余弦函数 创立模型挪动轨迹

想理解场景初始化、光照、暗影、根底几何体、网格、材质及其他 Three.js 的相干常识,可浏览我往期文章。转载请注明原文地址和作者。如果感觉文章对你有帮忙,不要忘了一键三连哦 👍

附录

  • [1]. Three.js 实现2022冬奥主题3D趣味页面 🐼
  • [2]. 1000粉!应用Three.js制作一个专属3D奖牌 🥇
  • [3]. Three.js 实现虎年春节3D创意页面
  • [4]. Three.js 实现脸书元宇宙3D动静Logo
  • [5]. Three.js 实现3D全景侦探小游戏
  • [6]. Three.js实现炫酷的酸性格调3D页面
  • [7]. 3dx模型转换为blender反对格局

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理