之前尝试过使用vtk.js在浏览器上绘制三维图形。其与VTK C++版接口类似,上手较快,但vtk.js相对更新较慢,接口功能不完善。three.js相对更为主流,文档较为丰富,也有许多示例程序。
blender是siggraph力推的一款开源、免费3D建模软件,借助社区内丰富的插件可以方便地实现许多功能。
1、读取静态模型
1.1 使用fbx格式导出blender模型
将导出到.blender文件的同级目录。
除了上面的几种导出格式外,还可导出为js或json格式。为保持纯粹性,目前three.js的github项目中已删去支持blender导出js文件或json文件的io插件,可以git到较老的版本,或使用我保存的io工具。复制到blender的addons文件夹下相应位置即可导出相应格式的文件。
1.2 three.js载入fbx文件
// 声明变量
let scene, camera, renderer, HEIGHT, WIDTH;
// 创建场景
function createScene() {
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
const fieldOfView = 60;
const aspectRatio = WIDTH / HEIGHT;
const nearPlane = 1;
const farPlane = 10000;
// 相机
camera = new THREE.PerspectiveCamera(
fieldOfView,
aspectRatio,
nearPlane,
farPlane
);
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 1000;
// 场景
scene = new THREE.Scene();
// 渲染
renderer = new THREE.WebGLRenderer({alpha: true, antialias: true});
renderer.setSize(WIDTH, HEIGHT);
renderer.shadowMap.enabled = true;
// 加入DOM
const container = document.getElementById('main');
container.appendChild(renderer.domElement);
window.addEventListener('resize', handleWindowResize, false);
}
// 屏幕缩放
function handleWindowResize() {
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
renderer.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
}
// 光照
function createLights() {
// 天空的反光颜色,地面的反光颜色,光的强度
const light = new THREE.HemisphereLight( 0xFFFFFF, 0xFFFFFF, 0.8 );
light.position.set(0, 200, 0);
scene.add(light);
}
// 创建物体,暴露接口
let obj;
function createObject() {
const loader = new THREE.FBXLoader();
loader.load('ship.fbx', function (object) {
obj = object;
scene.add(object);
// 载入obj后动画循环
loop();
});
}
// 动画循环
function loop() {
obj.rotation.y += 0.01;
renderer.render(scene, camera);
requestAnimationFrame(loop);
}
function init() {
createScene();
createLights();
createObject();
}
window.addEventListener('load', init, false);
使用THREE.FBXLoader导入模型时,要配合FBXLoader.js和inflate.min.js,index.html内容如下。
Load
运行http-server,打开127.0.0.1:8080。
完整程序见我的github,其中blend文件夹下为原始blend模型。
2、读取带动画的模型
在blender中可以给模型绑定动画,导出方法同1.1。不同的是需将模型动画绑定到THREE.AnimationMixer,并在每次动画循环时调用update方法更新。update方法中传入两次loop函数的时间间隔。
// 声明变量
let scene, camera, renderer, HEIGHT, WIDTH;
// 创建场景
function createScene() {
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
const fieldOfView = 60;
const aspectRatio = WIDTH / HEIGHT;
const nearPlane = 1;
const farPlane = 10000;
// 相机
camera = new THREE.PerspectiveCamera(
fieldOfView,
aspectRatio,
nearPlane,
farPlane
);
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 1000;
// 交互
const controls = new THREE.OrbitControls( camera );
controls.target.set(0, 100, 0);
controls.update();
// 场景
scene = new THREE.Scene();
// 渲染
renderer = new THREE.WebGLRenderer({alpha: true, antialias: true});
renderer.setSize(WIDTH, HEIGHT);
// 加入DOM
const container = document.getElementById('main');
container.appendChild(renderer.domElement);
window.addEventListener('resize', handleWindowResize, false);
}
// 屏幕缩放
function handleWindowResize() {
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
renderer.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
}
// 光照
function createLights() {
// 天空的反光颜色,地面的反光颜色,光的强度
const light = new THREE.HemisphereLight(0xFFFFFF, 0xFFFFFF, 0.85);
// light.position.set(0, 200, 0);
scene.add(light);
}
var mixers = [];
var clock = new THREE.Clock();
function createObject() {
const loader = new THREE.FBXLoader();
loader.load('Fish.fbx', function (object) {
object.mixer = new THREE.AnimationMixer(object);
mixers.push(object.mixer);
const action = object.mixer.clipAction(object.animations[0]);
action.play();
// 侧面面对镜头
object.rotation.y = -1.57;
// 加入场景
scene.add(object);
// 载入obj后动画循环
loop();
});
}
// 动画循环
function loop() {
requestAnimationFrame(loop);
if (mixers.length > 0) {
for (let i = 0; i < mixers.length; i ++) {
mixers[i].update(clock.getDelta());
}
}
renderer.render(scene, camera);
}
function init() {
createScene();
createLights();
createObject();
}
window.addEventListener('load', init, false);
three.js只需引入OrbitControls.j文件,通过THREE.OrbitControls(camera)绑定camera,即可用鼠标完成一些简单的交互,鼠标左键-旋转,鼠标滚轮-缩放,鼠标右键-拖动。
Load
完整程序见我的github。