小猪佩奇总是用侧脸示人,不论是转左边还是转右边,脸上总是有2只眼睛、2个鼻孔、1腮红,小手手不断挥呀挥,讲完一句话就要发出猪叫声,最爱在往泥巴坑里跳。
佩奇正脸也是相当神秘,从未用“正脸”示人,引起许多人好奇心。作为一个负责任的3D可视化厂商,在猪年春节来临之际ThingJS特意制作了一个3D粒子特效的小猪佩奇!
开来看看佩奇正脸到底长成什么样子!
点我看佩奇!
![](https://i-blog.csdnimg.cn/blog_migrate/5b69d82879ace911eabfdce31eecf4f9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1138c430a06bd9d21613d1780d7896ef.png)
源码(复制到
ThingJS在线开发平台即可运行):
document.title = "ThingJS祝您猪年大吉-3D应用开发选ThingJS-优锘科技";
THING.Utils.dynamicLoadJS(['http://darsa.in/fpsmeter/js/fpsmeter.min.js'], function () {
//variables----
var app = new THING.App({
forceWebGL1: true
});
var fpsMeter = new FPSMeter();
var bEnableEgg = true;
var modelA = null;
var modelB = null;
var modelEgg = null;
var pointCloudMeshAnimator = null;
var pointCloudMeshAnimatorEgg = null;
var pointCloud = null;
var pointCloudEgg = null;
var bTransforming = false;
var bEggShowing = false;
var fScaleMax = 1.5;
var fScaleMulit = 1.0;
var fScaleClickStep = 0.05;
var fScaleTimeStep = -0.001;
var bMute = true;
var listener = null;
var audioBuffer_Fireworks = null;
var audioBuffer_Background = null;
var bIsAudioBackgroundPlaying = false;
var iAudioBuffer_FireworksIndex = 0;
var texturePoint = null;
var textureFireworks = null;
var fireworksArray = new Array();
var colorFireworksArray = [
0xf5f5dc,
0xfafad2,
0xffffe0,
0xf0e68c,
0xffd700,
0xfff8dc,
0xdaa520,
0xffa500,
0xffefD5,
0xff7f50,
0xff4500,
0xffb6c1,
0xffc0cb
];
//----variables
//main loop----
setUI();
initEnv();
initAudioListener();
initAudio_Background();
initAudio_Fireworks();
addTouchListener();
initModels(function () {
app.camera.position = [100, 00, 150];
app.camera.target = [0, 0, 0];
CreatePointCloud(function () {
console.log("[CreatePointCloud] called finished;");
setTimeout(function(){
bTransforming = true;
doTransformLoop();
}, 3000);
});
});
// update浜嬩欢
app.on('update', function () {
onTick();
});
app.on('click', function (e) {
if (!app.isMobileDevice) {
console.log("[onClick]; bEggShowing = " + bEggShowing);
if (!bEggShowing) {
playFireworks();
fScaleMulit += fScaleClickStep;
if (fScaleMulit >= fScaleMax) {
fScaleMulit = 1.0;
if (bEnableEgg) {
playEgg(function () {
hideEgg();
});
}
}
}
}
});
//----main loop
//functions----
// 娣诲姞html
function setUI() {
setUIBackground();
setUIVolume();
}
function setUIVolume() {
var sign = `<div id='sign' data-type="" style="width: 40px;height: 40px;background: url('https://thingjs.com/static/particles/Assets/mute.png') no-repeat;background-size: contain;position: absolute;top: 20px;right: 20px;cursor: pointer;border-radius:50%"></div>`;
$('#content').append($(sign));
$('#sign').click(function () {
var type = $(this).attr('data-type');
if (type == 'checked') {
$(this).css({ 'backgroundImage': 'url(https://thingjs.com/static/particles/Assets/mute.png)', })
$(this).attr('data-type', '');
bMute = true;
setSound(bMute);
} else {
$(this).css({ 'backgroundImage': 'url(https://thingjs.com/static/particles/Assets/volume.png)', })
$(this).attr('data-type', 'checked');
bMute = false;
setSound(bMute);
}
});
}
function setUIBackground() {
$(document.body).css({
'backgroundImage': !app.isMobileDevice ? 'url(http://www.thingjs.com/uploads/wechat/oLX7p0-0atbpF5ckWc4QiVYPuxV8/file/2019/pig-pc.jpg)' : "url('http://www.thingjs.com/uploads/wechat/oLX7p0-0atbpF5ckWc4QiVYPuxV8/file/2019/pig-m.jpg')",
'backgroundRepeat': 'no-repeat',
'backgroundPosition': 'center top',
'backgroundSize': 'cover'
});
$('#div3d').css('background', 'none');
}
function initEnv() {
console.log("[initEnv];");
app.background = 0x000000;
app.camera.enablePan = false;
app.camera.enableZoom = false;
fpsMeter.hide();
}
function initModels(onFinished) {
console.log("[initModels];");
var bModelACreated = false;
var bModelBCreated = false;
var bModelEggCreated = false;
modelA = app.create({
type: 'Thing',
name: 'Piggy',
url: 'http://model.3dmomoda.com/models/22e0c9d763d4474288555435f250e2ba/0/gltf/',
position: [0, 0, 30],
angle: 0,
complete: function () {
console.log('[initModels] : thing created: ' + this.id);
bModelACreated = true;
if (bModelACreated && bModelBCreated && bModelEggCreated) {
onFinished();
}
}
});
modelA.rotateX(-90);
modelA.scale = [20, 20, 20];
modelA.visible = false;
modelB = app.create({
type: 'Thing',
name: 'Fu',
url: 'http://model.3dmomoda.com/models/933d3a29404948798334336bdfd20c57/0/gltf/',
position: [0, 30, 10],
angle: 0,
complete: function () {
console.log('[initModels] : thing created: ' + this.id);
bModelBCreated = true;
if (bModelACreated && bModelBCreated && bModelEggCreated) {
onFinished();
}
}
});
modelB.rotateX(-90);
modelB.rotateZ(30);
modelB.scale = [0.3, 0.3, 0.3];
modelB.visible = false;
modelEgg = app.create({
type: 'Thing',
name: 'Logo',
url: 'http://model.3dmomoda.com/models/ac9f2476dad14fc1aee321512bd908b2/0/gltf/',
position: [0, 0, 0],
angle: 0,
complete: function () {
console.log('[initModels] : thing created: ' + this.id);
bModelEggCreated = true;
if (bModelACreated && bModelBCreated && bModelEggCreated) {
onFinished();
}
}
});
modelEgg.rotateX(-90);
modelEgg.scale = [60, 60, 60];
modelEgg.visible = false;
}
function CreatePointCloud(onFinished) {
console.log("[CreatePointCloud];");
var dataVo = new Array();
var iAnimateIndexArray = new Array();
var dvA =
{
"object": modelA.node,
"position": new THREE.Vector3(
modelA.node.position.x,
modelA.node.position.y,
modelA.node.position.z),
"scale": new THREE.Vector3(
modelA.node.scale.x,
modelA.node.scale.y,
modelA.node.scale.z),
"quat": new THREE.Vector4(
modelA.node.quaternion.x,
modelA.node.quaternion.y,
modelA.node.quaternion.z,
modelA.node.quaternion.w),
"step": 0.02
};
dataVo.push(dvA);
iAnimateIndexArray.push(0);
var dvB =
{
"object": modelB.node,
"position": new THREE.Vector3(
modelB.node.position.x,
modelB.node.position.y,
modelB.node.position.z),
"scale": new THREE.Vector3(
modelB.node.scale.x,
modelB.node.scale.y,
modelB.node.scale.z),
"quat": new THREE.Vector4(
modelB.node.quaternion.x,
modelB.node.quaternion.y,
modelB.node.quaternion.z,
modelB.node.quaternion.w),
"step": 0.02
};
dataVo.push(dvB);
iAnimateIndexArray.push(1);
var manager = new THREE.LoadingManager();
manager.onProgress = function (item, loaded, total) {
console.log(item, loaded, total);
};
var textureLoader = new THREE.TextureLoader(manager);
var strTexturePath = "https://thingjs.com/static/particles/Assets/boom.png";
texturePoint = textureLoader.load(strTexturePath);
var material = new THREE.PointsMaterial({
color: 0xdaa520,
size: 2,
transparent: true,
blending: THREE.AdditiveBlending,
depthTest: false,
map: texturePoint
});
var params =
{
"dataVoArray": dataVo,
"animateIndexArray": iAnimateIndexArray,
"material": material
};
pointCloudMeshAnimator = new PointCloudMeshAnimator();
pointCloudMeshAnimator.Init(
params,
function (pc) {
if (pc != null && pc != undefined) {
pointCloud = pc;
app.scene.add(pc);
}
onFinished();
}
);
var dataVoEgg = new Array();
var iAnimateIndexArrayEgg = new Array();
var dvEgg =
{
"object": modelEgg.node,
"position": new THREE.Vector3(
modelEgg.node.position.x,
modelEgg.node.position.y,
modelEgg.node.position.z),
"scale": new THREE.Vector3(
modelEgg.node.scale.x,
modelEgg.node.scale.y,
modelEgg.node.scale.z),
"quat": new THREE.Vector4(
modelEgg.node.quaternion.x,
modelEgg.node.quaternion.y,
modelEgg.node.quaternion.z,
modelEgg.node.quaternion.w),
"step": 0.02
};
dataVoEgg.push(dvA);
iAnimateIndexArrayEgg.push(0);
dataVoEgg.push(dvEgg);
iAnimateIndexArrayEgg.push(1);
var paramsEgg =
{
"dataVoArray": dataVoEgg,
"animateIndexArray": iAnimateIndexArrayEgg,
"material": material
};
pointCloudMeshAnimatorEgg = new PointCloudMeshAnimator();
pointCloudMeshAnimatorEgg.Init(
paramsEgg,
function (pc) {
if (pc != null && pc != undefined) {
pointCloudEgg = pc;
app.scene.add(pc);
pointCloudEgg.visible = false;
}
}
);
};
function doTransformLoop() {
if (
bTransforming
&& pointCloudMeshAnimator != null
&& pointCloudMeshAnimator != undefined
) {
pointCloudMeshAnimator.DoAnimation(
function () {
setTimeout(doTransformLoop, 3000);
}
);
}
}
function doTransformLoopEgg() {
if (
bEggShowing
&& pointCloudMeshAnimatorEgg != null
&& pointCloudMeshAnimatorEgg != undefined
) {
pointCloudMeshAnimatorEgg.DoAnimation(
function () {
setTimeout(doTransformLoopEgg, 3000);
}
);
}
}
function onTick() {
fpsMeter.tick();
if (pointCloudMeshAnimator != null && pointCloudMeshAnimator != undefined) {
if (fpsMeter != null && fpsMeter != undefined)
pointCloudMeshAnimator.Tick(fpsMeter.fps);
else
pointCloudMeshAnimator.Tick(30.0);
}
if (bEggShowing && pointCloudMeshAnimatorEgg != null && pointCloudMeshAnimatorEgg != undefined) {
if (fpsMeter != null && fpsMeter != undefined)
pointCloudMeshAnimatorEgg.Tick(fpsMeter.fps);
else
pointCloudMeshAnimatorEgg.Tick(30.0);
}
if (fScaleMulit > 1.0)
fScaleMulit += fScaleTimeStep;
if (pointCloud != null && pointCloud != undefined) {
pointCloud.scale.x = fScaleMulit;
pointCloud.scale.y = fScaleMulit;
pointCloud.scale.z = fScaleMulit;
}
tickFireworks();
}
function playEgg(onFinished) {
console.log("[playEgg];");
if (bEggShowing)
return;
bEggShowing = true;
if (pointCloud != null && pointCloud != undefined)
pointCloud.visible = false;
if (pointCloudEgg != null && pointCloudEgg != undefined) {
pointCloudEgg.visible = true;
doTransformLoopEgg();
}
setTimeout(function () {
if (pointCloudEgg != null && pointCloudEgg != undefined) {
pointCloudEgg.visible = false;
}
if (pointCloud != null && pointCloud != undefined)
pointCloud.visible = true;
onFinished();
}, 12000);
}
function hideEgg() {
console.log("[hideEgg];");
bEggShowing = false;
}
function initAudioListener() {
console.log("[initAudioListener];");
listener = new THREE.AudioListener();
app.renderCamera.add(listener);
}
function initAudio_Background() {
console.log("[initAudio_Background];");
if (listener == null || listener == undefined) {
console.error("[initAudio_Background] : check your listener;");
return;
}
var strUrlAudio = "https://thingjs.com/static/particles/Assets/mp3/happy_new_year.mp3";
if (!app.isMobileDevice) {
audioBuffer_Background = new THREE.Audio(listener);
var audioLoader = new THREE.AudioLoader();
audioLoader.load(strUrlAudio, function (buffer) {
audioBuffer_Background.setBuffer(buffer);
audioBuffer_Background.setLoop(true);
audioBuffer_Background.setVolume(0.5);
audioBuffer_Background.play();
setSound(bMute);
});
}
else {
audioBuffer_Background = new WebAudio();
audioBuffer_Background._init({
src: strUrlAudio,
autoPlay: true,
loop: true,
onUpdatetime: function (e) {
//console.log("[initAudio_Background] : onUpdatetime : " + audioBuffer_Background.audio.currentTime);
}
});
audioBuffer_Background.load();
setSound(bMute);
}
}
function initAudio_Fireworks() {
console.log("[initAudio_Fireworks];");
if (listener == null || listener == undefined) {
console.error("[initAudio_Fireworks] : check your listener;");
return;
}
var strUrlAudio = "https://thingjs.com/static/particles/Assets/mp3/fireworks_explosion.mp3";
if (!app.isMobileDevice) {
var audioLoader = new THREE.AudioLoader();
audioLoader.load(strUrlAudio, function (buffer) {
audioBuffer_Fireworks = buffer;
});
}
else {
audioBuffer_Fireworks = new Array();
for (var i = 0; i < 10; i++) {
var abf = new WebAudio();
abf._init({
src: strUrlAudio,
onUpdatetime: function (e) {
}
});
abf.load();
audioBuffer_Fireworks.push(abf);
}
}
}
function addTouchListener() {
console.log("[addTouchListener];");
if (app.isMobileDevice) {
document.addEventListener("touchstart", function () {
if (
!bIsAudioBackgroundPlaying
&& audioBuffer_Background != null
&& audioBuffer_Background != undefined
) {
bIsAudioBackgroundPlaying = true;
audioBuffer_Background.play();
setSound(bMute);
}
if (!bMute && !bEggShowing)
playAudio_Fireworks_Mobile();
if (!bEggShowing) {
playFireworks();
fScaleMulit += fScaleClickStep;
if (fScaleMulit >= fScaleMax) {
fScaleMulit = 1.0;
if (bEnableEgg) {
playEgg(function () {
hideEgg();
});
}
}
}
}, false);
}
}
function playAudio_Fireworks_PC() {
if (audioBuffer_Fireworks == null || audioBuffer_Fireworks == undefined) {
console.error("[playAudio_Fireworks_PC] : check your audioBuffer_Fireworks;");
return;
}
var sound = new THREE.Audio(listener);
sound.setBuffer(audioBuffer_Fireworks);
sound.setLoop(false);
sound.setVolume(0.8);
sound.play();
}
function playAudio_Fireworks_Mobile() {
if (audioBuffer_Fireworks == null || audioBuffer_Fireworks == undefined) {
console.error("[playAudio_Fireworks_Mobile] : check your audioBuffer_Fireworks;");
return;
}
iAudioBuffer_FireworksIndex++;
if (iAudioBuffer_FireworksIndex >= audioBuffer_Fireworks.length)
iAudioBuffer_FireworksIndex = 0;
audioBuffer_Fireworks[iAudioBuffer_FireworksIndex].play();
}
function playFireworks() {
console.log("[playFireworks];");
var geometryFireBall = new THREE.Geometry();
for (var i = 0; i < 1; i++) {
var pos = new THREE.Vector3();
pos.x = 0;
pos.y = 0;
pos.z = 0;
geometryFireBall.vertices.push(pos);
}
if (textureFireworks == null || textureFireworks == undefined) {
var manager = new THREE.LoadingManager();
manager.onProgress = function (item, loaded, total) {
console.log(item, loaded, total);
};
var textureLoader = new THREE.TextureLoader(manager);
var strTexturePath = "https://thingjs.com/static/particles/Assets/fireworks_0.png";
textureFireworks = textureLoader.load(strTexturePath);
}
var color = colorFireworksArray[THREE.Math.randInt(0, colorFireworksArray.length - 1)];
var materialFireBall = new THREE.PointsMaterial({
color: color,
size: 10,
transparent: true,
blending: THREE.AdditiveBlending,
depthTest: false,
map: textureFireworks
});
var meshFireBall = new THREE.Points(geometryFireBall, materialFireBall);
app.scene.add(meshFireBall);
var fireworks = new Fireworks();
fireworksArray.push(fireworks);
fireworks.Init({
"fireBall": meshFireBall,
"speed": 6.5,
"speedSpread": 0.05,
"acc": -0.1,
"accSpread": 0.02,
"bomb": THREE.Math.randFloat(20.0, 50.0),
"life": 1000,
"t": 1
}, function () {
fireworks.TriggerBomb();
setTimeout(function () {
app.scene.remove(meshFireBall);
}, 100);
});
if (!bMute)
playAudio_Fireworks_PC();
}
function tickFireworks() {
for (var i = 0, iLen = fireworksArray.length; i < iLen; i++) {
fireworksArray[i].Tick();
if (!fireworksArray.bIsRunning) {
fireworksArray.slice(i, 1);
iLen = fireworksArray.length;
}
}
}
function setSound(bMute) {
if (bMute)
audioBuffer_Background.pause();
else
audioBuffer_Background.play();
}
});
//----functions
//Class Fireworks----
Fireworks = function () {
var strLogHead = "[Fireworks.js] : ";
var bEnableLog = true;
var bounds =
{
"minX": -50.0,
"maxX": 50.0,
"minY": -200.0,
"maxY": -100.00,
"minZ": -50.0,
"maxZ": 50.0,
};
this.meshFireBall = null;
this.particleFireworks = null;
this.bIsRunning = true;
this.bIsBombing = false;
this.vec3InitPos = null;
this.vec3Pos = null;
this.fSpeed = 10;
this.fBomb = 10;
this.fAcc = 1;
this.fT = 0.01;
this.fTime = 0;
var scope = this;
//public functions----
this.Init = function (params, onFinished) {
if (bEnableLog)
console.log(strLogHead + "[Init];");
if (onFinished == null || onFinished == undefined) {
console.error(strLogHead + "[Init] : onFinished must be setted;");
return;
}
if (params == null || params == undefined) {
console.error(strLogHead + "[Init] : params must be setted;");
onFinished(null);
return;
}
else {
if (params.fireBall == null || params.fireBall == undefined) {
console.error(strLogHead + "[Init] : params.fireBall must be setted;");
onFinished(null);
return;
}
scope.meshFireBall = params.fireBall;
scope.vec3InitPos = new THREE.Vector3(
THREE.Math.randFloat(bounds.minX, bounds.maxX),
THREE.Math.randFloat(bounds.minY, bounds.maxY),
THREE.Math.randFloat(bounds.minZ, bounds.maxZ)
);
scope.vec3Pos = scope.vec3InitPos.clone();
scope.meshFireBall.position.x = scope.vec3InitPos.x;
scope.meshFireBall.position.y = scope.vec3InitPos.y;
scope.meshFireBall.position.z = scope.vec3InitPos.z;
var fLife = 1000;
if (params.life == null || params.life == undefined) {
console.warn(strLogHead + "[Init] : params.life is not setted; use default life;");
}
else
fLife = params.life;
scope.fSpeed = 10;
if (params.speed == null || params.speed == undefined) {
console.warn(strLogHead + "[Init] : params.speed is not setted; use default speed;");
}
else
scope.fSpeed = params.speed;
scope.fAcc = 1;
if (params.acc == null || params.acc == undefined) {
console.warn(strLogHead + "[Init] : params.acc is not setted; use default acc;");
}
else
scope.fAcc = params.acc;
scope.fBomb = 10;
if (params.bomb == null || params.bomb == undefined) {
console.warn(strLogHead + "[Init] : params.bomb is not setted; use default bomb;");
}
else
scope.fBomb = params.bomb;
var fSpeedSpread = 1;
if (params.speedSpread == null || params.speedSpread == undefined) {
console.warn(strLogHead + "[Init] : params.speedSpread is not setted; use default speedSpread;");
}
else
fSpeedSpread = params.speedSpread;
var fAccSpread = 1;
if (params.accSpread == null || params.accSpread == undefined) {
console.warn(strLogHead + "[Init] : params.accSpread is not setted; use default accSpread;");
}
else
fAccSpread = params.accSpread;
scope.fT = 0.01;
if (params.t == null || params.t == undefined) {
console.warn(strLogHead + "[Init] : params.t is not setted; use default t;");
}
else
scope.fT = params.t;
scope.fSpeed = THREE.Math.randFloat(scope.fSpeed - fSpeedSpread, scope.fSpeed + fSpeedSpread);
scope.fAcc = THREE.Math.randFloat(scope.fAcc - fAccSpread, scope.fAcc + fAccSpread);
scope.fTime = 0;
scope.__initParticleFireworks(function () {
scope.bIsRunning = true;
setTimeout(function () {
scope.bIsRunning = false;
onFinished();
scope.__playParticleFireworks(function () {
});
}, fLife);
});
}
};
this.Tick = function (t) {
if (scope.bIsRunning && scope.meshFireBall) {
scope.fTime += scope.fT;
var t = scope.fTime;
var v = scope.fSpeed;
var a = scope.fAcc;
scope.vec3Pos.y = scope.vec3InitPos.y + v * t + 0.5 * a * t * t;
scope.meshFireBall.position.y = scope.vec3Pos.y;
}
if (scope.bIsBombing) {
scope.fTime += scope.fBomb;
var s = scope.fTime;
scope.meshFireBall.material.size = s;
scope.meshFireBall.material.needUpdate = true;
}
};
this.TriggerBomb = function () {
scope.bIsBombing = true;
scope.fTime = 0;
}
this.Uninit = function () {
if (bEnableLog)
console.log(strLogHead + "[Uninit];");
}
//----public functions
//private functions----
this.__initParticleFireworks = function (onFinished) {
if (bEnableLog)
console.log(strLogHead + "[__initParticleFireworks];");
if (onFinished == null || onFinished == undefined) {
console.error(strLogHead + "[__initParticleFireworks] : onFinished must be setted;");
return;
}
onFinished();
};
this.__playParticleFireworks = function (onFinished) {
if (bEnableLog)
console.log(strLogHead + "[__playParticleFireworks];");
if (onFinished == null || onFinished == undefined) {
console.error(strLogHead + "[__playParticleFireworks] : onFinished must be setted;");
return;
}
onFinished();
};
//----private functions
}
//----Class Fireworks
//Class PointCloudMeshAnimator----
PointCloudMeshAnimator = function () {
var DataVo =
{
"iTotalPointCount": 0,
"fStep": 0.01,
"position": new THREE.Vector3(0, 0, 0),
"scale": new THREE.Vector3(1, 1, 1),
"quat": new THREE.Vector4(0, 0, 0, 1),
"objectPoints": null,
"geometry": null
};
var strLogHead = "[PointCloudMeshAnimator.js] : ";
var bEnableLog = true;
this.iAnimateIndex = 0;
this.bIsTransforming = false;
this.fLerp = 0;
this.pointCloud = null;
this.material = null;
this.dataVoArray = new Array();
this.iAnimateIndexArray = new Array();
this.onTriggerDoAnimationFinished = null;
var scope = this;
//public functions----
// var DataVo =
// {
// "object": ,
// "position": new THREE.Vector3(0, 0, 0),
// "scale": new THREE.Vector3(0, 0, 0),
// "quat": new THREE.Vector4(0, 0, 0, 1),
// "step": 0.01
// };
//@dataVoArray;
//@material;
this.Init = function (params, onFinished) {
if (bEnableLog)
console.log(strLogHead + "[Init];");
if (onFinished == null || onFinished == undefined) {
console.error(strLogHead + "[Init] : onFinished must be setted;");
return;
}
if (params == null || params == undefined) {
console.error(strLogHead + "[Init] : params must be setted;");
onFinished(null);
return;
}
else {
if (params.dataVoArray == null || params.dataVoArray == undefined || params.dataVoArray.length <= 0) {
console.error(strLogHead + "[Init] : params.dataVoArray must be setted;");
onFinished(null);
return;
}
for (var i = 0, iLen = params.dataVoArray.length; i < iLen; i++) {
var objectA;
var objectB;
if (params.dataVoArray[i].object == null || params.dataVoArray[i].object == undefined) {
console.error(strLogHead + "[Init] : params.dataVoArray[" + i + "].object must be setted;");
onFinished(null);
return;
}
}
scope.Uninit();
if (params.animateIndexArray == null || params.animateIndexArray == undefined || params.animateIndexArray.length <= 0) {
console.warn(strLogHead + "[Init] : params.animateIndexArray is not setted; use default animateIndexArray;");
for (var i = 0, iLen = params.dataVoArray.length; i < iLen; i++) {
scope.iAnimateIndexArray.push(i);
}
}
else {
scope.iAnimateIndexArray = params.animateIndexArray;
}
for (var i = 0, iLen = params.dataVoArray.length; i < iLen; i++) {
var dataVo =
{
"iTotalPointCount": 0,
"fStep": 0.01,
"position": new THREE.Vector3(0, 0, 0),
"scale": new THREE.Vector3(1, 1, 1),
"quat": new THREE.Vector4(0, 0, 0, 1),
"objectPoints": null,
"geometry": null
};
if (params.dataVoArray[i].position == null || params.dataVoArray[i].position == undefined) {
console.warn(strLogHead + "[Init] : params.dataVoArray[" + i + "].position is not setted; use default position;");
}
else
dataVo.position = params.dataVoArray[i].position;
if (params.dataVoArray[i].scale == null || params.dataVoArray[i].scale == undefined) {
console.warn(strLogHead + "[Init] : params.dataVoArray[" + i + "].scale is not setted; use default scale;");
}
else
dataVo.scale = params.dataVoArray[i].scale;
if (params.dataVoArray[i].quat == null || params.dataVoArray[i].quat == undefined) {
console.warn(strLogHead + "[Init] : params.dataVoArray[" + i + "].quat is not setted; use default quat;");
}
else
dataVo.quat = params.dataVoArray[i].quat.normalize();
if (params.dataVoArray[i].step == null || params.dataVoArray[i].step == undefined) {
console.warn(strLogHead + "[Init] : params.dataVoArray[" + i + "].step is not setted; use default step;");
}
else
dataVo.fStep = params.dataVoArray[i].step;
var iLoadChildIndex = -1;
if (params.dataVoArray[i].loadIndex == null || params.dataVoArray[i].loadIndex == undefined) {
console.warn(strLogHead + "[Init] : params.dataVoArray[" + i + "].loadIndex is not setted; load all children;");
}
else
iLoadChildIndex = params.dataVoArray[i].loadIndex;
var x = 0;
var y = 0;
var z = 0;
var iTotalObjectCount = 0;
dataVo.objectPoints = new Array();
if (i == 0) {
dataVo.geometry = new THREE.Geometry();
var iChildIndex = 0;
params.dataVoArray[i].object.traverse(function (child) {
if (child instanceof THREE.Mesh) {
if (iLoadChildIndex == -1 || iLoadChildIndex == iChildIndex) {
var positions = child.geometry.attributes.position.array;
var index = 0;
var tmpPos;
iTotalObjectCount += child.geometry.attributes.position.count;
for (var i = 0, iLen = child.geometry.attributes.position.count; i < iLen; i++) {
x = positions[index++] * dataVo.scale.x + dataVo.position.x;
y = positions[index++] * dataVo.scale.y + dataVo.position.y;
z = positions[index++] * dataVo.scale.z + dataVo.position.z;
tmpPos = new THREE.Vector3(x, y, z);
tmpPos = tmpPos.applyQuaternion(dataVo.quat);
x = tmpPos.x;
y = tmpPos.y;
z = tmpPos.z;
dataVo.objectPoints.push(x);
dataVo.objectPoints.push(y);
dataVo.objectPoints.push(z);
dataVo.geometry.vertices.push(
new THREE.Vector3(x, y, z)
);
}
}
iChildIndex++;
}
});
}
else {
var iChildIndex = 0;
params.dataVoArray[i].object.traverse(function (child) {
if (child instanceof THREE.Mesh) {
if (iLoadChildIndex == -1 || iLoadChildIndex == iChildIndex) {
var positions = child.geometry.attributes.position.array;
var index = 0;
var tmpPos;
iTotalObjectCount += child.geometry.attributes.position.count;
for (var i = 0, iLen = child.geometry.attributes.position.count; i < iLen; i++) {
x = positions[index++] * dataVo.scale.x + dataVo.position.x;
y = positions[index++] * dataVo.scale.y + dataVo.position.y;
z = positions[index++] * dataVo.scale.z + dataVo.position.z;
tmpPos = new THREE.Vector3(x, y, z);
tmpPos = tmpPos.applyQuaternion(dataVo.quat);
x = tmpPos.x;
y = tmpPos.y;
z = tmpPos.z;
dataVo.objectPoints.push(x);
dataVo.objectPoints.push(y);
dataVo.objectPoints.push(z);
}
}
iChildIndex++;
}
});
}
dataVo.iTotalPointCount = iTotalObjectCount;
scope.dataVoArray.push(dataVo);
}
var iMaxObjectCount = 0;
for (var i = 0, iLen = scope.dataVoArray.length; i < iLen; i++) {
console.log(strLogHead + "[" + i + "]" + " mesh vertexs = " + scope.dataVoArray[i].iTotalPointCount);
if (iMaxObjectCount < scope.dataVoArray[i].iTotalPointCount)
iMaxObjectCount = scope.dataVoArray[i].iTotalPointCount;
}
for (var iIndex = 0, iArrayLen = scope.dataVoArray.length; iIndex < iArrayLen; iIndex++) {
if (scope.dataVoArray[iIndex].iTotalPointCount < iMaxObjectCount) {
if (iIndex == 0) {
for (var i = scope.dataVoArray[iIndex].iTotalPointCount, iLen = iMaxObjectCount; i < iLen; i++) {
scope.dataVoArray[iIndex].objectPoints.push(scope.dataVoArray[iIndex].objectPoints[0]);
scope.dataVoArray[iIndex].objectPoints.push(scope.dataVoArray[iIndex].objectPoints[1]);
scope.dataVoArray[iIndex].objectPoints.push(scope.dataVoArray[iIndex].objectPoints[2]);
scope.dataVoArray[iIndex].geometry.vertices.push(
new THREE.Vector3(0, 0, 0)
);
}
}
else {
for (var i = scope.dataVoArray[iIndex].iTotalPointCount, iLen = iMaxObjectCount; i < iLen; i++) {
scope.dataVoArray[iIndex].objectPoints.push(scope.dataVoArray[iIndex].objectPoints[0]);
scope.dataVoArray[iIndex].objectPoints.push(scope.dataVoArray[iIndex].objectPoints[1]);
scope.dataVoArray[iIndex].objectPoints.push(scope.dataVoArray[iIndex].objectPoints[2]);
}
}
}
}
if (params.material == null || params.material == undefined) {
console.warn(strLogHead + "[Init] : params.material is not setted; use default material;");
var material = new THREE.PointsMaterial({
color: 0xffffff,
size: 0.2,
transparent: true,
blending: THREE.AdditiveBlending
});
scope.material = material;
}
else
scope.material = params.material;
scope.__createPointCloud(scope.dataVoArray[0].geometry, scope.material, function (cp) {
onFinished(cp);
});
}
}
this.DoAnimation = function (onFinished) {
if (this.bIsTransforming)
return;
scope.iAnimateIndex++;
if (scope.iAnimateIndex >= scope.iAnimateIndexArray.length)
scope.iAnimateIndex = 0;
scope.fLerp = 0;
scope.bIsTransforming = true;
if (onFinished != null && onFinished != undefined)
scope.onTriggerDoAnimationFinished = onFinished;
}
this.Tick = function (fps) {
scope.__doingAnimation(fps);
}
this.Uninit = function () {
if (bEnableLog)
console.log(strLogHead + "[Uninit];");
scope.iAnimateIndex = 0;
scope.bIsTransforming = false;
scope.fLerp = 0;
if (scope.dataVoArray != null && scope.dataVoArray != undefined) {
for (var i = 0, iLen = scope.dataVoArray.length; i < iLen; i++) {
if (scope.dataVoArray[i].objectPoints != null && scope.dataVoArray[i].objectPoints != undefined)
scope.dataVoArray[i].objectPoints = [];
if (scope.dataVoArray[i].geometry != null && scope.dataVoArray[i].geometry != undefined)
scope.dataVoArray[i].geometry.dispose();
}
}
scope.dataVoArray = [];
scope.iAnimateIndexArray = [];
if (scope.pointCloud != null && scope.pointCloud != undefined)
scope.pointCloud.dispose();
if (scope.material != null && scope.material != undefined)
scope.material.dispose();
scope.pointCloud = null;
scope.material = null;
}
//----public functions
//private functions----
this.__createPointCloud = function (geom, mat, onFinished) {
if (bEnableLog)
console.log(strLogHead + "[__createPointCloud];");
if (scope.pointCloud != null && scope.pointCloud != undefined)
scope.pointCloud.dispose();
scope.pointCloud = new THREE.Points(geom, mat);
scope.pointCloud.sortParticles = true;
onFinished(scope.pointCloud);
}
this.__doingAnimation = function (fps) {
if (scope.pointCloud == null || scope.pointCloud == undefined || !scope.bIsTransforming)
return;
var step = scope.dataVoArray[scope.iAnimateIndexArray[scope.iAnimateIndex]].fStep;
if (fps != null && fps != undefined)
step *= (30 / fps);
scope.fLerp += step;
var index = 0;
var x = 0;
var y = 0;
var z = 0;
var positions = scope.pointCloud.geometry.vertices;
var iLastIndex = scope.iAnimateIndex - 1;
if (iLastIndex < 0)
iLastIndex = scope.iAnimateIndexArray.length - 1;
var fSin = Math.sin(scope.fLerp * 3.14);
var fRandomRange = 2;
for (var i = 0, iLen = scope.pointCloud.geometry.vertices.length; i < iLen; i++) {
x = THREE.Math.lerp(scope.dataVoArray[scope.iAnimateIndexArray[iLastIndex]].objectPoints[index], scope.dataVoArray[scope.iAnimateIndexArray[scope.iAnimateIndex]].objectPoints[index], scope.fLerp);
x += THREE.Math.randFloat(-fRandomRange, fRandomRange) * fSin;
index++;
y = THREE.Math.lerp(scope.dataVoArray[scope.iAnimateIndexArray[iLastIndex]].objectPoints[index], scope.dataVoArray[scope.iAnimateIndexArray[scope.iAnimateIndex]].objectPoints[index], scope.fLerp);
y += THREE.Math.randFloat(-fRandomRange, fRandomRange) * fSin;
index++;
z = THREE.Math.lerp(scope.dataVoArray[scope.iAnimateIndexArray[iLastIndex]].objectPoints[index], scope.dataVoArray[scope.iAnimateIndexArray[scope.iAnimateIndex]].objectPoints[index], scope.fLerp);
z += THREE.Math.randFloat(-fRandomRange, fRandomRange) * fSin;
index++;
positions[i] = new THREE.Vector3(x, y, z);
}
scope.pointCloud.geometry.verticesNeedUpdate = true;
if (scope.fLerp >= 1) {
if (scope.onTriggerDoAnimationFinished != null && scope.onTriggerDoAnimationFinished != undefined) {
scope.onTriggerDoAnimationFinished();
}
scope.bIsTransforming = false;
}
}
//----private functions
}
//----Class PointCloudMeshAnimator
var WebAudio = function () {
var strLogHead = "[WebAudio.js] : ";
var bEnableLog = true;
var events = [
"canplay", "canplaythrough", "durationchange", "emptied", "ended", "error",
"onloadeddata", "loadedmetadata", "loadstart", "pause", "play", "playing",
"progress", "ratechange", "readystatechange", "seeked", "seeking", "stalled",
"suspend", "timeupdate", "volumechange", "waiting"
];
var noop = function () {
};
this.audio = null;
this.options = null;
this._events = null;
var scope = this;
this._init = function (option) {
if (bEnableLog)
console.log(strLogHead + "[_init];");
var i;
var key;
option = option || {};
scope._events = events;
scope.options = {
src: "",
autoPlay: false,
loop: false,
duration: 0
};
for (i = 0; i < events.length; i++) {
scope.options["on" + firstLetterUppercase(events[i])] = noop;
}
for (key in option) {
if (option.hasOwnProperty(key)) {
scope.options[key] = option[key];
}
}
scope.audio = new Audio();
var that = scope;
var i;
var inIOS = isIOS();
var options = scope.options;
for (i = 0; i < scope._events.length; i++) {
scope._addEventListener(scope._events[i]);
}
if (inIOS) {
if (options.loop) {
scope.audio.addEventListener("timeupdate", function (e) {
if (_getDuration() - scope.audio.currentTime <= 0.8) {
scope.audio.currentTime = 0;
}
}, false);
}
if (options.autoPlay) {
document.addEventListener("touchstart", _autoPlay, false);
}
} else {
if (options.loop) {
scope.audio.loop = true;
}
if (options.autoPlay) {
_autoPlay();
}
}
function _autoPlay() {
that.load();
that.play();
if (inIOS) {
document.removeEventListener("touchstart", _autoPlay, false);
}
}
function _getDuration() {
var duration = that.options.duration;
var audioDuration = that.audio.duration;
if (typeof audioDuration === "number" && !isNaN(audioDuration) && isFinite(audioDuration)) {
duration = audioDuration;
}
return duration;
}
};
this.load = function (src) {
if (bEnableLog)
console.log(strLogHead + "[load];");
scope.audio.src = src || scope.options.src;
};
this.play = function () {
if (bEnableLog)
console.log(strLogHead + "[play];");
scope.audio.play();
};
this.pause = function () {
if (bEnableLog)
console.log(strLogHead + "[pause];");
scope.audio.pause();
};
this._addEventListener = function (event) {
if (bEnableLog)
console.log(strLogHead + "[_addEventListener];");
scope.audio.addEventListener(event, function (e) {
scope.options["on" + firstLetterUppercase(event)].call(scope, e);
}, false);
}
};
function firstLetterUppercase(word) {
if (typeof word === "string" && word.length) {
return word[0].toUpperCase() + word.substring(1);
} else {
return word;
}
}
function isIOS() {
return /iPad|iPhone|iPod/i.test(navigator.userAgent) && !window.MSStream;
}