Three.js+React使二维图片呈现3D效果

目录
  • 背景
  • 效果
  • 实现
    • 素材制作
    • 资源引入
    • 场景初始化
    • 创建漫画主体
    • 创建Boom背景
    • 镜头控制、缩放适配、动画
  • 总结

背景

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

效果

实现效果如下图所示:页面主要有背景图、漫画图片主体以及 Boom 爆炸背景图片构成,按住鼠标左键移动模型可以获得不同视图,让图片在视觉上有 3D 景深效果。

已适配:

PC端

移动端

在线预览:https://dragonir.github.io/3d/#/comic

实现

本文实现比较简单,和我前面几篇文章实现基本上是相同的,流程也比较简单,主要是素材准备流程比较复杂。下面看看具体实现方法。

素材制作

准备一张自己喜欢的图片作为素材原图,图片内容最好可以分成多个层级,以实现 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 爆炸图形平面作为背景,用鼠标移动的时候随着光线的变化,可以看到该图案有金属渐变效果,这种效果主要是通过高光材质 MeshPhongMaterial 的 specular 和 shininess 属性实现的。

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/3d/tree/master/src/containers/Comic

总结

本文知识点主要包含的的新知识:

THREE.Group 层级模型

MeshPhongMaterial 高光网格材质

正弦余弦函数 创建模型移动轨迹

以上就是Three.js+React使二维图片呈现3D效果的详细内容,更多关于Three.js React图片3D效果的资料请关注我们其它相关文章!

(0)

