Enhancing arrow cone spin with ThreeJs

My arrow function is supposed to connect pick and place points using QuadraticBezierCurve3 and ConeGeometry, but the rotation of the cone doesn't align perfectly with the curve as shown in the snippet below!

I'm seeking advice on how I can enhance the visualization (cone rotation) of my arrow function. Any suggestions are greatly appreciated.

var camera, scene, renderer;

init();
animate();

 /**
 draw arrow
*/
function drawArrow(pick_pos, place_pos, scene) {
    /**
    * Curve
    */
    const start = new THREE.Vector3();
    start.add(pick_pos)
    
    const finish = new THREE.Vector3();
    finish.add(place_pos)

    let mid = new THREE.Vector3();
    mid.add(start);
    let dist = finish.x + mid.x;
    mid.x = dist/2;
    mid.y += 3;

const b_curve = new THREE.QuadraticBezierCurve3(
    start,
    mid,
    finish
);
const points = b_curve.getPoints( 100 );
const line_geometry = new THREE.BufferGeometry().setFromPoints( points );
const material = new THREE.LineBasicMaterial( { color: 0x0ffffb, linewidth:5 } );
const curve = new THREE.Line( line_geometry, material );
/**
 * Cone
 */
const cone_geometry = new THREE.ConeGeometry( 0.2, 1, 8 );
const cone_material = new THREE.MeshBasicMaterial({ color: 0xff00fb });

const cone = new THREE.Mesh( cone_geometry, cone_material );
cone.position.set(points[98].x, points[98].y, points[98].z);
cone.rotateX(Math.PI * points[100].x); 
cone.rotateZ(Math.PI * points[100].z);

/**
 * Arrow
 */

const arrow = new THREE.Group();
arrow.add(curve);
arrow.add(cone);
arrow.name = 'arrow';
scene.add(arrow);
}

/**
 Create the scene, camera, renderer
*/
function init() {
  scene = new THREE.Scene();
  scene.background = new THREE.Color(0x21252d);
  renderer = new THREE.WebGLRenderer({antialias: true});
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 1000);
  camera.position.x = 0;
  camera.position.y = 8;
  camera.position.z = 10;
  scene.add(camera);
  
  controls = new THREE.OrbitControls(camera, renderer.domElement);
  
  const pick = new THREE.Vector3(0, 0, 0);
  const place = new THREE.Vector3(5, 0, 5);
  drawArrow(pick, place, scene);
  window.addEventListener('resize', onWindowResize);

}

function onWindowResize() {
 camera.aspect = window.innerWidth / window.innerHeight;
 camera.updateProjectionMatrix();
 renderer.setSize(window.innerWidth, window.innerHeight);
}

function animate() {
  requestAnimationFrame(animate);
  render();
}

function render() {
  renderer.render(scene, camera);
}
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="36425e4453537606180704041806">[email protected]</a>/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d4a0bca6b1b194e4fae5e6e6fae4">[email protected]</a>/examples/js/controls/OrbitControls.min.js"></script>

Answer №1

Resolution

  1. The cone's default orientation points towards the sky (z), causing rotation to be invalid.
  2. It appears that the arc's direction is reversed.
  3. .lookAt() is a convenient shortcut for obtaining rotation from two distinct 3D vectors.
// SOLUTION
const VEnd = points[15].clone();
// Adjust cone's default position to face downwards.
cone.geometry.rotateX( -Math.PI / 2 );
cone.lookAt(VEnd);

Test out the code snippet below:

var camera, scene, renderer;

init();
animate();

 /**
 draw arrow
*/
function drawArrow(pick_pos, place_pos, scene) {
    /**
    * Curve
    */
    const start = new THREE.Vector3();
    start.add(pick_pos)
    
    const finish = new THREE.Vector3();
    finish.add(place_pos)

    let mid = new THREE.Vector3();
    mid.add(start);
    let dist = finish.x + mid.x;
    mid.x = dist/2;
    mid.y += 3;

const b_curve = new THREE.QuadraticBezierCurve3(
    start,
    mid,
    finish
);
const points = b_curve.getPoints( 100 );
const line_geometry = new THREE.BufferGeometry().setFromPoints( points );
const material = new THREE.LineBasicMaterial( { color: 0x0ffffb, linewidth:5 } );
const curve = new THREE.Line( line_geometry, material );
/**
 * Cone
 */
const cone_geometry = new THREE.ConeGeometry( 0.2, 1, 8 );
const cone_material = new THREE.MeshBasicMaterial({ color: 0xff00fb });

const cone = new THREE.Mesh( cone_geometry, cone_material );
// ANSWER
const VEnd = points[15].clone();
// fix cone's default position which points skyward.
cone.geometry.rotateX( -Math.PI / 2 );
cone.lookAt(VEnd);

/**
 * Arrow
 */

const arrow = new THREE.Group();
arrow.add(curve);
arrow.add(cone);
arrow.name = 'arrow';
scene.add(arrow);
}

/**
 Create the scene, camera, renderer
*/
function init() {
  scene = new THREE.Scene();
  scene.background = new THREE.Color(0x21252d);
  renderer = new THREE.WebGLRenderer({antialias: true});
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 1000);
  camera.position.x = 0;
  camera.position.y = 8;
  camera.position.z = 10;
  scene.add(camera);
  
  controls = new THREE.OrbitControls(camera, renderer.domElement);
  
  const pick = new THREE.Vector3(0, 0, 0);
  const place = new THREE.Vector3(5, 0, 5);
  drawArrow(pick, place, scene);
  window.addEventListener('resize', onWindowResize);

}

