2012-11-19 74 views
2

我已经写了一个小生命的使用three.js所的3D渲染功能(如下全面测试应用程序):立方体旋转基于函数调用descibed动画每次我在屏幕上点击JavaScript回调动画

。但是我期待如果多维数据集已经在一个动画下动画,并且添加另一个动画会导致它闪烁,因为同一个属性被多个动画调用动画化。但是这不是发生在最后一个动画暂停并且新动画接管的情况下发生的,即使我的回调函数在最后显示旧动画功能仍在运行!那么为什么多次点击发送时多维数据集不会闪烁?

<!DOCTYPE html> 
<html> 
<head> 
    <title>Test Page</title> 
    <script src="three-mini.js"></script> 
    <style> 
     * { 
      margin: 0; 
      padding: 0; 
      overflow: hidden; 
     } 
    </style> 
</head> 
<body> 
    <script> 
     var animate = function(obj, prop, targetValue, length, callback) { 

      var startTime = Date.now(), inverseLength = 1/length, startValue = obj[prop]; 

      if(typeof targetValue === "string") { 
       if(targetValue.substring(0, 2) === "+=") { 
        targetValue = obj[prop] + Number(targetValue.substring(2)); 
       } else { 
        targetValue = obj[prop] - Number(targetValue.substring(2)); 
       } 
      } 

      var animateProp = function() { 

       var elapsed = (Date.now() - startTime) * inverseLength; 

       if(elapsed >= 1) { 

        obj[prop] = targetValue; 

        if(callback instanceof Function) { 
         requestAnimationFrame(callback); 
        } 
        return; 

       } else { 

        obj[prop] = (startValue - targetValue) * (Math.cos(elapsed * Math.PI) + 1) * 0.5 + targetValue; 

        requestAnimationFrame(animateProp); 

       } 

      }; 
      requestAnimationFrame(animateProp); 

     }; 
     var camera, scene, renderer; 
     var geometry, material, mesh; 

     init(); 

     function init() { 
      camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 1, 10000); 
      camera.position.z = 1000; 
      scene = new THREE.Scene(); 
      geometry = new THREE.CubeGeometry(200, 200, 200); 
      material = new THREE.MeshBasicMaterial({ 
       color : 0xff0000, 
       wireframe : true 
      }); 
      mesh = new THREE.Mesh(geometry, material); 
      scene.add(mesh); 
      renderer = new THREE.WebGLRenderer(); 
      renderer.setSize(window.innerWidth, window.innerHeight); 

      document.body.appendChild(renderer.domElement); 
      renderer.domElement.addEventListener('click', function() { 
       animate(mesh.rotation, "x", "-=" + Math.PI * 2 * 10, 5000, function() { 
        alert("CALLED BACK!") 
       }); 
       animate(mesh.rotation, "y", "-=" + Math.PI * 2 * 10, 15000, function() { 
       }); 
      }); 
      window.addEventListener('load', render); 
      window.addEventListener('resize', function() { 
       renderer.setSize(window.innerWidth, window.innerHeight); 
       camera.aspect = window.innerWidth/window.innerHeight; 
       camera.updateProjectionMatrix(); 
      }); 
     } 

     function render() { 

      // note: three.js includes requestAnimationFrame shim 
      requestAnimationFrame(render); 

      renderer.render(scene, camera); 

     } 
    </script> 
</body> 
</html> 

更新1:

在试图找出发生了什么事情我增加更多的网格和动画所有这些不同的代码如下,它以动画每一个网格,其后每点击它动画他们首先通过旋转,然后将它们向前移动然后向后移动,然后回到旋转。您可以在不停止旋转动画的情况下设置动画位置,并且可以同时为另一个网格动画一个网格而不停止以前的动画,那么为什么当多个动画运行在同一个网格上和相同的属性上时动画不会闪烁?

