2011-10-31 9 views
18

많은 요소가 나타나는 THREE.js 장면이 있는데 사용자가 클릭하고있는 개체를 감지해야합니다.THREE.js에서 클릭 된 개체 감지

지금까지 내가 한 것은 다음과 같습니다. 카메라가 많이 움직이지 않습니다. 수직 위치가 제한된 양만큼만 변경되므로 항상 같은 지점을 바라보아야합니다. 캔버스에 클릭 상대는

  • 나는 간단한 스케일링에 의해 WebGL이 장면에서 수평 및 수직 좌표로 변환하고, Z를 추가 할 경우

    • 나는 좌표를 가지고 : 내 대략적인 방법은 다음과 같다 좌표가 충분히 떨어져있다.
    • THREE.Ray()에 의해 생성 된 위의 지점부터 수평선을 취합니다.
    • 광선을 따라 첫 번째 요소를 찾으려면 ray.intersectObjects()를 사용합니다.

    이 방법은 대체로 효과가 있지만 때로는 실제 지점에서 몇 픽셀 떨어져 있습니다.

    사용자가 클릭 한 개체를 찾는 더 신뢰할만한 기술이 있습니까?

  • +0

    여백 및 여백 때문에 좌표가 약간 벗어날 수 있습니다. 당신이 그것을 설명 했습니까? – Prusse

    +0

    데모의 순간에는 마진이나 패딩이 없지만 설명 된 기술은 정확하지 않습니다. – Andrea

    +4

    [이 예제] (http://mrdoob.github.com/three.js/examples/canvas_interactive_cubes.html)를보십시오. –

    답변

    7

    어떤 종류의 카메라를 사용하고 있는지에 따라 다릅니다.

    1) PerspectiveCamera는 : Mr.doob가 제공하는 확인 링크입니다.
    2) OrthographicCamera는 :

    var init = function() { 
        camera = new THREE.OrthographicCamera(SCREEN_WIDTH/- 2, SCREEN_WIDTH/2, SCREEN_HEIGHT/2, SCREEN_HEIGHT/- 2, NEAR, FAR); 
        document.addEventListener('mousedown', onDocumentMouseDown, false); 
    } 
    
    function onDocumentMouseDown(e) { 
        e.preventDefault(); 
        var mouseVector = new THREE.Vector3(); 
        mouseVector.x = 2 * (e.clientX/SCREEN_WIDTH) - 1; 
        mouseVector.y = 1 - 2 * (e.clientY/SCREEN_HEIGHT); 
        var raycaster = projector.pickingRay(mouseVector.clone(), camera); 
        var intersects = raycaster.intersectObject(TARGET); 
        for(var i = 0; i < intersects.length; i++) { 
        var intersection = intersects[ i ], 
        obj = intersection.object; 
        console.log("Intersected object", obj); 
        } 
    } 
    
    +0

    "projector.pickingRay"가 제거 되었습니까? –

    +2

    대체 솔루션 https://github.com/mrdoob/three.js/issues/5587 –

    3

    체크 아웃이 하나 : 매우 다른 차원 공간에서 마우스의 교차로와 큐브의에 대한

    var camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 1, 5000); 
    var object; //your object 
    
    document.addEventListener('mousedown', onMouseDown, false); 
    
    function onMouseDown(e) { 
        var vectorMouse = new THREE.Vector3(//vector from camera to mouse 
         -(window.innerWidth/2-e.clientX)*2/window.innerWidth, 
         (window.innerHeight/2-e.clientY)*2/window.innerHeight, 
         -1/Math.tan(22.5*Math.PI/180)); //22.5 is half of camera frustum angle 45 degree 
        vectorMouse.applyQuaternion(camera.quaternion); 
        vectorMouse.normalize();   
    
        var vectorObject = new THREE.Vector3(); //vector from camera to object 
        vectorObject.set(object.x - camera.position.x, 
            object.y - camera.position.y, 
            object.z - camera.position.z); 
        vectorObject.normalize(); 
        if (vectorMouse.angleTo(vectorObject)*180/Math.PI < 1) { 
         //mouse's position is near object's position 
    
        } 
    } 
    
    +0

    이것은 매우 좋은 솔루션이며 CPU 집약적 인 레이 캐스트를 방지하지만 마우스가 객체의 피벗 근처를 클릭하는 경우에만 보입니다 . Avantage는 mesh aso가없는 객체가 이런 방식으로 작동한다는 것입니다. 단점은 원형 "핫스팟"입니다. – Hacky

    2

    확인하고 색상의 변경합니다. 어쩌면 this 당신을 도울 수 있습니다.

    +3

    스택 오버플로에 오신 것을 환영합니다! 잠깐 시간을내어 [How to Answer] (http://stackoverflow.com/questions/how-to-answer)를 읽으십시오.이 코드는 도움이 되겠지만 코드가하는 것에 대한 설명이 도움이 될 것입니다. [편집] http://stackoverflow.com/posts/41385887/edit-ing that in? –

    0

    화면의 전체 너비와 높이를 차지하지 않는 캔버스에이 기능을 구현할 때 문제가 발생했습니다. 여기 내가 찾은 해결책이 꽤 잘 작동합니다.

    기존의 캔버스에 모든 것을 초기화 :

    var init = function() { 
        var canvas_model = document.getElementById('model') 
        var viewSize = 50 // Depending on object size, canvas size etc. 
        var camera = new THREE.OrthographicCamera(-canvas_model.clientWidth/viewSize, canvas_model.clientWidth/viewSize, canvas_model.clientHeight/viewSize, -canvas_model.clientHeight/viewSize, 0.01, 2000), 
    } 
    

    캔버스에 이벤트 리스너를 추가

    canvas_model.addEventListener('click', function(event){ 
        var bounds = canvas_model.getBoundingClientRect() 
        mouse.x = ((event.clientX - bounds.left)/canvas_model.clientWidth) * 2 - 1; 
        mouse.y = - ((event.clientY - bounds.top)/canvas_model.clientHeight) * 2 + 1; 
        raycaster.setFromCamera(mouse, camera); 
        var intersects = raycaster.intersectObjects(scene.children, true); 
        if (intersects.length > 0) { 
        // Do stuff 
        } 
    }, false) 
    

    아니면 'touchstart'이벤트에 대한

    에서, mouse.x 계산 라인을 변경하고 mouse.y 입력 :

    mouse.x = ((event.touches[0].clientX - bounds.left)/canvas_model.clientWidth) * 2 - 1; 
    mouse.y = - ((event.touches[0].clientY - bounds.top)/canvas_model.clientHeight) * 2 + 1;