Manipulate objects in three.js to always face the mouse pointer

It seems that despite my efforts, I am struggling with this task as I am relatively new to it. Surprisingly, I am not getting any errors in Dreamweaver.

I've started fresh by integrating the look at function with the OBJ loader, camera, and lights in my current example.

While I believe I have a decent grasp of what the code is doing, it's still not functioning as expected. My assumption is that the issue lies in the code for window resizing. The look at function does not seem to adjust for this, causing it to fail as it assumes a fixed window size. Is my analysis of the situation correct?

Additionally, I'm uncertain if the two commented lines in the obj loader are necessary: object.rotateX(Math.PI / 2); and object.lookAt(new THREE.Vector3(0, 0, 0));. Are these lines just setting the initial position? Reintroducing these lines would simply rotate the object to an initial pose without adjusting it relative to the mouse position.

I'm struggling to identify the source of the conflict in my code.

Below is the updated code:

<script>

var SCREEN_WIDTH = window.innerWidth;
var SCREEN_HEIGHT = window.innerHeight;

var camera, scene;
var canvasRenderer, webglRenderer;

var container, mesh, geometry, plane;

var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

init();
animate();

function init() {

    container = document.createElement('div');
    document.body.appendChild(container);

    camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 1500);
    camera.position.x = 0;
    camera.position.z = 100;
    camera.position.y = 0;
    camera.lookAt({
        x: 0,
        y: 0,
        z: 0,
    });

    scene = new THREE.Scene();

    // LIGHTS
    scene.add(new THREE.AmbientLight(0x666666, 0.23));

    var light;

    light = new THREE.DirectionalLight(0xffc1c1, 2.20);
    light.position.set(0, 100, 0);
    light.position.multiplyScalar(1.2);

    light.castShadow = true;
    light.shadowCameraVisible = true;

    light.shadowMapWidth = 512;
    light.shadowMapHeight = 512;

    var d = 50000;

    light.shadowCameraLeft = -d;
    light.shadowCameraRight = d;
    light.shadowCameraTop = d;
    light.shadowCameraBottom = -d;

    light.shadowcameranear = 0.5;
    light.shadowCameraFar = 1000;
    //light.shadowcamerafov = 30;
    light.shadowDarkness = 0.1;

    scene.add(light);

    var mtlLoader = new THREE.MTLLoader();
                mtlLoader.setPath( 'model/' );
                mtlLoader.load( 'rope.mtl', function( materials ) {
                    materials.preload();
                    var objLoader = new THREE.OBJLoader();
                    objLoader.setMaterials( materials );
                    objLoader.setPath( 'model/' );
                    objLoader.load( 'rope.obj', function ( object ) {

            var positionX = 0;
            var positionY = 0;
            var positionZ = 0;

          object.position.x = positionX;
          object.position.y = positionY;
          object.position.z = positionZ;
          object.scale.x = 1;
          object.scale.y = 1;
          object.scale.z = 1;
          //object.rotateX(Math.PI / 2);

          //object.lookAt(new THREE.Vector3(0, 0, 0));

          // castshow setting for object loaded by THREE.OBJLoader()
          object.traverse( function ( child ) {
            if ( child instanceof THREE.Mesh ) {
              child.castShadow = true;
              child.receiveShadow = true;
            }
          });

          scene.add(object);
            });
        });



    // RENDERER
    //webglRenderer = new THREE.WebGLRenderer();
    webglRenderer = new THREE.WebGLRenderer({
    antialias: true
    });
    webglRenderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
    webglRenderer.domElement.style.position = "relative";
    webglRenderer.shadowMapEnabled = true;
    webglRenderer.shadowMapSoft = true;
    //webglRenderer.antialias: true;

    container.appendChild(webglRenderer.domElement);
    window.addEventListener('resize', onWindowResize, false);
}

window.addEventListener("mousemove", onmousemove, false);

var plane = new THREE.Plane(new THREE.Vector3(0, 0, 0), 0);
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var intersectPoint = new THREE.Vector3();

function onmousemove(event) {
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    raycaster.setFromCamera(mouse, camera);
    raycaster.ray.intersectPlane(plane, intersectPoint);
    object.lookAt(intersectPoint);
}       

function onWindowResize() {
    windowHalfX = window.innerWidth / 2;
    windowHalfY = window.innerHeight / 2;

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    webglRenderer.setSize(window.innerWidth, window.innerHeight);
}


function animate() {

    requestAnimationFrame(animate);
    render();

}

function render() {
    camera.lookAt(scene.position);
    webglRenderer.render(scene, camera);
}

    </script>

Answer №1

After modifying your code to eliminate the need for an object, I integrated it into this CodePen. One key issue that stood out was that the intersection plane was incorrectly defined. The normal vector, which is the first argument, should have a length of 1. In your case, it was set to 0, resulting in insignificant intersections.

var plane = new THREE.Plane(new THREE.Vector3(0, 0, 0), 0);

By adjusting it to

var plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 10);

the intersections became more meaningful, leading to the successful rotation of the object.

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 determine the duration that a click was held down for?

