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

Vertex normal to Worldspace normal

Discussion in 'Shaders' started by chayanvinayak, Jan 4, 2016.

  1. chayanvinayak

    chayanvinayak

    Joined:
    Jul 11, 2012
    Posts:
    24
    As in Unity 5 (and in Unity4) vertex normal is a float4 value and "w" value ( of xyzw) is 0.0.
    Considering that, is it ok to multiply v.normal with _Object2World to convert v.normal to worldSpaceNormal.
    i.e.
    float4 worldSpaceNormal = mul(_Object2World, v.normal);

    [ I wanted to verify because conversion of point-position and vector-normal work differently. I have read couple of thread posts related to this topic. But wanted to confirm.]


    Thanks!
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    If your model is uniformly scaled (or not scaled) you can do this:

    float3 worldSpaceNormal = normalize(mul((float3x3)_Object2World, v.normal.xyz));

    If your model is non-uniformly scaled this won't produce correct results, though it might be close enough for many uses. The correct thing to do would be to use the inverse transform matrix. Unity doesn't supply an inverse transpose matrix for object to world (as it does for object to view in UNITY_MATRIX_IT_MV), but it does supply the inverse, _World2Object, which is what Unity's own code uses to calculate the world normal.

    If you add #include "UnityCG.cginc" to your shader you can use Unity's built in function for this:
    float3 worldSpaceNormal = UnityObjectToWorldNormal(v.normal.xyz);

    Alternatively you could use the _Object2World like this:
    float3 worldSpaceNormal = normalize(mul(transpose(inverse((float3x3)_Object2World)), v.vertex.xyz);
    but that's super slow.
     
    colin299 and chayanvinayak like this.
  3. chayanvinayak

    chayanvinayak

    Joined:
    Jul 11, 2012
    Posts:
    24
    Hello bgolus,

    Thank you for your reply!
    In the first option that you mentioned - I am wondering why do I have to convert 4x4 matrix into 3x3 and v.normal into v.normal.xyz as v.normal.w component is already 0.0 in it and when we multiply 4x4 matrix with float4 normal, where normal.w = 0.0, translation values of the matrix will always be 0.0 and that is what we want for normal (as translations are not applied on normals)

    Here is a picture of what I mean :



    Please, let me know if I am missing anything!

    Thanks
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    There's no real requirement to do it, but the cast from float4x4 to float3x3 is free on nearly all hardware where as the additional math is not.
     
    chayanvinayak likes this.
  5. chayanvinayak

    chayanvinayak

    Joined:
    Jul 11, 2012
    Posts:
    24
    Got it! thanks so much.