Specular gloss alpha use UV2 lightmaps alpha

Hey guys

Ok so I’ve finally come unstuck with the whole shader thing. I’ve so far managed to make a shader that allows for lightmaps, a cubemap, specular and normals, but actually editing the specular shader it uses is far too confusing for me to understand, so I’ve no idea what needs to be changed, or how.

What I’m wanting to do, and am sure is possible
Change the specular gloss effect, so that rather than using the default UV1 coordinates and the alpha channel in the main texture. It instead would use the UV2 coordinates and the alpha channel in the Lightmap texture to control the amount of specularity visible.

What I’m wishing was possible, but probably isn’t
Better yet would be using two, with the lightmaps alpha on UV2 as a mask for the individual textures alpha on UV1 (which would also work great for using the UV1 alpha for the reflection amount when using Cubemaps too). But I imagine that would be pushing what’s possible in a shader.

Why?
If anyone has used lightmaps with regular lighting and on a specular material. You’ll know that unless you turn shadows on, the specular effect will appear in area’s it shouldn’t, and wouldn’t if Shadows were active.

Now you don’t want that obviously, because the lightmap is faking the shadows for you, and generally realtime shadows aren’t very visible on lightmapped surfaces (however normal mapping and specular effects are still useful). But you can use the alpha to block the specular effect in darker area’s, simulating what would happen with real shadows. Unfortunately because it currently uses the alpha in the main texture, it’s not really a viable option. But if it was the alpha of the Lightmap, then it could be created with it, use less resources and the end result would be more believable, without the overhead of using shadows, or losing out on specular effects entirely.

So does anyone know how to do this, or has already done it?

thats a pretty nice idea,thanks :wink:
also,i tried to write it.
The only way to go at it seemed to be modifying the actual lighting calculation,so i lifted it from Unitycg include
Since we read from lightmap anyway,we could at least benefit from it more,so for the moment,i set the specular color to be a percentage of the lightmap color,should work nicely with some global illumination,and works as a colored spec shader in a pinch. :slight_smile:

Shader "Masked 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.03, 1)) = 0.078125
	_ColorAmount ("Lightmap Specular", Range (0.0, 1)) = 0.5
	_MaskStrength ("Masking Strength", Range (0.0, 1)) = 1.0
	_Brightness ("LightMap Strength", Range (0.0, 1)) = 0.5
	_MainTex ("Base (RGB) Gloss (A)", 2D) = "white" {}
	_BumpMap ("Bumpmap (RGB)", 2D) = "bump" {}
	_LightMap ("Lightmap", 2D) = "white" {}
}

Category {
	Tags { "RenderType"="Opaque" }
	LOD 400
	Blend AppSrcAdd AppDstAdd
	Fog { Color [_AddFog] }
	
	// ------------------------------------------------------------------
	// ARB fragment program
	
	SubShader { 
		UsePass "Specular/BASE"
		
		// Pixel lights
		Pass { 
			Name "PPL"	
			Tags { "LightMode" = "Pixel" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_builtin
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest 
#include "UnityCG.cginc"
#include "AutoLight.cginc" 

struct v2f {
	V2F_POS_FOG;
	LIGHTING_COORDS
	float3	uvK; // xy = UV, z = specular K
		float2	uv2;
	float2	uv3;
	float3	viewDirT;
	float3	lightDirT;
}; 

uniform float4 _MainTex_ST, _BumpMap_ST,_LightMap_ST;
uniform float _Shininess;

struct appdata {
    float4 vertex;
    float2 texcoord;
	float2 texcoord1;
	float4 tangent;
	float3 normal;
};

v2f vert (appdata v)
{	
	v2f o;
	PositionFog( v.vertex, o.pos, o.fog );
	o.uvK.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
	o.uvK.z = _Shininess * 128;
	o.uv3 = TRANSFORM_TEX(v.texcoord, _BumpMap);
	o.uv2 = TRANSFORM_TEX(v.texcoord1, _LightMap);
	TANGENT_SPACE_ROTATION;
	o.lightDirT = mul( rotation, ObjSpaceLightDir( v.vertex ) );	
	o.viewDirT = mul( rotation, ObjSpaceViewDir( v.vertex ) );	

	TRANSFER_VERTEX_TO_FRAGMENT(o);	
	return o;
}

float _ColorAmount;
float _MaskStrength;
float _Brightness;
inline half4 SpecularMaskedLight( half3 lightDir, half3 viewDir, half3 normal, half4 color,half4 lightmap, float specK, half atten )
{
	#ifndef USING_DIRECTIONAL_LIGHT
	lightDir = normalize(lightDir);
	#endif
	viewDir = normalize(viewDir);
	half3 h = normalize( lightDir + viewDir );
	
	half diffuse = dot( normal, lightDir );
	
	float nh = saturate( dot( h, normal ) );
	float speccontribution=lerp(1.0,lightmap.a,_MaskStrength);
	float spec = pow( nh, specK ) * color.a*speccontribution;
	float3 white=(1.0,1.0,1.0);
	float3 lightcontribution=mix(white,lightmap.rgb,_ColorAmount);
	half4 c;
	c.rgb = (color.rgb * _ModelLightColor0.rgb*lightcontribution * diffuse + _SpecularLightColor0.rgb*lightcontribution* spec) * (atten * 2);
	c.a = _SpecularLightColor0.a*speccontribution* spec * atten; // specular passes by default put highlights to overbright
	return c;
}




uniform sampler2D _BumpMap;
uniform sampler2D _MainTex;
uniform sampler2D _LightMap;

float4 frag (v2f i) : COLOR
{		
	float4 texcol = tex2D( _MainTex, i.uvK.xy );
	float4 lightmap =tex2D(_LightMap,i.uv2);
	// get normal from the normal map
	float3 normal = tex2D(_BumpMap, i.uv3).xyz * 2.0 - 1.0;
	

	//texcol.rgb =(texcol.rgb+(lightmap.rgb)); 
	//Uncomment for simple lightmapping
	 texcol.rgb =(texcol.rgb*(lightmap.rgb*2.0-(1-_Brightness))); 
	
	half4 c = SpecularMaskedLight( i.lightDirT, i.viewDirT, normal, texcol,lightmap, i.uvK.z, LIGHT_ATTENUATION(i) );
	return c;
}
ENDCG  
		}
	}
	}
}

