Thank you to anyone who has already donated - your generous donations helped make three months of treatment possible.

My brother Nate continues to fight stage IV Hodgkin's lymphoma. He's just 31, with a wife and baby girl. They have no active income (since he's been unable to return to work), no insurance, and cannot afford the treatment he needs. Nate and his family need your help. Please consider a donation, every dollar helps. Thanks.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
**Step 1 - Writing Vertex Shader**

You can use a vertex shader to rotate the sprite around different axes than the default one. This is the vertex shader I used:

    sampler TextureSampler : register(s0);
    float2 ViewportSize;
    float4x4 Matrix;
     
    void SpriteVertexShader(inout float4 color : COLOR0, inout float2 texCoord : TEXCOORD0, inout float4 position : POSITION0)
    {
       // This is the important step
       position.xy = mul(position, Matrix).xy;
       
       // Half pixel offset for correct texel centering.
       position.xy -= 0.5;
     
       // Viewport adjustment
       position.xy = position.xy / ViewportSize;
       position.xy *= float2(2, -2);
       position.xy -= float2(1, -1);
    }
     
    technique SpriteBatch
    {
        pass
        {
            VertexShader = compile vs_2_0 SpriteVertexShader();
        }
    }

It's actually 99% boilerplate code required for any vertex shader to work with SpriteBatch, and the only line of code that I added was:

    position.xy = mul(position, Matrix).xy;

I'm only touching the X and Y coordinates otherwise the polygons would end up being clipped by the near and far planes when it rotates.

**Step 2 - Using the Vertex Shader**

Load the effect file and set the ViewportSize parameter right away since it's required by the shader:

    effect = Content.Load<Effect>("Effect1");
    effect.Parameters["ViewportSize"].SetValue(new Vector2(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height));

Then you have to update the Matrix attribute inside the shader with whatever rotation matrix you want to apply. This is what I did:

    Matrix matrix = Matrix.CreateRotationX(MathHelper.ToRadians(60f)) *
                    Matrix.CreateRotationY(MathHelper.ToRadians(30f));

    effect.Parameters["Matrix"].SetValue(matrix);

But the vertices inside the shader are already defined in world space, not in model space, so you might need to compensate for that in the matrix otherwise the position will appear to change too.

Finally, use the effect object when calling SpriteBatch.Begin:

    spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, effect);

**EDIT - Alternative using BasicEffect**

Managed to get the same results with the built-in BasicEffect class.

    BasicEffect basicEffect = new BasicEffect(GraphicsDevice);
    Matrix projection = Matrix.CreateOrthographicOffCenter(0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, -1000, 1000);
    Matrix halfPixelOffset = Matrix.CreateTranslation(-0.5f, -0.5f, 0);
    basicEffect.World = Matrix.Identity;
    basicEffect.View = Matrix.Identity;
    basicEffect.Projection = halfPixelOffset * projection;
    basicEffect.TextureEnabled = true;
    basicEffect.VertexColorEnabled = true;

Was not sure how to prevent the clipping from the near and far planes in this case, so I enlarged the range.

Next update the matrix with:

    basicEffect.World = matrix;

And draw as before but using this instance instead.