Матрица перспективы, которая полностью инкапсулирует объект
Я хотел бы создать проекционную матрицу, которая будет визуализировать объект с произвольной камеры. Мне удалось настроить viewMatrix, который будет смотреть на объект с произвольной позиции глаза, но у меня возникают трудности с настройкой матрицы проекции.
Учитывая, что объект с центром в точке (x,y,z), самая дальняя точка которого находится от центра r, может для любой произвольной ориентации быть полностью заключенным в сферу радиуса r с началом координат (x,y,z), я вычислил свою перспективу Матрица выглядит следующим образом:
float dist2Object = (float) Math.sqrt(vec.lengthSquared());
float objectRadius = (float) Math.sqrt(3 * Math.pow(0.5, 2));
float far = dist2Object + objectRadius;
float near = dist2Object - objectRadius;
// fov_2 = FOV / 2
float fov_2 = (float) (Math.asin(objectRadius / dist2Object));
float r = (float) (Math.tan(fov_2));
float frustum_length = far - near;
depthProjectionMatrix.m00 = 1 / r;
depthProjectionMatrix.m11 = depthProjectionMatrix.m00;
depthProjectionMatrix.m22 = -((far + near) / frustum_length);
depthProjectionMatrix.m23 = -1;
depthProjectionMatrix.m32 = -((2 * near * far) / frustum_length);
depthProjectionMatrix.m33 = 0;
В моем примере:
- vec - это вектор от камеры к объекту
- объект - это куб, у которого самая дальняя вершина (0,5, 0,5, 0,5), что дает ар из sqrt(0,75)
Насколько я могу судить, геометрия и тригонометрия должны быть правильными, но рендеринг координат осуществляется с помощью следующего фрагментного шейдера:
#version 150 core
in vec3 pCoord;
out vec4 out_Color;
void main(void) {
out_Color = vec4(0,1,0,1);
if(pCoord.x <= -1){
out_Color = vec4(1,0,0,1);
}
if(pCoord.x >= 1){
out_Color = vec4(0,0,1,1);
}
if(pCoord.z <= -1){
out_Color = vec4(1,0,1,1);
}
if(pCoord.z >= 1){
out_Color = vec4(1,0,1,1);
}
}
показанное на изображении показывает, что поле зрения слишком узкое и что ближняя и дальняя плоскости также слишком узки.
Как я могу это исправить?
1 ответ
Давно не делали этого, но, похоже, в ваших расчетах не указан размер области просмотра. Вот что я использовал для проекта. Имейте в виду, что матрица здесь начинается с _11, где вы используете m00:
double aspectRatio = (double)this.viewPort.Width /(double)this.viewPort.Height;
double fov = Math.toRadians(fieldOfView/2.0);
double size = nearClip * Math.tan(fov);
double left = -size* aspectRatio, right = size* aspectRatio, bottom = -size , top = size ;
projectionMatrix.resetToZero();
// the values in comments are for non symetrical frustrum
// First Column
projectionMatrix._11 = (float) (nearClip/right);//(float) ((2 * nearClip )/ (double)(right - left));
// Second Column
projectionMatrix._22 = (float)(nearClip/top);//(float) (2 * nearClip / (double)(top - bottom));
// Third Column
projectionMatrix._31 = 0;//(float) ((right + left) / (right - left));
projectionMatrix._32 = 0;//(float) ((top + bottom) / (top - bottom));
projectionMatrix._33 = -1*(farClip + nearClip) / (float)(farClip - nearClip);
projectionMatrix._34 = -1;
// Fourth Column
projectionMatrix._43 = -(2 * farClip * nearClip) / (float)(farClip - nearClip);