首页 文章

将Three.js骨骼动画更新为新的基于混音器的系统

提问于
浏览
10

混音器系统是在r73中引入的,从那以后我一直在尝试将我的游戏更新到这个新系统 .

除了一件事,我几乎都在那里 . 某些具有某些几何形状的动画的交叉渐变会有一些在r72中不存在的延迟 . 我攻击了r72的BlendCharacter和Animation功能以允许回调并且效果很好 . 在73中,如果通过事件触发器内置了此功能,则不需要这样做 .

在下面的小提琴中,一切都按预期工作(r72) .

http://jsfiddle.net/titansoftime/a93w5hw0/

<script src="http://www.titansoftime.com/webgl/Three72.full.js"></script>
<script src="http://www.titansoftime.com/webgl/BlendCharacter2.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/DDSLoader.js"></script>

var scene, camera, renderer, ambient, directional;
var mesh, geoCache={};
var clock, jsLoader, ddsLoader;

init();
animate();

function init() {

        scene = new THREE.Scene();

        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
        camera.position.z = 20;
        camera.position.y = 10;

        ambient = new THREE.AmbientLight(0xffffff);    
        scene.add(ambient);

        directional = new THREE.DirectionalLight(0xffffff,1);
        directional.position.set(1,1,0);
        scene.add(directional);

        clock = new THREE.Clock();

        jsLoader = new THREE.JSONLoader(true);    
        ddsLoader = new THREE.DDSLoader();

        renderer = new THREE.WebGLRenderer({antialias:true});
        renderer.setSize( window.innerWidth, window.innerHeight );
        renderer.setClearColor( 0xffffff, 1 );

        document.getElementById('idle').onclick = function(e){
            play('Idle',true);
        };

        document.getElementById('run').onclick = function(e){
            play('Run',true);
        };

        document.getElementById('melee').onclick = function(e){
            play('MelleAttack');
        };

        document.getElementById('magic').onclick = function(e){
            play('MagicAttack');
        };    

        document.body.appendChild( renderer.domElement );

        loadFloor();

        loadModel();

}

function createModel(json){

        var geo, geo2;

        if( geoCache[json.name] ){

                geo = geoCache[json.name];   

        }else{

                geo2 = jsLoader.parse(json).geometry;

                var m = new THREE.SkinnedMesh( geo2 );
                m.normalizeSkinWeights();
                geo2 = m.geometry;

                geo = new THREE.BufferGeometry().fromGeometry(geo2);
                geo.bones = geo2.bones;
                geo.animations = geo2.animations;

                geoCache[json.name] = geo;

        }

        var tex = ddsLoader.load('http://www.titansoftime.com/utils.php?task=getTexture&id=16');

        var mat = new THREE.MeshPhongMaterial({map:tex,skinning:true,side:THREE.DoubleSide});

        mesh = new THREE.BlendCharacter();
        mesh.load(geo,mat);

        //mesh.scale.set(10,10,10);

        //mesh.mixer = new THREE.AnimationMixer( mesh );

        //parseAnimations();    

        scene.add(mesh);

        play('Idle',true);

        camera.lookAt(new THREE.Vector3(mesh.position.x,7,mesh.position.z));

}

function loadModel(){

        $.ajax({

                url: 'http://www.titansoftime.com/utils.php',
                data: 'task=getModel&id=16',
                crossDomain: true,
                type: 'POST',
                success: function(response){
                        createModel(JSON.parse(response));
                }

        });    

}

function loadFloor(){

        var geo = new THREE.PlaneBufferGeometry(50,50);

        geo.applyMatrix(new THREE.Matrix4().makeRotationX(-Math.PI / 2));

        var mat = new THREE.MeshBasicMaterial({color:0x0000ff});

        var mesh = new THREE.Mesh(geo,mat);

        scene.add(mesh);

}

function play(name,loop){

    loop = loop || false;

    var anim = mesh.animations[name];

    anim.loop = loop;

    if( mesh.currentAnimation ){

        var cur = mesh.animations[mesh.currentAnimation];

        var theTime = 0.175;                

        if( !cur.loop ){

            var diff = cur.data.length - cur.currentTime;

            theTime = Math.max(0,Math.min(theTime,diff));

        }

        console.log('blending: '+name);
        mesh.crossfade(name,theTime,function(){

            play('Idle',true)

        });

    }else{              
        console.log('playing: '+name);
        mesh.play(name,loop);
    }

}

function animate() {

        requestAnimationFrame( animate );

        var delta = clock.getDelta();

        if( mesh ){

                mesh.update( delta );

        } 

        THREE.AnimationHandler.update(delta);

        renderer.render( scene, camera );

}

这个(r78)工作得很好,除了一个动画(魔法攻击)在返回空闲动画之前有一个很小但明显的延迟 . 在其他模型上它是近战动画,在某些模型上根本没有问题 . 超级困惑,因为他们都在72中正常工作 .

