Can uv1_offset, albedo_color, etc. be used individually on each 3D Model?

Godot Version

4.3

Question

Continuing from Setting UV Mapping for facial expression of a character , Right now, I am using uv1_offset to change a character’s facial expression :

		var mesh:MeshInstance3D = get_node("xxxxx")
		var mat:StandardMaterial3D = mesh.get_active_material(0)
		mat.uv1_offset = Vector3(xxx, yyy, zzz)

But then I realized one thing. If I have multiple instances of this 3D model, all of them will share the same facial expression - even the newly created ones that have been created after the code above got executed will have the facial expression set by the code above.

So in this case, is it possible to set uv1_offset individually for each 3D model?

Likewise, I have also tried something like mat.albedo_color = Color(0, 1, 1, 1) and it seems all the 3D models will share this. How to make these attributes individual for all 3D models?

EDIT: I found How do I change the albedo_color of a single instance of a 3d scene? - #2 by system . If this is the case, then I have to go to Shader only? Is it possible to do this without Shader?

Materials are shared for performance reasons. Since you need to modify them individually for each instance. You could go into the material of the mesh instance, right-click, and make it unique for each instance.

That second link looks interesting though but requires you to write a gdshader code, I think…

If this will preserve some performance you can transform your current shader into a gdshader script.

1 Like

@pennyloafers

After I clicked on “Make Unique” , I do not see any visual cue. How do I know if this material is already “unique”?

Going for Shader route, I studied from https://www.youtube.com/watch?v=6-eIEFPcvrU .

After that, I applied the required Per-instance uniforms accordingly into the Shader .gdshader file and call set_instance_shader_parameter in the gdscript. For all these, see Shading language — Godot Engine (stable) documentation in English From here, each instance can now has its own attributes such as albedo_color, etc.

Going a step further, the Shader code that got automatically generated from StandardMaterial3D upon conversion is very useful. From there, I could set the uv1_offset to be per-instance, and change the facial expression of each character accordingly:

// NOTE: Shader automatically converted from Godot Engine 4.3.stable's StandardMaterial3D.

shader_type spatial;
render_mode blend_mix, depth_draw_opaque, cull_disabled, diffuse_burley, specular_schlick_ggx;

uniform vec4 albedo : source_color;
uniform sampler2D texture_albedo : source_color, filter_linear_mipmap, repeat_enable;
uniform float point_size : hint_range(0.1, 128.0, 0.1);

uniform float roughness : hint_range(0.0, 1.0);
uniform sampler2D texture_metallic : hint_default_white, filter_linear_mipmap, repeat_enable;
uniform vec4 metallic_texture_channel;
uniform sampler2D texture_roughness : hint_roughness_r, filter_linear_mipmap, repeat_enable;

uniform float specular : hint_range(0.0, 1.0, 0.01);
uniform float metallic : hint_range(0.0, 1.0, 0.01);

uniform vec3 uv1_scale;
instance uniform vec3 uv1_offset;
uniform vec3 uv2_scale;
uniform vec3 uv2_offset;

void vertex() {
	UV = UV * uv1_scale.xy + uv1_offset.xy;
}

void fragment() {
	vec2 base_uv = UV;

	vec4 albedo_tex = texture(texture_albedo, base_uv);
	ALBEDO = albedo.rgb * albedo_tex.rgb;

	float metallic_tex = dot(texture(texture_metallic, base_uv), metallic_texture_channel);
	METALLIC = metallic_tex * metallic;
	SPECULAR = specular;

	vec4 roughness_texture_channel = vec4(1.0, 0.0, 0.0, 0.0);
	float roughness_tex = dot(texture(texture_roughness, base_uv), roughness_texture_channel);
	ROUGHNESS = roughness_tex * roughness;
}

After that, in gdscript, I could modify the now per-instance shader parameter using, for example:

MeshInstance3D_for_character_face.set_instance_shader_parameter("uv1_offset", Vector2( 0.5, 0.0 ))

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.