概述
在设计圆角容器时突发奇想:
- 将圆角矩形的每个顶点坐标除以对应圆角矩形所在
Rect2
的size
,就得到了顶点对应的UV坐标。 - 然后使用
draw_colored_polygon
,便可以做到用图片填充圆角矩形的效果。 - 而且这种计算的效果就是图片随着其填充的图像缩放。
- 这就类似于是在
CanvasItem
的绘图函数基础上实现了矢量蒙版效果
基础原理
-
以上面的五角星为例,它的某个顶点P的UV坐标,应该如下计算:
顶点P的UV坐标 = 点P的坐标 五角星所在轴对齐包围盒Rect2的size 顶点\text{P}的\text{UV}坐标 = \frac{点\text{P}的坐标}{五角星所在轴对齐包围盒\text{Rect2}的\text{size} } 顶点P的UV坐标=五角星所在轴对齐包围盒Rect2的size点P的坐标 -
前提是:五角星
Rect2
的position
为(0,0)
-
这是一种类似自适应的填充形式,图片会随图形的缩放进行缩放,大小和位置始终与图形的包围盒
Rect2
一致 -
但是在其他情况下,我们或许需要实现一些复杂的填充效果,比如控制图片进行偏移、旋转、缩放等。这时,上面的UV计算方法就不顶用了。
此时,我们需要考虑图片本身和图形两者是独立的,然后考虑通过它们之间偏移关系去映射坐标位置。
测试
编写了一个基础的UI场景进行测试:
# ==========================================================
# UVtest
# 类型:测试
# 概述:实现基于绘图函数的矢量蒙版效果
# 巽星石
# 创建时间:2025年1月3日22:50:10
# 最后修改时间:2025年1月3日23:04:28
# ==========================================================
@tool
extends Control
@export var texture:Texture2D:
set(val):
texture = val
queue_redraw()
@export var texture_position:=Vector2(): ## 纹理的偏移
set(val):
texture_position = val
queue_redraw()
@export var texture_scale:=Vector2.ONE: ## 纹理缩放值
set(val):
texture_scale = val
queue_redraw()
@export_range(-360,360,1) var texture_rotation_degree:=0: ## 纹理旋转
set(val):
texture_rotation_degree = val
queue_redraw()
@export var fill_color:=Color.WHITE:
set(val):
fill_color = val
queue_redraw()
func _draw() -> void:
var rect = get_rect() * get_transform()
var pots = star(0,5,rect.size.y/2.0,rect.size.y/3.0,rect.get_center())
# 绘制背景
if texture:
var rot = deg_to_rad(texture_rotation_degree)
var image_rect = Rect2(texture_position,texture.get_size() * texture_scale)
var r:Vector2 = rect.size/image_rect.size # 比例
var UV.html" title=uv>uvs:PackedVector2Array
for pot in pots: # 计算UV坐标
# 进行旋转变换后的坐标
var p = (pot - rect.get_center()).rotated(-rot) + rect.get_center()
UV.html" title=uv>uvs.append(((p - texture_position)/rect.size) * r)
# 绘制圆角矩形
draw_colored_polygon(pots,fill_color,UV.html" title=uv>uvs,texture)
else:
draw_polygon(pots,[fill_color])
pass
# 星形
func star(start_angle:int,edges:int,r:float,r2:float = 0,offset:Vector2 = Vector2.ZERO):
if r2 == 0:
r2 = r/2.0
var points:PackedVector2Array
# 外部半径
var vec = Vector2.RIGHT.rotated(deg_to_rad(start_angle)) * r
# 内部半径
var vec2 = Vector2.RIGHT.rotated(deg_to_rad(start_angle + 180/edges)) * r2
for i in range(edges):
points.append(vec.rotated(2 * PI/edges * i) + offset)
points.append(vec2.rotated(2 * PI/edges * i) + offset)
return points
效果:
进行偏移、旋转和缩放后的效果:
提示
本例中暂时没有使用几何图形自身的Rect2
,而是采用了测试场景控件元素的Rect2
,所以带来的实际效果可能不太相同。
也就是说这还是一个未完成的实验版本。后续敬请期待。