这不是我心目中的比目猪!快来看看这只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;
}

  


posted @ 2019-01-30 16:01  ThingJS_森友鹿锘  阅读(2469)  评论(0编辑  收藏  举报