「这是我参与2022首次更文挑战的第26天,活动详情查看:2022首次更文挑战」
示例代码采用three.js-r73版本: cdnjs.cloudflare.com/ajax/libs/t…
这一节,我们主要讲解怎么将模型导入three.js中,让three.js能够显示我们的模型。让我们来看看吧。
重构项目
由于我们现在所做的示例,有很多代码是不需要经常改的,但是代码量也不少,我们修改代码时找起来比较麻烦,所以对项目进行一次重构。
我们的项目整体分为以下几部分:
- 初始化渲染器
- 初始化场景
- 初始化相机
- 初始化灯光
- 初始化轨迹球
- 初始化GUI界面
- 初始化性能监控
- 初始化颜色选择器
- 初始化物体
- 渲染循环
- 监听浏览器尺寸改变
我们经常需要修改的部分:
- 相机
- 灯光
- gui界面
- 物体
- 渲染循环时数据的更新
- 颜色改变的更新
稍后实现加载模型示例时,对项目按照功能划分进行重构。
threejs加载模型过程
threejs中模型是怎么加载的呢,为了让大家明白这个道理,我们先看一下threejs加载模型的简化过程。
- 服务器上的模型文件以文本的方式存储
- 服务器上的模型文件大多是存储的模型的顶点信息,不一定通过文本方式存储
- 通过浏览器下载文件到本地
- javascript通过各种loader来解析模型文件,生成Mesh模型
- 通过loader我们可以解析各种格式的模型文件
- Javascript解析文本文件并生成一个geometry,最终生成Mesh
- 把模型添加到场景中,显示出来
加载vtk模型
- Vtk模型是一种以文本方式表示的3D模型文件,其能够表示点面信息,而且能够以人类易读易懂的方式以文本的形式存储下来。在科学研究中,这种文件格式使用得非常多。
- 我们要加载vtk模型,就需要准备vtk模型文件(上节已经用过了)和解析vtk模型文件的loader,我已经帮大家准备好了
- vtk模型文件:bunny.vtk.zip(890 kB)
- 解析vtk的loader:github.com/mrdoob/thre…
- 所有的loader都在threejs源码目录的
examples/js/loaders中,最好是找到threejs对应版本的loaders,不然容易出错
- 所有的loader都在threejs源码目录的
html页面
- 把我们的各种js资源进行引入
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="../../libs/three.js"></script>
<script src="../../libs/dat.gui.js"></script>
<script src="../../libs/TrackballControls.js"></script>
<script src="../../libs/jscolor.js"></script>
<script src="../../libs/stats.js"></script>
<!-- 检查浏览器是否支持webgl -->
<script src="../../libs/Detector.js"></script>
<script src="../../libs/loaders/VTKLoader.js"></script>
</head>
<style type="text/css">
body {
margin: 0;
overflow: hidden;
}
div#canvas-frame {
border: none;
cursor: pointer;
width: 100%;
height: 600px;
background-color: #eeeeee;
}
#color-picker {
position: absolute;
bottom: 50px;
left: 50px;
}
</style>
<body>
<div id="canvas-frame"></div>
<script src="./index.js"></script>
</body>
</html>
初始化渲染器
- 因为我们的模型是偏白色的,所以我们把画布设置为黑色
const clearColor = 0x000000; // 0xFFFFFF
function initRenderer() {
width = document.getElementById('canvas-frame').clientWidth;
height = document.getElementById('canvas-frame').clientHeight;
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(width, height);
document.getElementById('canvas-frame').appendChild(renderer.domElement);
renderer.setClearColor(clearColor, 1.0);
}
初始化场景
function initScene() {
scene = new THREE.Scene();
}
初始化相机
function initCamera() {
camera = new THREE.PerspectiveCamera(60, width / height, near, far);
camera.position.z = 0.2;
scene.add(camera);
}
初始化灯光
function initLight() {
light = new THREE.DirectionalLight(0xffffff);
light.position.set(200, 200, 1000).normalize();
camera.add(light);
camera.add(light.target);
}
- 我们把光添加到摄像机中,是为了模拟光是从相机里照射出来的
初始化物体
创建基础材质
// 初始化物体
function initObject() {
var material = new THREE.MeshLambertMaterial({ color: 0xffffff, side: THREE.DoubleSide });
}
loader加载vtk模型
- 我们通过
THREE.VTKLoader可以加载vtk模型,返回一个geometry
var loader = new THREE.VTKLoader();
loader.load("https://threejs-models.vercel.app/models/vtk/bunny.vtk", function (geometry) {
geometry.computeVertexNormals();
var mesh = new THREE.Mesh(geometry, material);
mesh.position.setY(- 0.09);
scene.add(mesh);
});
- loader加载完成之后,获取到
geometry,我们就可以创建网格并添加到场景中了。
初始化各种控件
- 这里初始化布控球、GUI界面、性能监控、颜色选择器,浏览器窗口变化时处理,之前都实战过了,就不一一介绍了
var param
function initGUI() {
var ParamObj = function () {
this.repeat = 4;
this.wrap = 1000;
}
param = new ParamObj();
const gui = new dat.GUI();
// gui.add(param, "repeat", -100, 100).name('纹理重复')
// gui.add(param, "wrap", 1000, 1002).name('纹理环绕').step(1)
}
var stats;
function initStats() {
stats = new Stats();
stats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3+: custom
// 将stats的界面对应左上角
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.body.appendChild(stats.dom);
}
function initColorPicker() {
const colorPicker = document.createElement('div');
colorPicker.id = 'color-picker'
document.body.appendChild(colorPicker);
const html = `<input
data-jscolor="{value:'#FF0000', alpha:1}"
onChange="colorPickerUpdate(this.jscolor, '#pr3')"
/>`
const colorPickerDom = document.querySelector('#color-picker')
colorPickerDom.innerHTML = html;
jscolor.install(colorPickerDom)
jscolor.presets.default = {
width: 141, // make the picker a little narrower
position: 'top', // position it to the right of the target
previewPosition: 'right', // display color preview on the right
previewSize: 40, // make the color preview bigger
format: 'hex',
previewSize: 40,
closeButton: true,
closeText: '关闭',
palette: [
'#000000', '#7d7d7d', '#870014', '#ec1c23', '#ff7e26',
'#fef100', '#22b14b', '#00a1e7', '#3f47cc', '#a349a4',
'#ffffff', '#c3c3c3', '#b87957', '#feaec9', '#ffc80d',
'#eee3af', '#b5e61d', '#99d9ea', '#7092be', '#c8bfe7',
],
}
}
function initControls() {
controls = new THREE.TrackballControls(camera);
controls.rotateSpeed = 0.2;// 旋转速度
controls.zoomSpeed = 0.2;// 缩放速度
controls.panSpeed = 0.1;// 平controls
controls.staticMoving = false;// 静止移动,为 true 则没有惯性
controls.dynamicDampingFactor = 0.2;// 阻尼系数 越小 则滑动越大
controls.minDistance = near; // 最小视角
controls.maxDistance = far;// 最大视角 Infinity 无穷大
}
/* 窗口变动触发 */
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
渲染循环
- 准备工作做的差不多了,就该进行渲染了
function animation() {
renderer.render(scene, camera);
requestAnimationFrame(animation);
stats.update();
controls.update();
update()
}
/* 数据更新 */
function update() {
// 各种参数更新
}
function threeStart() {
// 初始化渲染器
initRenderer()
// 初始化场景
initScene();
// 初始化相机
initCamera();
// 初始化灯光
initLight();
// 初始化物体
initObject();
// 初始化布控球
initControls();
// 初始化GUI界面
initGUI()
// 初始化性能监控
initStats()
// 初始化颜色选择器
initColorPicker()
// 渲染循环
animation();
/* 监听事件 */
window.addEventListener('resize', onWindowResize, false);
}
最终现实效果
codepen示例代码
总结
这一节我们主要讲了以下内容:
- 重构项目代码讲解
- threejs加载模型过程
- 加载vtk模型