negative lighting?

I’m actually learning how to write shaders and I’d appreciate your help :smile:

How can I change the method that lights get calculated to my diffuse texture?

In other words: is it possible to write a shader that makes an object darker when it gets hit by light?

I am looking through some basic vertex and fragment programs (like the one for the bump effect).

Where in these lines is the statement that says how to combine lighting and MainTex?
Where is the combination of bump and diffuse light?

		Pass {	
			Name "PPL"
			Tags {
				"LightMode" = "Pixel"  
				"LightTexCount" = "012"
			}
				
CGPROGRAM
// profiles arbfp1
// fragment frag
// fragmentoption ARB_fog_exp2
// fragmentoption ARB_precision_hint_fastest

// vertex vert
// autolight 7
#include "UnityCG.cginc"
#include "AutoLight.cginc"

struct v2f { 
	V2F_POS_FOG;
	float2	uv			: TEXCOORD0;
	float2	uv2			: TEXCOORD1;
	float3	lightDirT	: TEXCOORD2;
	V2F_LIGHT_COORDS(TEXCOORD3);
}; 
struct v2f2 { 
	V2F_POS_FOG;
	float2	uv			: TEXCOORD0;
	float2	uv2			: TEXCOORD1;
	float3	lightDirT	: TEXCOORD2;
};


v2f vert (appdata_tan v)
{
	v2f o;
	PositionFog( v.vertex, o.pos, o.fog );
	o.uv = TRANSFORM_UV(1);
	o.uv2 = TRANSFORM_UV(0);
	
	TANGENT_SPACE_ROTATION;
	o.lightDirT = mul( rotation, ObjSpaceLightDir( v.vertex ) );	
	
	PASS_LIGHT_COORDS(2);
	return o;
}

uniform sampler2D _BumpMap : register(s0);
uniform sampler2D _MainTex : register(s1);

float4 frag (v2f2 i, LIGHTDECL(TEXUNIT2)) : COLOR
{
	float4 texcol = tex2D(_MainTex,i.uv);
	
	// get normal from the normal map
	float3 normal = tex2D(_BumpMap, i.uv2).xyz * 2 - 1;
	
	return DiffuseLight( i.lightDirT, normal, texcol, LIGHTATT );
}
ENDCG  
			SetTexture [_BumpMap] {combine texture}
			SetTexture [_MainTex] {combine texture}
			SetTexture [_LightTexture0] {combine texture} 
			SetTexture [_LightTextureB0] {combine texture}
		}
	}

Here the light calculation happens inside DiffuseLight function. The function itself is defined in UnityCG.cginc file (inside application: Unity.app/Contents/CGIncludes/UnityCG.cginc).

However, by default lights in Unity are additive - i.e. each light adds illumination. There’s no easy way to make lights subtract illumination, but you could try to make lights multiply existing illumination to reduce it. Try adding something likeBlend Zero OneMinusSrcColor to the pixel-lit pass for a start. This will turn on inverse-multiplicative blending (instead of default additive one).

Things start to get clearer - thanks Aras !

There’s one more thing that I saw in the Reflective/Bumped Unlit Shader:

that shader doesn’t take diffuse lighting into account - it only adds the bump effect onto the reflective material.

and THAT’S what I need for my shader - if you would be so kind and help me one more time?

How can I eliminate the diffuse light from the light source in the fragment program and calculate the bump effect only?

I’ve made a workaround for my shader to get what I want but it’s far away from being elegant:

I use “Blend DstColor SrcColor” to add the Pixel Lit Pass and a 50% directional light (under 90° angle).
That way I maintain the brightness of the diffuse texture and add just the bumps.

Shader "MyBumpedShader" {
Properties {
    _MainTex ("Base (RGB)", 2D) = "white" {}
    _BumpMap ("Bump (RGB)", 2D) = "bump" {}
   
}

SubShader {
    
   Blend AppSrcAdd AppDstAdd
    // Ambient pass
    Pass {
        Name "BASE"
        Tags {"LightMode" = "PixelOrNone"}
        Color [_PPLAmbient]
               SetTexture [_MainTex] {
            combine texture
        }
    }
    
        // Vertex lights
    Pass {
        Name "BASE"
        Tags {"LightMode" = "Vertex"}
               
        Lighting On
      
		SetTexture [_MainTex] {
            combine texture
        }
    }

 Pass {	
			Name "PPL"
			Blend DstColor SrcColor
			Tags {
				"LightMode" = "Pixel"  
				"LightTexCount" = "012"
			}
				
CGPROGRAM
// profiles arbfp1
// fragment frag
// fragmentoption ARB_fog_exp2
// fragmentoption ARB_precision_hint_fastest

// vertex vert
// autolight 7
#include "UnityCG.cginc"
#include "AutoLight.cginc"

struct v2f { 
	V2F_POS_FOG;
	float2	uv			: TEXCOORD0;
	float2	uv2			: TEXCOORD1;
	float3	lightDirT	: TEXCOORD2;
	V2F_LIGHT_COORDS(TEXCOORD3);
}; 
struct v2f2 { 
	V2F_POS_FOG;
	float2	uv			: TEXCOORD0;
	float2	uv2			: TEXCOORD1;
	float3	lightDirT	: TEXCOORD2;
};


v2f vert (appdata_tan v)
{
	v2f o;
	PositionFog( v.vertex, o.pos, o.fog );
	o.uv = TRANSFORM_UV(1);
	o.uv2 = TRANSFORM_UV(0);
	
	TANGENT_SPACE_ROTATION;
	o.lightDirT = mul( rotation, ObjSpaceLightDir( v.vertex ) );	
	
	PASS_LIGHT_COORDS(2);
	return o;
}

uniform sampler2D _BumpMap : register(s0);
uniform sampler2D _MainTex : register(s1);

float4 frag (v2f2 i, LIGHTDECL(TEXUNIT2)) : COLOR
{
	float4 texcol = tex2D(_MainTex,i.uv);
	
	// get normal from the normal map
	float3 normal = tex2D(_BumpMap, i.uv2).xyz * 2 - 1;
	
	return DiffuseLight( i.lightDirT, normal, texcol, LIGHTATT );
}
ENDCG  
			SetTexture [_BumpMap] {combine texture}
			SetTexture [_MainTex] {combine texture}
			SetTexture [_LightTexture0] {combine texture} 
			SetTexture [_LightTextureB0] {combine texture}
		}
	}
    


Fallback " VertexLit", 2

}

