The orthographic camera method combined with raycasting for object selection

Currently, I'm facing a challenge when it comes to selecting objects with the orthographic camera using the raycaster. Interestingly, I don't encounter any issues when utilizing a perspective camera. The only difference between the two scenarios is the type of camera being used.

In the orthographic view, I am able to select faces, but the selection seems loosely connected to where I click on the screen. Even if I click far away from the object, it still registers as hitting the object near its center.

Do you have any insights into what might be causing this issue?

A lot of my code is based on this example, and I'm aiming to achieve similar results. (The provided example uses a perspective camera)

Any assistance would be greatly appreciated

<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>

This could possibly be something simple that I haven't figured out yet.

Using three.js r60

Answer №1

Implementing raycasting in both orthographic and perspective cameras involves following a specific pattern:

var raycaster = new THREE.Raycaster(); // Initialize only once
var mouse = new THREE.Vector2(); // Initialize only 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 );

This code snippet is for three.js r.84 version.

Answer №2

Here's a helpful tip to avoid any potential issues. If you happen to be using a camera similar to the following:

var cam = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

When performing raycasting, remember to adjust the origin.z of the ray to match the camera.far value so it can detect objects within the entire visible range:

this.raycaster.origin.set(0, 0, 0);
this.camera.localToWorld(this.raycaster.origin);
this.raycaster.setFromCamera(this.mouseCoords, this.camera);
this.raycaster.origin.z = this.camera.far;

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is there a way to toggle checkboxes by clicking on a link?

To toggle the checkboxes within a specific section when a link is clicked within that section, I need to ensure the script functions correctly. The checkboxes and the button must be nested within the same parent element. The HTML markup is provided below. ...

problem with displaying sidebar in Ember template

Using Ember, I have a login page where I don't want to display the header or sidebar navigation for my site until the user is authenticated. Once they are logged in, I want the header and sidebar to be visible. Currently, I am achieving this by checki ...

Struggling with repeatedly traversing characters in a string to solve the Palindrome challenge

I am working on a recursive solution for a Palindrome problem, but it seems that my code is only considering the first recursive call instead of the second one which should analyze all characters in the string. I suspect there might be a logical error in ...

What is the ideal timing to incorporate an error handler in an Observable?

I find myself uncertain about the best practices for error handling in general. For instance, if I'm already handling errors in my service using catchError, is it necessary to also include an error handler in my subscription? Here's an example o ...

What could be the reason behind my Javascript code returning "object object"?

I am a beginner with jQuery. I attempted to calculate the sum of items from my django views using jQuery. Here's what I have so far: $(document).ready(function() { var sch = $('#sch-books'); var gov = $('#gov-books'); ...

Error: The function seems to be malfunctioning or missing

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script> <script type="text/javascript"> $('div'); // <--- THIS DOESN'T WORK </script> An issue has been encountere ...

Steps for inserting an image onto a blank page

Struggling with HTML and javascript - need help with displaying an image on a new page: Creating a new page and want to show an image on it: thepage= window.open('', '', 'height=700,width=800,left=100,top=100,resizable=yes,scroll ...

Performing an ASync call to the GetData routine in MongoClient using NodeJS

Combining code snippets from https://www.w3schools.com/nodejs/nodejs_mongodb_find.asp and https://stackoverflow.com/questions/49982058/how-to-call-an-async-function#:~:text=Putting%20the%20async%20keyword%20before,a%20promise%20to%20be%20resolved. Upon ob ...

Tips for clearing object values without deleting the keys: Resetting the values of an object and its

Upon creating a service to share data among multiple components, it became necessary to reset the object values once the process was complete. To achieve this, I attempted the following: this.UserDetails = {}; This successfully cleared the values and remov ...

Tips on Guaranteeing AJAX Requests are Successfully Called in Sequential Order and Receive Responses in the Same Sequence

What is the best way to guarantee that AJAX requests are executed in a specific order and receive responses in the same order? ...

How can I easily incorporate glow, blur, and wind effects into my scene?

Is there an easy way to incorporate glow, blur, or wind effects into my models or scenes? I'm looking for the simplest method to achieve this. Can you provide some guidance? ...

Why does starting up the Firebase emulators trigger the execution of one of my functions as well?

Upon running firebase emulators:start --only functions,firestore, the output I receive is as follows: $ firebase emulators:start --only functions,firestore i emulators: Starting emulators: functions, firestore ⚠ functions: The following emulators are ...

Calculating the 3D Longitude and Latitude coordinates in a THREE.js globe using the radius along with the x and y values

Currently, I am exploring a Codepen where JSON data is being utilized to feed into a JavaScript application that maps coordinates using x and y values. Rather than utilizing longitude and latitude to map a location like Hong Kong, the developer uses these ...

Cleaning up unwanted objects in THREE.js webGL

Our app utilizes THREE.js to showcase 3D body meshes. We have a special object named MeshViewer that manages the rendering process; within the initialize method, we establish this.renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBu ...

Send the form data from a modal controller in AngularJS to an ng-controller outside of the modal

There seems to be a confusion with the functionality not working as expected: In my Angular application, I have a main page with an ng-controller named "SearchCtrl" that handles sending search requests to a webserver. app.controller('SearchCtrl&apos ...

Waiting for asynchronous subscriptions with RxJS Subjects in TypeScript is essential for handling data streams efficiently

Imagine having two completely separate sections of code in two unrelated classes that are both listening to the same Observable from a service class. class MyService { private readonly subject = new Subject<any>(); public observe(): Observable&l ...

Retrieve an object that includes a property with an array of objects by filtering it with an array of strings

I have a large JSON file filled with data on over 300 different types of drinks, including their ingredients, names, and instructions. Each object in the file represents a unique drink recipe. Here is an example of how one of these objects is structured: ...

Styling HTML elements with CSS to create a full width underline effect

Is there a way to make the underlines/borders full width for each line in a paragraph without adding line breaks? I'm seeking suggestions on how to achieve this. Two potential solutions I've considered are using the tag or creating an image, ...

What could be causing certain emails to disappear when trying to retrieve them through IMAP?

import Imap from 'node-imap' import { simpleParser } from 'mailparser' import { inspect } from 'util' export default async function emailHandler(req, res) { try { const credentials = req.body const imapConnection = ...

What are the best practices for implementing R3F hooks in components for testing with a Rollup build?

While developing an R3F component library, I encountered an issue where I'm getting the Error: R3F: Hooks can only be used within the Canvas component! error when importing it into my project, despite the fact that the component is placed within a Can ...