function onWindowResize() {
 camera.aspect = window.innerWidth / window.innerHeight;
 camera.updateProjectionMatrix();
 renderer.setSize(window.innerWidth, window.innerHeight);
}

function animate() {
  requestAnimationFrame(animate);
  render();
}

function render() {
  renderer.render(scene, camera);
}
<script src="https://cdn.jsdelivr.net/npm/three@0.133.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.133.0/examples/js/controls/OrbitControls.min.js"></script>

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 it possible for me to choose to establish a new scope within a directive?

Encountered an issue while reusing a directive where some tags had a second directive with a new scope created using new or {}, while others did not have one. Attempting to create a new scope when one already existed resulted in an error being thrown by An ...

How to use AngularJS to collapse various panels with unique content

Hey everyone, I'm working on developing a collapsible panel using Angular. The panel should consist of a header and body to display the content. The desired behavior is that when a button is clicked, the content collapses down, and clicking the same b ...

Switch between display modes by clicking using collections

I am trying to figure out how to create a function that will only show content for the specific element in which my button is located. Currently, when I click the button it shows content for all elements with the 'one' class, but I want it to dis ...

Is it possible to utilize Angular.js as a full substitute for a traditional JavaScript template engine?

While angular excels in two-way data binding and single-page applications, could it also serve as a viable replacement for a JavaScript template engine? Let's dive into the potential pros and cons of this approach. ...

Tips for repairing a button using a JavaScript function in an HTML document

I am currently working on extracting titles from body text. To achieve this, I have created a button and linked my function to it. The issue I am facing is that when I click on the button, it disappears from its original position. I intend to keep it in pl ...

Numerous asynchronous requests running simultaneously

After successfully querying a database using js/ajax for a single drop-down, I am now looking to enhance my solution by adding multiple identical drop-downs. The goal is to retrieve the same information when an option is selected without allowing duplicate ...

D3: Ensuring Map is Scaled Correctly and Oriented Correctly

I am attempting to integrate a map into a website using D3 and topoJSON that resembles the following: https://i.sstatic.net/1brVx.png However, when I create the map with D3/topoJSON, it shows up small and inverted. https://i.sstatic.net/LgQBd.png Even ...

A method to eliminate click events for an element

I have a unique element called #foo with a click event attached to it. This element is nested within another element called #bar, which also has a separate click event attached to it. <div id="bar"> <div id="foo" /> </div> Currently, ...

Await keyword cannot be used due to undefined object reference

Currently in the process of implementing authentication into my node API. Using PassportJS, although I am fairly new to this so please bear with me. The goal is to add a local strategy and verify the user's password during login: // Local Strategy ...

Mastering the art of square bracket destructuring in React through deep comprehension of the concept

import React, { useEffect, useState } from 'react' import { Text } from 'react-native' export default function Counter() { const [count, setCount] = useState(0) useEffect(() => { const id = setInterval(() => setCount((co ...

Trapping an iframe refresh event using jQuery

I am trying to dynamically load an iframe using jQuery. Here is my code: jQuery('<iframe id="myFrame" src="iframesrc.php"></iframe>').load(function(){ // do something when loaded }).prependTo("#myDiv"); Now, I need to capture th ...

Attempting to prevent the use of the <p> tag solely before the text

My toggle function is not working correctly in my FaQ section. When a user clicks on a topic, the bottom section should appear, but the <p> tag is being displayed across the entire line instead of just one word.. Here is an image to help illustrate ...

Make a decision within Express.js to select the appropriate middleware modules based on specific conditions

In my express.js endpoint, I am dynamically selecting between middleware callbacks to execute: const middleware1 = require('./m1') const middleware2 = require('./m2') app.get('/call', async (req, res) => { if (req.code == ...

The function `createUser` is currently not functioning properly on Firebase/Auth with Next.js

I am currently working on implementing email and password authentication using Firebase Auth with Next.js. This time, I want to utilize a dedicated UID for authentication purposes. In order to achieve this, I believe it would be better to use the createU ...

I am having trouble getting Form.Select to work in my basic react-bootstrap application, despite following the guidelines provided in the react-bootstrap documentation. Can

I am new to utilizing "react-bootstrap with hooks" and currently in the process of creating a basic form. I have been following the guidance provided by react-bootstrap documentation, but I encountered an issue specifically with select/option form elements ...

Having issues sorting the ranking table numerically in a Javascript/jQuery/JSON/localStorage game

I have successfully created a leaderboard for my game, but I am struggling to automatically sort the scores from high to low. I believe that placing the objects into an array and then sorting them may be the solution, however, I am unsure of how to do th ...

Navigating to a different state key within a state object in React - a simple guide

Trying to dive into React, I encountered an issue. My goal is to create my own example from a tutorial. import React, { Component } from 'react'; class MyComponent extends Component { state = { persons: [], firstPersons: 5, variab ...

How to extract a JavaScript object from an array using a specific field

When dealing with an array of objects, my goal is to choose the object that has the highest value in one of its fields. I understand how to select the value itself: Math.max.apply(Math, list.map(function (o) { return o.DisplayAQI; })) ... but I am unsur ...

Tips for retrieving the value of a dynamic and multi-update id using jQuery and Ajax

I'm in need of assistance with a few different tasks: Firstly, I am looking to understand how to retrieve the id of an input element when it is dynamically generated from a database. In the HTML, it displays something like field 1 -> id = "pa ...

JavaScript client side event that references the sender object ID in an aspx file

Can someone provide assistance with an issue in the code block below? function(s, e) { form1.hfRaiseEvent.value = s.ID; } This particular function is triggered when the Client Side Click Event occurs. From my understanding, s refers to the Sender Obj ...