Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

280 lines
13 KiB

  1. //
  2. // OvrAvatar Mobile combined mesh expressive shader
  3. // For use on expressive face meshes
  4. // Texture array approach for rendering a combined mesh avatar with blend shape expression
  5. // Coupled with OvrAvatarMaterialManager to populate the texture arrays
  6. //
  7. // Unity vertex-fragnment implementation
  8. // Simplified lighting model recommended for use on mobile supporting one directional light
  9. // Surface shader recommended on PC
  10. //
  11. // Uses transparent queue for fade effects
  12. //
  13. // Color and appearance of the facial regions controlled via G&B channels in roughness texture
  14. // Pupil size controlled by manipulating UV coordinates
  15. //
  16. // Shader keywords:
  17. // - SECONDARY_LIGHT_ON SECONDARY_LIGHT_OFF
  18. // Enable SECONDARY_LIGHT_ON for a second "light" comprised of _SecondaryLightDirection and
  19. // _SecondaryLightColor This will influence the rim effect providing a lit contour to the avatar
  20. //
  21. Shader "OvrAvatar/Avatar_Mobile_CombinedMeshExpressive"
  22. {
  23. Properties
  24. {
  25. [NoScaleOffset] _MainTex("Main Texture Array", 2DArray) = "white" {}
  26. [NoScaleOffset] _NormalMap("Normal Map Array", 2DArray) = "bump" {}
  27. [NoScaleOffset] _RoughnessMap("Roughness Map Array", 2DArray) = "black" {}
  28. _Dimmer("Dimmer", Range(0.0,1.0)) = 1.0
  29. _Alpha("Alpha", Range(0.0,1.0)) = 1.0
  30. // Index into the texture array needs an offset for precision
  31. _Slices("Texture Array Slices", int) = 4.97
  32. _PupilSize("Pupil Size", Range(-1, 2)) = 0
  33. _LipSmoothness("Lip Smoothness", Range(0, 1)) = 0
  34. _MaskColorIris("Iris Color", Color) = (0.0,0.0,0.0,1.0)
  35. _MaskColorLips("Lips Color", Color) = (0.0,0.0,0.0,1.0)
  36. _MaskColorBrows("Brows Color", Color) = (0.0,0.0,0.0,1.0)
  37. _MaskColorLashes("Lashes Color", Color) = (0.0,0.0,0.0,1.0)
  38. _MaskColorSclera("Sclera Color", Color) = (0.0,0.0,0.0,1.0)
  39. _MaskColorGums("Gums Color", Color) = (0.0,0.0,0.0,1.0)
  40. _MaskColorTeeth("Teeth Color", Color) = (0.0,0.0,0.0,1.0)
  41. [HideInInspector] _SrcBlend("", Float) = 1
  42. [HideInInspector] _DstBlend("", Float) = 0
  43. }
  44. SubShader
  45. {
  46. Tags { "LightMode" = "ForwardBase" "IgnoreProjector" = "True"}
  47. Pass
  48. {
  49. Blend [_SrcBlend] [_DstBlend]
  50. Cull Back
  51. CGPROGRAM
  52. #pragma vertex vert
  53. #pragma fragment frag
  54. #pragma target 3.5
  55. #pragma fragmentoption ARB_precision_hint_fastest
  56. #pragma multi_compile SECONDARY_LIGHT_OFF SECONDARY_LIGHT_ON
  57. #include "UnityCG.cginc"
  58. #include "UnityLightingCommon.cginc"
  59. UNITY_DECLARE_TEX2DARRAY(_MainTex);
  60. UNITY_DECLARE_TEX2DARRAY(_NormalMap);
  61. float4 _NormalMap_ST;
  62. UNITY_DECLARE_TEX2DARRAY(_RoughnessMap);
  63. int _Slices;
  64. half _Dimmer;
  65. half _Alpha;
  66. half4 _BaseColor[5];
  67. half _DiffuseIntensity[5];
  68. half _RimIntensity[5];
  69. half _ReflectionIntensity[5];
  70. half3 _SecondaryLightDirection;
  71. half4 _SecondaryLightColor;
  72. half _PupilSize;
  73. half _LipSmoothness;
  74. fixed4 _MaskColorIris;
  75. fixed4 _MaskColorSclera;
  76. fixed4 _MaskColorBrows;
  77. fixed4 _MaskColorLashes;
  78. fixed4 _MaskColorLashesEnd;
  79. fixed4 _MaskColorLips;
  80. fixed4 _MaskColorGums;
  81. fixed4 _MaskColorTeeth;
  82. static const int ONE = 1;
  83. static const fixed ALPHA_CLIP_THRESHOLD = 0.7;
  84. static const int IRIS_BRIGHTNESS_MODIFIER = 2;
  85. static const fixed SCLERA_BRIGHTNESS_MODIFIER = 1.2;
  86. static const fixed LIP_SMOOTHNESS_MULTIPLIER = 0.5;
  87. static const fixed LIP_SMOOTHNESS_MIN_NDOTL = 0.3;
  88. static const fixed BROWS_LASHES_DIFFUSEINTENSITY = ONE - 0.25;
  89. static const int COLOR_MULTIPLIER = 255;
  90. static const half2 PUPIL_CENTER_UV = half2(0.127, 0.1175);
  91. static const half DILATION_ENVELOPE = 0.024;
  92. static const half2 EYE_REGION_UV = PUPIL_CENTER_UV + DILATION_ENVELOPE;
  93. static const int MASK_SLICE_SIZE = 17;
  94. static const half MASK_SLICE_THRESHOLD = MASK_SLICE_SIZE * 0.5f;
  95. static const int MASK_INDEX_IRIS = 255;
  96. static const int MASK_INDEX_SCLERA = 238;
  97. static const int MASK_INDEX_LASHES = 221;
  98. static const int MASK_INDEX_LIPS = 204;
  99. static const int MASK_INDEX_GUMS = 187;
  100. static const int MASK_INDEX_TEETH = 170;
  101. static const int MASK_INDEX_BROWS = 153;
  102. struct appdata
  103. {
  104. float4 vertex: POSITION;
  105. float3 normal: NORMAL;
  106. float4 tangent: TANGENT;
  107. float2 texcoord: TEXCOORD0;
  108. float4 vertexColor : COLOR0;
  109. };
  110. struct v2f
  111. {
  112. float4 pos : SV_POSITION;
  113. float3 uv : TEXCOORD0;
  114. float4 posWorld: TEXCOORD1;
  115. float3 normalDir: TEXCOORD2;
  116. float3 tangentDir: TEXCOORD3;
  117. float3 bitangentDir: TEXCOORD4;
  118. };
  119. v2f vert(appdata v)
  120. {
  121. v2f o;
  122. // Calculate tangents for normal mapping
  123. o.normalDir = normalize(UnityObjectToWorldNormal(v.normal));
  124. o.tangentDir = normalize(mul(unity_ObjectToWorld, half4(v.tangent.xyz, 0.0)).xyz);
  125. o.bitangentDir = normalize(cross(o.normalDir, o.tangentDir) * v.tangent.w);
  126. o.posWorld = mul(unity_ObjectToWorld, v.vertex);
  127. o.pos = UnityObjectToClipPos(v.vertex);
  128. o.uv.xy = v.texcoord;
  129. o.uv.z = v.vertexColor.x * _Slices;
  130. return o;
  131. }
  132. fixed4 frag(v2f i) : COLOR
  133. {
  134. // Pupil size offsets uv coords
  135. if (all(i.uv.xy < EYE_REGION_UV))
  136. {
  137. i.uv.xy -= PUPIL_CENTER_UV;
  138. half pupil = saturate(length(i.uv.xy) / DILATION_ENVELOPE);
  139. i.uv.xy *= lerp(1.0, pupil, _PupilSize);
  140. i.uv.xy += PUPIL_CENTER_UV;
  141. }
  142. // Diffuse texture sample
  143. float4 albedoColor = UNITY_SAMPLE_TEX2DARRAY(_MainTex, i.uv);
  144. // Process normal map
  145. float3 transformedNormalUV = i.uv;
  146. transformedNormalUV.xy = float2(TRANSFORM_TEX(i.uv.xy, _NormalMap));
  147. float3 normalMap = UNITY_SAMPLE_TEX2DARRAY(_NormalMap, transformedNormalUV) * 2.0 - ONE;
  148. float3x3 tangentTransform = float3x3(i.tangentDir, i.bitangentDir, i.normalDir);
  149. float3 normalDirection = normalize(mul(normalMap.rgb, tangentTransform));
  150. // Roughness contains metallic in r, smoothness in a, mask region in b and mask control in g
  151. half4 roughnessTex = UNITY_SAMPLE_TEX2DARRAY(_RoughnessMap, i.uv);
  152. // Normal/Light/View calculations
  153. half3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
  154. half VdotN = saturate(dot(viewDirection, normalDirection));
  155. half NdotL = saturate(dot(normalDirection, normalize(_WorldSpaceLightPos0.xyz)));
  156. // Sample the default reflection cubemap using the reflection vector
  157. float3 worldReflection = reflect(-viewDirection, normalDirection);
  158. half4 skyData = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, worldReflection);
  159. // Decode cubemap data into actual color
  160. half3 reflectionColor = DecodeHDR(skyData, unity_SpecCube0_HDR);
  161. // Get index into texture array
  162. int componentIndex = floor(i.uv.z + 0.5);
  163. // Base color from array
  164. float4 baseColor = _BaseColor[componentIndex];
  165. // Color space conversions if we are in linear
  166. #ifndef UNITY_COLORSPACE_GAMMA
  167. _MaskColorIris.rgb = LinearToGammaSpace(_MaskColorIris.rgb);
  168. _MaskColorLips.rgb = LinearToGammaSpace(_MaskColorLips.rgb);
  169. _MaskColorBrows.rgb = LinearToGammaSpace(_MaskColorBrows.rgb);
  170. _MaskColorLashes.rgb = LinearToGammaSpace(_MaskColorLashes.rgb);
  171. _MaskColorLashesEnd.rgb = LinearToGammaSpace(_MaskColorLashesEnd.rgb);
  172. _MaskColorSclera.rgb = LinearToGammaSpace(_MaskColorSclera.rgb);
  173. _MaskColorGums.rgb = LinearToGammaSpace(_MaskColorGums.rgb);
  174. _MaskColorTeeth.rgb = LinearToGammaSpace(_MaskColorTeeth.rgb);
  175. #endif
  176. // Calculate color masks
  177. half irisScalar = abs(roughnessTex.b * COLOR_MULTIPLIER - MASK_INDEX_IRIS) <= MASK_SLICE_THRESHOLD ? roughnessTex.g : 0.0f;
  178. half lipsScalar = abs(roughnessTex.b * COLOR_MULTIPLIER - MASK_INDEX_LIPS) <= MASK_SLICE_THRESHOLD ? roughnessTex.g : 0.0f;
  179. half browsScalar = abs(roughnessTex.b * COLOR_MULTIPLIER - MASK_INDEX_BROWS) <= MASK_SLICE_THRESHOLD ? roughnessTex.g : 0.0f;;
  180. half lashesScalar = abs(roughnessTex.b * COLOR_MULTIPLIER - MASK_INDEX_LASHES) <= MASK_SLICE_THRESHOLD ? roughnessTex.g : 0.0f;
  181. half scleraScalar = abs(roughnessTex.b * COLOR_MULTIPLIER - MASK_INDEX_SCLERA) <= MASK_SLICE_THRESHOLD ? roughnessTex.g : 0.0f;
  182. half teethScalar = abs(roughnessTex.b * COLOR_MULTIPLIER - MASK_INDEX_TEETH) <= MASK_SLICE_THRESHOLD ? roughnessTex.g : 0.0f;;
  183. half gumsScalar = abs(roughnessTex.b * COLOR_MULTIPLIER - MASK_INDEX_GUMS) <= MASK_SLICE_THRESHOLD ? roughnessTex.g : 0.0f;;
  184. half3 maskIris = irisScalar * (_MaskColorIris * IRIS_BRIGHTNESS_MODIFIER - baseColor.rgb);
  185. half3 maskBrows = browsScalar * (_MaskColorBrows - baseColor.rgb);
  186. half3 maskLashes = lashesScalar * (_MaskColorLashes - baseColor.rgb);
  187. half3 maskSclera = scleraScalar * (_MaskColorSclera * SCLERA_BRIGHTNESS_MODIFIER - baseColor.rgb);
  188. half3 maskTeeth = teethScalar * (_MaskColorTeeth - baseColor.rgb);
  189. half3 maskGums = gumsScalar * (_MaskColorGums - baseColor.rgb);
  190. // Lip tint excluded from color mask as it lerps with texture color
  191. half3 colorMask = maskIris + maskBrows + maskLashes + maskSclera + maskTeeth + maskGums;
  192. // Diffuse intensity from array
  193. half diffuseIntensity = _DiffuseIntensity[componentIndex];
  194. // Lerp diffuseIntensity with roughness map
  195. diffuseIntensity = lerp(diffuseIntensity, ONE, roughnessTex.a);
  196. // Brows and lashes modify DiffuseIntensity
  197. diffuseIntensity *= ONE - (saturate(browsScalar + lashesScalar) * BROWS_LASHES_DIFFUSEINTENSITY);
  198. // Add in diffuseIntensity and main lighting to base color
  199. baseColor.rgb += diffuseIntensity * NdotL * _LightColor0;
  200. // Add in color mask to base color if this is the head component (index == 0)
  201. baseColor.rgb += clamp(ONE - componentIndex, 0, ONE) * colorMask;
  202. // Multiply texture with base color with special case for lips
  203. albedoColor.rgb = lerp(albedoColor.rgb * baseColor.rgb, _MaskColorLips.rgb, lipsScalar * _MaskColorLips.a);
  204. // Smoothness multiplier on lip region
  205. albedoColor.rgb += lipsScalar * reflectionColor * (_LipSmoothness * LIP_SMOOTHNESS_MULTIPLIER) *
  206. lerp(LIP_SMOOTHNESS_MIN_NDOTL, ONE, NdotL);
  207. // Reflection from cubemap
  208. albedoColor.rgb += reflectionColor * (roughnessTex.a * _ReflectionIntensity[componentIndex]) * NdotL;
  209. // Rim term
  210. #ifdef SECONDARY_LIGHT_ON
  211. // Secondary light proxy (direction and color) passed into the rim term
  212. NdotL = saturate(dot(normalDirection, _SecondaryLightDirection));
  213. albedoColor.rgb += pow(ONE - VdotN, _RimIntensity[componentIndex]) * NdotL * _SecondaryLightColor;
  214. #else
  215. albedoColor.rgb += pow(ONE - VdotN, _RimIntensity[componentIndex]) * NdotL;
  216. #endif
  217. // Global dimmer
  218. albedoColor.rgb *= _Dimmer;
  219. #if !defined(UNITY_COLORSPACE_GAMMA)
  220. albedoColor.rgb = GammaToLinearSpace(albedoColor.rgb);
  221. #endif
  222. albedoColor.rgb = saturate(albedoColor.rgb);
  223. // Set alpha, with special case for lashes
  224. albedoColor.a = saturate(albedoColor.a * lerp(ONE, _Alpha, ONE - lashesScalar) * _Alpha);
  225. // Clip fragments in the lash region for clean lash transparency
  226. clip(albedoColor.a - lerp(0.0, ALPHA_CLIP_THRESHOLD, lashesScalar));
  227. // Return clamped final color
  228. return albedoColor;
  229. }
  230. ENDCG
  231. }
  232. }
  233. }