Related
I pass the vertices to a buffer and the texture coordinates to an another buffer the vertices are draw perfectly, but the texture coordinate pointer is not doing anything, but in an another project it works without problems, I tried to copy from the other project but nothing happened. It produces the same problem without throwing any errors. However, it works perfectly in the immediate drawing mode.
void renderFrame(object o, FrameEventArgs e)
{
// Clear screen
GL.Translate(Input.GetMoveDir(.1f));
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
//Render image
//Enable thing before use
GL.BindTexture(TextureTarget.Texture2D, texture.ID);
GL.Enable(EnableCap.Texture2D);
//Setup blending
GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
// Immedaiate test
/*GL.Begin(BeginMode.Triangles);
for (int i = 0; i < vertexBuffer.Length; i++)
{
GL.Normal3(normalBuffer[i]);
GL.TexCoord2(uvBuffer[i]);
GL.Vertex3(vertexBuffer[i]);
}
GL.End();*/
//Enable arrays
GL.EnableClientState(ArrayCap.VertexArray);
GL.EnableClientState(ArrayCap.TextureCoordArray);
//GL.EnableClientState(ArrayCap.NormalArray);
//GL.Color3(Color.Red);
//Set vertex pointer
GL.BindBuffer(BufferTarget.ArrayBuffer, VEB);
GL.VertexPointer(3, VertexPointerType.Float, Vector3.SizeInBytes, 0);
//Set uv pointer
GL.BindBuffer(BufferTarget.ArrayBuffer, UVB);
GL.TexCoordPointer(2, TexCoordPointerType.Float, Vector2.SizeInBytes, 0);
//Set normal pointer
/*GL.BindBuffer(BufferTarget.ArrayBuffer, NOB);
GL.NormalPointer(NormalPointerType.Float, Vector3.SizeInBytes, 0);*/
//Draw
GL.DrawArrays(PrimitiveType.Quads, 0, vertexBuffer.Length);
// Swap buffers
GL.Flush();
window.SwapBuffers();
}
public void UpdateBuffers(Vector3[] vertices, Vector2[] uvs, Vector3[] normals)
{
//Vertex buffer
vertexBuffer = vertices;
GL.BindBuffer(BufferTarget.ArrayBuffer, VEB);
GL.BufferSubData<Vector3>(BufferTarget.ArrayBuffer, (IntPtr)0, (int)(Vector3.SizeInBytes * vertexBuffer.Length), vertexBuffer);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
//Uv buffer
uvBuffer = uvs;
GL.BindBuffer(BufferTarget.ArrayBuffer, UVB);
GL.BufferSubData<Vector2>(BufferTarget.ArrayBuffer, (IntPtr)0, (int)(Vector2.SizeInBytes * uvBuffer.Length), uvBuffer);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
//Normal buffer
normalBuffer = normals;
GL.BindBuffer(BufferTarget.ArrayBuffer, NOB);
GL.BufferSubData<Vector3>(BufferTarget.ArrayBuffer, (IntPtr)0, (int)(Vector3.SizeInBytes * normalBuffer.Length), normalBuffer);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
Console.WriteLine("Buffers updated");
}
My app is displaying an image in full screen by using OpenGL shader code as shown below. The vertex shader I used here is copied from somewhere. Can anyone explain why here used vTexCoord = (a_position.xy+1)/2;? When I'm trying with vTexCoord = a_position.xy, my OpenGL output is split into four rectangles and only it's top right portion is showing the image. Other three sides are seem as blurred. What change should I do to work it with vTexCoord = a_position.xy ?
Some important functions used in the project are shown below. Please check and help to correct.
float[] vertices = {
// Left bottom triangle
-1f, -1f, 0f,
1f, -1f, 0f,
1f, 1f, 0f,
// Right top triangle
1f, 1f, 0f,
-1f, 1f, 0f,
-1f, -1f, 0f
};
private void CreateShaders()
{
/***********Vert Shader********************/
vertShader = GL.CreateShader(ShaderType.VertexShader);
GL.ShaderSource(vertShader, #"attribute vec3 a_position;
varying vec2 vTexCoord;
void main() {
vTexCoord = (a_position.xy+1)/2;
gl_Position = vec4(a_position, 1);
}");
GL.CompileShader(vertShader);
/***********Frag Shader ****************/
fragShader = GL.CreateShader(ShaderType.FragmentShader);
GL.ShaderSource(fragShader, #"precision highp float;
uniform sampler2D sTexture;varying vec2 vTexCoord;
void main ()
{
vec4 color= texture2D (sTexture, vTexCoord);
gl_FragColor =color;
}");
GL.CompileShader(fragShader);
}
private void InitBuffers()
{
buffer = GL.GenBuffer();
positionLocation = GL.GetAttribLocation(program, "a_position");
positionLocation1 = GL.GetUniformLocation(program, "sTexture");
GL.EnableVertexAttribArray(positionLocation);
GL.BindBuffer(BufferTarget.ArrayBuffer, buffer);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * sizeof(float)), vertices, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(positionLocation, 3, VertexAttribPointerType.Float, false, 0, 0);
}
public void DrawImage(int image)
{
GL.Viewport(new Rectangle(0, 0, ScreenWidth, ScreenHeight));
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
GL.LoadIdentity();
//GL.Ortho(0, 1920, 0, 1080, 0, 1);
GL.MatrixMode(MatrixMode.Modelview);
GL.PushMatrix();
GL.LoadIdentity();
GL.Disable(EnableCap.Lighting);
GL.Enable(EnableCap.Texture2D);
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, image);
GL.Uniform1(positionLocation1, 0);
GL.Begin(PrimitiveType.Quads);
GL.TexCoord2(0, 1);
GL.Vertex3(0, 0, 0);
GL.TexCoord2(0, 0);
GL.Vertex3(1920, 0, 0);
GL.TexCoord2(1, 1);
GL.Vertex3(1920, 1080, 0);
GL.TexCoord2(1, 0);
GL.Vertex3(0, 1080, 0);
GL.End();
RunShaders();
GL.Disable(EnableCap.Texture2D);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Modelview);
glControl1.SwapBuffers();
}
private void RunShaders()
{
GL.UseProgram(program);
GL.DrawArrays(PrimitiveType.Triangles, 0, vertices.Length / 3);
}
Can anyone explain why here used vTexCoord = (a_position.xy+1)/2;?
The vertex coordinates in you example are in range [-1, 1], for the x and component. This matches to the normalized device space. The normalized device space is a cube from the left-lower-front (-1, -1, -1), to the right-top-back (1, 1, 1), this is the area wich is "visible". This area is mapped to the viewport.
This causes that the vertex coordinates, in your example, form a rectangle, which covers the entire viewport.
If the texture coordinates should wrap the entire texture to the quad, then the texture coordinates (u, v) have to be in range [0, 1]. (0, 0) is the lower left of the texture and (1, 1) the upper right.
See also How do OpenGL texture coordinates work?
So the x and y component of a_position have to be mapped form the range [-1, 1], to the range [0, 1], to be used as uv coordinates for the texture lookup:
u = (a_position.x + 1) / 2
v = (a_position.y + 1) / 2
What change should I do to work it with vTexCoord = a_position.xy?
This is not possible, but you can generate a separate texture coordinate attribute, which is common:
attribute vec3 a_position;
attribute vec2 a_texture;
varying vec2 vTexCoord;
void main() {
vTexCoord = a_texture;
gl_Position = vec4(a_position, 1);
}
float[] vertices = {
// x y z u v
// Left bottom triangle
-1f, -1f, 0f, 0f, 0f
1f, -1f, 0f, 1f, 0f
1f, 1f, 0f, 1f, 1f
// Right top triangle
1f, 1f, 0f, 1f, 1f
-1f, 1f, 0f, 0f, 1f
-1f, -1f, 0f 0f, 0f
};
buffer = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, buffer);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * sizeof(float)), vertices, BufferUsageHint.StaticDraw);
positionLocation = GL.GetAttribLocation(program, "a_position");
tetureLocation = GL.GetAttribLocation(program, "a_texture");
GL.EnableVertexAttribArray(positionLocation);
GL.EnableVertexAttribArray(tetureLocation);
int stride = sizeof(float) * 5; // 5 because of (x, y, z, u, v)
int offsetUV = sizeof(float) * 3; // 3 because the u and v coordinates are the 4th and 5th coordinate
GL.VertexAttribPointer(positionLocation, 3, VertexAttribPointerType.Float, false, stride, 0);
GL.VertexAttribPointer(tetureLocation, 2, VertexAttribPointerType.Float, false, stride, (IntPtr)(offsetUV));
I cannot render triangles for the life of me with a VBO in OpenTK. I am loading my data to the VBO in glControl_Load() event. I get a background screen with no triangles when running. The data is a from a mesh m.OpenGLArrays(out data, out indices) outputs a list of floats and ints. The list of floats for the vertices T1v1, T1v2, T1v3, T2v1, T2v2, T2v3, .... , all three vertices for each triangle back to back.
However given a blank screen with the code when I comment the "intermediate" rendering code everything renders fine....??? What am I doing wrong?
private void glControl_Load(object sender, EventArgs e)
{
loaded = true;
glControl.MouseMove += new MouseEventHandler(glControl_MouseMove);
glControl.MouseWheel += new MouseEventHandler(glControl_MouseWheel);
GL.ClearColor(Color.DarkSlateGray);
GL.Color3(1f, 1f, 1f);
m.OpenGLArrays(out data, out indices);
this.indicesSize = (uint)indices.Length;
GL.GenBuffers(1, out VBOid[0]);
GL.GenBuffers(1, out VBOid[1]);
SetupViewport();
}
private void SetupViewport()
{
if (this.WindowState == FormWindowState.Minimized) return;
glControl.Width = this.Width - 32;
glControl.Height = this.Height - 80;
Frame_label.Location = new System.Drawing.Point(glControl.Width / 2, glControl.Height + 25);
GL.MatrixMode(MatrixMode.Projection);
//GL.LoadIdentity();
GL.Ortho(0, glControl.Width, 0, glControl.Height, -1, 1); // Bottom-left corner pixel has coordinate (0, 0)
GL.Viewport(0, 0, glControl.Width, glControl.Height); // Use all of the glControl painting area
GL.Enable(EnableCap.DepthTest);
GL.BindBuffer(BufferTarget.ArrayBuffer, VBOid[0]);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(data.Length * sizeof(float)), data, BufferUsageHint.StaticDraw);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
float aspect_ratio = this.Width / (float)this.Height;
projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspect_ratio, 1, 1024);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadMatrix(ref projection);
}
private void glControl_Paint(object sender, PaintEventArgs e)
{
if (loaded)
{
GL.Clear(ClearBufferMask.ColorBufferBit |
ClearBufferMask.DepthBufferBit |
ClearBufferMask.StencilBufferBit);
modelview = Matrix4.LookAt(0f, 0f, -200f + zoomFactor, 0, 0, 0, 0.0f, 1.0f, 0.0f);
var aspect_ratio = Width / (float)Height;
projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspect_ratio, 1, 512);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadMatrix(ref projection);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadMatrix(ref modelview);
GL.Rotate(angleY, 1.0f, 0, 0);
GL.Rotate(angleX, 0, 1.0f, 0);
GL.EnableClientState(ArrayCap.VertexArray);
GL.BindBuffer(BufferTarget.ArrayBuffer, VBOid[0]);
GL.Color3(Color.Yellow);
GL.VertexPointer(3, VertexPointerType.Float, Vector3.SizeInBytes, new IntPtr(0));
GL.DrawArrays(PrimitiveType.Triangles, 0, data.Length);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.DisableClientState(ArrayCap.VertexArray);
//GL.Color3(Color.Yellow);
//GL.PolygonMode(MaterialFace.Front, PolygonMode.Fill);
//GL.Begin(PrimitiveType.Triangles);
//for (int i = 0; i < this.md.mesh.Count; i++)
//{
// GL.Normal3(this.md.mesh[i].normal);
// GL.Vertex3(this.md.mesh[i].vertices[0]);
// GL.Vertex3(this.md.mesh[i].vertices[1]);
// GL.Vertex3(this.md.mesh[i].vertices[2]);
//}
//GL.End();
//GL.EndList();
glControl.SwapBuffers();
Frame_label.Text = "Frame: " + frameNum++;
}
}
If something doesn't seem right, then it probably isn't. I seriously questioned my understanding of opengl and spent hours looking at this. However it was just a simple error of forgetting to iterate a count variable in a for loop to transfer the mesh from one object to another. Each triangle had identical vertices! Always expect the unexpected when it comes to debugging!
My image appears too large when it is rendered using SharpGL. How do I load it properly? The image's dimension is only 313 x 79 pixels but it almost occupy the rest of the screen when it renders.
I got this code from codeplex. The example given is how to render images in 3D (name of project is NativeTexturesSample).
https://sharpgl.codeplex.com/downloads/get/614989. I manage to make the rendering in 2D but I think I'm not doing it correctly.
private void openGLControl1_OpenGLDraw(object sender, RenderEventArgs e)
{
const int screenWidth = 1920;
const int screenHeight = 1080;
SharpGL.OpenGL gl = this.openGLControl1.OpenGL;
gl.MatrixMode(OpenGL.GL_PROJECTION);
gl.Ortho2D(0, screenWidth , screenHeight , 0);
gl.Disable(OpenGL.GL_DEPTH_TEST);
gl.LoadIdentity();
texture.Create(gl, #"C:\image\footerlogo.bmp");
texture.Bind(gl);
gl.Begin(OpenGL.GL_QUADS);
gl.TexCoord(0.0f, 1.0f); gl.Vertex(-2.0f, 0.0f);
gl.TexCoord(1.0f, 1.0f); gl.Vertex(1.0f, 0.0f);
gl.TexCoord(1.0f, 0.0f); gl.Vertex(1.0f, 1.0f);
gl.TexCoord(0.0f, 0.0f); gl.Vertex(-2.0f, 1.0f);
gl.End();
gl.Flush();
}
Try this code:
public partial class SharpGLForm : Form
{
private bool TexturesInitialised = false;
private float rotation = 0.0f;
private float Scale = 1;
private Bitmap gImage1;
private System.Drawing.Imaging.BitmapData gbitmapdata;
private uint[] gtexture = new uint[1];
/// <summary>
/// Initializes a new instance of the <see cref="SharpGLForm"/> class.
/// </summary>
public SharpGLForm()
{
InitializeComponent();
}
private void InitialiseTexture(ref OpenGL gl)
{
gImage1 = new Bitmap(#"C:\Jess1.bmp");// Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)
Rectangle rect = new Rectangle(0, 0, gImage1.Width, gImage1.Height);
gbitmapdata = gImage1.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
gImage1.UnlockBits(gbitmapdata);
gl.GenTextures(1, gtexture);
gl.BindTexture(OpenGL.GL_TEXTURE_2D, gtexture[0]);
gl.TexImage2D(OpenGL.GL_TEXTURE_2D, 0, (int)OpenGL.GL_RGB8, gImage1.Width, gImage1.Height, 0, OpenGL.GL_BGR_EXT, OpenGL.GL_UNSIGNED_BYTE, gbitmapdata.Scan0);
uint[] array = new uint[] { OpenGL.GL_NEAREST };
gl.TexParameterI(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_MIN_FILTER, array);
gl.TexParameterI(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_MAG_FILTER, array);
TexturesInitialised = true;
}
private void openGLControl_OpenGLDraw(object sender, RenderEventArgs e)
{
// Get the OpenGL object.
OpenGL gl = openGLControl.OpenGL;
// Clear the color and depth buffer.
gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
// Load the identity matrix.
gl.LoadIdentity();
if (!TexturesInitialised)
{
InitialiseTexture(ref gl);
}
gl.Enable(OpenGL.GL_TEXTURE_2D);
gl.BindTexture(OpenGL.GL_TEXTURE_2D, gtexture[0]);
gl.Color(1.0f, 1.0f, 1.0f, 0.1f); //Must have, weirdness!
gl.Begin(OpenGL.GL_QUADS);
gl.TexCoord(1.0f, 1.0f);
gl.Vertex(gImage1.Width, gImage1.Height, 1.0f);
gl.TexCoord(0.0f, 1.0f);
gl.Vertex(0.0f, gImage1.Height, 1.0f);
gl.TexCoord(0.0f, 0.0f);
gl.Vertex(0.0f, 0.0f, 1.0f);
gl.TexCoord(1.0f, 0.0f);
gl.Vertex(gImage1.Width, 0.0f, 1.0f);
gl.End();
gl.Disable(OpenGL.GL_TEXTURE_2D);
}
private void openGLControl_OpenGLInitialized(object sender, EventArgs e)
{
OpenGL gl = openGLControl.OpenGL;
gl.ClearColor(0, 0, 0, 0);
}
private void openGLControl_Resized(object sender, EventArgs e)
{
OpenGL gl = openGLControl.OpenGL;
gl.MatrixMode(OpenGL.GL_PROJECTION);
gl.LoadIdentity();
gl.Perspective(60.0f, (double)Width / (double)Height, 0.01, 10000.0);
gl.LookAt(0, 0, -500, 0, 0, 0, 0, 1, 0);
gl.MatrixMode(OpenGL.GL_MODELVIEW);
}
}
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);
}