2016-11-11 32 views
0

我已經看過很多示例 - 並從某些借用 - 似乎無法使其正常工作。我想要的是onDocumentMouseDown中的raycaster在用戶點擊精靈可見表面上的任何位置時拾取精靈。我得到的是一個未對齊的結果,因爲如果用戶在精靈的右側,上方或下方點擊某個精靈,並且根本不會在用戶點擊左側邊緣時完成拾取的精靈。所以基本上有些東西是錯位的,而且我搞不清楚我做錯了什麼。任何指導將不勝感激。無法使Three.js onDocumentMouseDown正常工作

<script src="/common/three.js"></script> 
<script src="/common/Detector.js"></script> 
<script src="/common/CanvasRenderer.js"></script> 


<script src="/common/GeometryUtils.js"></script> 
<script src="/common/OrbitControls.js"></script> 

<div id="WebGLCanvas"></div> 



<script> 
    var container, scene, camera, renderer, controls; 
    var keyboard; 

</script> 

<script> 




    // custom global variables 
    var mouse = { x: 0, y: 0 }; 
    var raycaster; 
    var sprites = new Array(); 
    init(); 
    try { 
     for (i = 0; i < 10; i++) { 
      var text = "Text " + i; 
      var x = Math.random() * 100; 
      var y = Math.random() * 100; 
      var z = Math.random() * 100; 
      var spritey = addOrUPdateSprite(text, i, x, y, z); 
     } 

    } 
    catch (ex) { 
     alert("error when creating sprite: " + ex.message); 
    } 


    animate(); 



    function init() { 
     try { 
      scene = new THREE.Scene(); 
      // CAMERA 
      var cont = document.getElementById("WebGLCanvas"); 
      var SCREEN_WIDTH = window.innerWidth; 
      OFFSET_TOP = document.getElementById("WebGLCanvas").getBoundingClientRect().top; 
      var SCREEN_HEIGHT = window.innerHeight - OFFSET_TOP; //; //-document.getElementById("upper").clientHeight; 
      var VIEW_ANGLE = 60; 
      var ASPECT = SCREEN_WIDTH/SCREEN_HEIGHT; 
      var NEAR = 0.1; 
      var FAR = 1000; 
      camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR); 
      scene.add(camera); 
      camera.position.set(0, 100, 200); 
      camera.lookAt(new THREE.Vector3()); 
      renderer = new THREE.WebGLRenderer({ antialias: true }); 
      container = document.getElementById('WebGLCanvas'); 
      container.appendChild(renderer.domElement); 
      renderer.setSize(window.innerWidth, SCREEN_HEIGHT); 

      controls = new THREE.OrbitControls(camera, renderer.domElement); 
      //    spritey.position.normalize(); 

      raycaster = new THREE.Raycaster(); 
      document.addEventListener('mousedown', onDocumentMouseDown, false); 
      document.addEventListener('touchstart', onDocumentTouchStart, false); 
     } 
     catch (ex) { 
      alert("error " + ex.message); 
     } 


    } 

    function animate() { 
     requestAnimationFrame(animate); 
     render(); 
     update(); 
    } 

    function update() { 
     controls.update(); 
    } 

    function render() { 
     renderer.render(scene, camera); 
    } 

    function addOrUPdateSprite(text, name, x, y, z) { 
     var sprite = scene.getObjectByName(name); 
     if (sprite == null) { 
      sprite = makeTextSprite(text, { fontsize: 36, borderColor: { r: 255, g: 0, b: 0, a: 1.0 }, backgroundColor: { r: 255, g: 100, b: 100, a: 0.8 } }); 
      sprite.name = name; 
      sprites.push(sprite); 
      scene.add(sprite); 
     } 

     sprite.position.set(x, y, z); 
    } 

    function makeTextSprite(message, parameters) { 
     if (parameters === undefined) parameters = {}; 
     var fontface = parameters.hasOwnProperty("fontface") ? parameters["fontface"] : "sans-serif"; 
     var fontsize = parameters.hasOwnProperty("fontsize") ? parameters["fontsize"] : 36; 
     var borderThickness = parameters.hasOwnProperty("borderThickness") ? parameters["borderThickness"] : 1; 
     var borderColor = parameters.hasOwnProperty("borderColor") ? parameters["borderColor"] : { r: 0, g: 0, b: 0, a: 1.0 }; 
     var backgroundColor = parameters.hasOwnProperty("backgroundColor") ? parameters["backgroundColor"] : { r: 255, g: 255, b: 255, a: 1.0 }; 
     var textColor = parameters.hasOwnProperty("textColor") ? parameters["textColor"] : { r: 0, g: 0, b: 0, a: 1.0 }; 

     var canvas = document.createElement('canvas'); 
     var context = canvas.getContext('2d'); 
     context.font = fontsize + "px " + fontface; 
     var metrics = context.measureText(message); 
     var textWidth = metrics.width; 

     context.fillStyle = "rgba(" + backgroundColor.r + "," + backgroundColor.g + "," + backgroundColor.b + "," + backgroundColor.a + ")"; 
     context.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + "," + borderColor.b + "," + borderColor.a + ")"; 

     context.lineWidth = borderThickness; 
     roundRect(context, borderThickness/2, borderThickness/2, (textWidth + borderThickness) * 1.1, fontsize * 1.4 + borderThickness, 8); 

     context.fillStyle = "rgba(" + textColor.r + ", " + textColor.g + ", " + textColor.b + ", 1.0)"; 
     context.fillText(message, borderThickness, fontsize + borderThickness); 

     var texture = new THREE.Texture(canvas) 
     texture.needsUpdate = true; 

     var spriteMaterial = new THREE.SpriteMaterial({ map: texture, useScreenCoordinates: false }); 
     var sprite = new THREE.Sprite(spriteMaterial); 
     sprite.scale.set(1.0 * fontsize, 0.5 * fontsize, 1.5 * fontsize); 
     return sprite; 


    } 

    // function for drawing rounded rectangles 
    function roundRect(ctx, x, y, w, h, r) { 
     ctx.beginPath(); 
     ctx.moveTo(x + r, y); 
     ctx.lineTo(x + w - r, y); 
     ctx.quadraticCurveTo(x + w, y, x + w, y + r); 
     ctx.lineTo(x + w, y + h - r); 
     ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h); 
     ctx.lineTo(x + r, y + h); 
     ctx.quadraticCurveTo(x, y + h, x, y + h - r); 
     ctx.lineTo(x, y + r); 
     ctx.quadraticCurveTo(x, y, x + r, y); 
     ctx.closePath(); 
     ctx.fill(); 
     ctx.stroke(); 
    } 



    function onDocumentTouchStart(event) { 
     event.preventDefault(); 

     event.clientX = event.touches[0].clientX; 
     event.clientY = event.touches[0].clientY; 
     onDocumentMouseDown(event); 



    } 

    function onDocumentMouseDown(event) { 
     mouse.x = (event.clientX/renderer.domElement.clientWidth) * 2 - 1; 
     mouse.y = -((event.clientY)/renderer.domElement.clientHeight) * 2 + 1; 
     raycaster.setFromCamera(mouse, camera); 

     var intersects = raycaster.intersectObjects(sprites, true); 

     if (intersects.length > 0) { 
      var obj = intersects[0].object; 

      alert(obj.name); 

      event.preventDefault(); 
     } 


    } 




