My friend wants a shader which has just about all the features that a piece of glass could possibly have - transparency, the ability to distort things behind it, variable tinting, transmission of light through it, and being Beast-aware.
I have all of those plugged in, but now I’m stuck on adding another feature - fresnel cubemap reflection, which needs to be normal-aware.
My current attempt was based on taking a procedurally-generated cubemap shader (using surface shader code), and adding that to my previous shader. Unfortunately the cubemap (although it behaves well enough), overrides nearly all of the features of the existing code.
My current code is below, and I’m hoping someone can help me work out where I’ve gone wrong…
Shader "AV/Glass/AVStained BumpDistort Transparent CubeTest 001" {
Properties {
_BumpAmt ("Distortion", range (0,128)) = 10
_MainTex ("Tint Color (RGB), Transparency (A)", 2D) = "white" {}
_BumpMap ("Normalmap", 2D) = "bump" {}
_TransparencyLM ("Transmissive Colour", 2D) = "white" {}
_SamplerCube0("CubeMap", CUBE) = "" {}
}
SubShader
{
Tags
{
"RenderType"="Opaque"
}
CGPROGRAM
#pragma surface surf BlinnPhongEditor
struct EditorSurfaceOutput {
half3 Albedo;
half3 Normal;
half3 Emission;
half3 Gloss;
half Specular;
half Alpha;
};
inline half4 LightingBlinnPhongEditor (EditorSurfaceOutput s, half3 lightDir, half3 viewDir, half atten)
{
#ifndef USING_DIRECTIONAL_LIGHT
lightDir = normalize(lightDir);
#endif
viewDir = normalize(viewDir);
half3 h = normalize (lightDir + viewDir);
half diff = max (0, dot (s.Normal, lightDir));
float nh = max (0, dot (s.Normal, h));
float3 spec = pow (nh, s.Specular*128.0) * s.Gloss;
half4 c;
c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * spec) * (atten * 2);
c.a = s.Alpha + _LightColor0.a * Luminance(spec) * atten;
return c;
}
inline half4 LightingBlinnPhongEditor_PrePass (EditorSurfaceOutput s, half4 light)
{
half3 spec = light.a * s.Gloss;
half4 c;
c.rgb = (s.Albedo * light.rgb + light.rgb * spec);
c.a = s.Alpha + Luminance(spec);
return c;
}
struct Input {
float3 viewDir;
};
samplerCUBE _SamplerCube0;
void surf (Input IN, inout EditorSurfaceOutput o) {
o.Albedo = 0.0;
o.Normal = float3(0.0,0.0,1.0);
o.Emission = 0.0;
o.Gloss = 0.0;
o.Specular = 0.0;
o.Alpha = 1.0;
float4 TexCUBE0=texCUBE(_SamplerCube0,float4(IN.viewDir, 1.0));
float4 Master0_Normal_NoInput = float4(0,0,1,1);
float4 Master0_Emission_NoInput = float4(0,0,0,0);
float4 Master0_Specular_NoInput = float4(0,0,0,0);
float4 Master0_Gloss_NoInput = float4(0,0,0,0);
float4 Master0_Alpha_NoInput = float4(0,0,0,0);
float4 Multiply3=float4(IN.viewDir, 1.0) * float4( -1);
float4 TexCUBE1 = TexCUBE0 * float4( 1.0 - dot( normalize( float4(IN.viewDir, 1.0).xyz), normalize( Multiply3.xyz ) ) );
o.Albedo = TexCUBE1;
o.Normal = float3( 0.0, 0.0, 1.0);
o.Alpha = 1.0;
}
ENDCG
}
CGINCLUDE
#pragma fragmentoption ARB_precision_hint_fastest
#pragma fragmentoption ARB_fog_exp2
#include "UnityCG.cginc"
sampler2D _GrabTexture : register(s0);
float4 _GrabTexture_TexelSize;
sampler2D _BumpMap : register(s1);
sampler2D _MainTex : register(s2);
struct v2f {
float4 vertex : POSITION;
float4 uvgrab : TEXCOORD0;
float2 uvbump : TEXCOORD1;
float2 uvmain : TEXCOORD2;
};
uniform float _BumpAmt;
half4 frag( v2f i ) : COLOR
{
// calculate perturbed coordinates
half2 bump = UnpackNormal(tex2D( _BumpMap, i.uvbump )).rg; // we could optimize this by just reading the x y without reconstructing the Z
float2 offset = bump * _BumpAmt * _GrabTexture_TexelSize.xy;
i.uvgrab.xy = offset * i.uvgrab.z + i.uvgrab.xy;
half4 col = tex2Dproj( _GrabTexture, i.uvgrab.xyw );
half4 tint = tex2D( _MainTex, i.uvmain );
return col * tint;
}
ENDCG
Category {
// We must be transparent, so other objects are drawn before this one.
Tags { "Queue"="Transparent" "RenderType"="Opaque" }
SubShader {
// This pass grabs the screen behind the object into a texture.
// We can access the result in the next pass as _GrabTexture
GrabPass {
Name "BASE"
Tags { "LightMode" = "Always" }
}
// Main pass: Take the texture grabbed above and use the bumpmap to perturb it
// on to the screen
Pass {
Name "BASE"
Tags { "LightMode" = "Always" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct appdata_t {
float4 vertex : POSITION;
float2 texcoord: TEXCOORD0;
};
v2f vert (appdata_t v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
#if UNITY_UV_STARTS_AT_TOP
float scale = -1.0;
#else
float scale = 1.0;
#endif
o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5;
o.uvgrab.zw = o.vertex.zw;
o.uvbump = MultiplyUV( UNITY_MATRIX_TEXTURE1, v.texcoord );
o.uvmain = MultiplyUV( UNITY_MATRIX_TEXTURE2, v.texcoord );
return o;
}
ENDCG
}
}
}
}
The right door has the functional glass, with lighting-aware transparency, normal-map distortion, etc.
The left door has the same code, but with a procedurally-generated cubemap included.
As you can see, the new shader’s cubemapping overrides almost everything else.
