// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt) // Simplified Diffuse shader. Differences from regular Diffuse one: // - no Main Color // - fully supports only 1 directional light. Other lights can affect it, but it will be per-vertex/SH. Shader "Carmen/Wood" { Properties { _MainTex ("Noise Texture", 2D) = "white" {} _Color("Colour 1", Color) = (0,0,0,1) _Color2("Colour 2", Color) = (1,1,1,1) } SubShader { Tags { "Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout" } LOD 200 CGPROGRAM #include "UnityCG.cginc" #include "UnityPBSLighting.cginc" #define _SPECULARHIGHLIGHTS_OFF #define _GLOSSYREFLECTIONS_OFF // Use our squeezed BRDF on mobile // In general we want FLOAT_MIN to be the smallest value such that (1.0f + FLOAT_MIN) != FLOAT_MIN #if defined(SHADER_API_MOBILE) #define VRC_BRDF_PBS BRDF2_VRC_PBS #define FLOAT_MIN 1e-4 #else #define VRC_BRDF_PBS UNITY_BRDF_PBS #define FLOAT_MIN 1e-6 #endif #pragma target 4.5 #pragma surface surf LambertVRC alphatest:_Cutoff exclude_path:prepass exclude_path:deferred noforwardadd UNITY_DECLARE_TEX2D(_MainTex); struct SurfaceOutputVRC { fixed3 Albedo; fixed3 Normal; fixed3 Emission; half Specular; fixed Gloss; fixed Alpha; }; struct Input { float2 uv_MainTex; half4 colour : COLOR; half4 colour2 : COLOR; }; half4 _Color; half4 _Color2; void surf (Input IN, inout SurfaceOutputVRC o) { o.Albedo = lerp(_Color, _Color2, UNITY_SAMPLE_TEX2D(_MainTex, IN.uv_MainTex).r); o.Alpha = 1.0; o.Gloss = 0.0; o.Normal = fixed3(0.0, 0.0, 1.0); } inline half3 VRC_SafeNormalize(half3 value) { float lenSqr = max((float)dot(value, value), FLOAT_MIN); return value * (half) rsqrt(lenSqr); } inline half shEvaluateDiffuseL1Geomerics(half L0, half3 L1, half3 n) { // avg direction of incoming light half3 R1 = 0.5f * L1; // directional brightness half lenR1 = length(R1); // linear angle between normal and direction 0-1, saturate fix from filamented half q = dot(VRC_SafeNormalize(R1), n) * 0.5 + 0.5; q = isnan(q) ? 1 : q; q = saturate(q); // power for q // lerps from 1 (linear) to 3 (cubic) based on directionality //half p = 1.0f + 2.0f * lenR1 / L0; // dynamic range constant // should vary between 4 (highly directional) and 0 (ambient) //half a = (1.0f - lenR1 / L0) / (1.0f + lenR1 / L0); // negative ambient fix, if L0 <= 0, return 0 //return (L0 <= 0.f) ? 0.f : (L0 * (a + (1.0f - a) * (p + 1.0f) * pow(q, p))); // optimized reordering. thanks wolfram return (L0 <= 0.f) ? 0.f : ( 4. * lenR1 * pow(q, (2 * lenR1) / L0 + 1) + ( L0 * (L0 - lenR1) )/(L0 + lenR1)); } inline UnityGI UnityGI_BaseVRC(UnityGIInput data, half occlusion, half3 normalWorld, half3 eyeVec, half smoothness, half hasReflProbe) { UnityGI o_gi; // Base pass with Lightmap support is responsible for handling ShadowMask / blending here for performance reason #if defined(HANDLE_SHADOWS_BLENDING_IN_GI) half bakedAtten = UnitySampleBakedOcclusion(data.lightmapUV.xy, data.worldPos); float zDist = dot(_WorldSpaceCameraPos - data.worldPos, UNITY_MATRIX_V[2].xyz); float fadeDist = UnityComputeShadowFadeDistance(data.worldPos, zDist); data.atten = UnityMixRealtimeAndBakedShadows(data.atten, bakedAtten, UnityComputeShadowFade(fadeDist)); #endif o_gi.light = data.light; o_gi.light.color *= data.atten; #if defined(LIGHTMAP_ON) #if defined(_MONOSH) BakeryMonoSH(o_gi.indirect.diffuse, o_gi.indirect.specular, data.lightmapUV.xy, normalWorld, eyeVec, smoothness, occlusion); #else // Baked lightmaps half3 bakedColor = half3(1.0, 1.0, 1.0); half4 bakedColorTex = UNITY_SAMPLE_TEX2D(unity_Lightmap, data.lightmapUV.xy); #if defined(FORCE_UNITY_DLDR_LIGHTMAP_ENCODING) bakedColor = DecodeLightmapDoubleLDR(bakedColorTex, unity_Lightmap_HDR); #elif defined(FORCE_UNITY_RGBM_LIGHTMAP_ENCODING) bakedColor = DecodeLightmapRGBM(bakedColorTex, unity_Lightmap_HDR); #elif defined(FORCE_UNITY_LIGHTMAP_FULL_HDR_ENCODING) bakedColor = bakedColorTex; #else bakedColor = DecodeLightmap(bakedColorTex); #endif // Can be set if the renderer has a valid lightmap but the shader doesn't use it #if !defined(UNITY_LIGHTMAP_NONE) #if defined(DIRLIGHTMAP_COMBINED) fixed4 bakedDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, data.lightmapUV.xy); o_gi.indirect.diffuse = DecodeDirectionalLightmap(bakedColor, bakedDirTex, normalWorld); #else // not directional lightmap o_gi.indirect.diffuse = bakedColor; #endif #else o_gi.indirect.diffuse = 1; #endif o_gi.indirect.specular = 0; #endif o_gi.indirect.diffuse *= occlusion; #elif defined(UNITY_SHOULD_SAMPLE_SH) o_gi.indirect.diffuse.r = shEvaluateDiffuseL1Geomerics(unity_SHAr.w, unity_SHAr.xyz, normalWorld); o_gi.indirect.diffuse.g = shEvaluateDiffuseL1Geomerics(unity_SHAg.w, unity_SHAg.xyz, normalWorld); o_gi.indirect.diffuse.b = shEvaluateDiffuseL1Geomerics(unity_SHAb.w, unity_SHAb.xyz, normalWorld); #if !defined(_SPECULARHIGHLIGHTS_OFF) UNITY_BRANCH #if !defined(_GLOSSYREFLECTIONS_OFF) if(!any(o_gi.light.color) && !hasReflProbe) #else if(!any(o_gi.light.color)) #endif { half3 L0rgb = half3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w); half3x3 L1rgb = half3x3(unity_SHAr.x, unity_SHAg.x, unity_SHAb.x, unity_SHAr.y, unity_SHAg.y, unity_SHAb.y, unity_SHAr.z, unity_SHAg.z, unity_SHAb.z); half3 L1 = unity_SHAr.xyz + unity_SHAg.xyz + unity_SHAb.xyz; half3 dominantDir = VRC_SafeNormalize(L1); // Light can be anywhere from 'fully sparse' to 'completely focused' based on how much of it is L0 or L1rgb. half L1len = length(L1); half focus = L1len / (length(L0rgb) + L1len); half specularTerm = ComputeSpecularGGX(dominantDir, eyeVec, normalWorld, smoothness * focus); // L0 + L1, the total light energy expected, is the same over the whole mesh. This is a problem with specular highlights // as they have a second peak in the negative direction - normally hidden by the fact that light energy there is normally zero. // Multiplying by non-linear diffuse gives satisfactory results, though isn't particularly physically accurate. // The brightness vs ground truth (a reflection probe) is too low though... closest we can get appears to be // a dimensionless version, shEvaluateDiffuseL1Geometrics but applied to just the ratio. half energyFactor = shEvaluateDiffuseL1Normalized(dot(L0rgb, 1), L1, normalWorld); half3 sh = (L0rgb + mul(dominantDir, L1rgb)) * energyFactor; o_gi.indirect.specular = max(specularTerm * sh, 0.0); // Reflection Probes use occlusion, direct lights don't. MonoSH and Specular Hack are both somewhere in between, // so we use focus to split the difference - 1.0 is direct, 0.0 is reflection probe, so we invert. o_gi.indirect.specular *= LerpOneTo(occlusion, 1 - focus); } else { o_gi.indirect.specular = 0; } #else o_gi.indirect.specular = 0; #endif o_gi.indirect.diffuse += data.ambient; o_gi.indirect.diffuse *= occlusion; #else o_gi.indirect.specular = 0; o_gi.indirect.diffuse = 0; #endif return o_gi; } inline fixed4 UnityLambertVRCLight (SurfaceOutputVRC s, UnityLight light) { fixed diff = max (0, dot (s.Normal, light.dir)); fixed4 c; c.rgb = s.Albedo * light.color * diff; c.a = s.Alpha; return c; } inline fixed4 LightingLambertVRC (SurfaceOutputVRC s, UnityGI gi) { fixed4 c; c = UnityLambertVRCLight (s, gi.light); #if defined(UNITY_LIGHT_FUNCTION_APPLY_INDIRECT) c.rgb += s.Albedo * gi.indirect.diffuse; #endif return c; } inline void LightingLambertVRC_GI ( SurfaceOutputVRC s, UnityGIInput data, inout UnityGI gi) { gi = UnityGI_BaseVRC(data, 1.0, s.Normal, half3(0, 0, 0), half(0), 0); } ENDCG } FallBack "Diffuse" }