<!DOCTYPE html> 
<html> 
<head> 
    <title>Test Page</title> 
    <script src="three-mini.js"></script> 
    <style> 
     * { 
      margin: 0; 
      padding: 0; 
      overflow: hidden; 
     } 
    </style> 
</head> 
<body> 
    <script> 
     var animate = function(obj, prop, targetValue, length, callback) { 

      var startTime = Date.now(), inverseLength = 1/length, startValue = obj[prop]; 

      if(typeof targetValue === "string") { 
       if(targetValue.substring(0, 2) === "+=") { 
        targetValue = obj[prop] + Number(targetValue.substring(2)); 
       } else { 
        targetValue = obj[prop] - Number(targetValue.substring(2)); 
       } 
      } 

      var animateProp = function() { 

       var elapsed = (Date.now() - startTime) * inverseLength; 

       if(elapsed >= 1) { 

        obj[prop] = targetValue; 

        if(callback instanceof Function) { 
         requestAnimationFrame(callback); 
        } 
        return; 

       } else { 

        obj[prop] = (startValue - targetValue) * (Math.cos(elapsed * Math.PI) + 1) * 0.5 + targetValue; 

        requestAnimationFrame(animateProp); 

       } 

      }; 
      requestAnimationFrame(animateProp); 

     }; 
     var camera, scene, renderer, geometry, material, mesh1, mesh2, mesh3, mesh4, mesh5, i = 0, j = 0; 

     init(); 

     function init() { 
      camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 1, 10000); 
      camera.position.z = 1000; 
      scene = new THREE.Scene(); 
      geometry = new THREE.CubeGeometry(200, 200, 200); 
      material = new THREE.MeshBasicMaterial({ 
       color : 0xff0000, 
       wireframe : true 
      }); 
      mesh1 = new THREE.Mesh(geometry, material); 
      scene.add(mesh1); 
      mesh2 = new THREE.Mesh(geometry, material); 
      mesh2.position.x = mesh2.position.y = mesh2.position.z = 200; 
      scene.add(mesh2); 
      mesh3 = new THREE.Mesh(geometry, material); 
      mesh3.position.x = mesh3.position.z = 200; 
      mesh3.position.y = -200; 
      scene.add(mesh3); 
      mesh4 = new THREE.Mesh(geometry, material); 
      mesh4.position.y = mesh4.position.z = 200; 
      mesh4.position.x = -200; 
      scene.add(mesh4); 
      mesh5 = new THREE.Mesh(geometry, material); 
      mesh5.position.y = mesh5.position.x = -200; 
      mesh5.position.z = 200; 
      scene.add(mesh5); 
      renderer = new THREE.CanvasRenderer(); 
      renderer.setSize(window.innerWidth, window.innerHeight); 

      document.body.appendChild(renderer.domElement); 
      renderer.domElement.addEventListener('click', function() { 
       var mesh; 
       if(i === 5) { 
        i = 0; 
        j++; 
        if(j === 3) { 
         j = 0; 
        } 
       } 
       i++; 

       var mesh = window['mesh' + i]; 
       if(j === 1) { 
        animate(mesh.position, "z", "+=" + 500, 2000, function() { 
         //alert("CALLED BACK!") 
        }); 
        return; 
       } 
       if(j === 2) { 
        animate(mesh.position, "z", "-=" + 500, 3000, function() { 
         //alert("CALLED BACK!") 
        }); retunr; 
       } 
       animate(mesh.rotation, "x", "-=" + Math.PI * 2 * 5, 5000, function() { 
        //alert("CALLED BACK!") 
       }); 
       animate(mesh.rotation, "y", "-=" + Math.PI * 2 * 6, 10000, function() { 
       }); 
      }); 
      window.addEventListener('load', render); 
      window.addEventListener('resize', function() { 
       renderer.setSize(window.innerWidth, window.innerHeight); 
       camera.aspect = window.innerWidth/window.innerHeight; 
       camera.updateProjectionMatrix(); 
      }); 
     } 

     function render() { 

      // note: three.js includes requestAnimationFrame shim 
      requestAnimationFrame(render); 

      renderer.render(scene, camera); 

     } 
    </script> 
