MarmosetInput.cginc:
Input结构定义:
struct Input { #if defined(MARMO_PACKED_UV) || defined(MARMO_PACKED_VERTEX_OCCLUSION) || defined(MARMO_PACKED_VERTEX_COLOR) float4 texcoord; #else float2 texcoord; #endif float3 worldNormal; #if defined(MARMO_SPECULAR_DIRECT) || defined(MARMO_SPECULAR_IBL) float3 viewDir; #endif #if defined(MARMO_COMPUTE_WORLD_POS) #ifdef MARMO_U5_WORLD_POS float3 worldPos; //this is free in Unity 5 #endif #else float4 worldP; //lets write our own #endif #if defined(MARMO_VERTEX_COLOR) || defined(MARMO_VERTEX_LAYER_MASK) half4 color : COLOR; #elif defined(MARMO_VERTEX_OCCLUSION) half2 color : COLOR; #endif #ifdef MARMO_DIFFUSE_VERTEX_IBL float3 vertexIBL; #endif INTERNAL_DATA };
Output结构定义:
struct MarmosetOutput { half3 Albedo; //diffuse map RGB half Alpha; //diffuse map A half3 Normal; //world-space normal half3 Emission; //contains IBL contribution half Specular; //specular exponent (required by Unity) #ifdef MARMO_SPECULAR_DIRECT half3 SpecularRGB; //specular mask #endif };
Unity自带的Output结构定义:
struct SurfaceOutput { fixed3 Albedo; fixed3 Normal; fixed3 Emission; half Specular; fixed Gloss; fixed Alpha; }; // Metallic workflow struct SurfaceOutputStandard { fixed3 Albedo; // base (diffuse or specular) color fixed3 Normal; // tangent space normal, if written half3 Emission; half Metallic; // 0=non-metal, 1=metal // Smoothness is the user facing name, it should be perceptual smoothness but user should not have to deal with it. // Everywhere in the code you meet smoothness it is perceptual smoothness half Smoothness; // 0=rough, 1=smooth half Occlusion; // occlusion (default 1) fixed Alpha; // alpha for transparencies }; // Specular workflow struct SurfaceOutputStandardSpecular { fixed3 Albedo; // diffuse color fixed3 Specular; // specular color fixed3 Normal; // tangent space normal, if written half3 Emission; half Smoothness; // 0=rough, 1=smooth half Occlusion; // occlusion (default 1) fixed Alpha; // alpha for transparencies };
MarmosetDirect.cginc:
直接光照的主要代码,去掉deferred lighting相关的代码。
#ifndef MARMOSET_DIRECT_CGINC #define MARMOSET_DIRECT_CGINC // Core inline float3 wrapLighting(float DP, float3 scatter) { scatter *= 0.5; float3 integral = float3(1.0,1.0,1.0)-scatter; float3 light = saturate(DP * integral + scatter); float shadow = (DP*0.5+0.5); shadow *= shadow; return light * integral * shadow; } // NOTE: some intricacy in shader compiler on some GLES2.0 platforms (iOS) needs 'viewDir' & 'h' // to be mediump instead of lowp, otherwise specular highlight becomes too bright. inline half4 marmosetLighting (MarmosetOutput s, half3 viewDir, half3 lightDir, half3 lightColor) { half4 frag = half4(0.0,0.0,0.0,s.Alpha); #if defined(MARMO_DIFFUSE_DIRECT) || defined(MARMO_SPECULAR_DIRECT) half3 L = lightDir; half3 N = s.Normal; #ifdef MARMO_HQ L = normalize(L); #endif #endif #ifdef MARMO_DIFFUSE_DIRECT half dp = saturate(dot(N,L)); #ifdef MARMO_DIFFUSE_SCATTER float4 scatter = _Scatter * _ScatterColor; half3 diff = wrapLighting(dp, scatter.rgb); diff *= 2.0 * s.Albedo.rgb; //*2.0 to match Unity #else half3 diff = (2.0 * dp) * s.Albedo.rgb; //*2.0 to match Unity #endif frag.rgb = diff * lightColor; #endif #ifdef MARMO_SPECULAR_DIRECT half3 H = normalize(viewDir+L); float specRefl = saturate(dot(N,H)); half3 spec = pow(specRefl, s.Specular*512.0); #ifdef MARMO_HQ //self-shadowing blinn #ifdef MARMO_DIFFUSE_DIRECT spec *= saturate(10.0*dp); #else spec *= saturate(10.0*dot(N,L)); #endif #endif spec *= lightColor; frag.rgb += (0.5 * spec) * s.SpecularRGB; //*0.5 to match Unity #endif return frag; } //forward lighting inline half4 LightingMarmosetDirect( MarmosetOutput s, half3 lightDir, half3 viewDir, half atten ) { return marmosetLighting( s, viewDir, lightDir, _LightColor0 * atten); } inline half4 LightingMarmosetDirect( MarmosetOutput s, half3 viewDir, UnityGI gi ) { fixed4 c; c = marmosetLighting (s, viewDir, gi.light.dir, gi.light.color); #ifdef UNITY_LIGHT_FUNCTION_APPLY_INDIRECT c.rgb += s.Albedo * gi.indirect.diffuse; #endif return c; } inline void LightingMarmosetDirect_GI (MarmosetOutput s, UnityGIInput giInput, inout UnityGI gi) { gi = UnityGlobalIllumination(giInput, 1.0, s.Normal); } #endif
MarmosetSurf.cginc:
旧版本的surf代码:
#ifndef MARMOSET_SURF_CGINC #define MARMOSET_SURF_CGINC void MarmosetSurf(Input IN, inout MarmosetOutput OUT) { #define uv_diff IN.uv_MainTex #define uv_spec IN.uv_MainTex #define uv_bump IN.uv_MainTex #define uv_glow IN.uv_MainTex //DIFFUSE #if defined(MARMO_DIFFUSE_DIRECT) || defined(MARMO_DIFFUSE_IBL) half4 diff = tex2D( _MainTex, uv_diff ); diff *= _Color; //camera exposure is built into OUT.Albedo diff.rgb *= _ExposureIBL.w; OUT.Albedo = diff.rgb; OUT.Alpha = diff.a; #ifdef MARMO_PREMULT_ALPHA OUT.Albedo *= diff.a; #endif #else OUT.Albedo = half3(0.0,0.0,0.0); OUT.Alpha = 1.0; #endif //NORMALS #ifdef MARMO_NORMALMAP float3 N = UnpackNormal(tex2D(_BumpMap,uv_bump)); #ifdef MARMO_HQ N = normalize(N); #endif OUT.Normal = N; //N is in tangent-space #else //OUT.Normal is not modified when not normalmapping float3 N = OUT.Normal; //N is in world-space #ifdef MARMO_HQ N = normalize(N); #endif #endif //SPECULAR #if defined(MARMO_SPECULAR_DIRECT) || defined(MARMO_SPECULAR_IBL) half4 spec = tex2D(_SpecTex, uv_spec); float3 E = IN.viewDir; //E is in whatever space N is #ifdef MARMO_HQ E = normalize(E); half fresnel = splineFresnel(N, E, _SpecInt, _Fresnel); #else half fresnel = fastFresnel(N, E, _SpecInt, _Fresnel); #endif //camera exposure is built into OUT.Specular spec.rgb *= _SpecColor.rgb * fresnel * _ExposureIBL.w; OUT.Specular = spec.rgb; half glossLod = glossLOD(spec.a, _Shininess); OUT.Gloss = glossExponent(glossLod); //conserve energy by dividing out specular integral OUT.Specular *= specEnergyScalar(OUT.Gloss); #endif //SPECULAR IBL #ifdef MARMO_SPECULAR_IBL #ifdef MARMO_NORMALMAP float3 R = WorldReflectionVector(IN, OUT.Normal); #else float3 R = IN.worldRefl; #endif #ifdef MARMO_SKY_ROTATION R = mulVec3(_SkyMatrix,R); //per-fragment matrix multiply, expensive #endif #ifdef MARMO_MIP_GLOSS half3 specIBL = glossCubeLookup(_SpecCubeIBL, R, glossLod); #else half3 specIBL = specCubeLookup(_SpecCubeIBL, R)*spec.a; #endif OUT.Emission += specIBL.rgb * spec.rgb * _ExposureIBL.y; #endif //DIFFUSE IBL #ifdef MARMO_DIFFUSE_IBL N = WorldNormalVector(IN,N); //N is in world-space #ifdef MARMO_SKY_ROTATION N = mulVec3(_SkyMatrix,N); //per-fragment matrix multiply, expensive #endif half3 diffIBL = diffCubeLookup(_DiffCubeIBL, N); OUT.Emission += diffIBL * diff.rgb * _ExposureIBL.x; #endif //GLOW #ifdef MARMO_GLOW half4 glow = tex2D(_Illum, uv_glow); glow.rgb *= _GlowColor.rgb; glow.rgb *= _GlowStrength; glow.a *= _EmissionLM; glow.rgb += OUT.Albedo * glow.a; OUT.Emission += glow.rgb * _ExposureIBL.w; #endif } #endif
IBL实现的两个关键函数:
half3 diffCubeLookup(samplerCUBE diffCube, float3 worldNormal) { half4 diff = texCUBE(diffCube, worldNormal); return fromRGBM(diff); } half3 specCubeLookup(samplerCUBE specCube, float3 worldRefl) { half4 spec = texCUBE(specCube, worldRefl); return fromRGBM(spec); }
IBL.diffuse使用world normal查询,IBL.specular使用world reflection查询。
宏定义解析:
MARMO_DIFFUSE_SPECULAR_COMBINED
Diffuse/Specular合并
_MainTex.RGBA = RGB表示Diffuse,A表示Specular强度和Gloss
MARMO_PACKED_UV
UV打包
#ifdef MARMO_PACKED_UV o.texcoord.zw = v.texcoord1.xy; #endif
MARMO_PACKED_VERTEX_COLOR
顶点色打包
#ifdef MARMO_PACKED_VERTEX_COLOR o.texcoord.zw = v.color.rg; o.worldP.w = v.color.b; #endif