如何在 Three.js 中为 N 表面的振荡设置动画

How to animate in oscillation a N surface in Three.js

我想创建一个带有 Three.js 振荡动画的 NURBS 曲面。

这是我对 NURBS 的初始化:

this.nsControlPoints = [
      [
        new THREE.Vector4 ( -20, -20, 10, 1 ),
        new THREE.Vector4 ( -20, -10, -20, 1 ),
        new THREE.Vector4 ( -20, 10, 25, 1 ),
        new THREE.Vector4 ( -20, 20, -10, 1 )
      ],
      [
        new THREE.Vector4 ( 0, -20, 0, 1 ),
        new THREE.Vector4 ( 0, -10, -10, 5 ),
        new THREE.Vector4 ( 0, 10, 15, 5 ),
        new THREE.Vector4 ( 0, 20, 0, 1 )
      ],
      [
        new THREE.Vector4 ( 20, -20, -10, 1 ),
        new THREE.Vector4 ( 20, -10, 20, 1 ),
        new THREE.Vector4 ( 20, 10, -25, 1 ),
        new THREE.Vector4 ( 20, 20, 10, 1 )
      ]
    ];
    var degree1 = 2;
    var degree2 = 3;
    var knots1 = [0, 0, 0, 1, 1, 1];
    var knots2 = [0, 0, 0, 0, 1, 1, 1, 1];
    this.nurbsSurface = new NURBSSurface(degree1, degree2, knots1, knots2, this.nsControlPoints);

    var map = new THREE.TextureLoader().load( 'assets/img/tile.jpg' );
    map.wrapS = map.wrapT = THREE.RepeatWrapping;
    map.anisotropy = 16;

    let nurbsSurface = this.nurbsSurface;
    let start = this.start;

    function getSurfacePoint(u, v, target) {

      return nurbsSurface.getPoint(u, v, target);

    }

    this.geometry = new THREE.ParametricBufferGeometry( getSurfacePoint, 20, 20 );
    var material = new THREE.MeshBasicMaterial( { wireframe: true, color: 0x666666, opacity: 1.0 } );
    this.objectSurface = new THREE.Mesh( this.geometry, material );
    this.objectSurface.position.set( - 200, -100, 0 );
    this.objectSurface.rotateX(90);
    this.objectSurface.scale.multiplyScalar( 50 );
    this.scene.add( this.objectSurface );

这就是我尝试做的动画:

...
var position = this.geometry.attributes.position;
position.setXYZ(1, position.x + ( Date.now() - this.start ), position.y + ( Date.now() - this.start ), position.z + ( Date.now() - this.start ));

if(position instanceof THREE.BufferAttribute) {
    position.needsUpdate = true;
} else {
    position.data.needsUpdate = true;
}
...
this.renderer.render(this.scene, this.camera);

有什么建议吗?我没有在互联网上找到任何与此主题相关的解决方案。

提前致谢!!!

以下实时片段显示您可以变换由 ParametricBufferGeometry 的实例表示的 NURBS 曲面的顶点。请注意如何使用 BufferAttribute.setUsage() 来告诉 WebGL 您将每帧动态更改位置属性。

动画非常基础,但代码应说明预期的方法。

var geometry, renderer, scene, camera, controls, clock;

var vertex = new THREE.Vector3();

init();
animate();

function init() {

    // renderer
    renderer = new THREE.WebGLRenderer();
    renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.setPixelRatio( window.devicePixelRatio );
    document.body.appendChild( renderer.domElement );

    // scene
    scene = new THREE.Scene();
    
    // camera
    camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 1000 );
    camera.position.set( 50, 50, 50 );

    // controls
    controls = new THREE.OrbitControls( camera, renderer.domElement );
  
    clock = new THREE.Clock();
    
    // axes
    scene.add( new THREE.AxesHelper( 20 ) );

    var nsControlPoints = [
      [
        new THREE.Vector4 ( -20, -20, 10, 1 ),
        new THREE.Vector4 ( -20, -10, -20, 1 ),
        new THREE.Vector4 ( -20, 10, 25, 1 ),
        new THREE.Vector4 ( -20, 20, -10, 1 )
      ],
      [
        new THREE.Vector4 ( 0, -20, 0, 1 ),
        new THREE.Vector4 ( 0, -10, -10, 5 ),
        new THREE.Vector4 ( 0, 10, 15, 5 ),
        new THREE.Vector4 ( 0, 20, 0, 1 )
      ],
      [
        new THREE.Vector4 ( 20, -20, -10, 1 ),
        new THREE.Vector4 ( 20, -10, 20, 1 ),
        new THREE.Vector4 ( 20, 10, -25, 1 ),
        new THREE.Vector4 ( 20, 20, 10, 1 )
      ]
    ];
    var degree1 = 2;
    var degree2 = 3;
    var knots1 = [0, 0, 0, 1, 1, 1];
    var knots2 = [0, 0, 0, 0, 1, 1, 1, 1];
    var nurbsSurface = new THREE.NURBSSurface(degree1, degree2, knots1, knots2, nsControlPoints);

    function getSurfacePoint(u, v, target) {

            return nurbsSurface.getPoint(u, v, target);

    }

    geometry = new THREE.ParametricBufferGeometry( getSurfacePoint, 20, 20 );
    var material = new THREE.MeshBasicMaterial( { wireframe: true, color: 0x666666 } );
    var objectSurface = new THREE.Mesh( geometry, material );
    scene.add( objectSurface );
  
    geometry.attributes.position.setUsage( THREE.DynamicDrawUsage );

}

function animate() {

    requestAnimationFrame( animate );
  
    var elapsedTime = clock.getElapsedTime();
 
    var position = geometry.attributes.position;
    
    for ( var i = 0; i < position.count; i ++ ) {
  
         var z = position.getZ( i );

         z += Math.sin( elapsedTime ) * 0.1;
   
         position.setZ( i, z );
  
    }
  
    position.needsUpdate = true;

    renderer.render( scene, camera );

}
<script src="https://rawcdn.githack.com/mrdoob/three.js/r113/build/three.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/r113/examples/js/controls/OrbitControls.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/r113/examples/js/curves/NURBSUtils.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/r113/examples/js/curves/NURBSSurface.js"></script>