When triggering an onClick event, I want to determine whether it was a single click or if the mouse button was held down for some time before releasing. This way, I can call the myTest() function within onClick="myTest()", which will log "mouse was click ...

Troubleshooting MongoDB query criteria in Meteor and JavaScript doesn't yield the expected results

I am encountering an issue with a Products collection that has an attribute called "productCode". My goal is to create a server-side query to fetch a product based on the productCode attribute. Unfortunately, I keep running into a "cannot read property &ap ...

Determine the y-coordinate of terrain in Three.js

I have acquired a Collada model of terrain and now wish to incorporate other models onto this terrain. To achieve this, I believe I need to retrieve the height coordinate (y) of the terrain based on specific x and z coordinates. Can someone please guide ...

Displaying a dynamic map with real-time coordinates sourced from a database using a combination of ajax and php

I'm currently facing an issue where my solution to retrieve coordinates for a specific place from a database and display a map centered on them is not working as expected. The problem seems to be arising because the map is being initialized without an ...

Transferring properties from React Router to child components on the server side

For my Isomorphic app using React, react-router v3, and material-ui, it's crucial to pass the client's user agent to the theme for server-side rendering. This is necessary for MUI to properly prefix inline styles. Initially, the root component o ...

Error: JavaScript function call did not provide a return value

Currently, I am in the process of creating a straightforward angular2/expressJS application. Within my expressJS code, I have an HTTP GET router call that retrieves all users from MongoDB and successfully returns them: app.get('/getusers', funct ...

Fixing Timezone Issue in VueJs 3 with Axios POST Request

Having an issue with axios. In my application, I have an input field for datetime-local. When I select a date and time, the displayed time is correct (e.g., selecting 10:00 shows as 10:00), but when calling a function using axios.post, the request sends th ...

Extracting the JQuery library from its source code

Is there a simple method for extracting only the necessary functions from the jQuery library? I have found that many of the functions within the library are not being utilized, so it would be beneficial to remove them. ...

Performing numerous asynchronous MongoDB queries in Node.js

Is there a better way to write multiple queries in succession? For example: Space.findOne({ _id: id }, function(err, space) { User.findOne({ user_id: userid }, function(err, user) { res.json({ space: space, user: user}); }); }); It can g ...

Mongoose Alert Utility Directive

const mongoose = require('mongoose'); module.exports = { init: () => { const dbOptions = { useNewUrlParser: true, useUnifiedTopology: true, autoIndex: false, reconnectTries: Number.MA ...

Having trouble getting Three.js to run on your local machine? Any suggestions on how to

I've decided to give Three.js a try, but I'm encountering some problems with running it. Following the tutorial on the website: <html> <head> <title>My first Three.js app</title> <style>canvas { ...

Blip Scripts: Converting JSON to JavaScript - Dealing with Undefined Arrays

I am currently working on a project to develop a bot on Blip. There are certain parts where I need to send a request to an API and then use a JavaScript script to extract elements from the JSON response. The JSON response I received from the API is stored ...

Retrieving components from Ajax response data

While I have a good grasp of PHP, diving into AJAX and dealing with JSON is proving to be quite challenging for me. My PHP script simply delivers a straightforward JSON string like this: {"bindings": [ {"ircEvent": "PRIVMSG", "method": "newURI", "regex": ...

Expanding the StringConstructor in TypeScript results in a function that is not defined

I'm currently trying to enhance the String class in TypeScript 2.5 by adding a static method, which will be compiled to ES5. Here's what I have in StringExtensions.d.ts: declare interface StringConstructor { isNullOrEmpty(value: string | nu ...

I am unable to deliver an email to the mailbox

Whenever I try to send an email, I encounter an issue. In order to complete the registration process, a confirmation mail needs to be sent. The error message that I receive is: Callback must be a function at maybeCallback const fs = require(& ...

the order of initialization in angularjs directives with templateUrl

In my current scenario, I am faced with a situation where I need to broadcast an event from one controller and have another directive's controller receive the message. The problem arises because the event is sent immediately upon startup of the contro ...

Infinite loop occurring when setting state to child component in React

On a page featuring dropdown menus for content searching, the dropdown is non-functional but provides context. This page serves as a listing page. After performing calculations on the listing page and updating the state, I encounter an infinite loop when ...

Having trouble populating the input text field with the selected value from a dropdown using JavaScript

I have implemented a JavaScript function to retrieve the id of a dropdown select with id='odrid'. The script looks like this: $('#odrid').change(function(){ $.getJSON( 'fetch.php', 'odrid='+$(&ap ...

What is the method for placing a title in the initial column with the help of v-simple-table from Vuetify.js?

I am interested in using the v-simple-table UI component from Vuetify.js to create a table similar to the one shown below. https://i.sstatic.net/QNdpJ.png After creating the code in codesandbox and previewing the output, I noticed that the title is not a ...

The identical animation is experiencing delays in various directions

Having an issue with my image slider - when clicking on the previous image button, the animation takes longer compared to when clicking on the next image button, even though the animation duration is set to be the same for both. Any idea why this might be ...