一步一步教你如何利用threejs加载gltf模型来实现DIY换肤功能。

模型准备

  • 模型制作

    模型可以通过网上下载,也可以自己通过c4d、maya、blender等模型制作软件得到。这里就不叙述有关模型制作的问题,本文中会在blender进行模型的有关设置。

  • 模型导出

    1、导出前设定

    为了在页面中方便后续的操作,在导出模型前,将模型的各个部件拆分好进行命名约定(本文以小车模型为例)具体如下图所示:

    图1

    2、导出模型格式选取

    threejs可以加载的模型有很多中,之前.ojb、.json、.FBX等格式都有讲过参我之前的文章从Maya中把模型搬运至网页的过程首个threejs-3D项目,所以我这里选取官方推荐现在使用的格式.gltf、.glb。

    gltf与glb的区别: gltf文件类似与json格式而glb是以二进制流进行存储。

    3、模型导出

    在blender中直接有gltf格式导出的选项,如果没有特别的要求,按照默认配置导出就可以了。导出界面如下图所示:

    图2

场景建立

  • 使用threejs建立一个场景

首先将需要的东西从threejs (r110) 中引入,然后进行建立场景四部曲:

  import {Scene, WebGLRenderer, PerspectiveCamera, Color} from 'three';

1、Scene

  let scene = new Scene();
scene.background = new Color(0xB3CEFB);
scene.fog = new Fog(scene.background, 1, 100);

2、Camera

  let camera = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 15;

