Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When using Convert to ShaderMaterial on a StandardMaterial3D, if the material has refraction, it stops working after being converted #99663

Closed
Jamsers opened this issue Nov 25, 2024 · 4 comments · Fixed by #99743

Comments

@Jamsers
Copy link

Jamsers commented Nov 25, 2024

Tested versions

  • Reproducible in: v4.4.dev5.official [9e60984]

System information

Godot v4.4.dev5 - Windows 10.0.22631 - Multi-window, 1 monitor - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 3060 Laptop GPU (NVIDIA; 32.0.15.6614) - AMD Ryzen 5 5600H with Radeon Graphics (12 threads)

Issue description

When converting a StandardMaterial3D to ShaderMaterial, refraction stops working.

Source StandardMaterial3D
[resource]
transparency = 1
cull_mode = 2
depth_draw_mode = 1
albedo_color = Color(0.431373, 0.635294, 0.87451, 0.705882)
metallic = 0.98
roughness = 0.02
normal_enabled = true
normal_scale = 0.05
normal_texture = ExtResource("1_lho8h")
refraction_enabled = true
refraction_scale = 0.1
refraction_texture = ExtResource("1_lho8h")
refraction_texture_channel = 4
uv1_scale = Vector3(15, 15, 15)
texture_filter = 5
proximity_fade_enabled = true
proximity_fade_distance = 0.5
Generated GDShader
shader_type spatial;
render_mode blend_mix, depth_draw_always, cull_disabled, diffuse_burley, specular_schlick_ggx;

uniform vec4 albedo : source_color;
uniform sampler2D texture_albedo : source_color, filter_linear_mipmap_anisotropic, repeat_enable;
uniform float proximity_fade_distance : hint_range(0.0, 4096.0, 0.01);
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_anisotropic, repeat_enable;
uniform vec4 metallic_texture_channel;
uniform sampler2D texture_roughness : hint_roughness_r, filter_linear_mipmap_anisotropic, 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 sampler2D texture_refraction : filter_linear_mipmap_anisotropic, repeat_enable;
uniform float refraction : hint_range(-1.0, 1.0, 0.001);
uniform vec4 refraction_texture_channel;
uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_linear_mipmap;
uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest;

uniform sampler2D texture_normal : hint_roughness_normal, filter_linear_mipmap_anisotropic, repeat_enable;
uniform float normal_scale : hint_range(-16.0, 16.0);

uniform vec3 uv1_scale;
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;

	// Normal Map: Enabled
	NORMAL_MAP = texture(texture_normal, base_uv).rgb;
	NORMAL_MAP_DEPTH = normal_scale;

	// Refraction: Enabled (with normal map texture)
	vec3 unpacked_normal = NORMAL_MAP;
	unpacked_normal.xy = unpacked_normal.xy * 2.0 - 1.0;
	unpacked_normal.z = sqrt(max(0.0, 1.0 - dot(unpacked_normal.xy, unpacked_normal.xy)));
	vec3 ref_normal = normalize(mix(
			NORMAL,
			TANGENT * unpacked_normal.x + BINORMAL * unpacked_normal.y + NORMAL * unpacked_normal.z,
			NORMAL_MAP_DEPTH));
	vec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(texture(texture_refraction, base_uv), refraction_texture_channel) * refraction;

	float ref_amount = 1.0 - albedo.a * albedo_tex.a;

	float refraction_depth_tex = textureLod(depth_texture, ref_ofs, 0.0).r;
	vec4 refraction_view_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, refraction_depth_tex, 1.0);
	refraction_view_pos.xyz /= refraction_view_pos.w;

	// If the depth buffer is lower then the model's Z position, use the refracted UV, otherwise use the normal screen UV.
	// At low depth differences, decrease refraction intensity to avoid sudden discontinuities.
	EMISSION += textureLod(screen_texture, mix(SCREEN_UV, ref_ofs, smoothstep(0.0, 1.0, VERTEX.z - refraction_view_pos.z)), ROUGHNESS * 8.0).rgb * ref_amount * EXPOSURE;
	ALBEDO *= 1.0 - ref_amount;
	// Force transparency on the material (required for refraction).
	ALPHA = 1.0;

	// Proximity Fade: Enabled
	float proximity_depth_tex = textureLod(depth_texture, SCREEN_UV, 0.0).r;
	vec4 proximity_view_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, proximity_depth_tex, 1.0);
	proximity_view_pos.xyz /= proximity_view_pos.w;
	ALPHA *= clamp(1.0 - smoothstep(proximity_view_pos.z + proximity_fade_distance, proximity_view_pos.z, VERTEX.z), 0.0, 1.0);
}

Steps to reproduce

  1. Open the MRP. Notice refraction works on the water material.
  2. Right click the water material in FileSystem and select Convert to ShaderMaterial.
  3. Reload the project after converting.
  4. Notice refraction stops working.

Minimal reproduction project (MRP)

conv-to-shader-refrac.zip

@tetrapod00
Copy link
Contributor

tetrapod00 commented Nov 25, 2024

Tested the MRP on v4.4.dev5.official [9e60984], Windows 10. The converted shader material does indeed look different:
StandardMaterial:
Image
ShaderMaterial:
Image

Also reproducible in 4.3.

@clayjohn
Copy link
Member

In the past when we have had issues like this it has come from the shader parameters getting lost in translation. Can one of you check and see if the shader parameters of the new ShaderMaterial look correct?

@tetrapod00
Copy link
Contributor

tetrapod00 commented Nov 27, 2024

I think it's from the generated shader's refraction_texture_channel being set to a default of vec4(0.0):

uniform vec4 refraction_texture_channel;

If you set one or more of the channels to 1.0, refraction returns. The other parameters mostly seem to transfer correctly, but the converted shader also appears to be a different color.


I duplicated the material in the filesystem, then converted with the filesystem Convert to ShaderMaterial context menu action that was recently added, if it makes a difference.

Original shader, text format:

[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://dun46tju52s24"]

[ext_resource type="Texture2D" uid="uid://bqyhvb4qj0rbe" path="res://Textures/Water/Water_Normal.png" id="1_lho8h"]

[resource]
transparency = 1
cull_mode = 2
depth_draw_mode = 1
albedo_color = Color(0.431373, 0.635294, 0.87451, 0.705882)
metallic = 0.98
roughness = 0.02
normal_enabled = true
normal_scale = 0.05
normal_texture = ExtResource("1_lho8h")
refraction_enabled = true
refraction_scale = 0.1
refraction_texture = ExtResource("1_lho8h")
refraction_texture_channel = 4
uv1_scale = Vector3(15, 15, 15)
texture_filter = 5
proximity_fade_enabled = true
proximity_fade_distance = 0.5

Converted shader parameters:
Image

@Jamsers
Copy link
Author

Jamsers commented Nov 27, 2024

I can confirm that setting Metallic Texture Channel and Refraction Texture Channel x values to 1.0 makes the converted GDShader look similar to its source StandardMaterial3D (at least to my eyes). I think this is just #84633, but for refraction as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants