一, 场景设计

Cocos Creator 3.x之点击选择3D物体_ray

二, SelectView.ts

import {
    _decorator,
    Component,
    Node,
    Camera,
    MeshRenderer,
    Mesh,
    EventTouch,
    input,
    Input,
    Vec2,
    v2,
    geometry,
    PhysicsSystem,
    PhysicsRayResult,
    Material,
    isValid
} from "cc";

const {ccclass, property} = _decorator;

@ccclass("SelectView")
export class SelectView extends Component {
    @property({type: Material, tooltip: "没有选中的材质"})
    private unSelectMtl: Material = null;
    @property({type: Material, tooltip: "选中的材质"})
    private selectMtl: Material = null;

    private tempScreenV2: Vec2;
    private tempScreenRay: geometry.Ray;
    private curSelect3DNode: Node;
    private camera3D: Camera = null;

    public init(camera3D: Camera): void {
        this.camera3D = camera3D;
    }

    protected onLoad(): void {
        this.tempScreenV2 = v2();
        this.tempScreenRay = new geometry.Ray();
    }

    protected onEnable(): void {
        this.listener(true);
    }

    protected onDisable(): void {
        this.listener(false);
    }

    private listener(isAdd: boolean): void {
        if (isAdd) {
            input.on(Input.EventType.TOUCH_END, this.onTouchHandler, this);
        } else {
            input.off(Input.EventType.TOUCH_END, this.onTouchHandler, this);
        }
    }

    private onTouchHandler(e: EventTouch): void {
        switch (e.type) {
            case Input.EventType.TOUCH_END:
                this.select3DObject(e);
                break;
        }
    }

    private setMaterial(mtl: Material): void{
        if(!isValid(this.curSelect3DNode)) return;
        let meshRenderer: MeshRenderer = this.curSelect3DNode.getComponent(MeshRenderer);
        if(!meshRenderer) return;
        meshRenderer.material = mtl;
    }

    private select3DObject(e: EventTouch): void {
        this.tempScreenV2 = e.getLocation();//获得屏幕坐标
        this.camera3D.screenPointToRay(this.tempScreenV2.x, this.tempScreenV2.y, this.tempScreenRay);//构建一条射线
        if (PhysicsSystem.instance.raycastClosest(this.tempScreenRay, PhysicsSystem.PhysicsGroup.DEFAULT) == true) {
            let ressult: PhysicsRayResult = PhysicsSystem.instance.raycastClosestResult;//最近的一个碰撞体
            this.setMaterial(this.unSelectMtl);
            this.curSelect3DNode = ressult.collider.node;
            let name: string = ressult.collider.node.name;//名称
            this.setMaterial(this.selectMtl);
        } else {
            if (!this.curSelect3DNode) return;
            this.setMaterial(this.unSelectMtl);
            this.curSelect3DNode = null;
        }
    }
}