我努力让您的代码运行。我半途而废,并使用锁定位实现了my prior answer 的逻辑。这是代码:
extends Sprite
export(Transform) var matrix:Transform
var sampler:Image
var buffer:Image
var size:Vector2
var center:Vector2
func _ready():
sampler = texture.get_data()
var err = sampler.decompress()
if err != OK:
push_error("Failed to decompress texture")
return
size = Vector2(texture.get_width(), texture.get_height())
center = size * 0.5
buffer = Image.new()
buffer.create(int(size.x), int(size.y), false, Image.FORMAT_RGBA8)
func _process(_delta):
#matrix = matrix.rotated(Vector3.RIGHT, 0.01)
sampler.lock()
buffer.lock()
for y in size.x:
for x in size.y:
var uv:Vector3 = matrix * Vector3(x - center.x, y - center.y, 1.0)
if uv.z <= 0.0:
buffer.set_pixel(x, y, Color.transparent)
continue
var _x = (uv.x / uv.z) + center.x
var _y = (uv.y / uv.z) + center.y
if _x < 0.0 or _x >= size.x or _y < 0.0 or _y >= size.y:
buffer.set_pixel(x, y, Color.transparent)
continue
#buffer.set_pixel(x, y, Color(_x / size.x, y / size.y, 0.0))
buffer.set_pixel(x, y, sampler.get_pixel(_x, _y))
buffer.unlock()
sampler.unlock()
var display = ImageTexture.new()
display.create_from_image(buffer, 0)
self.texture = display
如您所见,我正在导出 Transfrom 以在编辑器上可用。那是一个适当的 3D 变换。 _process 上有一个注释行,它做了一个轮换,试试看。
samplerImage 是Texture 的Sprite 的副本(副本在_ready 上制作)。 buffer Image 是要显示的内容的构造位置。
代码从buffer 创建一个ImageTexture,并用它替换当前的texture,每一帧(在_process 上)。我将标志设置为0,因为FLAG_REPEAT 加上FLAG_FILTER 模糊了Sprite 对面的边界。
向量Vector2 size 保存纹理的大小。而Vector2Center是中心的坐标。
正如我一开始所说,这是我之前回答的逻辑。这一行:
vec3 uv = matrix * vec3(UV - 0.5, 1.0);
相当于(除了我没有将坐标缩放到 0 到 1 的范围):
var uv:Vector3 = matrix * Vector3(x - center.x, y - center.y, 1.0)
然后我有这行:
if (uv.z < 0.0) discard;
结果是这样的:
if uv.z <= 0.0:
buffer.set_pixel(x, y, Color.transparent)
continue
我设置透明是因为我没有重新创建缓冲区,也没有事先清除它。
最后一行:
COLOR = texture(TEXTURE, (uv.xy / uv.z) + 0.5);
原来是这样的:
var _x = (uv.x / uv.z) + center.x
var _y = (uv.y / uv.z) + center.y
if _x < 0.0 or _x >= size.x or _y < 0.0 or _y >= size.y:
buffer.set_pixel(x, y, Color.transparent)
continue
buffer.set_pixel(x, y, sampler.get_pixel(_x, _y))
根据结果,这里是“以 3D 旋转”的 Godot 图标(不是真的,但这就是想法):
由于 GIF 编码,请忽略视觉伪影。
我不确定你是否想保持我之前回答的逻辑。但是,我相信这应该不会太难根据您的需要进行修改。
附录
我使用了 Transform,因为没有方便的 Matrix 类型可用。但是,Transform 在内部使用 Matrix。另见Transformation matrix。
Mode 7 formula according to Wikipedia 与 2 x 2 矩阵一起使用,这比我这里的更简单。但是,无论如何,您将需要 Matrix 和 Vector 的乘积。您不能独立计算组件。
这是根据维基百科的公式:
r' = M*(r - r_0) + r_0
即:
var rp = mult(M, r - r_0) + r_0
mult 看起来像这样:
func mult(matrix, vector:Vector2) -> Vector2:
var x = vector.x * matrix.a + vector.y * matrix.b
var y = vector.x * matrix.c + vector.y * matrix.d
return Vector2(x, y)
但是,正如我所说,没有方便的矩阵类型。如果我们导出a、b、c和d,我们有:
var rp = mult(a, b, c, d, r - r_0) + r_0
而mult 看起来像这样:
func mult(a:float, b:float, c:float, d:float, vector:Vector2) -> Vector2:
var x = vector.x * a + vector.y * b
var y = vector.x * c + vector.y * d
return Vector2(x, y)
我们可以轻松地使用修改代码来做到这一点。先导出a、b、c和d,就像我说的:
export(float) var a:float
export(float) var b:float
export(float) var c:float
export(float) var d:float
这是 _process 已修改:
func _process(_delta):
sampler.lock()
buffer.lock()
for y in size.x:
for x in size.y:
var rp = mult(a, b, c, d, Vector2(x, y) - center) + center
if rp.x < 0.0 or rp.x >= size.x or rp.y < 0.0 or rp.y >= size.y:
buffer.set_pixel(x, y, Color.transparent)
continue
buffer.set_pixel(x, y, sampler.get_pixel(rp.x, rp.y))
buffer.unlock()
sampler.unlock()
var display = ImageTexture.new()
display.create_from_image(buffer, 6)
self.texture = display
当然,mult 是我上面展示的那个。 我在这里假设r_0 就是我所说的center。
我不知道如何解释a、b、c和d,所以这里是a = 1、b = 2、c = 3和d = 4: