【问题标题】:How Do I Draw 3D Primitives in WP如何在 WP 中绘制 3D 图元
【发布时间】:2013-04-11 15:13:15
【问题描述】:

我是 XNA 的新手,几天来我一直在尝试解决这个问题,但每次我尝试完成它时都会遇到异常,或者应用程序只是简单地退出,这非常令人恼火.

我希望能够绘制 3D 图元,而无需为其预先制作模型。我先有这段代码:

VertexPositionColor[] primitiveList = { new VertexPositionColor(
                    new Vector3(1,1,0), Color.White), new VertexPositionColor(
                    new Vector3(0,1,-1), Color.White) };

short[] lineListIndices = { 0, 1 };

Controller.CurrentGame.GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionColor>(
    PrimitiveType.LineList,
    primitiveList,
    0,  // vertex buffer offset to add to each element of the index buffer
    2,  // number of vertices in pointList
    lineListIndices,  // the index buffer
    0,  // first index element to read
    1   // number of primitives to draw
);

我得到了一个 InvalidOperationException 和以下内容

消息“在执行任何绘制操作之前,必须在设备上设置顶点着色器和像素着色器。”

然后我尝试按照http://msdn.microsoft.com/en-us/library/bb203926.aspx 上的说明进行操作,最终得到以下代码:

BasicEffect basicEffect = new BasicEffect(Controller.Graphics.GraphicsDevice);

basicEffect.World = Matrix.Identity;
basicEffect.View = Controller.Cam.view;
basicEffect.Projection = Controller.Cam.projection;

// primitive color
basicEffect.AmbientLightColor = new Vector3(0.1f, 0.1f, 0.1f);
basicEffect.DiffuseColor = new Vector3(1.0f, 1.0f, 1.0f);
basicEffect.SpecularColor = new Vector3(0.25f, 0.25f, 0.25f);
basicEffect.SpecularPower = 5.0f;
basicEffect.Alpha = 1.0f;

basicEffect.LightingEnabled = true;
if (basicEffect.LightingEnabled)
{
    basicEffect.DirectionalLight0.Enabled = true; // enable each light individually
    if (basicEffect.DirectionalLight0.Enabled)
    {
        // x direction
        basicEffect.DirectionalLight0.DiffuseColor = new Vector3(1, 0, 0); // range is 0 to 1
        basicEffect.DirectionalLight0.Direction = Vector3.Normalize(new Vector3(-1, 0, 0));
        // points from the light to the origin of the scene
        basicEffect.DirectionalLight0.SpecularColor = Vector3.One;
    }

    basicEffect.DirectionalLight1.Enabled = true;
    if (basicEffect.DirectionalLight1.Enabled)
    {
        // y direction
        basicEffect.DirectionalLight1.DiffuseColor = new Vector3(0, 0.75f, 0);
        basicEffect.DirectionalLight1.Direction = Vector3.Normalize(new Vector3(0, -1, 0));
        basicEffect.DirectionalLight1.SpecularColor = Vector3.One;
    }

    basicEffect.DirectionalLight2.Enabled = true;
    if (basicEffect.DirectionalLight2.Enabled)
    {
        // z direction
        basicEffect.DirectionalLight2.DiffuseColor = new Vector3(0, 0, 0.5f);
        basicEffect.DirectionalLight2.Direction = Vector3.Normalize(new Vector3(0, 0, -1));
        basicEffect.DirectionalLight2.SpecularColor = Vector3.One;
    }
}

VertexDeclaration vertexDeclaration = new VertexDeclaration(new VertexElement[]
    {
        new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
        new VertexElement(12, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0),
        new VertexElement(24, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0)
    }
);

Vector3 topLeftFront = new Vector3(-1.0f, 1.0f, 1.0f);
Vector3 bottomLeftFront = new Vector3(-1.0f, -1.0f, 1.0f);
Vector3 topRightFront = new Vector3(1.0f, 1.0f, 1.0f);
Vector3 bottomRightFront = new Vector3(1.0f, -1.0f, 1.0f);
Vector3 topLeftBack = new Vector3(-1.0f, 1.0f, -1.0f);
Vector3 topRightBack = new Vector3(1.0f, 1.0f, -1.0f);
Vector3 bottomLeftBack = new Vector3(-1.0f, -1.0f, -1.0f);
Vector3 bottomRightBack = new Vector3(1.0f, -1.0f, -1.0f);

Vector2 textureTopLeft = new Vector2(0.0f, 0.0f);
Vector2 textureTopRight = new Vector2(1.0f, 0.0f);
Vector2 textureBottomLeft = new Vector2(0.0f, 1.0f);
Vector2 textureBottomRight = new Vector2(1.0f, 1.0f);

