Godot Version
4.2.1
Question
Hey -
the standard material in godot has the Alpha-hash transparency setting as an option!
This is a very cool form of alpha masking.
But how do one write that in code?
(I’ve searched and searched and it seems this is hard to find! )
instead of discarding if alpha > set_value use a noise texture or function
if (alpha > texture(noise_texture, UV).r) {
discard
}
1 Like
After selecting alpha hash in a material, you can click on the menu to create a material, and select “convert to shader”. You can then just use the provided code.
2 Likes
Ok, after much fiddle. I got this working. For posterity! Thanks all
uniform vec3 albedo : source_color = vec3(0.02, 0.45, 0.8);
uniform sampler2D albedo_tex;
uniform sampler2D noise_tex;
float hash_2d(vec2 p) {
return fract(1.0e4 * sin(17.0 * p.x + 0.1 * p.y) *
(0.1 + abs(sin(13.0 * p.y + p.x))));
}
float hash_3d(vec3 p) {
return hash_2d(vec2(hash_2d(p.xy), p.z));
}
float compute_alpha_hash_threshold(vec3 pos, float hash_scale) {
vec3 dx = dFdx(pos);
vec3 dy = dFdy(pos);
float delta_max_sqr = max(length(dx), length(dy));
float pix_scale = 1.0 / (hash_scale * delta_max_sqr);
vec2 pix_scales =
vec2(exp2(floor(log2(pix_scale))), exp2(ceil(log2(pix_scale))));
vec2 a_thresh = vec2(hash_3d(floor(pix_scales.x * pos.xyz)),
hash_3d(floor(pix_scales.y * pos.xyz)));
float lerp_factor = fract(log2(pix_scale));
float a_interp = (1.0 - lerp_factor) * a_thresh.x + lerp_factor * a_thresh.y;
float min_lerp = min(lerp_factor, 1.0 - lerp_factor);
vec3 cases = vec3(a_interp * a_interp / (2.0 * min_lerp * (1.0 - min_lerp)),
(a_interp - 0.5 * min_lerp) / (1.0 - min_lerp),
1.0 - ((1.0 - a_interp) * (1.0 - a_interp) / (2.0 * min_lerp * (1.0 - min_lerp))));
float alpha_hash_threshold =
(a_interp < (1.0 - min_lerp)) ? ((a_interp < min_lerp) ? cases.x : cases.y) : cases.z;
return clamp(alpha_hash_threshold, 0.00001, 1.0);
}
void fragment() {
vec2 base_uv = UV;
vec4 albedo_tex_ = texture(albedo_tex,base_uv);
vec4 noise_tex_ = texture(noise_tex,base_uv);
ALBEDO = albedo.rgb * albedo_tex_.rgb;
if (albedo_tex_.a < compute_alpha_hash_threshold(VERTEX, 0.5)) {
discard;
}
//ALPHA = albedo_tex.a;
}
Also note, your code is equivalent to writing:
uniform vec3 albedo : source_color = vec3(0.02, 0.45, 0.8);
uniform sampler2D albedo_tex;
uniform sampler2D noise_tex;
void fragment() {
vec2 base_uv = UV;
vec4 albedo_tex_ = texture(albedo_tex,base_uv);
vec4 noise_tex_ = texture(noise_tex,base_uv);
ALBEDO = albedo.rgb * albedo_tex_.rgb;
ALPHA_HASH_SCALE = 0.5;
//ALPHA = albedo_tex.a;
}
1 Like
It is? But there is almost nothing. ALPHA_HASH_SCALE does it all without all the jam?
Yep!
When you use ALPHA_HASH_SCALE in the shader, you enable the following code block:
#ifdef ALPHA_HASH_USED
vec3 object_pos = (inverse(read_model_matrix) * inv_view_matrix * vec4(vertex, 1.0)).xyz;
if (alpha < compute_alpha_hash_threshold(object_pos, alpha_hash_scale)) {
discard;
}
#endif // ALPHA_HASH_USED
1 Like
tried this but it just makes the mesh completely opaque.
0.1
0.0001
0.99
doesnt do any diff.
luckily this works splendid
if (albedo_tex_.a < compute_alpha_hash_threshold(VERTEX, 0.5)) {
discard;
}
just doesnt look very optimized.
I suppose you still need to assign alpha whne you use the alpha threshold built-in, otherwise Godot can’t know the alpha to compare against.
system
Closed
July 3, 2024, 1:27pm
12
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.