0
\$\begingroup\$

I'm using Monogame to draw 2D primitives to the screen. To do that, rather than use included structures like VertexPositionColor, I wrote my own vertex class for 2D.

public struct VertexColor : IPositionable, IVertexType
{
    private static readonly VertexDeclaration Declaration = new VertexDeclaration
    (
        new VertexElement(0, VertexElementFormat.Vector2, VertexElementUsage.Position, 0),
        new VertexElement(8, VertexElementFormat.Color, VertexElementUsage.Color, 0)
    );

    public VertexColor(Vector2 position, Color color)
    {
        Position = position;
        Color = color;
    }

    public Vector2 Position { get; set; }
    public Color Color { get; set; }
    public VertexDeclaration VertexDeclaration => Declaration;
}

Here's my associated HLSL shader, meant to simply translate vertices from normalized space to screen space.

#define VShaderModel vs_4_0_level_9_1
#define PShaderModel ps_4_0_level_9_1

matrix Projection;

struct VertexShaderInput
{
    float4 Position : SV_Position0;
    float4 Color : Color0;
};

struct VertexShaderOutput
{
    float4 Position : SV_Position0;
    float4 Color : Color0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output = (VertexShaderOutput)0;

    output.Position = mul(input.Position, Projection);
    output.Color = input.Color;

    return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : Color
{
    return input.Color;
}

technique Technique0
{
    pass Pass0
    {
        VertexShader = compile VShaderModel VertexShaderFunction();
        PixelShader = compile PShaderModel PixelShaderFunction();
    }
};

Where Projection is an orthographic matrix computed in code and passed to the shader based on current window size. However, when I attempt to draw primitives, I receive the following exception:

An error occurred while preparing to draw. This is probably because the current vertex declaration does not include all the elements required by the current vertex shader. The current vertex declaration includes these elements: SV_Position0, COLOR0.

Now, I'm familiar with this exception and I understand what it means. The exception is telling me that my shader does not include all required elements based on the current vertex declaration. However, as you can see, my shader does include those two elements (SV_Position0 and Color0).

What am I missing here?

\$\endgroup\$
  • \$\begingroup\$ You have Color0 not COLOR0 \$\endgroup\$ – Sidar Nov 8 '17 at 7:45
  • \$\begingroup\$ Casing isn't relevant from my experience. Changing to capital letters doesn't fix the issue. \$\endgroup\$ – Grimelios Nov 8 '17 at 7:48
  • \$\begingroup\$ Then I can only assume something isn't setup correctly prior to compiling your shader. \$\endgroup\$ – Sidar Nov 8 '17 at 7:50
  • \$\begingroup\$ I can use other shaders successfully using the same compiler version. It's specifically trying to use custom vertex structures that's causing me problems. \$\endgroup\$ – Grimelios Nov 8 '17 at 7:51
  • \$\begingroup\$ Ehh...you are declaring : VertexElementFormat.Vector2 but in the shader it's a float4. Shouldn't that be a float2?In fact make that VertexElementFormat.Vector4 instead? \$\endgroup\$ – Sidar Nov 8 '17 at 9:46
2
\$\begingroup\$

I'm not an expert on semantics (I usually work from templates that have everything I need), so I may be barking up the wrong tree...

But I notice that, for instance, Unity's unlit shader defaults to using the POSITION semantic for vertex input:

struct appdata
{
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
};

And SV_POSITION for vertex output / interpolator & fragment input:

struct v2f
{
    float2 uv : TEXCOORD0;
    UNITY_FOG_COORDS(1)
    float4 vertex : SV_POSITION;
};

And switching the former from POSITION to SV_Position prevents the shader from compiling.

Microsoft's documentation for the SV_Position semantic says:

When used in a shader, SV_Position describes the pixel location.

While the POSITION[n] semantic is defined as "Vertex position in object space."

So this suggests to me that the SV_Position semantic is reserved for post-projection coordinates, and this is recognized as a different information channel than object space vertex positions. So this input in your shader fails to match your vertex declaration's VertexElementFormat.Vector2, VertexElementUsage.Position and is treated as a third stream of information that's missing from the vertex buffer provided, leading to the error.

If this is correct, changing VertexShaderInput to use POSITION0 instead of SV_Position0 should resolve the issue.

\$\endgroup\$
1
\$\begingroup\$

I actually solved this problem in a way I didn't expect. Before, I had been starting my SpriteBatch and passing in the HLSL effect shown above, then attempting to draw primitives using GraphicsDevice. That was a mistake, and simply applying the effect before drawing primitives (without starting SpriteBatch) fixed the problem.

To emphasize: I changed nothing about my shader or the vertex class. Apparently the interaction with SpriteBatch was causing problems. I'll mark this as accepted (since it did fix the problem), but thank you to everyone who answered.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.