Hi,I want to know how Slot.color is written into the VertexColor in a shader?
I'm facing an issue where I want to use float value with 7 decimal places e.g. 0.1234567 to make a vector4 (0.4524834, 0.5555556, 0.6055556, 1)
I want to set value by Slot.SetColor() method in runtime, but the value I get in vertex shader(the breakpoint in the image below) is already with 5 decimal places (0.45098, 0.55294, 0.60392, 1). I think they're converted in to half4 but I don't know which part should I check?

Or is there anything I can do to preserve the precision of the vector4 value and ensure it doesn't lose precision?

I'm using spine-runtime 4.0 and Spine-Sprite-URP shader.Thanks!

Related Discussions
...

@ara Your observations are correct that calculateVertexColor returns a half4. To be precise, return type in code is fixed4, but fixed4 is defined as half4 for all URP shaders (e.g. here in Spine-Sprite-URP.shader).

The main Spine-Sprite-URP shader can be found here:
EsotericSoftware/spine-runtimesblob/4.0/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Spine-Sprite-URP.shader#L131
The relevand method call is located here:
EsotericSoftware/spine-runtimesblob/4.0/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/Spine-Sprite-ForwardPass-URP.hlsl#L173

Now the method calculateVertexColor in question is provided here:
EsotericSoftware/spine-runtimesblob/4.0/spine-unity/Assets/Spine/Runtime/spine-unity/Shaders/Sprite/CGIncludes/ShaderShared.cginc#L280

In general you can browse all the shader code and the referenced include files, it's all included with the Spine URP Shaders package and spine-unity unitypackage. Note that the URP shaders sometimes reference spine-unity core shaders like #include SpineCoreShaders/SpriteLighting.cginc which includes #include "Packages/com.esotericsoftware.spine.spine-unity/Runtime/spine-unity/Shaders/Sprite/CGIncludes/SpriteLighting.cginc"".

Most of the time it's easiest to just use a text editor like Visual Studio Code or Notepad++ which can search all files recursively in a given directory. Then you can search for the desired functions from a common top-directory.

  • ara replied to this.

    Harald
    Harald Thanks Harald! I have checked and modified most of these shader functions into float4 like float4 calculateVertexColor(float4 color)
    I mean, before calling calculateVertexColor(),
    VertextInput.color was already a half4(fixed4).
    I don't know what operation had already be done before entering VertexOutputLWRP ForwardPassVertexSprite(VertexInput input)
    I want to find out what's the intermediate step between c# Slot.SetColor() and VertexInput.color.Thanks!

      ara
      Maybe the vertex inputs such as position (float4) and color (float4) are automatically converted to half4 data type during the shader compilation process? I wonder is there something I could do like Slot.SetExtraColor() and pass extra value to each vertex if data precision loss is inevitable.
      struct VertexInput
      {
      float4 vertex : POSITION;
      float4 texcoord : TEXCOORD0;
      float4 color : COLOR;
      float4 extraColor
      };

        ara I don't know what operation had already be done before entering VertexOutputLWRP ForwardPassVertexSprite(VertexInput input)
        I want to find out what's the intermediate step between c# Slot.SetColor() and VertexInput.color.

        All source code is provided. Please have a look at MeshGenerator.cs then. Anyway, you will find out that it's normal float values that are assigned there.

        It's most likely in the vertex shader where you are losing precision, at some point in the line

        output.vertexColor = calculateVertexColor(input.color);

        So either you didn't change output.vertexColor (which is VertexOutputLWRP.vertexColor), input.color (VertexInput.color), or fixed4 calculateVertexColor(fixed4 color).

        Note that VertexOutputLWRP also uses fixed4 at the vertexColor property.
        EsotericSoftware/spine-runtimesblob/4.0/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/Spine-Sprite-ForwardPass-URP.hlsl#L16

        If you are still having troubles, you could simply replace the define-section in Spine-Sprite-URP.shader to define both fixed and half as float:

        #define fixed4 float4
        #define fixed3 float3
        #define fixed float
        #define half4 float4
        #define half3 float3
        #define half float

        ara Maybe the vertex inputs such as position (float4) and color (float4) are automatically converted to half4 data type during the shader compilation process?

        No. You can always look at the generated output of the shader, (especially the pre-processed output) there you can see the resulting types after any preprocessor-defines have been inlined.

        In general I would highly recommend opening the shader directories with Visual Studio Code and just searching through the files, then you should quickly find the relevant code sections.

        • ara replied to this.

          Harald
          Thank you for providing such a detailed answer!
          1.I'v checked MeshGenerator.cs finding all Slot.rgba are saved into Color32 for vertexColorBuffer.Won't these steps cause precision lose()? color.r = (byte)(skeletonR * slot.R * c.r * 255);
          2.I'v changed (VertexOutputLWRP.vertexColor, VertexInput.colo, and calculateVertexColor()) still having troubles. Also changed the function content inside calculateVertexColor();The result still loses precision.
          3.An error occurred while following your last suggestion replace define-section(only #define half4/half3 will cause this error), I'm so sorry I don't know how to handle pipeline buildin redefinition.

          I'm already searching/working with code IDE, and using RenderDoc for debugging shader.

          I'v upload a simple version of modified shader directories.

          tinttest.zip
          5MB

            ara 1.I'v checked MeshGenerator.cs finding all Slot.rgba are saved into Color32 for vertexColorBuffer.Won't these steps cause precision lose()? color.r = (byte)(skeletonR * slot.R * c.r * 255);

            Oh, you're absolutely right, the code in MeshGenerator.cs is indeed using 8bit / channel colors, thus reducing precision. Sorry for the oversight, I somehow forgot about that!

            As a result, you now have two options:
            1) Modify MeshGenerator.cs accordingly, or create a MeshGenerator subclass and use this subclass instead.
            2) Don't use the Color vertex attribute for passing down precise information, but instead use e.g. the Normal attribute, which will be a constant (0, 0, -1) for 2D skeletons anyway. Then you could use e.g. the SkeletonRenderer.OnPostProcessVertices delegate to fill the normals with your desired precise floating point data.

            If you could briefly explain what you have in mind, perhaps we can help finding the easiest solution.

            ara 3.An error occurred while following your last suggestion replace define-section(only #define half4/half3 will cause this error), I'm so sorry I don't know how to handle pipeline buildin redefinition.

            This is unfortunate, there seems to be overloads where two function signatures differ only by floating point type. Anyway, changing the signatures of the used functions from fixed/half to float would be the better solution.

            • ara replied to this.

              Harald
              Thank you Harald! I'v modified MeshGenerator.cs and use uv2 for passing down precise information.We want to tint more than one color for each single slot similar to spine tintBlack feature.
              I'm following https://github.com/EsotericSoftware/spine-runtimes/commit/a8e6552b81515bc2d466eff0759e68b6e872ead5
              and it works for us.
              Some other things I don't know :
              Will extra variant uv2 per-skeleton data break batching or SRPBatcher?
              Is it better performance to split r2g2b2 data into Vector2 uv2,uv3 instead of storing them in a single Vector4 uv2?
              rgb2.x = slot.R2; //r
              rgb2.y = slot.G2; //g
              rgb2.z = slot.B2; //b
              rgb2.w = 1.0f;
              ResizeOptionalUVBuffer(ref uv2, vbiLength);
              if (this.uv2 != null)
              {
              mesh.SetUVs(1, this.uv2.Items);
              }

                ara Will extra variant uv2 per-skeleton data break batching or SRPBatcher?

                Using a different shader will definitely break batching. It does not matter whether you use additional vertex attributes at this batch or not.

                ara Is it better performance to split r2g2b2 data into Vector2 uv2,uv3 instead of storing them in a single Vector4 uv2?

                The main problem is that Unity's old Mesh API did not provide any option to pass higher dimension data than a Vector2 as UVn attributes. The newer Mesh API now allows to specify custom vertex layouts, but it's only supported in Unity 2019.3 and newer.

                It should not make a measurable difference though to use two float2 attributes (which likely really end up as two streams) instead of one float4.

                • ara replied to this.
                • ara likes this.

                  Harald
                  Sorry I didn't make my question clearly.
                  I mean, we have many SkeletonAnimation GameObjects, all of them have same skeletonDataAsset, same mesh same material with same shader.
                  Will my extra uv2,uv3 data which is set to different vector2 (runtime update per object different) break batching or SRPBatcher?

                  @ara No, it won't break batching then, quite the opposite - passing information via vertex attributes while using the same Material is the way to allow batching. 🙂

                  • ara likes this.