微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

简单模式 7 公式/示例?

如何解决简单模式 7 公式/示例?

我最近发现了使用 Snes 模式 7 的伪 3d 效果,并想尝试在 Godot 引擎中复制它。我尝试在网上环顾四周,但所有内容要么以我无法理解的方式解释,要么以我不知道的编程语言进行解释。我还需要学习如何旋转区域,并将精灵作为角色或敌人放入,但我没有在这些上找到任何东西。有人可以解释这个公式,以及我如何实现它吗?

解决方法

好的,我想通了。我将解释两种设置。

在我们开始之前,让我解释一下我们将使用的着色器代码:

shader_type canvas_item;
uniform mat3 matrix;

void fragment()
{
    vec3 uv = matrix * vec3(UV,1.0);
    COLOR = texture(TEXTURE,uv.xy / uv.z);
}

这是一个 canvas_item 着色器,因此它旨在用于 2D。我们正在做的是将变换矩阵(作为 uniform 传递)应用于纹理坐标(UV)。我们将结果存储在 uv 变量中。我们将使用它来对使用此着色器的任何节点的纹理进行采样……但是我们需要使用 zuv 来实现透视效果。为此,我们将 uv.xy 除以 uv.z

但是,我想将它应用到纹理的中心。所以,让我在开头减去 0.5,然后在最后加上 0.5

shader_type canvas_item;
uniform mat3 matrix;

void fragment()
{
    vec3 uv = matrix * vec3(UV - 0.5,(uv.xy / uv.z) + 0.5);
}

还有一件事。我不喜欢在极端值上我们看到反转的图像。因此,我会这样处理:

shader_type canvas_item;
uniform mat3 matrix;

void fragment()
{
    vec3 uv = matrix * vec3(UV - 0.5,1.0);
    if (uv.z < 0.0) discard;
    COLOR = texture(TEXTURE,(uv.xy / uv.z) + 0.5);
}

这里有一个给无分支爱好者的替代方案(不知道是不是更好):

shader_type canvas_item;
uniform mat3 matrix;

void fragment()
{
    vec3 uv = matrix * vec3(UV - 0.5,(uv.xy / uv.z) + 0.5);
    COLOR.a *= sign(sign(uv.z) + 1.0);
}

此处的 sign(uv.z) 将是 -1.00.01.0

然后 sign(uv.z) + 1.0 将是 0.01.02.0

最后 sign(sign(uv.z) + 1.0) 将是 0.01.0(如果您愿意,可以改用 clamp(sign(uv.z),0.0,1.0))。因此,COLOR.a *= sign(sign(uv.z) + 1.0)0.0 为负的任何地方都将 alpha 乘以 uv.z


注意:我在片段着色器中操作 UV 坐标而不是在顶点着色器中操作的原因是因为 Godot 正在为 2D 做仿射纹理映射。这会导致失真。这是一种解决方法。


第一个设置只是一个精灵。使用您想要的任何纹理设置 Sprite,并将材质设置为新的着色器材质,并在着色器中使用我在开始时显示的代码。

Godot 将为您提供编辑材料资源中 uniform mat3 matrix 下的 Shader Param 的选项。默认情况下,它将是单位矩阵,在编辑器中看起来像这样:

x 1  y 0  z 0
x 0  y 1  z 0
x 0  y 0  z 1

您可以使用它来应用旋转、缩放、剪切或透视变换。 *我建议从改变z列(最右边的)的零开始,控制透视:

x 1  y 0  z 3d_rotate_horizontal
x 0  y 1  z 3d_rotate_vertical
x 0  y 0  z scale

示例结果:

Robot with no effect and Robot with perspective effect

建议:不要使用一直延伸到边缘的纹理。当您应用透视时,着色器将读取超出边缘的内容,但默认它被钳制,这会导致拉伸纹理边缘的任何像素。

顺便说一句,如果您将图像导入为 Image(而不是默认的 Texture),您可以将 Sprite 纹理设置为 ImageTexture,这将为您提供一些额外的控制关于纹理的显示方式,包括启用 mipmap、抗锯齿过滤器以及在其边缘之外重复纹理(镜像和非镜像)。


第二个更复杂的设置是针对多个对象。这也是适用于 TileMap 的设置。您将需要这种树结构:

- Sprite2D
  +- Viewport
     +- Camera2D
     +- target

Sprite2D 放在我们想要看到的位置,使用我在开始时显示的着色器代码为其提供着色器材质。 顺便说一句,这也应该与 TextureRect 一起使用,以防您在 UI 中需要它。

不要为 Sprite2D(或 TextureRect)设置纹理。您将附加一个如下所示的脚本:

extends Sprite

func _ready():
    var viewport = $Viewport
    yield(get_tree(),"idle_frame")
    yield(get_tree(),"idle_frame")
    texture = viewport.get_texture()

如果需要,将 Sprite 更改为 TextureRect

此代码引用 Viewport 节点,等待两帧(以确保 Viewport 纹理可用),然后获取纹理并将其分配给自身。

您需要为视口设置您想要的大小。另外我建议设置Transparent BgV FlipCamera2D 可以保留其默认值。

最后,“目标”是您想要显示的任何内容。它可以是一个或多个二维节点。我建议将其设为另一个场景,这样就可以轻松地独立于此设置对其进行编辑(Viewport 的任何子项在编辑器中都将不可见)。

示例结果:

TileMap with perspective effect and Robot ontop with no effect

是的,我们可以在 Godot 中使用实际 3D 存档相同的效果,没问题。但我们没有。我们选择使用 2D 工具实现这种效果并做其他事情,不是因为它们容易,而是因为它们很难。


此答案中使用的纹理属于公共领域 (CC0),来自 Kenney

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。