Set Single Color To Transparent using shaders?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Tachekentya

Hello. I have a sprite whit a png texture and I want to make transparent the black areas of this image (I know this can be done modifying the image with other programs like photoshop, but I would have to do that many times and I think is better to solve this using code).
I’m trying to use the solution found in https://forum.godotengine.org/18639/how-can-i-set-any-single-color-to-be-transparent

shader_type canvas_item;
uniform texture diffuse;
color col = tex(diffuse,UV).rgba;
if (col.r==1.0 && col.g==0.0 && col.b==1.0) {
    col.a=0.0;
}
COLOR=col;

The problem is that Godot does not recognize “diffuse” as a variable (I’m getting error(3): Expected datatype.) I’m trying to understand the shading language, but I still don’t get it, I would really appreciate if you can help me understand how this works

:bust_in_silhouette: Reply From: 2plus2makes5

Is that the entire shader? Because if so the problem is that you forgot the fragment function, vec4 instead of color,texture instead of tex and sampler2D instead of texture:

shader_type canvas_item;
uniform sampler2D diffuse;

void fragment(){
vec4 col = texture(diffuse,UV).rgba;
if (col.r==1.0 && col.g==0.0 && col.b==1.0) {
    col.a=0.0;
}
COLOR=col;
}

EDIT:
I edited because i saw other errors later.

  1. You can omit the .rgba in the line where you sample the texture, since you’re storing it in a vec4 anyway.
  2. The conditional inside the if can be replaced with col.rgb == vec3(1,0,0).

Just thought I’d help shorten the code.

SIsilicon | 2018-12-27 19:32

Thanks!!! that works perfect, but I realized the condition “if” was too abrupt for me and I need something that works with a grayscale. The following make a smooth transition to transparency

shader_type canvas_item;
uniform float max_col_b = 0.22;
float line(float col_b){
	return (1.0/max_col_b)*col_b;
}
void fragment(){
	vec4 col = texture(TEXTURE,UV).rgba;
	if (col.r<=24.0 && col.g<=24.0 &&  col.b <= max_col_b) {
		col.a = line(col.b);
	}
	COLOR=col;
}

Tachekentya | 2018-12-28 00:31

:bust_in_silhouette: Reply From: Achenar

I managed to achieve something along these lines through a custom spatial shader that sets ‘discard’ if the underlying texture color matches a certain value. In my situation, I am generating meshes and applying textures at runtime from legacy formats (including bmp) which have alpha color specified in some of the supporting data files.

Example shader code and (C#) script to achieve this is below - note it’s somewhat hacked together to assume that the “transparent” color is bright blue (rgb 0,0,255).

C# script to assign the shader

ImageTexture tex = new ImageTexture();
Error e = tex.Load("path/to/texture.bmp");
ShaderMaterial sm1 = new ShaderMaterial();

sm1.Shader = ResourceLoader.Load<Shader>("res://simple_trans_tex.shader");
sm1.SetShaderParam("day_texture", tex);

Shader (saved in project as simple_trans_tex.shader)

shader_type spatial; 
render_mode cull_disabled;

uniform sampler2D day_texture : hint_albedo;

void fragment() {
    vec3 day_tex_color = texture(day_texture, UV ).rgb;

	// filter out transparent color
	float blue = 255f / 255f;
	
	ALBEDO = day_tex_color;

	// discard pixels (transparency) when 8 bit blue = 255
    if (day_tex_color.r==0.0 && day_tex_color.g==0.0 && day_tex_color.b==1.0) {   
	   discard = true;
	}
}