Rotating a non-centered triangle geometry in ThreeJS

I've been struggling to understand why my triangle isn't rotating around the center as I expected. My goal is to have two triangles side by side, with one rotated 60 degrees. However, when I rotate them, all corners should remain the same size.

Below is a snippet of my code. Why is the blue triangle moving to the left? It seems that the top right corner of the orange triangle is larger than the other two...

<!DOCTYPE html>
      <html lang="en">
      <head>
      <title>three.js webgl - geometries</title>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
      <style>
      body {
      color: #eee;
      font-family:Monospace;
      font-size:13px;
      text-align:center;
      background-color: #ffffff;
      margin: 0px;
      padding: 0px;
      overflow: hidden;
      }
      #info {
      position: absolute;
      top: 0px; width: 100%;
      padding: 5px;
      }
      a {
      color: #0080ff;
      }
      </style>
      </head>
      <body>

      <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/103/three.js"></script>


      <script>
      var SCREEN_WIDTH = window.innerWidth;
      var SCREEN_HEIGHT = window.innerHeight;
      var aspect = SCREEN_WIDTH / SCREEN_HEIGHT;
      var camera, scene, renderer, stats;
      var frustumSize = 100000;
      function init() {
      camera = new THREE.OrthographicCamera( 0.5 * frustumSize * aspect / - 2, 0.5 * frustumSize * aspect / 2, frustumSize / 2, frustumSize / - 2, -1000, 10000 );
      camera.position.y = 400;
      scene = new THREE.Scene();
      scene.background = new THREE.Color( 0xf0f0f0 );
      camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 1000 );
      camera.position.set( 0, 0, 2 );
      camera.lookAt(0, 0, 0)
      scene.add( camera );
      var light = new THREE.PointLight( 0xffffff, 0.8 );
      camera.add( light );

      drawSquare()

      var margin = 0.2;
      var t = new triangle(0.5);
      t.draw();
      t.createSides(margin);

      //
      renderer = new THREE.WebGLRenderer( { antialias: true } );
      renderer.setPixelRatio( window.devicePixelRatio );
      renderer.setSize( window.innerWidth, window.innerHeight );
      document.body.appendChild( renderer.domElement );

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

      class triangle {

      constructor(length){
      this.length = length;
      }

      draw(color='orange'){
      var h = this.length * (Math.sqrt(3)/2);

      var shape = new THREE.Shape();
      shape.moveTo( 0,-h/2 );
      shape.lineTo( -this.length / 2, h / 2 );
      shape.lineTo( this.length / 2, h / 2 );

      var extrudeSettings = {
      steps: 2,
      depth: 0.4,
      bevelEnabled: false
      };

      var geometry = new THREE.ExtrudeBufferGeometry( shape, extrudeSettings );
      geometry.center();

      var line2 = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( {color: color} ) );
      line2.position.set(0, 0, 0);
      scene.add(line2);
      this.mesh = line2;
      }

      createSides(margin){
      for(var i = 0;i<3;i++){
      var t = new triangle(this.length);
      t.draw('blue');
      //t.mesh.position.x += this.length;
      t.mesh.geometry.rotateZ(THREE.Math.degToRad(60));
      }
      }
      }

      function drawSquare(){
      var size = 1;
      var geometry = new THREE.Geometry();
      geometry.vertices.push(
      new THREE.Vector3(0, 0, 0),
      new THREE.Vector3(size, 0, 0),
      new THREE.Vector3(size, size, 0),
      new THREE.Vector3(0, size, 0),
      new THREE.Vector3(0, 0, 0));
      var line2 = new THREE.Line(geometry, new THREE.LineBasicMaterial({color: "red"}));
      line2.position.set(-size/2, -size/2, 0);
      scene.add(line2);
      }
      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 );
      }

      init();
      animate();
      </script>

      </body>
      </html>

Answer №1

The focal point or the heart of the Enclosed circle for an Equilateral triangle does not align with the center of the bounding box:

In an Equilateral triangle where (0, 0) serves as the focal point of the enclosed circle:

var l = this.length;
var h = l * Math.sqrt(3) / 2; // 0.866
shape.moveTo(  0,      h * 2/3 );
shape.lineTo( -l / 2, -h * 1/3 );
shape.lineTo(  l / 2, -h * 1/3 );

Additionally, please remember that the .center() function within THREE.BufferGeometry should be disregarded:

Center the geometry based on the bounding box.

To illustrate, discard the following line:

var geometry = new THREE.ExtrudeBufferGeometry( shape, extrudeSettings );

geometry.center();

Although the triangle may not perfectly align with the box, it rotates around the focal point of the enclosed circle. To compensate for this, you can adjust the triangle's position along the y-axis by -h/6:

var line2 = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( {color: color} ) );
line2.position.set(0, -h / 6, 0);

Refer to the example below.

var SCREEN_WIDTH = window.innerWidth;
var SCREEN_HEIGHT = window.innerHeight;
var aspect = SCREEN_WIDTH / SCREEN_HEIGHT;
var camera, scene, renderer, stats;
var frustumSize = 100000;
var triangles = [];
var rot = 0
// Additional code for initialization and rendering is included here for illustrative purposes
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.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

