three.jsreact-three-fiberreact-three-drei

How to rotate a cube using an edge as axis


I'm new to react three fiber (and threejs too) but I was wondering if it is posible to rotate a cube using an edge as axis. Specifically, I would want to rotate around the bottom-front edge. Any advice is appreciated.

I tried grouping the cube in a with same dimensions but twice as high so it will rotate around the middle of it, that would be the bottom of my 'original' cube.

The problems with that approach are two: first, the cube is not rotating around the bottom-front edge, but around the bottom-middle X axis, and then, as the group is scaled 2x in the Y axis, I'm seeing now a cube twice as high. That's why I am looking for a better less-tricky approach.

import { OrbitControls, useHelper } from '@react-three/drei'
import { Canvas, useFrame } from '@react-three/fiber'
import { BoxHelper } from 'three'
import { useRef } from 'react'

const Cube = ({ rotation = 0 }) => {
  const cubeDepth = 0.1
  const groupRef = useRef(null)

  useHelper(groupRef, BoxHelper, 'blue')

  useFrame(() => {
    if (groupRef.current) {
      groupRef.current.rotation.x = rotation * (Math.PI / 180)
    }
  })
  return (
    //group the cube in a <group> tag with same width and depth but twice the height
    <group
      ref={groupRef}
      scale={[1, 2, cubeDepth]}
      position={[0, 0, -cubeDepth / 2.0]}
    >
      <mesh>
        <boxGeometry />
        <meshStandardMaterial color={'red'} />
      </mesh>
    </group>
  )
}

const Scene = () => {
  return (
    <Canvas className="w-screen h-screen bg-gray-400">
      <axesHelper args={[2]} />
      <gridHelper args={[10, 10]} />
      <OrbitControls maxDistance={15} minDistance={1} />
      <directionalLight position={[0, 3, 7]} />
      <Cube rotation={45} />
    </Canvas>
  )
}

export default Scene

Solution

  • you don't have to use a group here. I believe you can set the pivot point for your mesh as well with an empty 3d object, knowing that any 3d object in three.js can nest children But if you wanna use a group here's the example:

    const offset = [-0.5, 0.5, 0.5]
    
    function Box(props) {
      // unused
      const mesh = useRef()
    
      // reference to the threejs group
      const group = useRef()
    
      useFrame(() => {
        // rotating the group instead of the mesh
        group.current.rotation.y += Math.PI / 500
      })
    
      return (
        <group ref={group}>
          <mesh {...props} ref={mesh}>
            <boxGeometry args={[1, 1, 1]} />
            <meshStandardMaterial color={'orange'} />
          </mesh>
        </group>
      )
    }