View Full Version : XNA Help: Drawing Primitives
CiNiMoDZA
27-12-2010, 08:19 PM
Arrgh, I am so flippen tired of looking for this! Im on holiday so my net is shaky. The countless tutorials I have looked at for drawing primitives dont help me at all. They are all identical and none work on XNA 4.0(for windows phone).
Can some please either point me in the right direction or help me out here.
Im creating a little library to help with rapid development for XNA Windows Phone. Its got collision detection, sprite manipulation blah blah blahbut I need to figure out how to draw primitives, and Im stumped!!!
Please, I am begging you, someone, put me out of my misery!!!
dislekcia
28-12-2010, 12:30 AM
Arrgh, I am so flippen tired of looking for this! Im on holiday so my net is shaky. The countless tutorials I have looked at for drawing primitives dont help me at all. They are all identical and none work on XNA 4.0(for windows phone).
Can some please either point me in the right direction or help me out here.
Im creating a little library to help with rapid development for XNA Windows Phone. Its got collision detection, sprite manipulation blah blah blahbut I need to figure out how to draw primitives, and Im stumped!!!
Please, I am begging you, someone, put me out of my misery!!!
What are the things you've tried that aren't working? To draw primitives you basically need to populate a vertex buffer with the geometry you want to draw and lob that at the graphics card every frame... There are various ways to do that and various formats and things FOR vertex buffers in XNA, but the basics go like this:
1. Create a vertex buffer (I've heard that in XNA 4.0 you don't need to do the annoying stuff you did in earlier versions with VertexFormats)
2. Populate your vertex buffer with the vertices you want drawn. If that's a simple triangle, give it three verts and be done with it.
3. Point the graphics device at your vertex buffer and set up your state variables like lighting, textures, etc.
4. Call DrawIndexedPrimitives.
CiNiMoDZA
28-12-2010, 08:35 AM
Ok, so I store my verts like so
protected void SetupVertexArray()
{
vertices = new VertexPositionColor[3];
vertices[0].Position = new Vector3(-.5f, -.5f, 0f);
vertices[0].Color = Color.Red;
vertices[1].Position = new Vector3(0f, .5f, 0f);
vertices[1].Color = Color.Blue;
vertices[2].Position = new Vector3(.5f, -.5f, 0f);
vertices[2].Color = Color.Green;
}
Which is all good, but what do I do in the Draw method to actually draw it. I tried this:
spriteBatch.Begin();
GraphicsDevice.DrawUserPrimitives(PrimitiveType.Tr iangleList, vertices, 0, 1);
spriteBatch.End();
Firstly, I dont understand what Im doing in there, and secondly, it gives the following error:
Both a vertex shader and pixel shader must be set on the device before any draw operations may be performed.
Chippit
28-12-2010, 10:52 AM
SpriteBatch is no good for drawing primitives. I know it lost its mind-boggling (read:awesome) vertex shader in XNA 4.0 (which means it may be technically possible to use it to draw primitives), but you really should be creating an instance of BasicEffect and using it instead.
Also, I'm not sure about what dis said with regards to VertexDeclarations (which I assume is what he means), but if that's true it's handy indeed. Otherwise you'll need to set the correct details on the GraphicsDevice telling it what kind of vertex data you're sending before you call DrawUserPrimitives. All the built-in XNA vertex types, like VertexPositionColor, have a pre-created static (I think) property for their vertex info. So it saves you most of the trouble in this regard. But it's an essential step, otherwise you usually get the wrong output altogether, or run into problems later when you start drawing other things and have forgetten to set the declaration.
CiNiMoDZA
28-12-2010, 10:32 PM
Ok, so here is my code in the draw event:
spriteBatch.Begin();
device.SetVertexBuffer(buffer);
device.DrawPrimitives(PrimitiveType.TriangleList, 0, vertices.Length);
spriteBatch.End();
Im still getting the vertex shader and pixel shader must be set error. Chippit, would it be possible for you to show some sample code or point me in the direction of a good tutorial regarding your method using the Effect class? Thanks for the help so far guys.
Edit: Hack Win:
public Texture2D CreateCircularTexture(GraphicsDevice device, int radius, int antialiasSize)
{
int textureSize = (radius * 2) + 2;
int solidRadius = radius - antialiasSize;
Vector2 textureCenter = new Vector2(textureSize / 2f, textureSize / 2f);
Texture2D texture = new Texture2D(device, textureSize, textureSize);
Color[] pixels = new Color[texture.Width * texture.Height];
for (int x = 0; x < textureSize; x++)
{
for (int y = 0; y < textureSize; y++)
{
float d = Vector2.Distance(new Vector2(x, y), textureCenter);
int i = y * textureSize + x;
if (d < solidRadius)
pixels[i] = Color.White;
else if (d < radius)
pixels[i] = Color.White;
else
pixels[i] = new Color(0, 0, 0, 0);
}
}
texture.SetData(pixels);
return texture;
}
I realize now that I may have been a little misleading in my original post, but this is pretty much exactly waht I needed to do! I will now use this texture with my collision detection to do a collision circle, like you can in Game Maker. I have also used this technique to draw the borders of the shapes I do collision detection with so that the person using my library can set their game to "debug mode" and when they are calling a specific type of collision, it will draw it on the screen, just to make things easire for the developers!! Thanks for the help guys!
dislekcia
29-12-2010, 03:12 AM
Um. Drawing primitives is a problem that you still haven't solved here (You need to stop using SpriteBatch, it does nothing for primitives, create an effect and do Begin and End calls on that per Pass)... It's also completely different to calculating collisions. You need a much more thought-out system for that.
CiNiMoDZA
29-12-2010, 02:46 PM
Thanks guys. Like I said, I was probably misleading in my initial post. I really just wanted to draw primitive shapes as textures. My method is working fine, but what would the differences be (performance or otherwise) if I were to use primitives?
dislekcia
30-12-2010, 02:41 AM
Thanks guys. Like I said, I was probably misleading in my initial post. I really just wanted to draw primitive shapes as textures. My method is working fine, but what would the differences be (performance or otherwise) if I were to use primitives?
Ok, you kinda need to get better at explaining what it is you're trying to do when you ask these sorts of questions...
Is there any particular reason you didn't just use one texture with a circle on it and scale that to the right size when drawing your "primitives"? The code you posted creates a whole new texture for every circle you want to draw, that's not very efficient (textures take up a lot of memory compared to simple lists of vertices) plus you're not doing anything to ensure that your created textures are powers of two, which could be a problem on certain graphics cards.
For future reference, XNA now uses an Effect system to control a whole host of things on the GPU, ranging from shaders to transforms, matrices and lighting information. Effects are totally awesome and much easier to use than having to set up hordes of different calls.
Each effect has a collection of passes, which are basically numbers of times that everything that goes through that effect should be rendered. Generally you won't have multi-pass effects until you're messing with things like vertex shadows and stuff like that. Using an effect (the awesome BasicEffect exists in XNA so you don't have to set up your own if you don't what to/know how) is as simple as starting the effect with a Begin() call, iterating over all the passes it contains (yay foreach) and drawing your vertex buffer(s) each time.
Yes, once you have multiple effects going you'll need to start managing switches between them, which can be expensive, but for simple projects it's often easiest to just set up a static BasicEffect somewhere and draw everything using that.
Here's some copypasta of the simplest rendering code I could find... This is XNA GS 3.0 though, so the VertexDeclaration stuff might have changed by now, but the Render() method is what you care about anyway, right? ;)
/// <summary>
/// Constructor
/// </summary>
/// <param name="_matrix">The matrix used to render this line...</param>
/// <param name="_color">The line's colour</param>
public BoardLine(Matrix _matrix, Color _color, float _width, float _height)
{
worldMatrix = _matrix;
color = _color;
//Graphics:
vertexDeclaration = new VertexDeclaration(QCFSudokuGame.GraphicsDevice, VertexPositionColor.VertexElements);
vertexBuffer = new VertexBuffer(QCFSudokuGame.GraphicsDevice, typeof(VertexPositionColor), 4, BufferUsage.WriteOnly);
//Create the quad
VertexPositionColor[] verts = new VertexPositionColor[4];
float width, height;
width = _width;
height = _height;
verts[0] = new VertexPositionColor(new Vector3(-width / 2f, height / 2f, 0f), Color.White);
verts[1] = new VertexPositionColor(new Vector3(width / 2f, height / 2f, 0f), Color.White);
verts[2] = new VertexPositionColor(new Vector3(width / 2f, -height / 2f, 0f), Color.White);
verts[3] = new VertexPositionColor(new Vector3(-width / 2f, -height / 2f, 0f), Color.White);
vertexBuffer.SetData<VertexPositionColor>(verts);
}
/// <summary>
/// Renders a dividing line
/// </summary>
public void Render()
{
QCFSudokuGame.GraphicsDevice.VertexDeclaration = vertexDeclaration;
QCFSudokuGame.GraphicsDevice.Vertices[0].SetSource(vertexBuffer, 0, VertexPositionColor.SizeInBytes);
//Uses static effect
QCFSudokuGame.basicEffect.Begin();
QCFSudokuGame.basicEffect.DiffuseColor = color.ToVector3();
foreach (EffectPass pass in QCFSudokuGame.basicEffect.CurrentTechnique.Passes)
{
pass.Begin();
QCFSudokuGame.basicEffect.World = worldMatrix; //Probably not strictly necessary
QCFSudokuGame.basicEffect.CommitChanges();
QCFSudokuGame.GraphicsDevice.DrawPrimitives(Primit iveType.TriangleFan, 0, 2);
pass.End();
}
QCFSudokuGame.basicEffect.End();
}
}
BTW, Evolution: Your post made no sense. What did the C++ equivalent of a function that shouldn't be called to draw vertex lists have to do with anything?
Evolution
30-12-2010, 08:55 AM
It was an efficient way to get the vertex points of a circle, using trig functions are very taxing to perform on every point in a circle. Imagine drawing a circle with the radius of 100, which is 100 segments(sqrt(100)*10), this leaves you with the 200 trig functions which need to be called just to draw a circle with 200 pixel diameter.
It also increases the segments based on the radius of the circle so you always get a smooth circle no matter how large you make it.
3. Point the graphics device at your vertex buffer and set up your state variables like lighting, textures, etc.
Thanks for deleting my post which listed these state variables.
All my primitive code in xna was messed up during the port to 4.0 so I'm sorry if I can't use it to demonstrate.
So xna is moving towards an opengl way of doing things :) with their effects
Evolution
30-12-2010, 09:34 AM
You could also use point sprite. Here is an effect you could use. Sorry if my code is more focused on 3d game development.
PointSpriteParticles.fx
float4x4 World;
float4x4 View;
float4x4 Projection;
float ParticleSize = 200;
float ViewportHeight;
texture ParticleTexture;
sampler ParticleSampler = sampler_state
{
Texture = <ParticleTexture>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Wrap;
AddressV = Wrap;
};
struct VS_Input
{
float4 Position : POSITION0;
float4 Color : COLOR0;
float2 TexCoord : TEXCOORD0;
};
struct VS_Output
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
float4 Color : COLOR0;
float PSize : PSIZE0;
};
VS_Input VS_PointSprite(VS_Input input)
{
VS_Input output;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
output.TexCoord = input.TexCoord;
output.Color = input.Color;
return input;
}
VS_Output VS_ScaledPointSprite(VS_Input input)
{
VS_Output output;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
output.TexCoord = input.TexCoord;
output.Color = input.Color;
output.PSize = ParticleSize * Projection._m11 / output.Position.w * ViewportHeight / 2;
return output;
}
float4 PS_PointSprite(VS_Input input) : COLOR0
{
return tex2D(ParticleSampler, input.TexCoord) * input.Color;
}
float4 PS_ScaledPointSprite(VS_Output input) : COLOR0
{
return tex2D(ParticleSampler, input.TexCoord) * (input.Color * 2);
}
technique PointSprite
{
pass P0
{
VertexShader = compile vs_2_0 VS_PointSprite();
PixelShader = compile ps_2_0 PS_PointSprite();
}
}
technique ScaledPointSprite
{
pass P0
{
VertexShader = compile vs_2_0 VS_ScaledPointSprite();
PixelShader = compile ps_2_0 PS_ScaledPointSprite();
}
}
Chippit
30-12-2010, 09:58 AM
Stuff...
Someone who uses all the fancy XML comments in C# code. <3
Also, I believe the most major change in XNA 4, if memory serves correctly, was that you no longer need to call End() on passes (and perhaps even on the effect itself, I don't remember).
Evolution
30-12-2010, 11:10 AM
If you used my first post I posted(now deleted) you would have downloaded the sample from the xna website and edited it to look something like this. Here's the link (http://create.msdn.com/en-US/education/catalog/sample/primitives) again.
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.Black);
// how big is the screen? we'll use that information to center the sun
// and place the ships.
int screenWidth = graphics.GraphicsDevice.Viewport.Width;
int screenHeight = graphics.GraphicsDevice.Viewport.Height;
DrawCircle(new Vector2(screenWidth / 2, screenHeight / 2), 100, Color.CornflowerBlue, true);
DrawCircle(new Vector2(screenWidth / 2, screenHeight / 2), 128, Color.White, false);
/*
// draw the sun in the center
DrawSun(new Vector2(screenWidth / 2, screenHeight / 2));
// draw the left hand ship
DrawShip(new Vector2(100, screenHeight / 2));
// and the right hand ship
DrawShip(new Vector2(screenWidth - 100, screenHeight / 2));
DrawStars();*/
base.Draw(gameTime);
}
void DrawCircle(Vector2 position, float radius, Color color, bool fill_centre)
{
int num_segments = (int)(Math.Sqrt(radius)*10);
float theta = MathHelper.TwoPi / num_segments;
float tangetial_factor = (float)Math.Tan(theta);//calculate the tangential factor
float radial_factor = (float)Math.Cos(theta);//calculate the radial factor
float x = radius;//we start at angle = 0
float y = 0;
// stars are drawn as a list of points, so begin the primitiveBatch.
primitiveBatch.Begin(fill_centre?PrimitiveType.Tri angleList:PrimitiveType.LineList);
if (!fill_centre) primitiveBatch.AddVertex(new Vector2(x + position.X, y + position.Y), color);//output vertex
for(int ii = 0; ii < num_segments; ii++)
{
if (fill_centre)
{
primitiveBatch.AddVertex(position, color);//output vertex
primitiveBatch.AddVertex(new Vector2(x + position.X, y + position.Y), color);//output vertex
}
else
{
primitiveBatch.AddVertex(new Vector2(x + position.X, y + position.Y), color);//output vertex
primitiveBatch.AddVertex(new Vector2(x + position.X, y + position.Y), color);//output vertex
}
//calculate the tangential vector
//remember, the radial vector is (x, y)
//to get the tangential vector we flip those coordinates and negate one of them
float tx = -y;
float ty = x;
//add the tangential vector
x += tx * tangetial_factor;
y += ty * tangetial_factor;
//correct using the radial factor
x *= radial_factor;
y *= radial_factor;
if (fill_centre) primitiveBatch.AddVertex(new Vector2(x + position.X, y + position.Y), color);//output vertex
}
if (!fill_centre) primitiveBatch.AddVertex(new Vector2(x + position.X, y + position.Y), color);//output vertex
// and then tell it that we're done.
primitiveBatch.End();
}
Which gives you this...
http://img337.imageshack.us/img337/2659/65859884.png
The whole point of my first post was to not spoon feed you like I just did.
CiNiMoDZA
30-12-2010, 12:29 PM
@Dislekia: Thanks for the help, I'll try male more sense in future. The reason why i didn't just use an already created texture is because I'm using the circle in a library. I didn't do any research but I didn't see how to add an image to a library so that it would be loaded into the content pipeline. I'll keep learning how to use primitives effectively!!
dislekcia
30-12-2010, 01:02 PM
It was an efficient way to get the vertex points of a circle, using trig functions are very taxing to perform on every point in a circle. Imagine drawing a circle with the radius of 100, which is 100 segments(sqrt(100)*10), this leaves you with the 200 trig functions which need to be called just to draw a circle with 200 pixel diameter.
It also increases the segments based on the radius of the circle so you always get a smooth circle no matter how large you make it.
And yet you chose not to EXPLAIN that's why you were lobbing a random link into your post which was more about other languages than the one the question was originally asked in. Plus, why the crap would anyone use trig functions when you can simply use matrix math for free and rotate a radius by 2pi divided by the number of segments you want? That's hardly rocket-surgery...
While we're at it: Does having a 512x512 circle texture that's scaled down as needed by the card somehow give you a less accurate circle? AND, how are diameter*diameter square roots (for the texture generation, spot the vector.Distance call) faster than 200 divisions (if you were doing trig)? Help people the **** out man, don't just lob random crap at them.
Thanks for deleting my post which listed these state variables.
In a different frakking language. Of a different version of the library. With no real explanation of why those things were being set. FOR THE FUNCTION THAT SHOULDN'T HAVE BEEN USED IN THE FIRST PLACE!
Yeah. Helpful...
You could also use point sprite. Here is an effect you could use. Sorry if my code is more focused on 3d game development.
Your code is in a different language, again. It's not focused on 3D game development dude, it's focused on your ego. Why aren't you explaining what point sprites ARE and how they MIGHT BE USEFUL? Then, when someone asks how to set them up, then you can splack code at them, once they actually care to read it.
Someone who uses all the fancy XML comments in C# code. <3
Also, I believe the most major change in XNA 4, if memory serves correctly, was that you no longer need to call End() on passes (and perhaps even on the effect itself, I don't remember).
I <3 those comments, love that VS picks them up in code completion :) Don't need End anymore? Neat, those were pretty expensive when we profiled Spacehack. Wonder if Begin just does more stuff now to compensate though...
If you used my first post I posted(now deleted) you would have downloaded the sample from the xna website and edited it to look something like this. Here's the link (http://create.msdn.com/en-US/education/catalog/sample/primitives) again.
The whole point of my first post was to not spoon feed you like I just did.
Posting a whack of code is spoon feeding? Damn, you must have had a hard life. Although I must admit, I learned something useful there, let's see how to point that out in a non-condescending and non-spoonfeeding way, shall we?
Cinimod! There ISN'T a new thing in XNA 4.0, PrimitiveBatch, which behaves a lot like the primitives did in GM. Take a look at it in the help and see if that's easier to get a handle on than the whole effect thing - it looks a lot simpler to use :) the sample Evolution was so super kind to post and nab it from there if it's useful
Evolution
30-12-2010, 01:35 PM
What is the internet there for if I have to explain every term I use. There is no PrimitiveBatch in XNA 4.0 it's a class in the code sample that handles primitive batching. I don't have a hard life, I'm just realistic on the matter. If you want to get work as a game programmer you can't expect everything to be handed to you in cut and paste format. Write a physics engine and then talk about why I think 100 trig function is taxing to draw one circle. Do you know how much multiplication that is for every point using matrix maths, even in a shader their will be an overhead. I posted the correct way to draw a circle so stop complaining and get on with your life.
I had the honer of working with someone that can program commercial grade game engines and I have worked on 7 game engines most of which are my own, so stop acting like some know it all genius.
Chippit
30-12-2010, 03:06 PM
I <3 those comments, love that VS picks them up in code completion :) Don't need End anymore? Neat, those were pretty expensive when we profiled Spacehack. Wonder if Begin just does more stuff now to compensate though...
Hargreaves has a blog (http://blogs.msdn.com/b/shawnhar/archive/2010/04/22/effect-api-changes-in-xna-game-studio-4-0.aspx) on these changes, as well as many others on the changes from XNA 3.0 > XNA 4.0. As always, insightful.
And yes, that IntelliSense in VS uses them is awesome. :3
dislekcia
30-12-2010, 06:29 PM
I had the honer of working with someone that can program commercial grade game engines and I have worked on 7 game engines most of which are my own, so stop acting like some know it all genius.
Well done. I'm sure you have a huge penis too! You're still not very good at explaining, so either listen to feedback and get better at it, or keep watching rambling, off-topic posts get deleted :)
I finally found what I wanted to share here (didnt have internet till today, was away till yesterday anyway), I remember finding what this guy posted (http://forums.create.msdn.com/forums/t/47696.aspx) quite useful.
It uses the Primitives Sample (http://create.msdn.com/en-US/education/catalog/sample/primitives), and he wrote some code of his own to add support for doing circles:
public void RenderCircle(PrimitiveBatch PrmtBatch, Vector2 CentrePos, float Radius, float NumSides, Color Colour)
{
//angle of the current point
float Angle = 0;
float AngleIncrease = (MathHelper.Pi * 2) / NumSides;
//list of all primitives for the circle - each edge of the circle needs two point onefor each line
List<Vector2> PrimitiveList = new List<Vector2>();
for (int i = 0; i < NumSides; i++)
{
//first point of a line
//pos of point
Vector2 newPos = new Vector2((float)(Math.Sin(Angle)), (float)(Math.Cos(Angle)));
newPos *= Radius;
PrimitiveList.Add(CentrePos + newPos);
//2ed point of a line
newPos = new Vector2((float)(Math.Sin(Angle + AngleIncrease)), (float)(Math.Cos(Angle + AngleIncrease)));
newPos *= Radius;
PrimitiveList.Add(CentrePos + newPos);
//move to next side
Angle += AngleIncrease;
}
}
It does essentially the same thing as what Evolution posted, just thought I would share it.
I really want to start doing this kind of thing with BasicEffect though, I have the feeling it will end up being a lot more adaptable if I want to change colours, etc. Anyway, just my 2c and all.
Powered by vBulletin® Version 4.2.4 Copyright © 2019 vBulletin Solutions, Inc. All rights reserved.