InvalidCallException in 3D primitives code attempt
Hello,
Lacking full examples in the docs, I threw together some of the sample code in the How to: Draw 3D Primitives section, probably incorrectly, and am getting an InvalidCallException on the following line:
graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleList, 12, nonIndexedCube);
The details of the exception are not helpful. They say "External component has thrown an exception." My code is below, hopefully this forum formats it ok, without smiley faces etc.
Any suggestions appreciated. By the way, I am using an ATI Radeon Mobility X600 and had no problems compiling and running the Spacewar demo.
- Matteus
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Components;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
namespace _dTest
{
/// <summary>
/// This is the main type for your game
/// </summary>
partial class Game1 : Microsoft.Xna.Framework.Game
{
VertexPositionColor[] nonIndexedCube;
public Game1()
{
InitializeComponent();
nonIndexedCube = new VertexPositionColor[36];
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);
// Front face
nonIndexedCube[0] =
new VertexPositionColor( topLeftFront, Color.Red );
nonIndexedCube[1] =
new VertexPositionColor( bottomLeftFront, Color.Red );
nonIndexedCube[2] =
new VertexPositionColor( topRightFront, Color.Red );
nonIndexedCube[3] =
new VertexPositionColor( bottomLeftFront, Color.Red );
nonIndexedCube[4] =
new VertexPositionColor( bottomRightFront, Color.Red );
nonIndexedCube[5] =
new VertexPositionColor( topRightFront, Color.Red );
// Back face
nonIndexedCube
=
new VertexPositionColor( topLeftBack, Color.Orange );
nonIndexedCube[7] =
new VertexPositionColor( topRightBack, Color.Orange );
nonIndexedCube
=
new VertexPositionColor( bottomLeftBack, Color.Orange );
nonIndexedCube[9] =
new VertexPositionColor( bottomLeftBack, Color.Orange );
nonIndexedCube[10] =
new VertexPositionColor( topRightBack, Color.Orange );
nonIndexedCube[11] =
new VertexPositionColor( bottomRightBack, Color.Orange );
// Top face
nonIndexedCube[12] =
new VertexPositionColor( topLeftFront, Color.Yellow );
nonIndexedCube[13] =
new VertexPositionColor( topRightBack, Color.Yellow );
nonIndexedCube[14] =
new VertexPositionColor( topLeftBack, Color.Yellow );
nonIndexedCube[15] =
new VertexPositionColor( topLeftFront, Color.Yellow );
nonIndexedCube[16] =
new VertexPositionColor( topRightFront, Color.Yellow );
nonIndexedCube[17] =
new VertexPositionColor( topRightBack, Color.Yellow );
// Bottom face
nonIndexedCube[18] =
new VertexPositionColor( bottomLeftFront, Color.Purple );
nonIndexedCube[19] =
new VertexPositionColor( bottomLeftBack, Color.Purple );
nonIndexedCube[20] =
new VertexPositionColor( bottomRightBack, Color.Purple );
nonIndexedCube[21] =
new VertexPositionColor( bottomLeftFront, Color.Purple );
nonIndexedCube[22] =
new VertexPositionColor( bottomRightBack, Color.Purple );
nonIndexedCube[23] =
new VertexPositionColor( bottomRightFront, Color.Purple );
// Left face
nonIndexedCube[24] =
new VertexPositionColor( topLeftFront, Color.Blue );
nonIndexedCube[25] =
new VertexPositionColor( bottomLeftBack, Color.Blue );
nonIndexedCube[26] =
new VertexPositionColor( bottomLeftFront, Color.Blue );
nonIndexedCube[27] =
new VertexPositionColor( topLeftBack, Color.Blue );
nonIndexedCube[28] =
new VertexPositionColor( bottomLeftBack, Color.Blue );
nonIndexedCube[29] =
new VertexPositionColor( topLeftFront, Color.Blue );
// Right face
nonIndexedCube[30] =
new VertexPositionColor( topRightFront, Color.Green );
nonIndexedCube[31] =
new VertexPositionColor( bottomRightFront, Color.Green );
nonIndexedCube[32] =
new VertexPositionColor( bottomRightBack, Color.Green );
nonIndexedCube[33] =
new VertexPositionColor( topRightBack, Color.Green );
nonIndexedCube[34] =
new VertexPositionColor( topRightFront, Color.Green );
nonIndexedCube[35] =
new VertexPositionColor( bottomRightBack, Color.Green );
}
protected override void Update()
{
// The time since Update was called last
float elapsed = (float)ElapsedTime.TotalSeconds;
// TODO: Add your game logic here
// Let the GameComponents update
UpdateComponents();
}
protected override void Draw()
{
// Make sure we have a valid device
if (!graphics.EnsureDevice())
{
return;
}
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
using (VertexDeclaration decl = new VertexDeclaration(
graphics.GraphicsDevice, VertexPositionColor.VertexElements))
{
graphics.GraphicsDevice.VertexDeclaration = decl;
graphics.GraphicsDevice.RenderState.CullMode =
CullMode.CullClockwiseFace;
graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleList, 12, nonIndexedCube);
}
graphics.GraphicsDevice.EndScene();
graphics.GraphicsDevice.Present();
}
}
}
[6134 byte] By [
MatteusX] at [2007-12-25]
I've been having the same problem and I'm trying to figure it out. I don't have an answer, but here's some information that's hopefully helpful for someone on the XNA team to help us figure out what the issue is.
Here's the stack trace from my code, which is pretty much identical to yours:
{"External component has thrown an exception."}
at Microsoft.Xna.Framework.Graphics.GraphicsDevice.DrawUserPrimitives[T](PrimitiveType primitiveType, Int32 primitiveCount, T[] vertexStreamZeroData)
at DrawCub.Game1.Draw() in [MyDirectoryOmitted]\DrawCube\Game1.cs:line 147
at Microsoft.Xna.Framework.Game.DoDraw()
at Microsoft.Xna.Framework.Game.Paint(Object sender, EventArgs e)
at Microsoft.Xna.Framework.GameWindow.OnPaint()
at Microsoft.Xna.Framework.WindowsGameWindow.mainForm_Paint(Object sender, PaintEventArgs e)
at System.Windows.Forms.Control.OnPaint(PaintEventArgs e)
at System.Windows.Forms.Form.OnPaint(PaintEventArgs e)
at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
at System.Windows.Forms.Control.WmPaint(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
There's no inner exception in the exception.
Edit: It looks like the problem is we both forgot to put graphics.GraphicsDevice.BeginScene(); after clearing the graphics device and before trying to draw the triangles.
However, I still do not see a cube when I run the example; I just get a black screen. I'm still investgating what could be causing this. My guess is that we need to set up a BasicEffect or a shader so that we have some primitive lighting and can set up the matrices. I'm trying this now, but the help files on BasicEffects appear to throw this same error.
Would it be possible for the XNA team to post a full example of drawing a 3D Primitive?
Alright. I got things working; you do need to apply a basic effect to set the world, view, and projection matrix. However, when I draw I get a plain grey cube. I'm not sure why the colors specified by the VertexPositionColor are being ignored. I imagine there's some sort of default lighting, but I can't seem to disable it.
Here's my code. Sorry if the formatting is really bad, I couldn't figure out how to get the forums to display it nicely.
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Components;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
namespace DrawCub
{
/// <summary>
/// This is the main type for your game
/// </summary>
partial class Game1 : Microsoft.Xna.Framework.Game
{
VertexPositionColor[] nonIndexedCube = new VertexPositionColor[36];
VertexDeclaration decl;
BasicEffect effect;
Matrix world, view, projection;
public Game1()
{
InitializeComponent();
effect = new BasicEffect(graphics.GraphicsDevice, null);
world = Matrix.CreateTranslation(new Vector3(0, 0, 0));
view = Matrix.CreateLookAt(new Vector3(3, 3, 0), Vector3.Zero, Vector3.Up);
projection = Matrix.CreatePerspectiveFieldOfView((float)Math.PI / 2.0f, (float)Window.ClientWidth / (float)Window.ClientHeight, 0.1f, 1000.0f);
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);
// Front face
nonIndexedCube[0] =
new VertexPositionColor(topLeftFront, Color.Red);
nonIndexedCube[1] =
new VertexPositionColor(bottomLeftFront, Color.Red);
nonIndexedCube[2] =
new VertexPositionColor(topRightFront, Color.Red);
nonIndexedCube[3] =
new VertexPositionColor(bottomLeftFront, Color.Red);
nonIndexedCube[4] =
new VertexPositionColor(bottomRightFront, Color.Red);
nonIndexedCube[5] =
new VertexPositionColor(topRightFront, Color.Red);
// Back face
nonIndexedCube
=
new VertexPositionColor(topLeftBack, Color.Orange);
nonIndexedCube[7] =
new VertexPositionColor(topRightBack, Color.Orange);
nonIndexedCube
=
new VertexPositionColor(bottomLeftBack, Color.Orange);
nonIndexedCube[9] =
new VertexPositionColor(bottomLeftBack, Color.Orange);
nonIndexedCube[10] =
new VertexPositionColor(topRightBack, Color.Orange);
nonIndexedCube[11] =
new VertexPositionColor(bottomRightBack, Color.Orange);
// Top face
nonIndexedCube[12] =
new VertexPositionColor(topLeftFront, Color.Yellow);
nonIndexedCube[13] =
new VertexPositionColor(topRightBack, Color.Yellow);
nonIndexedCube[14] =
new VertexPositionColor(topLeftBack, Color.Yellow);
nonIndexedCube[15] =
new VertexPositionColor(topLeftFront, Color.Yellow);
nonIndexedCube[16] =
new VertexPositionColor(topRightFront, Color.Yellow);
nonIndexedCube[17] =
new VertexPositionColor(topRightBack, Color.Yellow);
// Bottom face
nonIndexedCube[18] =
new VertexPositionColor(bottomLeftFront, Color.Purple);
nonIndexedCube[19] =
new VertexPositionColor(bottomLeftBack, Color.Purple);
nonIndexedCube[20] =
new VertexPositionColor(bottomRightBack, Color.Purple);
nonIndexedCube[21] =
new VertexPositionColor(bottomLeftFront, Color.Purple);
nonIndexedCube[22] =
new VertexPositionColor(bottomRightBack, Color.Purple);
nonIndexedCube[23] =
new VertexPositionColor(bottomRightFront, Color.Purple);
// Left face
nonIndexedCube[24] =
new VertexPositionColor(topLeftFront, Color.Blue);
nonIndexedCube[25] =
new VertexPositionColor(bottomLeftBack, Color.Blue);
nonIndexedCube[26] =
new VertexPositionColor(bottomLeftFront, Color.Blue);
nonIndexedCube[27] =
new VertexPositionColor(topLeftBack, Color.Blue);
nonIndexedCube[28] =
new VertexPositionColor(bottomLeftBack, Color.Blue);
nonIndexedCube[29] =
new VertexPositionColor(topLeftFront, Color.Blue);
// Right face
nonIndexedCube[30] =
new VertexPositionColor(topRightFront, Color.Green);
nonIndexedCube[31] =
new VertexPositionColor(bottomRightFront, Color.Green);
nonIndexedCube[32] =
new VertexPositionColor(bottomRightBack, Color.Green);
nonIndexedCube[33] =
new VertexPositionColor(topRightBack, Color.Green);
nonIndexedCube[34] =
new VertexPositionColor(topRightFront, Color.Green);
nonIndexedCube[35] =
new VertexPositionColor(bottomRightBack, Color.Green);
decl = new VertexDeclaration(
graphics.GraphicsDevice, VertexPositionColor.VertexElements);
}
protected override void Update()
{
// The time since Update was called last
float elapsed = (float)ElapsedTime.TotalSeconds;
// TODO: Add your game logic here
// Let the GameComponents update
UpdateComponents();
}
protected override void Draw()
{
// Make sure we have a valid device
if (!graphics.EnsureDevice())
return;
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
graphics.GraphicsDevice.BeginScene();
graphics.GraphicsDevice.VertexDeclaration = decl;
graphics.GraphicsDevice.RenderState.CullMode =
CullMode.None;
//This code would go between a device BeginScene-EndScene block.
effect.Begin(EffectStateOptions.Default);
effect.World = world;
effect.View = view;
effect.Projection = projection;
effect.Techniques[0].Passes[0].Begin();
graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>
(PrimitiveType.TriangleList, 12,
nonIndexedCube);
effect.CommitChanges();
effect.Techniques[0].Passes[0].End();
effect.End();
graphics.GraphicsDevice.EndScene();
graphics.GraphicsDevice.Present();
}
}
}
Yes, that did it. I was just realizing that the code in the documentation (ms-help://MS.VSExpressCC.v80/MS.VSIPCC.v80/MS.XNAFX.1033/XNA/Draw_3D_Primitives.htm) left out the line:
graphics.GraphicsDevice.BeginScene();
which was throwing the exception. That solved, I got a black screen also and was trying to get a shader going. I am not very familiar with them, but I recall reading somewhere that they can either override the color data in the vertices, or allow it to persist... have to find out more, but thank you this is a great help.
Also, for those interested, you'll have to replace Devil with square bracket 6 close square bracket... (6) with square brackets, and Music with square bracket 8 close square bracket... (8) with square brackets.
An aside:
I find it kind of ridiculous that in a forum about programming auto-smileys are enabled with no way to turn them off. Going into HTML mode and wrapping code with <pre> tags did not help. A paragraph style of "Code" would be most useful, taking ideas from other board software, it could easily allow auto line numbering, syntax highlighting, function lookup, etc. I do really like Microsoft's forums' Helpful/Answer marking tools.
Ahh.. anyway.. thanks for the useful code. I'll post back whatever I end up doing with it.
- Matteus
Glad I could help. I'll let you know if I figure out what the deal with coloring is. Let me know if you figure it out before then :)
I think it should be effect.LightingEnable = false, but toggling this boolean doesn't appear to change whether it uses the BasicEffect's lighting or not. Is this a bug?
Alright, I don't mean to keep spamming this thread, but I finally got all of the code working.
This thread (http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=687936&SiteID=1) has the complete code to the 3D example. I wasn't able to ever get the effect working with the BasicEffect. You'll need to use the Shader out of How To: Apply an Effect
I think BasicEffect needs a tutorial of its own; it has an example but doesn't show how to use it without lighting (i.e. just for rotations, etc). If EnableLighting is intended to disable the lighting, then it's either bugged or there's a lot more to it than I think.
Well, somehow I can't get rid of the InvalidCallException despite your advice.... anything wrong with the code bel;ow?
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Components;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
namespace Kulnor.XNA
{
/// <summary>
/// This is the main type for your game
/// </summary>
partial class Game1 : Microsoft.Xna.Framework.Game
{
Triangle t1;
BasicEffect effect;
Matrix world, view, projection;
public Game1()
{
InitializeComponent();
t1 = new Triangle(new Vector3(-0.5f,0,0),new Vector3(0,0.5f,0),new Vector3(0.5f,0,0), Color.Red );
effect = new BasicEffect(graphics.GraphicsDevice, null);
world = Matrix.CreateTranslation(new Vector3(0, 0, 0));
view = Matrix.CreateLookAt(new Vector3(3, 3, 0), Vector3.Zero, Vector3.Up);
projection = Matrix.CreatePerspectiveFieldOfView((float)Math.PI / 2.0f, (float)Window.ClientWidth / (float)Window.ClientHeight, 0.1f, 1000.0f);
}
class Triangle
{
public VertexPositionColor[] triangle;
public Triangle(Vector3 p1, Vector3 p2, Vector3 p3, Color c) {
triangle = new VertexPositionColor
;
triangle[0] = new VertexPositionColor(p1, c);
triangle[1] = new VertexPositionColor(p2, c);
triangle[2] = new VertexPositionColor(p3, c);
triangle[3] = new VertexPositionColor(p1, c);
triangle[4] = new VertexPositionColor(-p2, c);
triangle[5] = new VertexPositionColor(p3, c);
}
}
protected override void Update()
{
// The time since Update was called last
float elapsed = (float)ElapsedTime.TotalSeconds;
// TODO: Add your game logic here
// Let the GameComponents update
UpdateComponents();
}
protected override void Draw()
{
// Make sure we have a valid device
if (!graphics.EnsureDevice())
return;
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
graphics.GraphicsDevice.BeginScene();
// TODO: Add your drawing code here
VertexDeclaration decl = new VertexDeclaration(graphics.GraphicsDevice, VertexPositionColor.VertexElements);
graphics.GraphicsDevice.VertexDeclaration = decl;
graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;
//This code would go between a device BeginScene-EndScene block.
effect.Begin(EffectStateOptions.Default);
effect.World = world;
effect.View = view;
effect.Projection = projection;
effect.Techniques[0].Passes[0].Begin();
// ** THE LINE BELOW CAUSE AN INVALID CALL EXCEPTION ERROR **
graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleList, 2, t1.triangle);
effect.CommitChanges();
effect.Techniques[0].Passes[0].End();
effect.End();
// This outside the effect works fine
graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleList, 2, t1.triangle);
// Let the GameComponents draw
DrawComponents();
graphics.GraphicsDevice.EndScene();
graphics.GraphicsDevice.Present();
}
}
}
this code compiles fine, and i've tried other examples too, but i get an unknown error on the drawuserprimitives call. Any ideas? I can't seem to get any 3d code to not throw that error on the draw calls. I have an x800 xl ati video card...
I figured out my problem :)
To get color, you have to set the BasicEffect.Diffuse property to a color. I asked something similar and the answer was that it does not use the vertex color. You can implement your own shader, however.