I want my shader to do bumpmapping without brightening my _MainTex…

The reflective bumped unlit shader and your case are a bit different. In reflective case, it does not do “bumpmapping” in lighting sense, it does a “bumpmapped cubemap reflection” (and that does not need any lights at all).

What you want is some sort of “lighting” without the actual lighting, and I’m not sure how to do that :slight_smile: You want to bumpmap the base texture, without changing it’s illumination - but for the bump effect to be visible, it has to lighten or darken some parts of the texture at least… so I’m not sure how to do that. Maybe try not real bump-mapping, but emboss mapping?

I think I’ve found a solution…
Please let me know what you think about that:

// Pixel lights
		Pass {	
			Name "PPL"
			Blend  DstColor SrcColor 
			Tags {
				"LightMode" = "Pixel"  
				"LightTexCount" = "012"
			}
				
CGPROGRAM
// profiles arbfp1
// fragment frag
// fragmentoption ARB_fog_exp2
// fragmentoption ARB_precision_hint_fastest

// vertex vert
// autolight 7
#include "UnityCG.cginc"
#include "AutoLight.cginc"

struct v2f { 
	V2F_POS_FOG;
	float2	uv			: TEXCOORD0;
	float2	uv2			: TEXCOORD1;
	float3	lightDirT	: TEXCOORD2;
	V2F_LIGHT_COORDS(TEXCOORD3);
}; 
struct v2f2 { 
	V2F_POS_FOG;
	float2	uv			: TEXCOORD0;
	float2	uv2			: TEXCOORD1;
	float3	lightDirT	: TEXCOORD2;
};


v2f vert (appdata_tan v)
{
	v2f o;
	PositionFog( v.vertex, o.pos, o.fog );
	o.uv = TRANSFORM_UV(1);
	o.uv2 = TRANSFORM_UV(0);
	
	TANGENT_SPACE_ROTATION;
	o.lightDirT = mul( rotation, ObjSpaceLightDir( v.vertex ));	
	
	PASS_LIGHT_COORDS(2);
	return o;
}

uniform sampler2D _BumpMap : register(s0);


float4 frag (v2f2 i, LIGHTDECL(TEXUNIT2)) : COLOR
{
	
	// get normal from the normal map
	float3 normal = tex2D(_BumpMap, i.uv2).xyz - 0.5;
	
	half diffuse = dot( normal, 1 );
	
	half4 c;
	c.rgb =  diffuse;
	c.a = 0; // diffuse passes by default don't contribute to overbright
	return c;
	
}
ENDCG  
			SetTexture [_BumpMap] {combine texture}
			SetTexture [_LightTexture0] {combine texture} 
			SetTexture [_LightTextureB0] {combine texture}
		}
	}

It just needs a light source to go into the PPL program:

  • blend mode is 2x multiplicative (Ambient * PPL *2)

  • I replace the Lambertion diffuse light function from the UNITYCG file by my own calculation IN the shader itself

  • I take the bump map, subtract 0.5 to make it a 50% grey texture (128/128/128) with bumps

  • I replaced the second component in the dot product by “1” to eliminate / replace the light source’s influence. As I said: I don’t care about light strenght or angle…

However, I do get a difference of 1% brightness when combinig ambient and PPL pass.

I made a test with a 50% grey Base Texture:

The ambient pass by itself keeps the 128/128/128 RGB values of course.

The PPL pass (with a wildcard bumpmap that’s actually a white RGB texture turned into a bump map) gives me 128/128/128 as well.

When combining Ambient and PPL by “Blend DstColor SrcColor” I get 129/129/129 as a result…

Do you have any clue where that comes from? Is that a round-off error in the Blend DstColor SrcColor Command?

Cause basically it is: (0.5 * 0.5) * 2 - but the result is 0.51 !

If it works for you - then it’s good :slight_smile:

I’d guess it’s a rounding error in the blending. Framebuffer is 8 bits per component, and the hardware might round in one or other way… I think I also remember someone on mac-opengl mailing list saying that some graphics cards do blending with “one bit off” - you might be experiencing the same issue.

I tried subtracting 0.004 from the diffuse value but then it switches from RGB 129 to RGB 127.

Not a big deal but I have to explain things like that in my thesis… thanks for the information!