有这么个需求,需要动态画一根线,并以动画的方式延长。
我们先来拆解下技术要点:
1、首先,我们得把一根线给画出来;
2、然后,得让这根线动态地延长。
先来解决第一个问题,画线。Babylon提供了画线的方法 BABYLON.MeshBuilder.CreateLines。该方法接受3个参数,具体可以参照api文档:https://doc.babylonjs.com/api/classes/babylon.meshbuilder#createlines
这里直接举个例子可以看得明白:
var myPoints = [];
var point1 = new BABYLON.Vector3(0, 1, 0);
myPoints.push(point1);
var point2 = new BABYLON.Vector3(2, 1, 1);
myPoints.push(point2);
var lines = BABYLON.MeshBuilder.CreateLines("lines", {points: myPoints}, engine.scene);
CreateLines第一个参数,只是一个名字,无关紧要;第二个参数就是多段线之间的点。从CreateLines的s可以看得到,其实它是可以支持画多根线的,只需要把拐点定义好即可。最后一个参数就是scene场景对象。
这样,第一个问题解决。我们来看第二个问题。
大家一般会想到,我用个定时器,定时地改变线段的终点,这样子不也是动画了?其实也是可以的,但这样子一般不是很好,会带来很多额外的运算,而且不一定那么连贯。最佳方式还是使用动画机制,动画机制一般是由引擎内部实现的刷新,一般来说不会那么卡顿。
动画的话,BabylonJs提供了Animation对象。它的构造函数声明见API:
https://doc.babylonjs.com/api/classes/babylon.animation#constructor
我们直接上代码:
var framePerSecond = 30;
var totalFrames = 1500;
var animationLine = new BABYLON.Animation("myAnimation", "scaling", framePerSecond,
BABYLON.Animation.ANIMATIONTYPE_VECTOR3,
BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
var keys = [];
keys.push({
frame: 1,
value: new BABYLON.Vector3(1, 1, 1)
});
keys.push({
frame: totalFrames,
value: new BABYLON.Vector3(100, 1, 100)
});
animationLine.setKeys(keys);
var finishEvent = new BABYLON.AnimationEvent(totalFrames, function () {
console.log("animation finish");
}, false);
animationLine.addEvent(finishEvent);
lines.animations = [];
lines.animations.push(animationLine);
scene.beginAnimation(lines, 0, totalFrames, false);
上述代码经过以下几个步骤:
1、定义好动画市场的总帧数totalFrames以及每秒多少帧framePerSecond。这里可以看到整个动画会持续50秒。
2、定义动画对象animationLine。第一个参数依然是一个名字,无关紧要;第二个参数就是动画要改变的属性,这里是scaling缩放;第三个参数是动画的帧率,fps;第四个参数是动画改变属性的数据类型,由于scaling是一个三元组,所以这里填BABYLON.Animation.ANIMATIONTYPE_VECTOR3;最后是动画是否循环。这里是不循环
3、定义关键帧keys。这里是个数组,数组元素是一个定义第i帧的具体的数值的对象,不难理解。但要注意,初始帧的状态一定要加上,不然的话动画一下子就biu到结束状态了。所以这里的数组长度至少为2.
4、设置动画回调,设置在最后一帧回调,就是动画结束的时候回调。
5、设置动画并执行,就是以下几句话,不难理解:
lines.animations = [];
lines.animations.push(animationLine);
scene.beginAnimation(lines, 0, totalFrames, false);
这个过程可能会有个关键点,会有同学问我怎么知道scaling可以做这个缩放动画呢?首先这个肯定是根据具体需求来的。如果实在不知道效果如何,可以先试下看改变它的数值是否能达到目的,我这里就写了个操作检查下scaling是否会达到我想到的效果。
// //这样子能撑大,接下来写个动画实现它即可
// setTimeout(function(){
// lines.scaling.x = 100;
// lines.scaling.z = 100;
// },500);
确认无误之后,我就可以用动画实现它了。
以上就是画一个会变长的金箍棒的过程。全部代码如下:
/**
* assetcontaier的demo
*/
$(function(){
console.log('demo page is ready');
var modelDataList = [{
modelUrl:'/static/model/LNL/3/LNL3_F1.glb',
},{
modelUrl:'/static/model/LNL/LNL.glb',
}
,{
modelUrl:'/static/model/LNL/3/LNL3_F2.glb',
}]
var assetContainers = [];
var currentSceneIndex = 0;
var engine = null;
var scene = null;
var initScene = function (cameraType) {
var canvas = document.getElementById('renderCanvas');
var engine = new BABYLON.Engine(canvas, true);
var createScene = function () {
scene = new BABYLON.Scene(engine);
//默认用3D
var camera;
camera = new BABYLON.ArcRotateCamera("Camera", 0, 0, 100, BABYLON.Vector3.Zero(), scene);
camera.setPosition(new BABYLON.Vector3(120, 120, 120));
camera.attachControl(canvas, false, false);
var hemisphericLight = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 100, 0), scene);
let loadedModelCount = 0; //加载成功的模型
for (var i = 0; i < modelDataList.length; i++) {
var modelData = modelDataList[i];
var fullPath = modelData.modelUrl;
if(!fullPath){
loadedModelCount++;
continue;
}
var idx = fullPath.lastIndexOf('/');
var folder = fullPath.substring(0, idx + 1);
var fileName = fullPath.substring(idx + 1);
BABYLON.SceneLoader.LoadAssetContainer(folder, fileName, scene, function (container) {
assetContainers.push(container);
loadedModelCount++;
if(loadedModelCount==modelDataList.length){
//加载完毕
assetContainers[currentSceneIndex].addAllToScene();
}
});
}
return scene;
};
scene = createScene();
engine.runRenderLoop(function () {
scene.render();
});
window.addEventListener('resize', function () {
engine.resize();
});
var customLoadingUI = new ZFBabylonLoadingScreen();
engine.loadingScreen = customLoadingUI; //改成自定义的loading界面
return engine;
};
var drawLine = function() {
var myPoints = [];
var point1 = new BABYLON.Vector3(0, 1, 0);
myPoints.push(point1);
var point2 = new BABYLON.Vector3(2, 1, 1);
myPoints.push(point2);
var lines = BABYLON.MeshBuilder.CreateLines("lines", {points: myPoints}, engine.scene);
console.log(lines);
var framePerSecond = 30;
var totalFrames = 1500;
var animationLine = new BABYLON.Animation("myAnimation", "scaling", framePerSecond,
BABYLON.Animation.ANIMATIONTYPE_VECTOR3, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
var keys = [];
keys.push({
frame: 1,
value: new BABYLON.Vector3(1, 1, 1)
});
keys.push({
frame: totalFrames,
value: new BABYLON.Vector3(100, 1, 100)
});
animationLine.setKeys(keys);
var finishEvent = new BABYLON.AnimationEvent(totalFrames, function () {
console.log("animation finish");
}, false);
animationLine.addEvent(finishEvent);
lines.animations = [];
lines.animations.push(animationLine);
scene.beginAnimation(lines, 0, totalFrames, false);
// //这样子能撑大,接下来写个动画实现它即可
// setTimeout(function(){
// lines.scaling.x = 100;
// lines.scaling.z = 100;
// },500);
};
engine = initScene();
setTimeout(function(){
drawLine(engine);
},1000);
});