#How to rotate the camera paralel to a mesh face ?

53 messages · Page 1 of 1 (latest)

cosmic valley
#

my code:

#
const handleButtonClick = async (targetRef) => {
  const currentPos = await refs.cameraControlsRef.current.getPosition();
  const target = await targetRef.current.position;
  const targetRotation = await targetRef.current.rotation;

  const geometry = targetRef.current.children[0].children[0].geometry;
  const faceNormals = targetRef.current.children[0].children[0].geometry.attributes.normal.array;

  const cameraControls = await refs.cameraControlsRef.current;
  const camera = await refs.cameraRef.current;

  const center = new THREE.Vector3();
  geometry.computeBoundingBox();
  geometry.boundingBox.getCenter(center);
  targetRef.current.localToWorld(center);

  const normal = new THREE.Vector3();
  faceNormals.forEach((n, i) => {
    if (i % 2 !== 1) {
      normal.set(n, faceNormals[i + 1], faceNormals[i + 2]);
      targetRef.current.children[0].children[0].matrixWorld.extractRotation(
        targetRef.current.children[0].children[0].matrixWorld
      );
      normal.applyMatrix4(targetRef.current.children[0].children[0].matrixWorld);
      normal.negate();
      return;
    }
  });

  const distance = 15;
  const cameraPosition = center.clone().add(normal.clone().multiplyScalar(distance));

  gsap.to(currentPos, {
    duration: 1,
    x: cameraPosition.x,
    y: cameraPosition.y,
    z: cameraPosition.z,
    onUpdate: () => {
      cameraControls.setPosition(currentPos.x, currentPos.y, currentPos.z);

      

      cameraControls.setLookAt(
        cameraPosition.x,
        cameraPosition.y,
        cameraPosition.z,
        target.x,
        target.y,
        target.z,
        true
      );
    },

    onComplete: () => {

      cameraControls.rotate(Math.PI/2, 0, true);
    }
  });



  console.log(targetRotation);
  console.log(cameraControls.camera.rotation);
};


#

when i rotate like this, the camera rotates around the center of the target cuboid mesh, but not paralel to it

#

gif of what it looks like:

#

what can i do ?

#

thx

safe agate
#

There are two main changes that need to be made:

Calculating the face normal

Right now, you're iterating over faceNormals and using every second normal as the target normal. If you want to align the camera with a specific face of the mesh, you'll need to identify that face and calculate its normal vector. This might involve identifying the vertices of the face and calculating the cross product of two of its edges.

Aligning the camera with the normal

Once you have the correct normal vector, you need to orient the camera along that vector. Right now, the camera's position is being updated, but its orientation is not.

Note that this code still needs to define the calculateFaceNormal() function, which is responsible for calculating the normal of the face you're interested in. This would typically involve identifying the vertices of that face and calculating the cross product of two of its edges.

cosmic valley
#

but i thought i am already calculating the face normal here :

#

  const normal = new THREE.Vector3();
  faceNormals.forEach((n, i) => {
    if (i % 2 !== 1) {
      normal.set(n, faceNormals[i + 1], faceNormals[i + 2]);
      targetRef.current.children[0].children[0].matrixWorld.extractRotation(
        targetRef.current.children[0].children[0].matrixWorld
      );
      normal.applyMatrix4(targetRef.current.children[0].children[0].matrixWorld);
      normal.negate();
      return;
    }
  });
#

am i wrong ?

safe agate
# cosmic valley ```javascript const normal = new THREE.Vector3(); faceNormals.forEach((n, i...

Yes, you're right that you're attempting to calculate the face normal in that piece of code. But, there are a few issues with your current method.

**Normal Selection **

The faceNormals array contains the normals for all faces in your mesh, not just one. With if (i % 2 !== 1), you're essentially picking the normal of every other face. If you're interested in a specific face, you need a more precise way of identifying its normal. The exact method will depend on how your mesh is structured.

**Matrix Transformation **

You're applying the matrixWorld of the mesh to the normal, but before that, you're doing extractRotation(targetRef.current.children[0].children[0].matrixWorld). extractRotation gets the rotational part of a matrix, but in this case, it's not being assigned to anything, so this line doesn't do anything.

**Return Statement **

You're using a return statement inside your forEach loop. This will exit the current iteration of the loop, but it won't prevent the other normals from being processed. If you want to exit the loop entirely once you've found the right normal, you might want to use a traditional for loop with a break statement.

I have provided a small code which you can try instead. You would have to replace faceIndex with the index of the face you're interested in.

cosmic valley
#

