Alpha used to modify the multiply

i am very new to unity but am a 3d artist and am guessing that the multiply for a shader is used to add color to a base texture… If I am correct in that assumption, then the question I have is can you use an alpha to effect what the multiply shows?

As an example: There is a house and you want the user to be able to select whatever color of the house they want. So, the base texture would be the “occlusion render” of the house (i.e. shadows etc ) then when they selected a color from the color pallet, the color would be overlaid on the house. The alpha would prevent the color being added to the windows etc.

Also, if it is possible or if someone knows a way to do what I am describing, it would need to be compatible with Open GL 1.1

Thanks in advance.

I don’t program for the iPhone, but I believe you’re going to be limited by the maximum of two texture operations. Here is a shader that does what you described, but I don’t think I could work light into it:

Shader "Masked Tint" {
	Properties {
		_Color ("Tint Color", Color) = (1,1,1,1)
		_MainTex ("Base (RGB) Mask (A)", 2D) = "white" {}
	}

	SubShader {
		Pass {
			// (_Color.rgb + (float3(1,1,1) - _MainTex.aaa)) * _MainTex.rgb
			SetTexture [_MainTex] {
				ConstantColor [_Color]
				Combine constant + one - texture alpha, constant
			} 
			SetTexture [_MainTex] {
				Combine previous * texture, previous
			} 
		}
	}
}

I came up with a solution recently that gets the same results as yours, but only if the mask is inverted.

http://forum.unity3d.com/viewtopic.php?t=29859

I did not know that you could use the alpha keyword, though, which simplifies things! Thanks! I’m not very experienced with shaders yet, and am wondering why you have put the other stuff in, in addition to this version of what you wrote:

Shader "Masked Tint" {
	
Properties
{ 
	_Color ("Tint Color", Color) = (1,1,1) 
	_MainTex ("Base (RGB) Mask (A)", 2D) = "white"
}

SubShader
{ 
	Pass
	{ 
		SetTexture [_MainTex]
		{ 
			ConstantColor [_Color] 
			Combine constant + texture alpha 
		}
		
		SetTexture [_MainTex]
		{ 
			Combine previous * texture
		}
	} 
}

}

The comment in mine is just what it would look like in a Cg fragment program. I find it helpful sometimes to write out exactly what operations I want before converting them to the fairly opaque language of texture combiners.

I just meant, why did you bother to invert the mask, and why are you explicitly dealing with the resulting alpha channel, when it seems to have no use?

I inverted the mask because I think artists tend to be used to the effect of something increasing as alpha increases, rather than as it decreases. If the tint colour were being used additively, I would not invert the alpha.

I explicitly write the alpha channel so that I can control full screen glow intensity with the tint colour.

This is sort of a complicated matter. If you look at it one way, you can say “I want to allow for more colorization as value increases”.

However, the way the person in the other thread presented the idea, the preparative thought would go more like “I am preserving color from the original image by increasing alpha”. I think this way of thinking is more in-line with how masking works in Photoshop.

After more thinking and testing, I realized that your method allows for blown highlights, while what I did in that other thread (with lerp) prevents them. If an artist wants an area of the image to receive a maximized color value, they can just use pure white in the RGB channels. I don’t see a need to allow for lightening.

I think it’s really simple, just a matter of preference and expectation. You can think of it as the colour being applied to the texture (as I do) or the texture being applied to the colour. Neither way is better.

I’m not sure what you mean about blown-out highlights. The results of the first combiner is clamped to [0,1] before it gets used in the second combiner. A tint colour of white will have no effect at all.

If you could point me to the thread where you used lerp, I’d like to see what you did, there.

Now that I’ve played around a lot with what you did, I think I understand why you think it’s so simple. Your shader seems absolutely optimal, but only if you only use what is effectively a 1-bit alpha. I’m imagining a variety of greyscale values in the alpha channel, based on how much you want any given area to be colorized.

Up to now, I had been thinking about the alpha channel as a mask for transparency, for the RGB image, and applying that on top of a “colorized” version of the same image. (This is exactly what is going on in my shader.) However, you can see from my screenshots below (my previous method on top, yours below) how much more practical it would be, given a large amount of layers, to set things up using your idea. With my old method, you have to keep merging layers and putting the result at the bottom. That is stupid :o, but I hadn’t used it enough to realize that.

Now, it would be no big deal to invert the mask used for the color to be multiplied in, as an alpha channel. And I think that it should be, if using your shader, to avoid the subtraction. But this is a non-issue, when using lerp as I do below.

See, I was testing out just the first texture block of your code, with the rest commented out, and had no idea this clamping would occur. So indeed, blown highlights are not an issue, but there’s still plenty of weirdness going on if you use any grey values in the alpha channel.

See the second line in my first post in this thread. It’s currently the last post in that thread. But I think I improved it, using your logic:

Now that I’ve embraced your view on the alpha channel, it’s a simple matter of switching the order of the first and last arguments of the final line of the shader. So we don’t even need to do a subtraction! :smile:

Shader "Tinted using -Alpha" { 
    
Properties 
{ 
   _Color ("Tint Color", Color) = (1,1,1) 
   _MainTex ("Texture", 2D) = "white" 
} 

SubShader 
{	
	Pass
	{
		SetTexture [_MainTex] 
		{
			ConstantColor [_Color]
			Combine texture * constant
		} 

		SetTexture [_MainTex] 
		{
			Combine previous lerp(texture) texture 
		}
	}
} 

}

189636--6728--$my_way_156.png
189636--6729--$your_way_847.png

1 Like

That makes a lot of sense. I didn’t feel great about adding to the tint colour, but it was the obvious way for me to push it towards not having an effect. Your lerp solution keeps everything proportional, so the alpha value has an effect across its full range, not just over (1 - colour). This would be especially noticeable when using a colour like (0.9,0.9,0.9), where my solution would result in most alpha values being clamped, whereas yours would do proper alpha blending.

I thought of a way to do this today, without linear interpolation. Before, I was thinking of this as alpha blending a texture with a colorized version of itself. Today, I thought, instead, “a texture multiplied by white is itself, so we should be able to do an interpolation between a color, and white, and then multiply by that”.

An alpha blend between a color, and white, can be simplified to multiplying the color by the alpha value, and adding the inverse of the alpha.

texture.rgb * (_Color * texture.a + (1. - texture.a))

Unfortunately, that can’t be done in one texture stage, in fixed function, without resorting to Lerp.

So, I thought about it yet another way. It’s easy to get white, in fixed function, by using “one”. We’re either going to be multiplying by one, or something less than it, so one - something should work. The something is the difference between the colorizing value, and white, multiplied by the alpha mask. (Higher mask value = subtracting more of the difference.)

SetTexture[_MainTex] {Combine texture alpha * one - constant ConstantColor[_Color]}    
SetTexture[_MainTex] {Combine texture * one - previous}

http://www.unifycommunity.com/wiki/index.php?title=Masked_Tint