概述
在設計圓角容器時突發奇想:
- 將圓角矩形的每個頂點坐標除以對應圓角矩形所在
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 = valqueue_redraw()@export var texture_position:=Vector2(): ## 紋理的偏移set(val):texture_position = valqueue_redraw()@export var texture_scale:=Vector2.ONE: ## 紋理縮放值set(val):texture_scale = valqueue_redraw()@export_range(-360,360,1) var texture_rotation_degree:=0: ## 紋理旋轉set(val):texture_rotation_degree = valqueue_redraw()@export var fill_color:=Color.WHITE:set(val):fill_color = valqueue_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 uvs:PackedVector2Arrayfor pot in pots: # 計算UV坐標# 進行旋轉變換后的坐標var p = (pot - rect.get_center()).rotated(-rot) + rect.get_center()uvs.append(((p - texture_position)/rect.size) * r)# 繪制圓角矩形draw_colored_polygon(pots,fill_color,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.0var 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)) * r2for 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
,所以帶來的實際效果可能不太相同。
也就是說這還是一個未完成的實驗版本。后續敬請期待。