场景:
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; //最终模型的转换矩阵