如何应用着色器并仅生成图像一次?
我正在尝试将像素化着色器应用于我的纹理,并且我只需要将其应用一次,之后我可以一遍又一遍地重复使用我的着色器生成的图像作为纹理,而不必每次都进行计算。
那么我该如何拍摄一些图像 ->应用着色器并在每次游戏加载时仅渲染一次 ->并使用它们作为我的纹理?
到目前为止,我已经设法找到要应用的着色器:
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;
}
但我不知道如何使用它渲染图像
I'm trying to apply a pixelation shader to my textures and I need it to be applied only once, after that I can reuse my shader generated images as textures over and over without having to calculate every single time.
so how do I take a few images -> apply a shader and render them only once every time the game loads -> and use them as my textures?
so far I've managed to find the shader to apply:
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;
}
but I have no idea how to render out the images using it
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
着色器驻留在 GPU 中,它们的输出显示在屏幕上。为了保存图像,CPU 必须查看 GPU 输出,但这通常不会发生。而且由于不经过CPU,所以性能不错。 通常。好吧,至少比 CPU 一直这样做要好。
此外,您确定不想通过其他方式获得像素艺术外观吗?例如从纹理中删除过滤器,更改拉伸模式并在小分辨率下工作,也许还可以启用像素捕捉?不?观看如何为 Godot 中的像素艺术游戏制作丝般光滑的相机。仍然没有?好吧...
无论如何,对于你想要的东西,你将需要一个
Viewport
。视口设置
您需要创建一个
视口
。 不要忘记设置其大小
。还可能需要将 render_target_v_flip 设置为 true,这会垂直翻转图像。如果您发现输出图像颠倒,那是因为您需要切换render_target_v_flip
。然后将要渲染的内容放置为
Viewport
的子级。渲染
接下来,您可以从
视口
读取纹理,将其转换为图像,并将其保存为png。我在附加到Viewport
的工具脚本上执行此操作,因此我将有一个解决方法来从检查器面板触发代码。我的代码如下所示:当然,您可以
导出
一个FILE
路径String
以轻松在检查器面板中更改它。在这里,我将介绍常见的边缘情况:另一种选择是使用
ResourceSaver
:这仅适用于 Godot 编辑器,并且仅适用于 Godot,因为您获得了 Godot 资源文件。尽管我发现使用 Godot 生成图像的想法很有趣。如果您想为 Godot 自动生成它们,我建议使用
ResourceSaver
。关于从工具脚本保存资源
在上面的示例中,我假设您要保存到资源路径。这是因为目的是将输出图像用作Godot 中的资源。使用资源路径有几个含义:
我们可以处理
EditorPlugin
中的第二点,如果这就是你正在做的事情,你可以这样做来告诉 Godot 扫描更改:如果你不是,你可以通过创建一个空的
EditorPlugin
。我们的想法是这样做:顺便说一句,您将希望缓存
EditorPlugin
而不是每次都创建一个新的。或者更好的是,缓存从get_resource_filesystem
获取的EditorFileSystem
。自动化
现在,我意识到将东西放入
Viewport
中可能会很麻烦。如果您不需要一直这样做,那么这对于您的工作流程来说可能没问题。但是自动化呢?好吧,无论采用哪种方法,您都需要一个
tool
脚本来创建一个隐藏的Viewport
,采用一个Node
,检查它是否有着色器,如果是,则将其临时移动到Viewport
,获取渲染纹理(get_texture()
)将其设置为Node
的纹理>,删除着色器,并返回Node
到其在场景中的原始位置。 或者不要在节点中寻找着色器,而是始终将着色器应用于任何节点
,可能作为资源加载而不是硬编码。 >注意:我相信您需要在将
Node
添加到Viewport
和获取纹理之间传递一个空闲帧,以便纹理更新。 或者是两个空闲帧?好吧,如果一个不起作用,请尝试添加另一个。关于制作
EditorPlugin
如您所知,您可以从项目设置创建插件。这将为您创建一个
EditorPlugin
脚本。在那里,您可以将选项添加到工具菜单(使用add_tool_menu_item
),或将其添加到编辑器的工具栏(使用add_control_to_container
)。并让它作用于编辑场景中的当前选择(您可以使用get_selection
,或覆盖edit
和handles
方法)。 您可能还想为此创建一个撤消条目,请参阅get_undo_redo
。或者,您也可以让它跟踪(或查找)
Nodebuild
虚拟方法,该方法在项目即将运行时运行。 我没有使用过build
虚拟方法,所以我不知道它是否有任何需要注意的怪癖。Shaders reside in the GPU, and their output goes to the screen. To save the image, the CPU would have to see the GPU output, and that does not happen… Usually. And since it does not go through the CPU, the performance is good. Usually. Well, at least it is better than if the CPU was doing it all the time.
Also, are you sure you don't want to get a pixel art look by other means? Such as removing filter from the texture, changing the stretch mode and working on a small resolution, and perhaps enable pixel snap? No? Watch How to make a silky smooth camera for pixelart games in Godot. Still No? Ok...
Anyway, for what you want, you are going to need a
Viewport
.Viewport setup
What you will need is to create a
Viewport
. Don't forget to set itssize
. Also may want to setrender_target_v_flip
totrue
, this flips the image vertically. If you find the output image is upside down it is because you need to togglerender_target_v_flip
.Then place as child of the
Viewport
what you want to render.Rendering
Next, you can read the texture form the
Viewport
, convert it to an image, and save it to a png. I'm doing this on a tool script attached to theViewport
, so I'll have a workaround to trigger the code from the inspector panel. My code looks like this:You can, of course,
export
aFILE
pathString
to ease changing it in the inspector panel. Here I'm handing common edge cases:Another option is to use
ResourceSaver
:This will only work from the Godot editor, and will only work for Godot, since you get a Godot resource file. Although I find interesting the idea of using Godot to generate images. I'm going to suggest going with
ResourceSaver
if you want to automate generating them for Godot.About saving resources from tool scripts
In the examples above, I'm assuming you are saving to a resource path. This is because the intention is to use the output image as a resource in Godot. Using a resource path has a couple implications:
We can deal with the second point from an
EditorPlugin
, if that is what you are doing, you can do this to tell Godot to scan for changes:And if you are not, you can cheat by creating an empty
EditorPlugin
. The idea is to do this:By the way, you will want to cache cache the
EditorPlugin
instead of making a new one each time. Or better yet, cache theEditorFileSystem
you get fromget_resource_filesystem
.Automation
Now, I'm aware that it can be cumbersome to have to place things inside the
Viewport
. It might be Ok for your workflow if you don't need to do it all the time.But what about automating it? Well, regardless of the approach, you will need a
tool
script that makes a hiddenViewport
, takes aNode
, checks if it has a shader, if it does, it moves it temporarily to theViewport
, get the rendered texture (get_texture()
) sets it as the texture of theNode
, removes the shader, and returns theNode
to its original position in the scene. Or instead of looking for a shader in the Node, always apply a shader to whateverNode
, perhaps loaded as a resource instead of hard-coded.Note: I believe you need to let an idle frame pass between adding the
Node
to theViewport
and getting the texture, so the texture updates. Or was it two idle frames? Well, if one does not work, try adding another one.About making an
EditorPlugin
As you know, you can create an addon from project settings. This will create an
EditorPlugin
script for you. There you can either add an option to the tools menu (withadd_tool_menu_item
), or add it to the tool bar of the editor (withadd_control_to_container
). And have it act on the current selection in the edited scene (you can either useget_selection
, or overwrite theedit
andhandles
methods). You may also want to make an undo entry for that, seeget_undo_redo
.Or, alternatively you can have it keep track (or look for) the
Node
s it has to act upon, and then work on thebuild
virtual method, which runs when the project is about to run. I haven't worked with thebuild
virtual method, so I don't know if it has any quirks to gotchas to be aware of.