【问题标题】:Optimize hundreds of dynamic lines in Three.js优化 Three.js 中数百条动态线
【发布时间】:2018-10-06 20:07:29
【问题描述】:

我是 Three.js 的新手,我只是玩得开心。我正在尝试在页面上实现一个简单的动态背景全屏,你得到the example here

function createHexagon( vertices, color ) {
    var geometry = new THREE.BufferGeometry();
    geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
    var material = new THREE.LineBasicMaterial( { color: color, opacity: Math.min((Math.random() / 5), 0.1), transparent: true } );

    var hexagon = new THREE.Line( geometry, material );
    return hexagon;
}

function initMatrix() {
    var color = defaultColor.getHex();
    var vertices;

    var x = ( width / -2 ) - 90;
    var y = height / -2;
    var deltaX = 120;
    var deltaY = 60;
    var time = 5.0;
    while( y < height / 2 ) {
        while( x < width / 2 ) {

            vertices = new Float32Array([
                0,  30, 0,
               20,   0, 0
            ]);
            var hexagon = createHexagon( vertices, color );
            scene.add( hexagon );  
            hexagon.position.set( x, y, 0 );

            vertices = new Float32Array([
               20,   0, 0,
               60,   0, 0
            ]);
            var hexagon = createHexagon( vertices, color );
            scene.add( hexagon );  
            hexagon.position.set( x, y, 0 );

            vertices = new Float32Array([
               60,   0, 0,
               80,  30, 0
            ]);
            var hexagon = createHexagon( vertices, color );
            scene.add( hexagon );  
            hexagon.position.set( x, y, 0 );

            x += deltaX;

        }

        x = ( width / -2 ) - 90;
        y += deltaY;
    }

    x = ( width / -2 ) - 30;
    y = ( height / -2 ) - 30;
    deltaX = 120;
    deltaY = 60;
    while( y < height / 2 ) {
        while( x < width / 2 ) {

            vertices = new Float32Array([
                0,  30, 0,
               20,   0, 0
            ]);
            var hexagon = createHexagon( vertices, color );
            scene.add( hexagon );  
            hexagon.position.set( x, y, 0 );

            vertices = new Float32Array([
               20,   0, 0,
               60,   0, 0
            ]);
            var hexagon = createHexagon( vertices, color );
            scene.add( hexagon );  
            hexagon.position.set( x, y, 0 );

            vertices = new Float32Array([
               60,   0, 0,
               80,  30, 0
            ]);
            var hexagon = createHexagon( vertices, color );
            scene.add( hexagon );  
            hexagon.position.set( x, y, 0 );          

            x += deltaX;
        }

        x = ( width / -2 ) - 30;
        y += deltaY;
    }
}

这些是单个 bufferGeometry 线(如您在上面创建背景的函数中所见),使用 raycaster 和 TweenLite 在鼠标悬停时随机旋转和更改不透明度。它工作得很好。您可以注意到 CPU 使用率几乎达到 100%。

我知道如果我将线条分组到相同的几何体中,性能会更好,但是我无法使用 raycaster 为单个线条制作动画,尤其是不透明度。

我搜索了很多讨论并尝试了很多东西。最好的结果是这样,单独渲染单行。你能提出一些建议吗?

【问题讨论】:

  • @gman 感谢您的回复!我看了这个例子,我没有弄清楚如何将它应用到我的案例中,因为它是一个自动的,我需要一个鼠标事件相关的行为。无论如何,我想出了如何实现我所需要的。

标签: javascript performance three.js 3d


【解决方案1】:

(代表问题作者发布).

我找到了解决方案。我制作了一个完整的几何图形,并对顶点和相应的颜色进行了索引。唯一的问题是我不能以这种方式管理不透明度,但它工作正常,CPU 约为 20%。

document.addEventListener( 'DOMContentLoaded', main );

var width = screen.width;
var height = screen.height;
var camera, scene, renderer, raycaster, mouse;
var rayColor = new THREE.Color( 0x0640C2 );
var rayColor2 = new THREE.Color( 0xCC311B );
var colors;
var linesPositions, originalPositions;
var linesMesh;
var geometry;
var intersects;

var stats;

function initMatrix() {

    var AlinesPositions = [ ];

    var x = ( width / - 2 ) - 80;
    var y = ( height / - 2 ) - 60;
    var deltaX = 120;
    var deltaY = 60;

    while( y <= ( height / 2 ) ) {

        while( x <= ( width / 2 ) ) {

            AlinesPositions.push( x, y, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x + 80, y, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x + 80, y, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x + 80, y + 60, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x + 80, y + 60, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x, y + 60, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x, y + 60, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x, y, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );

            x += deltaX;

        }

        x = ( width / -2 ) - 80;
        y += deltaY;

    }

    x = ( width / - 2 );
    y = ( height / - 2 ) - 60;

    while( y <= ( height / 2 ) ) {

        while( x <= ( width / 2 ) ) {

            AlinesPositions.push( x, y, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x + 80, y, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x + 80, y, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x + 80, y + 60, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x + 80, y + 60, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x, y + 60, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x, y + 60, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x, y, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );

            x += deltaX;

        }

        x = ( width / -2 );
        y += deltaY;

    }

    linesPositions = new Float32Array( AlinesPositions );

    var Acolors = [ ];
    for( var i = 0; i < AlinesPositions.length; i++ ) {

        var fact = Math.random() * 20.0;
        var ran = Math.min( Math.max( ( Math.random() / fact ), 0.01 ), 0.5 );
        Acolors[i] = ran;
        Acolors[i+1] = ran;
        Acolors[i+2] = ran;

        i += 2;
    }

    colors = new Float32Array( Acolors );

    geometry = new THREE.BufferGeometry();

    geometry.addAttribute( 'position', new THREE.BufferAttribute( linesPositions, 3 ).setDynamic( true ) );
    geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ).setDynamic( true ) );

    var material = new THREE.LineBasicMaterial( {
        vertexColors: THREE.VertexColors,
        blending: THREE.AdditiveBlending,
        transparent: true
    } );

    linesMesh = new THREE.LineSegments( geometry, material );
    scene.add( linesMesh );

    originalPositions = new THREE.BufferAttribute( linesPositions, 3 );
    originalPositions.copy( linesMesh.geometry.attributes.position );

}

function init() {
    scene = new THREE.Scene();
    //camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 1, 100 );
    camera = new THREE.PerspectiveCamera( 120, width / height, 1, 1000 );
    camera.position.set( 0, 0, 200 );
    camera.lookAt( 0, 0, 0 );

    // Create matrix
    initMatrix();

    raycaster = new THREE.Raycaster();
    raycaster.linePrecision = 20;

    mouse = new THREE.Vector2();

    renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize( width, height );
    document.body.appendChild( renderer.domElement );
}

function main() {

    init();
    animate();

}

function animate() {

    requestAnimationFrame( animate );
    render();

}

var intersected = [];

function removeX( i ) { intersected.splice( i, 1 ); }

