Есть несколько шагов к этому вычислению, и я советую разбить его на соответствующие секции и проверить каждый из них.
Модель с координатами камеры - Этоэто поворот position = (x,y,z)
точек из координат модели в координаты камеры.Здесь мы предполагаем, что цель камеры находится в начале координат.
local = rot * (position - target)
| x' | | rx ry rz | | x | | rx*x + ry*y + rz*z |
| y' | = | ux uy yz | * | y | = | ux*x + uy*y + uz*z |
| z' | | fx fy fz | | z | | fx*x + fy*y + fz*z |
Перспективная проекция - Вам необходимо определить расстояние между целью и камерой, а также размер модели, которая будет охватыватьПосмотреть.Давайте назовем их, distance
и size
.Результат - координаты вида, которые варьируются между 0..1
как по x, так и по y.
| vx | | (distance/size)*(x'/(distance+z')) |
| | = | | |
| vy | | (distance/size)*(y'/(distance+z')) |
Это происходит из похожих треугольников.Если x'=size
и z'=0
, то vx=1
.Чем больше z'
, тем меньше становится vx
.
Пиксельные координаты
Здесь вы отображаете координаты вида в пикселях.Ваш видовой экран имеет width
и height
, и вы хотите [0,0]
пикселей в левом верхнем углу и [width-1,height-1]
в правом нижнем углу.
width
+-------------------+
|(-1,1) : (1,1)|
| : |
| : (0,0) |
+- - - - -+- - - - -+ height
| : |
| : |
|(-1,-1) : (1,-1)|
+-------------------+
px = (width-1)*(vx+1.0)/2.0
py = (height-1)*(1.0-vy)/2.0
Наконец,Я рекомендую использовать программирование ООП (если возможно), чтобы отделить математику вектора / матрицы от цели.Рассмотрим следующий пример в c # .
public static Vector3 ThroughCamera(Vector3 point, Vector3 target, Matrix3 camera)
{
return camera.Transpose()*(point-target);
}
public static Vector2 Perspective(Vector3 point, double distance, double size=1)
{
return new Vector2(
(distance/size)*(point.X/(distance+point.Z)),
(distance/size)*(point.Y/(distance+point.Z)) );
}
public static PointF Pixel(Vector2 point, int width, int height)
{
return new PointF(
(float) ((width-1)*(point.X+1)/2),
(float) ((height-1)*(1-point.Y)/2) );
}
static void dlg_Paint(object sender, PaintEventArgs e)
{
Form dlg=sender as Form;
// Set camera rotation
Matrix3 camera=Matrix3.Ry(0.67);
double distance=25;
double size=20;
for(int i=0; i<10; i++)
{
for(int j=0; j<10; j++)
{
// this is the model points
Vector3 pt=new Vector3(5*(i-5), 5*(j-5), 0);
// these are the points through the camera
Vector3 pt_local=ThroughCamera(pt, Vector3.O, camera);
// these are the view coordinates
Vector2 pt_view=Perspective(pt_local, distance, size);
// these are the pixel coordinates
PointF px=Pixel(pt_view, dlg.ClientSize.Width, dlg.ClientSize.Height);
e.Graphics.DrawRectangle(Pens.Blue, px.X, px.Y, 1f, 1f);
}
}
}