一、前言
这篇文章主要学习 ThreeJs 中的 demo loader/obj2,主要是分析一下 obj 是如何加载的,纹理以及材质是如何加载的,3d camera 以及 camera controller 这些是如何实现的等。那么,先来 2 个 gif 图震撼一下吧。
二、代码分析
1.html 部分
<div id="glFullscreen">
<!-- 渲染 3D 场景的 canvas -->
<canvas id="example"></canvas>
</div>
<!-- dat gui 的 div 占位-->
<div id="dat">
</div>
<!--three.js 的其他一些信息说明-->
<div id="info">
<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - OBJLoader2 direct loader test
<div id="feedback"></div>
</div>
复制代码
这一部分最重要的就是这个 标记的添加,也说明了 WebGL 的主要实现就去用这个 canvas 去绘制。这和 Android 端上的原生 API 很像嘛。
2.script 导入
<!-- 导入 threejs 核心库 -->
<script src="../build/three.js"></script>
<!-- 导入 camera controller,用于响应鼠标/手指的拖动,放大,旋转等操作 -->
<script src="js/controls/TrackballControls.js"></script>
<!-- 材质加载 -->
<script src="js/loaders/MTLLoader.js"></script>
<!-- 三方库 dat gui 库的导入-->
<script src="js/libs/dat.gui.min.js"></script>
<!-- 三方库 stats 的导入-->
<script type="text/javascript" src="js/libs/stats.min.js"></script>
<!-- 构建 mesh,texture 等支持 -->
<script src="js/loaders/LoaderSupport.js"></script>
<!-- 加载 obj 的主要实现 -->
<script src="js/loaders/OBJLoader2.js"></script>
复制代码
3.模型加载
3.1 定义OBJLoader2Example
在ThreeJS 学习笔记——JavaScript 中的函数与对象中了解到,JavaScript 中是通过原型(prototype)来实现面向对象编程。这里先定义了函数 OBJLoader2Example(),然后再指定OBJLoader2Example的 prototype 的 constructor 为 OBJLoader2Example() 本身,这也就定义了一个 “类” OBJLoader2Example,我们可以使用这个类来声明新的对象。
var OBJLoader2Example = function ( elementToBindTo ) {......};
OBJLoader2Example.prototype = {
constructor: OBJLoader2Example,
initGL: function () {......},
initContent: function () {......},
_reportProgress: function () {......},
resizeDisplayGL: function () {......},
recalcAspectRatio: function () {......},
resetCamera: function () {......},
updateCamera: function () {......},
render: function () {......}
}
复制代码
3.2 OBJLoader2Example 的构造方法
var OBJLoader2Example = function ( elementToBindTo ) {
// 渲染器,后面它会绑定 canvas 节点
this.renderer = null;
// canvas 节点
this.canvas = elementToBindTo;
// 视图比例
this.aspectRatio = 1;
this.recalcAspectRatio();
// 3D 场景
this.scene = null;
// 默认相机参数
this.cameraDefaults = {
// 相机的位置,就是相机该摆在哪里
posCamera: new THREE.Vector3( 0.0, 175.0, 500.0 ),
// 相机的目标
posCameraTarget: new THREE.Vector3( 0, 0, 0 ),
// 近截面
near: 0.1,
// 远截面
far: 10000,
// 视景体夹角
fov: 45
};
// 3D 相机
this.camera = null;
// 3D 相机的目标,就是相机该盯着哪里看
this.cameraTarget = this.cameraDefaults.posCameraTarget;
// 3D 相机控制器,当然也可理解就是一个手势控制器
this.controls = null;
};
复制代码
构造方法主要是属性的定义,代码中添加了注释简要介绍了各个属性的作用,总体来说就是3D场景,3D 相机,相机控制器以及最重要的渲染器,渲染器绑定了 canvas,3D 场景及其所有的物件都会通过这个渲染器渲染到 canvas 中去。
3.3 initGL()
initGL: function () {
// 创建渲染器
this.renderer = new THREE.WebGLRenderer( {
// 绑定 canvas
canvas: this.canvas,
// 抗锯齿
antialias: true,
autoClear: true
} );
this.renderer.setClearColor( 0x050505 );
this.scene = new THREE.Scene();
// 初始化透视投影相机,这是一个三角的景锥体,物体在其里面呈现的效果是近大远小
this.camera = new THREE.PerspectiveCamera( this.cameraDefaults.fov, this.aspectRatio, this.cameraDefaults.near, this.cameraDefaults.far );
this.resetCamera();
// 初始化 controller
this.controls = new THREE.TrackballControls( this.camera, this.renderer.domElement );
// 添加环境光与平行光
var ambientLight = new THREE.AmbientLight( 0x404040 );
var directionalLight1 = new THREE.DirectionalLight( 0xC0C090 );
var directionalLight2 = new THREE.DirectionalLight( 0xC0C090 );
directionalLight1.position.set( -100, -50, 100 );
directionalLight2.position.set( 100, 50, -100 );
this.scene.add( directionalLight1 );
this.scene.add( directionalLight2 );
this.scene.add( ambientLight );
// 添加调试网格
var helper = new THREE.GridHelper( 1200, 60, 0xFF4444, 0x404040 );
this.scene.add( helper );
},
复制代码
initGL() 方法中初始化了各个属性,同时还添加了环境光与平行光源,以用于调试的网格帮助模型。在 3D 场景中很多物体都可看成是一个模型,如这里的光源。而 camera 在有一些渲染框架中也会被认为是一个模型,但其只是一个用于参与 3D 渲染时的参数。camera 最主要的作用是决定了投影矩阵,在投影矩阵内的物体可见,而不在里面则不可见。