function alterate( index ) {

    var randColor = ( Math.random() <= 0.49 ) ? rayColor : rayColor2;
    // Change color
    var currentC = new THREE.Color( linesMesh.geometry.attributes.color.getX( index ), linesMesh.geometry.attributes.color.getY( index ), linesMesh.geometry.attributes.color.getZ( index ));
    var tweenC = TweenLite.to( currentC, 1.0, {

        r: randColor.r,
        g: randColor.g,
        b: randColor.b,
        immediateRender: true,
        lazy: false,
        onUpdate: function() {

            linesMesh.geometry.attributes.color.setXYZ( index, currentC.r, currentC.g, currentC.b );
            linesMesh.geometry.attributes.color.needsUpdate = true;

        },
        onUpdateParams: [ index, currentC ]

    });

    // Change coordinates
    var currentXY = { x: originalPositions.getX( index ), y: originalPositions.getY( index ), z: originalPositions.getZ( index ) };
    var goal = [ ( currentXY.x + ( Math.random() * 50 ) * ( ( Math.random() < 0.5 ) ? 1 : -1 ) ), ( currentXY.y + ( Math.random() * 50 ) * ( ( Math.random() < 0.5 ) ? 1 : -1 ) ), ( currentXY.z + ( Math.random() * 50 ) * ( ( Math.random() < 0.5 ) ? 1 : -1 ) ) ];
    var tweenXY = TweenLite.to( currentXY, 1.0, {

        x: goal[ 0 ],
        y: goal[ 1 ],
        z: goal[ 2 ],
        immediateRender: true,
        lazy: false,
        onUpdate: function() {

            linesMesh.geometry.attributes.position.setXYZ( index, currentXY.x, currentXY.y, currentXY.z );    
            linesMesh.geometry.attributes.position.needsUpdate = true;

        },
        onUpdateParams: [ index, currentXY ]

    });

}

function render() {

    // update the picking ray with the camera and mouse position
    raycaster.setFromCamera( mouse, camera );

    intersects = raycaster.intersectObject( linesMesh );

    if( intersects.length ) {

        if( !intersected.includes( intersects[ 0 ].index ) ) {

            for( var x = 0; x < intersects.length; x++ ) {

                if( !intersected.includes( intersects[ x ].index ) ) {

                    var index = intersects[ x ].index;

                    // Save index
                    intersected.push( index );

                    alterate( index );

                }

            }

            var present = 0;

            for( var y = 0; y < intersected.length; y++ ) {

                for( var j = 0; j < intersects.length; j++ ) {

                    if( intersects[ j ].index == intersected[ y ] ) { present = 1; break; }

                }

                if( !present ) {

                    ( function( y ) { 

                        var randC = Math.min( Math.max( ( Math.random() / ( Math.random() * 20.0 ) ), 0.01 ), 0.5 );

                        // Current item old coordinates
                        let index = intersected[ y ];
                        var indexX = originalPositions.getX( index );
                        var indexY = originalPositions.getY( index );
                        var indexZ = originalPositions.getZ( index );

                        removeX( y );

                        // Reset color
                        var currentCreset = new THREE.Color( linesMesh.geometry.attributes.color.getX( index ), linesMesh.geometry.attributes.color.getY( index ), linesMesh.geometry.attributes.color.getZ( index ));
                        var tweenCreset = TweenLite.to( currentCreset, 1.5, {

                            r: randC,
                            g: randC,
                            b: randC,
                            immediateRender: true,
                            lazy: false,
                            onUpdate: function() {

                                linesMesh.geometry.attributes.color.setXYZ( index, currentCreset.r, currentCreset.g, currentCreset.b );
                                linesMesh.geometry.attributes.color.needsUpdate = true;

                            },
                            onUpdateParams: [ index, currentCreset ],
                            onComplete: function() { }

                        } );

                        // Reset coordinates
                        var currentXYreset = { x: linesMesh.geometry.attributes.position.getX( index ), y: linesMesh.geometry.attributes.position.getY( index ), z: linesMesh.geometry.attributes.position.getZ( index ) };
                        var tweenXYreset = TweenLite.to( currentXYreset, 1.5, {

                            x: indexX,
                            y: indexY,
                            z: indexZ,
                            immediateRender: true,
                            lazy: false,
                            onUpdate: function() {

                                linesMesh.geometry.attributes.position.setXYZ( index, currentXYreset.x, currentXYreset.y, currentXYreset.z );    
                                linesMesh.geometry.attributes.position.needsUpdate = true;

                            },
                            onUpdateParams: [ index, currentXYreset ]                       

                        });

                    }) ( y );

                }

            }

        }

    }

    renderer.render( scene, camera );

}

