Transforming a Three.js Torus Geometry to Match Custom Parameters

I’m currently learning to draw basic shapes using three.js. I now need to draw a torus at a specified position, and I always know the following parameters about the torus:

const targetData = {
  a: [1.78, 6.29, 0], 
  b: [-1.78, 6.29, 0],
  tangentA: [0, 0, 1],
  tangentB: [0, 0, 1],
  c: [0, 6.29, -1.78],
  o: [0, 6.29, 0],
  tubeRadius: 0.1,
  torusRadius: 1.78, 
  arc: Math.PI,
}

Where a, b, c are three points on the torus, tangentA is the tangent at endpoint a, tangentB is the tangent at endpoint b, o is the center of the torus, tubeRadius is the radius of the tube, torusRadius is the radius of the torus, and arc is the radian of the torus arc. (This is an example set of parameters)

I provided a CodePen example: https://codepen.io/laddishx/pen/QWzXerL

I know I should use three.js docs to implement it:

  const geometry = new THREE.TorusGeometry(1.78, 0.1, 120, 64, Math.PI);
// radius - Radius of the torus, from the center of the torus to the center of the tube. Default is 1.
// tube — Radius of the tube. Default is 0.4. 
// radialSegments — Default is 12
// tubularSegments — Default is 48.
// arc — Central angle. Default is Math.PI * 2.

However, the torus drawn with THREE.TorusGeometry is always centered at [0,0,0]. I summarized its parameters as:

Copy code

const originData = {
  a: [1.78, 0, 0],
  b: [-1.78, 0, 0],
  tangentA: [0, -1, 0],
  tangentB: [0, -1, 0],
  c: [0, 1.78, 0],
  o: [0, 0, 0],
  tubeRadius: 0.1,
  torusRadius: 1.78,
  arc: Math.PI,
}


I want to know how to do the transformation to move it to the corresponding position. I tried setting the position, then calculating the angle between the target plane and the default initial plane (xy plane), then rotating around the plane to achieve the effect. This works for the current set of parameters, but when my target parameters change, there are many problems and I can’t achieve the desired effect. Is there a general method to do the transformation based on the known parameters?

No. There isn’t really a general method like that. You can either change the input parameters to the generator… or you can change .position/scale/rotation of the resulting mesh… Or you can physically transform the vertices of the geometry using the mesh.geometry.translate** or .rotate methods.

You can get the bounding box of the mesh using

new Box3().setFromObject( yourMesh ) and use the resulting bounding box to figure out how you need to re-scale it to fit some desired size… but it will scale the whole thing uniformly… shapes/primitives don’t really “exist” after creation in threejs… once they are created they are just “meshes” which are a collection of triangles.

2 Likes

Thank you for your patient explanation. Regarding the first point, I have a question - can I specify parameters to make torusGeometry draw at a specific position? I guess this would require modifying the torusGeometry source code.

For the second point, I wonder if I can achieve my goal through matrix transforms. Do my parameters provide enough information for the matrix transform requirements? If so, how should I do it?

The problem I currently have is that I don’t know how to do the coordinate transforms - I’m not clear on the correct steps for the transforms.

As @manthrax mentioned, use geometry.translate(x, y, z);: Edit fiddle - JSFiddle - Code Playground
Or move a mesh at the desired point, using its position property :thinking:

2 Likes

Thank you for the patient explanation and example. I know I can draw directly at a specified position to skip the translation step. However, this involves:

  1. Rotating the geometry from the xy plane to the target plane.
  2. After rotating to the target plane, further rotating around the center point on that plane to align the endpoints.

This process requires calculating rotation angles around the x, y, z axes, which is straightforward for a simple case like this where the target plane is parallel to xz. But for some arbitrary angled target planes in 3D space (e.g. target plane at an arbitrary angle in 3D), calculating those angles is difficult for me.

However, ChatGPT told me this transform could be done using THREE.js’s Matrix4 class, which provides methods for translations, rotations, scaling etc. Since I’m new to matrix transforms, I’m unclear on the specifics like what parameters to assemble and steps to take in order to achieve the matrix transform.- for example, given known start and end positions, what parameters need to be assembled to achieve the matrix transform? What are the steps? Do my current known parameters satisfy the requirements?

I tried watching some YouTube videos (e.g. https://www.youtube.com/watch?v=RqZH-7hlI48&t=12s, https://www.youtube.com/watch?v=4csuTO7UTMo) but am still confused on constructing such a matrix transform.

For most situations where you consider fiddling with hand constructing matrices, there is often a more readable approach using combinations of position,scale,rotation on the object (or geometry), possibly coupled with the .lookAt method (which is inherited by all classes derived from Object3D which includes Meshes).
Can you describe on a higher level what you are trying to achieve? Are you building some kind of 3d modelling software?

If we know what you are trying to build, we can better inform your approach.

That said… here are the docs for Matrix4:
https://threejs.org/docs/?q=Matrix4#api/en/math/Matrix4
It has lots of methods that you can use to construct it… or you can construct it by hand if that’s your jam.

It’s a 16 element array… the first 12 elements hold the 3 scaled axis vectors describing the orthonormal coordinate frame, with a 0 as the 4th element, and the last 4 floats in the array are the position, followed by a 1. The 0’s and 1’s are what determines if the row vectors will be treated as vectors, or points during transformation.

xx,xy,xz,0,
yx,yy,yz,0,
zx,zy,zz,0,
px,py,pz,1

but end of the day, you’ll probably be recreating portions of what the Object3D abstraction does for you…
namely… taking a position,scale,and quaternion and .compose() ing it into the mesh.matrix.

https://threejs.org/docs/?q=Matrix4#api/en/math/Matrix4.compose

https://threejs.org/docs/?q=Matrix4#api/en/math/Matrix4.decompose

ChatGPT is often quite literal in its solutions to things… especially with regards to OpenGL since a lot of GL stuff is done very low level without a scene graph abstraction like threejs provides…and may not be considering more intuitive/readable approaches to the problem.

You might try asking it how to achieve what you want, but without hand assembling matrices, but instead by using the object3d or geometry transformation methods.

1 Like