Placing GLB next to another GLB accounting for its rotation

Hi all! I have an application with R3F that allows for placement and selection of GLB’s loaded in real time. I do have a button on my UI to place that GLB in the middle of the scene. I have implemented an extra functionality that is if I have one GLB in the scene as selected and then I click that UI button to place another GLB, this other GLB gets placed on the right side of the selected GLB, considering size and rotation of the original one.

So far, I’ve achieved the part where I place the GLB next to each other considering size, but I do not see the way to do it so it accounts for rotation. This is how I’m doing it.

//Getting the glb size
const boundingBox = new Box3().setFromObject(glb.scene)
const glbSize = boundingBox.getSize(new Vector3())
...

const position = new Vector3()
// This is my reference GLB I'm looking into to know where to place my new GLB
const {referenceMatrix ,glbSize} = getSelectedGLB(id)
// Get its position with decompose
referenceMatrix.decompose(position, new Quaternion(), new Vector3())
const newMatrix = new Matrix4()
// Get its rotation
      .extractRotation(referenceMatrix)
// And place the item right where the original was located but with a Z offset accounting for the reference GLB
      .setPosition(position.x, position.y, position.z + glbSize.x)
createNewMeshWithMatrix(newMatrix)

While this is giving me good results when the reference GLB is not rotated, when it is rotated it gives me the second set of furniture in the attached screenshot. I would like to have the GLB to be positioned touching the right side of the original one. I tried positioning the GLB first and then rotate, but it seems like my matrix turns out to be invalid if I do this and the GLB just gets placed on (0,0).
I really appreciate any help you can provide.
2023-06-12 09_22_04-For2Home

Object3D.localToWorld is what you seek, most likely :relieved:

A small example - lines 5-20 precisely.

1 Like

Hi @mjurczyk. Thanks a lot for the reply! I tried doing what the example is showing but my problem is that I’m managing matrices to be later applied to meshes in R3F. I do not get to touch any Object3D up until later. Is there anything similar to localToWorld but with matrices? I’ve been searching and it does not seem to be anything similar. Any help is greatly appreciated!

So I tried replicating the code by creating a placeholder mesh and I do not get the same results, right GLB is the original one, left is the one that is supossed to concatenate with the first one:

image

Here is my modified code:

      const offset = [0, 0, glbSize.x]
      const newObject = new Mesh()
      const originalObject = new Mesh()
      const targetPosition = new Vector3()
      const offsetVector = new Vector3(...offset)

      originalObject.applyMatrix4(itemMatrix)
      originalObject.updateMatrixWorld()
      originalObject.localToWorld(offsetVector)
      originalObject.getWorldPosition(targetPosition).add(offsetVector)

      newObject.position.copy(targetPosition)
      newObject.quaternion.copy(originalObject.quaternion)
      newObject.updateMatrix()
      newObject.updateMatrixWorld()

      const matrix = new Matrix4().copy(newObject.matrix)
     ... I later give this matrix to the new object

I would simply use:

sourceModel.matrix.extractBasis( vx, vy, vz );
targetModel.position.addScaledVector( vx, offset );

Here is a proof-of-concept (the smaller model takes its position and orientation from the big model, see lines 74-82):

https://codepen.io/boytchev/full/KKrdqGX

image

2 Likes

@PavelBoytchev This worked! Thanks a million for your Codepen, this is exactly what I needed. Here is my code in case it can help anyone in the future:

     const offset = glbSize.x
      const model2 = new Mesh()
      const model = new Mesh()
      const vx = new Vector3()

      model.applyMatrix4(itemMatrix)
      model2.position.copy(model.position)
      model2.rotation.copy(model.rotation)

      model.matrix.extractBasis(vx, new Vector3(), new Vector3())
      model2.position.addScaledVector(vx, offset)
      model2.updateMatrix()

      const matrix = new Matrix4().copy(model2.matrix)
     ... Apply this matrix to the mesh

1 Like