i can see the other mistakes that ive made now. thx so much again !

safe agate
# cosmic valley so i guess that if (i % 3 === 0) will choose every face ?

Yes, your understanding is correct, but make sure you're aware that this is processing each triangle's normal, not each 'face' of a cube if you're thinking of faces as the six sides of a cube. If you're wanting to align the camera with a specific side of a cuboid, you would need to identify which triangles make up that side, and then calculate the average of their normals to get the face normal.

cosmic valley
safe agate
#

Here is a small piece of code which I drafted up for you.

cosmic valley
#

i see, but if the camera is looking at a cuboids face so that its paralel to the camera face, how will it rotate to the correct position ? also, i cant rotate camera directly since its being overwritten by a camera controls.

safe agate
#

You will need to set the target of the camera controls to the desired position rather than the camera itself.

#

If the cuboid's face is parallel to the camera's viewing direction, then the camera should already be oriented correctly. However, if you also need the camera's up vector (which defines the camera's rotation around its viewing axis) to align with a specific direction, you may need to do additional calculations.

cosmic valley
cosmic valley
safe agate
#

You need to match the camera's "up" direction with the "up" direction of the target mesh.

cosmic valley
# safe agate You need to match the camera's "up" direction with the "up" direction of the tar...

is it possible to do that with these controls ? https://www.npmjs.com/package/camera-controls

#

i just tried to use applyCameraUp() method, but now the camera just seems to assume the up of the previous mesh

safe agate
cosmic valley
# safe agate

oh, but what is the up property in the geometry object ?

#

¨do i need to compute the up vector from the objects rotation or is it just the normal of the meshes top side ?

safe agate
#

The 'up' property is a THREE.Vector3 that defines the up direction for an object in 3D space. I wasn't aware it was included in the geometry object so in this case you can just grab it from the Geometry object directly.

cosmic valley
cosmic valley
#

OH

#

when i do

#
  refs.cameraControlsRef.current.camera.up = targetRef.current.up
      refs.cameraControlsRef.current.updateCameraUp()
      refs.cameraControlsRef.current.applyCameraUp()
#

the camera really does rotate according to the previous meshes up

#

and the up does change

cosmic valley
safe agate
#

I am currently busy with an issue of my own, which I will probably have to file an issue to the github for, so I am sorry if I take a bit to respond sometimes.

cosmic valley
cosmic valley
#
  const up = new THREE.Vector3(0, 1, 0); 
  targetRef.current.localToWorld(up)
  up.sub(targetRef.current.position).normalize();

  refs.cameraControlsRef.current.camera.up.copy(up);
  refs.cameraControlsRef.current.updateCameraUp()
  refs.cameraControlsRef.current.applyCameraUp()
  
#

i have to click two times on the target for the camera to actually rotate to the desired place, but ill just use a promise somewhere !!!

#

thank you yet again so much for this. i have been struggling with this for 3 days in a row now. you really made someone happy rn. thank you ! thank you ! thank you !

safe agate
cosmic valley
cosmic valley
#

is there anything that might be causing that ?

#

  const positionArray = positionAttribute.array;
  const indices = indexAttribute.array;
  const vertexNormals = normalAttribute.array;


  const center = new THREE.Vector3();
  geometry.computeBoundingBox();
  geometry.boundingBox.getCenter(center);
  targetRef.current.localToWorld(center);

  const normal = new THREE.Vector3();
  vertexNormals.forEach((n, i) => {
    if (i % 2 !== 1) {
      normal.set(n, vertexNormals[i+1], vertexNormals[i+2]);
      targetRef.current.children[0].children[0].matrixWorld.extractRotation(targetRef.current.children[0].children[0].matrixWorld);
      normal.applyMatrix4(targetRef.current.children[0].children[0].matrixWorld);
      normal.negate();
      return;
    }
  });
  const distance = 15;
  const cameraPosition = center.clone().add(normal.clone().multiplyScalar(distance));
  
  gsap.to(currentPos, {
    duration: 1.7,
    x: cameraPosition.x,
    y: cameraPosition.y,
    z: cameraPosition.z,
    onUpdate: () => {
      const up = new THREE.Vector3(0, 1, 0); 
      targetRef.current.localToWorld(up)
      up.sub(targetRef.current.position).normalize();
      refs.cameraControlsRef.current.camera.up.copy(up);
      refs.cameraControlsRef.current.updateCameraUp()
      refs.cameraControlsRef.current.applyCameraUp()
#

also, the extractRotation() is actually doing something because when i delete it, the code sends the camera far away