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

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

背景

近期学习了 WebGLThree.js 的一些基础知识,于是想结合最近流行的酸性设计风格,装饰一下个人主页,同时总结一些学到的知识。本文内容主要介绍,通过使用 React + three.js 技术栈,加载 3D模型、添加 3D文字、增加动画、点击交互等,配合样式设计,实现充满设计感的 🤢 酸性风格页面。

基础知识

Three.js

Three.js 是一款基于原生 WebGL封装运行在浏览器中的 3D引擎,可以用它创建各种三维场景,包括了摄影机、光影、材质等各种对象。是一款使用非常广泛的三维引擎。可以在 three.js官方中文文档 进一步深入学习。

酸性设计

酸性设计 一词翻译自 Acid Graphics,起源于 上世纪90年代 的酸浩室音乐、电子舞曲以及嬉皮士文化。在设计领域,这种酸性美学承载一种 自由的主张,怪诞的图形,大胆鲜明的配色,特殊的材料质感,搭配多种字体,组成了独特的酸性设计风格。

总之,鲜艳高饱和度 的色彩组合;黑灰色打底高饱和 荧光色 点缀画面的 五彩斑斓的黑;充满未来感、炫酷、充满科技感的液态金属玻璃铝箔塑料等材质;随机 的元素、图形的布局;不断 重复、裁切、组合 几何图形 等都是酸性设计风格。酸性风格在音乐专辑封面、视觉海报、书籍电影封面、网页设计中也逐渐开始流行。

实现效果

在线预览:https://tricell.fun

实现

3D模型

场景初始化

🌏 创建场景

scene = new THREE.Scene();

📷 初始化相机

透视相机 PerspectiveCamera4个 参数分别是指:视场、长宽比、近面、远面。

camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 1000);
// 设置相机位置
camera.position.set(600, 20, -200);
// 相机聚焦到屏幕中央
camera.lookAt(new THREE.Vector3(0, 0, 0));

💡 初始化光源

添加 半球光源 HemisphereLight:创建室外效果更加自然的光源

light = new THREE.HemisphereLight(0xffffff, 0x444444);
light.position.set(0, 20, 0);
scene.add(light);
light = new THREE.DirectionalLight(0xffffff);
light.position.set(0, 20, 10);
light.castShadow = true;
scene.add(light);

添加 环境光 AmbientLight

var ambiColor = '#0C0C0C';
var ambientLight = new THREE.AmbientLight(ambiColor);
scene.add(ambientLight);

添加辅助工具(可选)

📦 添加辅助网格

GridHelper 可用于添加网格辅助线,也可用于装饰,通过 GridHelper(size, divisions, colorCenterLine, colorGrid) 实现。

  • size:网格宽度,默认值为 10divisions:等分数,默认值为 10
  • colorCenterLine:中心线颜色,默认值为 0x444444
  • colorGrid: 网格线颜色,默认值为 0x888888
var grid = new THREE.GridHelper(1000, 100, 0x000000, 0x000000);
grid.material.opacity = 0.1;
grid.material.transparent = true;
grid.position.set(0, -240, 0);
scene.add(grid);

📦 添加相机控件

通过相机控件 OrbitControls 可以对三维场景进行缩放、平移、旋转操作,本质上改变的并不是场景,而是相机的参数。开发时 OrbitControls.js 需要单独引入。

controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
controls.update();

📦 添加性能查看插件

stats 是一个 Three.js 开发的辅助库,主要用于检测动画运行时的帧数。stats.js 也需要单独引入。

stats = new Stats();
container.appendChild(stats.dom);

加载模型

本文示例用到的 扔铁饼的人 雕像 3D 模型来源于 threedscans.com,可 免费😄 下载使用,本文末尾提供了多个免费模型下载网站,有 200多页 免费模型,大家感兴趣的话可以挑选自己喜欢的模型下载使用。当然,有建模能力的同学,也可以使用 blender3dmax 等专业建模软件生成自己喜欢的模型。

加载 objfbx 模型

需要单独引入 FBXLoader.jsOBJLoader.js.fbx.obj 格式的模型加载方法是一样的。

// var loader = new THREE.FBXLoader();
var loader = new THREE.OBJLoader();
loader.load(model, function (object) {
  object.traverse(function (child) {
    if (child.isMesh) {
      child.castShadow = true;
      child.receiveShadow = true;
    }
  });
  object.rotation.y = Math.PI / 2;
  object.position.set(0, -200, 0);
  object.scale.set(0.32, 0.32, 0.32);
  model = object;
  scene.add(object);
});

加载 gltf 模型

需要单独引入 GLTFLoader.js,加载 .gltf 格式模型方法稍有不同,需要注意的是模型的遍历对象和最终添加到场景中的是 object.scene 而不是 object

var loader = new THREE.GLTFLoader();
loader.load(model, function (object) {
  object.scene.traverse(function (child) {
    if (child.isMesh) {
      child.castShadow = true;
      child.receiveShadow = true;
    }
  });
  object.scene.rotation.y = Math.PI / 2;
  object.scene.position.set(0, -240, 0);
  object.scene.scale.set(0.33, 0.33, 0.33);
  model = object.scene;
  scene.add(object.scene);
});

添加网格、加载完成模型之后的效果如下图所示。

添加转盘动画

通过 requestAnimationFrame 刷新页面的方法添加转盘动画效果。window.requestAnimationFrame() 告诉浏览器希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。

function animate () {
  requestAnimationFrame(animate);
  // 随着页面重绘不断改变场景的rotation.y来实现旋转
  scene.rotation.y -= 0.015;
  renderer.render(scene, camera);
}

添加点击交互

Three.js 场景中我们要点击某个模型获取它的信息、或者做一些其他操作,要用到 Raycaster(光线投射),原理就是在你鼠标点击的位置发射一束射线,被射线中的物体都被记录下来。基本语法是 Raycaster(origin, direction, near, far),其中:

  • origin:射线的起点向量。
  • direction:射线的方向向量。
  • near:所有返回的结果应该比 near 远。值不能为负,默认值为 0
  • far:所有返回的结果应该比 far 近。不能小于 near,默认值为 无穷大

代码实现的基本步骤是:获取鼠标在屏幕的坐标 屏幕坐标转标准设备坐标 标准设备坐标转世界坐标 拿到鼠标在场景的世界坐标 根据世界坐标和相机生成射线投射方向单位向量 根据射线投射方向单位向量创建射线投射器对象。

//声明raycaster和mouse变量
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
onMouseClick = event => {
  // 将鼠标点击位置的屏幕坐标转成threejs中的标准坐标,以屏幕中心为原点,值的范围为-1到1.
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
  // 通过鼠标点的位置和当前相机的矩阵计算出raycaster
  raycaster.setFromCamera(mouse, camera);
  // 获取raycaster直线和所有模型相交的数组集合
  let intersects = raycaster.intersectObjects(scene.children);
  if (intersects.length > 0) {
    alert('HELLO WORLD')
    // 可以通过遍历实现点击不同mesh触发不同交互,如:
    let selectedObj = intersects[0].object;
    if (selectedObj.name === 'car') {
      alert('汽车🚗')
    }
  }
}
window.addEventListener('click', onMouseClick, false);

添加3D文字

使用 TextGeometry(text : String, parameters : Object) 添加 3D文字,以下是可设置属性的说明:

  • size:字号大小,一般为大写字母的高度。
  • height:文字的厚度。weight:值为 normalbold,表示是否加粗。
  • font:字体,默认是 helvetiker,需对应引用的字体文件。
  • style:值为 normalitalics,表示是否斜体
  • bevelThickness:倒角厚度。
  • bevelSize:倒角宽度。
  • curveSegments:弧线分段数,使得文字的曲线更加光滑。
  • bevelEnabled:布尔值,是否使用倒角,意为在边缘处斜切。
var loader = new THREE.FontLoader();
loader.load('gentilis_regular.typeface.json', function (font) {
  var textGeo = new THREE.TextGeometry('HELLO WORLD', {
    font: font,
    size: .8,
    height: .8,
    curveSegments: .05,
    bevelThickness: .05,
    bevelSize: .05,
    bevelEnabled: true
  });
  var textMaterial = new THREE.MeshPhongMaterial({ color: 0x03c03c });
  var mesh = new THREE.Mesh(textGeo, textMaterial);
  mesh.position.set(0, 3.8, 0);
  scene.add(mesh);
});

优化

