Search Unity

Making a modified UnityObjectToClipPos()

Discussion in 'Shaders' started by Stef_Morojna, Jul 12, 2017.

  1. Stef_Morojna

    Stef_Morojna

    Joined:
    Apr 15, 2015
    Posts:
    289
    Alright so I guess I will first try to explain what i'm trying to do with this shader.

    What i'm trying to do is have icons above my player (like name and health for example), that stay the same size and in the same orientation (on the screen), no matter the position-rotation of the camera.

    So I have 2 options that work, but I think are impractical and expensive to do.

    1: Use UI for the icon.
    The problem with it is, that I for every frame I need to manually position the icon, and do the WorldToSceen calculation.

    2: Use sprite and text mesh.
    The problem here is that I have to adjust the size of the icon depending of how far the camera is every frame, and also rotate the icon towards the camera.

    Now my 3rd option that I think could work would be to use a modified "UnityObjectToClipPos( IN.vertex)" that:

    Dosen't apply camera to object distance.
    Dosen't apply camera rotation.
    Dosent apply object rotation.

    So I guess my final question is, where can I get the source code for UnityObjectToClipPos or how could I replicate it (to modify it later)?
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    https://unity3d.com/get-unity/download/archive
    Downloads > Built in shaders

    However it's effectively just:
    float4 pos = mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1.0)));

    If that doesn't make it any clearly (and I suspect it's just as confusing to you) then you should read up on projection matrices and GPU rendering.

    However in the most basic terms the final clip space position the xy values are in +1 to -1 range, z is 0 to w (except when it's not), and w is ... well I'd go read up on that, but using w=1 and z=1 for this case is likely fine.
     
  3. Stef_Morojna

    Stef_Morojna

    Joined:
    Apr 15, 2015
    Posts:
    289

    Alright so I have been messing around with the code line you gave me, and also some google searching, and this is what I understand so far.

    This calculates where the vertices are on the screen:

    float4 pos = mul(UNITY_MATRIX_VP, "mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1.0))" );

    And this applys all the scaling, rotation, distance-size etc

    float4 pos = "mul( UNITY_MATRIX_VP," mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1.0)) );

    So my guess is, I have to make a costum "UNITY_MATRIX_VP"?
     
  4. Stef_Morojna

    Stef_Morojna

    Joined:
    Apr 15, 2015
    Posts:
    289
    So after even more messing around, I kinda got to this.

    OUT.vertex = UnityObjectToClipPos( IN.vertex * -_WorldSpaceCameraPos.z);


    Sence i'm only using it for sprites that are at 0 z position, it works fine.

    However there are some problems:

    1st: I'm just up-scaling the mesh, to reverse the down-scaling the camera distance does.
    2nd: The sprite still rotates if I rotate the camera ( I could apply some kind of reverse rotation to the vertices before I pass them into the UnityObjectToClipPos, but I feels that would be a really dirty way of doing it).
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Applies the scaling, rotation, and position, yes. This is analogous to the world position in the editor. However I believe with sprites / canvas elements (also particles, and batched geometry) this matrix is actually essentially blank as those meshes are already in world space. This does not do the "distance size", that's a product of perspective applied by the projection matrix.

    UNITY_MATRIX_VP is the view projection matrix, which is a combination of the UNITY_MATRIX_V matrix which transforms things from world space into view space (essentially the same as if it was parented to the camera in Unity, but not exactly the same) and the UNITY_MATRIX_P which transforms view space into projection / clip space.

    Since you effectively just want it to be attached to the camera you might be able to just do this:
    float4 pos = mul(UNITY_MATRIX_P, (v.vertex.xyz, 1.0));

    Though you may need to push the sprites far off of z=0, not sure if positively or negatively, for it to show up the way you want.