在XNA中创建2D多边形

7

我有一个问题。我是XNA的新手,想要绘制一个多边形,看起来像这样(最终,我希望这些点是随机的):

矩形内的多边形

所以我阅读了一些文章,最终得到了以下代码:

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;
}

当我调用Render时,它开始绘制一些正方形,就好像它在一个循环中一样。我猜我做错了什么。如果有人能指点我正确的方向,我会非常感激。只是创建一个多边形并将其绘制出来。它看起来很简单...

第一次设置后,您是否更改顶点? - Cameron
不,我只调用一次Render函数。 - Jordy Langen
你从哪里调用了Render函数? - Dave Carlile
我是从游戏更新中调用它的。我已经找到了另一个解决方案,我会在这里发布给那些也想看到它的人。 - Jordy Langen
2
如果你是从Update中调用它,那么实际上你每帧都在创建一个新的纹理,这并不是你想要做的事情。确保在你的新解决方案中处理好这个问题。 - Dave Carlile
谢谢你指出这个问题。也许你可以快速看一下我的另一个问题http://stackoverflow.com/questions/7258880/animating-a-polygon-drawn-with-vertices。是的,我只在游戏的绘制方法中调用了多边形类中的Draw函数一次。 - Jordy Langen
3个回答

4

我现在有这个。

一个生成具有所需分配的BasicEffect类。

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);
    }
}

这是我的多边形形状类:
/// <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);
}

抱歉,内容有点多。现在,让我们继续下一个任务。动画我的多边形。

希望这对遇到相同问题的人有所帮助。


我刚在我的MonoGame项目中尝试了它。它非常好用!除了阴影有点奇怪,但它可靠地绘制多边形。我相信奇怪的着色效果——一种隧道效果——是由于投影矩阵引起的。我正在研究这个问题,但除此之外,它的表现如广告所述!干得好! - Frecklefoot

2

这段代码可以用于绘制2D线条,一些计算可以在初始化调用中完成,但我更喜欢在此示例中将所有内容放在一起。

 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;        
    }  
}

我尝试了你的解决方案,但是出现了这个错误信息:在执行任何绘制操作之前,设备必须设置顶点着色器和像素着色器。 - Jordy Langen
我已经将像素着色器添加到lines.fx文件中。 - Blau

1

我曾经在一个物理模拟项目中使用过XNA,其中我需要使用GraphicsDevice.DrawIndexedPrimitives绘制边界框(您可以通过谷歌或MSDN查找此函数以获取更多的示例)。

以下代码是我在项目中用于绘制3D几何体的代码。

/// <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();
}

这个函数是几何对象(类)的成员方法,并从Game类的Draw(GameTime)方法中调用。


你能给我展示一下 _mVertexDeclaration、_mIndexBuffer 和 _mVertexBuffer 对象的样子吗? - Jordy Langen
它们看起来与它们实际上一样。分别检查 GraphicsDevice.VertexDeclaration、GraphicsDevice.Indices 和 Microsoft.Xna.Framework.Graphics.VertexBuffer 的 API。 - Jake

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接