</script> 

回答

1

在你makeTextSprite()功能,後

var textWidth = metrics.width; 

添加此

context.strokeStyle = "white"; 
context.lineWidth = 5; 
context.strokeRect(0,0,canvas.width, canvas.height); 

,你會看到,你的精靈有沒有你認爲的大小。

UPD。您可以設置畫布大小這樣

var ctxFont = "bold " + fontsize + "px " + fontface; 
var canvas = document.createElement('canvas'); 
var context = canvas.getContext('2d'); 
context.font = ctxFont; 
var metrics = context.measureText(message); 
var textWidth = metrics.width; 

canvas.width = textWidth + borderThickness * 2; 
canvas.height = fontsize * 1.2 + (borderThickness * 2); 
context = canvas.getContext('2d'); 
context.font = ctxFont; 

,然後設置一個精靈

sprite.scale.set(canvas.width/10, canvas.height/10, 1); 

jsfiddle例如

+0

有趣,謝謝!我認爲這解釋了爲什麼廣泛的截斷。你知道是否有任何方法讓實際大小隻是需要的? –

+0

感謝prisoner849,這是非常有用的,因爲它已修復了我不知道的畫布寬度問題,現在文本不再被截斷,並且在可見精靈之外單擊不會被拾取。然而,仍然存在一個問題,那就是精靈左側的點擊仍然沒有被拾取,點擊精靈最右側也是如此。就好像射線照相機現在認爲精靈比它小。你的jsfiddle似乎承擔了這一點。這是一個戲劇性的改進,所以我很感激!任何更多的技巧你的冷笑? –

+0

我發現這個[SO問題](http://stackoverflow.com/questions/36123458/three-raycaster-not-working-properly-with-scaled-three-sprite)。簡而言之:精靈越接近正方形(方形)越好。因此,最好儘可能靠近精靈的中心點。 – prisoner849

0

您的Three.js畫布可能不在屏幕的左上角,而且您沒有考慮頁面上0,0的偏移量。要修復它,調整鼠標位置以減去偏移量。

var rect = container.getBoundingClientRect(); 
mouse.x = ((event.clientX - rect.left)/renderer.domElement.clientWidth) * 2 - 1; 
mouse.y = -((event.clientY - rect.top)/renderer.domElement.clientHeight) * 2 + 1; 
+0

沒有規模,這不是它。並且它不僅在0,0,而且如果你繪製出raycaster拾取精靈的區域,它會比精靈大。就好像精靈更大,並且移動到它在屏幕上顯示的位置的右​​側。我感覺好像我的相機有問題,但我不知道它會是什麼。 –