模型绕着摄像机旋转

场景:
1.摄像机位置不变,可绕x,y轴任意旋转
2.模型不能超出摄像机视野,超出则拉回到视野边缘

1.获取摄像机的旋转

auto CrameraRot = [](const float3 eye, float3 center, const float3& up) noexcept ->mat4f {
        float3 z_axis(normalize(center - eye));
        float3 norm_up(normalize(up));
        if (std::abs(dot(z_axis, norm_up)) > 0.999) {
            norm_up = { norm_up.z, norm_up.x, norm_up.y };
        }
        float3 x_axis(normalize(cross(z_axis, norm_up)));
        float3 y_axis(cross(x_axis, z_axis));
        return mat4f(
            float4(x_axis, 0),
            float4(y_axis, 0),
            float4(-z_axis, 0),
            float4(0, 0, 0, 1));
    };

这个函数跟LookAt的参数一致,用来获取当前相机的旋转矩阵

2. 计算模型旋转后的位移向量

计算相机透视投影平截头体在经过模型中心且垂直于相机空间Z轴的面的包围盒

auto calcBound = [](double fov, double asp, double focusLen,filament::Camera::Fov dire)->float4 {
        double w;
        double h;
        double s = std::tan(fov * filament::math::d::DEG_TO_RAD / 2.0) * focusLen;
        if (dire == filament::Camera::Fov::VERTICAL) {
            w = s * asp;
            h = s;
        }
        else {
            w = s;
            h = s / asp;
        }
        return float4(-w, w, -h, h);
    };

3.计算模型的转换矩阵

mat4f cameraMat = CrameraRot(camera_pos, camera_pos + camera_forword, world_up);
	//mFocusPosition 为相机位移坐标
    float3 model_normal = mFocusPosition - camera_pos;	//以相机为原点,模型的向量
    float3 cameraForward = camera->getForwardVector();	//相机forward向量
    float model_radius = distance(module_tran, camera_pos);	//模型绕相机旋转的半径长
    float forword_len = dot(model_normal, cameraForward) / length(cameraForward);//模型在相机方向上的投影长
    float4 bound = calcBound(fovInDegrees, aspect, forword_len, direction);//计算相机位置在平截头体的空间大小

    float model_width = width;	//模型在视口空间的大小
    float model_height = height;	
    float view_width = abs(bound.y - bound.x);//投影空间的截面宽高
    float view_height = abs(bound.z - bound.w);
    float3 view_left = normalize(camera->getLeftVector());//截面上相机的左向量
    float3 view_up = normalize(cross(cameraForward, view_left));//截面上相机的上向量
    float3 model_normal_view = model_normal - normalize(cameraForward) * forword_len;//截面上指向模型的向量

    float model_up_len = dot(model_normal_view, view_up) / length(view_up);	//该向量在相机上向量投影长
    float model_left_len = dot(model_normal_view, view_left) / length(view_left);
    float3 model_up_normal = view_up * model_up_len;	//相机上向量方向的分向量
    float3 model_left_normal = view_left * model_left_len;

    float max_x_len = (view_width - model_width) / 2; //截面上横轴方向允许模型距离中心的最大距离
    float max_y_len = (view_height - model_height) / 2;

    if (abs(model_up_len) > max_y_len) {	//模型超出边缘的时候放置在边缘
        model_up_normal = (model_up_len >= 0 ? view_up : -view_up) * max_y_len; 
    }
    if (abs(model_left_len) > max_x_len) {
        model_left_normal = (model_left_len >= 0 ? view_left : -view_left) * max_x_len;
    }
    float3 ttmp = model_up_normal + model_left_normal; //截面上矫正后的模型的分向量
    float forword_len_new = sqrt(pow(model_radius, 2) - pow(length(ttmp), 2));//根据旋转半径和模型分向量计算模型实际向量在相机forward方向的投影长
    model_normal = model_up_normal + model_left_normal + normalize(cameraForward) * forword_len_new;	//矫正后的模型向量
    mFocusPosition = model_normal + camera_pos; //模型的矫正坐标(位移坐标)

    mFocusTrandform = mat4f::translation(mFocusPosition) *cameraMat * rotation; //最终模型的转换矩阵
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值