在2D平面上旋转3D向量 [英] Rotate 3D vectors on 2D plane

查看:165
本文介绍了在2D平面上旋转3D向量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个Vec3,分别是Camera Forward和Turret Forward.这两个向量都位于不同的平面上,"Camera Forward"基于自由外观的相机,"Turret Forward"由其所在的坦克,坦克所在的地形等确定."Turret Up"和"Camera Up"很少匹配.

I have two Vec3s, Camera Forward and Turret Forward. Both of these vectors are on different planes where Camera Forward is based on a free-look camera and Turret Forward is determined by the tank it sits on, the terrain the tank is on, etc. Turret Up and Camera Up are rarely ever going to match.

我的问题如下:我希望转塔能够以固定速度(每秒44度)旋转,以使其始终与相机指向的方向会合.如果水箱处于怪异的角度而无法与相机汇合,则应该找到最近的位置并坐在那里,而不是无限地晃动.

My issue is as follows: I want the turret to be able to rotate using a fixed velocity (44 degrees per second) so that it always converges with the direction that the camera is pointed. If the tank is at a weird angle where it simply cannot converge with the camera, it should find the closest place and sit there instead of jitter around indefinitely.

我似乎一生无法解决这个问题.我尝试了网上发现的几种方法,这些方法总是会产生奇怪的结果.

I cannot for the life of me seem to solve this problem. I've tried several methods I found online that always produce weird results.

    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

推荐答案

经过更多的研究和测试,我得出了以下解决方案.它畅通无阻!

After some more research and testing, I ended up with the following solution. It works swimmingly!

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

这篇关于在2D平面上旋转3D向量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