如何拖动 Threejs 点

how to dragging Threejs point

我正在尝试使用 threejs r86(最新的主版本)进行巨大的图形可视化,为了显示 600,000 个节点,我找到了一种绘制它们的方法,比使用 THREE.points 使用网格更快,但我知道我需要制作它们可拖动,经过多次搜索后我发现 raycast 找到了最接近鼠标点的对象,但我遇到了一个问题,因为所有的 taht 点都只是一个对象,不能单独更改。

function Graph3(Nodes, Edges) {
this.renderer = new THREE.WebGLRenderer({ alpha: true});
var width = window.innerWidth , height = window.innerHeight;
this.renderer.setSize(width, height, false);
document.body.appendChild(this.renderer.domElement);
this.scene = new THREE.Scene(),
this.camera = new THREE.PerspectiveCamera(100, width / height, 0.1, 3000),
this.controls = new THREE.OrbitControls(this.camera);
this.controls.enableKeys = true;
this.controls.enableRotate = false;

var material, geometry;
self = this;
material = new THREE.LineBasicMaterial({color: '#ccc'});

geometry = new THREE.Geometry();
geometry.vertices = Nodes.map(function(item){return new THREE.Vector3(item.pos.x,item.pos.y,item.pos.z);});
// this.vertices = geometry.vertices;


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

var Node = new THREE.Group();

material = new THREE.PointsMaterial( { color:0x000060 ,size:1 } );

this.particles = new THREE.Mesh(geometry,material)
this.particles = new THREE.Points( geometry, material);
this.scene.add( this.particles );

dragControls = new THREE.DragControls([this.particles], this.camera/*,this.scene*/, this.renderer.domElement);

this.camera.position.z = 200;

var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();

document.addEventListener( 'click', function ( event ) {

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

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

}, false );


stats = new Stats();
document.body.appendChild(stats.dom);

this.animate = function()
{

    raycaster.setFromCamera( mouse, self.camera );
    var intersections = raycaster.intersectObject( self.particles );
    intersection = ( intersections.length ) > 0 ? intersections[ 0 ] : null;

    if ( intersection !== null) {
        console.log(intersection);
    }

    requestAnimationFrame( self.animate );
    stats.update();

    self.renderer.render(self.scene, self.camera);
}
this.animate();}

我可以使用 dragControls 更改所有点,但不能单独移动它们 我找到了 EventsControls.js 文件来帮助我们处理事件,但我无法使用它

在这里您可以检查如何使用光线投射器定位缓冲区几何体的各个部分: https://github.com/mrdoob/three.js/blob/master/examples/webgl_interactive_buffergeometry.html

关于搬家,参考这个问答: How to quickly update a large BufferGeometry?

感谢您在上一个问题中帮助我。 我在 2d 平面 (z = 0) 中制作我的点,我可以用 bufferGeometry 和 RawShaderMaterial 制作它们,但现在我在拖动它们时遇到另一个问题,raycaster 怎么做?它需要 vec3 个位置,但出于性能目的我已经更改了它。

var Geo = new THREE.BufferGeometry();

            var position = new Float32Array( NodeCount * 2 );
            var colors = new Float32Array( NodeCount * 3 );
            var sizes = new Float32Array( NodeCount );

            for ( var i = 0; i < NodeCount; i++ ) {

                position[ 2*i ]     = (Math.random() - 0.5) * 10;
                position[ 2*i + 1 ] = (Math.random() - 0.5) * 10;


                colors[ 3*i ] = Math.random();
                colors[3*i+1] = Math.random();
                colors[3*i+2] = Math.random();

                // sizes

                sizes[i] = Math.random() * 5 ;

            }

            Geo.addAttribute( 'position', new THREE.BufferAttribute( position, 2 ) );
            Geo.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
            Geo.addAttribute( 'size', new THREE.BufferAttribute( sizes, 1 ) );



            points = new THREE.Points( Geo, new THREE.RawShaderMaterial({
                vertexShader:`
                precision highp float;

                uniform mat4 modelViewMatrix;
                uniform mat4 projectionMatrix;
                uniform vec3 cameraPosition;
                attribute vec2 position;  /// reason of problem

                varying vec3 vColor;
                attribute vec3 color;
                attribute float size;

                void main() {
                    vColor = color;

                    gl_PointSize = size;
                    gl_Position = projectionMatrix * modelViewMatrix * vec4( position , 0, 1 );
                }`,
                fragmentShader:`
                precision highp float;
                varying vec3 vColor;
                void main() {
                    gl_FragColor = vec4( vColor, 1.0 ) ;
                }`
            }) );
            scene.add( points );

以及我对 raycaster 的使用:

    function mouseDown(e) {
                e.preventDefault();

                var mouse = new THREE.Vector2();
                mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
                mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
//                mouse.z = 0;
                raycaster.setFromCamera(mouse, camera);
                raycaster.far = camera.position.z + 3;
                const intersect = raycaster.intersectObject(points);
                console.log(intersect);
                if (intersect.length > 0) {
                    controls.enabled = false;
                    console.log(intersect);
                    selection = intersect[0].index;
                }
            }

        function mouseUp(e) {
            controls.enabled = true;
            var vector = new THREE.Vector3();
            vector.x = (( event.clientX / window.innerWidth ) * 2 - 1);
            vector.y = (- ( event.clientY / window.innerHeight ) * 2 + 1);
            vector.z = 1.0;
            console.log(camera.position.z);
            vector.unproject( camera );

            var dir = vector.sub( camera.position ).normalize();

            var distance = - camera.position.z / dir.z;

            var temp = camera.position.clone().add( dir.multiplyScalar( distance ) );
            var pos = points.geometry.attributes.position;
            pos.setXY(selection, temp.x, temp.y);
            pos.updateRange.offset = selection; // where to start updating
            pos.updateRange.count = 1; // how many vertices to update
            pos.needsUpdate = true;
            selection = undefined;
        }