Search Unity

Custom shader with many textures and channels

Discussion in 'Shaders' started by Tabb, Nov 20, 2017.

  1. Tabb

    Tabb

    Joined:
    Jan 2, 2015
    Posts:
    40
    Hi all,

    It is my first time using shaders and customizing them.

    I have a 3D model and textures for it (from EVE Online). The textures are 3 .dds files each using RGB and Alpha channels. See below :


    Here is what I did :
    Code (CSharp):
    1. Shader "Custom/ShipShader" {
    2.     Properties {
    3.         _AR ("AR", 2D) = "white" {}
    4.         _ColorAR1 ("Channel R", Color) = (1,1,1,1)
    5.         _ColorAR2 ("Channel G", Color) = (1,1,1,1)
    6.         _ColorAR3 ("Channel B", Color) = (1,1,1,1)
    7.         _ColorAR4 ("Channel Alpha", Color) = (1,1,1,1)
    8.         _PMDG ("PMDG", 2D) = "white" {}
    9.         _ColorPMDG1 ("Channel R", Color) = (1,1,1,1)
    10.         _ColorPMDG2 ("Channel G", Color) = (1,1,1,1)
    11.         _ColorPMDG3 ("Channel B", Color) = (1,1,1,1)
    12.         _ColorPMDG4 ("Channel Alpha", Color) = (1,1,1,1)
    13.         _LightForce ("Light Intensity", Range(0,1)) = 1
    14.     }
    15.     SubShader {
    16.         Tags { "RenderType"="Opaque" }
    17.         LOD 200
    18.        
    19.         CGPROGRAM
    20.         // Physically based Standard lighting model, and enable shadows on all light types
    21.         #pragma surface surf Standard fullforwardshadows
    22.  
    23.         // Use shader model 3.0 target, to get nicer looking lighting
    24.         #pragma target 3.0
    25.  
    26.         struct Input {
    27.             float2 uv_AR;
    28.             float2 uv_PMDG;
    29.         };
    30.  
    31.         sampler2D _AR;
    32.         sampler2D _PMDG;
    33.  
    34.         fixed4 _ColorAR1;
    35.         fixed4 _ColorAR2;
    36.         fixed4 _ColorAR3;
    37.         fixed4 _ColorAR4;
    38.  
    39.         fixed4 _ColorPMDG1;
    40.         fixed4 _ColorPMDG2;
    41.         fixed4 _ColorPMDG3;
    42.         fixed4 _ColorPMDG4;
    43.         half _LightForce;
    44.  
    45.         // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
    46.         // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
    47.         // #pragma instancing_options assumeuniformscaling
    48.         UNITY_INSTANCING_CBUFFER_START(Props)
    49.             // put more per-instance properties here
    50.         UNITY_INSTANCING_CBUFFER_END
    51.  
    52.         void surf (Input IN, inout SurfaceOutputStandard o) {
    53.             fixed4 AR = normalize(tex2D(_AR, IN.uv_AR));
    54.             //fixed4 AR = tex2D(_AR, IN.uv_AR);
    55.             fixed4 ARc = lerp(AR, AR * _ColorAR1, AR.r);
    56.             ARc = lerp(ARc, ARc * _ColorAR2, AR.g);
    57.             ARc = lerp(ARc, ARc * _ColorAR3, AR.b);
    58.             ARc = lerp(ARc, ARc * _ColorAR4, AR.a);
    59.             o.Albedo = ARc.rgb;
    60.             o.Smoothness = ARc.a;
    61.  
    62.             fixed4 PMDG = normalize(tex2D(_PMDG, IN.uv_PMDG));
    63.             //fixed4 PMDG = tex2D(_PMDG, IN.uv_PMDG);
    64.             fixed4 PMDGc = lerp(PMDG, PMDG * _ColorPMDG1, PMDG.r);
    65.             PMDGc = lerp(PMDGc, PMDGc * _ColorPMDG2, PMDG.g);
    66.             PMDGc = lerp(PMDGc, PMDGc * _ColorPMDG3, PMDG.b);
    67.             PMDGc = lerp(PMDGc, PMDGc * _ColorPMDG4 * _LightForce, PMDG.a);
    68.             o.Metallic = PMDGc.g;
    69.             o.Emission = PMDGc.a;
    70.         }
    71.         ENDCG
    72.     }
    73.     FallBack "Diffuse"
    74. }


    This is not too bad (I didn't think I would achieve this today ^^)
    I tried to make the Albedo and Roughness (from the AR file) and the Meterial and Glow (from PMDG file) work.
    But I don't understand everything.

    - I normalize but i'm not sure if it is needed or not. Both methods work but one is more "colored".
    - For the Emission (from PMDG file alpha channel), it works, but I can't change the color of the glow which stays white.

    In general, I'm not sure I'm doing things correctly.
    Can you tell me what must be corrected in my code ?

    Thank you for your help.

    I uploaded the files I'm using if you want to download them to try.
     

    Attached Files:

    • Post.rar
      File size:
      335.2 KB
      Views:
      354
    deepportion likes this.
  2. brownboot67

    brownboot67

    Joined:
    Jan 5, 2013
    Posts:
    375
    I don't know what you're trying to achieve with all these lerps... Here's very much a guess at what this wants to be....

    AR map is pretty straight forward.
    NO as well.
    PMDG is, I'm guessing here, a series of color and property masks, plus glow.

    Code (csharp):
    1.  
    2. fixed4 AR = tex2D(_AR, IN.uv_AR));
    3.  
    4. //we'll output albedo later
    5. o.Smoothness = AR.a;
    6.  
    7. fixed4 NO = tex2D(_NO, IN.uv_NO)):
    8. fixed3 norm = fixed3(NO.g, 1.0, NO.a) * 2.0.xxx - 1.0.xxx;
    9. o.Normal = norm;
    10. o.Occlusion = NO.b;
    11.  
    12. fixed4 PMDG = tex2D(_PMDG, IN.uv_PMDG);
    13. o.Emission = PMDG.aaa * _GlowColor.rgb; //name your props more sensibly
    14.  
    15. //albedo stuff
    16. fixed3 surfaceColor = lerp(_HullColorOne.rgb, _HullColorTwo.rgb, PMDG.g); //you could probably use this mask for reflectiveness or other stuff too....
    17. fixed3 paintColor = lerp(surfacColor, _PaintColor.rgb, PMDG.r);
    18. fixed3 dirtColor = lerp(paintColor, _DirtColor.rgb, PMDG.b);
    19.  
    20. o.Albedo = dirtColor * AR.rgb;
    21.  
     
  3. Tabb

    Tabb

    Joined:
    Jan 2, 2015
    Posts:
    40
    Thank you so much for your help.

    It is now almost 100/100 working with this code :

    Code (CSharp):
    1. Shader "Custom/ShipShader" {
    2.     Properties {
    3.         _AR ("AR", 2D) = "white" {}
    4.         _NO ("NO", 2D) = "white" {}
    5.         _PMDG ("PMDG", 2D) = "white" {}
    6.         _HullColorOne ("Hull Color 1", Color) = (1,1,1,1)
    7.         _HullColorTwo ("Hull Color 2", Color) = (1,1,1,1)
    8.         _Reflectiveness ("Reflectiveness", Range(0,1)) = 1
    9.         _PaintColor ("Paint Color", Color) = (1,1,1,1)
    10.         _DirtColor ("Dirt Color", Color) = (1,1,1,1)
    11.         _GlowIntensity ("Light Intensity", Range(0,1)) = 1
    12.         _GlowColor ("Glow Color", Color) = (1,1,1,1)
    13.     }
    14.     SubShader {
    15.         Tags { "RenderType"="Opaque" }
    16.         LOD 200
    17.      
    18.         CGPROGRAM
    19.         // Physically based Standard lighting model, and enable shadows on all light types
    20.         #pragma surface surf Standard fullforwardshadows
    21.  
    22.         // Use shader model 3.0 target, to get nicer looking lighting
    23.         #pragma target 3.0
    24.  
    25.         struct Input {
    26.             float2 uv_AR;
    27.             float2 uv_NO;
    28.             float2 uv_PMDG;
    29.         };
    30.  
    31.         sampler2D _AR;
    32.         sampler2D _NO;
    33.         sampler2D _PMDG;
    34.  
    35.         fixed4 _HullColorOne;
    36.         fixed4 _HullColorTwo;
    37.         half _Reflectiveness;
    38.         fixed4 _PaintColor;
    39.         fixed4 _DirtColor;
    40.         half _GlowIntensity;
    41.         fixed4 _GlowColor;
    42.  
    43.         // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
    44.         // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
    45.         // #pragma instancing_options assumeuniformscaling
    46.         UNITY_INSTANCING_CBUFFER_START(Props)
    47.             // put more per-instance properties here
    48.         UNITY_INSTANCING_CBUFFER_END
    49.  
    50.         void surf (Input IN, inout SurfaceOutputStandard o) {
    51.             fixed4 AR = tex2D(_AR, IN.uv_AR);
    52.             //we'll output albedo later
    53.             o.Smoothness = AR.a;
    54.             fixed4 NO = tex2D(_NO, IN.uv_NO);
    55.             fixed3 norm = fixed3(NO.g, 1.0, NO.a) * 2.0.xxx - 1.0.xxx;
    56.             o.Normal = norm;
    57.             o.Occlusion = NO.b;
    58.             fixed4 PMDG = tex2D(_PMDG, IN.uv_PMDG);
    59.             o.Emission = PMDG.aaa * _GlowColor.rgb * _GlowIntensity;
    60.             //albedo stuff
    61.             fixed3 surfaceColor = lerp(_HullColorOne.rgb, _HullColorTwo.rgb, PMDG.g); //you could probably use this mask for reflectiveness or other stuff too....
    62.             fixed3 paintColor = lerp(surfaceColor, _PaintColor.rgb, PMDG.r);
    63.             fixed3 dirtColor = lerp(paintColor, _DirtColor.a * _DirtColor.rgb, PMDG.b);
    64.             o.Metallic = PMDG.g * _Reflectiveness;
    65.             //o.Albedo = dirtColor * AR.rgb;
    66.             o.Albedo = paintColor * AR.rgb;
    67.         }
    68.         ENDCG
    69.     }
    70.     FallBack "Diffuse"
    71. }
    72.  
    The only thing still giving me hard times is the dirt channel. The texture is darker when there is no dirt, which should be the opposite.
    I added _DirtColor.a to be able to change this value in realtime to change dirt level on the ship.
    Is it the correct way to do so ?

    Also, can you explain me this line : fixed3 norm = fixed3(NO.g, 1.0, NO.a) * 2.0.xxx - 1.0.xxx;
    I understand what is does, but I don't understant how.

    And finally in this line : o.Emission = PMDG.aaa * _GlowColor.rgb * _GlowIntensity;
    What is aaa doing ?
     
    Last edited: Nov 20, 2017
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    That's trying to unpack the normal map. Normal maps are unit length vectors (length(normal) == 1.0) encoded in a texture, and are often stored as two components, reconstructing the third in the shader. That line is a method sometimes used, but in this case is wrong. It's making the assumption that the X and Z components are stored in the green and alpha, and that the normal is stored as a derivative normal map. But it's much more likely to be the X and Y channels stored in the green and alpha channels and the Z needs to be reconstructed via the Pythagorean Theorem.

    Luckily Unity has code for this already. UnpackNormal() or more explicitly UnpackNormalDXT5nm(). However this expects the normal to be packed with the X in the alpha channel and the Y in the green channel, and for the Y to be +Y encoded (aka OpenGL format, or Y up). EVE appears to be doing X in the green and Y in the alpha, and is using -Y (aka Direct3D format, or Y down).

    So this should get you want you want:
    fixed3 norm = UnpackNormalDXT5nm(fixed4(0.0, 1.0 - NO.a, 0.0, NO.g));
     
    StenCG and sigono-chao3 like this.
  5. Tabb

    Tabb

    Joined:
    Jan 2, 2015
    Posts:
    40
    Yep, it works like a charm :)

    Any idea to solve the dirt issue ?
     
  6. Tabb

    Tabb

    Joined:
    Jan 2, 2015
    Posts:
    40
    I'm facing another issue regarding the textures. On some ships exported from EVE (capital ships mainly), the occlusion map (from the b channel of NO file) gives a weird result.

    All textures work perfectly fine (normal, glow, albedo, etc) except for this one.
    I don't understand why ...

    The attached file contains the .obj and the .dds of the example below.

    Ship with occlusion deactivated :


    And the result once I activate occlusion :



    The other issue with some ships is that they use 2 AR, NO, PMDG files instead of one.
    The ship above engines textures are on another file so as you can see the result is ugly.



    How can I use 2 textures in unity ? How can they then be correctly applied on the 3d model ?

    I can't thank you enough for your help :)
     

    Attached Files:

    • post.rar
      File size:
      325.5 KB
      Views:
      358
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    My guess is the larger ships are using multiple UV sets, with occlusion probably on the secondary UVs. To my knowledge the OBJ format does not support multiple UV sets, so that data is lost.
     
  8. Tabb

    Tabb

    Joined:
    Jan 2, 2015
    Posts:
    40
    Ok. I have the 3D models in .obj, and in .gr2. But I didn't find anyway to convert those .gr2 files to anything I could use :/
     
  9. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    That's a Granny 3D file. Very common in the industry ... and it's quite explicitly used as an export format to get it into game engines. RAD Game Tools, the authors, don't even provide any kind of "importer" to get them back into a model program because that's simply not how the files would be used, and companies who do write converters are going to be using them to convert into another proprietary format for a specific game engine with even less expectation of use outside of that game.

    There are a few community built converters out there, but they convert to .obj since it is a simple format to convert to, or some other simple format with support for only one UV set.
     
  10. Tabb

    Tabb

    Joined:
    Jan 2, 2015
    Posts:
    40
    In other words, i'm screwed ? :p

    Anyway thank you all for your help !