Threejs achieves click effect through Raycast

Threejs achieves click effect through Raycast

introduction

In Threejs, in order to achieve the click effect of 3D objects, all objects currently clicked can be obtained through Raycast. I am a novice in threejs, if there is something wrong, I hope everyone can criticize and correct me.

accomplish

1. Obtain all objects through Raycast

There are many examples of this on the Internet, and there are corresponding examples on the official website, so I won’t go into details here.

Raycaster – Three.js Documentation (threejs.org)

const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();

/**
  * 获取点击到的所有物体 
  */
function getIntersects(event, group) {
    
    
    event.preventDefault();
    // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
    var x = ( event.clientX / window.innerWidth ) * 2 - 1;
    var y = - ( event.clientY / window.innerHeight ) * 2 + 1;
    // 通过鼠标点击的位置(二维坐标)和当前相机的矩阵计算出射线的位置
    raycaster.setFromCamera(new THREE.Vector2(x, y), camera);
    // 获取与raycaster射线相交的数组集合,其中的元素按照距离排序,越靠近的越靠前
    var intersects = raycaster.intersectObjects(scene, true);
    // 返回选中的对象数组
    return intersects;
}

/**  
  * 点击事件 
  **/
function mouseClick(event) {
    
    
    const intersects = getIntersects(event, deviceGroup);
    if (intersects.length > 0) {
    
    
        //点击到的第一个物体
        let selectObj = intersects[0].object;
        console.log(selectObj);
    }
}

//注册事件,也可以放到div上,根据业务需求来定
window.addEventListener( 'click', mouseClick );

2. Hidden objects can also be clicked

After testing, after hiding the object through visible = false, the object can still be clicked. I use r146. I don’t know if there is a problem with my use, or what, the hidden object will still be clicked, so here we have to deal with this problem. My solution is to filter hidden objects after getting all clicked objects.

Determine whether the object is hidden in the scene.


/**
 * 物体是否在场景中显示 
 * @param {THREE.Object3D} obj 3D物体
 * @return {Boolean} 是否在场景中显示
 * */
function ActiveInHierarchy(obj) {
    
    
    if (!obj.visible) {
    
    
        return false;
    }
    //遍历父对象
    let parent = obj.parent;
    while (parent) {
    
    
        if (!parent.visible) {
    
    
            return false;
        }
        parent = parent.parent;
    }
    return true;
}

3. Canvas is not full screen

When the canvas is not full screen, using the above method will cause a click offset, obviously when the object is clicked but not clicked.


/**
 * 获取点击到的所有物体
 * @param {THREE.Event} event 点击事件
 * @param {THREE.Camera} camera 摄像机
 * @param {THREE.Group} group group
 * @param {Boolean} visible 物体隐藏还是显示
 * @return {Array} 射线下的所有物体
 *  */
function GetIntersects(event, camera, group, visible) {
    
    
    let canvas = event.path[0];
    event.preventDefault();
    /**
     * THREE.Raycaster 对象从屏幕上的点击位置向场景发射的一束光线
     *  THREE.Raycaster,THREE.Vector2():声明raycaster 和mouse变量
     * */
    var raycaster = new THREE.Raycaster();
    //处理画布与电脑屏幕存在偏移量问题
    var divObj = canvas.getBoundingClientRect();
    // 获取鼠标点击位置
    var Sx = event.clientX - divObj.left;
    var Sy = event.clientY - divObj.top;
    // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
    var x = (Sx / canvas.width) * 2 - 1;
    var y = -(Sy / canvas.height) * 2 + 1;
    // 通过鼠标点击的位置(二维坐标)和当前相机的矩阵计算出射线的位置
    raycaster.setFromCamera(new THREE.Vector2(x, y), camera);
    // 获取与raycaster射线相交的数组集合,其中的元素按照距离排序,越靠近的越靠前
    var intersects = raycaster.intersectObjects(group.children, true);
    let objs = [];
    intersects.forEach(object => {
    
    
        if (ActiveInHierarchy(object.object) == visible) {
    
    
            objs.push(object);
        }
    });
    // 返回选中的对象数组query
    return objs;
}

Guess you like

Origin blog.csdn.net/yr1102358773/article/details/127811365