Emissive á la Dragon Age

As I used Bioware’s modding tools for Dragon Age, I saw they used some sort of simple emissive effect. The deal is that there’s a grayscale map where black means that it is recieving lights as usual while white means it’s fullbright (per pixel on UV map). I wonder if this is possible in Unity, and in free, for there’s no glow or ilumination involved?

If it is, then can you tell me how much you need paid (PayPal) to make a shader with diffuse, normal, specular and such a map. Reasson why I want specular separate is that I find it cumbersome to use the alpha channel. I don’t really know how much effort this is, that’s why I am asking how much you need paid.

Thanks in advance.

What do you mean by “cumbersome”? Do you want to scale/offset the emission map differently from the diffuse map?

Yes, I would prefer it as a map in itself, not an alpha channel of another. I would prefer a shader with the diffuse, specular, normal and the “psuedo-emmisive” map as four separate texture map, i.e. no alpha channels.

Can such an emissive map be made and work in Unity free?

unityfree doesn’t have restrictions on shader unless render to texture is used, so yeah you can. Finding someone to code it for you isn’t so easy.

Shader "Bumped Specular Self-Illuminated" {
	Properties {
		_Color ("Main Color", Color) = (1,1,1,1)
		_SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
		_Shininess ("Shininess", Range (0.03, 1)) = 0.078125
		_MainTex ("Base (RGB) Gloss (A)", 2D) = "white" {}
		_BumpMap ("Normalmap", 2D) = "bump" {}
		_SelfIllumTex ("Self-Illumination (R)", 2D) = "black" {}
	}

	SubShader{
		Tags { "RenderType"="Opaque" }
		LOD 400
		CGPROGRAM
			#pragma surface surf SelfIllum

			struct SurfaceOutputSelfIllum {
				fixed3 Albedo;
				fixed3 Normal;
				fixed SelfIllum;
				fixed3 Emission;
				half Specular;
				fixed Gloss;
				fixed Alpha;
			};

			inline fixed4 LightingSelfIllum (SurfaceOutputSelfIllum s, fixed3 lightDir, fixed3 viewDir, fixed atten)
			{
				fixed3 h = normalize (lightDir + viewDir);

				fixed diff = max (0, dot (s.Normal, lightDir));

				float nh = max (0, dot (s.Normal, h));
				float spec = pow (nh, s.Specular*128.0) * s.Gloss;

				diff = lerp(diff, 1, s.SelfIllum);
				atten = lerp(atten, 1, s.SelfIllum);

				fixed4 c;
				c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColor.rgb * spec) * (atten * 2);
				c.a = s.Alpha + _LightColor0.a * _SpecColor.a * spec * atten;
				return c;
			}

			struct Input
			{
				float2 uv_MainTex;
				float2 uv_BumpMap;
				float2 uv_SelfIllumTex;
			};
			
			sampler2D _MainTex, _BumpMap, _SelfIllumTex;
			float _Shininess, _Gloss;
			float4 _Color;
				
			void surf (Input IN, inout SurfaceOutputSelfIllum o)
			{
				fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);
				o.Albedo = tex.rgb * _Color.rgb;
				o.Alpha = tex.a * _Color.a;
				o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
				o.Specular = _Shininess;
				o.Gloss = tex.a;
				o.SelfIllum = tex2D(_SelfIllumTex, IN.uv_SelfIllumTex).r;
			}
		ENDCG
	}
	FallBack "Specular"
}

This is just a modified BlinnPhong but there’s a slot for Self-Illumination. It’ll take a full RGB texture but it will only read the red channel to handle self-illumination.

That’ll be $500 please.

(just kidding :P)

Oh no please don’t use that shader! I’ll make a way simpler one tomorrow.

What is wrong with that shader?

There’s nothing inherently wrong with it. It’s just a bit of a hack, really.

The shader above has a few flaws:

  1. It doesn’t work properly with more than one light in forward rendering, because the emission is added every time.
  2. It doesn’t attenuate specular or ambient contributions when emission goes up
  3. It doesn’t support deferred lighting even thought it could
  4. It doesn’t work with vertex or spherical harmonic lights because they bypass the lighting function

All of these things can be fixed without even using a custom lighting model: by changing the albedo and gloss of the surface to complement the emission, we can attenuate all lighting results equally. This shader is a slight modification of the built-in Self-Illum/Bumped Specular:

Shader "Self-Illumin Exclusive/Bumped Specular" {
Properties {
	_Color ("Main Color", Color) = (1,1,1,1)
	_SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
	_Shininess ("Shininess", Range (0.01, 1)) = 0.078125
	_MainTex ("Base (RGB) Gloss (A)", 2D) = "white" {}
	_Illum ("Illumin (A)", 2D) = "white" {}
	_BumpMap ("Normalmap", 2D) = "bump" {}
	_EmissionLM ("Emission (Lightmapper)", Float) = 0
}
SubShader {
	Tags { "RenderType"="Opaque" }
	LOD 400
CGPROGRAM
#pragma surface surf BlinnPhong

sampler2D _MainTex;
sampler2D _BumpMap;
sampler2D _Illum;
fixed4 _Color;
half _Shininess;

struct Input {
	float2 uv_MainTex;
	float2 uv_Illum;
	float2 uv_BumpMap;
};

void surf (Input IN, inout SurfaceOutput o) {
	fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);
	fixed4 c = tex * _Color;
[COLOR="#4169e1"]	fixed emission = tex2D(_Illum, IN.uv_Illum).a;
	o.Albedo = c.rgb * (1 - emission);
	o.Emission = c.rgb * emission;
	o.Gloss = tex.a * (1 - emission);[/COLOR]
	o.Alpha = c.a;
	o.Specular = _Shininess;
	o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
}
ENDCG
}
FallBack "Self-Illumin/Specular"
}

Splitting everything out into separate maps is left as an exercise to the reader. I’m still not sure why you would want to burden a shader with extra textures just to avoid packing.

Huh, interesting. Guess I’ve still got to get used to how the surface shaders interact with all the other nonsense :stuck_out_tongue:

@Daniel Brauer, this will work in Unity Free, right? My trial has only 12-13 days left.

It’s tricky: there are a lot of different ways that lighting can be computed, and the lighting function isn’t applied to most of them. There happened to be an easy way out in this case, but most custom lighting models have to make compromises.

Yes.

Possibly the noobiest question ever, but how can I use it? I tried creating a new shader, opening its script and owerwrite it, but it reverted back to the default new shader once I closed the script editor.

Perhaps you forgot to save the file, or you changed its name while you had it open in the editor?