Search Unity

Windows Phone cubemap + normal map

Discussion in 'Shaders' started by PanicEnsues, Feb 26, 2015.

  1. PanicEnsues

    PanicEnsues

    Joined:
    Jul 17, 2014
    Posts:
    187
    I'm trying to port my game to Windows Phone 8.1, but my water shader (which is based on "Reflective/Bumped Diffuse") isn't d3d11_9x compatible.

    In trying to come up with something that IS compatible, I've come to the conclusion that it's impossible to have a cubemap-based reflection that is affected by a normal map. This boggles my mind, and I'm hoping someone can tell me that I'm wrong...

    This is the simplest-possible test case I could come up with for a normal-mapped cube reflection shader:

    Shader "Custom/Bumped Reflection" {
    Properties {
    _Cube ("Reflection Cubemap", Cube) = "" { TexGen CubeReflect }
    _BumpMap ("Normalmap", 2D) = "bump" {}
    }

    SubShader {
    CGPROGRAM
    #pragma surface surf BlinnPhong
    #pragma target 3.0

    sampler2D _BumpMap;
    samplerCUBE _Cube;

    struct Input {
    float2 uv_BumpMap;
    float3 worldRefl;
    INTERNAL_DATA
    };

    void surf (Input IN, inout SurfaceOutput o) {

    o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
    float3 worldRefl = WorldReflectionVector (IN, o.Normal);
    fixed4 reflcol = texCUBE (_Cube, worldRefl);

    o.Albedo = fixed4(0.5, 0.5, 0.5, 1);
    o.Emission = reflcol.rgb;
    }
    ENDCG
    }
    }


    Which fails to work (solid pink) on Windows Phone devices. Any suggestions?

    Thanks,

    -Scott
     
  2. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    Maybe remove that part?
     
  3. Jonny-Roy

    Jonny-Roy

    Joined:
    May 29, 2013
    Posts:
    666
    To put it more politely:

    #pragma target 3.0

    This tells the shader to only compile in Shader Model 3.0 and above, Windows Phone 8.1 and 8.0 are both Shader Model 2.0

    http://en.wikipedia.org/wiki/High-Level_Shading_Language

    This partly outlines the differences and it's mainly an issue with instruction or texture limits you hit is SM2
     
  4. PanicEnsues

    PanicEnsues

    Joined:
    Jul 17, 2014
    Posts:
    187
    Well crap, I could have sworn I'd read that WP8 was SM3. Oops. Thanks for the info!

    -Scott
     
  5. Jonny-Roy

    Jonny-Roy

    Joined:
    May 29, 2013
    Posts:
    666
    Yeah, I think diffuse, bumped and reflective might be pushing it, I have a shader I write that did it, I think for wp8 I had to choose between either reflective or bump, bump won!
     
  6. PanicEnsues

    PanicEnsues

    Joined:
    Jul 17, 2014
    Posts:
    187
    Yeah, looks like this is a no-go. At SM2, that test case shader fails to compile due to too many texture interpolators. Looks like INTERNAL_DATA compiles to 3 half3s, so that's quickly pushing it over the input limit.

    I'm rapidly losing interest in porting to Windows Phone... o_O

    Thanks for the help, Jonny!

    -Scott
     
  7. Jonny-Roy

    Jonny-Roy

    Joined:
    May 29, 2013
    Posts:
    666
    You might be able to do it as a Vertex, Fragment shader as you get a bit more control, I'll take a quick look. Incidentally, I have done a release across all platforms of a free game and it got 20% more downloads on Windows Store than on iOS, so it might be more hassle, but it also might have a hungrier market. On the other hand, it might have been luck!
     
  8. Jonny-Roy

    Jonny-Roy

    Joined:
    May 29, 2013
    Posts:
    666
    Here you go, works on mine fine:


    Code (CSharp):
    1. Shader "Custom/Bumped Reflection" {
    2. Properties {
    3. _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    4. _BumpMap ("Normalmap", 2D) = "bump" {}
    5. _Cube ("Reflection Cubemap", Cube) = "" { TexGen CubeReflect }
    6.  
    7. }
    8.  
    9. SubShader {
    10.     // ---- forward rendering base pass:
    11.     Pass {
    12.         Name "FORWARD"
    13.         Tags { "LightMode" = "ForwardBase" }
    14.  
    15. CGPROGRAM
    16. // compile directives
    17. #pragma vertex vert_surf
    18. #pragma fragment frag_surf
    19. #pragma target 2.0
    20. #pragma multi_compile_fwdbase
    21. #include "HLSLSupport.cginc"
    22. #include "UnityShaderVariables.cginc"
    23. #define UNITY_PASS_FORWARDBASE
    24. #include "UnityCG.cginc"
    25. #include "Lighting.cginc"
    26. #include "AutoLight.cginc"
    27.  
    28. #define INTERNAL_DATA half3 TtoW0; half3 TtoW1; half3 TtoW2;
    29. #define WorldReflectionVector(data,normal) reflect (data.worldRefl, half3(dot(data.TtoW0,normal), dot(data.TtoW1,normal), dot(data.TtoW2,normal)))
    30. #define WorldNormalVector(data,normal) fixed3(dot(data.TtoW0,normal), dot(data.TtoW1,normal), dot(data.TtoW2,normal))
    31.  
    32. // Original surface shader snippet:
    33. #line 8 ""
    34. #ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING
    35. #endif
    36.  
    37. //#pragma surface surf BlinnPhong
    38. //#pragma target 2.0
    39.  
    40. sampler2D _BumpMap;
    41. sampler2D _MainTex;
    42. samplerCUBE _Cube;
    43.  
    44. struct Input {
    45. float2 uv_MainTex;
    46. float3 worldRefl;
    47. INTERNAL_DATA
    48. };
    49.  
    50. void surf (Input IN, inout SurfaceOutput o)
    51. {
    52. fixed4 tex=tex2D (_MainTex, IN.uv_MainTex);
    53. o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex));
    54. float3 worldRefl = WorldReflectionVector (IN, o.Normal);
    55. fixed4 reflcol = texCUBE (_Cube, worldRefl);
    56.  
    57. o.Albedo = tex.rgb;
    58. o.Emission = reflcol.rgb;
    59. }
    60.  
    61. // vertex-to-fragment interpolation data
    62. #ifdef LIGHTMAP_OFF
    63. struct v2f_surf {
    64.   float4 pos : SV_POSITION;
    65.   //float2 pack0 : TEXCOORD0;
    66.   fixed4 TtoW0 : TEXCOORD0;
    67.   fixed4 TtoW1 : TEXCOORD1;
    68.   fixed4 TtoW2 : TEXCOORD2;
    69.   fixed3 lightDir : TEXCOORD3;
    70.   float4 vlight : TEXCOORD4;
    71.   float4 viewDir : TEXCOORD5;
    72.   LIGHTING_COORDS(6,7)
    73. };
    74. #endif
    75. #ifndef LIGHTMAP_OFF
    76. struct v2f_surf {
    77.   float4 pos : SV_POSITION;
    78.   float2 pack0 : TEXCOORD0;
    79.   fixed4 TtoW0 : TEXCOORD1;
    80.   fixed4 TtoW1 : TEXCOORD2;
    81.   fixed4 TtoW2 : TEXCOORD3;
    82.   float2 lmap : TEXCOORD4;
    83. #ifndef DIRLIGHTMAP_OFF
    84.   float3 viewDir : TEXCOORD5;
    85.   LIGHTING_COORDS(6,7)
    86. #else
    87.   LIGHTING_COORDS(5,6)
    88. #endif
    89. };
    90. #endif
    91. #ifndef LIGHTMAP_OFF
    92. float4 unity_LightmapST;
    93. #endif
    94. float4 _MainTex_ST;
    95.  
    96. // vertex shader
    97. v2f_surf vert_surf (appdata_full v) {
    98.   v2f_surf o;
    99.   o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
    100.   #ifdef LIGHTMAP_OFF
    101.   o.vlight.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
    102.   #endif
    103.   #ifndef LIGHTMAP_OFF
    104.   o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
    105.   #endif
    106.   float3 viewDir = -ObjSpaceViewDir(v.vertex);
    107.   float3 worldRefl = mul ((float3x3)_Object2World, viewDir);
    108.   TANGENT_SPACE_ROTATION;
    109.   o.TtoW0 = float4(mul(rotation, _Object2World[0].xyz), worldRefl.x)*unity_Scale.w;
    110.   o.TtoW1 = float4(mul(rotation, _Object2World[1].xyz), worldRefl.y)*unity_Scale.w;
    111.   o.TtoW2 = float4(mul(rotation, _Object2World[2].xyz), worldRefl.z)*unity_Scale.w;
    112.   #ifndef LIGHTMAP_OFF
    113.   o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
    114.   #endif
    115.   float3 worldN = mul((float3x3)_Object2World, SCALED_NORMAL);
    116.   float3 lightDir = mul (rotation, ObjSpaceLightDir(v.vertex));
    117.   #ifdef LIGHTMAP_OFF
    118.   o.lightDir = lightDir;
    119.   #endif
    120.   #if defined (LIGHTMAP_OFF) || !defined (DIRLIGHTMAP_OFF)
    121.   float3 viewDirForLight = mul (rotation, ObjSpaceViewDir(v.vertex));
    122.   #ifdef LIGHTMAP_OFF
    123.   o.viewDir.xyz = viewDirForLight.xyz;
    124.   #endif
    125.   #ifndef LIGHTMAP_OFF
    126.   o.viewDir = viewDirForLight;
    127.   #endif
    128.   #endif
    129.  
    130.   // SH/ambient and vertex lights
    131.   #ifdef LIGHTMAP_OFF
    132.   float3 shlight = ShadeSH9 (float4(worldN,1.0));
    133.   float3 vlight = shlight;
    134.   #ifdef VERTEXLIGHT_ON
    135.   float3 worldPos = mul(_Object2World, v.vertex).xyz;
    136.   vlight += Shade4PointLights (
    137.     unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
    138.     unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
    139.     unity_4LightAtten0, worldPos, worldN );
    140.   #endif // VERTEXLIGHT_ON
    141.   o.vlight.zw = vlight.xy;
    142.   o.viewDir.w = vlight.z;
    143.   #endif // LIGHTMAP_OFF
    144.  
    145.  
    146.  
    147.   // pass lighting information to pixel shader
    148.   TRANSFER_VERTEX_TO_FRAGMENT(o);
    149.   return o;
    150. }
    151. #ifndef LIGHTMAP_OFF
    152. sampler2D unity_Lightmap;
    153. #ifndef DIRLIGHTMAP_OFF
    154. sampler2D unity_LightmapInd;
    155. #endif
    156. #endif
    157.  
    158. // fragment shader
    159. fixed4 frag_surf (v2f_surf IN) : SV_Target {
    160.   // prepare and unpack data
    161.   #ifdef UNITY_COMPILER_HLSL
    162.   Input surfIN = (Input)0;
    163.   #else
    164.   Input surfIN;
    165.   #endif
    166.   #ifdef LIGHTMAP_OFF
    167.   surfIN.uv_MainTex = IN.vlight.xy;
    168.   #endif
    169.   #ifndef LIGHTMAP_OFF
    170.   surfIN.uv_MainTex = IN.pack0.xy;
    171.   #endif
    172.  
    173.  
    174.   surfIN.worldRefl = float3(IN.TtoW0.w, IN.TtoW1.w, IN.TtoW2.w);
    175.   surfIN.TtoW0 = IN.TtoW0.xyz;
    176.   surfIN.TtoW1 = IN.TtoW1.xyz;
    177.   surfIN.TtoW2 = IN.TtoW2.xyz;
    178.   #ifdef UNITY_COMPILER_HLSL
    179.   SurfaceOutput o = (SurfaceOutput)0;
    180.   #else
    181.   SurfaceOutput o;
    182.   #endif
    183.   o.Albedo = 0.0;
    184.   o.Emission = 0.0;
    185.   o.Specular = 0.0;
    186.   o.Alpha = 0.0;
    187.   o.Gloss = 0.0;
    188.  
    189.   // call surface function
    190.   surf (surfIN, o);
    191.  
    192.   // compute lighting & shadowing factor
    193.   fixed atten = LIGHT_ATTENUATION(IN);
    194.   fixed4 c = 0;
    195.  
    196.   // realtime lighting: call lighting function
    197.   #ifdef LIGHTMAP_OFF
    198.   c = LightingBlinnPhong (o, IN.lightDir, normalize(half3(IN.viewDir.xyz)), atten);
    199.   #endif // LIGHTMAP_OFF || DIRLIGHTMAP_OFF
    200.   #ifdef LIGHTMAP_OFF
    201.   float3 vlight;
    202.   vlight.xy=IN.vlight.zw;
    203.   vlight.z=IN.viewDir.w;
    204.   c.rgb += o.Albedo * vlight;
    205.   #endif // LIGHTMAP_OFF
    206.  
    207.   // lightmaps:
    208.   #ifndef LIGHTMAP_OFF
    209.     #ifndef DIRLIGHTMAP_OFF
    210.       // directional lightmaps
    211.       half3 specColor;
    212.       fixed4 lmtex = tex2D(unity_Lightmap, IN.lmap.xy);
    213.       fixed4 lmIndTex = tex2D(unity_LightmapInd, IN.lmap.xy);
    214.       half3 lm = LightingBlinnPhong_DirLightmap(o, lmtex, lmIndTex, normalize(half3(IN.viewDir)), 1, specColor).rgb;
    215.       c.rgb += specColor;
    216.     #else // !DIRLIGHTMAP_OFF
    217.       // single lightmap
    218.       fixed4 lmtex = tex2D(unity_Lightmap, IN.lmap.xy);
    219.       fixed3 lm = DecodeLightmap (lmtex);
    220.     #endif // !DIRLIGHTMAP_OFF
    221.  
    222.     // combine lightmaps with realtime shadows
    223.     #ifdef SHADOWS_SCREEN
    224.       #if defined(UNITY_NO_RGBM)
    225.       c.rgb += o.Albedo * min(lm, atten*2);
    226.       #else
    227.       c.rgb += o.Albedo * max(min(lm,(atten*2)*lmtex.rgb), lm*atten);
    228.       #endif
    229.     #else // SHADOWS_SCREEN
    230.       c.rgb += o.Albedo * lm;
    231.     #endif // SHADOWS_SCREEN
    232.   c.a = o.Alpha;
    233.   #endif // LIGHTMAP_OFF
    234.  
    235.   c.rgb += o.Emission;
    236.   return c;
    237. }
    238.  
    239. ENDCG
    240.  
    241. }
    242.  
    243.     // ---- forward rendering additive lights pass:
    244.     Pass {
    245.         Name "FORWARD"
    246.         Tags { "LightMode" = "ForwardAdd" }
    247.         ZWrite Off Blend One One Fog { Color (0,0,0,0) }
    248.  
    249. CGPROGRAM
    250. // compile directives
    251. #pragma vertex vert_surf
    252. #pragma fragment frag_surf
    253. #pragma target 2.0
    254. #pragma multi_compile_fwdadd
    255. #include "HLSLSupport.cginc"
    256. #include "UnityShaderVariables.cginc"
    257. #define UNITY_PASS_FORWARDADD
    258. #include "UnityCG.cginc"
    259. #include "Lighting.cginc"
    260. #include "AutoLight.cginc"
    261.  
    262. #define INTERNAL_DATA
    263. #define WorldReflectionVector(data,normal) data.worldRefl
    264. #define WorldNormalVector(data,normal) normal
    265.  
    266. // Original surface shader snippet:
    267. #line 8 ""
    268. #ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING
    269. #endif
    270.  
    271. //#pragma surface surf BlinnPhong
    272. //#pragma target 2.0
    273.  
    274. sampler2D _BumpMap;
    275. sampler2D _MainTex;
    276. samplerCUBE _Cube;
    277.  
    278. struct Input {
    279. float2 uv_MainTex;
    280. float3 worldRefl;
    281. INTERNAL_DATA
    282. };
    283.  
    284. void surf (Input IN, inout SurfaceOutput o)
    285. {
    286. fixed4 tex=tex2D (_MainTex, IN.uv_MainTex);
    287. o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex));
    288. float3 worldRefl = WorldReflectionVector (IN, o.Normal);
    289. fixed4 reflcol = texCUBE (_Cube, worldRefl);
    290.  
    291. o.Albedo = tex.rgb;
    292. o.Emission = reflcol.rgb;
    293. }
    294.  
    295. // vertex-to-fragment interpolation data
    296. struct v2f_surf {
    297.   float4 pos : SV_POSITION;
    298.   float2 pack0 : TEXCOORD0;
    299.   half3 lightDir : TEXCOORD1;
    300.   half3 viewDir : TEXCOORD2;
    301.   LIGHTING_COORDS(3,4)
    302. };
    303. float4 _MainTex_ST;
    304.  
    305. // vertex shader
    306. v2f_surf vert_surf (appdata_full v) {
    307.   v2f_surf o;
    308.   o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
    309.   o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
    310.   TANGENT_SPACE_ROTATION;
    311.   float3 lightDir = mul (rotation, ObjSpaceLightDir(v.vertex));
    312.   o.lightDir = lightDir;
    313.   float3 viewDirForLight = mul (rotation, ObjSpaceViewDir(v.vertex));
    314.   o.viewDir = viewDirForLight;
    315.  
    316.   // pass lighting information to pixel shader
    317.   TRANSFER_VERTEX_TO_FRAGMENT(o);
    318.   return o;
    319. }
    320.  
    321. // fragment shader
    322. fixed4 frag_surf (v2f_surf IN) : SV_Target {
    323.   // prepare and unpack data
    324.   #ifdef UNITY_COMPILER_HLSL
    325.   Input surfIN = (Input)0;
    326.   #else
    327.   Input surfIN;
    328.   #endif
    329.   surfIN.uv_MainTex = IN.pack0.xy;
    330.   #ifdef UNITY_COMPILER_HLSL
    331.   SurfaceOutput o = (SurfaceOutput)0;
    332.   #else
    333.   SurfaceOutput o;
    334.   #endif
    335.   o.Albedo = 0.0;
    336.   o.Emission = 0.0;
    337.   o.Specular = 0.0;
    338.   o.Alpha = 0.0;
    339.   o.Gloss = 0.0;
    340.  
    341.   // call surface function
    342.   surf (surfIN, o);
    343.   #ifndef USING_DIRECTIONAL_LIGHT
    344.   fixed3 lightDir = normalize(IN.lightDir);
    345.   #else
    346.   fixed3 lightDir = IN.lightDir;
    347.   #endif
    348.   fixed4 c = LightingBlinnPhong (o, lightDir, normalize(half3(IN.viewDir)), LIGHT_ATTENUATION(IN));
    349.   c.a = 0.0;
    350.   return c;
    351. }
    352.  
    353. ENDCG
    354.  
    355. }
    356.  
    357.  
    358. #LINE 35
    359.  
    360. }
    361. }

    Okay it's quite a bit more complex than your's above! Anyway, have a look and let me know if it looks alright for you.

    Jon
     
  9. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    I always try to keep SM2 as a target also for iOs and Android, so then it's no longer that much trouble. A surface shader is compiled for both forward and deferred rendering paths, and if one of the shaders doesn't fit in SM2, the whole surface shader fails for SM2. I usually use these constraints to get my surface shaders working for Mobile within SM2:
    Code (csharp):
    1.  
    2. #pragma surface surf Lambert noforwardadd nolightmap nodirlightmap
    3.  
     
  10. Jonny-Roy

    Jonny-Roy

    Joined:
    May 29, 2013
    Posts:
    666
    That wouldn't help with Scott's Shader it will still use too many interpolators like that.
     
  11. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    Compiles fine here:
    Code (csharp):
    1.  
    2. Shader "Custom/Bumped Reflection" {
    3. Properties {
    4. _Cube ("Reflection Cubemap", Cube) = "" { TexGen CubeReflect }
    5. _BumpMap ("Normalmap", 2D) = "bump" {}
    6. }
    7.  
    8. SubShader {
    9. CGPROGRAM
    10. #pragma surface surf Lambert noforwardadd nolightmap nodirlightmap
    11. #pragma target 2.0
    12.  
    13. sampler2D _BumpMap;
    14. samplerCUBE _Cube;
    15.  
    16. struct Input {
    17. float2 uv_BumpMap;
    18. float3 worldRefl;
    19. INTERNAL_DATA
    20. };
    21.  
    22. void surf (Input IN, inout SurfaceOutput o) {
    23.  
    24. o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
    25. float3 worldRefl = WorldReflectionVector (IN, o.Normal);
    26. fixed4 reflcol = texCUBE (_Cube, worldRefl);
    27.  
    28. o.Albedo = fixed4(0.5, 0.5, 0.5, 1);
    29. o.Emission = reflcol.rgb;
    30. }
    31. ENDCG
    32. }
    33. }
    34.  
     
  12. PanicEnsues

    PanicEnsues

    Joined:
    Jul 17, 2014
    Posts:
    187
    Yeah, it compiles and looks good in the editor, but just renders as solid black on my test hardware.
     
  13. PanicEnsues

    PanicEnsues

    Joined:
    Jul 17, 2014
    Posts:
    187
    Hey, thanks a lot! I did a quick test with it (successful), so will see if I can adapt it for my needs.

    Regards,

    -Scott
     
  14. PanicEnsues

    PanicEnsues

    Joined:
    Jul 17, 2014
    Posts:
    187
    Looks like the "#pragma surface surf BlinnPhong" (because I want specular too, because I'm greedy) is what was causing it to no worky.

    -Scott
     
  15. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    Yes, BlinnPhong pushes it over the edge. I didn't see specular settings, so I went for Lambert.