现在模型加载已经基本完成了,但是 3D 模型的体积一般比较大,部署之后我发现网页加载非常慢,影响用户体验,减小模型体积是十分必要的,在网上找了很久压缩工具,发现在不需要安装大型 3D建模软件 的情况下,使用 obj2gltf 可以将体积较大的 OBJ 格式模型转化为 gltf 模型,有效优化模型体积,提升网页加载速度。

安装

npm install obj2gltf --save

将obj模型复制到以下目录中

node_modules\obj2gltf\bin

执行转码指令

node obj2gltf.js -i demo.obj -o demo.gltf

如图出现类似上述内容,转码完成,对比转化前后的文件体积,本例中 kas.obj 初始文件大小为 9.7M 转化后的文件 kas.gltf 只有 4.6M,体积缩小一半,此时将转化后的模型加载到页面上,肉眼几乎看不出模型效果的变化,同时页面加载速度得到明显提升。

obj2gltf 也可以作为库使用,通过 node服务 实时转化模型,感兴趣的同学可以通过文章末尾链接深入学习。
也可以是使用 3D 建模软件如 blender 等手动通过减少模型 面数缩小体积 等途径对模型压缩优化,这种优化效果更明显。

完整代码

var model = require('@/assets/models/kas.gltf');
var container, stats, controls;
var camera, scene, renderer, light, model;
class Kas extends React.Component {
  render () {
    return (
      <div id="kas"></div>
    )
  }
  componentDidMount () {
    this.initThree();
  }
  initThree () {
    init();
    animate();
    function init () {
      container = document.getElementById('kas');
      scene = new THREE.Scene();
      scene.fog = new THREE.Fog(0xa0a0a0, 200, 1000);
      // 透视相机:视场、长宽比、近面、远面
      camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 1000);
      camera.position.set(600, 20, -200);
      camera.lookAt(new THREE.Vector3(0, 0, 0));
      // 半球光源:创建室外效果更加自然的光源
      light = new THREE.HemisphereLight(0xffffff, 0x444444);
      light.position.set(0, 20, 0);
      scene.add(light);
      light = new THREE.DirectionalLight(0xffffff);
      light.position.set(0, 20, 10);
      light.castShadow = true;
      scene.add(light);
      // 环境光
      var ambiColor = '#0C0C0C';
      var ambientLight = new THREE.AmbientLight(ambiColor);
      scene.add(ambientLight);
      // 网格
      var grid = new THREE.GridHelper(1000, 100, 0x000000, 0x000000);
      grid.material.opacity = 0.1;
      grid.material.transparent = true;
      grid.position.set(0, -240, 0);
      scene.add(grid);
      // 加载gltf模型
      var loader = new THREE.GLTFLoader();
      loader.load(model, function (object) {
        object.scene.traverse(function (child) {
          if (child.isMesh) {
            child.castShadow = true;
            child.receiveShadow = true;
          }
        });
        object.scene.rotation.y = Math.PI / 2;
        object.scene.position.set(0, -240, 0);
        object.scene.scale.set(0.33, 0.33, 0.33);
        model = object.scene;
        scene.add(object.scene);
      });
      renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setSize(window.innerWidth, window.innerHeight);
      renderer.setClearAlpha(0);
      renderer.shadowMap.enabled = true;
      container.appendChild(renderer.domElement);
      window.addEventListener('resize', () => {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
      }, false);
      stats = new Stats();
      container.appendChild(stats.dom);
    }
    function animate () {
      var clock = new THREE.Clock()
      requestAnimationFrame(animate);
      var delta = clock.getDelta();
      scene.rotation.y -= 0.015;
      renderer.render(scene, camera);
      stats.update();
    }
    // 增加点击事件
    //声明raycaster和mouse变量
    var raycaster = new THREE.Raycaster();
    var mouse = new THREE.Vector2();
    function onMouseClick(event) {
      // 通过鼠标点击位置计算出raycaster所需要点的位置,以屏幕中心为原点,值的范围为-1到1.
      mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
      mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
      // 通过鼠标点的位置和当前相机的矩阵计算出raycaster
      raycaster.setFromCamera(mouse, camera);
      // 获取raycaster直线和所有模型相交的数组集合
      var intersects = raycaster.intersectObjects(scene.children);
      if (intersects.length > 0) {
        alert('HELLO WORLD')
      }
    }
    window.addEventListener('click', onMouseClick, false);
  }
}

其他设计元素