Wow that is awesome! The effect is gives is perfect! :smile: :smile: :smile: I hope others find it useful too. It certainly gets rid of the far too visible specular effects that would otherwise appear in dark area’s (and with bloom/glow, those stood out waaaay too much lol). And saves countless draw calls. Awesome! Absolutely awesome! Plus your method of using the actual Lightmap makes sense, since the alpha would end up probably looking just the same, the end result is the same, only your method requires one less channel :smile:

Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! Thank you!

lol.

i do use lightmap alpha :slight_smile:
currently it does exact the same thing as the specular channel on main texture and shininess slider,but i want to use the spec channel on main texture for cubemap reflection control.I’m just gonna update the post above if i complete it.

Ahh my bad! :smile:

I wonder if this would be useful for Unity 3 users even more? What with Beast being right there.

I did have an idea using this and lightmaps along with a cubemap for a kind of all in one lightmap shader that would give the slight reflection effect you’d find on HL2 surfaces. But didn’t get very far, lol.

Shader "!Test Shader" {
	Properties {
		_Color ("Main Color", Color) = (0.5,0.5,0.5,0)
		_SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
		_LightmapModifier ("Lightmap Modifier", Color) = (0.5,0.5,0.5,0)
		_ReflectColor ("Reflection Modifier", Color) = (0.2,0.2,0.2,0)
		_Shininess ("Shininess", Range (0.03, 1)) = 0.05
		_GBlend ("Gloss Blend", Range (0.03, 1)) = 0.05
		
		_MainTex ("Color Texture (RGB)", 2D) = "" {}
		_Bumpmap ("Normal Map (RGB) Reflection (A)", 2D) = "" {}
		_LightMap ("Lightmap (RGB) Gloss Blend (A)", 2D) = "" {}
		_Cube ("Reflection Cubemap (RGB)", Cube) = "_Skybox" { TexGen CubeReflect }
		
		
	}
	SubShader {

		Tags { "RenderType"="Opaque" }
          UsePass "LightmappedDiffuse/BASE"
          UsePass "Bumped Specular/PPL"
		  UsePass "Reflective/VertexLit/BASE"

} 
     FallBack "Lightmapped/VertexLit", 1
}

It’s not much but you’re welcome to use it if you want.

I still decided to make a new post,the shader has some things I’d like to explain.
It now loads a cubemap,the Proximity Scaling slider is for tweaking the “closeness” or parallax of the cubemap,if applied on a wall for example.Nvidia explains it better in this presentation for those interested:Link

Leave it on maximum for small objects or if you don’t bother to tweak it.
Currently the reflection is (mostly) uniform,but normal map alpha channel is still free,if per-pixel reflection control is needed.Shader instruction limit is somewhere closeby though.
Lightmap Specular Contribution controls where the specular color is coming from,at 0.5 its a mix of default specular and lightmap color.Masking strength controls the level of specularity masking(lightmap alpha).
LightMap Strength controls the blend mode,at lowest it is multiplicative,at highest additive.0.5 is generally a good compromise.
I’ll try to get some demo up to show it off,too :slight_smile:

Shader "Masked 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.03, 1)) = 0.2
	_ColorAmount ("Lightmap Specular Contribution", Range (0.0, 1)) = 0.5
	_MaskStrength ("Masking Strength", Range (0.0, 1)) = 1.0
	_Brightness ("LightMap Strength", Range (0.0, 1)) = 0.5
	_MainTex ("Base (RGB) Gloss (A)", 2D) = "white" {}
	_BumpMap ("Bumpmap (RGB)", 2D) = "bump" {}
	_LightMap ("Lightmap(RGB) Specular Mask(A)",2D) = "white" {}
	_Constant ("Proximity Scaling", Range (0.01, 7)) = 6
	_CubeDimness ("Cubemap Multiplier", Range (0.01, 25)) = 5
	_Cube ("Reflection Cubemap", Cube) = "_Skybox" 
}

