【问题标题】:Godot repeating breaks scriptGodot 重复中断脚本
【发布时间】:2021-05-05 14:46:21
【问题描述】:

我正在 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

图片:

但是,我有一个问题。我在准备函数中有代码,在一个 for 循环中。我希望每帧都调用它,但是当我将重复次数从 1 增加到 2 时,它会将整个图像变成红色。我不知道这是什么原因造成的。一种猜测是我没有正确锁定和解锁图像,但很可能并非如此。另一个猜测是 x 和 y 变量不是每次都重置,但这也很好。我不认为循环本身是问题,但我不知道出了什么问题。

【问题讨论】:

    标签: loops godot gdscript


    【解决方案1】:

    我努力让您的代码运行。我半途而废,并使用锁定位实现了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 上有一个注释行,它做了一个轮换,试试看。

    samplerImageTextureSprite 的副本(副本在_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)
    

    但是,正如我所说,没有方便的矩阵类型。如果我们导出abcd,我们有:

    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)
    

    我们可以轻松地使用修改代码来做到这一点。先导出abcd,就像我说的:

    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

    我不知道如何解释abcd,所以这里是a = 1b = 2c = 3d = 4

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-23
      • 2012-08-11
      • 2021-06-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多