Search Unity

Feature Request Bone indices and weights node

Discussion in 'Shader Graph' started by felipin, Sep 17, 2020.

  1. felipin

    felipin

    Joined:
    Nov 18, 2015
    Posts:
    49
    I'm working on my own DOTS Animation implementation and I'd like to use Shader Graph, but I can only do it using "Linear Blend Skinning" where it's a little tricky (bone matrices buffer should have the same name from Unity Implementation, so it'll be impossible to use both my implementation and the unity one on the same project). It'd be nice to have a node to access vertex data such as BLENDINDICES and BLENDWEIGHTS.
     
    Krajca likes this.
  2. Krajca

    Krajca

    Joined:
    May 6, 2014
    Posts:
    347
    bump as it would help me also
     
  3. xotonic

    xotonic

    Joined:
    Feb 21, 2016
    Posts:
    11
  4. fmcdeoliveira

    fmcdeoliveira

    Joined:
    Sep 21, 2021
    Posts:
    19
  5. fmcdeoliveira

    fmcdeoliveira

    Joined:
    Sep 21, 2021
    Posts:
    19
    Hi, i've found a poor workaround to access blend indices and blend weights in the shader graph.

    The ideia consists in using a macro to override the Unity_LinearBlendSkinning_float call so when it's call the IN.BoneWeights and IN.BoneIndices are stored in variables that should be previous declared. To achieve it it's necessary create two custom function nodes with two distinguished cginc files.

    The first one is only responsible for declaring the variables, it uses a macro that receives a dummy input and basically copy the value to the output, the reason for this is that we need that this node should be evaluated by the shader graph when generating the shader. The node with this custom function should came before the the Unity_LinearBlendSkinning_float call, this is why it's required two files, as the declaring function is executed before the Unity_LinearBlendSkinning_float, its file is included before the definition of Unity_LinearBlendSkinning_float function and we need to define a macro with this identifier but if we do this in the first file, the shader will not be able to define the function and the compilation is gonna fail.

    Code (CSharp):
    1. //UNITY_SHADER_NO_UPDATE
    2. #ifndef DECLAREBLENDPROPERTIES_INCLUDED
    3. #define DECLAREBLENDPROPERTIES_INCLUDED
    4.  
    5. #define DeclareBlendProperties_float(In, Out)\
    6. Out = In;\
    7. int4 VertexIndicies = int4(0,0,0,0);\
    8. float4 VertexWeights = float4(0,0,0,0);
    9.  
    10. #endif //DECLAREBLENDPROPERTIES_INCLUDED
    11.  
    The second file is responsible for two thing, define a function that will expose the declared variables (in the first file) and to define a macro that replaces the Unity_LinearBlendSkinning_float call for instruction that copy the parameters to our variables

    Code (CSharp):
    1. //UNITY_SHADER_NO_UPDATE
    2. #ifndef GETBLENDINGPROPERTIES_INCLUDED
    3. #define GETBLENDINGPROPERTIES_INCLUDED
    4.  
    5. #define Unity_LinearBlendSkinning_float(_indices, _weights, positionIn, normalIn, tangentIn, positionOut, normalOut, tangentOut)\
    6. positionOut = positionIn;\
    7. normalOut = normalIn;\
    8. tangentOut = tangentIn;\
    9. VertexIndicies = _indices;\
    10. VertexWeights = _weights;
    11.  
    12. #define GetBlendProperties_float(In, Out, OutVertexIndices, OutVertexWeights)\
    13. Out = In;\
    14. OutVertexIndices = asint(VertexIndicies);\
    15. OutVertexWeights = VertexWeights;
    16.  
    17. #endif //GETBLENDINGPROPERTIES_INCLUDED
    18.  
    Now, the nodes... First of all we NEED a Linear Blend Skinning node as this is the only node that can require the BoneIndices and BoneWeights to be included in the AttributesMesh then we have to declare our variables to do this add a node BEFORE Linear Blend Skinning (it can be in any input node) then add to the input of the new node the previous valeu that was feeding the LBS node (in my case the Position in the object space), as we already have our variables declared we should replace the Unity_LinearBlendSkinning_float call and access the values to do so add another node AFTER the LBS (again, it can be in any output value) the use the output value of the new node as the original value from LBS. Notice that the value will not be changed, even the LBS behaviour will not work as it's not being called anymore, but now you have access to BoneIndices and BoneWeights and there's only a restriction, it can only be used in the vertex shader.

    upload_2021-12-2_19-8-52.png

    And some errors will be logged in the console, thoses errors came from the intermediare shaders created the preview panel in the nodes, this errors should not be displayed and they should be ignored, unity is aware of this and they will fix it

    Drawback: LBS define a hybrid instance property _SkinMatrixIndex that is not used
     

    Attached Files:

    Last edited: Dec 2, 2021
  6. TLuthDidimo

    TLuthDidimo

    Joined:
    Jul 11, 2021
    Posts:
    9
    Hey @fmcdeoliveira,
    I tried to implement your solution but it generated an error 'Shader error in 'Master': syntax error: unexpected token 'out' at line 511 (on d3d11)'. The line doesn't correspond to anything relevant on the decompiled shaders, so that's no help.
    I thought perhaps that the signature to 'Unity_LinearBlendSkinning_float' might have changed but I can't find any reference to that function in the unity graphics (https://github.com/Unity-Technologies/Graphics.git) project so I assume it's some internal black box.
    Do you have any suggestions? Where did you find or how did you figure out that work around please?
     
  7. Forberg

    Forberg

    Joined:
    Oct 27, 2018
    Posts:
    25