Limiting the draggable area

Hi,

I’ve loaded a 3D model and I want to limit the dragging property of tree from entering into certain areas(like car ,house etc.) I’ve used dragcontrols, and I would also like to restrict the tree from going outside the base mesh. How to achieve it? Someone please help! I’ve been stuck for a while.

Thank you and below is my script

<script>
    var house,tree,raycaster,mouse,selectedObject,selob;
    let scene,camera,renderer,controls,snow,objects=[],flag=0,flag2=0,flag3=0,positions=[],velocities=[];
    const snowCount=150000;
    const maxRange = 1000, minRange=maxRange/2;
    const minHeight= 150;


    function initialize() {

        scene = new THREE.Scene();
        scene.background = new THREE.Color(0x696969);
        scene.fog = new THREE.Fog(0x1261A0,1,100);
        camera = new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,100);
        camera.position.set(25,8,0);
        

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

        controls = new THREE.OrbitControls(camera,renderer.domElement);
        controls.addEventListener('change',render);
        controls.maxPolarAngle = 1.53;
        controls.minDistance = 8;
        controls.maxDistance = 50;

        const dragControls = new THREE.DragControls( objects, camera, renderer.domElement );

        const directionalLight = new THREE.DirectionalLight(0xffffff,1);
        directionalLight.position.set(0,10,-5);
        directionalLight.target.position.set(-10, 0, 0);
        scene.add(directionalLight);
        scene.add(directionalLight.target);
        
        const hemisphereLight = new THREE.HemisphereLight(0xB1E1FF, 0xB97A20, 1);
        scene.add(hemisphereLight);

        const spotLight = new THREE.SpotLight(0xffffff, 0.3);
        spotLight.position.set(10, 10, 0);
        spotLight.target.position.set(-2, -2, -2);
        scene.add(spotLight);
        scene.add(spotLight.target);

        const planeSize = 4000;
        const repeats = planeSize / 2;

        var groundTexture = new THREE.TextureLoader().load('./textures/1.webp')
        groundTexture.wrapS = THREE.RepeatWrapping;
        groundTexture.wrapT = THREE.RepeatWrapping;
        groundTexture.repeat.set(repeats, repeats);
        const groundGeometry = new THREE.PlaneBufferGeometry(planeSize, planeSize);
        const groundMaterial = new THREE.MeshPhongMaterial({
        map: groundTexture,
         side: THREE.DoubleSide,
        });
        const ground = new THREE.Mesh(groundGeometry, groundMaterial);
        ground.rotation.x = Math.PI * .5;
        ground.position.y=0.61;
        scene.add(ground);

        const snowGeometry = new THREE.BufferGeometry();
        const snowTexture = new THREE.TextureLoader();
        addSnowflakes();

        function addSnowflakes(){
            for(let i =0;i<snowCount;i++) {
                positions.push(   
                    Math.floor(Math.random()* maxRange - minRange),
                    Math.floor(Math.random()* minRange + minHeight),
                    Math.floor(Math.random()* maxRange - minRange));

                velocities.push(
                    Math.floor(Math.random()* 6 - 3) * 0.1,
                    Math.floor(Math.random()* 5 + 0.12) * 0.18,
                    Math.floor(Math.random()* 6 - 3) * 0.1);
                

            }

            snowGeometry.setAttribute('position', new THREE.Float32BufferAttribute(positions,3));
            snowGeometry.setAttribute('velocity', new THREE.Float32BufferAttribute(velocities,3));

            const snowMaterial = new THREE.PointsMaterial({
                size:3,
                map: snowTexture.load('./textures/Ice_cristal_-_heraldic_figure.svg'),
                blending: THREE.AdditiveBlending,
                depthTest:false,
                transparent:true,
                opacity:0.8,

            });
            snow = new THREE.Points(snowGeometry,snowMaterial);
            scene.add(snow);
            
        }

        var hemiSphereGeom = new THREE.SphereBufferGeometry(15,32,16);
        let verts = hemiSphereGeom.attributes.position.array
        for(var i=0;i<verts.length;i+=3){
            if(verts[i+1]<0)
            verts[i+1]=0;
        }
        const hemiSphereMaterial = new THREE.MeshBasicMaterial({wireframe:true,color: "black",transparent:true,opacity:0.25 });
        const hemiSphereMesh = new THREE.Mesh(hemiSphereGeom,hemiSphereMaterial);
        scene.add(hemiSphereMesh);
        hemiSphereMesh.position.y = 1.3;

        const cylinderGeometry = new THREE.CylinderBufferGeometry(15,15,2.5,32);
        const cylinderMaterial = new THREE.MeshBasicMaterial( {color: 0x5B270B, wireframe: false,});
        const cylinderMesh = new THREE.Mesh(cylinderGeometry,cylinderMaterial);
        scene.add(cylinderMesh);

    //DAT.GUI
        class ColorGUIHelper {
        constructor(object, prop) {
        this.object = object;
        this.prop = prop;
        }
        get value() {
        return `#${this.object[this.prop].getHexString()}`;
        }
        set value(hexString) {
        this.object[this.prop].set(hexString);
        }
        }

        {
            const color = 0xFFFFFF;
            const intensity = 1;
            const ambientLight = new THREE.AmbientLight(color, intensity);
            scene.add(ambientLight);

            const gui = new dat.GUI();
            gui.addColor(new ColorGUIHelper(ambientLight, 'color'), 'value').name('Ambient Light');
            gui.add(ambientLight, 'intensity', 0, 2, 0.01).name('Intensity');
        }

    //Loading 3D Model
        let gltfLoader = new THREE.GLTFLoader();
        gltfLoader.load('http://localhost/myproject/3js/3jsdemo/house.gltf',function(gltf){
            scene.add(gltf.scene);
            house = gltf.scene;
            house.traverse(function (child){
                //CAR                
                if(child.name==='initialShadingGrouppolySurface116_polySurface3'){

                    document.onkeydown = (e) => {
                        if(event.keyCode == 37) {
                            if(child.position.z <27.5 ) {
                            child.position.z+=0.35;
                        }
                        }else if(event.keyCode == 39) {
                            if(child.position.z>-4.3) {
                                child.position.z-=0.3;
                        }
                        }
                    }
                }

                //TREE
                if(child.name==='polySurface355_lambert14_0'){
                    tree = child;
                    objects.push(tree);
                    dragControls.addEventListener( 'dragstart', function ( event ) {
                        
                        controls.enabled=false;
                        event.object.material.opacity=0.5;  
                    });

                    dragControls.addEventListener( 'drag', function ( event ) {
                        event.object.position.y=0;
                        // console.log(event.object.position.z)
                        // console.log(event.object.position.x)
                        if(event.object.position.z>32 || event.object.position.x<=1){
                            console.log("Cannot place there");
                            dragControls.enabled=false;
                        }
                        if(event.object.position.z<32 || event.object.position.x>=1){
                            dragControls.enabled=true;
                        }
                   
                    });
                    
                    dragControls.addEventListener( 'dragend', function ( event ) {
                        event.object.material.opacity=1;
                        controls.enabled=true;
                    });
                    

                }
                
                
            });
            gltf.scene.scale.set(0.5,0.5,0.5);
            gltf.scene.position.set(0,1.3,0);
          
        },undefined,function(error) {
            console.log("Error Occured");
            renderer.render(scene,camera);
        
        });
    }

    raycaster = new THREE.Raycaster();
    mouse = new THREE.Vector2(); 
    document.addEventListener('click',onclick,true );
    document.addEventListener( 'pointermove', onPointerMove );
    window.addEventListener('resize',onWindowResize,false);
    initialize();
    animate();
  
    function onclick(event) {
        raycaster.setFromCamera(mouse, camera);
        var intersects = raycaster.intersectObjects(scene.children,true);
            if (intersects.length > 0) {
                selectedObject = intersects[1].object.name;
                selob=intersects[1];
                console.log(selob)


                if(selectedObject=='initialShadingGrouppolySurface116_polySurface3_lambert17_0'){
                    if(flag3==0){
                        intersects[1].object.material.transparent=true;
                        intersects[1].object.material.opacity=0.5;
                        flag3=1;
                    }
                    else{
                    intersects[1].object.material.opacity=1;
                    flag3 = 0;
                    }
                }
                if(selectedObject=='Garage_door_lambert16_0'){   
                    if(flag2==0){
                        intersects[1].object.rotation.set(0,0,-0.6);
                        flag2 = 1; 
                    }
                    else {
                        intersects[1].object.rotation.set(0,0,0);
                        flag2 =0;
                    }          
                }
                if(selectedObject=='House_door_lambert16_0'){
                    if(flag==0){
                        intersects[1].object.position.set(2,0,0)
                        intersects[1].object.rotation.set(0,-0.2,0);
                        flag = 1;
                    }
                    else {
                        intersects[1].object.rotation.set(0,0,0);
                        flag =0;
                    }                               
                }
            }
                
    }

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

    function render() {
        renderer.render(scene,camera);
   
    }
    
    function animate() {
        requestAnimationFrame(animate);
        updateSnow();
        renderer.render(scene,camera);
        controls.update();
    }
    function onWindowResize() {
        camera.aspect = window.innerWidth/window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth,window.innerHeight);
    }


    function updateSnow(){
        for(let i=0; i<snowCount*3; i+=3){
           snow.geometry.attributes.position.array[i]-=snow.geometry.attributes.velocity.array[i];
           snow.geometry.attributes.position.array[i+1]-=snow.geometry.attributes.velocity.array[i+1];
           snow.geometry.attributes.position.array[i+2]-=snow.geometry.attributes.velocity.array[i+2];

            if(snow.geometry.attributes.position.array[i+1]<0) {
               snow.geometry.attributes.position.array[i] =  Math.floor(Math.random()* maxRange - minRange);
               snow.geometry.attributes.position.array[i+1] = Math.floor(Math.random()* minRange + minHeight);
               snow.geometry.attributes.position.array[i+2] = Math.floor(Math.random()* maxRange - minRange);
            }

        }
       snow.geometry.attributes.position.needsUpdate = true;
    }  
</script>

Maybe you can use the approach mentioned here:

@Mugen87 What I want to achieve is that the tree mesh shouldn’t be overlapping with any other meshes, not just limiting the movement between two points


I should be able to place the tree mesh in the black space and limit for other areas(I know the name of that ground mesh ,Should I able to do anything with that?).