Vector3 frontNormal = new Vector3(0.0f, 0.0f, 1.0f);
Vector3 backNormal = new Vector3(0.0f, 0.0f, -1.0f);
Vector3 topNormal = new Vector3(0.0f, 1.0f, 0.0f);
Vector3 bottomNormal = new Vector3(0.0f, -1.0f, 0.0f);
Vector3 leftNormal = new Vector3(-1.0f, 0.0f, 0.0f);
Vector3 rightNormal = new Vector3(1.0f, 0.0f, 0.0f);

VertexPositionNormalTexture[] cubeVertices = new VertexPositionNormalTexture[6];

// Front face.
cubeVertices[0] =
    new VertexPositionNormalTexture(
    topLeftFront, frontNormal, textureTopLeft);
cubeVertices[1] =
    new VertexPositionNormalTexture(
    bottomLeftFront, frontNormal, textureBottomLeft);
cubeVertices[2] =
    new VertexPositionNormalTexture(
    topRightFront, frontNormal, textureTopRight);
cubeVertices[3] =
    new VertexPositionNormalTexture(
    bottomLeftFront, frontNormal, textureBottomLeft);
cubeVertices[4] =
    new VertexPositionNormalTexture(
    bottomRightFront, frontNormal, textureBottomRight);
cubeVertices[5] =
    new VertexPositionNormalTexture(
    topRightFront, frontNormal, textureTopRight);

RasterizerState rasterizerState1 = new RasterizerState();
rasterizerState1.CullMode = CullMode.None;
Controller.Graphics.GraphicsDevice.RasterizerState = rasterizerState1;
foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
{
    pass.Apply();

    Controller.Graphics.GraphicsDevice.DrawPrimitives(
        PrimitiveType.TriangleList,
        0,
        12
    );
}

我得到以下异常

消息“在执行任何绘制操作之前,必须在设备上设置一个有效的顶点缓冲区(以及一个有效的索引缓冲区,如果您使用索引图元)。”

我知道我不应该将所有这些代码都放在同一个地方,但我只是希望能够得到一些东西来绘制,这样我就可以看到它是如何工作的,但没有任何工作,而且我似乎无法加载任何示例到 VS 中。

正如我所说,我是个新手,我也非常感谢任何能够为 3D XNA 指明正确方向的阅读材料。感谢您的阅读。

【问题讨论】:

  • 文档有时会有所帮助。不幸的是,DrawPrimitives 不是很有用,但 DrawIndexedPrimitives has some example code 向您展示了您需要设置的内容。
  • 啊!谢谢,我会看看它,看看它是怎么回事。

标签: visual-studio-2012 3d xna windows-phone


【解决方案1】:

在您的第一个示例中,您正确地绘制了一个顶点列表,但正如错误所说,它没有着色器。关于着色器的快速说明:由于 WP7 上没有自定义着色器,这意味着您没有应用任何 Effect; WP7 仅限于可以在here 中找到的Effect 子类。它们本质上包含内置着色器。

在第二个示例中,您设置了一个着色器,但现在您没有从任何列表或缓冲区进行绘制。 DrawUserIndexedPrimitves 采用索引和顶点数组。它使用那些来绘制。 DrawPrimitives 没有;它依赖于绑定到图形设备的顶点缓冲区。

要么将第二个示例更改为 DrawUserIndexedPrimitives 并传入你的数组(cubeVertices 和...等等,你没有索引数组,创建一个),或者设置一个 VertexBuffer相同的信息并绑定如下:

Controller.Graphics.GraphicsDevice.SetVertexBuffer(vb);

【讨论】:

  • 那么在幕后哪种方式更有效?或者期望能够组合来自不同函数的多个原语以形成一个大网格以最小化发送到 GPU 的调用数量,哪种方式会更好?
  • 就批量处理多个顶点而言,您可以使用任何一种方法;只需在同一个绘图调用中尽可能多地放置,无论是直接绘制图元还是缓冲。提交到图形卡通常会以任何一种方式完成。缓冲通过以更适合 GPU 的格式存储顶点来提供优势,从而节省一些将所有这些顶点煮沸的工作。
  • 好吧,我尝试使用第一个示例来保持简单,并制作了一个 BasicEffect 并且它可以工作。但是,即使我已将顶点指定为黑色,该线仍显示为白色。此处的代码:pastebin.com/n8QnVWKJ 我想使用缓冲区,但据我所知,您只能“设置”缓冲区而不能附加缓冲区。谢谢。
  • 您使用的是顶点着色但不是enabling it
  • 谢谢伙计。它现在完美运行。我将了解如何获取多边形并将所有内容合并到一个缓冲区中。您是否碰巧知道如何在加载时组合许多不同的缓冲区(假设相同的纹理或根本没有纹理)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-28
  • 2019-07-01
  • 2019-11-30
  • 1970-01-01
  • 2021-07-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多