본문 바로가기

Graphics/playcanvas

[translate] 플레이캔버스 튜토리얼 Entity Picking

Collision Picking - 클릭해보세요

[기능은 같고 구현방법은 달라서 예제 추가안함]

Frame Buffer Picking - 클릭해보세요

에디터에서 실행해보세요 예제 프로젝트

이 튜토리얼은 3D 씬 에서 엔티티를 선택하는 방법을 설명합니다.

Collision Picking

선택기능을 추가할 엔티티에 충돌컴포넌트를 등록함으로써 시작합니다.

그리고 rigidbody 시스템에 있는 racastFirst() 메서드를 이용해서 마우스에서 화면상으로 ray를 발생시킵니다.

그니깐 마우스가 충돌컴포넌트에 Hit하면 엔티티가 선택되는겁니다.

var PickerRaycast = pc.createScript('pickerRaycast');

// initialize code called once per entity
PickerRaycast.prototype.initialize = function() {
    this.app.mouse.on(pc.EVENT_MOUSEDOWN, this.onSelect, this);
};

PickerRaycast.prototype.onSelect = function (e) {
    var from = this.entity.camera.screenToWorld(e.x, e.y, this.entity.camera.nearClip);
    var to = this.entity.camera.screenToWorld(e.x, e.y, this.entity.camera.farClip);

    var result = this.app.systems.rigidbody.raycastFirst(from, to);
    if (result) {
        var pickedEntity = result.entity;
        pickedEntity.script.pulse.pulse();
    }
};

Frame Buffer Picking

프레임버퍼에서 선택(Picking)을 사용하려면 pc.Picker 클래스를 사용해 내부 버퍼에 렌더하게 하면됩니다.

마우스가 클릭되었을대, 마우스의 위치의 칼라버퍼가 어떤 메시 인스턴스가 선택되었는지 결정합니다.

이 방법은 위의 Collision Picking에 비해 장정과 단점이 있습니다. 장점으로는 사각형을 사용하기 때문에 씬에 있는 여러 아이템들을 한꺼번에 선택할수 있다는것입니다. 이것은 따로 물리라이브러리를 필요하지 않습니다. 하지만 단점으로는 readPixels 메서드를 사용함으로써 그래프파이프 라인을 중단시킬수 있다는점입니다. 이것은 모바일 같은 부분에서 렌더링 퍼포먼스 부분에 상당한 영향을 끼칠수있습니다.

var PickerFramebuffer = pc.createScript('pickerFramebuffer');

// initialize code called once per entity
PickerFramebuffer.prototype.initialize = function() {
    // Create a frame buffer picker with a resolution of 1024x1024
    this.picker = new pc.Picker(this.app.graphicsDevice, 1024, 1024);
    this.app.mouse.on(pc.EVENT_MOUSEDOWN, this.onSelect, this);
};

PickerFramebuffer.prototype.onSelect = function (event) {
    var canvas = this.app.graphicsDevice.canvas;
    var canvasWidth = parseInt(canvas.clientWidth, 10);
    var canvasHeight = parseInt(canvas.clientHeight, 10);

    var camera = this.entity.camera.camera;
    var scene = this.app.scene;
    var picker = this.picker;

    picker.prepare(camera, scene);

    // Map the mouse coordinates into picker coordinates and
    // query the selection
    var selected = picker.getSelection({
        x: Math.floor(event.x * (picker.width / canvasWidth)),
        y: picker.height - Math.floor(event.y * (picker.height / canvasHeight))
    });

    if (selected.length > 0) {
        // Get the graph node used by the selected mesh instance
        var entity = selected[0].node;

        // Bubble up the hierarchy until we find an actual Entity
        while (!(entity instanceof pc.Entity) && entity !== null) {
            entity = entity.getParent();
        }
        if (entity) {
            entity.script.pulse.pulse();
        }
    }
};