3、Render

  let renderer = new WebGLRenderer({
alpha: true,
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);

4、Animate

  const render = function () {
requestAnimationFrame(render);
renderer.render(scene, camera);
}

然后就会看到一个蓝蓝的场景(因为设置了背景颜色)

加载模型

  • GLTFLoader加载模型至场景
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';

const loader = function () {
let gltfLoader = new GLTFLoader();
gltfLoader.load(
'toycar.glb', // your .glb & .gltf
gltf => {
scene.add(gltf.scene); // 添加至建立好的场景中 // gltf.animations; // Array<THREE.AnimationClip>
// gltf.scene; // THREE.Group
// gltf.scenes; // Array<THREE.Group>
// gltf.cameras; // Array<THREE.Camera>
// gltf.asset; // Object
},
() => {
// ..
},
(error) => {
console.log(error);
}
)
}

GLTFLoader加载成功后会返回一个对象,其中scene.children中会包含所导出的所有部件。具体返回以及参数介绍可以查看参考文档

添加至场景后可以看到一个漆黑的汽车,如下图所示:

图3

这是因为场景中没有光源的照射所以导致漆黑一片,只能看一个轮廓,所以我么需要在建立的场景中增加灯关。

  • 添加灯光

threejs中灯光有很多中,这里我们添加DirectionalLight(平行光)HemisphereLight(半球光)

  import {
DirectionalLight,
DirectionalLightHelper,
HemisphereLight,
HemisphereLightHelper
} from 'three'; // Helper为灯关的辅助线方便调试 let directionalLight = new DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(-4, 8, 4);
let dhelper = new DirectionalLightHelper(directionalLight, 5, 0xff0000); let hemisphereLight = new HemisphereLight(0xffffff, 0xffffff, 0.4);
hemisphereLight.position.set(0, 8, 0);
let hHelper = new HemisphereLightHelper(hemisphereLight, 5); scene.add(directionalLight);
scene.add(hemisphereLight);

添加灯光后效果如图:

图4

  • 阴影渲染

接着我们将设置模型的阴影显示,阴影显示需要光源和投射地(阴影显示的地方),现在我们已经有了光源差投射地,所以我们创建一个地板,让阴影投射至地板上,来达到想要的效果:

  // 制作一个地板
import {PlaneGeometry, MeshPhongMaterial, Mesh} from 'three'; let floorGeometry = new PlaneGeometry(5000, 5000, 1);
let floorMaterial = new MeshPhongMaterial({
color: 0x77F28F,
shininess: 0,
// wireframe: true
});
let floor = new Mesh(floorGeometry, floorMaterial);
floor.rotation.x = -0.5 * Math.PI;
floor.position.y = -2.1; scene.add(floor);

现在我们可以看到一个绿色的地板出现在场景中,但是还是不见车子的阴影,这是因为我们还要对光源、渲染器、模型、地板进行设置才能显示阴影:


// 首先渲染器开启阴影
renderer.shadowMap.enabled = true; // 光源开启阴影
directionalLight.castShadow = true;
directionalLight.shadow.mapSize = new Vector2(1024, 1024); // 地板接受阴影开启
floor.receiveShadow = true; // 模型Mesh开启阴影
gltf.scene.traverse(obj => {
if(obj.isMesh) {
obj.castShadow = true;
obj.receiveShadow = true;
}
})

这时候就可以看到小车的阴影渲染到绘制的地板上了,然后你可能会看到车身上有很多条纹状的黑线,这是因为在渲染阴影中产生了伪影,然后我们可以调节light.shadow.bias来解决

  directionalLight.shadow.bias = -0.001;  // value 自行调节

阴影渲染对比如下图所示:

图5

换肤功能

想要实现各个部件换肤功能,我们需要选中部件,修改选中部件材质来达到我们换肤的功能。

  • 部件选中

选取部件其实比较简单,在场景中加入射线检测就可以了,实现如下:

  import {Vector2, Vector3, Raycaster} from 'three';

  let raycaster = new Raycaster();

  let mouse = new Vector2();

  document.body.addEventListener('click', selectHandler, false);

  const selectHandler = function (ev) {
mouse.x = (ev.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(ev.clientY / window.innerHeight) * 2 + 1; raycaster.setFromCamera(mouse, camera); // 这里我们只检测模型的选中情况
let intersects = raycaster.intersectObjects(gltf.scene.children, true); if (intersects.length > 0) {
let selectedObjects = intersects[0].object;
}
}
  • 设置颜色或者纹理

现在我们得到部件,现在只需要修改材质颜色即可。

核心code如下:

let newMaterial = selectedObjects.material.clone();
newMaterial.color = new Color('#D3C542'); //重新修改颜色
selectedObjects.material = newMaterial;

如果需要用图片,那么更改方式更修改图片类似,先用TextureLoader()加载纹理图,然后设置material.map,最后更新material就可以了。

  • 添加选中效果

这里想增加一个选中部件后,那个部件进行外发光的效果,让用户觉得自己是选中了这个部件。这个外发光的效果可以自己用ShaderMaterial()去实现,我这边用的threejs在postprocessing提供的效果,具体实现如下所示:

  import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer';

  import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass';

  import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass';

  let composer = new EffectComposer(renderer);
let renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass); let outlinePass = new OutlinePass(new Vector2(window.innerWidth, window.innerHeight), scene, camera);
composer.addPass(outlinePass); outlinePass.visibleEdgeColor.set('#130AF2'); // 选中颜色
outlinePass.edgeStrength = 5;
outlinePass.edgeGlow = 1.5; const render = function () {
requestAnimationFrame(render);
composer.render();
}

功能展示(gif图的效果可能没那么好):


图6

至此使用threejs给3d模型的基本操作就是这样的了,剩下的发挥靠自己想象吧。

其它功能效果

  • camera-controls

    模型的旋转控制,这里直接使用threejs提供的控件OrbitControls()

    import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
    
    let controls = new OrbitControls(camera, renderer.domElement);
    controls.enablePan = false;
    controls.maxPolarAngle = Math.PI / 2;
    controls.minPolarAngle = Math.PI / 3;
    controls.enableZoom = false; controls.update();
  • 部件分离动画

    分离动画:简单点解释就是给各个部件的位置设置一个开始的点,一个结束点,然后利用TweenLite、TweenMax进行补间动画, 下面以车声为例子:

    // 车身上移动画
    let component = gltf.scene.getObjectByName('car_body');
    TweenLite.to(component.position, 1.5, {
    y: 5,
    ease: Power4.easeOut
    });
  • 重影动画

    利用threejs的提供的postprocessing来实现部件移动的时候会产生重影,实现如下:

    import { AfterimagePass } from 'three/examples/jsm/postprocessing/AfterimagePass.js';
    
    let afterimagePass = new AfterimagePass();
    
    composer.addPass(afterimagePass);

    功能展示(gif图的效果可能没那么好):


图7

最后的最后

如果以上有啥错误或者有啥要交流的欢迎骚扰:(吃口饭不容易!)

wechat: flowers1225

gmail: asdflowers1225@gmail.com

github: https://github.com/flowers1225

个人网站:https://flowers1225.com/

教你如何利用threejs对3D模型皮肤进行DIY的更多相关文章

  1. threejs和3d各种效果的学习

    写给即将开始threejs学习的自己,各种尝试,各种记忆.不要怕,灰色的年华终会过去. 一个技术学习的快慢,以及你的深刻程度,还有你的以后遇到这个东西的时候的反应速度,很大程度上,取决于你的博客的深刻 ...

  2. WPF利用HelixToolKit后台导入3D模型

    原文:WPF利用HelixToolKit后台导入3D模型 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/m0_37591671/article/de ...

  3. ThreeJS 3d模型简介

    本文主要是对Threejs中加载模型的支持种类进行简单的知识科普. 3ds (.3ds) 3ds是3ds max通用储存文件格式.使用的范围更宽,可被更多的软件识别使用. amf (.amf) AMF ...

  4. 3d模型一般怎么导入到到Threejs中使用

    这是我之前做的一个demo,导入的3d模型文件是obj格式的,需要使用OBJLoader和MTLLoader, mtl文件用于描述多边形可视面貌的材质如果你可以导出obj.mtl文件的话,那么就可以使 ...

  5. 在SAP UI中使用纯JavaScript显示产品主数据的3D模型视图

    在Jerry写这篇文章时,通过Google才知道,SAP其实是有自己的3D模型视图显示解决方案的. 故事要从Right Hemisphere说起,这是一家专业的企业级2D/3D模型浏览及转换的软件供应 ...

  6. ifix中嵌入3d模型初探(一)

    在ifix项目中插入3d模型,是当前工控上位机的一个发展趋势,故而我也来尝尝鲜.利用现有条件,初步打算完成一个工厂俯视3d全景. 基本思路:利用webbrowser+3dmax+three.js来嵌入 ...

  7. 转 threejs中3D视野的缩放实现

    Threejs基础部分学习知道透视相机new THREE.PerspectiveCamera(fov, aspect , near,far)中. fov视野角(拍摄距离)越大,场景中的物体越小.fov ...

  8. Flash Stage3D 在2D UI 界面上显示3D模型问题完美解决

    一直以来很多Stage3D开发者都在为3D模型在2DUI上显示的问题头疼.Stage3D一直是在 Stage2D下面.为了做到3D模型在2DUI上显示通常大家有几种实现方式,下面来说说这几种实现方式吧 ...

  9. three.js实现3D模型展示

    由于项目需要展示3d模型,所以对three做了点研究,分享出来 希望能帮到大家 先看看效果: three.js整体来说 不是很难 只要你静下心来研究研究 很快就会上手的 首先我们在页面上需要创建一个能 ...

随机推荐

  1. Sed 实记 · laoless's Blog

    sed编辑命令 p 打印匹配行 = 打印文件行号 a 在定位行之后追加文本 i 在定位行之前插入文本 d 删除定位行 c 用新文本替换定位文本 s 使用替换模式替换相应模式 r 从另一个文件读取文本 ...

  2. Vimium - 让你体验Geek般的浏览体验

    相信很多电脑高手们都会寻找一一些快捷高效的操作方式,如经常利用键盘的快速操作,让你脱离鼠标,可以让你不用花太多精力地去移动细小的指针进行操作,使得工作的效率提高许多. 不过,实际上很多时候我们还是不得 ...

  3. 记 MySQL优化 20条

    1. 为查询缓存优化你的查询 大多数的MySQL服务器都开启了查询缓存.这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的.当有很多相同的查询被执行了多次的时候,这些查询结果会被放到一 ...

  4. ip修改成域名

    将ip修改成域名,这样的话可以使程序变得更加健壮,别人不能直接看见你的ip地址. 后来总结下分享给大家.首先找到hosts文件的位置,这个文件是系统dns默认查找的文件. windows 系统:C:\ ...

  5. cmake引用包初探

    应要求使用的是 mediastreamer2 库.以前开发是在tools下注册了一个新的tool,现在应该另行建立一个项目. 好像 CMake 写的项目叫package??? 项目名字是 mstest ...

  6. volatile和synchronized到底啥区别?多图文讲解告诉你

    你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it well enough ...

  7. JS 增删改查操作XML

    效果图: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <titl ...

  8. linux 安装Mosquitto

    这篇博客讲的很好:https://www.cnblogs.com/chen1-kerr/p/7258487.html 此处简单摘抄部分内容 1.下载mosquitto安装包 源码地址:http://m ...

  9. js的变量——基本类型保存在栈中,引用类型保存在堆中

    javascript的基本类型:Undefined,Null,Boolean,Number,String 引用类型:Object,Array,Function 基本类型值在内存中占据固定大小,被保存在 ...

  10. 2020年ubuntu sever1804 安装和配置

    最后一次折腾linux服务器,应该是13的我的VPS.因为转行后,没有及时关注vps续费的问题,结果过期,所有的数据丢失了 当时觉得,反正都不做了,丢了就丢了吧,可现在想起来,实在是太后悔了. 今天, ...