在2D平面上旋转3D矢量

时间:2015-02-10 06:25:28

标签: math vector lua rotation

我有两个Vec3,Camera Forward和Turret Forward。这两个矢量都在不同的平面上,其中Camera Forward基于自由外观相机,而Turret Forward由它所在的坦克,坦克所在的地形等决定。炮塔和摄像机很少会去匹配。

我的问题如下:我希望炮塔能够以固定速度(每秒44度)旋转,以便它始终与摄像机指向的方向会聚。如果坦克处于一个奇怪的角度,它根本无法与相机会聚,它应该找到最近的位置并坐在那里而不是无限期地抖动。

我不能为我的生活似乎解决这个问题。我尝试了几种在网上找到的方法,这些方法总会产生奇怪的结果。

    local forward    = player.direction:rotate(player.turret, player.up)
    local side       = forward:cross(player.up)
    local projection = self.camera.direction:dot(forward) * forward + self.camera.direction:dot(side) * side
    local angle      = math.atan2(forward.y, forward.x) - math.atan2(projection.y, projection.x)

    if angle ~= 0 then
        local dt = love.timer.getDelta()

        if angle <= turret_speed * dt then
            player.turret_velocity = turret_speed
        elseif angle >= -turret_speed * dt then
            player.turret_velocity = -turret_speed
        else
            player.turret_velocity = 0
            player.turret          = player.turret + angle
        end
    end

Figure 1

2 个答案:

答案 0 :(得分:0)

我会采用不同的方式

  1. 在GCS(全局坐标系)中获取摄像机方向向量c

  2. 在GCS中获取炮塔方向向量t

    • 与bullet 1相同。
  3. 在展位方向计算旋转炮塔方向向量

    • t0=rotation(-44.0deg/s)*t
    • t1=rotation(+44.0deg/s)*t
  4. 现在计算点积

    • a =dot(c,t)
    • a0=dot(c,t0)
    • a1=dot(c,t1)
  5. 确定炮塔旋转

    • 如果max(a0,a,a1)== a0 rotate(-44.0deg / s)`
    • 如果max(a0,a,a1)== a1 rotate(+ 44.0deg / s)`
  6. [注释]

    • 这应该收敛到理想的方向
    • 应调整角度步长以匹配用于更新此
    • 的时间间隔
    • 您可以对子弹1,2使用任何常用坐标系,而不仅仅是GCS
    • 在这种情况下,点积为cos(angle between vectors),因为c,t都是单位向量(如果取自标准变换矩阵)
    • 所以如果cos(角度)== 1那么方向是相同的
    • 但您的相机可以在不同的轴上旋转,因此只需找到cos(角度)的最大值

答案 1 :(得分:0)

经过一些研究和测试,我最终得到了以下解决方案。它运作得很好!

function Gameplay:moved_axisright(joystick, x, y)
    if not self.manager.id then return end

    local turret_speed = math.rad(44)
    local stick        = cpml.vec2(-x, -y)
    local player       = self.players[self.manager.id]

    -- Mouse and axis control camera view
    self.camera:rotateXY(stick.x * 18, stick.y * 9)

    -- Get angle between Camera Forward and Turret Forward
    local fwd   = cpml.vec2(0, 1):rotate(player.orientation.z + player.turret)
    local cam   = cpml.vec2(1, 0):rotate(math.atan2(self.camera.direction.y, self.camera.direction.x))
    local angle = fwd:angle_to(cam)

    -- If the turret is not true, adjust it
    if math.abs(angle) > 0 then
        local function new_angle(direction)
            local dt       = love.timer.getDelta()
            local velocity = direction * turret_speed * dt
            return cpml.vec2(0, 1):rotate(player.orientation.z + player.turret + velocity):angle_to(cam)
        end

        -- Rotate turret into the correct direction
        if new_angle(1) < 0 then
            player.turret_velocity = turret_speed
        elseif new_angle(-1) > 0 then
            player.turret_velocity = -turret_speed
        else
            -- If rotating the turret a full frame will overshoot, set turret to camera position
            -- atan2 starts from the left and we need to also add half a rotation. subtract player orientation to convert to local space.
            player.turret          = math.atan2(self.camera.direction.y, self.camera.direction.x) + (math.pi * 1.5) - player.orientation.z
            player.turret_velocity = 0
        end
    end

    local direction         = cpml.mat4():rotate(player.turret, { 0, 0, 1 }) * cpml.mat4():rotate(player.orientation.z, { 0, 0, 1 })
    player.turret_direction = cpml.vec3(direction * { 0, 1, 0, 1 })
end