如何应用着色器并仅生成图像一次?

2024-05-05

我正在尝试将像素化着色器应用于我的纹理,并且我只需要将其应用一次,之后我可以一遍又一遍地重复使用我的着色器生成的图像作为纹理,而不必每次都进行计算。

那么我如何拍摄一些图像 -> 应用着色器并在每次游戏加载时仅渲染它们一次 -> 并将它们用作我的纹理?

到目前为止,我已经成功找到要应用的着色器:

shader_type canvas_item;

uniform int amount = 40;

void fragment()
{
    vec2 grid_uv = round(UV * float(amount)) / float(amount);
    
    vec4 text = texture(TEXTURE, grid_uv);
    
    COLOR = text;
}

但我不知道如何使用它渲染图像


着色器驻留在 GPU 中,它们的输出显示在屏幕上。为了保存图像,CPU 必须查看 GPU 输出,但这通常不会发生。而且由于不经过CPU,所以性能很好。通常。好吧,至少比 CPU 一直这样做要好。

另外,您确定不想通过其他方式获得像素艺术外观吗?例如从纹理中删除过滤器,更改拉伸模式并在小分辨率下工作,也许还可以启用像素捕捉?不?手表如何在 Godot 中为像素艺术游戏制作丝般光滑的相机 https://www.youtube.com/watch?v=zxVQsi9wnw8。仍然没有?好的...

不管怎样,为了你想要的,你需要一个Viewport.


视口设置

你需要的是创建一个Viewport. 不要忘记设置它size。还可能想设置render_target_v_flip to true,这会垂直翻转图像。如果你发现输出图像是颠倒的这是因为你需要切换render_target_v_flip.

然后放置为Viewport你想要渲染什么。


渲染

接下来,您可以从Viewport,将其转换为图像,并将其保存为 png。我正在使用附加到的工具脚本执行此操作Viewport,所以我将有一个解决方法来从检查器面板触发代码。我的代码如下所示:

tool
extends Viewport

export var save:bool setget do_save

func do_save(new_value) -> void:
    var image := get_texture().get_data()
    var error := image.save_png("res://output.png")
    if error != OK:
        push_error("failed to save output image.")

当然,你可以export a FILE path String以便在检查器面板中轻松更改它。我在这里给出常见的边缘情况:

tool
extends Viewport

export(String, FILE) var path:String
export var save:bool setget do_save

func do_save(_new_value) -> void:
    var target_path := path.strip_edges()
    var folder := target_path.get_base_dir()
    var file_name := target_path.get_file()
    var extension := target_path.get_extension()
    if file_name == "":
        push_error("empty file name.")
        return

    if not (Directory.new()).dir_exists(folder):
        push_error("output folder does not exist.")
        return

    if extension != "png":
        target_path += "png" if target_path.ends_with(".") else ".png"

    var image := get_texture().get_data()
    var error := image.save_png(target_path)
    if error != OK:
        push_error("failed to save output image.")
        return

    print("image saved to ", target_path)

另一种选择是使用ResourceSaver:

tool
extends Viewport

export var save:bool setget do_save

func do_save(new_value) -> void:
    var image := get_texture().get_data()
    var error := ResourceSaver.save("res://image.res", image)
    if error != OK:
        push_error("failed to save output image.")

这仅适用于 Godot 编辑器,并且仅适用于 Godot,因为您获得了 Godot 资源文件。尽管我发现使用 Godot 生成图像的想法很有趣。我建议去ResourceSaver如果你想为 Godot 自动生成它们。


关于从工具脚本保存资源

在上面的示例中,我假设您正在保存到资源路径。这是因为目的是将输出图像用作Godot 中的资源。使用资源路径有几个含义:

  1. 这可能不适用于导出的游戏(因为目标是改进工作流程,所以这是可以的)。
  2. Godot 需要重新导入资源,但不会注意到它发生了变化。

我们可以处理第二点EditorPlugin,如果这就是你正在做的事情,你可以这样做来告诉 Godot 扫描更改:

get_editor_interface().get_resource_filesystem().scan()