function onMouseMove( event ) {

    // calculate mouse position in normalized device coordinates
    // (-1 to +1) for both components
    event.preventDefault();

    mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
    mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

    var normX = event.clientX - ( window.innerWidth / 2 );
    var normY = event.clientY - ( window.innerHeight / 2 );

    camera.position.set( 0 + ( normY / 50 ), 0 + ( normX / 50 ), 200 );
    camera.lookAt( 0 + ( normY / 50 ), 0 + ( normX / 50 ), 0 );

}

window.addEventListener( 'click', function() {

    if( intersected.length ) {

        for( var x = 0; x < intersected.length; x++ ) {

            var index = intersected[ x ];

            alterate( index );

        }

    }

});

window.addEventListener( 'mousemove', onMouseMove, false );
// Set new dimensions for scene when resize window
window.addEventListener( 'resize', function() { 
    var wWidth = window.innerWidth;
    var wHeight = window.innerHeight;

    /*camera.left = wWidth / -2;
    camera.right = wWidth / 2;
    camera.top = wHeight / 2;
    camera.bottom = wHeight / -2;*/
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    raycaster.setFromCamera( mouse, camera );
    renderer.setSize( window.innerWidth, window.innerHeight );
} );

这是Codepen link

【讨论】:

  • 我应该在这里回复吗?
  • 理想情况下是的,@ThoughtsRiff。我们更喜欢将答案与问题分开,因为:(1)它们可以被接受和/或投票,(2)它们可以由数据 API 正确处理。如果您想复制 + 粘贴此答案,所以它是您自己的名字,请这样做(如果您这样做,请告诉我,以便我可以删除我的 wiki 答案)。
  • 哦,我明白了。那我很抱歉。好的,我复制/粘贴它,只是为了准确。谢谢你,对这个错误深表歉意。
【解决方案2】:

我找到了解决方案。我制作了一个完整的几何图形,并对顶点和相应的颜色进行了索引。唯一的问题是我无法以这种方式管理不透明度,但它工作正常,CPU 约为 20%。

document.addEventListener( 'DOMContentLoaded', main );

var width = screen.width;
var height = screen.height;
var camera, scene, renderer, raycaster, mouse;
var rayColor = new THREE.Color( 0x0640C2 );
var rayColor2 = new THREE.Color( 0xCC311B );
var colors;
var linesPositions, originalPositions;
var linesMesh;
var geometry;
var intersects;

var stats;

function initMatrix() {

    var AlinesPositions = [ ];

    var x = ( width / - 2 ) - 80;
    var y = ( height / - 2 ) - 60;
    var deltaX = 120;
    var deltaY = 60;

    while( y <= ( height / 2 ) ) {

        while( x <= ( width / 2 ) ) {

            AlinesPositions.push( x, y, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x + 80, y, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x + 80, y, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x + 80, y + 60, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x + 80, y + 60, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x, y + 60, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x, y + 60, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x, y, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );

            x += deltaX;

        }

        x = ( width / -2 ) - 80;
        y += deltaY;

    }

    x = ( width / - 2 );
    y = ( height / - 2 ) - 60;

    while( y <= ( height / 2 ) ) {

        while( x <= ( width / 2 ) ) {

            AlinesPositions.push( x, y, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x + 80, y, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x + 80, y, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x + 80, y + 60, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x + 80, y + 60, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x, y + 60, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x, y + 60, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );
            AlinesPositions.push( x, y, 0 /*Math.abs( ( 100 / ( width / 2 ) * x ) + ( 100 / ( height / 2 ) * y ) )*/ );

            x += deltaX;

        }

        x = ( width / -2 );
        y += deltaY;

    }

    linesPositions = new Float32Array( AlinesPositions );

    var Acolors = [ ];
    for( var i = 0; i < AlinesPositions.length; i++ ) {

        var fact = Math.random() * 20.0;
        var ran = Math.min( Math.max( ( Math.random() / fact ), 0.01 ), 0.5 );
        Acolors[i] = ran;
        Acolors[i+1] = ran;
        Acolors[i+2] = ran;

        i += 2;
    }

    colors = new Float32Array( Acolors );

    geometry = new THREE.BufferGeometry();

    geometry.addAttribute( 'position', new THREE.BufferAttribute( linesPositions, 3 ).setDynamic( true ) );
    geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ).setDynamic( true ) );

    var material = new THREE.LineBasicMaterial( {
        vertexColors: THREE.VertexColors,
        blending: THREE.AdditiveBlending,
        transparent: true
    } );

    linesMesh = new THREE.LineSegments( geometry, material );
    scene.add( linesMesh );

    originalPositions = new THREE.BufferAttribute( linesPositions, 3 );
    originalPositions.copy( linesMesh.geometry.attributes.position );

}