http://jsfiddle.net/titansoftime/2sh95etj/

<script src="https://rawgit.com/mrdoob/three.js/master/build/three.min.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/master/examples/js/loaders/DDSLoader.js"></script>

var scene, camera, renderer, ambient, directional;
var mesh, geoCache={};
var clock, jsLoader, ddsLoader;

init();
animate();

function init() {

        scene = new THREE.Scene();

        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
        camera.position.z = 20;
        camera.position.y = 10;

        ambient = new THREE.AmbientLight(0xffffff);    
        scene.add(ambient);

        directional = new THREE.DirectionalLight(0xffffff,1);
        directional.position.set(1,1,0);
        scene.add(directional);

        clock = new THREE.Clock();

        jsLoader = new THREE.JSONLoader(true);    
        ddsLoader = new THREE.DDSLoader();

        renderer = new THREE.WebGLRenderer({antialias:true});
        renderer.setSize( window.innerWidth, window.innerHeight );
        renderer.setClearColor( 0xffffff, 1 );

        document.getElementById('idle').onclick = function(e){
            play('Idle',true);
        };

        document.getElementById('run').onclick = function(e){
            play('Run',true);
        };

        document.getElementById('melee').onclick = function(e){
            play('MelleAttack');
        };

        document.getElementById('magic').onclick = function(e){
            play('MagicAttack');
        };    

        document.body.appendChild( renderer.domElement );

        loadFloor();

        loadModel();

}

function createModel(json){

        var geo, geo2;

        if( geoCache[json.name] ){

                geo = geoCache[json.name];   

        }else{

                geo2 = jsLoader.parse(json).geometry;

                var m = new THREE.SkinnedMesh( geo2 );
                m.normalizeSkinWeights();
                geo2 = m.geometry;

                geo = new THREE.BufferGeometry().fromGeometry(geo2);
                geo.bones = geo2.bones;
                geo.animations = geo2.animations;

                geoCache[json.name] = geo;

        }

        var tex = ddsLoader.load('http://www.titansoftime.com/utils.php?task=getTexture&id=16');

        var mat = new THREE.MeshPhongMaterial({map:tex,skinning:true,side:THREE.DoubleSide});

        mesh = new THREE.SkinnedMesh(geo,mat);

        //mesh.scale.set(10,10,10);

        mesh.mixer = new THREE.AnimationMixer( mesh );

        parseAnimations();

        play('Idle',true);

        scene.add(mesh);

        camera.lookAt(new THREE.Vector3(mesh.position.x,7,mesh.position.z));

}

function loadModel(){

        $.ajax({

                url: 'http://www.titansoftime.com/utils.php',
                data: 'task=getModel&id=16',
                crossDomain: true,
                type: 'POST',
                success: function(response){
                        createModel(JSON.parse(response));
                }

        });    

}

function loadFloor(){

        var geo = new THREE.PlaneBufferGeometry(50,50);

        geo.applyMatrix(new THREE.Matrix4().makeRotationX(-Math.PI / 2));

        var mat = new THREE.MeshBasicMaterial({color:0x0000ff});

        var mesh = new THREE.Mesh(geo,mat);

        scene.add(mesh);

}

function play(name,loop){

    var to = mesh.animations[ name ];       

    if( mesh.currentAnimation ){

        var from = mesh.animations[ mesh.currentAnimation ];

        to.reset();

        if( loop ){

            to.setLoop(THREE.LoopRepeat);
            to.clampWhenFinished = false;

        }else{

            to.setLoop(THREE.LoopOnce, 0);
            to.clampWhenFinished = true;                    

            mesh.mixer.addEventListener('finished',function(e){

                play('Idle',true);

            });                     

        }

        from.play();
        to.play();

        from.enabled = true;
        to.enabled = true;

        from.crossFadeTo( to, 0.3 );                    

    }else{

        to.play();

    }

    mesh.currentAnimation = name;

}

function parseAnimations(){

    var o, anim, anims = {};

    console.log(mesh);

    for( var i=0,len=mesh.geometry.animations.length;i<len;i++){

        o = mesh.geometry.animations[i];
        if( o ){

            anim = mesh.mixer.clipAction(o,mesh);
            anim.setEffectiveWeight(1);

            anims[o.name] = anim;

        }

    }

    mesh.animations = anims;

}

function animate() {

        requestAnimationFrame( animate );

        var delta = clock.getDelta();

        if( mesh ){

            if( mesh.mixer ){

                mesh.mixer.update( delta );

            }

         } 

        renderer.render( scene, camera );

}

为什么会这样?

UPDATE: 我注意到这个问题并不仅限于在动画之间进行混合 . 我的一个动画现在循环播放有一个延迟!

72:http://jsfiddle.net/titansoftime/8v0pasp5/

78:http://jsfiddle.net/titansoftime/n6apnj3z/

到底是怎么回事!?是否存在某种自动纠正行为或72中的某些行已被删除?

1 回答

相关问题