如果你不是,你可以通过创建一个空的来作弊EditorPlugin。我们的想法是这样做:

var ep = EditorPlugin.new()
ep.get_editor_interface().get_resource_filesystem().scan()
ep.free()

顺便说一下,你会想要缓存EditorPlugin而不是每次都制作一个新的。或者更好的是,缓存EditorFileSystem你从get_resource_filesystem.


自动化

现在,我意识到必须将东西放在里面可能很麻烦Viewport。如果您不需要一直这样做,那么这对于您的工作流程来说可能没问题。

但是自动化呢?好吧,无论采用哪种方法,您都需要一个tool隐藏的脚本Viewport,需要一个Node,检查它是否有着色器,如果有,则将其暂时移动到Viewport,获取渲染纹理(get_texture())将其设置为纹理Node,删除着色器,并返回Node到其在场景中的原始位置。或者不是在中寻找着色器Node,始终将着色器应用于任何内容Node,也许作为资源加载而不是硬编码。

Note:我相信你需要在添加之间让一个空闲帧通过Node to the Viewport并获取纹理,以便纹理更新。或者是两个空闲帧?好吧,如果其中一个不起作用,请尝试添加另一个。


关于制作一个EditorPlugin

如您所知,您可以从项目设置创建插件。这将创建一个EditorPlugin给你的脚本。在那里,您可以向工具菜单添加一个选项(使用add_tool_menu_item),或者将其添加到编辑器的工具栏(使用add_control_to_container)。并让它作用于编辑场景中的当前选择(您可以使用get_selection,或覆盖edit and handles方法)。您可能还想为此创建一个撤消条目,请参阅get_undo_redo.