相关推荐

  • Three.js实现3D机房效果

    3D机房系统是最近用户的需求,通过相关了解最后使用Three.js,也发现最近有东西可以写出来分享: webGL可以让我们在canvas上实现3D效果.而three.js是一款webGL框架,由于其易用性被广泛应用 Three.js是通过对WebGL接口的封装与简化而形成的一个易用的图形库 分步实现3D效果 初始化3D模型参数 开始搭建场景 初始化渲染器 初始化摄像机 创建场景 灯光布置 创建网格线 循环渲染界面 创建鼠标控制器 添加对象到场景中 一 . 初始化3D模型参数 //参数处理 thi

  • three.js如何实现3D动态文字效果

    前言 大家好,这里是 CSS 魔法使--alphardex. 之前在逛国外网站的时候,发现有些网站的文字是刻在3D图形上的,并且能在图形上运动,视觉效果相当不错,于是笔者就也想用three.js来尝试复现出这种效果 上图只是所有效果的其中之一,接下来让我们一起开干吧~ 准备工作 笔者自行封装的three.js模板:Three.js Starter 读者可以点击右下角fork一份后再开始本项目 本项目需要用到位图字体,可以直接复制demo的HTML里的font字体代码 一个注意点:three-bm

  • 基于Three.js制作一个3D中国地图

    目录 1.使用geoJson绘制3d地图 1.1 创建场景相关 1.2 根据json绘制地图 2.增加光照 3.增加阴影模糊 4.增加鼠标事件 5.渲染 6.动画效果 不想看繁琐步骤的,可以直接去github下载项目,如果可以顺便来个star哈哈 本项目使用vue-cli创建,但不影响使用,主要绘制都已封装成类 1.使用geoJson绘制3d地图 1.1 创建场景相关 // 创建webGL渲染器 this.renderer = new THREE.WebGLRenderer( { antiali

  • Three.js的使用及绘制基础3D图形详解

    一. 前言 Three.js 是一款 webGL(3D绘图标准,在此不赘述)引擎,可以运行于所有支持 webGL 的浏览器.Three.js 封装了 webGL 底层的 API ,为我们提供了高级的开发接口,可以使用简单的代码去实现 3D 渲染.(官网:https://threejs.org/) 二. 为什么要选择Three.js? Three.js 作为原生 web3D 引擎,对插件式 web3D 引擎的优势不言而喻:不需要安装插件.在移动端支持好. Three.js 与其他原生 web3D

  • 使用Three.js制作一个3D奖牌页面

    目录 背景 效果 实现 引入资源 场景初始化 光照效果 Three.js 提供的光源 添加网格和地面 创建奖牌 奖牌UI素材生成 Three.js 中的贴图 MeshPhysicalMaterial 物理材质 特殊属性 加载1000+文字模型 补间动画 动画更新 礼花动画 总结 背景 本文使用 React + Three.js 技术栈,实现粉丝突破1000的3D纪念页面,包含的主要知识点包括:Three.js 提供的光源.DirectionLight 平行光.HemisphereLight 半球

  • 使用three.js实现炫酷的酸性风格3D页面效果

    本文内容主要介绍,通过使用React+three.js技术栈,加载3D模型.添加3D文字.增加动画.点击交互等,配合样式设计,实现充满设计感的

  • three.js实现3D视野缩放效果

    首先,不再废话了,什么是three.js,是干什么的,知道的就是知道,不知道的就百度吧. 小编为大家推荐一篇:Three.js快速入门教程 昨儿发现three.js中的3D视野的缩小和放大效果可以用照相机的远近焦来实现. 缩小后: 这里采用的是透视照相机: //照相机配置 var fov = 40;//拍摄距离 var near = 1;//最小范围 var far = 1000;//最大范围 var camera = new THREE.PerspectiveCamera(fov, windo

  • Three.js+React使二维图片呈现3D效果

    目录 背景 效果 实现 素材制作 资源引入 场景初始化 创建漫画主体 创建Boom背景 镜头控制.缩放适配.动画 总结 背景 逛 sketchfab 网站的时候我看到有很多二维平面转 3D 的模型例子,于是仿照他们的例子,使用 Three.js + React 技术栈,将二维漫画图片转化为三维视觉效果.本文包含的内容主要包括:THREE.Group 层级模型.MeshPhongMaterial 高光网格材质.正弦余弦函数 创建模型移动轨迹等. 效果 实现效果如下图所示:页面主要有背景图.漫画图片

  • Angular JS 生成动态二维码的方法

    一.场景 二维码的场景,很多.这里是二维码一种小场景,比如分享一个链接,商品链接,项目链接,优惠券链接- 技术实现,如果用后端实现,需要构造输出一个图片流.或者后端生产二维码图片,给图片地址就好了.弊端,这个二维码就是一个链接,后端的文件 IO 操作,还得考虑存储.太费力. 如果前端实现,这样就很轻松了.这只是个分享二维码,分享出去给人家扫一扫.利用前端的 canvas,这里坐下调研. jq 封装的 qrcode.js ,文章网上一大堆. angular js :https://github.c

  • 11行JS代码制作二维码生成功能

    HTML代码: <img style="display: none" id="qrcode" data-width="100" data-height="100" data-url="https://www.baidu.com/"> 相关JS代码: /** * 生成二维码 * data-width={宽度} * data-height={高度} * data-url={链接} * @param

  • three.js 制作动态二维码的示例代码

    今天郭先生说一下用canvas解析图片流,然后制作一个动态二维码的小案例,话不多说先上图,这是郭先生的微信二维码哦! 1. 解析图片流 canvas = document.createElement('canvas');//创建canvas画布 content = canvas.getContext('2d');//获取画布的上下文 canvas.width = 310;//设置尺寸 canvas.height = 310; img = new Image();//创建一张图片 img.src

  • JS实现将二维数组转为json格式字符串操作示例

    本文实例讲述了JS实现将二维数组转为json格式字符串操作.分享给大家供大家参考,具体如下: <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>json</title> <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js

  • MNIST数据集转化为二维图片的实现示例

    本文介绍了MNIST数据集转化为二维图片的实现示例,分享给大家,具体如下: #coding: utf-8 from tensorflow.examples.tutorials.mnist import input_data import scipy.misc import os # 读取MNIST数据集.如果不存在会事先下载. mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) # 我们把原始图片保存在MNIST

  • JS仿hao123导航页面图片轮播效果

    hao123网站大家都很熟悉吧,具体的效果不用我多说吧,感兴趣的朋友可以去参考效果图,下面小编给大家分享下实现代码思路,当然大家可以根据需求适当的添加修改删除代码. 关键代码如下所示: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>图片轮播</title> <style> .warp{ wi

  • js实现鼠标移动到图片产生遮罩效果

    本文实例为大家分享了js实现鼠标移动到图片产生遮罩效果的具体代码,供大家参考,具体内容如下 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>mask</title> <style> .pic{ width:300px; height:250px; background:url(icon/pro

  • JS实现的文字与图片定时切换效果代码

    本文实例讲述了JS实现的文字与图片定时切换效果代码.分享给大家供大家参考.具体如下: 这是近来门户们都喜欢用的特效,左侧是一个大图片,右侧是对应文字,鼠标移动时,对应行的文字会变化,图片也相应的切换,如果没有鼠标动作时,它会自己播放,播放时间可调整,个人感觉挺不错的导航效果. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/js-txt-pic-time-cha-tab-codes/ 具体代码如下: <head> <meta http-e

  • js canvas实现二维码和图片合成的海报

    本文实例为大家分享了canvas二维码和图片合成海报的具体代码,供大家参考,具体内容如下 思路:在微信中登录,后台传来的是一个链接.一个名字.一张图片.把图片当做背景,画满整个画布.之后需要把链接转为二维码,使用jq.qrcode转化,转化完成后是一个canvas,把这个canvas再转成一张图片,画到大的画布上.把名字画到画布上.把整张画布转为图片. 一.定义画布和合成海报的img <style type="text/css"> #canbox { width: 100%

随机推荐