Is there a way to convert a standard material to a shader material from script? I need to inject some vertex shader code into materials imported from glft.
There are some PRs on github to expose access to material’s shader rid but nothing officially approved.
Converting a StandardMaterial3D to a ShaderMaterial is an editor-only feature. Without getting the ShaderRID of the Material It’s not possible to replicate it in code at runtime.
You can re-import your models overriding their materials though. More info here:
I know but that’s not automated enough for what I need as it can only override with “static” pre-made materials. I need to build a material based on what is in the asset, alter its vertex shader and assign it back. With the current override mechanism, I have to manually create a new override material based on the asset material at every import if incoming asset material is altered, or for every new asset. This is tedious.
The current solution is to have a shader material with all possible uniforms that I can typically expect in a standard material, duplicate it for each material found in the asset and re-assign uniforms one by one. Not too elegant but it does the job.
I am doing it within EditorScenePostImport tool script. However the script still has to copy the values of material properties to corresponding uniforms in a premade shader material, one by one, as it cannot get to the imported material’s shader source code.
It’s not as elegant and bugproof as it could be if the actual material shader code was possible to get.
@normalized Do you mind sharing your script and shader used ?
I’m in the exact same case as you and I’m struggling to change every property of the original material to the newly created shader material.
I have a predefined shader material resource stored on disk. in EditorScenePostImport script I just get each material assigned to a mesh, assign a duplicate of the shader material instead, and copy the values of relevant properties one by one.
@tool
extends EditorScenePostImport
func _post_import(scene):
# get all mesh instances
var mesh_instances = scene.find_children("*", "MeshInstance3D", true)
# get all meshes
var meshes = {}
for mi in mesh_instances:
if not mi.mesh:
continue
meshes[mi.mesh] = true
# get all materials
var materials = {}
for m: Mesh in meshes:
for i in m.get_surface_count():
var mat: StandardMaterial3D= m.surface_get_material(i)
if not mat:
continue
var mat_new: ShaderMaterial = make_shader_material(mat)
m.surface_set_material(i, mat_new)
materials[mat] = true
return scene
func make_shader_material(orig: StandardMaterial3D) -> ShaderMaterial:
var m: ShaderMaterial = preload("res://override.material").duplicate(true)
m.set_shader_parameter("albedo", orig.albedo_color)
# etc...
return m