美文网首页
官网3D Banner效果 three.js+vue实现

官网3D Banner效果 three.js+vue实现

作者: 郭隆邦技术博客 | 来源:发表于2023-12-17 13:16 被阅读0次

    官网3D Banner效果 three.js+vue实现

    image.png

    最近没什么事,写了一个3D Banner效果,给广大前端同行们分享下。

    在线3D体验地址1:http://www.webgl3d.cn/3D/banner1/index.html

    在线3D体验地址2:http://www.webgl3d.cn/3D/banner3/index.html

    【视频展示】 https://www.bilibili.com/video/BV1Ci4y1e7XX/?share_source=copy_web&vd_source=026f0cd0b145ec9bc2c005d9eaf67b0b

    官网3D Banner

    大部分官网的Banner效果一般是一张背景图片,或者多张图构成的小动画。不过随着webgl的流行,一些官网会用3D模型制作官网的Banner效果。

    3D Banner相比普通的静态图片,视觉效果更好,更立体。

    技术栈

    1. 三维建模软件:Blender
    2. 3D部分代码:three.js引擎
    3. 普通前端部分:Vue + Vite

    普通web前端部分没什么特殊的,主要是3D部分给大家介绍下,整体的思路。

    三维建模软件:Blender

    对于普通的2D网页,一般需要UI设计师,先出设计稿,然后前端写代码。

    对于3D网页效果,类似的流程,首先需要3D美术,使用三维建模软件,绘制3D效果图,然后前端根据3D模型素材写相关代码。

    建模软件:3D建模软件有很多可供选择,比如C4D、Blender,我上面案例就是用的三维建模软件Blender绘制。

    3D代码:Three.js

    为了渲染3D效果,大家需要去了解一个WebGL相关的3D引擎库,就是Three.js。

    如果你不了解threejs,可以参考学习threejs中文网的课程

    参考资料

    Thee.js中文网:http://www.webgl3d.cn/

    步骤1. Vue+Three.js开发环境、第一个3D案例效果

    如果你对threejs有一定基础了,这部分可以跳过。

    视频讲解

    threejs与前端框架结合问题

    有些同学是前端转来过来的,受到平时开发习惯影响,第一反应可能是threejs能不能与vue或react结合。

    其实threejs知识点相对普通web前端是比较独立的,threejs的用法,你直接用.html文件写,还是结合vue或React框架写,API语法都是一样的。

    所以你学习threejs的重点不是考虑前端框架问题,而是threejs本身,掌握了threejs,剩下的事情就很简单了。

    Vue与threejs结合思路

    回顾下前面1.6. 第一个3D案例知识点

    three.js执行渲染方法.render();会输出一个canvas画布renderer.domElement,这个Canvas画布本质上就是一个HTML元素。

    threejs与Vue结合的时候,你只需要把Canvas画布renderer.domElement插入到你的Vue页面上就行,插入任何一个div或其它元素中,或者放到某个Vue组件中都行。

    // WebGL渲染器
    const renderer = new THREE.WebGLRenderer();
    renderer.setSize(width, height); 
    renderer.render(scene, camera);
    //three.js执行渲染命令会输出一个canvas画布(HTML元素)
    document.body.appendChild(renderer.domElement);
    

    接下来,你写的threejs代码结构,并不一定就要和我下面视频完全一致,你可以根据你自己项目情况,自由调整。

    脚手架Vite

    使用脚手架Vite快速创建一个vue工程文件,具体跟着视频可操作即可

    npm create  vite@latest
    

    执行命令npm create vite@latest,然后选择你想要的开发环境即可。

    vite使用文档

    第一步是选择你的前端框架,第二步是选择是否支持TS。

    注意:安装使用Vite之前,确保你电脑已经安装Nodejs了,尽量用最新版本的。

    预览vite项目默认效果

    • 命令行执行npm i,安装所有默认依赖

    • 命令行执行npm run dev,查看vite里面Vue代码默认渲染效果。

    现在你可以把默认的HTML和CSS代码删掉,然后在引入threejs代码。

    npm安装threejs

    安装threesjs时候,你可以指定你想要的版本。

    // 比如安装157版本
    npm install three@0.157.0 -S
    

    Vue中引入threejs代码

    新建index.js文件,把threejs代码写在index.js里面。

    index.js文件引入three.js。

    import * as THREE from 'three';
    

    复制前面课程第一个3D案例的代码,粘贴到index.js文件。

    // 三维场景
    const scene = new THREE.Scene();
    // 模型对象
    const geometry = new THREE.BoxGeometry(50, 50, 50);
    const material = new THREE.MeshBasicMaterial({
        color: 0x0000ff, 
    });
    const mesh = new THREE.Mesh(geometry, material); 
    scene.add(mesh); 
    // AxesHelper:辅助观察的坐标系
    const axesHelper = new THREE.AxesHelper(250);
    scene.add(axesHelper);
    const width = 800; //宽度
    const height = 500; //高度
    // 相机
    const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
    camera.position.set(292, 223, 185);
    camera.lookAt(0, 0, 0);
    // WebGL渲染器
    const renderer = new THREE.WebGLRenderer();
    renderer.setSize(width, height); 
    renderer.render(scene, camera);
    //three.js执行渲染命令会输出一个canvas画布(HTML元素),你可以插入到web页面中
    document.body.appendChild(renderer.domElement);
    

    然后把threejs对应的index.js文件引入到vue的main.js文件中。

    // main.js文件
    import './index.js'// 执行threejs代码
    

    当然你也可以根据需要,在其它Vue组件中调用执行threejs代码。

    设置canvas画布全屏

    上面画布设置了固定宽高度,下面改成文档区域宽高度,也就是所谓canvas画布全屏

    const width = window.innerWidth;
    const height = window.innerHeight;
    const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
    const renderer = new THREE.WebGLRenderer();
    renderer.setSize(width, height);
    
    // 可以放到vite项目style.css文件中
    body{
        // 把canvas画布与body区域边距设置为0
        margin: 0px;
    }
    

    引入扩展库OrbitControls

    查看文件node_modules,在目录three/examples/jsm中,你可以看到threejs的很多扩展库。

    对于这些扩展库,不会一次都引入,一般你用到那个,单独引入即可,下面以OrbitControls为例给大家展示。

    OrbitControls功能就是旋转缩放平移,在1.9小节有具体讲解:1.9. 相机控件OrbitControls,如果还没学习,可以提前看下。

    import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
    

    复制1.9. 相机控件OrbitControls里面关于相机控件的代码。

    // 设置相机控件轨道控制器OrbitControls
    const controls = new OrbitControls(camera, renderer.domElement);
    // 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
    controls.addEventListener('change', function () {
        renderer.render(scene, camera); //执行渲染操作
    });//监听鼠标、键盘事件
    

    步骤2:加载gltf模型

    美术制作好Banner的3D模型之后,可以选择导出gltf格式,当然也可以用别的格式,只是说gltf格式非常常用。

    然后使用threejs的gltf加载器,加载渲染Banner的gltf模型,这样,你就能在网页上看到Banner的3D效果图。

    本节课,以gltf格式为例,给大家讲解加载外部三维模型的整个过程。

    场景、光源、渲染器、相机控件等前面说过基础代码,本节课不专门讲解,主要是把下面三部,给大家全流程演示一遍。

    1. gltf模型加载器GLTFLoader.js
    2. 相机参数根据需要设置
    3. 加载gltf的时候,webgl渲染器编码方式设置

    1.1.引入GLTFLoader.js

    // 引入gltf模型加载库GLTFLoader.js
    import { GLTFLoader } from 'three/examples/jsm//loaders/GLTFLoader.js';
    

    1.2.gltf加载器new GLTFLoader()

    执行new GLTFLoader()就可以实例化一个gltf的加载器对象。

    // 创建GLTF加载器对象
    const loader = new GLTFLoader();
    

    1.3.gltf加载器方法.load()

    通过gltf加载器方法.load()就可以加载外部的gltf模型。

    执行方法.load()会返回一个gltf对象,作为参数2函数的参数,改gltf对象可以包含模型、动画等信息,本节课你只需要先了解gltf的场景属性gltf.scene,该属性包含的是模型信息,比如几何体BufferGometry、材质Material、网格模型Mesh

    loader.load( 'gltf模型.gltf', function ( gltf ) {
      console.log('控制台查看加载gltf文件返回的对象结构',gltf);
      console.log('gltf对象场景属性',gltf.scene);
      // 返回的场景对象gltf.scene插入到threejs场景中
      scene.add( gltf.scene );
    })
    

    相机选择(正投影OrthographicCamera透视投影PerspectiveCamera)

    如果你想预览一个三维场景,一般有正投影相机OrthographicCamera透视投影相机PerspectiveCamera可供选择。不过大部分3D项目,比如一般都是使用透视投影相机PerspectiveCamera,比如游戏、物联网等项目都会选择透视投影相机PerspectiveCamera

    如果你希望渲染的结果符合人眼的远小近大的规律,毫无疑问要选择透视投影相机,如果不需要模拟人眼远小近大的投影规律,可以选择正投影相机。

    尺寸概念

    项目开发的时候,程序员对一个模型或者说一个三维场景要有一个尺寸的概念,不用具体值,要有一个大概印象。

    一般通过三维建模软件可以轻松测试测量模型尺寸,比如作为程序员你可以用三维建模软件blender打开gltf模型,测量尺寸。

    单位问题

    three.js的世界并没有任何单位,只有数字大小的运算。

    obj、gltf格式的模型信息只有尺寸,并不含单位信息。

    不过实际项目开发的时候,一般会定义一个单位,一方面甲方、前端、美术之间更好协调,甚至你自己写代码也要有一个尺寸标准。比如一个园区、工厂,可以m为单位建模,比如建筑、人、相机都用m为尺度去衡量,如果单位不统一,就需要你写代码,通过.scale属性去缩放。

    设置合适的相机参数

    通过gltf加载完成,模型后,你还需要根据自身需要,设置合适的相机参数,就好比你拍照,你想拍摄一个石头,肯定要把相机对着石头,如果希望石头在照片上占比大,就要离石头近一些。

    相机位置怎么设置,你就类比你的眼睛,如果你想模拟人在3D场景中漫游,那么很简单,你把相机放在地面上,距离地面高度和人身高接近即可。

    如果你想看到工厂的全貌,你可以理解为你坐着无人机向下俯瞰,简单说,相比人漫游工厂,整体预览工厂相机距离工厂距离更远一些,否则你也看不到全貌,当然过于远了,你就看不清工厂了。

    以课程工厂为例,先设定一个小目标,我们希望工厂能够居中显示在canvas画布上,并且保证可以整体预览。

    下面以透视投影相机PerspectiveCamera为例说明。

    2.1.相机位置.position

    工厂尺寸范围大概200米数量级,那么如果想整体预览观察工厂所有模型,那很简单,第一步,把camera.position的xyz值统统设置为几百即可,比如(200, 200, 200)

    具体xyz值,你可以通过OrbitControls可视化操作调整,然后浏览器控制台记录相机参数即可。

    camera.position.set(200, 200, 200);
    

    2.2 某位置在canvas画布居中

    你需要工厂那个位置在canavs画布上居中,直接把camera.lookAt()指向哪个坐标。

    如果美术建模,把工厂整体居中,也就是说模型的几何中心,大概位于世界坐标原点。你设置camera.lookAt(0,0,0),相机视线指向坐标原点。

    camera.lookAt(0, 0, 0);
    

    注意相机控件OrbitControls会影响lookAt设置,注意手动设置OrbitControls的目标参数

    
    camera.lookAt(100, 0, 0);
    // 设置相机控件轨道控制器OrbitControls
    const controls = new OrbitControls(camera, renderer.domElement);
    // 相机控件.target属性在OrbitControls.js内部表示相机目标观察点,默认0,0,0
    // console.log('controls.target', controls.target);
    controls.target.set(100, 0, 0);
    controls.update();//update()函数内会执行camera.lookAt(controls.targe)
    

    2.3.远裁截面far参数

    近裁截面near和远裁截面far,要能包含你想渲染的场景,否则超出视锥体模型会被剪裁掉,简单说near足够小,far足够大,主要是far。

    PerspectiveCamera(fov, aspect, near, far)

    测量工厂尺寸大概几百的数量级,这里不用测具体尺寸,有个大概数量级即可,然后far设置为3000足够了。

    const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
    

    3.纹理贴图颜色偏差解决

    three.js加载gltf模型的时候,可能会遇到three.js渲染结果颜色偏差,对于这种情况,你只需要修改WebGL渲染器默认的编码方式.outputEncoding即可

    //解决加载gltf格式模型纹理贴图和原图不一样问题
    renderer.outputEncoding = THREE.sRGBEncoding;
    

    注意!!!!!!!最新版本属性名字有改变。渲染器属性名.outputEncoding已经变更为.outputColorSpace

    查WebGL渲染器文档,你可以看到.outputColorSpace的默认值就是SRGB颜色空间THREE.SRGBColorSpace,意味着新版本代码中,加载gltf,没有特殊需要,不设置.outputColorSpace也不会引起色差。

    //新版本,加载gltf,不需要执行下面代码解决颜色偏差
    renderer.outputColorSpace = THREE.SRGBColorSpace;//设置为SRGB颜色空间
    

    步骤3:材质效果

    作为Banner,肯定需要比较好的材质效果,不能随随便便加载一个gltf模型,这样的材质效果不会太好。

    一般来说首先美术在Blender软件中,可以设置PBR材质的相关属性,比如玻璃材质的金属度、粗糙度、透射度等属性,然后导出gltf格式模型的时候,这些PBR材质属性可以跟随导出。threejs加载gltf模型的时候,会自动解析相关的材质属性。

    尤其是上面Banner中的玻璃材质,为了更好的3D效果,最好设置好环境贴图,这样玻璃质感才会更强烈。

    // 加载环境贴图
    const textureCube = new THREE.CubeTextureLoader()
        .setPath('./环境贴图/环境贴图0/')
        .load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']);
    new THREE.MeshStandardMaterial({
        metalness: 1.0,
        roughness: 0.5,
        envMap: textureCube, //设置pbr材质环境贴图
    })    
    
    obj.material.envMap = textureCube; //设置环境贴图 
    

    补充内容:PBR材质介绍

    本节课没有具体的代码,就是给大家科普一下PBR材质,所谓PBR就是,基于物理的渲染(physically-based rendering)。

    Three.js提供了两个PBR材质相关的APIMeshStandardMaterialMeshPhysicalMaterial,MeshPhysicalMaterialMeshStandardMaterial扩展的子类,提供了更多功能属性。

    光照模型

    如果你有初高中最基本的物理光学知识,应该有折射、镜面反射、漫反射等基本光学概念,对于实际生活中的光学问题,Three.js会提供一些的光照模型来模拟物体表面的光照,光照模型就一种模拟光照的计算方法。MeshPhysicalMaterialMeshLambertMaterial一样都是渲染网格模型的材质,但是他们用的光照模型不同,具体点说就是材质模拟Mesh反射光照的代码算法不同,算法不同,自然模拟光照的真实程度也不同。

    如果你想深入研究光照模型,可以学习下原生WebGL或WebGPU,或者看看计算机图形学相关书籍,使用threejs的大部分情况,用不着你自己实现光照模型算法,毕竟threejs通过网格模型材质帮你实现了。

    PBR相关理论介绍文章

    网格模型材质整体回顾

    • MeshLambertMaterial: Lambert光照模型(漫反射)

    • MeshPhongMaterial:Phong光照模型(漫反射、高光反射)

    • MeshStandardMaterial和MeshPhysicalMaterial:基于物理的光照模型(微平面理论、能量守恒、菲涅尔反射...)

    PBR材质相比MeshLambertMaterial和MeshPhongMaterial可以提供更逼真的、更接近生活中的材质效果,当然也会占用更多的电脑硬件资源。

    通过MeshPhysicalMaterial文档,提供的资源,可以查看多个PBR材质的案例效果,系统课程中轿车展示案例也会用到PBR材质。

    渲染占用资源和表现能力

    整体上来看,就是渲染表现能力越强,占用的计算机硬件资源更多。

    • 占用渲染资源
      MeshBasicMaterial < MeshLambertMaterial < MeshPhongMaterial < MeshStandardMaterial < MeshPhysicalMaterial

    • 渲染表现能力
      MeshBasicMaterial < MeshLambertMaterial < MeshPhongMaterial < MeshStandardMaterial < MeshPhysicalMaterial

    PBR材质金属度和粗糙度(金属效果)

    本节课给大家介绍PBR材质MeshStandardMaterial金属度metalness粗糙度roughness,再加上下节课讲解的环境贴图.envMap,给大家呈现一个金属渲染效果

    金属度metalness

    金属度属性.metalness表示材质像金属的程度, 非金属材料,如木材或石材,使用0.0,金属使用1.0。

    threejs的PBR材质,.metalness默认是0.5,0.0到1.0之间的值可用于生锈的金属外观

    new THREE.MeshStandardMaterial({
        metalness: 1.0,//金属度属性
    })
    
    mesh.material.metalness = 1.0;//金属度
    

    粗糙度roughness

    生活中不同物体表面的粗糙程度不同,比如地面比较粗糙,比如镜子表面就非常非常光滑。

    粗糙度roughness表示模型表面的光滑或者说粗糙程度,越光滑镜面反射能力越强,越粗糙,表面镜面反射能力越弱,更多地表现为漫反射。

    粗糙度roughness,0.0表示平滑的镜面反射,1.0表示完全漫反射,默认0.5。

    new THREE.MeshStandardMaterial({
        roughness: 0.5,//表面粗糙度
    })
    
    mesh.material.roughness = 0.5;//表面粗糙度
    

    环境贴图.envMap(金属效果)

    环境贴图对PBR材质渲染效果影响还是比较大,一般渲染PBR材质的模型,最好设置一个合适的环境贴图。

    立方体纹理加载器CubeTextureLoader

    • TextureLoader返回Texture
    • CubeTextureLoader返回CubeTexture

    通过前面学习大家知道,通过纹理贴图加载器TextureLoader.load()方法加载一张图片可以返回一个纹理对象Texture

    立方体纹理加载器CubeTextureLoader.load()方法是加载6张图片,返回一个立方体纹理对象CubeTexture

    立方体纹理对象CubeTexture的父类是纹理对象Texture

    CubeTextureLoader加载环境贴图

    所谓环境贴图,就是一个模型周围的环境的图像,比如一间房子,房子的上下左右前后分别拍摄一张照片,就是3D空间中6个角度方向的照片。

    // 加载环境贴图
    // 加载周围环境6个方向贴图
    // 上下左右前后6张贴图构成一个立方体空间
    // 'px.jpg', 'nx.jpg':x轴正方向、负方向贴图  p:正positive  n:负negative
    // 'py.jpg', 'ny.jpg':y轴贴图
    // 'pz.jpg', 'nz.jpg':z轴贴图
    const textureCube = new THREE.CubeTextureLoader()
        .setPath('./环境贴图/环境贴图0/')
        .load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']);
        // CubeTexture表示立方体纹理对象,父类是纹理对象Texture 
    

    MeshStandardMaterial环境贴图属性.envMap

    实际生活中,一个物体表面,往往会反射周围的环境。人的眼睛看到的东西,往往反射有周围景物,所以three.js渲染模型,如果想渲染效果更好看,如果想更符合实际生活情况,也需要想办法让模型反射周围景物。

    MeshStandardMaterial材质的环境贴图属性是.envMap,通过PBR材质的贴图属性可以实现模型表面反射周围景物,这样渲染效果更好。

    // 加载环境贴图
    const textureCube = new THREE.CubeTextureLoader()
        .setPath('./环境贴图/环境贴图0/')
        .load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']);
    new THREE.MeshStandardMaterial({
        metalness: 1.0,
        roughness: 0.5,
        envMap: textureCube, //设置pbr材质环境贴图
    })    
    
    obj.material.envMap = textureCube; //设置环境贴图 
    

    环境贴图反射率.envMapIntensity

    MeshStandardMaterial.envMapIntensity属性主要用来设置模型表面反射周围环境贴图的能力,或者说环境贴图对模型表面的影响能力。具体说.envMapIntensity相当于环境贴图的系数,环境贴图像素值乘以该系数后,在用于影响模型表面。

    // envMapIntensity:控制环境贴图对mesh表面影响程度
    //默认值1, 设置为0.0,相当于没有环境贴图
    obj.material.envMapIntensity = 1.0;
    

    粗糙度roughness为0

    你可以尝试把粗糙度roughness设置为0,看看模型对环境贴图的反射效果。

    obj.material.roughness = 0.0;//完全镜面反射,像镜子一样
    

    选择合适的环境贴图

    不同的明暗或景物的环境贴图对渲染效果的影响是不一样的,所以不仅要设置环境贴图,还要根据需要选择合适的环境贴图,一般实际开发使用美术提供的环境贴图即可。

    你可以尝试测试源码中提供多个环境贴图对比渲染效果差异。

    纹理和渲染器颜色空间一致

    //如果renderer.outputEncoding=THREE.sRGBEncoding;环境贴图需要保持一致
    textureCube.encoding = THREE.sRGBEncoding;   
    

    环境贴图2

    接着上节课的环境贴图给大家讲解。

    环境贴图作用测试

    实际生活中光源照射到一个物体上,这个物体反射出去的光线也会影响其他的物体,环境贴图就是用一种简单方式,近似模拟一个物体周边环境对物体表面的影响。

    测试:对于PBR材质,如果threejs三维场景不添加任何光源,物体就是完全黑色的,你可以不添加任何光源,尝试只使用环境贴图,你会发现物体表面的颜色也能看到,这说明环境贴图其实相当于提供了物体周围环境发射或反射的光线。

    测试:更换不同明暗的环境贴图,你会发现场景中模型的明暗也有变化。

    场景环境属性.environment

    网格模型可以通过材质的.envMap属性设置环境贴图,如果一个gltf模型中所有的Mesh都要设置环境贴图就需要递归遍历gltf模型,给里面每个Mesh的材质设置.envMap

    loader.load("../工厂.glb", function (gltf) {
        // 递归遍历批量设置环境贴图
        gltf.scene.traverse(function (obj) {
            if (obj.isMesh) { //判断是否是网格模型
                obj.material.envMap = textureCube; //设置环境贴图
            }
        });
    })
    

    如果你希望环境贴图影响场景中scene所有Mesh,可以通过Scene的场景环境属性.environment实现,把环境贴图对应纹理对象设置为.environment的属性值即可。

    // 环境贴图纹理对象textureCube作为.environment属性值,影响所有模型
    scene.environment = textureCube;
    

    环境贴图色彩空间编码.encoding

    //如果renderer.outputEncoding=THREE.sRGBEncoding;环境贴图需要保持一致
    textureCube.encoding = THREE.sRGBEncoding;   
    

    MeshPhysicalMaterial清漆层.clearcoat

    MeshPhysicalMaterialMeshStandardMaterial都是拥有金属度metalness、粗糙度roughness属性的PBR材质,MeshPhysicalMaterial是在MeshStandardMaterial基础上扩展出来的子类,除了继承了MeshStandardMaterial的金属度、粗糙度等属性,还新增了清漆.clearcoat、透光率.transmission、反射率.reflectivity、光泽.sheen、折射率.ior等等各种用于模拟生活中不同材质的属性。

    清漆层属性.clearcoat

    清漆层属性.clearcoat可以用来模拟物体表面一层透明图层,就好比你在物体表面刷了一层透明清漆,喷了点水。.clearcoat的范围0到1,默认0。

    const material = new THREE.MeshPhysicalMaterial( {
        clearcoat: 1.0,//物体表面清漆层或者说透明涂层的厚度
    } );
    

    清漆层粗糙度.clearcoatRoughness

    清漆层粗糙度.clearcoatRoughness属性表示物体表面透明涂层.clearcoat对应的的粗糙度,.clearcoatRoughness的范围是为0.0至1.0。默认值为0.0。

    const material = new THREE.MeshPhysicalMaterial( {
        clearcoat: 1.0,//物体表面清漆层或者说透明涂层的厚度
        clearcoatRoughness: 0.1,//透明涂层表面的粗糙度
    } );
    

    车外壳PBR材质设置

    在设置车外壳清漆层之前,先创建一个MeshPhysicalMaterial材质,并设置好环境贴图、金属度、粗糙度,属性值先根据文档说明给一个大概的值,具体可以通过gui交互界面可视化调试。

    const mesh = gltf.scene.getObjectByName('外壳01');
    mesh.material = new THREE.MeshPhysicalMaterial({
            color: mesh.material.color, //默认颜色
            metalness: 0.9,//车外壳金属度
            roughness: 0.5,//车外壳粗糙度
            envMap: textureCube, //环境贴图
            envMapIntensity: 2.5, //环境贴图对Mesh表面影响程度
    })  
    

    车外壳油漆效果

    车外壳油漆效果,你可以通过PBR材质的清漆层属性.clearcoat和清漆层粗糙度.clearcoatRoughness属性模拟。

    属性值先根据文档说明给一个大概的值,具体可以通过gui交互界面可视化调试。

    const mesh = gltf.scene.getObjectByName('外壳01');
    mesh.material = new THREE.MeshPhysicalMaterial( {
        clearcoat: 1.0,//物体表面清漆层或者说透明涂层的厚度
        clearcoatRoughness: 0.1,//透明涂层表面的粗糙度
    } );
    

    GUI可视化调试PBR材质属性

    关于gui的使用,在第一章节入门中详细将结果,具体使用可以参照前面讲解。

    // 范围可以参考文档
    matFolder.add(mesh.material,'metalness',0,1);
    matFolder.add(mesh.material,'roughness',0,1);
    matFolder.add(mesh.material,'clearcoat',0,1);
    matFolder.add(mesh.material,'clearcoatRoughness',0,1);
    matFolder.add(mesh.material,'envMapIntensity',0,10);
    

    物理材质透光率.transmission

    如果你已经掌握上节课内容,可以继续学习物理材质MeshPhysicalMaterial的透光率属性.transmission和折射率属性.ior

    透光率(透射度).transmission

    为了更好的模拟玻璃、半透明塑料一类的视觉效果,可以使用物理透明度.transmission属性代替Mesh普通透明度属性.opacity

    使用.transmission属性设置Mesh透明度,即便完全透射的情况下仍可保持高反射率。

    物理光学透明度.transmission的值范围是从0.0到1.0。默认值为0.0。

    const mesh = gltf.scene.getObjectByName('玻璃01')
    mesh.material = new THREE.MeshPhysicalMaterial({
        transmission: 1.0, //玻璃材质透光率,transmission替代opacity 
    })
    

    折射率.ior

    非金属材料的折射率从1.0到2.333。默认值为1.5。

    不同材质的折射率,你可以百度搜索。

    new THREE.MeshPhysicalMaterial({
        ior:1.5,//折射率
    })
    

    玻璃透光率.transmission设置

    先设置玻璃金属度和粗糙度

    const mesh = gltf.scene.getObjectByName('玻璃01')
    mesh.material = new THREE.MeshPhysicalMaterial({
        metalness: 0.0,//玻璃非金属 
        roughness: 0.0,//玻璃表面光滑
        envMap:textureCube,//环境贴图
        envMapIntensity: 1.0, //环境贴图对Mesh表面影响程度
    })
    

    设置透光率.transmission和折射率.ior

    new THREE.MeshPhysicalMaterial({
        transmission: 1.0, //玻璃材质透光率,transmission替代opacity 
        ior:1.5,//折射率
    })
    

    GUI可视化调试PBR材质属性

    基本参数和代码设置好以后,就是通过GUI可视化交互界面,调试PBR材质或光源的参数,gui.js库的使用参考入门章节介绍。

    const obj = {
        color: mesh.material.color, // 材质颜色
    };
    // 材质颜色color
    matFolder.addColor(obj, 'color').onChange(function (value) {
        mesh.material.color.set(value);
    });
    // 范围可以参考文档
    matFolder.add(mesh.material,'metalness',0,1);
    matFolder.add(mesh.material,'roughness',0,1);
    matFolder.add(mesh.material,'transmission',0,1);
    matFolder.add(mesh.material,'ior',0,3);
    matFolder.add(mesh.material,'envMapIntensity',0,10);
    

    三维建模软件导出PBR材质属性

    实际开发的时候PBR材质的属性,很多时候是可以在三维建模软件中设置的,然后通过gltf导出即可,这样就不用在threejs代码设置。

    通常美术对三维场景渲染的了解也比大部分前端程序员多的多,只要美术在三维建模软件设置好并导出包含pbr材质属性的gltf即可。

    threejs与建模软件对接的问题

    1. gltf能否存储3D建模软件的某个材质属性:有些三维软件特有的材质属性,不一定能通过gltf导出,也谈不上threejs解析
    2. 三维建模能否导出PBR材质:能导出的话,能导出哪些属性,不能导出哪些属性

    如果你的三维建模不能导出pbr材质,或者部分pbr材质属性无法导出,那你通常需要用代码方式添加材质,这样就麻烦些。

    Blender导出PBR材质演示

    首先Blender最新版导出gltf模型时候,是可以把PBR材质的很多属性导出的,比如金属度metalness、粗糙度roughness、清漆.clearcoat、透光率(透射度).transmission等等。课件源码中提供了blender导出的gltf模型你可以浏览器控制台打印测试,这些PBR材质属性能否解析渲染。

    Bledner中设置PBR材质

    你可以在Bledner中设置车外壳、车玻璃的材质属性

    1. 车外壳:清漆、清漆粗糙度
    2. 车玻璃:透光率(透射度)

    threejs解析gltf材质规则

    大家都知道,MeshPhysicalMaterialMeshStandardMaterial的子类,具有更多的PBR材质属性和功能。

    所以,threejs解析gltf模型,会用两种材质PBR材质去解析,一个是标准网格材质MeshStandardMaterial,一个是物理网格材质MeshPhysicalMaterial,如果能用MeshStandardMaterial表示就用,不能就换MeshPhysicalMaterial

    具体说就是,threejs解析gltf模型材质的时候,一般默认使用标准网格材质MeshStandardMaterial,如果gltf有的材质具有.clearcoat.transmission等属性,标准网格材质MeshStandardMaterial无法表达的时候,会用物理网格材质MeshPhysicalMaterial来解析gltf材质。

    查看threejs解析的PBR材质

    gltf.scene.traverse(function(obj) {
        if (obj.isMesh) {
            console.log('obj.material',obj.material);
        }
    });
    console.log('外壳',mesh1.material);
    console.log('玻璃',mesh2.material);
    

    设置环境贴图

    这时候清漆、清漆粗糙度、透光率(透射度)等属性Bledner都已经设置好了,threejs可以自动解析渲染,不用在代码中麻烦设置了,只要配上环境贴图即可。

    const mesh1 = gltf.scene.getObjectByName('外壳01');
    mesh1.material.envMap = textureCube; //环境贴图
    mesh1.material.envMapIntensity = 1.0; ////环境贴图对Mesh表面影响程度
    const mesh2 = gltf.scene.getObjectByName('玻璃01');
    mesh2.material.envMap = textureCube; //环境贴图
    mesh2.material.envMapIntensity = 1.0; ////环境贴图对Mesh表面影响程度
    

    相关文章

      网友评论

          本文标题:官网3D Banner效果 three.js+vue实现

          本文链接:https://www.haomeiwen.com/subject/cfldlrtx.html