Utilize Three.js to trace user mouse clicks and project them onto the Fabric.js canvas being employed as the texture

I am currently working on creating a 3D product configurator.

Initially, I import the .gltf model and render it using Three.js.

Next, I generate an SVG onto a Fabric.js canvas and utilize that canvas to create a THREE.CanvasTexture, which is then used to update the model.

The issue at hand
I have enabled users to upload text and images. These images are incorporated into the Fabric canvas as new elements that can be freely moved and resized on the canvas, while the main SVG remains fixed in the background.

Canvas object screenshot
https://i.sstatic.net/0HKKh.png

Objective
My aim is to enable users to directly interact with the uploaded Fabric.js layers, such as dragging and resizing, on the visible 3D Three.js model itself, rather than on the canvas, which is currently hidden.

Model image illustration
https://i.sstatic.net/Dt9Lg.png

Being new to the 3D realm, I am struggling to find examples or guidance on where to begin. I understand that Raycasting will be necessary, but I am unsure of how to convert the points to the correct 2D canvas coordinates and simulate click and drag actions.

Answer №1

If you're looking for some examples, you can check out the following links:

Example 1 -

Example 2 - https://codepen.io/ricardcreagia/pen/EdEGod

        /**
         * Experimenting with Fabricjs and Threejs integration
         */

        var canvas = new fabric.Canvas( "canvas" );
        canvas.backgroundColor = "#FFBE9F";

        var rectangle = new fabric.Rect( {
            top: 100,
            left: 100,
            fill: '#FF6E27',
            width: 100,
            height: 100,
            transparentCorners: false,
            centeredScaling: true,
            borderColor: 'black',
            cornerColor: 'black',
            corcerStrokeColor: 'black'
        } );

        canvas.add( rectangle );


        /**
         * Setting up Threejs environment
         */

        var containerHeight = "512";
        var containerWidth = "512";
        var camera, renderer, container, scene, texture, material, geometry,cube;

        var raycaster = new THREE.Raycaster();
        var mouse = new THREE.Vector2();
        var onClickPosition = new THREE.Vector2();

        init();
        animate();


        /**
         * Initializing the setup
         */

        function init() {

            /**
             * Setting up the Camera
             */

            camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 0.01, 100 );
            camera.position.set( 0, 0, 3.5 );


            /**
             * Setting up the Renderer
             */

            container = document.getElementById( "renderer" );
            renderer = new THREE.WebGLRenderer( { antialias: true } );
            renderer.setPixelRatio( window.devicePixelRatio );
            renderer.setSize( containerWidth, containerHeight );
            camera.aspect = container.clientWidth / container.clientHeight;
            camera.updateProjectionMatrix();
            container.appendChild( renderer.domElement );


            /**
             * Creating the Scene
             */

            scene = new THREE.Scene();
            scene.background = new THREE.Color( 0x000000 );


            /**
             * Creating Texture and Material
             */

            texture = new THREE.Texture( document.getElementById( "canvas" ) );
            texture.anisotropy = renderer.capabilities.getMaxAnisotropy();

            material = new THREE.MeshBasicMaterial( { map: texture } );


            /**
             * Setting up the Model
             */

             geometry = new THREE.BoxGeometry( 1, 1, 1 );
             cube = new THREE.Mesh( geometry, material );
             scene.add( cube );
        }


        /**
         * Rendering the frame
         */

        function animate() {
            requestAnimationFrame( animate );

            cube.rotation.x += 0.004;
            cube.rotation.y += 0.001;
            texture.needsUpdate = true;

            renderer.render( scene, camera );
        }


        /**
         * Event Listeners
         */

        container.addEventListener( "mousedown", onMouseClick, false );


        /**
         * Other Utility Functions
         */

        function onMouseClick( evt ) {
            evt.preventDefault();

            var array = getMousePosition( container, evt.clientX, evt.clientY );
            onClickPosition.fromArray( array );

            var intersects = getIntersects( onClickPosition, scene.children );

            if ( intersects.length > 0 && intersects[ 0 ].uv ) {
                var uv = intersects[ 0 ].uv;
                intersects[ 0 ].object.material.map.transformUv( uv );

                var circle = new fabric.Circle({
                    radius: 3,
                    left: getRealPosition( "x", uv.x ),
                    top: getRealPosition( "y", uv.y ),
                    fill: 'red'
                });
                canvas.add( circle );
            }
        }

        function getRealPosition( axis, value ) {
            let CORRECTION_VALUE = axis === "x"
                                    ? 4.5
                                    : 5.5;

            return Math.round( value * 512 ) - CORRECTION_VALUE;
        }

        var getMousePosition = function ( dom, x, y ) {
            var rect = dom.getBoundingClientRect();
            return [ ( x - rect.left ) / rect.width, ( y - rect.top ) / rect.height ];
        };

        var getIntersects = function ( point, objects ) {
            mouse.set( ( point.x * 2 ) - 1, - ( point.y * 2 ) + 1 );
            raycaster.setFromCamera( mouse, camera );
            return raycaster.intersectObjects( objects );
        };

Hopefully this code snippet can be beneficial to someone exploring these concepts!

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