本文主要介绍 3D元素 的加载,由于文章篇幅以及时间有限(博主太懒😂)其他元素的实现不做详细讲解(可能后续有时间会总结整理 maybe)感兴趣的同学可以扩展阅读以下其他大神优秀的文章。

流体背景

静态 液态背景图可以通过 SVG filter 实现,可以阅读《Creating Patterns With SVG Filters》,实现 动态 流体背景,可以使用Three.js 结合原生GLSL实现,可参考《CodePen Shader Template》示例来实现。

金属、霓虹、故障效果等酸性效果字体可以阅读我的另一篇文章《仅用CSS几步实现赛博朋克2077风格视觉效果》,也可以使用设计生成,由于时间关系,本文项目中的金属效果文字以及本文banner头图中的文字都是使用在线艺术字体生成网站生成的,感兴趣的同学可以自行尝试设计。

未来进一步优化

  • #todo 酸性风格液态背景实现。
  • #todo 3D模型液态金属效果。

three.js 优秀案例推荐

最后给大家推荐几个非常惊艳的 three.js 项目来一起体验和学习,无论是页面交互、视觉设计还是性能优化都做到了极致,可以从中学到很多。

github首页3D地球 实时显示全球热门仓库。

kodeclubs:低面数 3D城市 第三人称小游戏。

球鞋展示720度 球鞋动态展示。

沙雕dance:沙雕动物舞者。

Zenly软件Zenly App 中文主页。

参考资料

three.js: https://threejs.org

obj2gltf: https://github.com/CesiumGS/obj2gltf

200多页免费3d模型 https://www.turbosquid.com

免费3D雕像: https://threedscans.com

免费3D模型:https://free3d.com

艺术字体在线生成:https://cooltext.com

什么是酸性设计:https://www.shejipi.com/361258.html

作者:dragonir 本文地址:https://www.cnblogs.com/dragonir/p/15350537.html

