这篇文章将初浅地介绍怎样从三维软件(本文使用3dmax)中建立模型并导出为gltf模型在网页上显示(babylonjs)的全过程。
小场景效果
目录
项目文件:链接:https://pan.baidu.com/s/1SPJ1vH2GFJOZIT2-B_y6PA
提取码:uuxc
3dmax端
1、建模篇
一个三维模型由点、线、面组成。
台灯 台灯-线框图
台灯底座-线框图
在三维软件(3dmax、blender、maya等)中,通过对基础几何体(平面、长方体、球体、柱体、锥体)的编辑变换组合形成一个个的三维网格。例如制作一个枕头的模型,首先建立一个立方体,然后对该立方体设置cloth变换即可。
枕头制作过程
在3Dmax中对基本几何的编辑操作有:平移、缩放、旋转、网格编辑算法等。
由于本人非专业建模技术人员,不熟悉上面所列编辑算法,为了构建一个小场景用于测试,从网络上下载了相关子模型,包括小桌、台灯模型。
建模步骤:1、从sketchfab下载了台灯和桌子的模型;
2、建立正交的三面墙体;
3、导入小桌子模型(fbx格式),进行缩放、平移到场景中;
4、导入台灯模型(3ds格式),平移到桌子上;
5、最终建立的小场景。
小场景线框图 没有贴图的小场景面图
2、材质与贴图篇
在我们的现实世界中,存在各种各样不同的材质,例如布料、木料、玻璃、金属,这些材质在外观上、物理特性上有着不同程度的区别,例如玻璃可以透光、表面光滑、可以反射周围的环境,金属不透明但可以反射更强的光,等等。
为了模拟现实环境中不同的材质,在三维软件中设置了很多的材质属性去调节,例如基础色、反射率、透明度、金属度等等。
但是,由于现实环境特别复杂,三维软件中难以精细化地设置模型每一处的材质,为了方便,人们常常使用拍摄或者电脑制作的图片附加在模型表面,然后在此基础上设置一些参数来模拟物体材质。
在众多的技术中,当下属基于物理的渲染过程(Physically Based Rendering,PBR)最为流行,它广泛应用于游戏(刺激战场、极品飞车)、动画(无敌破坏王)、影视(阿凡达、流浪地球)等领域中,与传统的Lambert着色和Phong着色相比,PBR着色在效果上有质的提升,其能达到更加逼真的效果。PBR有以下几个优势:1、不同的艺术家提供统一的工作流程;2、方法论和算法基于精确的计算公式,免除创作表面的猜想过程;3、在任何光照环境都能表现出正确的结果。
在基于物理纹理的渲染(PBR)中,有两种最常见的工作流程,即金属/粗糙度和高光反射/光泽度。在使用过程中,两种工作流程各有利弊(详见PBR-Guide)。
金属/粗糙度和高光反射/光泽度工作流程
现阶段,各个软件对PBR的支持也越来越好了,3Dmax 2021重点更新了支持PBR的功能。制作PBR贴图的常用工具Substance系列软件,免费下载材质的地址有:Texturehaven。
本例的小场景中,只有墙的材质需要从自己单独下载贴图,桌子和台灯在素材中有贴图。
步骤:1、为桌子重新链接贴图;
2、为台灯重新链接贴图;
3、为墙体添加贴图;由于图片大小限制,未能展示所有贴图添加过程,其余贴图以同样的方式自行添加。
场景效果图
3、灯光
与现实场景一样,还需要灯光才能点亮整个场景。在软件中,常用的有点光(类似灯泡,向四周发光)、聚光灯(一定范围内发光)、面光(类似窗户光)、太阳光(从很远的地方平行照射)。
本场景中在台灯中添加一个点光即可。
至此 ,可以使用渲染器渲染了,小场景算构建完成。
场景中只有一个光源,物体还不够亮。可以通过添加(渲染>环境>环境贴图)HDR环境光来弥补;
另外,还可以直接在渲染>渲染到纹理 菜单中选择导出lightmap。
导出为GLTF
GLTF格式是由Khronos Group制定的一种3D格式,在2017年发布GLTF 2.0。该格式可以有效率的在网络上传输和加载,它最小化了3D资产,同时它还支持扩展,用户可根据需求自定义字段。gltf可以作为一种3D交付格式,允许整个行业对其自由操作3D内容,简化了创作流程和交互服务。
Khronos Group制定的标准
现阶段,各个厂家也在逐渐支持gltf文件。skechfab将fbx、obj等常用格式转为gltf在网页预览并下载;高德地图支持直接在地图上指定位置显示gltf文件;3dmax、blender、maya、revit等三维软件可以直接或间接导出为gltf文件;threejs、babylonjs等web三维显示引擎可以直接显示gltf文件;windows 10系统中自带的3D查看器可直接预览gltf文件。
整个GLTF资产由三类文件组成,一个json文件,它是gltf的核心文件,描述了三维模型的结构和组成;一个二进制文件,其存储了顶点数据、着色方式、动画等信息;还有一类jpg或png格式的图片,它们是资产中使用的贴图。gltf的详细解释如下:
在本例中,在3dmax中使用babylonjs插件导出为gltf格式。
win10中3D查看器预览的效果图
babylonjs端
1、Typescript介绍
Typescript是微软开发的一个开源编程语言,其本身是为了解决JavaScript语言本身的局限性,难以胜任和维护大型项目开发,作者是C#的首席架构师安德斯·海尔斯伯格。
Typescript是Javascript的一个超集,而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。TypeScript扩展了JavaScript的语法,所以任何现有的JavaScript程序可以运行在TypeScript环境中。TypeScript是为大型应用的开发而设计,并且可以编译为JavaScript。TypeScript 支持为已存在的 JavaScript 库添加类型信息的头文件,扩展了它对于流行库的支持,如 jQuery,MongoDB,Node.js 和 D3.js 等。这些第三方库的类型定义本身也是开源的,所有开发者都能参与贡献。
TypeScript 是一种给 JavaScript 添加特性的语言扩展。
●类
●接口
●模块 [11]
语法上,TypeScript 很类似于 JScript .NET,另外一个添加了对静态类型,经典的面向对象语言特性如类,继承,接口和命名空间等的支持的 Microsoft 对 ECMAScript 语言标准的实现。
2、Typescript项目的搭建与打包
本项目编辑工具webstrom。
步骤:1、安装nodejs。nodejs的诞生不仅能够使javascript流畅运行在服务器,而且还解决了很多实际工程中繁琐的事情,比如安装依赖库、打包等问题,类似于python中的pip模块、java中的maven模块。
安装nodejs很简单,只需要在网络上下载nodejs安装包,windows系统直接安装即可。
打开cmd窗口,输入
node -v
显示版本号,即安装成功。
2、在项目文件夹下新建 package.json 文件,该文件描述了项目的信息,其中特别重要的是描述了项目的依赖,具体请参考官方文档。
本项目中仅需要安装babylonjs用于测试。
{
"name": "hello-world",
"version": "1.0.0",
"dependencies": {
"babylonjs": "^5.0.0-alpha.22",
"babylonjs-loaders": "^5.0.0-alpha.22"
}
}
3、新建项目所需文件夹。文件夹命名没有规定,根据个人喜好定义。demo文件夹存放最终html资源文件、资产文件、项目外其他js文件等,相当于一个完整的js项目文件夹;dist文件存放typescript输出的js和map文件;src存放项目源码,本项目为ts文件。
4、新建tsconfig.json文件,该文件配置了typescript编译为js的参数设置,详细解释见官方文档文件解释和编译选项。
本项目中由于使用webpack编译打包,因此此文件只需简略设置即可。
{
"compilerOptions": {
// 详细解释参考请https://www.tslang.cn/docs/handbook/compiler-options.html
"module": "commonjs",//指定生成哪个模块系统代码: "None", "CommonJS", "AMD", "System", "UMD", "ES6"或 "ES2015"。
"target": "es5",// 编译目标
"sourceMap": true // 是否保留map文件,该文件包含ts函数命名解释文件,供调试时使用
},
// 项目排除的文件夹
"exclude": [
"node_modules" // 为node的安装包模块文件夹
],
// 项目包含的源码文件夹
"include": [
"./src/**/*"
]
}
5、新建webpack.config.js 文件,该文件描述webpack打包时所需的配置。
首先需要安装webpack依赖包,修改package.json文件,配置开发过程中需要的依赖包,即devDependencies 属性。
{
"name": "hello-world",
"version": "1.0.0",
"devDependencies": {
"awesome-typescript-loader": "^5.2.1",
"source-map-loader": "^1.1.3",
"typescript": "^4.2.3",
"webpack": "^4.46.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.2"
},
"dependencies": {
"babylonjs": "^5.0.0-alpha.22",
"babylonjs-loaders": "^5.0.0-alpha.22"
}
}
配置webpack.config.js文件,详细解释参考官方文档,本例的解释如下:
// 本例中打包是将所有源码打包为一个js文件
const path = require('path')
// 设置打包好后项目的全局访问名称,类似于jQuery库的$
const packName = "hello_world"
// 导出配置
module.exports = {
entry: {
// 源码主文件入口
launcher: "/src/index.ts"
},
// 打包模式
mode: "development",
output: {
// 打包后输出的js文件
filename: "hello_world.js",
// 输出目录
path: path.resolve(__dirname + "/dist"),
// 目标库,只有umd模式可以打包为一个js文件
libraryTarget: "umd",
// 设置库名
library: {
root: packName,
amd: packName,
commonjs: packName
},
globalObject: '(typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this)',
umdNamedDefine: true
},
// 输出source-map文件
devtool: "source-map",
resolve: {
// 打包指定后缀的文件
extensions: [".ts", ".tsx", ".js", ".json"],
modules: ['node_modules']
},
module: {
rules: [
// 打包规则.
{test: /\.ts?$/, loader: "awesome-typescript-loader"},
// 输出map规则
{enforce: "pre", test: /\.js$/, loader: "source-map-loader"}
]
},
// 打包时排除本项目引用,但非本项目的模块
externals: {
"babylonjs": "BABYLON",
"babylonjs-loaders": "BABYLON",
"babylonjs-gui": "BABYLON",
}
};
6、编写测试源文件。在src文件夹添加index.ts和tools/myMath.ts文件,目录如下:
index.ts
export * from "./tools/myMath"
myMath.ts
export class MyMath {
public static sum(a: number, b: number): number {
return a + b;
}
}
然后在命令行输入webpack命令即可打包,可以看到在dist文件夹已输入打包好的js文件。
7、测试打包好的文件。在demo文件夹添加index的文件测试。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 导入打包好的js文件-->
<script src="../dist/hello_world.js"></script>
</head>
<body>
</body>
<script>
// 输出
console.log(hello_world.MyMath.sum(1, 2));
</script>
</html>
3、babylonjs模型显示
babylonjs是一款基于WebGL的3D图形引擎,也是目前处于该领域世界领先水平的引擎之一。其是由微软的团队开发并维护,拥有完善的文档,相对稳定,性能优化好,适合做大型项目,交互事件完善。
本项目中,仅添加模型显示的代码用于测试。
需编写的文件目录如下:
步骤:1、在源码中添加launcher类,用于编写模型加载方法,详细代码如下:
launcher.ts
import {SceneLoader, Engine, Scene} from "babylonjs"
/**
* 定义加载模型时需传入的参数
*/
interface ILauncher {
/**
* 存放资产的目录
*/
assetUrl: string,
/**
* 资产名称
*/
assetName: string,
/**
* 渲染canvas的名称
*/
container: string;
}
/**
* 模型加载类
*/
export class Launcher {
public assetUrl: string;
public assetName: string;
public canvas: HTMLCanvasElement;
/**
* babylonjs 引擎
*/
public engine: Engine;
/**
* babylonjs 场景
*/
public scene: Scene;
/**
* 类初始化
* @param params 参数
*/
constructor(params: ILauncher) {
this.assetUrl = params.assetUrl;
this.assetName = params.assetName;
this.canvas = <HTMLCanvasElement>document.getElementById(<string>params.container);
}
public launch() {
// 新建引擎
this.engine = new Engine(this.canvas);
// Resize事件
window.addEventListener("resize", () => {
this.engine.resize();
});
// 调用SceneLoader类加载模型
SceneLoader.LoadAsync(this.assetUrl, this.assetName).then((scene) => {
// 加载完成后的处理
scene.whenReadyAsync().then(() => {
// 创建默认相机
scene.createDefaultCamera(true);
scene.activeCamera.attachControl();
// 创建默认光
scene.createDefaultLight();
// 不断循环渲染
this.engine.runRenderLoop(() => {
scene.render();
});
});
})
}
}
2、在index.ts 文件中添加导出launcher类;然后输入命令webpack重新打包,重新生成hello_world.js文件;
export * from "./tools/myMath"
export * from "./tools/launcher"
3、编写demo下的index.html;并将上文中导出的gltf文件放置在asset文件夹下;
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 导入babylon的打包文件-->
<!-- 该文件可在node_modules对应的模块找到-->
<script src="../demo/asset/babylon.js"></script>
<script src="../demo/asset/babylonjs.loaders.min.js"></script>
<style>
html, body, canvas {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
overflow: hidden
}
</style>
<!-- 导入打包好的js文件-->
<script src="../dist/hello_world.js"></script>
</head>
<body>
<!--加载容器-->
<canvas id="renderCanvas"></canvas>
<script>
// 导入模型所需参数
let ilauncher = {
assetUrl: "../demo/asset/gltf/",
assetName: "1.gltf",
container: "renderCanvas"
}
// 实例化对象
let launcher = new hello_world.Launcher(ilauncher);
// 模型加载
launcher.launch();
</script>
</body>
</html>
4、运行index文件可以看到最后的结果;
4、总结
本篇文章初略的讲解了从gltf模型绘制、导出、显示的整个过程,每个环节都只做了最简单的操作演示,您若想深入了解具体某个模块,请自行查阅相关资料。
若文中有错误之处,还请大家批评指正。
5、参考资料
https://zhuanlan.zhihu.com/p/260973533
https://www.nothing-is-3d.com/article27/from-blender-to-babylonjs