Unity Gl to Draw a Circle
This fourth dimension I want to talk virtually drawing geometric shapes using OpenGL. As we know, we tin can depict lines, triangles, and quads, merely what almost circles? There are several ways to exercise this. First fashion is gauge circle with number of lines. Permit's look at the figure one. We have an approximation of circle nowadays past sixteen vertices. We will describe 16 edges: {[v1, v2],[v2, v3],…,[v16, v1]}. This can be enough fo the circle to looks smooth at depression resolutions, but nosotros accept to make more vertices and edges to make the circle smooth at loftier DPI displays.
To generate this type of circle we tin can use this fragment of (C11) code
#define NUMBER_OF_VERTICES 16 float radius = 0.5; std::vector<float> vertexBuffer; for(double i = 0; i < two * M_PI; i += 2 * M_PI / NUMBER_OF_VERTICES){ vertexBuffer.push_back(cos(i) * radius); //10 coordinate vertexBuffer.push_back(sin(i) * radius); //Y coordinate vertexBuffer.push_back(0.0); //Z coordinate }
This code generates a buffer, that we can bind to attribute vector in vertex shader
glBindBuffer(GL_ARRAY_BUFFER, 0); glVertexAttribPointer(VERTEX_ATTRIBUTE_INDEX , 3, GL_FLOAT, GL_FALSE, 12, vertexBuffer.information());
and describe information technology, using OpenGL function glDrawArrays
glDrawArrays(GL_LINE_LOOP, 0, NUMBER_OF_VERTICES);
Draw filled circle
So, we tin draw a circle, but what we have to do if we wan to fill information technology with colour? We take to subdivide our effigy to triangles and render each triangle filled with colour. Look at figure ii.
This shape is subdivided to xiv triangles with mutual vertices v1. In OpenGL this structure of mesh calls TRIANGLE_FAN, and we have special drawing fashion GL_TRIANGLE_FAN. To implement information technology we'll modify simply one line of code:
glDrawArrays(GL_TRIANGLE_FAN, 0, NUMBER_OF_VERTICES);
At present we complicate our chore. We`ll draw something like a torus project on the plain. As we did above, we`ll approximate this effigy with simple polygons. Looks at the figure 3.
I suggest using GL_QUAD_STRIP to draw this figure. Now we'll depict a strip of 16 quads, that looks like sequence of vertices: {[v'1,v1,5'2,v2],[v'2,v2,v'3,v3]…[v'16,v16,v'1,v1]}. Let's generate vertices for quads
#define NUMBER_OF_VERTICES 16 float radius_1 = 0.5; bladder radius_2 = 0.25; std::vector::vertexBuffer; for(double i = 0; i &lt; 2 * PI; i += PI / NUMBER_OF_VERTICES_2){ vertexBuffer.pushBack(cos(i) * radius_2); //X coordinate vertexBuffer.pushBack(sin(i) * radius_2); //Y coordinate vertexBuffer..pushBack(0.0); //Z coordinate vertexBuffer.pushBack(cos(i) * radius_1); //X coordinate vertexBuffer.pushBack(sin(i) * radius_1); //Y coordinate vertexBuffer..pushBack(0.0); //Z coordinate } vertexBuffer.pushBack(radius_2); vertexBuffer.pushBack(0.0); vertexBuffer.pushBack(0.0); vertexBuffer.pushBack(radius_1); vertexBuffer.pushBack(0.0); vertexBuffer.pushBack(0.0);
and describe a quad strip:
glBindBuffer(GL_ARRAY_BUFFER, 0); glVertexAttribPointer(VERTEX_ATTRIBUTE_INDEX , 3, GL_FLOAT, GL_FALSE, 12, vertexBuffer.information()); glDrawArrays(GL_QUAD_STRIP, 0, ii*NUMBER_OF_VERTICES+2);
Draw filled circle in shader (GLSL)
Those methods are based on the shape of object. At present I desire to present you another one method based on a shading. As we well know we can inscribe circle into quad, I chose this figure as basic archaic that I should laissez passer into fragments shader. I correspond quad by «triangle fan», because GPUs render «triangle fan» faster then other shapes. Our vertexBuffer will be looks like this
float right = 0.5; float bottom = -0.5; float left = -0.5; bladder top = 0.5; bladder vertexBuffer[xviii]={ //x y z right, lesser, 0, // v1 right, top, 0, // v2 left, summit, 0, // v3 left, bottom, 0, // v4 };
If we draw this vertexBuffer we'll se a quad on the screen. Yous can inquire me: So, where is a circle? To plow this quad into a circle we accept to add some data.
float valueBuffer[12]={ //lx ly 1.0, -1.0, 1.0, 1.0, -one.0, 1.0, -1.0, -one.0, }
Now we accept 2 coordinate systems: OpenGL coordinate arrangement and local coordinate organization.
In OpenGL coordinate systems nosotros can do any ain modifications of shape (such every bit translate, rotate and scale) which change vertex data, but values in local coordinate system will be constant. To increases performance I combine vertexBuffer and valueBuffer and bind this result to VBO:
float right = 0.5; float bottom = -0.5; float left = -0.5; bladder height = 0.5; float quad[xx] = { //x, y, z, sixty, ly right, bottom, 0, 1.0, -1.0, correct, top, 0, 1.0, 1.0, left, elevation, 0, -one.0, 1.0, left, bottom, 0, -i.0, -1.0, }; unsigned int glBuffer; glGenBuffers(one, &glBuffer); glBindBuffer(GL_ARRAY_BUFFER, glBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*twenty, quad, GL_STATIC_DRAW);
Let'south look at fragment shader.
aspect vec4 vertex; attribute vec2 value; uniform mat4 viewMatrix; uniform mat4 projectionMatrix; varying vec2 val; void main() { val = value; gl_Position = projectionMatrix*viewMatrix*vertex; }
In fragment shader we accept two attribute vectors. We bid vertexBuffer to vertex aspect vector and valueBuffer to value attribute vector. So nosotros pass local coordinate values to fragment shader using varying vec2 val. Now GPU interpolates local values for each pixel of the quad on the screen. All we know standard equitation of a circle on coordinate plane:
(10-x0)^2+(y-y0)^2 = R^two
x0 and y0 are coordinates of the center on the coordinate plane, x and y are local coordinates of quad and R is radius of the circle. Nosotros have all necessary data do write a fragment shader.
varying vec2 val; void main() { float R = 1.0; float R2 = 0.5; float dist = sqrt(dot(val,val)); if (dist >= R || dist <= R2) { discard; } gl_FragData[0] = vec4(0.0, 0.0, 1.0, one.0); //Blue colour }
This shader fills with blue colour only distance between R1 and R2. As you can see, this circle is non antialiased. If you implement 'Deferred rendering' technique with FXAA post processing you can don`t care nearly this and use this shader «as-is». Past the mode, on retina display it looks good. 🙂 Otherwise you can smooth edges of circle past smoothstep part.
varying vec2 val; void main() { float R = one.0; float R2 = 0.5; float dist = sqrt(dot(val,val)); if (dist >= R || dist <= R2) { discard; } float sm = smoothstep(R,R-0.01,dist); float sm2 = smoothstep(R2,R2+0.01,dist); float alpha = sm*sm2; gl_FragColor = vec4(0.0, 0.0, 1.0, alpha); }
Note, before using this shader, yous take to enable alpha blending.
glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
That'due south all, folks! In that location is our circle!
As usual, you can download code sample from this link:circles.tar.gz
Source: https://blog.lapingames.com/draw-circle-glsl-shader/