Developing a unique 3D shape using THREE.JS

Is there a way to use THREE.JS in WebGLRenderer to create a cube with a top face that is rotated 45 degrees? I am looking to generate a cube shape where the top face is specifically rotated, can I do this by adjusting the vertices or is there another meth ...

Enter a keyword in the search bar to find what you're looking

I am working on a form where users can select their occupation from a list that is stored in a separate .js file. The list includes various occupations like 'AA Patrolman' and 'Abattoir Inspector'. var occupationSelect = "<select id ...

"Toggling the parent element through jQuery within a search function

I have a similar structure in my table: <input id="mySearch" placeholder="Search..." type="text"/> <table> <th>Main header</th> <tbody id="searchable"> <tr class="parent"><td>Parent</td></tr> ...

When the AJAX function is called again, the previous loading process is interrupted, without the use of jQuery

I have created a function that loads a URL into an element, but it seems to be encountering issues when called repeatedly in a loop to load multiple elements. The current load operation stops prematurely: function loadDataFromURL(url, elementId) { var ...

Updating the geometry of vertices after rotating or moving an object

I've been experimenting with using position and rotation values to transform a mesh, but now I'd like to modify the geometry vertices directly in x, y, and z coordinates while freeing or resetting the rotation and position values. I'm not qu ...

Implementing JavaScript SDK to modify a Parse object upon a button click: A Step-by-Step Guide

Incorporating Parse.com and JavaScript SDK is the focal point here. The goal of the function below is: a) To provide a list of users that the current user must respond to regarding a friend request. b) When the "cancel" option is clicked, the state of th ...

Is it feasible to implement hot swapping in Node.js?

Can Node.JS support or mimic hot swapping code functionality? If so, what is the process? Hot swapping, also known as hot plugging, involves replacing or adding components without system shutdown. Erlang and Lisp have native support for hot swapping. ...

When populating data, two ID fields (_id and id) are generated as duplicates

Upon retrieving information from my database, I have noticed the presence of an additional id field alongside the standard _id field. These two fields consistently contain identical values. However, it seems that the id field appears only during population ...

angular failure to assign a variable to $scope

When communicating with the Node server, I am able to receive a response message in the controller. However, there seems to be an issue with assigning it properly. .controller('someCtrl', function(exportExcel){ $scope.clickEvent = function() ...

Employ the symbol ""q" within a repetition sequence

When trying to retrieve data from a Mssql server, I encountered an issue with a function that contains a loop. The function returns some data to the callback, and now I need to figure out how to store this data from kriskowal's "q" into the resultset ...

Leveraging .position() in jQuery

Check out my script here that needs some adjustments in the positioning of the text. When you click on one of the choices, the text should smoothly slide down to that specific height. I am attempting to utilize .position() to determine a relative position, ...

Transforming PHP MySQL date into a Javascript timestamp for plotting time series data with FLOT

Currently, I am in the process of developing a Flot JavaScript Time Series Line Graph that analyzes the registration activity of users over time. The graph depicts the number of users registering accounts against the timestamp of when the account was creat ...

Reloading content using AJAX

Index.php ... <form id="calculator_form" name="form" action="" method="get" > <input name="one" type="text"> <input name="two" type="text"> <input type="submit"> </form> ... <!-- reload area --> <?php if(isset( ...

Having trouble interpreting PHP-generated JSON data in JavaScript

I have a PHP script that outputs a JSON string. <?php $arr = array( 'id' => '1', 'myarray' => array( array('a' => 'a1', 'b' => 'b1', 'c' => 'c1', & ...

Shared codes are compatible with both C and Javascript programming languages

Within the scope of this project, data will be retrieved from the server in either JSON or XML format. There are two separate client applications that will handle the data processing, with one being web-based and written in JavaScript, while the other is ...

Creating an interactive bootstrap modal: a step-by-step guide

For instance, I have 3 different tags with unique target-data for each one. <a class="btn btn-outline-primary btn-sm" href="#" data-toggle="modal" data-target="#firstdata"> DATA 1 </a> <a class=&q ...

The pagination in Laravel Vue is causing a validation error due to an invalid prop type check failing

Recently, I delved into working with Nuxt.js and decided to install the Laravel-Vue-Pagination plugin. However, I encountered an error message in my console system that reads: [Vue warn]: Invalid prop: type check failed for prop "data". Expected Object, ...

Automating the click of JavaScript buttons with Selenium

Test page Experimenting with the above Indeed link to test my selenium automation skills. I am attempting to automate the clicking of the 'apply' button using the Firefox webdriver. My code snippet is as follows: from selenium import webdriver ...

JavaScript function overriding allows a subclass to provide a specific implementation of

I have a JavaScript file with two methods: var DBProcessing = function() { console.log("ok") ... } var DBProcessing = function(str) { console.log(str); ... } When calling DBProcessing(), I am only getting an output of undefined. Is there a way to expli ...

Steps for creating a two-dimensional arc

I want to input some pre-determined acr values from another program and replicate them in three.js Currently, I'm using code I found on this site to draw the arc, although it might not be the most optimal solution. function DRAWarc(){ ...