坐标系转换历程
模型坐标系 -> 世界坐标系 -> 摄像机坐标系 -> 视口(屏幕)坐标系
变换
仿射变换和线性变换
线性:旋转 缩放 镜像 切变
放射: 平移
平移
2D变换矩阵
3D变换矩阵
旋转
2D旋转矩阵
//2D 旋转
private (float,float) VertexRotate(float angle ,float x,float y)
{
float newX = (float)(x * Math.Cos(angle) - y * Math.Sin(angle));
float newY = (float)(x * Math.Sin(angle) + y * Math.Cos(angle));
return (newX,newY);
}
public void Rotate(int degree)
{
float angle = (float)(degree / 360.0f * Math.PI);
//a点
float newX, newY;
(newX,newY) = VertexRotate(angle, A.X, A.Y);
A.X = newX;
A.Y = newY;
//b点
(newX, newY) = VertexRotate(angle, B.X, B.Y);
B.X = newX;
B.Y = newY;
//C点
(newX, newY) = VertexRotate(angle, C.X, C.Y);
C.X = newX;
C.Y = newY;
}
e.Graphics.TranslateTransform(200, 200);调整坐标中心到屏幕中央
3D 旋转矩阵
组合变换(平移 + 旋转)
dx dy dz是平移分量
矩阵乘积表示 组合变换比如
先旋转 再平移
可以看出左上角是旋转变换,最后一行是平移的变换
//矩阵相乘
public Matrix4X4 Mul(Matrix4X4 m)
{
Matrix4X4 newM = new Matrix4X4();
for (int w = 1; w <= 4; w++)
for (int h = 1; h <= 4; h++)
for (int n = 1; n <= 4; n++)
{
newM[w, h] += this[w, n] * m[n, h];
}
return newM;
}
public Vector4 Mul(Vector4 v)
{
Vector4 newV = new Vector4();
newV.x = v.x * this[1,1] + v.y * this[2,1] + v.z * this[3,1] + v.w * this[4,1];
newV.x = v.x * this[1,2] + v.y * this[2,2] + v.z * this[3,2] + v.w * this[4,2];
newV.x = v.x * this[1,3] + v.y * this[2,3] + v.z * this[3,3] + v.w * this[4,3];
newV.x = v.x * this[1,4] + v.y * this[2,4] + v.z * this[3,4] + v.w * this[4,4];
return newV;
}
//三角形利用矩阵乘法进行变换
public void Transform(Matrix4X4 m)
{
this.a = this.A = m.Mul(this.A);
this.b = this.B = m.Mul(this.B);
this.c = this.C = m.Mul(this.C);
}
public void Draw(Graphics g)
{
g.DrawLines(new Pen(Color.Red,2),this.Get2DPointFArr());
}
private PointF[] Get2DPointFArr()
{
PointF[] arr = new PointF[4];
arr[0] = Get2DPointF(this.a);
arr[1] = Get2DPointF(this.b);
arr[2] = Get2DPointF(this.c);
arr[3] = arr[0];
return arr;
}
private PointF Get2DPointF(Vector4 v)
{
PointF p = new PointF();
p.X = (float)(v.x / v.w);
p.Y = (float)(v.y / v.w);
return p;
}
此时只有单纯的旋转。
如果在Z方向上添加透视投影矩阵
m_view = new Matrix4X4();
m_view = [1, 1] = 1;
m_view = [2, 2] = 1;
m_view = [3, 3] = 1;
m_view = [4, 3] = 250;
m_view = [4, 4] = 1;
m_projection = new Matrix4X4();
m_projection = [1, 1] = 1;
m_projection = [2, 2] = 1;
m_projection = [3, 3] = 1;
m_projection = [3, 4] = 1.0 / 250;
即可。
透视投影
小孔成像。利用相似三角形计算物体轮廓
透视投影矩阵
最终只有x y表达,实际的x 坐标需要 透视除法 (x / (z/d))
撤销变换
变换矩阵A * 变换矩阵A的逆矩阵