Category {
	Tags { "RenderType"="Opaque" }
	LOD 600
	Blend AppSrcAdd AppDstAdd
	Fog { Color [_AddFog] }
	
	// ------------------------------------------------------------------
	// ARB fragment program
	
	SubShader { 
		UsePass "Specular/BASE"
		
		// Pixel lights
		Pass { 
			Name "PPL"	
			Tags { "LightMode" = "Pixel" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_builtin
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest 
#include "UnityCG.cginc"
#include "AutoLight.cginc" 

struct v2f {
	V2F_POS_FOG;
	LIGHTING_COORDS
	float3	uvK:TEXCOORD1; // xy = UV, z = specular K
	float2	uv2:TEXCOORD2;
	float3	viewDirT:TEXCOORD3;
	float3	lightDirT:TEXCOORD4;
	float3	I:TEXCOORD5;

}; 

uniform float4 _MainTex_ST,_LightMap_ST;
uniform float _Shininess;
uniform float _CubeDimness;

struct appdata {
    float4 vertex;
    float2 texcoord;
	float2 texcoord1;
	float4 tangent;
	float3 normal;
};
uniform float _Constant;

v2f vert (appdata v)
{	
	v2f o;
	PositionFog( v.vertex, o.pos, o.fog );
	float3 viewDir = ObjSpaceViewDir( v.vertex );
	float3 I =mul((float3x3)_Object2World,v.normal);
	float3 worldpos=mul(_Object2World,v.vertex)-mul(_Object2World,_ObjectSpaceCameraPos);
	o.I = normalize(reflect(_Constant *worldpos+I,I)); 
	o.uvK.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
	o.uvK.z = _Shininess * 128;
	o.uv2 = TRANSFORM_TEX(v.texcoord1, _LightMap);
	TANGENT_SPACE_ROTATION;
	o.lightDirT = mul( rotation, ObjSpaceLightDir( v.vertex ) );	
	o.viewDirT = mul( rotation, ObjSpaceViewDir( v.vertex ) );	

	TRANSFER_VERTEX_TO_FRAGMENT(o);	
	return o;
}

float _ColorAmount;
float _MaskStrength;
float _Brightness;
inline half4 SpecularMaskedLight( half3 lightDir, half3 viewDir, half3 normal, half4 color,half4 lightmap,half4 refl, float specK, half atten )
{
	#ifndef USING_DIRECTIONAL_LIGHT
	lightDir = normalize(lightDir);
	#endif
	viewDir = normalize(viewDir);
	half3 h = normalize( lightDir + viewDir );
		float3 white=(1.0,1.0,1.0);
	half diffuse = dot( normal, lightDir );
	float nh = saturate( dot( h, normal ) );
	float3 lightcontribution=mix(white,lightmap.rgb,_ColorAmount);
	float speccontribution=mix(1.0,lightmap.a,_MaskStrength);
	float3 spec = saturate(pow( nh, specK ) )*speccontribution;
	refl.rgb=(refl.rgb)*pow(nh,_CubeDimness)*lightmap.rgb;


	half4 c;
	c.rgb = ((color.rgb+refl.rgb) * _ModelLightColor0.rgb*lightcontribution * diffuse + _SpecularLightColor0.rgb*lightcontribution* spec)* (atten * 2);
	c.a = _SpecularLightColor0.a* spec * atten; // specular passes by default put highlights to overbright
	return c;
}




uniform sampler2D _BumpMap;
uniform sampler2D _MainTex;
uniform sampler2D _LightMap;
uniform samplerCUBE _Cube;

float4 frag (v2f i) : COLOR
{		
	float4 texcol = tex2D( _MainTex, i.uvK.xy );
	float4 lightmap =tex2D(_LightMap,i.uv2);
	// get normal from the normal map
	float3 normal = tex2D(_BumpMap, i.uvK.xy).xyz * 2.0 - 1.0;
	float4 reflcol = texCUBE( _Cube,i.I);

	//texcol.rgb =(texcol.rgb+(lightmap.rgb)); 
	//Uncomment for simple lightmapping
	 texcol.rgb =(texcol.rgb*(lightmap.rgb*2.0-(1-_Brightness))); 
	
	half4 c = SpecularMaskedLight( i.lightDirT, i.viewDirT, normal, texcol,lightmap,reflcol, i.uvK.z, LIGHT_ATTENUATION(i) );
	return c;
}
ENDCG  
		}
	}
	}
	FallBack "Bumped Specular", 1

}

Damn dude! You should work for Unity or something lol. Seriously that is insane! :slight_smile: I gotta try it soon as I get a chance! When you get a demo up and running you should make a new thread about it so people see it properly! :smile:

Hey MultiVac, did you ever write a version of this that works with Beast lightmaps?