#ifndef AVATAR_UTIL_CG_INCLUDED #define AVATAR_UTIL_CG_INCLUDED #include "UnityCG.cginc" #define SAMPLE_MODE_COLOR 0 #define SAMPLE_MODE_TEXTURE 1 #define SAMPLE_MODE_TEXTURE_SINGLE_CHANNEL 2 #define SAMPLE_MODE_PARALLAX 3 #define SAMPLE_MODE_RSRM 4 #define MASK_TYPE_NONE 0 #define MASK_TYPE_POSITIONAL 1 #define MASK_TYPE_REFLECTION 2 #define MASK_TYPE_FRESNEL 3 #define MASK_TYPE_PULSE 4 #define BLEND_MODE_ADD 0 #define BLEND_MODE_MULTIPLY 1 #ifdef LAYERS_1 #define LAYER_COUNT 1 #elif LAYERS_2 #define LAYER_COUNT 2 #elif LAYERS_3 #define LAYER_COUNT 3 #elif LAYERS_4 #define LAYER_COUNT 4 #elif LAYERS_5 #define LAYER_COUNT 5 #elif LAYERS_6 #define LAYER_COUNT 6 #elif LAYERS_7 #define LAYER_COUNT 7 #elif LAYERS_8 #define LAYER_COUNT 8 #endif #define DECLARE_LAYER_UNIFORMS(index) \ int _LayerSampleMode##index; \ int _LayerBlendMode##index; \ int _LayerMaskType##index; \ fixed4 _LayerColor##index; \ sampler2D _LayerSurface##index; \ float4 _LayerSurface##index##_ST; \ float4 _LayerSampleParameters##index; \ float4 _LayerMaskParameters##index; \ float4 _LayerMaskAxis##index; DECLARE_LAYER_UNIFORMS(0) DECLARE_LAYER_UNIFORMS(1) DECLARE_LAYER_UNIFORMS(2) DECLARE_LAYER_UNIFORMS(3) DECLARE_LAYER_UNIFORMS(4) DECLARE_LAYER_UNIFORMS(5) DECLARE_LAYER_UNIFORMS(6) DECLARE_LAYER_UNIFORMS(7) struct VertexOutput { float4 pos : SV_POSITION; float2 texcoord : TEXCOORD0; float3 worldPos : TEXCOORD1; float3 worldNormal : TEXCOORD2; float3 viewDir : TEXCOORD3; float4 vertColor : COLOR; #if NORMAL_MAP_ON || PARALLAX_ON float3 worldTangent : TANGENT; float3 worldBitangent : TEXCOORD5; #endif }; float _Alpha; int _BaseMaskType; float4 _BaseMaskParameters; float4 _BaseMaskAxis; fixed4 _DarkMultiplier; fixed4 _BaseColor; sampler2D _AlphaMask; float4 _AlphaMask_ST; sampler2D _AlphaMask2; float4 _AlphaMask2_ST; sampler2D _NormalMap; float4 _NormalMap_ST; sampler2D _ParallaxMap; float4 _ParallaxMap_ST; sampler2D _RoughnessMap; float4 _RoughnessMap_ST; float4x4 _ProjectorWorldToLocal; VertexOutput vert(appdata_full v) { VertexOutput o; UNITY_INITIALIZE_OUTPUT(VertexOutput, o); o.texcoord = v.texcoord.xy; o.worldPos = mul(unity_ObjectToWorld, v.vertex); o.vertColor = v.color; o.viewDir = normalize(_WorldSpaceCameraPos.xyz - o.worldPos); o.worldNormal = normalize(mul(unity_ObjectToWorld, float4(v.normal, 0.0)).xyz); #if NORMAL_MAP_ON || PARALLAX_ON o.worldTangent = normalize(mul(unity_ObjectToWorld, float4(v.tangent.xyz, 0.0)).xyz); o.worldBitangent = normalize(cross(o.worldNormal, o.worldTangent) * v.tangent.w); #endif o.pos = UnityObjectToClipPos(v.vertex); return o; } #ifndef NORMAL_MAP_ON #define COMPUTE_NORMAL IN.worldNormal #else #define COMPUTE_NORMAL normalize(mul(lerp(float3(0, 0, 1), surfaceNormal, normalMapStrength), tangentTransform)) #endif float3 ComputeColor( VertexOutput IN, float2 uv, #if PARALLAX_ON || NORMAL_MAP_ON float3x3 tangentTransform, #endif #ifdef NORMAL_MAP_ON float3 surfaceNormal, #endif sampler2D surface, float4 surface_ST, fixed4 color, int sampleMode, float4 sampleParameters ) { if (sampleMode == SAMPLE_MODE_TEXTURE) { float2 panning = _Time.g * sampleParameters.xy; return tex2D(surface, (uv + panning) * surface_ST.xy + surface_ST.zw).rgb * color.rgb; } else if (sampleMode == SAMPLE_MODE_TEXTURE_SINGLE_CHANNEL) { float4 channelMask = sampleParameters; float4 channels = tex2D(surface, uv * surface_ST.xy + surface_ST.zw); return dot(channels, channelMask) * color.rgb; } #ifdef PARALLAX_ON else if (sampleMode == SAMPLE_MODE_PARALLAX) { float parallaxMinHeight = sampleParameters.x; float parallaxMaxHeight = sampleParameters.y; float parallaxValue = tex2D(_ParallaxMap, TRANSFORM_TEX(uv, _ParallaxMap)).r; float scaledHeight = lerp(parallaxMinHeight, parallaxMaxHeight, parallaxValue); float2 parallaxUV = mul(tangentTransform, IN.viewDir).xy * scaledHeight; return tex2D(surface, (uv * surface_ST.xy + surface_ST.zw) + parallaxUV).rgb * color.rgb; } #endif else if (sampleMode == SAMPLE_MODE_RSRM) { float roughnessMin = sampleParameters.x; float roughnessMax = sampleParameters.y; #ifdef ROUGHNESS_ON float roughnessValue = tex2D(_RoughnessMap, TRANSFORM_TEX(uv, _RoughnessMap)).r; float scaledRoughness = lerp(roughnessMin, roughnessMax, roughnessValue); #else float scaledRoughness = roughnessMin; #endif #ifdef NORMAL_MAP_ON float normalMapStrength = sampleParameters.z; #endif float3 viewReflect = reflect(-IN.viewDir, COMPUTE_NORMAL); float viewAngle = viewReflect.y * 0.5 + 0.5; return tex2D(surface, float2(scaledRoughness, viewAngle)).rgb * color.rgb; } return color.rgb; } float ComputeMask( VertexOutput IN, #ifdef NORMAL_MAP_ON float3x3 tangentTransform, float3 surfaceNormal, #endif int maskType, float4 layerParameters, float3 maskAxis ) { if (maskType == MASK_TYPE_POSITIONAL) { float centerDistance = layerParameters.x; float fadeAbove = layerParameters.y; float fadeBelow = layerParameters.z; float3 objPos = mul(unity_WorldToObject, float4(IN.worldPos, 1.0)).xyz; float d = dot(objPos, maskAxis); if (d > centerDistance) { return saturate(1.0 - (d - centerDistance) / fadeAbove); } else { return saturate(1.0 - (centerDistance - d) / fadeBelow); } } else if (maskType == MASK_TYPE_REFLECTION) { float fadeStart = layerParameters.x; float fadeEnd = layerParameters.y; #ifdef NORMAL_MAP_ON float normalMapStrength = layerParameters.z; #endif float power = layerParameters.w; float3 viewReflect = reflect(-IN.viewDir, COMPUTE_NORMAL); float d = max(0.0, dot(viewReflect, maskAxis)); return saturate(1.0 - (d - fadeStart) / (fadeEnd - fadeStart)); } else if (maskType == MASK_TYPE_FRESNEL) { float power = layerParameters.x; float fadeStart = layerParameters.y; float fadeEnd = layerParameters.z; #ifdef NORMAL_MAP_ON float normalMapStrength = layerParameters.w; #endif float d = saturate(1.0 - max(0.0, dot(IN.viewDir, COMPUTE_NORMAL))); float p = pow(d, power); return saturate(lerp(fadeStart, fadeEnd, p)); } else if (maskType == MASK_TYPE_PULSE) { float distance = layerParameters.x; float speed = layerParameters.y; float power = layerParameters.z; float3 objPos = mul(unity_WorldToObject, float4(IN.worldPos, 1.0)).xyz; float d = dot(objPos, maskAxis); float theta = 6.2831 * frac((d - _Time.g * speed) / distance); return saturate(pow((sin(theta) * 0.5 + 0.5), power)); } else { return 1.0; } } float3 ComputeBlend(float3 source, float3 blend, float mask, int blendMode) { if (blendMode == BLEND_MODE_MULTIPLY) { return source * (blend * mask); } else { return source + (blend * mask); } } float4 ComputeSurface(VertexOutput IN) { #if PROJECTOR_ON float3 projectorPos = mul(_ProjectorWorldToLocal, float4(IN.worldPos, 1.0)).xyz; if (abs(projectorPos.x) > 1.0 || abs(projectorPos.y) > 1.0 || abs(projectorPos.z) > 1.0) { discard; } float2 uv = projectorPos.xy * 0.5 + 0.5; #else float2 uv = IN.texcoord.xy; #endif fixed4 c = _BaseColor; IN.worldNormal = normalize(IN.worldNormal); #if PARALLAX_ON || NORMAL_MAP_ON float3x3 tangentTransform = float3x3(IN.worldTangent, IN.worldBitangent, IN.worldNormal); #endif #ifdef NORMAL_MAP_ON float3 surfaceNormal = UnpackNormal(tex2D(_NormalMap, TRANSFORM_TEX(uv, _NormalMap))); #endif #if PARALLAX_ON || NORMAL_MAP_ON #ifndef NORMAL_MAP_ON #define COLOR_INPUTS IN, uv, tangentTransform #define MASK_INPUTS IN #else #define COLOR_INPUTS IN, uv, tangentTransform, surfaceNormal #define MASK_INPUTS IN, tangentTransform, surfaceNormal #endif #else #define COLOR_INPUTS IN, uv #define MASK_INPUTS IN #endif #define LAYER_COLOR(index) ComputeColor(COLOR_INPUTS, _LayerSurface##index, _LayerSurface##index##_ST, _LayerColor##index, _LayerSampleMode##index, _LayerSampleParameters##index) #define LAYER_MASK(index) ComputeMask(MASK_INPUTS, _LayerMaskType##index, _LayerMaskParameters##index, _LayerMaskAxis##index##.xyz) #define LAYER_BLEND(index, c) ComputeBlend(c, LAYER_COLOR(index), LAYER_MASK(index), _LayerBlendMode##index) c.rgb = LAYER_BLEND(0, c.rgb); #if LAYER_COUNT > 1 c.rgb = LAYER_BLEND(1, c.rgb); #endif #if LAYER_COUNT > 2 c.rgb = LAYER_BLEND(2, c.rgb); #endif #if LAYER_COUNT > 3 c.rgb = LAYER_BLEND(3, c.rgb); #endif #if LAYER_COUNT > 4 c.rgb = LAYER_BLEND(4, c.rgb); #endif #if LAYER_COUNT > 5 c.rgb = LAYER_BLEND(5, c.rgb); #endif #if LAYER_COUNT > 6 c.rgb = LAYER_BLEND(6, c.rgb); #endif #if LAYER_COUNT > 7 c.rgb = LAYER_BLEND(7, c.rgb); #endif #ifdef VERTALPHA_ON float scaledValue = IN.vertColor.a * 2.0; float alpha0weight = max(0.0, 1.0 - scaledValue); float alpha2weight = max(0.0, scaledValue - 1.0); float alpha1weight = 1.0 - alpha0weight - alpha2weight; c.a = _Alpha * c.a * (tex2D(_AlphaMask, TRANSFORM_TEX(uv, _AlphaMask)).r * alpha1weight + tex2D(_AlphaMask2, TRANSFORM_TEX(uv, _AlphaMask2)).r * alpha2weight + alpha0weight) * ComputeMask(MASK_INPUTS, _BaseMaskType, _BaseMaskParameters, _BaseMaskAxis); #else c.a = _Alpha * c.a * tex2D(_AlphaMask, TRANSFORM_TEX(uv, _AlphaMask)).r * IN.vertColor.a * ComputeMask(MASK_INPUTS, _BaseMaskType, _BaseMaskParameters, _BaseMaskAxis); #endif c.rgb = lerp(c.rgb, c.rgb * _DarkMultiplier, IN.vertColor.r); return c; } #endif