这不是我心目中的比目猪!快来看看这只3D小猪佩奇!
小猪佩奇总是用侧脸示人,不论是转左边还是转右边,脸上总是有2只眼睛、2个鼻孔、1腮红,小手手不断挥呀挥,讲完一句话就要发出猪叫声,最爱在往泥巴坑里跳。
佩奇正脸也是相当神秘,从未用“正脸”示人,引起许多人好奇心。作为一个负责任的3D可视化厂商,在猪年春节来临之际ThingJS特意制作了一个3D粒子特效的小猪佩奇!
开来看看佩奇正脸到底长成什么样子!
点我看佩奇!
源码(复制到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; }