Is there a way not to have the shader editor open every time a shader is created ?

Godot Version

4.6

Question

I’m making a system that programmatically generates shaders by editing their code String.

I click on an @export_tool_button, a shader code String is generated. It is then applied to a Material

var code : String = generate_shader_through_magic()

if !(material_override is ShaderMaterial):
	material_override = ShaderMaterial.new()
if material_override.shader == null:
	material_override.shader = Shader.new()
material_override.shader.code = code

# Idk if that's needed, trying to find out
material_override.emit_changed()
material_override.shader.emit_changed()

I’ve noticed 2 things :

  • Whenever I generate a new shader like this, the shader editor automatically opens the new shader

  • When I try to edit my shader through code by clicking the @export_tool_button again, the shader doesn’t get updated if it’s open in the shader editor (may be a bug), I need to close it first and then try to generate the shader code

This means that I constantly get cock-blocked by the shader editor as I’m trying to test my shader because every time between 2 generations I need to manually close the shader in the editor.

It’s useful to be able to read the resulting shader to see what my code outputed and debug, but it’s annoying to have to constantly close the editor that I generally won’t use.

Is there a way not to have the shader editor open every time a shader is created ?

Or

Is there a way to programmatically edit the code of a shader while it’s open in the shader editor ?

If it were me, I’d just look for a way to programmatically close the shader in the editor after it opens.

The other two are definitely possible if you’re willing to roll your own version of Godot.

Can you post a minimal reproduction example?

1 Like

How ? The godot forums won’t let me attach a folder or a zip to my message. It looks like the only supported formats are image and video files

The important thing is - minimal. Can you reproduce it with a single tool script and post the script?

@tool
class_name ShaderGenerator
extends MeshInstance3D

@export var color : Color
@export_tool_button("Generate", "Shader") var generate = _generate

func generate_shader_through_magic() -> String:
	return "shader_type spatial;
render_mode unshaded;

const vec4 color = vec4"+str(color)+";

void fragment()
{
	ALBEDO = color.rgb;
	ALPHA = color.a;
}"

func _generate():
	var code : String = generate_shader_through_magic()
	
	if !(material_override is ShaderMaterial):
		material_override = ShaderMaterial.new()
	if material_override.shader == null:
		material_override.shader = Shader.new()
	material_override.shader.code = code
	
	# Idk if that's needed
	material_override.emit_changed()
	material_override.shader.emit_changed()

Add this script to a MeshInstance3D. Generate a shader with the button. For some reason you will have to reload the project for the shader to apply*

When you generate the shader, it will be opened in the shader editor. Change the color and generate again, the color won’t change on the model, UNLESS you closed the shader editor first.

*and again if you deleted the “shader” property of your material, basically whenever the Shader.new() gets called it’s a new project reset (but that’s not too bad since you don’t create a new shader often)

It doesn’t open the shader editor for me.

In any case, assign the complete material to material_override property, with the shader and its code already assigned to the material object. This will trigger the actual shader compilation and update.

func _generate():
	var code: String = generate_shader_through_magic()
	var material = ShaderMaterial.new()
	material.shader = Shader.new()
	material.shader.code = code
	material_override = material

You also might want to linearize your color value:

const vec4 color = vec4" + str(color.srgb_to_linear()) + ";
2 Likes

Your solution works so well. Not only does your code not open the shader editor, but even if I manually open the shader editor, I can still update the code with the tool button. thanks.