Creating a 2D polygon in XNA

11,397

Solution 1

Here it what I have right now.

A class that generates a BasicEffect with some desired asignments.

public class StandardBasicEffect : BasicEffect
{
    public StandardBasicEffect(GraphicsDevice graphicsDevice)
        : base(graphicsDevice)
    {
        this.VertexColorEnabled = true;
        this.Projection = Matrix.CreateOrthographicOffCenter(
            0, graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height, 0, 0, 1);
    }

    public StandardBasicEffect(BasicEffect effect)
        : base(effect) { }

    public BasicEffect Clone()
    {
        return new StandardBasicEffect(this);
    }
}

Here is my PolygonShape class

/// <summary>
/// A Polygon object that you will be able to draw.
/// Animations are being implemented as we speak.
/// </summary>
/// <param name="graphicsDevice">The graphicsdevice from a Game object</param>
/// <param name="vertices">The vertices in a clockwise order</param>
public PolygonShape(GraphicsDevice graphicsDevice, VertexPositionColor[] vertices)
{
    this.graphicsDevice = graphicsDevice;
    this.vertices = vertices;
    this.triangulated = false;

    triangulatedVertices = new VertexPositionColor[vertices.Length * 3];
    indexes = new int[vertices.Length];
}

/// <summary>
/// Triangulate the set of VertexPositionColors so it will be drawn correcrly        
/// </summary>
/// <returns>The triangulated vertices array</returns>}
public VertexPositionColor[] Triangulate()
{
    calculateCenterPoint();{
    setupIndexes();
    for (int i = 0; i < indexes.Length; i++)
    {
        setupDrawableTriangle(indexes[i]);
    }

    triangulated = true;
    return triangulatedVertices;
}

/// <summary>
/// Calculate the center point needed for triangulation.
/// The polygon will be irregular, so this isn't the actual center of the polygon
/// but it will do for now, as we only need an extra point to make the triangles with</summary>
private void calculateCenterPoint()
{
    float xCount = 0, yCount = 0;

    foreach (VertexPositionColor vertice in vertices)
    {
        xCount += vertice.Position.X;
        yCount += vertice.Position.Y;
    }

    centerPoint = new Vector3(xCount / vertices.Length, yCount / vertices.Length, 0);
}

private void setupIndexes()
{
    for (int i = 1; i < triangulatedVertices.Length; i = i + 3)
    {
        indexes[i / 3] = i - 1;
    }
}

private void setupDrawableTriangle(int index)
{
    triangulatedVertices[index] = vertices[index / 3]; //No DividedByZeroException?...
    if (index / 3 != vertices.Length - 1)
        triangulatedVertices[index + 1] = vertices[(index / 3) + 1];
    else
        triangulatedVertices[index + 1] = vertices[0];
    triangulatedVertices[index + 2].Position = centerPoint;
}

/// <summary>
/// Draw the polygon. If you haven't called Triangulate yet, I wil do it for you.
/// </summary>
/// <param name="effect">The BasicEffect needed for drawing</param>
public void Draw(BasicEffect effect)
{
    try
    {
        if (!triangulated)
            Triangulate();

        draw(effect);
    }
    catch (Exception exception)
    {
        throw exception;
    }
}

private void draw(BasicEffect effect)
{
    effect.CurrentTechnique.Passes[0].Apply();
    graphicsDevice.DrawUserPrimitives<VertexPositionColor>(
        PrimitiveType.TriangleList, triangulatedVertices, 0, vertices.Length);
}

Sorry, it's kind of alot. Now for my next quest. Animation my polygon.

Hope it helped fellow people with the same problem.

Solution 2

this code is useful to draw 2D lines, some calcs can be done into an initilization call, but i prefer for this example to keep all together.

 public void DrawLine(VertexPositionColor[] Vertices)
    {           
        Game.GraphicsDevice.DepthStencilState = DepthStencilState.Default;

        Vector2 center;
        center.X = Game.GraphicsDevice.Viewport.Width * 0.5f;
        center.Y = Game.GraphicsDevice.Viewport.Height * 0.5f;

        Matrix View = Matrix.CreateLookAt( new Vector3( center, 0 ), new Vector3( center, 1 ), new Vector3( 0, -1, 0 ) );
        Matrix Projection = Matrix.CreateOrthographic( center.X * 2, center.Y * 2, -0.5f, 1 );
        Effect EffectLines = Game.Content.Load<Effect>( "lines" );
        EffectLines.CurrentTechnique = EffectLines.Techniques["Lines"];

        EffectLines.Parameters["xViewProjection"].SetValue( View * Projection );
        EffectLines.Parameters["xWorld"].SetValue( Matrix.Identity );

        foreach ( EffectPass pass in EffectLines.CurrentTechnique.Passes )
        {
            pass.Apply( );
            Game.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>
                ( PrimitiveType.LineList, Vertices, 0, Vertices.Length/2 );
        }            
    }

LINES.FX

uniform float4x4 xWorld;
uniform float4x4 xViewProjection;

void VS_Basico(in float4 inPos : POSITION,  in float4 inColor: COLOR0,  out float4     outPos: POSITION,    out float4 outColor:COLOR0 )
{
    float4 tmp = mul (inPos, xWorld);
    outPos = mul (tmp, xViewProjection);
    outColor = inColor; 
}

float4 PS_Basico(in float4 inColor:COLOR) :COLOR
{
return inColor;
}


technique Lines
{
pass Pass0
    {   
        VertexShader = compile vs_2_0 VS_Basico();
        PixelShader = compile ps_2_0 PS_Basico();
        FILLMODE = SOLID;
        CULLMODE = NONE;        
    }  
}

Solution 3

I worked with XNA in the past on a physics simulation where I had to draw bounding boxes with GraphicsDevice.DrawIndexedPrimitives (You should google or MSDN for this function for more worked examples.)

The below code is what I used in my project for drawing a 3D geometry.

/// <summary>
/// Draw the primitive.
/// </summary>
/// <param name="world">World Matrix</param>
/// <param name="view">View Matrix</param>
/// <param name="projection">Projection Matrix</param>
/// <param name="color">Color of the primitive</param>
public void Draw(Matrix world, Matrix view, Matrix projection, Color color)
{
    _mGraphicsDevice.VertexDeclaration = _mVertexDeclaration;
    _mGraphicsDevice.Vertices[0].SetSource(_mVertexBuffer, 0, VertexPositionNormal.SizeInBytes);
    _mGraphicsDevice.Indices = _mIndexBuffer;

    _mBasicEffect.DiffuseColor = color.ToVector3();
    _mBasicEffect.World = _mTransform * world;
    _mBasicEffect.View = view;
    _mBasicEffect.Projection = projection;

    int primitiveCount = _mIndex.Count / 3;

    _mBasicEffect.Begin();
    foreach (EffectPass pass in _mBasicEffect.CurrentTechnique.Passes)
    {
        pass.Begin();
        _mGraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, _mVertex.Count, 0, primitiveCount);
        pass.End();
    }
    _mBasicEffect.End();
}

