You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何围绕玩家移动相机并将其固定在玩家身上?

实现相机围绕玩家旋转的解决方案

看起来你想要实现相机围绕玩家旋转的第三人称视角效果对吧?我看了你当前的Camera类实现,现在的逻辑是相机基于自身位置和前方向生成视图矩阵,要改成围绕玩家移动的话,我们需要调整核心逻辑——把玩家位置作为固定目标点,相机的位置根据角度和距离围绕这个目标点计算。

首先先把你提供的现有代码格式化出来:

class Camera {
public:
    Camera(glm::vec3 position, glm::vec3 up, GLfloat yaw, GLfloat pitch) {
        this->position = position;
        this->m_WorldUp = up;
        this->up = up;
        this->m_Yaw = yaw;
        this->m_Pitch = pitch;
        this->UpdateCameraVectors();
    }

    glm::mat4 Camera::getViewMatrix() {
        return glm::lookAt(position, position + m_Front, up);
    }

    void Camera::ProcessKeyboard(Camera_Movement direction, GLfloat deltaTime) {
        float velocity = ...; // 你这里的代码没写完,不过没关系
        // 现有键盘处理逻辑
    }

private:
    glm::vec3 position;
    glm::vec3 m_WorldUp;
    glm::vec3 up;
    glm::vec3 m_Front;
    glm::vec3 m_Right;
    GLfloat m_Yaw;
    GLfloat m_Pitch;

    void UpdateCameraVectors();
};

接下来是具体的修改方案:

1. 新增核心成员变量

我们需要给Camera类添加两个关键变量:

  • m_Target:存储玩家的位置,也就是相机要围绕旋转的目标点
  • m_Distance:相机到玩家的距离,用来控制视角的远近

修改后的类成员如下:

private:
    glm::vec3 position;
    glm::vec3 m_WorldUp;
    glm::vec3 up;
    glm::vec3 m_Front;
    glm::vec3 m_Right;
    GLfloat m_Yaw;
    GLfloat m_Pitch;
    // 新增:玩家目标位置
    glm::vec3 m_Target;
    // 新增:相机与玩家的距离
    GLfloat m_Distance;

2. 调整构造函数

更新构造函数,初始化目标点和距离,并且根据初始角度计算相机的初始位置:

Camera::Camera(glm::vec3 target, glm::vec3 up, GLfloat yaw, GLfloat pitch, GLfloat distance) {
    this->m_Target = target;
    this->m_Distance = distance;
    this->m_WorldUp = up;
    this->up = up;
    this->m_Yaw = yaw;
    this->m_Pitch = pitch;
    // 根据角度和距离计算相机初始位置
    UpdateCameraPosition();
    this->UpdateCameraVectors();
}

3. 添加相机位置计算方法

新增一个UpdateCameraPosition方法,通过球面坐标转笛卡尔坐标的方式,根据yaw、pitch和距离计算相机相对于玩家的位置:

void Camera::UpdateCameraPosition() {
    // 球面坐标转换:基于目标点计算相机位置
    GLfloat x = m_Target.x + m_Distance * cos(glm::radians(m_Pitch)) * cos(glm::radians(m_Yaw));
    GLfloat y = m_Target.y + m_Distance * sin(glm::radians(m_Pitch));
    GLfloat z = m_Target.z + m_Distance * cos(glm::radians(m_Pitch)) * sin(glm::radians(m_Yaw));
    this->position = glm::vec3(x, y, z);
}

4. 修改视图矩阵生成逻辑

原来的getViewMatrix是让相机看向自身前方向,现在要改成看向玩家位置:

glm::mat4 Camera::getViewMatrix() {
    // 第二个参数改为玩家目标点,而不是相机位置+前方向
    return glm::lookAt(position, m_Target, up);
}

5. 调整鼠标与键盘输入处理

  • 鼠标移动:当用户拖动鼠标时,更新yaw和pitch,然后重新计算相机位置:
void Camera::ProcessMouseMovement(GLfloat xoffset, GLfloat yoffset, GLboolean constrainPitch = true) {
    // 调整鼠标灵敏度
    xoffset *= 0.1f;
    yoffset *= 0.1f;

    m_Yaw += xoffset;
    m_Pitch += yoffset;

    // 限制俯仰角,避免相机翻转到奇怪的角度
    if (constrainPitch) {
        if (m_Pitch > 89.0f)
            m_Pitch = 89.0f;
        if (m_Pitch < -89.0f)
            m_Pitch = -89.0f;
    }

    // 更新相机位置和方向向量
    UpdateCameraPosition();
    UpdateCameraVectors();
}
  • 键盘输入:可以改成控制相机与玩家的距离(拉近/拉远):
void Camera::ProcessKeyboard(Camera_Movement direction, GLfloat deltaTime) {
    GLfloat speed = 2.5f * deltaTime;
    if (direction == FORWARD)
        m_Distance -= speed;
    if (direction == BACKWARD)
        m_Distance += speed;
    // 限制距离范围,避免相机贴脸或者太远
    m_Distance = glm::clamp(m_Distance, 1.0f, 20.0f);
    // 更新相机位置
    UpdateCameraPosition();
}

6. 玩家移动时更新目标点

当玩家在场景中移动时,只需要调用一个setter方法更新相机的目标点即可:

void Camera::SetTarget(glm::vec3 newTarget) {
    m_Target = newTarget;
    UpdateCameraPosition();
}

这样修改后,相机就会始终围绕玩家(m_Target)旋转,鼠标控制旋转角度,键盘控制视角远近,完全符合你想要的效果。

内容的提问来源于stack exchange,提问作者IScream

火山引擎 最新活动