Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a 2D polygon in XNA

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...

like image 940
Jordy Langen Avatar asked Aug 30 '11 16:08

Jordy Langen


3 Answers

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.

like image 187
Jordy Langen Avatar answered Nov 16 '22 16:11

Jordy Langen


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;        
    }  
}
like image 2
Blau Avatar answered Nov 16 '22 16:11

Blau


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

like image 1
Jake Avatar answered Nov 16 '22 17:11

Jake