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

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 Engine:GDScript 4.X中语法的变化(2020年8月4日 更新)

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

    花了两天时间 做了一个初步的图形软件效果 先占个坑 以后再叙
  • Godot 4 源码分析 - 文件读入编码处理

    今天需要读入xml文件进行处理 结果读入一个带中文的文件时 出错了 当然程序还能运行 但编译器一直报错 而且XML解析也不正确 单步调试发现读入的内容出现乱码 具体逻辑 String FileAccess get as text bool
  • 关于在windows使用msys2 + mingw + gcc/g++ 编译godot的笔记

    关于在windows使用msys2 mingw gcc g 编译godot的笔记 编译参数 1 target release debug release debug 2 多线程参数 j数字 3 profile是自定义构建参数 可以启用或者禁
  • 戈多3.2.1。刷新查询时无法更改此状态。使用 call_deferred() 或 set_deferred() 来更改监控状态

    在我的 2D 游戏中 玩家能够摧毁箱子 具有两种碰撞形状的物体 当被摧毁时 板条箱会产生也具有碰撞形状的物品 但是当调用以下函数时 Godot控制台中会显示许多类似的错误 Code func on Crate item dropped co
  • 合并多个精灵节点?

    例如 假设我有 2 个精灵节点 但也可以超过 2 个 如下所示 每个人都有自己独立的图像我想要的是将它们组合起来并用单个图像创建一个新的精灵节点 在工具模式下 like this 也许可以通过使用Image 毫无疑问涉及计算 或者也许使用一
  • (Godot 引擎)用 Tilemap 瓷砖填充 2D 多边形

    我在 Godot 引擎中遇到一个无法解决的问题 怎么可能 在代码中 用图块填充 Polygon2D 区域 我尝试过获得点位置 使用 2D for 循环遍历线的顶点 但我无法理解这一点 这是我期待的结果的模型 我有解决方案 有一点 hacky
  • 在 Area2D 中覆盖 KinematicBody2D 运动?

    I m trying to create a windy area within which the player would be pushed continuously to the left lt 到目前为止 这就是我想出的Windy
  • 如何在Godot 4.0游戏引擎中实现可组合的角色/技能系统?

    我目前正在使用 Godot 尝试 MOBA 风格游戏的原型 我正在努力寻找一种管理角色及其技能的方法 所有角色都将具有相似的属性 姓名 生命值 奔跑速度 力量等 然而 所有角色的技能都会有所不同 尽管有些角色非常相似 例如基于投射物的技能将
  • Godot 监听来自同一场景的多个实例的信号

    我有以下场景 玩家 敌人 攻击 当攻击与敌人发生碰撞时 敌人会发出 onHit 信号 播放器监听该信号并反弹 这一切都运行良好 但现在如果我复制敌人 因此有多个敌人场景 我如何收听所有敌人的信号 有没有办法获取场景的所有实例并连接到它们的所
  • 在 godot 游戏引擎中使用不同的编程语言?

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

    这里是新手 我用Godot游戏引擎制作了我的第一个游戏并成功导出到android 复制到我的手机上 它安装并运行良好 几个小时后 我做了一些更改并再次导出 再次复制了 apk 但现在当我尝试安装它时 它没有完成安装 我多次尝试更改导出设置
  • 如何在 Godot 中将字符串转换为枚举?

    使用 Godot 3 4 我的枚举设置为 enum STRENGTH DEXTERITY CONSTITUTION INTELLIGENCE WISDOM CHARISMA 我希望能够使字符串 STRENGTH 返回枚举值 0 我希望下面的
  • Godot:调用外部方法

    经过大量谷歌搜索 我仍然不明白什么可能是一个简单的解决方案 场景 主要 包含一个 TileMap Grid 并附有一个脚本 Grid gd 场景 玩家 包含一个 KinematicBody2D Player 及其附加脚本 Player gd
  • 传递Physics2DShapeQueryParameters 层进行检查

    我目前正在为我的 2D 自上而下游戏开发一个构建系统 最后一步是检查是否有任何物体 例如树或玩家 阻碍了物品的放置 经过一些研究后 我发现使用Physics2DShapeQueryParameters 是正确的方法 我唯一的问题是我不知道如
  • 如何应用着色器并仅生成图像一次?

    我正在尝试将像素化着色器应用于我的纹理 并且我只需要将其应用一次 之后我可以一遍又一遍地重复使用我的着色器生成的图像作为纹理 而不必每次都进行计算 那么我如何拍摄一些图像 gt 应用着色器并在每次游戏加载时仅渲染它们一次 gt 并将它们用作
  • 关闭 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

随机推荐