或者,您也可以让它跟踪(或查找)Node它必须采取行动,然后致力于build虚拟方法,当项目即将运行时运行。我没有与build虚拟方法,所以我不知道它是否有任何需要注意的怪癖。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何应用着色器并仅生成图像一次? 的相关文章

  • 【Godot】对 Godot 节点设计的思考

    对 Godot 中节点设计的思考 单个节点的功能设计的想法 xff0c 体会 Godot 的设计思想 低耦合 设计单个节点可复用的节点时 xff0c 调用方法尽量只对当前节点可获取到的变量或方法进行使用 xff0c 比如我写一个可以控制 K
  • 【Godot】行为树(一)了解与设计行为树代码

    行为树介绍 行为树是个节点树 xff0c 父节点通过不断遍历子节点 xff0c 根据不同类型的节点执行不同的分支 最终调用叶节点执行功能 行为树也不难理解 xff0c 他就像代码逻辑一样 xff0c 只是用节点的方式展现出来 xff0c 而
  • 【Godot 4.0】一个简单的匿名方法的使用lambda

    Godot 4 0 beta3 Godot 4 0 中添加了 lambda 表达式 xff0c 匿名方法等很多方便的特性 xff0c 这里我写个用于扫描目录下所有文件的功能 可以看到代码非常简洁 span class token keywo
  • Godot Engine:GDScript 4.X中语法的变化(2020年8月4日 更新)

    文章目录 4 X版 GDScript范例支持注解属性 xff08 Properties xff09 的定义格式await关键字代替yield加入super关键字去除了多级调用问题小结 4 X版 GDScript范例 支持注解 从4 x开始
  • Godot 4 应用 - 图形绘制

    花了两天时间 做了一个初步的图形软件效果 先占个坑 以后再叙
  • 关于在windows使用msys2 + mingw + gcc/g++ 编译godot的笔记

    关于在windows使用msys2 mingw gcc g 编译godot的笔记 编译参数 1 target release debug release debug 2 多线程参数 j数字 3 profile是自定义构建参数 可以启用或者禁
  • 如何创建没有 setter 函数的 getter 函数?

    我的脚本中有多个导出的变量 每当更改一个变量时 我想调用一个通用的 getter 并让值自动设置 tool export float var sample1 setget smthn changed export float var sam
  • 如何检测 Godot 中的碰撞?

    我有3个场景 一个名为 KinematicBody2D tscn 的 KinematicBody2D 节点 该场景是一个玩家在屏幕上从左向右移动 我还有一个名为 mob tscn 的场景 它是一个igidbody2d节点 这个场景只有精灵和
  • 在 godot 游戏引擎中使用不同的编程语言?

    我想要将不同的编程语言绑定到 Godot 游戏引擎 有关于这个主题的指导文件或视频吗 例如 这个项目是如何完成的 戈多锈 https github com godot rust godot rust 如果我能学习基础知识 我就能成功地用不同
  • 安卓:应用程序未安装

    这里是新手 我用Godot游戏引擎制作了我的第一个游戏并成功导出到android 复制到我的手机上 它安装并运行良好 几个小时后 我做了一些更改并再次导出 再次复制了 apk 但现在当我尝试安装它时 它没有完成安装 我多次尝试更改导出设置
  • 如何获取另一个场景godot中的节点?

    我正在制作一个具有多个场景的游戏 需要有 get node 来自另一个场景的节点 变量 并且我不知道如何从另一个场景获取节点 如果我理解正确的话 您想连接到来自另一个场景中的节点的信号 直接方法会起作用 const bullet prelo
  • 如何在 Godot 中将字符串转换为枚举?

    使用 Godot 3 4 我的枚举设置为 enum STRENGTH DEXTERITY CONSTITUTION INTELLIGENCE WISDOM CHARISMA 我希望能够使字符串 STRENGTH 返回枚举值 0 我希望下面的
  • 如何在戈多中使刚体跳跃而不赋予其飞行能力

    我本来会使用运动体 但我想将现实生活中的物理添加到我的 2d 对象中 但似乎我可以通过多次按向上键来飞行 extends RigidBody2D var velocity Vector2 ZERO const GRAVITY 35 cons
  • Godot:调用外部方法

    经过大量谷歌搜索 我仍然不明白什么可能是一个简单的解决方案 场景 主要 包含一个 TileMap Grid 并附有一个脚本 Grid gd 场景 玩家 包含一个 KinematicBody2D Player 及其附加脚本 Player gd
  • 如何克服 Godot 将按钮字体更改为默认颜色的问题?

    我正在使用 Godot 4 我在容器中手动创建了很多按钮 我在主场景中设置了一个颜色变量 tempcol 当我单击带有 tempcol 设置的按钮时 比如 Color Red 按钮的字体颜色更改为白色 似乎是默认字体颜色 但是当我单击另一个
  • 传递Physics2DShapeQueryParameters 层进行检查

    我目前正在为我的 2D 自上而下游戏开发一个构建系统 最后一步是检查是否有任何物体 例如树或玩家 阻碍了物品的放置 经过一些研究后 我发现使用Physics2DShapeQueryParameters 是正确的方法 我唯一的问题是我不知道如
  • 同一节点的碰撞检测和重叠检测? [第2部分]

    的延续上一个问题 https stackoverflow com questions 71608423 collision detection and overlapping detection in same node 71622366
  • 关闭 Godot 中的游戏

    我正在使用 Godot 创建网页游戏 为了关闭游戏 我尝试使用 get tree quit 如果我在 IDE 上使用它 它就可以工作 当我在我的服务器上尝试它时 导出项目后 它不起作用 我确信导出设置没问题 我怎样才能关闭游戏 并且 如何添
  • 简单模式7公式/例子?

    我最近发现了利用 SNES 模式 7 的伪 3D 效果 并想尝试在 Godot 引擎中复制它 我尝试在网上查找 但所有内容要么以我无法理解的方式解释 要么以我不知道的编程语言解释 我还需要学习如何旋转该区域 并将精灵作为角色或敌人放入 但我
  • Godot:检测 Area2D 内部的“鼠标按下”和 Area2D 外部的“鼠标向上”

    我想检测 Area2D 内部的鼠标单击 并按住 然后检测 Area2D 内部或外部的鼠标释放 这是我到目前为止所拥有的 extends Area2D PickArea func input event viewport event shap

随机推荐