Drawing a triangle in MonoGame - c#

I'm trying to draw a green 2D triangle in MonoGame using DrawUserPrimitives, but I can't seem to get it working. Every approach that I have tried results in either vague errors or nothing being drawn.
This is my latest attempt at drawing a triangle, taken almost completely from a resource that I found on the Internet:
protected override void LoadContent()
{
_vertexPositionColors = new[]
{
new VertexPositionColor(new Vector3(0, 0, 1), Color.Green),
new VertexPositionColor(new Vector3(10, 0, 1), Color.Green),
new VertexPositionColor(new Vector3(10, 10, 1), Color.Green)
};
_basicEffect = new BasicEffect(GraphicsDevice);
_basicEffect.World = Matrix.CreateOrthographicOffCenter(
0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, 1);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
EffectTechnique effectTechnique = _basicEffect.Techniques[0];
EffectPassCollection effectPassCollection = effectTechnique.Passes;
foreach (EffectPass pass in effectPassCollection)
{
pass.Apply();
GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList,
_vertexPositionColors, 0, 1);
}
base.Draw(gameTime);
}
This results in a empty blue screen without any trace of a triangle.

Related

Drawing a rectangle in C#

This is a very simple question but I couldn't find anything on the internet that was helpful. Basically, I am trying to draw a rectangle but when I launch my code nothing is happening (I don't have any errors either). Here is the code:
class Buildings
{
public void test(Game1 mainGame, SpriteBatch spriteBatch)
{
var buildingrect = new Rectangle(mainGame.bufferHeight - 30, 50, 200, 50);
// (Note: mainGame.alien2 is a texture I have - this isn't the problem)
spriteBatch.Draw(mainGame.alien2, buildingrect, Color.White);
}
}
public class Game1 : Microsoft.Xna.Framework.Game
{
protected override void Draw(GameTime gameTime)
{
buildings.test(this, spriteBatch);
}
}
Thank you for your help and I apologize again for this being such a simple question - I'm still a beginner.
Unfortunately, you can not draw rectangles simple like that. You can solve it like this:
Create a texture that holds the pixelcolor for the rectangle
private Texture2D pixel;
private Rectangle rect; //your rectangle`
Initialize it with your preferred color:
pixel = new Texture2D(GraphicsDevice, 1, 1);
pixel.SetData(new[] { Color.White });`
In your draw method you now draw each side of your rectangle:
int bw = 2; // Border width
//Left
spriteBatch.Draw(pixel, new Rectangle(rect.Left, rect.Top, bw, rect.Height), Color.Black);
//Right
spriteBatch.Draw(pixel, new Rectangle(rect.Right, rect.Top, bw, rect.Height), Color.Black);
//Top
spriteBatch.Draw(pixel, new Rectangle(rect.Left, rect.Top, rect.Width, bw), Color.Black);
//Bottom
spriteBatch.Draw(pixel, new Rectangle(rect.Left, rect.Bottom, rect.Width, bw), Color.Black);

OpenGL doesn't render to Framebuffer but to Window

My problem is that OpenGL renders to the Main-Window, although I bound the Framebuffer I want to use.
This is my Main Rendering-Method
protected override void OnRenderFrame(FrameEventArgs e)
{
base.OnRenderFrame(e);
renderer.BeginFrame();
renderer.RenderEntity(testEntity);
renderer.EndFrame();
SwapBuffers();
}
This is my Renderer
class Renderer
{
List<Vertex> screenQuadVertecies = new List<Vertex>
{
new Vertex(new Vector3(-1, 1, 0), new Vector3()),
new Vertex(new Vector3(1, 1, 0), new Vector3()),
new Vertex(new Vector3(-1, -1, 0), new Vector3()),
new Vertex(new Vector3(1, -1, 0), new Vector3())
};
List<int> screenQuadIndices = new List<int>
{
0, 1, 2,
1, 2, 3
};
List<Vector2> screenQuadUVs = new List<Vector2>
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(1, 1)
};
TexturedMesh screenQuad;
Framebuffer mainPassFramebuffer;
Camera activeCamera;
Shader ModelShader;
Shader PostProcessingShader;
int width, height;
public Renderer(int width, int height)
{
this.width = width;
this.height = height;
ModelShader = new MainShader();
PostProcessingShader = new PostProcessingShader();
mainPassFramebuffer = new Framebuffer(width, height);
screenQuad = new TexturedMesh(screenQuadVertecies, screenQuadIndices, screenQuadUVs);
}
public void BeginFrame()
{
mainPassFramebuffer.EndRendering();
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
mainPassFramebuffer.ClearBuffer();
mainPassFramebuffer.BeginRendering();
}
public void EndFrame()
{
mainPassFramebuffer.EndRendering();
mainPassFramebuffer.BindTexture();
PostProcessingShader.UseShader();
screenQuad.PrepareRendering();
GL.DrawElements(PrimitiveType.Triangles, 6, DrawElementsType.UnsignedInt, 0);
screenQuad.EndRendering();
PostProcessingShader.UnuseShader();
}
public void RenderEntity(Entity e)
{
e.Mesh.PrepareRendering();
ModelShader.UseShader();
ModelShader.LoadCamera(activeCamera);
ModelShader.LoadModel(e.GetModelMatrix());
GL.DrawElements(PrimitiveType.Triangles, e.Mesh.GetSize(), DrawElementsType.UnsignedInt, 0);
ModelShader.UnuseShader();
}
public void RenderTerrain(Terrain t)
{
foreach (var chunk in t.chunks)
{
RenderEntity(chunk.GetEntity());
}
}
public void SetActiveCamera(Camera camera)
{
activeCamera = camera;
}
}
And this is my Framebuffer Class
class Framebuffer
{
int frameBufferID;
int textureID;
int width, height;
public Framebuffer(int width, int height)
{
this.width = width;
this.height = height;
frameBufferID = GL.GenRenderbuffer();
GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBufferID);
textureID = CreateTexture();
GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, textureID, 0);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
}
protected int CreateTexture()
{
int returnID;
returnID = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, returnID);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, width, height, 0, PixelFormat.Rgb, PixelType.UnsignedByte, (IntPtr)0);
int nearest = (int)TextureMagFilter.Nearest;
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, ref nearest);
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, ref nearest);
return returnID;
}
public void BeginRendering()
{
GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBufferID);
GL.Viewport(new System.Drawing.Point(0, 0), new System.Drawing.Size(width, height));
}
public void EndRendering()
{
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
}
public void BindTexture()
{
GL.BindTexture(TextureTarget.Texture2D, textureID);
}
public void ClearBuffer()
{
GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBufferID);
GL.Viewport(new System.Drawing.Point(0, 0), new System.Drawing.Size(width, height));
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
}
}
The expected result is a black quad because I have been implementing Texturing when I discovered that my Model still renders to the screen. I found that out when I commentend out the GL.DrawElements call in EndRendering() which should render the quad to the screen. When I now don't draw that quad the image still appears.
What am I doing wrong?
A render buffer is not a framebuffer object:
frameBufferID = GL.GenRenderbuffer();
When you try to bind an ID you got from glGenRenderbuffers as a framebuffer, you will get an GL_INVALID_OPERATION error from glBindFramebuffer(), and the command will have no further effect (leaving the default framebuffer bound).
New FBO names are generated via glGenFramebuffers, so you should use that.

Setting up OpenGL camera

I'm having trouble setting up my camera in 3D space.
Here's my code:
private void SetupViewPort()
{
GL.Viewport(0, 0, glControl1.Width, glControl1.Height);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Ortho(0, 1000,0,1000, 0, 1);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
Vector3d eyePos = new Vector3d(0, 0, 1);
Vector3d point = new Vector3d(500, 500, 0.01);
Vector3d up = new Vector3d(0, 0 , 1);
Matrix4d mat = Matrix4d.LookAt(eyePos, point, up);
//mat.Invert();
GL.LoadMatrix(ref mat);
}
I'm expecting to see shapes that I've drawn onto the 2D plane. But I get a blank screen every time.
Here's the code where my shapes are drawn:
private void glControl1_Paint(object sender, PaintEventArgs e)
{
if (!loaded)
return;
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.Enable(EnableCap.DepthTest);
GL.DepthMask(true);
GL.ClearDepth(1.0);
GL.Color3(Color.Yellow);
GL.Begin(PrimitiveType.Triangles);
GL.Vertex2(0, 0);
GL.Vertex2(0, 600);
GL.Vertex2(600, 600);
GL.Vertex2(100, 100);
GL.Vertex2(50, 70);
GL.Vertex2(200, 100);
GL.End();
glControl1.SwapBuffers();
}
An orthonormal projection matrix and a lookAt view matrix don't play well together. Since you are drawing 2D just leave the lookAt matrix out and use the identity matrix.

Sprite animation error

My animation for a 37*37 resolution sprite is working swell a part from when I have both the left and right arrow key pressed down, two animations appear on top of each other.
Here is my code:
keys = Keyboard.GetState();
if (keys.IsKeyDown(Keys.Right))
{
position = new Vector2(position.X + 1.4f, position.Y);
isRight = true;
isLeft = false;
if (keys.IsKeyDown(Keys.Left))
{
isLeft = true;
isRight = false;
}
}
if (keys.IsKeyDown(Keys.Left))
{
position = new Vector2(position.X - 1.4f, position.Y);
isLeft = true;
isRight = false;
if (keys.IsKeyDown(Keys.Right))
{
isRight = true;
isLeft = false;
}
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
int frame = (int)((gameTime.TotalGameTime.TotalSeconds * 12) % 4);
if (keys.IsKeyDown(Keys.Right))
spriteBatch.Draw(texture, position, new Rectangle(frame * 37, 0, 37, 37), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 1.0f);
if (keys.IsKeyDown(Keys.Left))
spriteBatch.Draw(texture, position, new Rectangle(frame * 37, 0, 37, 37), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.FlipHorizontally, 1.0f);
if (keys.IsKeyUp(Keys.Left) && keys.IsKeyUp(Keys.Right))
{
if (isRight)
spriteBatch.Draw(texture, position, new Rectangle(0, 0, 37, 37), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 1.0f);
if (isLeft)
spriteBatch.Draw(texture, position, new Rectangle(0, 0, 37, 37), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.FlipHorizontally, 1.0f);
}
spriteBatch.End();
What am I doing wrong?
You have two animations appearing on top of each other because you have two separate SpriteBatch.Draw calls in your Draw method. When you press both left and right keys, both of IsKeyDown ifs are true, and both draws are executed.
Also, this post is more appropriate in https://gamedev.stackexchange.com/.

Draw Rectangle in MonoGame

How do you draw shapes, such as Rectangles and Circles, in MonoGame without having to save the a predrawn shape in the Content folder?
DrawRectangle() and DrawEllipse() are for Windows Form and do not work in OpenGL, which is what I am using.
Use 3D primitives and a 2D projection
Here's a simple example with explanations
I define a 10x10 rectangle and set the world matrix to make it look like a 2D projection :
Note : the BasicEffect is what draws your primitive
protected override void LoadContent()
{
_vertexPositionColors = new[]
{
new VertexPositionColor(new Vector3(0, 0, 1), Color.White),
new VertexPositionColor(new Vector3(10, 0, 1), Color.White),
new VertexPositionColor(new Vector3(10, 10, 1), Color.White),
new VertexPositionColor(new Vector3(0, 10, 1), Color.White)
};
_basicEffect = new BasicEffect(GraphicsDevice);
_basicEffect.World = Matrix.CreateOrthographicOffCenter(
0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, 1);
}
Then I draw the whole thing :D
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
EffectTechnique effectTechnique = _basicEffect.Techniques[0];
EffectPassCollection effectPassCollection = effectTechnique.Passes;
foreach (EffectPass pass in effectPassCollection)
{
pass.Apply();
GraphicsDevice.DrawUserPrimitives(PrimitiveType.LineStrip, _vertexPositionColors, 0, 4);
}
base.Draw(gameTime);
}
There you have your rectangle !
Now this is just the tip the of the iceberg,
To draw filled rectangles : draw 2 triangle primitives
For an ellipse/circle see these : Draw an Ellipse in XNA and Draw simple circle in XNA
Or as mentioned in one of the posts above you could use a shader that does it instead ...
I needed to draw a Superellipse a while ago and ended up sketching this shader :
Drawing a SuperEllipse in HLSL
As you can see in the post a Superellipse not only draws ellipse but also other shapes and maybe even circles (I did not test) so you might be interested in it.
Ultimately you will want some class/methods to hide all these details so you just have to invoke something like DrawCircle().
Tip : by posting # https://gamedev.stackexchange.com/ you will likely get more answers for Monogame-related questions
:D
If you need to create a rectangle in 2D you can just do this:
Color[] data = new Color[rectangle.Width * rectangle.Height];
Texture2D rectTexture = new Texture2D(GraphicsDevice, rectangle.Width, rectangle.Height);
for (int i = 0; i < data.Length; ++i)
data[i] = Color.White;
rectTexture.SetData(data);
var position = new Vector2(rectangle.Left, rectangle.Top);
spriteBatch.Draw(rectTexture, position, Color.White);
Might be a tad bit easier than Aybe's answer in some situations. This creates a solid rectangle.
I found a simple solution for drawing filled and non-filled shapes, I don't know if it's power consuming or not, but here it is anyway:
{
//Filled
Texture2D _texture;
_texture = new Texture2D(graphicsDevice, 1, 1);
_texture.SetData(new Color[] { Color.White });
spriteBatch.Draw(_texture, Rect, Color.White);
}
{
//Non filled
Texture2D _texture;
_texture = new Texture2D(graphicsDevice, 1, 1);
_texture.SetData(new Color[] { Color.White });
spriteBatch.Draw(_texture, new Rectangle(Rect.Left, Rect.Top, Rect.Width, 1), Color.White);
spriteBatch.Draw(_texture, new Rectangle(Rect.Right, Rect.Top, 1, Rect.Height), Color.White);
spriteBatch.Draw(_texture, new Rectangle(Rect.Left, Rect.Bottom, Rect.Width, 1), Color.White);
spriteBatch.Draw(_texture, new Rectangle(Rect.Left, Rect.Top, 1, Rect.Height), Color.White);
}

Categories

Resources