任意图形的变换原理

前言

学习目标

  • 基于某一基点变换任意图形

知识点

  • 矩阵变换

1-基点变换的思路

此时我突然想起一句让人午夜惊醒的话:来,咱们再把这件事情的来龙去脉从头捋一遍。

我现在就想着把这个基点变换的逻辑从头捋一遍。

我之前把图案变换的文章和课件放出去后,有的同学竟然无法照葫芦画瓢的实现文字变换。

这个问题是我的锅,这不是谦虚,而是事实,因为我的那几个同学的编程能力和学习能力都很强的。

矩阵变换是我们走图形学路线的同学必须要掌握且夯实的,所以我觉得我必须再把这件事情的来龙去脉从头捋一遍。

已知:

1.图形obj的初始状态如下,其所在的坐标系为m0,m0不可写。

image-20230612202533018

x0,y0是m0的基向量。

A0是obj在m0中的右下角点。

2.obj只能通过矩阵m1变换,现在obj被m1变换成了下图的样式:

image-20230612204353708

  • x,y是世界坐标系的基向量。
  • A1是m1*A0后得到的A0在世界坐标系中的点位。

求:以A0为变换基点,mt为相对变换矩阵,对当前状态的obj进行相对变换后的绝对矩阵m1

思路:任意图形的基点变换都可以通过一个矩阵实现。我们可以创建一个矩阵,使obj的变换基点在A0上,然后再对其进行mt的变换,如下图所示:

image-20230612205911588

解:

1.建立矩阵m2,使其可以在m0坐标系中,将A0移动到原点。

m2.position=-A0

m2*m0 的效果如下:

image-20230612224101370

假设当前变换的图形为obj’,接下来需要在世界坐标系中,将其与当前状态的obj重合。

2.建立矩阵m3,设置其位移量,使让obj’的A0点与obj的A1点对齐。

m3.position=A1

m3m2m0 的效果如下:

image-20230612224520083

现在基点就对齐了,接下来再将obj’的缩放量和旋转量与obj对齐。

3.将m1中的旋转量和缩放量赋值给m3。

m3.scale=m1.scale
m3.rotate=m1.rotate

m3m2m0 的效果如下:

image-20230612225211751

现在已经实现了obj’和obj的重合。

4.在m3中加上相对变换矩阵的变换量,对obj’进行相对变换。

m3.scale*=mt.scale
m3.rotate+=mt.rotate
m3.position+=mt.position

上面的m1便是基于A0点,对当前状态的obj进行相对变换mt后的绝对矩阵m1。

可实现类似效果:

image-20230612230018411

接下来,我们在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)

效果如下:

image-20230613110032872

之前声明的变换基点A0便是在这个矩形的左下角。

4.创建m2矩阵,使其可以在m0坐标系中,将A0移动到原点。

const m2 = new Matrix3().makeTranslation(-A0.x, -A0.y)

基于m2绘制一个矩形看看:

drawRect(ctx, m2, 'orange')

效果如下:

image-20230613111238274

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')

效果如下:

image-20230613112103094

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)

效果如下:

image-20230613114921601

关于基点变换的代码实现就是这样,大家可以自己调着试试。

总结

我之前的图案变换主要是做一个热身,那个理解起来比较具象。

接下我们可以把之前的图案变换忘掉,用现在的变换方法来实现任意图形的变换。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYChoGzp' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片