Incorporating interactive images into a mesh

Even though I'm new to three.js, I've managed to load an obj file on the web and make it controllable via mouse. However, I need help with the next step.

My goal is to overlay a clickable .jpg or .png file onto a section of the existing mesh, linking out to some completed web pages. Can someone guide me or provide an example of how to achieve this? If it's not possible, alternative suggestions are welcome.

The code below is what I currently have, mostly put together from online examples. Please forgive any redundancy or lack of elegance in the code.

var container, stats;

        var camera, scene, renderer;

        var mouseX = 0, mouseY = 0;

        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( 45, window.innerWidth / window.innerHeight, 1, 2000 );
            camera.position.z = 10;


        controls = new THREE.TrackballControls( camera );

        controls.rotateSpeed = 1.0;
        controls.zoomSpeed = 1.2;
        controls.panSpeed = 0.8;

        controls.noZoom = false;
        controls.noPan = false;

        controls.staticMoving = true;
        controls.dynamicDampingFactor = 0.3;

        controls.keys = [ 65, 83, 68 ];

        controls.addEventListener( render );


            // scene

            scene = new THREE.Scene();

            var ambient = new THREE.AmbientLight( 0xFFFFFF );
            scene.add( ambient );

            /*var directionalLight = new THREE.DirectionalLight( 0xffffff );
            directionalLight.position.set( 1, 1, 0 ).normalize();
            scene.add( directionalLight );*/

            var hemisphereLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, .70);
            scene.add( hemisphereLight );

            // model

            var onProgress = function ( xhr ) {
                if ( xhr.lengthComputable ) {
                    var percentComplete = xhr.loaded / xhr.total * 100;
                    console.log( Math.round(percentComplete, 2) + '% downloaded' );
                }
            };

            var onError = function ( xhr ) {
            };


            THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader() );

        THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader() );

            var loader = new THREE.OBJMTLLoader();
            loader.load( 'obj/test/test_model.obj', 'obj/test/test_model.mtl', function ( object ) {

                object.scale = new THREE.Vector3( 25, 25, 25 );

                //object.position.y = - 80;
                scene.add( object );

            }, onProgress, onError );

            //

            renderer = new THREE.WebGLRenderer({ alpha: true });
            renderer.setSize( window.innerWidth, window.innerHeight );
            container.appendChild( renderer.domElement );

            document.addEventListener( 'mousemove', onDocumentMouseMove, false );

            //

            window.addEventListener( 'resize', onWindowResize, false );

        }

        function onWindowResize() {

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

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

            renderer.setSize( window.innerWidth, window.innerHeight );

            controls.handleResize();

        }

        function onDocumentMouseMove( event ) {

//              mouseX = ( event.clientX - windowHalfX ) / 2;
//              mouseY = ( event.clientY - windowHalfY ) / 2;

        }


        //

        function animate() {

            requestAnimationFrame( animate );
            controls.update();
            render();

        }

        function render() {

            //camera.position.x += ( mouseX - camera.position.x ) * .05;
            //camera.position.y += ( - mouseY - camera.position.y ) * .05;
            //camera.lookAt( scene.position );

            renderer.render( scene, camera );

        }

Answer №1

When working with the onDocumentMouseMove function or a click event, it is essential to calculate a ray-picking intersection using and manage the response from there.

Several examples demonstrating this can be found in the Three.js documentation (such as ) and on StackOverflow.

A simple solution could look like the following:

// Note that if the renderer is not fullscreen, other properties may need to be used
var mouseX = ( event.clientX / window.innerWidth ) * 2 - 1;
var mouseY = -( event.clientY / window.innerHeight ) * 2 + 1;

var vector = new THREE.Vector3( mouseX, mouseY, camera.near );
vector.unproject( camera ); // Convert screen coordinate to world coordinate on near plane

var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );

// Check for intersections with objects in the scene
var intersects = raycaster.intersectObjects( scene, true ); // true for recursion

// Toggle rotation boolean for clicked meshes
if ( intersects.length > 0 ) {

    var clickedObject = intersects[ 0 ].object;

    // Handle properties of clickedObject to react accordingly, e.g., show overlay or jump to another page
}

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

Cannot get the before-leave transition JavaScript hook to function properly in Vue.js

I am facing an issue with my variable, transitionName, in the beforeLeaveHook function. Despite attempting to change it to 'left', the value remains stuck at 'right'. Any assistance on resolving this matter would be greatly appreciated. ...

The JavaScript slideshow fails to display an image during one rotation

The slideshow displays a sequence of images from pic1.jpg to pic8.jpg, followed by a 4-second pause with no image, and then repeats starting again at pic1.jpg. I am looking to have it loop back to pic1.jpg immediately after displaying pic8.jpg. Below is t ...