Shifting elements between positions using jquery or angular

Here's the issue I'm facing... I have an array of movie divs (image and description) displayed using ng-repeat. Now, when I select one of them, I want to implement the following (almost like a game of positioning): 1) I want to smoothly remove t ...

Switch up the information upon button click using reactjs and Material UI

The current website is in the development phase and is being built using Reactjs and Material UI. To display different components based on the address change, switch statements have been utilized. Buttons are expected to update the URL using 'Link to ...

Vue 3: `defineProps` allows components to locally reference declared variables

Why am I receiving a warning error message: defineProps is referencing locally declared variables. eslint(vue/valid-define-props) whenever I utilize a custom validator in props within an SFC <script setup> mode: <script setup> import { valid ...

When using the * selector in jQuery on Chrome, it targets and selects scrollbars

Here's the code I'm currently using: $("*").bind("mousedown.sg", { 'self':this }, this.sgMousedown); This code binds an event listener to all elements on the page, and it functions properly in most browsers except for Chrome. In Chrom ...

What steps do I need to follow to create a 3D shooting game using HTML5 Canvas?

I'm eager to create a 3D shooter game with HTML5 Canvas, focusing solely on shooting mechanics without any movement. Can anyone provide guidance on how to accomplish this? I've looked for tutorials online, but haven't come across any that m ...

beforeSend method in jquery ajax synchronously calling

One of my functions is called: function callAjax(url, data) { $.ajax( { url: url, // same domain data: data, cache: false, async: false, // use sync results beforeSend: function() { // show loading indicator }, ...

Server for Electron application using Node.js

Working on a project that involves Electron + React, I need to develop a feature that allows users to save files on the server similar to Google Drive. Currently, I am setting up the server side using express but I'm not sure how to send files to the ...

The filter on the mobile version is not displaying correctly

When I select a category in the input filter, only items with the same category are displayed when clicked. However, when I click on "Others" on the desktop version, only rows with that category are shown, but on mobile after resizing and filtering, nothin ...

Building responsive grids in React using Material-UI components

https://i.sstatic.net/d2CIo.png On the left side, there is a map with controls, and on the right side, there are fields displaying the last update, a table, and an input field. I am looking to create a responsive design where when it reaches a certain si ...

Preserving the Selected Date on the Calendar Even After the PHP Variable is Passed

I am currently using the calendar code below with a slight modification that I implemented. However, I have encountered an issue where when I select a date, the calendar successfully highlights the selected date. But once I pass this selected date along ...

Sorting through a list post a retrieval action

Could you guys please help me understand why my code is not functioning properly? I am receiving an array from my backend rails API, which is providing the data correctly. I have created an empty array where I filter the records based on their ID. The fi ...

Is there a way to verify the existence of an EJS variable?

When working with my Node.js application, I encountered an issue with EJS layout where if the required data is not available in the EJS file, it throws an error. I am looking for a way to add a condition to check for the availability of the EJS variable in ...

Form a hierarchical data structure using a combination of three arrays

Here are three sets of data: let firstData = [ {key: value1}, {key: value2}, {key:value3} ] let secondData = [ {key: value1}, {key: value2}, {key:value3}, {key: value4} ] //same structure, different values let thirdData = [ [1,1,1,1], [1,1,1,1], [1,1,1,1] ...

Pass information to a PHP file using JavaScript when the form is submitted

Essentially, I am looking to extract values from various inputs and spans using JavaScript when the submit input is clicked. These values will then be sent to PHP using $post in order to ultimately send them via email. Previously, I tested replacing all of ...

Exploring the contents of this JSON array

I'm trying to fetch data from this link: <script type="text/javascript"> $.getJSON('http://api01.notaion.com/?item&id=120001462', function(data) { }); </script> I am uncertain whether I need to use a callback=?, a ...

Break down the text of a paragraph into separate words, placing each word within its own span element, and then add animations

I am facing an issue with my paragraph element that has the display property set to hidden. I have split each word of the paragraph and placed them inside individual span elements. My goal is to create an effect where each word comes from different locatio ...

Incorporating a JavaScript workflow into Django

Currently, I am following a tutorial on integrating a modern JavaScript pipeline into my Django application. The objective is to have the JavaScript code write "Hello webpack" onto the page, but unfortunately, it is not displaying as expected. Since I alr ...

Searching through a populated field in MongoDB

If I want to search for a specific book based on the reviews field, how can I do that? The reviews field contains an array of objects, and one of the keys in each object is the description. If my search query matches the description of any review, then I w ...

Running a setTimeout function within the context of a jQuery each

My goal is to animate characters one by one, but for some reason the following code isn't functioning as expected: $('.overlay-listing').hover(function(){ var idx = 1; $('.strip-hov span', this).each(function(){ if ...

Customizing the appearance of React Navigation StackNavigator through background color changes and styling

Recently delving into React Native, I've managed to create a basic app with three different scenes. Initially, I used Navigator for navigation purposes, but found it to be sluggish and decided to give React Navigation (found at https://reactnavigation ...