</body> 
</html> 

为WestLangley评论: 让我试着解释一点,我不被明确道歉。可以说我点击一次,它会从position.x = 0开始动画到targetValue: '+=200'。然后再次点击该动画,我再次点击该动画,此时会以position.x = 100(因为它在第一个动画的中途开始)开始的负x方向动画并具有targetValue: '-=200'。现在我预计第一个动画仍在运行,因此它将继续从x=100x=200生成动画,而第二个动画现在也从x=100运行到x=-100,因此每个动画函数被调用时,我都希望看到立方体向左跳直到第一个动画结束,然后第二个动画可以不受阻碍地继续。这正是我期待的事情,因此我期待它闪烁。但显然多个动画功能同时运行,但只有最新的功能才能更新网格属性。 :S至少据我所知。

我主要担心的是,我可以从实验中看出,“隐藏的”动画调用仍在处理中,因此抛弃了宝贵的处理器周期,这也导致在回调函数中添加动画调用时出现问题。为此,我主要关心的是如何阻止这些“隐藏的”动画调用?

+0

你_want_它闪烁? :-)你的方法对我来说是合法的。事实上,我有点喜欢它。 – WestLangley

+0

我不想让它闪烁,但我期待它。如果您运行第一个代码段并每三秒钟点击一次,您将看到动画在每次点击时开始,并且最终您将获得每次点击的警报,这意味着多个动画针对同一个网格针对相同的属性运行那么为什么它不闪烁? – 0xor1

+0

它不闪烁,因为你正在做一些明智的事情。如果你的更新函数是'obj [prop] = 100 * Math.random()+ targetValue;'你会看到一些严重的闪烁。 – WestLangley

回答

0

我仍然不完全知道发生了什么,但我所知道的是即使没有显示早期的动画,多个动画也同时在运行。我主要关心的是,它正在使用不必要的处理能力。所以我已经添加了后缀符号,现在我将动画功能添加到拥有动画的属性本身,所以如果我动画position.x我创建我的动画功能并将其分配给position.x_animateposition.x_animate_alt或者。这是我可以取消之前的,仍在运行的动画,所以我不会浪费处理器周期。全段紧挨着下面动画功能:

var animate = function(obj, prop, targetValue, length, callback) { 

      var suffix = '_animate', altSuffix = '_animate_alt', thisSuffix = suffix, startTime = Date.now(), inverseLength = 1/length, startValue = obj[prop]; 

      if(typeof targetValue === "string") { 
       if(targetValue.substring(0, 2) === "+=") { 
        targetValue = obj[prop] + Number(targetValue.substring(2)); 
       } else { 
        targetValue = obj[prop] - Number(targetValue.substring(2)); 
       } 
      } 

      if(obj[prop+suffix] instanceof Function){ 
       obj[prop+suffix].cancelled = true; 
       thisSuffix = altSuffix; 
      } 
      if(obj[prop+altSuffix] instanceof Function){ 
       obj[prop+altSuffix].cancelled = true; 
       thisSuffix = suffix; 
      } 

      obj[prop+thisSuffix] = function() { 

       var elapsed; 
       if(obj[prop+thisSuffix].cancelled){ 
        delete obj[prop+thisSuffix]; 
        return; 
       } 
       elapsed = (Date.now() - startTime) * inverseLength; 

       if(elapsed >= 1) { 

        obj[prop] = targetValue; 
        delete obj[prop+thisSuffix]; 
        if(callback instanceof Function) { 
         requestAnimationFrame(callback); 
        } 
        return; 

       } else { 

        obj[prop] = (startValue - targetValue) * (Math.cos(elapsed * Math.PI) + 1) * 0.5 + targetValue; 

        requestAnimationFrame(obj[prop+thisSuffix]); 

       } 

      }; 

      requestAnimationFrame(obj[prop+thisSuffix]); 

     };