正交相机和使用射线选取物体

12

使用正交相机和射线投射器选择对象时,我遇到了一些困难。然而,当我使用透视相机时,我没有任何问题。在切换两者之间唯一更改的是相机类型。

我能够在正交视图上选择面,但它只与我在屏幕上点击的位置松散相关。我可以远离物体单击,它仍将返回为如果它已经击中了靠近其中心的物体。

你们有什么想法,我在这里错过了什么吗?

我的代码主要基于这个示例,我希望从我的代码中实现非常类似的结果。(这个我参考的示例使用透视相机)

非常感谢您的任何帮助。

<html>
<head>
  <style>
    canvas {
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
      position: fixed;
      background-color: #111115;
    }
  </style>
</head>
<body id='c'>
  <script src="js/three.js"></script>

  <script>

    var obj = [];
    var mouse ={};
    var zoom = 2;

    var scene = new THREE.Scene();

    //switch between these two and see the difference:
    //var camera =  new THREE.OrthographicCamera(window.innerWidth / -zoom, window.innerWidth / zoom, window.innerHeight / zoom, window.innerHeight / -zoom, -1000, 1000);
    var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );

    camera.position = new THREE.Vector3(100,100,100);
    camera.lookAt(new THREE.Vector3(0,0,0));

    // this material causes a mesh to use colors assigned to faces
    var material = new THREE.MeshBasicMaterial( 
    { color: 0xffffff, vertexColors: THREE.FaceColors } );

    var sphereGeometry = new THREE.SphereGeometry( 80, 32, 16 );
    for ( var i = 0; i < sphereGeometry.faces.length; i++ ) 
    {
      face = sphereGeometry.faces[ i ]; 
      face.color.setRGB( 0, 0, 0.8 * Math.random() + 0.2 );     
    }
    obj['box'] = {};
    obj['box'] = new THREE.Mesh( sphereGeometry, material );
    obj['box'].castShadow = true;
    obj['box'].receiveShadow = true;
    scene.add(obj['box']);

    var ambientLight = new THREE.AmbientLight(0xbbbbbb);
    scene.add(ambientLight);

    var directionalLight = new THREE.DirectionalLight(0xffffff, 1);
    directionalLight.position.set(-100, 40, 100);
    directionalLight.castShadow = true;
    directionalLight.shadowOnly = true;
    directionalLight.shadowDarkness = .5;
    scene.add(directionalLight); 

    var renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMapEnabled = true;
    renderer.shadowMapSoft = true;
    document.body.appendChild(renderer.domElement);

    projector = new THREE.Projector();
    document.addEventListener( 'mousedown', onDocumentMouseDown, false );
    function onDocumentMouseDown( event ) {
      // the following line would stop any other event handler from firing
      // (such as the mouse's TrackballControls)
      // event.preventDefault();

      console.log("Click.");

      // update the mouse variable
      mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
      mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

      // find intersections

      // create a Ray with origin at the mouse position
      //   and direction into the scene (camera direction)
      var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
      projector.unprojectVector( vector, camera );
      var ray = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );

      // create an array containing all objects in the scene with which the ray intersects
      var intersects = ray.intersectObjects( [obj['box']] );

      // if there is one (or more) intersections
      if ( intersects.length > 0 )
      {
        console.log("Hit @ " + toString( intersects[0].point ) );
        console.log(intersects);
        // change the color of the closest face.
        intersects[ 0 ].face.color.setRGB( 0.8 * Math.random() + 0.2, 0, 0 ); 
        intersects[ 0 ].object.geometry.colorsNeedUpdate = true;
      }
    }

    function toString(v) { return "[ " + v.x + ", " + v.y + ", " + v.z + " ]"; }

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

    console.log(camera);
    console.log(obj['box'])
    render();

    </script>
</body>

我希望这只是一些我还不知道的简单问题。

three.js r60


1
提示:你的 OrthographicCameranear 平面是负数。这是在相机后面。它应该是正数。此外,前四个参数是世界坐标,而不是像素坐标,所以不要混淆。 - WestLangley
2个回答

21

这是在正交相机或透视相机中进行光线投射时使用的模式:

var raycaster = new THREE.Raycaster(); // create once
var mouse = new THREE.Vector2(); // create once

...

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( objects, recursiveFlag );

three.js r.84


1
感觉很不舒服,因为选择代码取决于相机类型。谢谢。 - KregHEk
1
......但比起在WebGL中自己制作,要好得多 :) - potomek
请添加相机配置,因为您呈现的代码片段依赖于它。 - ryanafrish7

2

还有一点需要注意,这可能会为您节省一些麻烦。如果您拥有这样的相机:

var camera = new THREE.OrthographicCamera(0, window.innerWidth, -window.innerHeight, 0, -100, 100);

在进行射线投射期间,请确保将射线起点的z坐标移动到相机的远裁剪面,以便它能够击中整个可见范围内的任何物体:

this.ray.origin.set(0, 0, 0);
this.camera.localToWorld(this.ray.origin);
this.ray.setFromCamera(this.mouseCoord, this.camera);
this.ray.origin.z = this.camera.far;

太好了 :) 我还要补充一下,this.ray = this.raycaster.ray。 - Timtest
请问您能否提供一个完整的例子? - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接