Question

I'm working on a CG shader which will do a limited amount of vertex animation (or 'morphing') on low end hardware. I'll be packing animation frames into extra texcoords (the limited resolution is acceptable for what I need to do ) and interpolating between them at runtime based on a control value provided by the host program - effectively a slider that goes from pose 1 to N (N is probably 6, that looks like the number of texcoords I have to play with).

I know how to implement the catmull interpolation in a conventional programming context, but I'm not sure the right approach to take in a shader. Here's some concrete questions:

1) I've seen the catmull interpolation expressed in algebraic and matrix form (examples here. Is one form likely to be more performant than the other on OGL-ES2 hardware?

2) I've got the alegebraic form working for a sequence of floats; it works fine. However I can't seem to declare an array of float4s to hold may data. If I change the line uniform float Key[8] in this example:

sampler2D _MainTex;
float     _KeyTime;
uniform float Key[8];

    struct v2f {
            float4 pos   : SV_POSITION;
            float4 color : COLOR0;


        };

    float4 catmull (float p0, float p1, float p2, float  p3, fixed t)
        {

        fixed t2 = pow(t, 2);
        fixed t3 = pow(t, 3);
        return .5 * ((2.0 * p1) + (-1 * p0 + p2) * t + 
                (2 * p0 - 5 * p1 + 4 * p2 - p3) * t2 +
                (-1 * p0 + 3 * p1 - 3 * p2 + p3) * t3)
                ;
        }


    v2f vert (appdata_base v)
        {
            v2f o;
            o.pos = mul (UNITY_MATRIX_MVP, v.vertex);

            Key[0] = float(1);
            Key[1] = float(1);
            Key[2] =  float(.8);
            Key[3] =  float(.6);
            Key[4] =  float(.4);
            Key[5] =  float(.2);
            Key[6] =  float(.1);
            Key[7] =  float(.1);
            int prior = trunc(_KeyTime);

            o.color = catmull(Key[prior], 
                            Key[prior + 1],
                             Key[prior + 2], 
                             Key[prior + 3], 
                             frac(_KeyTime));
            return o;

to uniform float4[8] Key; the shader still compiles but I get an error from unity saying 'No subshaders can be run on this hardware', which I take to be a misleading reflection of something else (I've got plenty of other shaders with multipass and so on that work fine). If I declare the array inside the vert program instead of as a uniform, I get an error that arrays with non static indexers need to be uniform. So, is there a way out of this mess?

PS I hastily changed the catmull function to work on floats just to test the hypothesis that it was something about declaring an array of float4s that caused the problem.

Was it helpful?

Solution 2

For future readers:

The resolution is that evidently does not want to compile shaders that include dynamic indexes - this won't work on all platforms and so the compiler is apparently over-zealous in deciding not to allow it in the case of the targets I was aiming at (IOS 6+ / DX9). So it's 'by design' rather than a bug, although that does not make it less annoying.

The best workaround I've been able to come up with is to use Float4x4s as if they were 16 -unit arrays. You can grab the correct values by using float4 vectors with all zero except for the correct row and column you want to select. Multiply the column vector by the matrix (as if transforming it), then dot that against the row vector. That gives the item at [row, column]. It's a pain in the butt workaround but it does work. Obviously the same trick could be used sans dot product step to extract rows only as float4s.

OTHER TIPS

I notice that you declare your catrom output float4 while the inputs are float. Why?

Try actually doing what you say you plan to do: declare the Key values as part of the input vertex data. Declaring it as "uniform" in this context seems awkward and may confuse the compiler, just make it part of the input struct and don't try to over-write the values in the shader. Declaring extra values on texcoords in this way is extremely common for animation skinning.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top