Transfer of part of a JSON object

My current setup involves an API in PHP that sends JSON data to a Javascript webpage for processing. However, when dealing with large datasets, it can strain both the user's internet connection and computer capabilities. To address this issue, I want ...

The error message I'm receiving is saying that the map function is not recognized for the posts variable (posts.map

I encountered a puzzling error, even though everything seems fine: posts.map is not a function import React from 'react' import { useSelector } from 'react-redux' export const PostsList = () => { const posts = useSelector(state = ...

Ways to showcase an alert or popup when clicking?

I am utilizing a date picker component from this site and have enabled the 'disablePast' prop to gray out past dates preventing selection. Is there a way to trigger an alert or popup when attempting to click on disabled days (past dates)? Any sug ...

There seems to be nothing in the request.body that was sent

I've encountered an issue with my code - whenever I use postman or cURL to send a post request, the body is empty. const express= require('express'); const app = express(); app.use(express.json()) app.post('/',(req,res)=>{ ...

Javascript and iframes may encounter compatibility issues with browsers other than Internet Explorer

My HTML file includes an iframe and JavaScript that function correctly in IE Browser, but they do not work in other browsers such as Safari and Firefox. When using Safari, only the iframe box is displayed without showing the content inside it. I am curio ...

Using http-proxy to forward request to a different port

In my code, I am creating a proxy that routes all application calls from port 3000 to port 3002 seamlessly. var http = require('http'), httpProxy = require('http-proxy'); var proxy = httpProxy.createProxyServer(); http.create ...

Troubleshooting the "Failed to mount component" error in Vue: fixing template or render function definition issues

Struggling with writing a Vue component, encountering the issue: Failed to mount component: template or render function not defined. Tried various fixes like adding default when importing the component, but none of them seem to work. My component code is i ...

Encountering issue: Unrecognized parameter "id" in the "user" field of type "Query" [GraphQL, Relay, React]

We are currently setting up a query in relay. Our user database is structured like this: function User(id, name, description) { this.id = id.toString() this.name = name this.description = description } var users = [new User(1, 'abc', &a ...

Displaying the HTML code for a dynamically generated table

Can the generated HTML code be retrieved when dynamically creating a table using v-for loops in Vue? <table> <tr> <th colspan="99">row 1</th> </tr> <tr> <th rowspan="2">row 2< ...

Having trouble retrieving user data that is being passed as a context value using React's useContext

Currently, I am integrating Google login into my React application and facing an issue with passing the response data from Google login (i.e. user data) to other React components using the useContext hook. Unfortunately, I am unable to retrieve the user da ...

Utilize jQuery to append YQL output in JSON format to specific IDs in your code

I have a YQL output JSON string at this URL: Check out the YQL JSON here I encountered some other I am exploring why I am facing difficulties in extracting certain items from the returned JSON. For instance, when using jQuery to access the H1 tag within ...

Confusion surrounding asynchronous functions in Node.js

When handling routes or endpoints with multiple operations, I often encounter scenarios where I need to perform additional actions. For instance, when deleting an item, it's necessary to also remove the related file from S3 along with deleting the col ...

Using Python to extract the audio URL (specifically in mp3 format) from a web player

I have been attempting to extract the URL link from a webpage in order to download the audio as an mp3 file, but so far I have not been successful. Here is the code snippet of the webpage: webpage code Specifically, I am trying to retrieve the value of t ...

Workbox background sync - Retrieving replayed API responses

Currently, I am utilizing the Workbox GenerateSW plugin and implementing the backgroundSync option within runtimeCaching. You can find more information in the documentation here. This powerful plugin enables me to monitor APIs and successfully retry faile ...

mention the element to display on the pagination

I find the logic here quite puzzling. This particular code block seems to be related to pagination, as it involves a function that is triggered upon clicking. componentDidUpdate() { const { location } = this.context; const { query } = this; if ...

What is the best way to switch image position using javascript?

I'm experimenting with creating a function that toggles the image source when clicked - changing it back and forth. <img src="http://images.clipartpanda.com/laughing-smiley-face-clip-art-smiley-face-clip-art10.jpeg" longdesc="http://sm ...

Sharing styles between ReactJS and Material-UI - best practices

I am currently facing an issue where I need to share styles across my entire web application. Here is the Problem: I have been using makeStyles in a repetitive manner as shown below: In component_A.js const useStyles = makeStyles({ specific_style: { ...

Searching for an element using Python's Selenium and JavaScript

on this page I am trying to click on the "Choose file" button but I keep getting the error message: javascript error: argument is not defined var1 = sys.argv[1] path = os.path.abspath(var1) driver.get("https://www.virustotal.com/gui/home/upload& ...