mh-alahdadian
mh-alahdadian

Reputation: 383

how to dragging Threejs point

I'm trying to huge graph visualization with threejs r86(latest master version), for showing 600,000 nodes I found a way to draw them faster than using mesh with THREE.points but know I need to make them draggable, after many searches I found raycast to found closest object to mouse point but I have a problem becouse all of taht points are just an object and can not be changed seperately.

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();}

I had able to change all the points with dragControls but can't move them seperatly I had found EventsControls.js file which help us to handle events but I couldn't use it

Upvotes: 1

Views: 1154

Answers (2)

mh-alahdadian
mh-alahdadian

Reputation: 383

Thanks for helping me in previous question. I am making my points in 2d plane (z = 0) and I could making them with bufferGeometry and RawShaderMaterial but now I have another problem in dragging them, how raycaster do? it need vec3 positions but I have changed it for performance purpose.

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 );

and my using of 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;
        }

Upvotes: 0

Scharnvirk
Scharnvirk

Reputation: 337

Here you can check how to target individual parts of a buffer geometry with a raycaster: https://github.com/mrdoob/three.js/blob/master/examples/webgl_interactive_buffergeometry.html

As for moving them, refer to this question and answer: How to quickly update a large BufferGeometry?

Upvotes: 0

Related Questions