Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Computing vertex normals | Noob Question

Discussion in 'Shaders' started by McSellerie, Aug 1, 2014.

  1. McSellerie

    McSellerie

    Joined:
    Jun 21, 2014
    Posts:
    9
    Hello everybody,

    I´m currently struggeling to understand how to compute the vertex normals within a shader. I´m a complete noob, so please just point out where to get the information I need if my question sounds silly and I will happily keep on investigating this further.

    So I´ve got a shader:

    Code (CSharp):
    1. Shader "Outlined/Silhouetted Bumped Diffuse" {
    2.     Properties {
    3.         _Color ("Main Color", Color) = (.5,.5,.5,1)
    4.         _OutlineColor ("Outline Color", Color) = (0,0,0,1)
    5.         _Outline ("Outline width", Range (0.0, 0.03)) = .005
    6.         _MainTex ("Base (RGB)", 2D) = "white" { }
    7.         _BumpMap ("Bumpmap", 2D) = "bump" {}
    8.     }
    9. CGINCLUDE
    10. // Upgrade NOTE: excluded shader from DX11 and Xbox360; has structs without semantics (struct appdata members normal)
    11. #pragma exclude_renderers d3d11 xbox360
    12. #include "UnityCG.cginc"
    13. struct appdata {
    14.     float4 vertex : POSITION;
    15.     float3 normal : NORMAL;
    16. };
    17. struct v2f {
    18.     float4 pos : POSITION;
    19.     float4 color : COLOR;
    20. };
    21. uniform float _Outline;
    22. uniform float4 _OutlineColor;
    23. v2f vert(appdata v) {
    24.     // just make a copy of incoming vertex data but scaled according to normal direction
    25.     v2f o;
    26.     o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    27.     float3 norm   = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);
    28.     float2 offset = TransformViewToProjection(norm.xy);
    29.     o.pos.xy += offset * o.pos.z * _Outline;
    30.     o.color = _OutlineColor;
    31.     return o;
    32. }
    33. ENDCG
    34.     SubShader {
    35.         Tags { "Queue" = "Transparent" }
    36.         // note that a vertex shader is specified here but its using the one above
    37.         Pass {
    38.             Name "OUTLINE"
    39.             Tags { "LightMode" = "Always" }
    40.             Cull Off
    41.             ZWrite Off
    42.             // you can choose what kind of blending mode you want for the outline
    43.             Blend SrcAlpha OneMinusSrcAlpha // Normal
    44.             //Blend One One // Additive
    45.             //Blend One OneMinusDstColor // Soft Additive
    46.             //Blend DstColor Zero // Multiplicative
    47.             //Blend DstColor SrcColor // 2x Multiplicative
    48. CGPROGRAM
    49. #pragma vertex vert
    50. #pragma fragment frag
    51. half4 frag(v2f i) : COLOR {
    52.     return i.color;
    53. }
    54. ENDCG
    55.         }
    56. CGPROGRAM
    57. #pragma surface surf Lambert
    58. struct Input {
    59.     float2 uv_MainTex;
    60.     float2 uv_BumpMap;
    61. };
    62. sampler2D _MainTex;
    63. sampler2D _BumpMap;
    64. uniform float3 _Color;
    65. void surf(Input IN, inout SurfaceOutput o) {
    66.     o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb * _Color;
    67.     o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
    68. }
    69. ENDCG
    70.     }
    71.     SubShader {
    72.         Tags { "Queue" = "Transparent" }
    73.         Pass {
    74.             Name "OUTLINE"
    75.             Tags { "LightMode" = "Always" }
    76.             Cull Front
    77.             ZWrite Off
    78.             Offset 15,15
    79.             // you can choose what kind of blending mode you want for the outline
    80.             //Blend SrcAlpha OneMinusSrcAlpha // Normal
    81.             //Blend One One // Additive
    82.             //Blend One OneMinusDstColor // Soft Additive
    83.             //Blend DstColor Zero // Multiplicative
    84.             Blend DstColor SrcColor // 2x Multiplicative
    85.             CGPROGRAM
    86.             #pragma vertex vert
    87.             #pragma exclude_renderers gles xbox360 ps3
    88.             ENDCG
    89.             SetTexture [_MainTex] { combine primary }
    90.         }
    91. CGPROGRAM
    92. #pragma surface surf Lambert
    93. struct Input {
    94.     float2 uv_MainTex;
    95.     float2 uv_BumpMap;
    96. };
    97. sampler2D _MainTex;
    98. sampler2D _BumpMap;
    99. uniform float3 _Color;
    100. void surf(Input IN, inout SurfaceOutput o) {
    101.     o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb * _Color;
    102.     o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
    103. }
    104. ENDCG
    105.     }
    106.     Fallback "Outlined/Silhouetted Diffuse"
    107. }
    108.  
    This is applied to a flat mesh, so all vertex normals point upwards. Now I need to rotate to vertex normals of each vertex 90° to make them point outwards, to achieve the result I´m aiming for. I did that in a 3D Editor, but there is no way to do it manually throughout my project due to workload.

    I assume that the computation needs to take place after reading the vertex normals somewhere here:

    Code (CSharp):
    1. float3 norm   = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);
    but since I do not really know what I´m doing I´d be really grateful if someone with a deeper understading gave me a hint on how to achieve this.

    Thanks in advance.

    Cheers
    M.
     
  2. bricevdm

    bricevdm

    Joined:
    Nov 4, 2009
    Posts:
    34
    it's not so clear what you want to achieve by rotating the normals of this outline shader. I assume you know ;)

    you can't generate normals in a shader since normals are based on surrounding geometry.
    But this is a special case, since you use a plane ("flat mesh", right?). So all normals are identical, you could just override the mesh data with your own without even trying to rotate it in the shader (assuming the rotation value is always 90 and not changing).

    so just write something instead of "v.normal" like "float3(0,1f,0)" (pointing up). but you've used the word 'outwards' which implies a center, and not a uniform 90° rotation. in this case you could use something else, like "normalize(v.vertex.xyz)" (very hacky but "outwards" for a plane with its pivot in the center)

    does it help? shaders are not easy but worth learning :)
     
  3. McSellerie

    McSellerie

    Joined:
    Jun 21, 2014
    Posts:
    9
    It kind of helps. To explain why I want those vertex rotated is that by rotating them to point outwards the Outline shader I´m modifying here would work on planes as well when looking at it from a steep angle. Right now with all normals pointing upward this gives an ugly, uneven line, that disappears when looking at it from lets say a 30° angle.

    I only thought about overriding the vertex data within the shader since doing it manually achieved the result I need (an even outline for plane meshes from whereever you look at it .. :D.

    Anyways thanks for your reply.
     
  4. bricevdm

    bricevdm

    Joined:
    Nov 4, 2009
    Posts:
    34
    You could then just deal with special cases with a custom outline geometry. Each plane could have another box as a child, rendered with only the outline subshader. All the other cases could be dealt with with the regular two pass system.
    Alternatively you could avoid using planes altogether and model very thin boxes instead