This function is a member method of a geometry object (class) and is called from the Game class' Draw(GameTime) method

Share:
11,397
Jordy Langen
Author by

Jordy Langen

Updated on June 04, 2022

Comments

  • Jordy Langen
    Jordy Langen almost 2 years

    I have some sort of a problem. I'm new to XNA and want to draw a polygon shape that looks something like this (In the end, I want these point to be random):

    Polygon within a rectangle

    So I read some articles and this is what I ended up with:

    private VertexPositionColor[] vertices;
    
    public TextureClass()
    {
        setupVertices();
    }
    
    public override void Render(SpriteBatch spriteBatch)
    {
        Texture2D texture = createTexture(spriteBatch);
        spriteBatch.Draw(texture, new Rectangle((int)vertices[0].Position.X, (int)vertices[0].Position.Y, 30, 30), Color.Brown);
    }
    
    private Texture2D createTexture(SpriteBatch spriteBatch)
    {
        Texture2D texture = new Texture2D(spriteBatch.GraphicsDevice, 1, 1, false, SurfaceFormat.Color);
        texture.SetData<Color>(new Color[] { Color.Brown });
        return texture;
    }
    

    When I call Render it's starts drawing some squares as if it where in a loop. I'm just guessing I'm doing it all wrong. I would love it if someones points me into the right direction. Just creating a polygon and drawing it. It seemed so simple...

  • Jordy Langen
    Jordy Langen over 12 years
    Could you show me how the _mVertexDeclaration, _mIndexBuffer and _mVertexBuffer objects look like?
  • Jake
    Jake over 12 years
    They look exactly like what they are. Check the API for GraphicsDevice.VertexDeclaration, GraphicsDevice.Indices and Microsoft.Xna.Framework.Graphics.VertexBuffer respectively.
  • Jordy Langen
    Jordy Langen over 12 years
    I tried your solution but i'm getting this errormessage: Both a vertex shader and pixel shader must be set on the device before any draw operations may be performed.
  • Blau
    Blau over 12 years
    i have added the pixel shader to lines.fx