到此这篇关于使用three.js实现炫酷的酸性风格3D页面的文章就介绍到这了,更多相关three.js酸性风格3D页面内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • vue页面引入three.js实现3d动画场景操作

    vue中安装Three.js 近来无聊顺便研究一些关于3D图形化库.three.js是JavaScript编写的WebGL第三方库.Three.js 是一款运行在浏览器中的 3D 引擎,你可以用它通过控制相机.视角.材质等相关属性来创造大量3D动画场景. 我们开始引入three.js相关插件. 1.首先利用淘宝镜像,操作命令为: cnpm install three 2.接下来利用npm安装轨道控件插件: 关注我的微信公众号[前端基础教程从0开始],加我微信,可以免费为您解答问题.回复"1&qu

  • three.js中3D视野的缩放实现代码

    通过Threejs基础学习--修改版知道创建一个相机的相关知识点 var camera = new THREE.PerspectiveCamera( fov, aspect , near,far ); 视野角:fov 这里视野角(有的地方叫拍摄距离)越大,场景中的物体越小,视野角越小,场景中的物体越大 纵横比:aspect   (3d物体的宽/高比例) 相机离视体积最近的距离:near 相机离视体积最远的距离:far 其中fov视野角(拍摄距离)越大,场景中的物体越小.fov视野角(拍摄距离)越

  • 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的使用及绘制基础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源码阅读笔记(Object3D类)

    这是Three.js源码阅读笔记的第二篇,直接开始. Core::Object3D Object3D似乎是Three.js框架中最重要的类,相当一部分其他的类都是继承自Object3D类,比如场景类.几何形体类.相机类.光照类等等:他们都是3D空间中的对象,所以称为Object3D类.Object3D构造函数如下: 复制代码 代码如下: THREE.Object3D = function () { THREE.Object3DLibrary.push( this ); this.id = THR

  • Three.js实现简单3D房间布局

    本文实例为大家分享了Three.js实现简单3D房间布局的具体代码,供大家参考,具体内容如下 废话不说了,直接上成果图. 代码如下 <!doctype html> <html lang="en"> <head> <title>房间布局</title> <meta charset="utf-8"> <meta name="viewport" content="w

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

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

  • js实现炫酷光感效果

    本文实例为大家分享了js实现炫酷光感效果的具体代码,供大家参考,具体内容如下 首先写一个大盒子 <div class="main"></div> 然后给这个大盒子添加样式 * { margin: 0; padding: 0; } html, body { height: 100%; overflow: hidden; } body { background: darkblue; } .main { width: 8px; height: 8px; positio

  • JS实现炫酷轮播图

    本文实例为大家分享了JS实现炫酷轮播图的具体代码,供大家参考,具体内容如下 效果图 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta

  • js实现炫酷的烟花效果

    本文实例为大家分享了js实现炫酷的烟花效果的具体代码,供大家参考,具体内容如下 我们要理清整个流程的思路. 首先建立一块画布,用于展示烟花的效果,然后就要去思考烟花燃放的流程,我们都知道烟花通常都是先有一份飞上天,然后再分散成很多个小烟花,并且每一个小烟花都有不同的样式以及运动方式. 所有整体思路就是先建立一个div作为我们的大烟花,当大烟花运动到我们鼠标点击的位置的时候,大烟花就会消失,然后就会产生更多的小烟花,并且这些小烟花的运动轨迹样式各不相同. 1.建立一块画布(div)用于展示烟花的效

  • vue+three.js实现炫酷的3D登陆页面示例详解

    目录 前言: Three.js的基础知识 关于场景 关于光源 关于相机(重要) 关于渲染器 完善效果 创建一个左上角的地球 使地球自转 创建星星 使星星运动 创建云以及运动轨迹 使云运动 完成three.js有关效果 结语 前言: 大家好,我是xx传媒严导(xx这两个字请自行脑补) . 该篇文章用到的主要技术:vue3.three.js 我们先看看成品效果: 高清大图预览(会有些慢): 座机小图预览: 废话不多说,直接进入正题 Three.js的基础知识 想象一下,在一个虚拟的3D世界中都需要什

  • C#实现炫酷启动图-动态进度条效果

    一.简述 最近接到一个新需求,让做一个动效进度条. 由于我们的产品比较大,在软件启动的时候会消耗比较长的时间,原生的进度条已经不能满足我们的需求,这里我们就需要一个会动的进度条,效果如下图所示. 光效进度条主要是做了一个进度动画,在已完成的部分上进行快速的迭代渲染,给用户一种直观感受,我们的软件一直努力加载,它还活着. 有了这个进度条之后,当我们的进度从40%到50%这个持续的过程中,界面再也不会出现假死的情况,是不是很完美呢... 下面我就来分析下这个动效进度条是怎么做的 二.动效进度条 如效

  • Qt实现炫酷启动图动态进度条效果

    目录 一.简述 二.动效进度条 1.光效进度条 2.延迟到达进度条 3.接口说明 三.启动图 1.实现思路 2.背景图切换 四.测试 1.构造启动图 2.背景图 3.其他信息 4.事件循环 五.源码 一.简述 最近接到一个新需求,让做一个动效进度条. 由于我们的产品比较大,在软件启动的时候会消耗比较长的时间,原生的进度条已经不能满足我们的需求,这里我们就需要一个会动的进度条,效果如下图所示. 光效进度条主要是做了一个进度动画,在已完成的部分上进行快速的迭代渲染,给用户一种直观感受,我们的软件一直

  • three.js实现炫酷的全景3D重力感应

    本文实例为大家分享了three.js 全景重力感应的具体代码,供大家参考,具体内容如下 实现three.js 全景图 demo 使用three.js 写了球体和圆柱体版本的3D重力感应全景图,支持手指触摸和陀螺仪感应,也支持PC端的鼠标.给大家介绍一下基于移动端H5球体的实现方法,圆柱体类似. 设置容器和展示的样式 设置容器的宽高为全屏展示,清除body的margin,引用three.min.js(3D渲染框架) 和orienter.js (陀螺仪经纬度计算) <div id="Canva

  • js实现炫酷的左右轮播图

    本文实例为大家分享了js左右轮播图的具体代码,供大家参考,具体内容如下 html代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta keyword="左右轮播图-效果比较好"> <title>Document</title> <link rel="style

  • JS实现炫酷雪花飘落效果

    用js实现漂亮的雪花飘过效果: 步骤: 页面基本样式,雪花旋转动画效果 body{ width: 100vw; height: 100vh; background-color: #000; overflow: hidden; user-select: none; -webkit-user-select: none; } .snowAnimation { animation: snow 5s infinite linear; -webkit-animation: snow 5s infinite

随机推荐