ArcballCamera has wrong rotation if target is not [0, 0, 0]

Hi @caroline , please see the attached project and video.

05-lighting-fundamentals.zip (163.1 KB)

I set train.position = [10, 0, 0], and camera.target = [10, 0, 0].
So in my opinion the camera should rotate around the train when moved, but as you can see in the movie it is rotating around in a bizarre way.

thx

Yes, you’re right. The Arcball camera doesn’t work correctly.

Try this code for Arcball:

class ArcballCamera: Camera {

  var fov = Float(70).degreesToRadians

  let minDistance: Float = 0.0
  let maxDistance: Float = 20
  var target: float3 = [0, 0, 0]
  var distance: Float = 2.5

  override var viewMatrix: float4x4 {
    let matrix: float4x4
    if target == position {
      matrix = (float4x4(translation: target) * float4x4(rotationYXZ: rotation)).inverse
    } else {
      matrix = float4x4(eye: position, center: target, up: [0, 1, 0])
    }
    return matrix
  }

  override func zoom(delta: Float) {
    let sensitivity: Float = 0.05
    distance -= delta * sensitivity
    let rotateMatrix = float4x4(
      rotationYXZ: [-rotation.x, rotation.y, 0])
    let distanceVector = float4(0, 0, -distance, 0)
    let rotatedVector = rotateMatrix * distanceVector
    position = target + rotatedVector.xyz
  }

  override func rotate(delta: float2) {
    let sensitivity: Float = 0.005
    rotation.y += delta.x * sensitivity
    rotation.x += delta.y * sensitivity
    rotation.x = max(
      -Float.pi/2,
      min(rotation.x, Float.pi/2))

    let rotateMatrix = float4x4(
      rotationYXZ: [-rotation.x, rotation.y, 0])
    let distanceVector = float4(0, 0, -distance, 0)
    let rotatedVector = rotateMatrix * distanceVector
    position = target + rotatedVector.xyz
  }
}

This one rotates the vector properly and takes into account distance. It’s not completely correct, as it does a weird flip at extremes, but you can probably put limits on the rotation to prevent that.

In Renderer, when you initialise camera, after setting camera.rotation.x = Float(-10).degreesToRadians, add this:

 camera.rotate(delta: [0, 0])

This just initializes the view matrix.

1 Like