Hello, who can help with the conversion of this shader in Unity? I found many examples of shaders, but, more correctly, I do not quite understand, here are some of them http://www.gamedev.ru/code/articles/Cook-Torrance http://steps3d.narod.ru/tutorials/lighting-tutorial.html http://content.gpwiki.org/index.php/D3DBook:%28Lighting%29_Cook-Torrance Code (csharp): float CookTorrance(vec3 _normal, vec3 _light, vec3 _view, float roughness_val) { if (roughness_val <= 0.0) return 0.0; } vec3 half_vec = normalize( _view + _light ); float NdotL = max( dot( _normal, _light ), 0.0 ); float NdotV = max( dot( _normal, _view ), 0.0 ); float NdotH = max( dot( _normal, half_vec ), 1.0e-7 ); float VdotH = max( dot( _view, half_vec ), 0.0 ); float geometric = 2.0 * NdotH / VdotH; geometric = min( 1.0, geometric * min(NdotV, NdotL) ); float r_sq = roughness_val * roughness_val; float NdotH_sq = NdotH * NdotH; float NdotH_sq_r = 1.0 / (NdotH_sq * r_sq); float roughness_exp = (NdotH_sq - 1.0) * ( NdotH_sq_r ); float roughness = exp(roughness_exp) * NdotH_sq_r / (4.0 * NdotH_sq ); float fresnel = 1.0 / (1.0 + NdotV); Rs = min(1.0, (fresnel * geometric * roughness) / (NdotV * NdotL + 1.0e-7)); vResult = vAmbient + LdotN * (vDiffuse + vSpecular * Rs)
cook-torrance is a lighting model, and its best you apply it as a custom lighting function in a surface shader. Check the unity shader include files in unity/data/cgincludes folder and there you will see some examples of how to make your own custom lighting functions. Thing is, cook-torrance is mathematically heavy and unnecessary for most cases.
I think that should do it... Code to generate the Beckmann lookup texture can be found at the bottom of this page; http://www.altdevblogaday.com/2011/12/31/skin-shading-in-unity3d/ Roughness slider: Code (csharp): Shader "Custom/CookTorrance" { Properties { _Color ("Main Color", Color) = (1,1,1,1) _MainTex ("Diffuse (RGB) Alpha (A)", 2D) = "white" {} _Roughness ("Roughness", Range(0,1)) = 0.5 _BumpMap ("Normal (Normal)", 2D) = "bump" {} _Beckmann ("Beckmann Lookup (RGB)", 2D) = "gray" {} _Fresnel ("Fresnel Value", Float) = 0.028 _Cutoff ("Alpha Cut-Off Threshold", Range(0,1)) = 0.5 } SubShader{ Tags { "Queue" = "Geometry" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout" } CGPROGRAM #pragma surface surf CookTorrance exclude_path:prepass nolightmap nodirlightmap fullforwardshadows #pragma target 3.0 struct Input { float2 uv_MainTex; }; sampler2D _MainTex, _BumpMap, _Beckmann; float _Fresnel, _Cutoff, _Roughness; void surf (Input IN, inout SurfaceOutput o) { fixed4 albedo = tex2D(_MainTex, IN.uv_MainTex); o.Albedo = albedo.rgb; o.Alpha = albedo.a; o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex)); } inline fixed4 LightingCookTorrance (SurfaceOutput s, fixed3 lightDir, fixed3 viewDir, fixed atten) { clip ( s.Alpha - _Cutoff ); viewDir = normalize ( viewDir ); lightDir = normalize ( lightDir ); float3 h = normalize ( lightDir + viewDir ); float NdotL_unsat = dot ( s.Normal, lightDir ); float NdotH_unsat = dot ( s.Normal, h ); float NdotL = saturate( NdotL_unsat ); float NdotH = saturate( NdotH_unsat ); float NdotV = saturate( dot ( s.Normal, viewDir ) ); float VdotH = saturate( dot ( viewDir, h ) ); float geo_numerator = 2.0 * NdotH; float geo_b = ( geo_numerator * NdotV ) / VdotH; float geo_c = ( geo_numerator * NdotL ) / VdotH; float geo = min( 1.0f, min( geo_b, geo_c ) ); fixed roughness = tex2D( _Beckmann, float2 ( NdotH_unsat * 0.5 + 0.5, _Roughness ) ).r; float fresnel = pow( 1.0 - VdotH, 5.0 ); fresnel *= ( 1.0 - _Fresnel ); fresnel += _Fresnel; float3 spec = float3 ( fresnel * geo * roughness ) / ( NdotV * NdotL ); fixed4 c; c.rgb = NdotL * ( _LightColor0.rgb * spec + s.Albedo ) * atten; c.a = s.Alpha; return c; } ENDCG } FallBack "Transparent/Cutout/VertexLit" } Rougness texture: Code (csharp): Shader "Custom/CookTorrance" { Properties { _Color ("Main Color", Color) = (1,1,1,1) _MainTex ("Diffuse (RGB) Alpha (A)", 2D) = "white" {} _Roughness ("Roughness (R)", 2D) = "gray" {} _BumpMap ("Normal (Normal)", 2D) = "bump" {} _Beckmann ("Beckmann Lookup (RGB)", 2D) = "gray" {} _Fresnel ("Fresnel Value", Float) = 0.028 _Cutoff ("Alpha Cut-Off Threshold", Range(0,1)) = 0.5 } SubShader{ Tags { "Queue" = "Geometry" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout" } CGPROGRAM #pragma surface surf CookTorrance exclude_path:prepass nolightmap nodirlightmap fullforwardshadows #pragma target 3.0 struct Input { float2 uv_MainTex; }; sampler2D _MainTex, _BumpMap, _Beckmann, _Roughness; float _Fresnel, _Cutoff; void surf (Input IN, inout SurfaceOutput o) { fixed4 albedo = tex2D(_MainTex, IN.uv_MainTex); o.Albedo = albedo.rgb; o.Alpha = albedo.a; o.Specular = tex2D(_Roughness, IN.uv_MainTex).r; o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex)); } inline fixed4 LightingCookTorrance (SurfaceOutput s, fixed3 lightDir, fixed3 viewDir, fixed atten) { clip ( s.Alpha - _Cutoff ); viewDir = normalize ( viewDir ); lightDir = normalize ( lightDir ); float3 h = normalize ( lightDir + viewDir ); float NdotL_unsat = dot ( s.Normal, lightDir ); float NdotH_unsat = dot ( s.Normal, h ); float NdotL = saturate( NdotL_unsat ); float NdotH = saturate( NdotH_unsat ); float NdotV = saturate( dot ( s.Normal, viewDir ) ); float VdotH = saturate( dot ( viewDir, h ) ); float geo_numerator = 2.0 * NdotH; float geo_b = ( geo_numerator * NdotV ) / VdotH; float geo_c = ( geo_numerator * NdotL ) / VdotH; float geo = min( 1.0f, min( geo_b, geo_c ) ); fixed roughness = tex2D( _Beckmann, float2 ( NdotH_unsat * 0.5 + 0.5, s.Specular ) ).r; float fresnel = pow( 1.0 - VdotH, 5.0 ); fresnel *= ( 1.0 - _Fresnel ); fresnel += _Fresnel; float3 spec = float3 ( fresnel * geo * roughness ) / ( NdotV * NdotL ); fixed4 c; c.rgb = NdotL * ( _LightColor0.rgb * spec + s.Albedo ) * atten; c.a = s.Alpha; return c; } ENDCG } FallBack "Transparent/Cutout/VertexLit" }
This solution is not entirely correct. No need to use any textures except diffuse. Specular And Roughness should be managed by sliders or float
If you want those values per-material, sure. If you want parts of your texture to be glossy and others to be matte, then... no. It shouldn't take you more than 1 minute to swap it out for sliders, though. I've edited it to make the version you want.
What do you mean by correct? Uniform reflectance and roughness across the whole model would be unfortunately restrictive use of such a complex lighting model. Farfarer's use of textures for these values lets you have smoother, rougher, more and less reflective areas on the same model. The Beckmann lookup texture is a good trade of a tiny bit of VRAM for a constant speedup in the fragment shader. Two of your three links use this texture.
Using textures would make far more sense, now i have to convert it back, thankyou for the example Farfarer your contributions to Unity shaders have been really useful for me in these forums
I found the correct shader, and I was able to convert it to Unity3D, I was very happy with the result.
Just in case anyone comes across this thread in the future, it's worth noting that there is nothing incorrect about Farfarer's implementation. It's just faster and more versatile than the version Nose wanted.
Haha sorry i was being a smartass and agreeing with you with a silly joke, dont mind me! Thankyou for supplying both Farfarer, im sure id have figured it but im at the point of learning shaders (rewriting other peoples and smooshing them together mainly) where being able to compare is very handy