前言
学习目标
- 基于某一基点变换任意图形
知识点
- 矩阵变换
1-基点变换的思路
此时我突然想起一句让人午夜惊醒的话:来,咱们再把这件事情的来龙去脉从头捋一遍。
我现在就想着把这个基点变换的逻辑从头捋一遍。
我之前把图案变换的文章和课件放出去后,有的同学竟然无法照葫芦画瓢的实现文字变换。
这个问题是我的锅,这不是谦虚,而是事实,因为我的那几个同学的编程能力和学习能力都很强的。
矩阵变换是我们走图形学路线的同学必须要掌握且夯实的,所以我觉得我必须再把这件事情的来龙去脉从头捋一遍。
已知:
1.图形obj的初始状态如下,其所在的坐标系为m0,m0不可写。
x0,y0是m0的基向量。
A0是obj在m0中的右下角点。
2.obj只能通过矩阵m1变换,现在obj被m1变换成了下图的样式:
- x,y是世界坐标系的基向量。
- A1是m1*A0后得到的A0在世界坐标系中的点位。
求:以A0为变换基点,mt为相对变换矩阵,对当前状态的obj进行相对变换后的绝对矩阵m1
思路:任意图形的基点变换都可以通过一个矩阵实现。我们可以创建一个矩阵,使obj的变换基点在A0上,然后再对其进行mt的变换,如下图所示:
解:
1.建立矩阵m2,使其可以在m0坐标系中,将A0移动到原点。
m2.position=-A0
m2*m0 的效果如下:
假设当前变换的图形为obj’,接下来需要在世界坐标系中,将其与当前状态的obj重合。
2.建立矩阵m3,设置其位移量,使让obj’的A0点与obj的A1点对齐。
m3.position=A1
m3m2m0 的效果如下:
现在基点就对齐了,接下来再将obj’的缩放量和旋转量与obj对齐。
3.将m1中的旋转量和缩放量赋值给m3。
m3.scale=m1.scale
m3.rotate=m1.rotate
m3m2m0 的效果如下:
现在已经实现了obj’和obj的重合。
4.在m3中加上相对变换矩阵的变换量,对obj’进行相对变换。
m3.scale*=mt.scale
m3.rotate+=mt.rotate
m3.position+=mt.position
上面的m1便是基于A0点,对当前状态的obj进行相对变换mt后的绝对矩阵m1。
可实现类似效果:
接下来,我们在canvas里写一下这个过程。
2-基点变换的代码实现
1.声明已知变量。
/* 变换基点 */
const A0 = new Vector2(150, 100)
/* m1 */
const position = new Vector2(0, 0)
const rotate = 0.3
const scale = new Vector2(1.5, 1)
const m1 = new Matrix3()
.scale(scale.x, scale.y)
.rotate(rotate)
.translate(position.x, position.y)
/* 相对变换矩阵mt中的变换量 */
const mtRotate = 0.2
const mtScale = new Vector2(1, 2)
const mtPosition = new Vector2(-100, -50)
2.声明一个绘制矩形的方法。
/* 绘制矩形 */
function drawRect(
ctx: CanvasRenderingContext2D,
m: Matrix3,
fillStyle = '#000'
) {
const { elements: e } = m
ctx.save()
ctx.fillStyle = fillStyle
ctx.transform(e[0], e[1], e[3], e[4], e[6], e[7])
ctx.fillRect(0, 0, 150, 100)
ctx.restore()
}
3.先绘制一个obj对象
drawRect(ctx, m1)
效果如下:
之前声明的变换基点A0便是在这个矩形的左下角。
4.创建m2矩阵,使其可以在m0坐标系中,将A0移动到原点。
const m2 = new Matrix3().makeTranslation(-A0.x, -A0.y)
基于m2绘制一个矩形看看:
drawRect(ctx, m2, 'orange')
效果如下:
5.创建m3矩阵,先使其可以在世界坐标系中,将刚才画的橙色矩形obj’与黑色矩形obj对齐。
const A1 = A0.clone().applyMatrix3(m1)
const m3 = new Matrix3()
.scale(scale.x, scale.y)
.rotate(rotate)
.translate(A1.x, A1.y)
使用m3和m2绘制一个红色的obj’。
drawRect(ctx, m3.clone().multiply(m2), 'red')
效果如下:
6.在m3中,基于矩阵mt做相对变换。
const m3 = new Matrix3()
.scale(scale.x * mtScale.x, scale.y * mtScale.y)
.rotate(rotate + mtRotate)
.translate(A1.x + mtPosition.x, A1.y + mtPosition.y)
效果如下:
关于基点变换的代码实现就是这样,大家可以自己调着试试。
总结
我之前的图案变换主要是做一个热身,那个理解起来比较具象。
接下我们可以把之前的图案变换忘掉,用现在的变换方法来实现任意图形的变换。