function init() {
    scene = new THREE.Scene();
    //camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 1, 100 );
    camera = new THREE.PerspectiveCamera( 120, width / height, 1, 1000 );
    camera.position.set( 0, 0, 200 );
    camera.lookAt( 0, 0, 0 );

    // Create matrix
    initMatrix();

    raycaster = new THREE.Raycaster();
    raycaster.linePrecision = 20;

    mouse = new THREE.Vector2();

    renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize( width, height );
    document.body.appendChild( renderer.domElement );
}

function main() {

    init();
    animate();

}

function animate() {

    requestAnimationFrame( animate );
    render();

}

var intersected = [];

function removeX( i ) { intersected.splice( i, 1 ); }

function alterate( index ) {

    var randColor = ( Math.random() <= 0.49 ) ? rayColor : rayColor2;
    // Change color
    var currentC = new THREE.Color( linesMesh.geometry.attributes.color.getX( index ), linesMesh.geometry.attributes.color.getY( index ), linesMesh.geometry.attributes.color.getZ( index ));
    var tweenC = TweenLite.to( currentC, 1.0, {

        r: randColor.r,
        g: randColor.g,
        b: randColor.b,
        immediateRender: true,
        lazy: false,
        onUpdate: function() {

            linesMesh.geometry.attributes.color.setXYZ( index, currentC.r, currentC.g, currentC.b );
            linesMesh.geometry.attributes.color.needsUpdate = true;

        },
        onUpdateParams: [ index, currentC ]

    });

    // Change coordinates
    var currentXY = { x: originalPositions.getX( index ), y: originalPositions.getY( index ), z: originalPositions.getZ( index ) };
    var goal = [ ( currentXY.x + ( Math.random() * 50 ) * ( ( Math.random() < 0.5 ) ? 1 : -1 ) ), ( currentXY.y + ( Math.random() * 50 ) * ( ( Math.random() < 0.5 ) ? 1 : -1 ) ), ( currentXY.z + ( Math.random() * 50 ) * ( ( Math.random() < 0.5 ) ? 1 : -1 ) ) ];
    var tweenXY = TweenLite.to( currentXY, 1.0, {

        x: goal[ 0 ],
        y: goal[ 1 ],
        z: goal[ 2 ],
        immediateRender: true,
        lazy: false,
        onUpdate: function() {

            linesMesh.geometry.attributes.position.setXYZ( index, currentXY.x, currentXY.y, currentXY.z );    
            linesMesh.geometry.attributes.position.needsUpdate = true;

        },
        onUpdateParams: [ index, currentXY ]

    });

}

