Skip to content

Instantly share code, notes, and snippets.

@shivaduke28
Created March 16, 2022 17:49
Show Gist options
  • Save shivaduke28/7d2aa7fd9651d06be96f1dee9441e20a to your computer and use it in GitHub Desktop.
Save shivaduke28/7d2aa7fd9651d06be96f1dee9441e20a to your computer and use it in GitHub Desktop.
a copy of Standard shader
/*
Copyright(c) 2016 Unity Technologies
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files(the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef TKMNY_STANDARD_VARIANT_INCLUDED
#define TKMNY_STANDARD_VARIANT_INCLUDED
#include <UnityCG.cginc>
#include <UnityLightingCommon.cginc>
#include <AutoLight.cginc>
//---------------------------------------
// define
//---------------------------------------
#if (_NORMALMAP || DIRLIGHTMAP_COMBINED || _PARALLAXMAP)
#define _TANGENT_TO_WORLD 1
#endif
#if (_DETAIL_MULX2 || _DETAIL_MUL || _DETAIL_ADD || _DETAIL_LERP)
#define _DETAIL 1
#endif
#ifdef _PARALLAXMAP
#define IN_VIEWDIR4PARALLAX(i) half3(i.tangentToWorldAndPackedData[0].w,i.tangentToWorldAndPackedData[1].w,i.tangentToWorldAndPackedData[2].w)
#define IN_VIEWDIR4PARALLAX_FWDADD(i) normalize(i.viewDirForParallax.xyz)
#else
#define IN_VIEWDIR4PARALLAX(i) half3(0,0,0)
#define IN_VIEWDIR4PARALLAX_FWDADD(i) half3(0,0,0)
#endif
#if UNITY_REQUIRE_FRAG_WORLDPOS
#if UNITY_PACK_WORLDPOS_WITH_TANGENT
#define IN_WORLDPOS(i) half3(i.tangentToWorldAndPackedData[0].w,i.tangentToWorldAndPackedData[1].w,i.tangentToWorldAndPackedData[2].w)
#else
#define IN_WORLDPOS(i) i.posWorld
#endif
#define IN_WORLDPOS_FWDADD(i) i.posWorld
#else
#define IN_WORLDPOS(i) half3(0,0,0)
#define IN_WORLDPOS_FWDADD(i) half3(0,0,0)
#endif
#define UNITY_SPECCUBE_LOD_STEPS (6)
#define IN_LIGHTDIR_FWDADD(i) half3(i.tangentToWorldAndLightDir[0].w, i.tangentToWorldAndLightDir[1].w, i.tangentToWorldAndLightDir[2].w)
//---------------------------------------
// uniform
//---------------------------------------
half4 _Color;
half _Cutoff;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _DetailAlbedoMap;
float4 _DetailAlbedoMap_ST;
sampler2D _BumpMap;
half _BumpScale;
sampler2D _DetailMask;
sampler2D _DetailNormalMap;
half _DetailNormalMapScale;
sampler2D _SpecGlossMap;
sampler2D _MetallicGlossMap;
half _Metallic;
float _Glossiness;
float _GlossMapScale;
sampler2D _OcclusionMap;
half _OcclusionStrength;
sampler2D _ParallaxMap;
half _Parallax;
half _UVSec;
half4 _EmissionColor;
sampler2D _EmissionMap;
//---------------------------------------
// struct
//---------------------------------------
struct VertexInput
{
float4 vertex : POSITION;
half3 normal : NORMAL;
float2 uv0 : TEXCOORD0;
float2 uv1 : TEXCOORD1;
#if defined(DYNAMICLIGHTMAP_ON) || defined(UNITY_PASS_META)
float2 uv2 : TEXCOORD2;
#endif
#ifdef _TANGENT_TO_WORLD
half4 tangent : TANGENT;
#endif
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct VertexOutputForwardBase
{
UNITY_POSITION(pos);
float4 tex : TEXCOORD0;
float4 eyeVec : TEXCOORD1; // eyeVec.xyz | fogCoord
float4 tangentToWorldAndPackedData[3] : TEXCOORD2; // [3x3:tangentToWorld | 1x3:viewDirForParallax or worldPos]
half4 ambientOrLightmapUV : TEXCOORD5; // SH or Lightmap UV
UNITY_LIGHTING_COORDS(6, 7)
// next ones would not fit into SM2.0 limits, but they are always for SM3.0+
#if UNITY_REQUIRE_FRAG_WORLDPOS && !UNITY_PACK_WORLDPOS_WITH_TANGENT
float3 posWorld : TEXCOORD8;
#endif
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
//----------------------------------------
// functions
inline float3 Unity_SafeNormalize(float3 inVec)
{
float dp3 = max(0.001f, dot(inVec, inVec));
return inVec * rsqrt(dp3);
}
float SmoothnessToPerceptualRoughness(float smoothness)
{
return (1 - smoothness);
}
float PerceptualRoughnessToRoughness(float perceptualRoughness)
{
return perceptualRoughness * perceptualRoughness;
}
inline half OneMinusReflectivityFromMetallic(half metallic)
{
// We'll need oneMinusReflectivity, so
// 1-reflectivity = 1-lerp(dielectricSpec, 1, metallic) = lerp(1-dielectricSpec, 0, metallic)
// store (1-dielectricSpec) in unity_ColorSpaceDielectricSpec.a, then
// 1-reflectivity = lerp(alpha, 0, metallic) = alpha + metallic*(0 - alpha) =
// = alpha - metallic * alpha
half oneMinusDielectricSpec = unity_ColorSpaceDielectricSpec.a;
return oneMinusDielectricSpec - metallic * oneMinusDielectricSpec;
}
inline half3 DiffuseAndSpecularFromMetallic(half3 albedo, half metallic, out half3 specColor, out half oneMinusReflectivity)
{
specColor = lerp(unity_ColorSpaceDielectricSpec.rgb, albedo, metallic);
oneMinusReflectivity = OneMinusReflectivityFromMetallic(metallic);
return albedo * oneMinusReflectivity;
}
inline half Pow5(half x)
{
return x * x * x * x * x;
}
half2 ParallaxOffset1Step(half h, half height, half3 viewDir)
{
h = h * height - height / 2.0;
half3 v = normalize(viewDir);
v.z += 0.42;
return h * (v.xy / v.z);
}
half LerpOneTo(half b, half t)
{
half oneMinusT = 1 - t;
return oneMinusT + b * t;
}
half3 LerpWhiteTo(half3 b, half t)
{
half oneMinusT = 1 - t;
return half3(oneMinusT, oneMinusT, oneMinusT) + b * t;
}
half3 UnpackScaleNormalRGorAG(half4 packednormal, half bumpScale)
{
#if defined(UNITY_NO_DXT5nm)
half3 normal = packednormal.xyz * 2 - 1;
#if (SHADER_TARGET >= 30)
// SM2.0: instruction count limitation
// SM2.0: normal scaler is not supported
normal.xy *= bumpScale;
#endif
return normal;
#else
// This do the trick
packednormal.x *= packednormal.w;
half3 normal;
normal.xy = (packednormal.xy * 2 - 1);
#if (SHADER_TARGET >= 30)
// SM2.0: instruction count limitation
// SM2.0: normal scaler is not supported
normal.xy *= bumpScale;
#endif
normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
return normal;
#endif
}
half3 UnpackScaleNormal(half4 packednormal, half bumpScale)
{
return UnpackScaleNormalRGorAG(packednormal, bumpScale);
}
half3 BlendNormals(half3 n1, half3 n2)
{
return normalize(half3(n1.xy + n2.xy, n1.z * n2.z));
}
half3x3 CreateTangentToWorldPerVertex(half3 normal, half3 tangent, half tangentSign)
{
// For odd-negative scale transforms we need to flip the sign
half sign = tangentSign * unity_WorldTransformParams.w;
half3 binormal = cross(normal, tangent) * sign;
return half3x3(tangent, binormal, normal);
}
float4 TexCoords(VertexInput v)
{
float4 texcoord;
texcoord.xy = TRANSFORM_TEX(v.uv0, _MainTex); // Always source from uv0
texcoord.zw = TRANSFORM_TEX(((_UVSec == 0) ? v.uv0 : v.uv1), _DetailAlbedoMap);
return texcoord;
}
half DetailMask(float2 uv)
{
return tex2D(_DetailMask, uv).a;
}
half3 Albedo(float4 texcoords)
{
half3 albedo = _Color.rgb * tex2D(_MainTex, texcoords.xy).rgb;
#if _DETAIL
half mask = DetailMask(texcoords.xy);
half3 detailAlbedo = tex2D (_DetailAlbedoMap, texcoords.zw).rgb;
#if _DETAIL_MULX2
albedo *= LerpWhiteTo (detailAlbedo * unity_ColorSpaceDouble.rgb, mask);
#elif _DETAIL_MUL
albedo *= LerpWhiteTo (detailAlbedo, mask);
#elif _DETAIL_ADD
albedo += detailAlbedo * mask;
#elif _DETAIL_LERP
albedo = lerp (albedo, detailAlbedo, mask);
#endif
#endif
return albedo;
}
half Alpha(float2 uv)
{
#if defined(_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A)
return _Color.a;
#else
return tex2D(_MainTex, uv).a * _Color.a;
#endif
}
half Occlusion(float2 uv)
{
half occ = tex2D(_OcclusionMap, uv).g;
return LerpOneTo(occ, _OcclusionStrength);
}
half2 MetallicGloss(float2 uv)
{
half2 mg;
#ifdef _METALLICGLOSSMAP
#ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
mg.r = tex2D(_MetallicGlossMap, uv).r;
mg.g = tex2D(_MainTex, uv).a;
#else
mg = tex2D(_MetallicGlossMap, uv).ra;
#endif
mg.g *= _GlossMapScale;
#else
mg.r = _Metallic;
#ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
mg.g = tex2D(_MainTex, uv).a * _GlossMapScale;
#else
mg.g = _Glossiness;
#endif
#endif
return mg;
}
half3 Emission(float2 uv)
{
#ifndef _EMISSION
return 0;
#else
return tex2D(_EmissionMap, uv).rgb * _EmissionColor.rgb;
#endif
}
#ifdef _NORMALMAP
half3 NormalInTangentSpace(float4 texcoords)
{
half3 normalTangent = UnpackScaleNormal(tex2D (_BumpMap, texcoords.xy), _BumpScale);
#if _DETAIL && defined(UNITY_ENABLE_DETAIL_NORMALMAP)
half mask = DetailMask(texcoords.xy);
half3 detailNormalTangent = UnpackScaleNormal(tex2D (_DetailNormalMap, texcoords.zw), _DetailNormalMapScale);
#if _DETAIL_LERP
normalTangent = lerp(
normalTangent,
detailNormalTangent,
mask);
#else
normalTangent = lerp(
normalTangent,
BlendNormals(normalTangent, detailNormalTangent),
mask);
#endif
#endif
return normalTangent;
}
#endif
float4 Parallax(float4 texcoords, half3 viewDir)
{
#if !defined(_PARALLAXMAP)
// Disable parallax on pre-SM3.0 shader target models
return texcoords;
#else
half h = tex2D (_ParallaxMap, texcoords.xy).g;
float2 offset = ParallaxOffset1Step (h, _Parallax, viewDir);
return float4(texcoords.xy + offset, texcoords.zw + offset);
#endif
}
float3 PerPixelWorldNormal(float4 i_tex, float4 tangentToWorld[3])
{
#ifdef _NORMALMAP
half3 tangent = tangentToWorld[0].xyz;
half3 binormal = tangentToWorld[1].xyz;
half3 normal = tangentToWorld[2].xyz;
#if UNITY_TANGENT_ORTHONORMALIZE
// ortho-normalize Tangent
tangent = normalize (tangent - normal * dot(tangent, normal));
// recalculate Binormal
half3 newB = cross(normal, tangent);
binormal = newB * sign (dot (newB, binormal));
#endif
half3 normalTangent = NormalInTangentSpace(i_tex);
float3 normalWorld = normalize(tangent * normalTangent.x + binormal * normalTangent.y + normal * normalTangent.z);
#else
float3 normalWorld = normalize(tangentToWorld[2].xyz);
#endif
return normalWorld;
}
inline half3 PreMultiplyAlpha(half3 diffColor, half alpha, half oneMinusReflectivity, out half outModifiedAlpha)
{
#if defined(_ALPHAPREMULTIPLY_ON)
// NOTE: shader relies on pre-multiply alpha-blend (_SrcBlend = One, _DstBlend = OneMinusSrcAlpha)
// Transparency 'removes' from Diffuse component
diffColor *= alpha;
// Reflectivity 'removes' from the rest of components, including Transparency
// outAlpha = 1-(1-alpha)*(1-reflectivity) = 1-(oneMinusReflectivity - alpha*oneMinusReflectivity) =
// = 1-oneMinusReflectivity + alpha*oneMinusReflectivity
outModifiedAlpha = 1-oneMinusReflectivity + alpha*oneMinusReflectivity;
#else
outModifiedAlpha = alpha;
#endif
return diffColor;
}
//--------------------------------
// PBR functions
//--------------------------------
// Note: Disney diffuse must be multiply by diffuseAlbedo / PI. This is done outside of this function.
half DisneyDiffuse(half NdotV, half NdotL, half LdotH, half perceptualRoughness)
{
half fd90 = 0.5 + 2 * LdotH * LdotH * perceptualRoughness;
// Two schlick fresnel term
half lightScatter = (1 + (fd90 - 1) * Pow5(1 - NdotL));
half viewScatter = (1 + (fd90 - 1) * Pow5(1 - NdotV));
return lightScatter * viewScatter;
}
// NDF
inline float GGXTerm(float NdotH, float roughness)
{
float a2 = roughness * roughness;
float d = (NdotH * a2 - NdotH) * NdotH + 1.0f; // 2 mad
return UNITY_INV_PI * a2 / (d * d + 1e-7f); // This function is not intended to be running on Mobile,
// therefore epsilon is smaller than what can be represented by half
}
// Visibility
inline float SmithJointGGXVisibilityTerm(float NdotL, float NdotV, float roughness)
{
float a = roughness;
float lambdaV = NdotL * (NdotV * (1 - a) + a);
float lambdaL = NdotV * (NdotL * (1 - a) + a);
return 0.5f / (lambdaV + lambdaL + 1e-5f);
}
inline half3 FresnelTerm(half3 F0, half cosA)
{
half t = Pow5(1 - cosA); // ala Schlick interpoliation
return F0 + (1 - F0) * t;
}
inline half3 FresnelLerp(half3 F0, half3 F90, half cosA)
{
half t = Pow5(1 - cosA); // ala Schlick interpoliation
return lerp(F0, F90, t);
}
half4 BRDF(half3 diffColor, half3 specColor, half oneMinusReflectivity, half smoothness,
float3 normal, float3 viewDir,
UnityLight light)
{
float perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness);
float3 halfDir = Unity_SafeNormalize(float3(light.dir) + viewDir);
half nv = abs(dot(normal, viewDir)); // This abs allow to limit artifact
float nl = saturate(dot(normal, light.dir));
float nh = saturate(dot(normal, halfDir));
half lv = saturate(dot(light.dir, viewDir));
half lh = saturate(dot(light.dir, halfDir));
// Diffuse term
half diffuseTerm = DisneyDiffuse(nv, nl, lh, perceptualRoughness) * nl;
// Specular term
// HACK: theoretically we should divide diffuseTerm by Pi and not multiply specularTerm!
// BUT 1) that will make shader look significantly darker than Legacy ones
// and 2) on engine side "Non-important" lights have to be divided by Pi too in cases when they are injected into ambient SH
float roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
// GGX with roughtness to 0 would mean no specular at all, using max(roughness, 0.002) here to match HDrenderloop roughtness remapping.
roughness = max(roughness, 0.002);
float V = SmithJointGGXVisibilityTerm(nl, nv, roughness);
float D = GGXTerm(nh, roughness);
float specularTerm = V * D * UNITY_PI; // Torrance-Sparrow model, Fresnel is applied later
// specularTerm * nl can be NaN on Metal in some cases, use max() to make sure it's a sane value
specularTerm = max(0, specularTerm * nl);
#if defined(_SPECULARHIGHLIGHTS_OFF)
specularTerm = 0.0;
#endif
// To provide true Lambert lighting, we need to be able to kill specular completely.
specularTerm *= any(specColor) ? 1.0 : 0.0;
half grazingTerm = saturate(smoothness + (1 - oneMinusReflectivity));
half3 color = diffColor * (light.color * diffuseTerm) + specularTerm * light.color * FresnelTerm(specColor, lh);
return half4(color, 1);
}
//------------------------------
// GI diffuse
//-----------------------------
half3 ShadeSHPerVertex(half3 normal, half3 ambient)
{
#if UNITY_SAMPLE_FULL_SH_PER_PIXEL
// Completely per-pixel
// nothing to do here
#elif (SHADER_TARGET < 30) || UNITY_STANDARD_SIMPLE
// Completely per-vertex
ambient += max(half3(0, 0, 0), ShadeSH9(half4(normal, 1.0)));
#else
// L2 per-vertex, L0..L1 & gamma-correction per-pixel
// NOTE: SH data is always in Linear AND calculation is split between vertex & pixel
// Convert ambient to Linear and do final gamma-correction at the end (per-pixel)
#ifdef UNITY_COLORSPACE_GAMMA
ambient = GammaToLinearSpace (ambient);
#endif
ambient += SHEvalLinearL2 (half4(normal, 1.0)); // no max since this is only L2 contribution
#endif
return ambient;
}
half3 ShadeSHPerPixel(half3 normal, half3 ambient, float3 worldPos)
{
half3 ambient_contrib = 0.0;
#if UNITY_SAMPLE_FULL_SH_PER_PIXEL
// Completely per-pixel
#if UNITY_LIGHT_PROBE_PROXY_VOLUME
if (unity_ProbeVolumeParams.x == 1.0)
ambient_contrib = SHEvalLinearL0L1_SampleProbeVolume(half4(normal, 1.0), worldPos);
else
ambient_contrib = SHEvalLinearL0L1(half4(normal, 1.0));
#else
ambient_contrib = SHEvalLinearL0L1(half4(normal, 1.0));
#endif
ambient_contrib += SHEvalLinearL2(half4(normal, 1.0));
ambient += max(half3(0, 0, 0), ambient_contrib);
#else
// L2 per-vertex, L0..L1 & gamma-correction per-pixel
// Ambient in this case is expected to be always Linear, see ShadeSHPerVertex()
#if UNITY_LIGHT_PROBE_PROXY_VOLUME
if (unity_ProbeVolumeParams.x == 1.0)
ambient_contrib = SHEvalLinearL0L1_SampleProbeVolume (half4(normal, 1.0), worldPos);
else
ambient_contrib = SHEvalLinearL0L1 (half4(normal, 1.0));
#else
ambient_contrib = SHEvalLinearL0L1(half4(normal, 1.0));
#endif
ambient = max(half3(0, 0, 0), ambient + ambient_contrib); // include L2 contribution in vertex shader before clamp.
#endif
return ambient;
}
//--------------------
half3 GI_diffuse(half3 diffColor, float3 worldPos, half3 normal, half4 ambientOrLightmapUV, half atten, half occlusion)
{
half3 diffuse;
// SH
#if UNITY_SHOULD_SAMPLE_SH
diffuse = ShadeSHPerPixel(normal, ambientOrLightmapUV.rgb, worldPos);
#endif
// Baked lightmaps
#if defined(LIGHTMAP_ON)
float2 lightmapUV = ambientOrLightmapUV.xy;
half4 bakedColorTex = UNITY_SAMPLE_TEX2D(unity_Lightmap, lightmapUV);
half3 bakedColor = DecodeLightmap(bakedColorTex);
// directional mode
#ifdef DIRLIGHTMAP_COMBINED
fixed4 bakedDirTex = UNITY_SAMPLE_TEX2D_SAMPLER (unity_LightmapInd, unity_Lightmap, lightmapUV);
diffuse += DecodeDirectionalLightmap (bakedColor, bakedDirTex, normal);
#else // not directional lightmap
diffuse += bakedColor;
#endif
#if defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN)
diffuse = SubtractMainLightWithRealtimeAttenuationFromLightmap (diffuse, atten, bakedColorTex, normal);
#endif
#endif // LIGHTMAP_ON
// Dynamic lightmaps
#ifdef DYNAMICLIGHTMAP_ON
float2 dynamicLightmapUV = lightmapUV.zw;
fixed4 realtimeColorTex = UNITY_SAMPLE_TEX2D(unity_DynamicLightmap, dynamicLightmapUV);
half3 realtimeColor = DecodeRealtimeLightmap (realtimeColorTex);
#ifdef DIRLIGHTMAP_COMBINED
half4 realtimeDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicDirectionality, unity_DynamicLightmap, dynamicLightmapUV);
diffuse += DecodeDirectionalLightmap (realtimeColor, realtimeDirTex, normal);
#else
diffuse += realtimeColor;
#endif
#endif // DYNAMICLIGHTMAP_ON
diffuse *= occlusion;
return diffuse * diffColor;
}
//----------------------------
// GI Specular
//----------------------------
half3 Unity_GlossyEnvironment(UNITY_ARGS_TEXCUBE(tex), half4 hdr, half perceptualRoughness, half3 reflUVW)
{
perceptualRoughness = perceptualRoughness * (1.7 - 0.7 * perceptualRoughness);
// perceptual roughness to mipmap level
half mip = perceptualRoughness * UNITY_SPECCUBE_LOD_STEPS;
half3 R = reflUVW;
half4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(tex, R, mip);
return DecodeHDR(rgbm, hdr);
}
inline float3 BoxProjectedCubemapDirection(float3 worldRefl, float3 worldPos, float4 cubemapCenter, float4 boxMin, float4 boxMax)
{
// Do we have a valid reflection probe?
UNITY_BRANCH
if (cubemapCenter.w > 0.0)
{
float3 nrdir = normalize(worldRefl);
#if 1
float3 rbmax = (boxMax.xyz - worldPos) / nrdir;
float3 rbmin = (boxMin.xyz - worldPos) / nrdir;
float3 rbminmax = (nrdir > 0.0f) ? rbmax : rbmin;
#else // Optimized version
float3 rbmax = (boxMax.xyz - worldPos);
float3 rbmin = (boxMin.xyz - worldPos);
float3 select = step (float3(0,0,0), nrdir);
float3 rbminmax = lerp (rbmax, rbmin, select);
rbminmax /= nrdir;
#endif
float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z);
worldPos -= cubemapCenter.xyz;
worldRefl = worldPos + nrdir * fa;
}
return worldRefl;
}
inline half3 UnityGI_IndirectSpecular(UnityGIInput data, half occlusion, half perceptualRoughness, half3 reflUVW)
{
half3 specular;
#ifdef UNITY_SPECCUBE_BOX_PROJECTION
// we will tweak reflUVW in glossIn directly (as we pass it to Unity_GlossyEnvironment twice for probe0 and probe1), so keep original to pass into BoxProjectedCubemapDirection
half3 originalReflUVW = reflUVW;
reflUVW = BoxProjectedCubemapDirection (originalReflUVW, data.worldPos, data.probePosition[0], data.boxMin[0], data.boxMax[0]);
#endif
#ifdef _GLOSSYREFLECTIONS_OFF
specular = unity_IndirectSpecColor.rgb;
#else
half peceptualRoughness = perceptualRoughness;
half3 env0 = Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE(unity_SpecCube0), data.probeHDR[0], peceptualRoughness, reflUVW);
#ifdef UNITY_SPECCUBE_BLENDING
const float kBlendFactor = 0.99999;
float blendLerp = data.boxMin[0].w;
UNITY_BRANCH
if (blendLerp < kBlendFactor)
{
#ifdef UNITY_SPECCUBE_BOX_PROJECTION
reflUVW = BoxProjectedCubemapDirection (originalReflUVW, data.worldPos, data.probePosition[1], data.boxMin[1], data.boxMax[1]);
#endif
half3 env1 = Unity_GlossyEnvironment (UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1,unity_SpecCube0), data.probeHDR[1], peceptualRoughness, reflUVW);
specular = lerp(env1, env0, blendLerp);
}
else
{
specular = env0;
}
#else
specular = env0;
#endif
#endif
return specular * occlusion;
}
half3 GI_specular(half3 specColor, half smoothness, half percepstualRoughness, half roughness, half3 normal, half3 view, half nv, half occlusion, half oneMinusReflectivity)
{
half3 specular;
half3 reflUVW = reflect(-view, normal);
UnityGIInput d;
d.probeHDR[0] = unity_SpecCube0_HDR;
d.probeHDR[1] = unity_SpecCube1_HDR;
#if defined(UNITY_SPECCUBE_BLENDING) || defined(UNITY_SPECCUBE_BOX_PROJECTION)
d.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending
#endif
#ifdef UNITY_SPECCUBE_BOX_PROJECTION
d.boxMax[0] = unity_SpecCube0_BoxMax;
d.probePosition[0] = unity_SpecCube0_ProbePosition;
d.boxMax[1] = unity_SpecCube1_BoxMax;
d.boxMin[1] = unity_SpecCube1_BoxMin;
d.probePosition[1] = unity_SpecCube1_ProbePosition;
#endif
// reflection probes and ambient reflection
half3 gi_specular = UnityGI_IndirectSpecular(d, occlusion, percepstualRoughness, reflUVW);
half grazingTerm = saturate(smoothness + (1 - oneMinusReflectivity));
half surfaceReduction = 1.0 / (roughness * roughness + 1.0); // fade \in [0.5;1]
return surfaceReduction * gi_specular * FresnelLerp(specColor, grazingTerm, nv);
}
//--------------------------------------------
// vertex function
//--------------------------------------------
VertexOutputForwardBase vertBase(VertexInput v)
{
UNITY_SETUP_INSTANCE_ID(v);
VertexOutputForwardBase o;
UNITY_INITIALIZE_OUTPUT(VertexOutputForwardBase, o);
UNITY_TRANSFER_INSTANCE_ID(v, o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
float3 posWorld = mul(unity_ObjectToWorld, v.vertex);
// world position
#if UNITY_REQUIRE_FRAG_WORLDPOS
#if UNITY_PACK_WORLDPOS_WITH_TANGENT
o.tangentToWorldAndPackedData[0].w = posWorld.x;
o.tangentToWorldAndPackedData[1].w = posWorld.y;
o.tangentToWorldAndPackedData[2].w = posWorld.z;
#else
o.posWorld = posWorld;
#endif
#endif
// clip position
o.pos = UnityObjectToClipPos(v.vertex);
// uv
o.tex = TexCoords(v);
o.eyeVec.xyz = posWorld.xyz - _WorldSpaceCameraPos;
// normal
float3 normalWorld = UnityObjectToWorldNormal(v.normal);
#ifdef _TANGENT_TO_WORLD
float4 tangentWorld = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w);
float3x3 tangentToWorld = CreateTangentToWorldPerVertex(normalWorld, tangentWorld.xyz, tangentWorld.w);
o.tangentToWorldAndPackedData[0].xyz = tangentToWorld[0];
o.tangentToWorldAndPackedData[1].xyz = tangentToWorld[1];
o.tangentToWorldAndPackedData[2].xyz = tangentToWorld[2];
#else
o.tangentToWorldAndPackedData[0].xyz = 0;
o.tangentToWorldAndPackedData[1].xyz = 0;
o.tangentToWorldAndPackedData[2].xyz = normalWorld;
#endif
// light coord and shadow coord (AutoLight.cginc)
UNITY_TRANSFER_LIGHTING(o, v.uv1);
// ambient and lightmap uv
half4 ambientOrLightmapUV = 0;
#ifdef LIGHTMAP_ON
ambientOrLightmapUV.xy = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
ambientOrLightmapUV.zw = 0;
#elif UNITY_SHOULD_SAMPLE_SH
#ifdef VERTEXLIGHT_ON
// Approximated illumination from non-important point lights
ambientOrLightmapUV.rgb = Shade4PointLights (
unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
unity_4LightAtten0, posWorld, normalWorld);
#endif
ambientOrLightmapUV.rgb = ShadeSHPerVertex (normalWorld, ambientOrLightmapUV.rgb);
#endif
// realtime gi
#ifdef DYNAMICLIGHTMAP_ON
ambientOrLightmapUV.zw = v.uv2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
#endif
o.ambientOrLightmapUV = ambientOrLightmapUV;
// parallax
#ifdef _PARALLAXMAP
TANGENT_SPACE_ROTATION;
half3 viewDirForParallax = mul (rotation, ObjSpaceViewDir(v.vertex));
o.tangentToWorldAndPackedData[0].w = viewDirForParallax.x;
o.tangentToWorldAndPackedData[1].w = viewDirForParallax.y;
o.tangentToWorldAndPackedData[2].w = viewDirForParallax.z;
#endif
// fog
UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o,o.pos);
return o;
}
//--------------------------------------------
// fragment function
//--------------------------------------------
fixed4 fragBase(VertexOutputForwardBase i) : SV_Target
{
UNITY_APPLY_DITHER_CROSSFADE(i.pos.xy);
// uv
float4 i_tex = i.tex;
// parallax
i_tex = Parallax(i_tex, IN_VIEWDIR4PARALLAX(i));
// alpha
half alpha = Alpha(i_tex.xy);
// alpha test
#if defined(_ALPHATEST_ON)
clip (alpha - _Cutoff);
#endif
// p, n, v
float3 worldPos = IN_WORLDPOS(i);
half3 normal = PerPixelWorldNormal(i_tex, i.tangentToWorldAndPackedData);
half3 eyeVec = normalize(i.eyeVec.xyz);
half3 view = -eyeVec;
half nv = max(0, dot(normal, view));
// surface data
half2 metallicGloss = MetallicGloss(i_tex.xy);
half metallic = metallicGloss.x;
half smoothness = metallicGloss.y; // this is 1 minus the square root of real roughness m.
half perceptualRoughness = 1 - smoothness;
half roughness = perceptualRoughness * perceptualRoughness;
half oneMinusReflectivity;
half3 specColor;
half3 diffColor = DiffuseAndSpecularFromMetallic(Albedo(i_tex), metallic, /*out*/specColor, /*out*/oneMinusReflectivity);
// NOTE: shader relies on pre-multiply alpha-blend (_SrcBlend = One, _DstBlend = OneMinusSrcAlpha)
diffColor = PreMultiplyAlpha(diffColor, alpha, oneMinusReflectivity, /*out*/alpha);
UNITY_SETUP_INSTANCE_ID(i);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
// occlusion
half occlusion = tex2D(_OcclusionMap, i.tex.xy).g;
occlusion = LerpOneTo(occlusion, _OcclusionStrength);
// shadowing
UNITY_LIGHT_ATTENUATION(atten, i, worldPos);
// GI
half3 gi_diffuse = GI_diffuse(diffColor, worldPos, normal, i.ambientOrLightmapUV, atten, occlusion);
half3 gi_specular = GI_specular(specColor, smoothness, perceptualRoughness, roughness, normal, view, nv, occlusion, oneMinusReflectivity);
// main directional light
UnityLight mainLight;
#if defined(LIGHTMAP_ON) && defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN)
mainLight.color = half3(0, 0, 0);
mainLight.dir = half3(0, 1, 0);
#else
mainLight.color = _LightColor0.rgb * atten;
mainLight.dir = _WorldSpaceLightPos0.xyz;
#endif
// brdf
half4 output = BRDF(diffColor, specColor, oneMinusReflectivity, smoothness, normal, view, mainLight);
// emission
output.rgb += Emission(i.tex.xy);
// fog
UNITY_EXTRACT_FOG_FROM_EYE_VEC(i);
UNITY_APPLY_FOG(_unity_fogCoord, c.rgb);
// alpha
#if defined(_ALPHABLEND_ON) || defined(_ALPHAPREMULTIPLY_ON)
output.a = s.alpha;
#else
output.a = 1;
#endif
return output;
}
// ------------------------------------------------------------------
// Additive forward pass (one light per pass)
struct VertexOutputForwardAdd
{
UNITY_POSITION(pos);
float4 tex : TEXCOORD0;
float4 eyeVec : TEXCOORD1; // eyeVec.xyz | fogCoord
float4 tangentToWorldAndLightDir[3] : TEXCOORD2; // [3x3:tangentToWorld | 1x3:lightDir]
float3 posWorld : TEXCOORD5;
UNITY_LIGHTING_COORDS(6, 7)
// next ones would not fit into SM2.0 limits, but they are always for SM3.0+
#if defined(_PARALLAXMAP)
half3 viewDirForParallax : TEXCOORD8;
#endif
UNITY_VERTEX_OUTPUT_STEREO
};
VertexOutputForwardAdd vertAdd(VertexInput v)
{
UNITY_SETUP_INSTANCE_ID(v);
VertexOutputForwardAdd o;
UNITY_INITIALIZE_OUTPUT(VertexOutputForwardAdd, o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
float4 posWorld = mul(unity_ObjectToWorld, v.vertex);
o.pos = UnityObjectToClipPos(v.vertex);
o.tex = TexCoords(v);
o.eyeVec.xyz = posWorld.xyz - _WorldSpaceCameraPos;
o.posWorld = posWorld.xyz;
float3 normalWorld = UnityObjectToWorldNormal(v.normal);
#ifdef _TANGENT_TO_WORLD
float4 tangentWorld = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w);
float3x3 tangentToWorld = CreateTangentToWorldPerVertex(normalWorld, tangentWorld.xyz, tangentWorld.w);
o.tangentToWorldAndLightDir[0].xyz = tangentToWorld[0];
o.tangentToWorldAndLightDir[1].xyz = tangentToWorld[1];
o.tangentToWorldAndLightDir[2].xyz = tangentToWorld[2];
#else
o.tangentToWorldAndLightDir[0].xyz = 0;
o.tangentToWorldAndLightDir[1].xyz = 0;
o.tangentToWorldAndLightDir[2].xyz = normalWorld;
#endif
//We need this for shadow receiving and lighting
UNITY_TRANSFER_LIGHTING(o, v.uv1);
float3 lightDir = _WorldSpaceLightPos0.xyz - posWorld.xyz * _WorldSpaceLightPos0.w;
o.tangentToWorldAndLightDir[0].w = lightDir.x;
o.tangentToWorldAndLightDir[1].w = lightDir.y;
o.tangentToWorldAndLightDir[2].w = lightDir.z;
#ifdef _PARALLAXMAP
TANGENT_SPACE_ROTATION;
o.viewDirForParallax = mul(rotation, ObjSpaceViewDir(v.vertex));
#endif
UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o, o.pos);
return o;
}
half4 fragAdd(VertexOutputForwardAdd i) : SV_Target // backward compatibility (this used to be the fragment entry function)
{
UNITY_APPLY_DITHER_CROSSFADE(i.pos.xy);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
// uv
float4 i_tex = i.tex;
// parallax
i_tex = Parallax(i_tex, IN_VIEWDIR4PARALLAX_FWDADD(i));
// alpha
half alpha = Alpha(i_tex.xy);
// p, n, v
float3 worldPos = IN_WORLDPOS_FWDADD(i);
half3 normal = PerPixelWorldNormal(i_tex, i.tangentToWorldAndLightDir);
half3 eyeVec = normalize(i.eyeVec.xyz);
half3 view = -eyeVec;
half nv = max(0, dot(normal, view));
// surface data
half2 metallicGloss = MetallicGloss(i_tex.xy);
half metallic = metallicGloss.x;
half smoothness = metallicGloss.y; // this is 1 minus the square root of real roughness m.
half perceptualRoughness = 1 - smoothness;
half roughness = perceptualRoughness * perceptualRoughness;
half oneMinusReflectivity;
half3 specColor;
half3 diffColor = DiffuseAndSpecularFromMetallic(Albedo(i_tex), metallic, /*out*/specColor, /*out*/oneMinusReflectivity);
// NOTE: shader relies on pre-multiply alpha-blend (_SrcBlend = One, _DstBlend = OneMinusSrcAlpha)
diffColor = PreMultiplyAlpha(diffColor, alpha, oneMinusReflectivity, /*out*/alpha);
// shadow
UNITY_LIGHT_ATTENUATION(atten, i, worldPos)
// additional light
UnityLight light;
light.color = _LightColor0.rgb;
light.dir = IN_LIGHTDIR_FWDADD(i);
#ifndef USING_DIRECTIONAL_LIGHT
light.dir = normalize(light.dir);
#endif
light.color *= atten;
half4 output = BRDF(diffColor, specColor, oneMinusReflectivity, smoothness, normal, view, light);
// fog
UNITY_EXTRACT_FOG_FROM_EYE_VEC(i);
UNITY_APPLY_FOG_COLOR(_unity_fogCoord, c.rgb, half4(0,0,0,0)); // fog towards black in additive pass
// alpha
#if defined(_ALPHABLEND_ON) || defined(_ALPHAPREMULTIPLY_ON)
output.a = s.alpha;
#else
output.a = 1;
#endif
return output;
}
#endif
/*
Copyright(c) 2016 Unity Technologies
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files(the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
Shader "TKMNY/StandardVariant"
{
Properties
{
_Color("Color", Color) = (1,1,1,1)
_MainTex("Albedo", 2D) = "white" {}
_Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5
_Glossiness("Smoothness", Range(0.0, 1.0)) = 0.5
_GlossMapScale("Smoothness Scale", Range(0.0, 1.0)) = 1.0
[Enum(Metallic Alpha,0,Albedo Alpha,1)] _SmoothnessTextureChannel("Smoothness texture channel", Float) = 0
[Gamma] _Metallic("Metallic", Range(0.0, 1.0)) = 0.0
_MetallicGlossMap("Metallic", 2D) = "white" {}
[ToggleOff] _SpecularHighlights("Specular Highlights", Float) = 1.0
[ToggleOff] _GlossyReflections("Glossy Reflections", Float) = 1.0
_BumpScale("Scale", Float) = 1.0
_BumpMap("Normal Map", 2D) = "bump" {}
_Parallax("Height Scale", Range(0.005, 0.08)) = 0.02
_ParallaxMap("Height Map", 2D) = "black" {}
_OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0
_OcclusionMap("Occlusion", 2D) = "white" {}
_EmissionColor("Color", Color) = (0,0,0)
_EmissionMap("Emission", 2D) = "white" {}
_DetailMask("Detail Mask", 2D) = "white" {}
_DetailAlbedoMap("Detail Albedo x2", 2D) = "grey" {}
_DetailNormalMapScale("Scale", Float) = 1.0
_DetailNormalMap("Normal Map", 2D) = "bump" {}
[Enum(UV0,0,UV1,1)] _UVSec("UV Set for secondary textures", Float) = 0
// Blending state
[HideInInspector] _Mode("__mode", Float) = 0.0
[HideInInspector] _SrcBlend("__src", Float) = 1.0
[HideInInspector] _DstBlend("__dst", Float) = 0.0
[HideInInspector] _ZWrite("__zw", Float) = 1.0
}
CGINCLUDE
#define UNITY_SETUP_BRDF_INPUT MetallicSetup
ENDCG
SubShader
{
Tags { "RenderType" = "Opaque" "PerformanceChecks" = "False" }
LOD 300
Pass
{
Name "FORWARD"
Tags { "LightMode" = "ForwardBase" }
Blend[_SrcBlend][_DstBlend]
ZWrite[_ZWrite]
CGPROGRAM
#pragma target 3.0
#pragma shader_feature _NORMALMAP
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
#pragma shader_feature _EMISSION
#pragma shader_feature _METALLICGLOSSMAP
#pragma shader_feature ___ _DETAIL_MULX2
#pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature _ _SPECULARHIGHLIGHTS_OFF
#pragma shader_feature _ _GLOSSYREFLECTIONS_OFF
#pragma shader_feature _PARALLAXMAP
#pragma shader_feature _KANIKAMA_MODE_SINGLE _KANIKAMA_MODE_ARRAY _KANIKAMA_MODE_DIRECTIONAL
#pragma multi_compile_fwdbase
#pragma multi_compile_fog
#pragma multi_compile_instancing
#pragma vertex vertBase
#pragma fragment fragBase
#include <StandardVariant.hlsl>
ENDCG
}
Pass
{
Name "FORWARD_DELTA"
Tags { "LightMode" = "ForwardAdd" }
Blend[_SrcBlend] One
Fog { Color(0,0,0,0) } // in additive pass fog should be black
ZWrite Off
ZTest LEqual
CGPROGRAM
#pragma target 3.0
#pragma shader_feature _NORMALMAP
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
#pragma shader_feature _METALLICGLOSSMAP
#pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature _ _SPECULARHIGHLIGHTS_OFF
#pragma shader_feature ___ _DETAIL_MULX2
#pragma shader_feature _PARALLAXMAP
#pragma multi_compile_fwdadd_fullshadows
#pragma multi_compile_fog
#pragma vertex vertBase
#pragma fragment fragBase
#include <StandardVariant.hlsl>
ENDCG
}
Pass
{
Name "ShadowCaster"
Tags { "LightMode" = "ShadowCaster" }
ZWrite On ZTest LEqual
CGPROGRAM
#pragma target 3.0
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
#pragma shader_feature _METALLICGLOSSMAP
#pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature _PARALLAXMAP
#pragma multi_compile_shadowcaster
#pragma multi_compile_instancing
#pragma vertex vertShadowCaster
#pragma fragment fragShadowCaster
#include "UnityStandardShadow.cginc"
ENDCG
}
Pass
{
Name "META"
Tags { "LightMode" = "Meta" }
Cull Off
CGPROGRAM
#pragma vertex vert_meta
#pragma fragment frag_meta
#pragma shader_feature _EMISSION
#pragma shader_feature _METALLICGLOSSMAP
#pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature ___ _DETAIL_MULX2
#pragma shader_feature EDITOR_VISUALIZATION
#include "UnityStandardMeta.cginc"
ENDCG
}
}
FallBack "VertexLit"
CustomEditor "StandardShaderGUI"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment