通过设置morphTargetInfluences属性创建动画

更新时间: 2021-09-22 11:20:49

morphTargetInfluencesMesh对象的属性,其作用是从0-1开始的一组权重,指定了应用的变体数量,默认为undefined。 也就是说影响的范围是0-1,如果一个状态为1而另一个状态为0,则此时物体的形体状态是影响值为1的那个形态。

首先建立一个cube,然后为其创建变形的顶点目标两组,然后再改变morphTargetInfluences属性的值来更改变形影响的权重,查看效果:

然后在改变

完整代码:

import * as THREE from 'three/build/three.module.js';
import * as dat from '../../@js/dat.gui.js'
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls'

let container, camera, scene, renderer, mesh

function init() {

    container = document.getElementById( 'three1' );

    scene = new THREE.Scene();
    scene.background = new THREE.Color( 0x8FBCD4 );

    camera = new THREE.PerspectiveCamera( 45, container.clientWidth / container.clientHeight, 1, 20 );
    camera.position.z = 10;
    scene.add( camera );

    scene.add( new THREE.AmbientLight( 0x8FBCD4, 0.4 ) );

    const pointLight = new THREE.PointLight( 0xffffff, 1 );
    camera.add( pointLight );

    const geometry = createGeometry();

    const material = new THREE.MeshPhongMaterial( {
        color: 0xff0000,
        flatShading: true
    } );

    mesh = new THREE.Mesh( geometry, material );
    scene.add( mesh );

    initGUI();

    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setSize( container.clientWidth , container.clientHeight );

    //每个可用帧都会调用的函数。 如果传入‘null’,所有正在进行的动画都会停止。可用来代替requestAnimationFrame的内置函数.
    renderer.setAnimationLoop( function () {

        renderer.render( scene, camera );

    } );
    container.appendChild( renderer.domElement );

    const controls = new OrbitControls( camera, renderer.domElement );
    controls.enableZoom = false;

    window.addEventListener( 'resize', onWindowResize );

}

function createGeometry() {

    const geometry = new THREE.BoxGeometry( 2, 2, 2, 32, 32, 32 );

    // create an empty array to  hold targets for the attribute we want to morph
    // morphing positions and normals is supported
    // 保存变形目标顶点数组
    geometry.morphAttributes.position = [];

    // the original positions of the cube's vertices
    const positionAttribute = geometry.attributes.position;

    // for the first morph target we'll move the cube's vertices onto the surface of a sphere
    const spherePositions = [];

    // for the second morph target, we'll twist the cubes vertices
    const twistPositions = [];
    const direction = new THREE.Vector3( 1, 0, 0 );
    const vertex = new THREE.Vector3();

    for ( let i = 0; i < positionAttribute.count; i ++ ) {

        const x = positionAttribute.getX( i );
        const y = positionAttribute.getY( i );
        const z = positionAttribute.getZ( i );

        spherePositions.push(

            x * Math.sqrt( 1 - ( y * y / 2 ) - ( z * z / 2 ) + ( y * y * z * z / 3 ) ),
            y * Math.sqrt( 1 - ( z * z / 2 ) - ( x * x / 2 ) + ( z * z * x * x / 3 ) ),
            z * Math.sqrt( 1 - ( x * x / 2 ) - ( y * y / 2 ) + ( x * x * y * y / 3 ) )

        );

        // stretch along the x-axis so we can see the twist better
        vertex.set( x * 2, y, z );

        vertex
        .applyAxisAngle( direction, Math.PI * x / 2 )
        .toArray( twistPositions, twistPositions.length );

    }

    // add the spherical positions as the first morph target
    geometry.morphAttributes.position[ 0 ] = new THREE.Float32BufferAttribute( spherePositions, 3 );

    // add the twisted positions as the second morph target
    geometry.morphAttributes.position[ 1 ] = new THREE.Float32BufferAttribute( twistPositions, 3 );

    return geometry;

}

function initGUI() {

    // Set up dat.GUI to control targets
    const params = {
        Spherify: 0,
        Twist: 0,
    };
    const gui = new dat.GUI({}, container);
    const folder = gui.addFolder( 'Morph Targets' );

    folder.add( params, 'Spherify', 0, 1 ).step( 0.01 ).onChange( function ( value ) {

        mesh.morphTargetInfluences[ 0 ] = value;

    } );
    folder.add( params, 'Twist', 0, 1 ).step( 0.01 ).onChange( function ( value ) {

        mesh.morphTargetInfluences[ 1 ] = value;

    } );

    folder.open();

}

init()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132