Godot 重复中断脚本
Godot repeating breaks script
我正在 Godot 中制作模式 7/透视投影项目。当我 运行 它时,它会产生预期的效果,将 2d 图像显示为 3d 平面。
代码:
func _ready():
map.load("res://map2.png")
perspective.load("res://map2.png")
for px in 1:
self.texture = display
for y in map.get_height():
_y = (y + py - 1)/z
for x in map.get_width():
_x = (x + px)/z
map.lock()
pix = map.get_pixel(_x, _y)
map.unlock()
perspective.lock()
perspective.set_pixel(x, y, pix)
perspective.unlock()
display.create_from_image(perspective)
z += 1
图片:
但是,我有一个问题。我在 ready 函数中有代码,在 for 循环中。我希望每一帧都调用它,但是当我将重复次数从一增加到两次时,它会将整个图像变成红色。我不知道是什么原因造成的。一种猜测是我没有正确锁定和解锁图像,但情况很可能并非如此。另一个猜测是 x 和 y 变量不是每次都重置,但也可以正常工作。我不认为循环本身是问题,但我不知道哪里出了问题。
我努力编写你的代码 运行。我中途放弃了,转而使用锁定位实现了 中的逻辑。这是代码:
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
上有注释行是做旋转的,试试看。
sampler
Image
是 Sprite
的 Texture
的副本(副本是在 _ready
上制作的)。而 buffer
Image
是构建要显示的内容的地方。
代码正在从 buffer
创建一个 ImageTexture
并用它替换当前的 texture
,每一帧(在 _process
上)。我将标志设置为 0
,因为 FLAG_REPEAT
加 FLAG_FILTER
模糊了 Sprite
.
对面的边界
矢量Vector2
size
保存纹理的大小。而Vector2
Center
就是圆心的坐标。
正如我一开始所说,这是我之前回答的逻辑。这一行:
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 类型可用。但是,转换在内部使用矩阵。另见 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
:
我正在 Godot 中制作模式 7/透视投影项目。当我 运行 它时,它会产生预期的效果,将 2d 图像显示为 3d 平面。 代码:
func _ready():
map.load("res://map2.png")
perspective.load("res://map2.png")
for px in 1:
self.texture = display
for y in map.get_height():
_y = (y + py - 1)/z
for x in map.get_width():
_x = (x + px)/z
map.lock()
pix = map.get_pixel(_x, _y)
map.unlock()
perspective.lock()
perspective.set_pixel(x, y, pix)
perspective.unlock()
display.create_from_image(perspective)
z += 1
图片:
但是,我有一个问题。我在 ready 函数中有代码,在 for 循环中。我希望每一帧都调用它,但是当我将重复次数从一增加到两次时,它会将整个图像变成红色。我不知道是什么原因造成的。一种猜测是我没有正确锁定和解锁图像,但情况很可能并非如此。另一个猜测是 x 和 y 变量不是每次都重置,但也可以正常工作。我不认为循环本身是问题,但我不知道哪里出了问题。
我努力编写你的代码 运行。我中途放弃了,转而使用锁定位实现了
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
上有注释行是做旋转的,试试看。
sampler
Image
是 Sprite
的 Texture
的副本(副本是在 _ready
上制作的)。而 buffer
Image
是构建要显示的内容的地方。
代码正在从 buffer
创建一个 ImageTexture
并用它替换当前的 texture
,每一帧(在 _process
上)。我将标志设置为 0
,因为 FLAG_REPEAT
加 FLAG_FILTER
模糊了 Sprite
.
矢量Vector2
size
保存纹理的大小。而Vector2
Center
就是圆心的坐标。
正如我一开始所说,这是我之前回答的逻辑。这一行:
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 类型可用。但是,转换在内部使用矩阵。另见 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
: