2016-11-11 33 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拾取精灵的区域,它会比精灵大。就好像精灵更大,并且移动到它在屏幕上显示的位置的右​​侧。我感觉好像我的相机有问题,但我不知道它会是什么。 –