function render() {

    // update the picking ray with the camera and mouse position
    raycaster.setFromCamera( mouse, camera );

    intersects = raycaster.intersectObject( linesMesh );

    if( intersects.length ) {

        if( !intersected.includes( intersects[ 0 ].index ) ) {

            for( var x = 0; x < intersects.length; x++ ) {

                if( !intersected.includes( intersects[ x ].index ) ) {

                    var index = intersects[ x ].index;

                    // Save index
                    intersected.push( index );

                    alterate( index );

                }

            }

            var present = 0;

            for( var y = 0; y < intersected.length; y++ ) {

                for( var j = 0; j < intersects.length; j++ ) {

                    if( intersects[ j ].index == intersected[ y ] ) { present = 1; break; }

                }

                if( !present ) {

                    ( function( y ) { 

                        var randC = Math.min( Math.max( ( Math.random() / ( Math.random() * 20.0 ) ), 0.01 ), 0.5 );

                        // Current item old coordinates
                        let index = intersected[ y ];
                        var indexX = originalPositions.getX( index );
                        var indexY = originalPositions.getY( index );
                        var indexZ = originalPositions.getZ( index );

                        removeX( y );

                        // Reset color
                        var currentCreset = new THREE.Color( linesMesh.geometry.attributes.color.getX( index ), linesMesh.geometry.attributes.color.getY( index ), linesMesh.geometry.attributes.color.getZ( index ));
                        var tweenCreset = TweenLite.to( currentCreset, 1.5, {

                            r: randC,
                            g: randC,
                            b: randC,
                            immediateRender: true,
                            lazy: false,
                            onUpdate: function() {

                                linesMesh.geometry.attributes.color.setXYZ( index, currentCreset.r, currentCreset.g, currentCreset.b );
                                linesMesh.geometry.attributes.color.needsUpdate = true;

                            },
                            onUpdateParams: [ index, currentCreset ],
                            onComplete: function() { }

                        } );

                        // Reset coordinates
                        var currentXYreset = { x: linesMesh.geometry.attributes.position.getX( index ), y: linesMesh.geometry.attributes.position.getY( index ), z: linesMesh.geometry.attributes.position.getZ( index ) };
                        var tweenXYreset = TweenLite.to( currentXYreset, 1.5, {

                            x: indexX,
                            y: indexY,
                            z: indexZ,
                            immediateRender: true,
                            lazy: false,
                            onUpdate: function() {

                                linesMesh.geometry.attributes.position.setXYZ( index, currentXYreset.x, currentXYreset.y, currentXYreset.z );    
                                linesMesh.geometry.attributes.position.needsUpdate = true;

                            },
                            onUpdateParams: [ index, currentXYreset ]                       

                        });

                    }) ( y );

                }

            }

        }

    }

    renderer.render( scene, camera );

}

function onMouseMove( event ) {

    // calculate mouse position in normalized device coordinates
    // (-1 to +1) for both components
    event.preventDefault();

    mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
    mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

    var normX = event.clientX - ( window.innerWidth / 2 );
    var normY = event.clientY - ( window.innerHeight / 2 );

    camera.position.set( 0 + ( normY / 50 ), 0 + ( normX / 50 ), 200 );
    camera.lookAt( 0 + ( normY / 50 ), 0 + ( normX / 50 ), 0 );

}

window.addEventListener( 'click', function() {

    if( intersected.length ) {

        for( var x = 0; x < intersected.length; x++ ) {

            var index = intersected[ x ];

            alterate( index );

        }

    }

});

window.addEventListener( 'mousemove', onMouseMove, false );
// Set new dimensions for scene when resize window
window.addEventListener( 'resize', function() { 
    var wWidth = window.innerWidth;
    var wHeight = window.innerHeight;

    /*camera.left = wWidth / -2;
    camera.right = wWidth / 2;
    camera.top = wHeight / 2;
    camera.bottom = wHeight / -2;*/
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    raycaster.setFromCamera( mouse, camera );
    renderer.setSize( window.innerWidth, window.innerHeight );
} );

这是一个 Codepen 链接:Example

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-02
    • 2013-01-23
    • 1970-01-01
    • 1970-01-01
    • 2021-10-14
    • 2012-05-16
    • 1970-01-01
    • 2023-04-04
    相关资源
    最近更新 更多