Draw Circles Java Site Stackoverflow.com
First created on 2016-03-19
Last updated on 2019-02-03
This article builds on code and data that was provided in a number of other manufactures on this site. See Related Articles, at the bottom of this commodity, for the full list.
The but shapes that OpenGL tin depict are points, lines, and triangles,so how do you depict circles and other shapes? A reasonable approximation of a circumvolve can be drawn using many, many triangles with one vertex at the heart of the circle and the other two vertices sharing the same location as one of the vertices of the triangles side by side to it on the outer edge of the circle. Triangles of course have straight sides, but the more triangles you utilize to ascertain the circle, and therefore the closer the vertices on the edge of the circle are, the closer they stand for a rounded edge. But that is a lot of work, and at that place is a better fashion: define a square whose sides are equal to the diameter of the circle you desire to draw and take the fragment shader decide whether the point information technology is cartoon is inside or exterior the circle. That is what we will do in this post.
The program that we volition create in this post will just depict a green circumvolve at the centre of the view, just we volition be modifying the programme over time to display circles and other objects at various locations in the view and rotate them around the centre of the view. New techniques will exist described as they are used.
Drawing A Circumvolve
Starting time by creating a new empty project in Visual Studio chosen
CirclesAndRotators, then add three new classes to information technology called CirclesAndRotatorsApp, CirclesAndRotatorsFrame, and CirclesAndRotatorsCanvas. Follow the steps outlined in:
- Creating wxWidgets Programs with Visual Studio 2017 – Function 1
- Visual Studio, wxWidgets and OpenGL
- Hello Triangle: OpenGL with wxWidgets, and
- OpenGL Shaders.
replacing form names as advisable.
A number of the methods in the classes remain the aforementioned, then they volition non be repeated in this mail. However, the source of the full programme is provided on Github if yous find you are having problems. The code for this commodity is in the master co-operative.
CirclesAndRotatorsApp.OnInit is modified to place lawmaking in a try-catch cake because additional exceptions may be thrown. The catch block simply displays a message box with the text of the exception. For a total discussion of handling exceptions in wxWidgets programs, come across C++ Exceptions and wxWidgets. Here is the OnInit code:
bool CirclesAndRotatorsApp::OnInit() { try { CirclesAndRotatorsFrame* mainFrame = new CirclesAndRotatorsFrame(nullptr, Fifty"Circles and Rotators"); mainFrame->Show(true); } catch (std::exception& e) { wxMessageBox(e.what(), "CirclesAndRotators"); } return true; } The CirclesAndRotatorsFrame constructor creates a CirclesAndRotatorsCanvas object that is 800 by 800 pixels in size. While this size can be inverse, the lawmaking in this program assumes that the canvas is square (i.eastward. has the same number of pixels in both ten and y directions). If you exercise not create a square canvas, you will have to modify the plan to compensate.
Every bit with the other programs I take shown so far, the majority of the code is in the canvas grade.
The BuildCircleVertexShader method builds the vertex shader for the circle. Here is the code:
void CirclesAndRotatorsCanvas::BuildCircleVertexShader() { const GLchar* vertexSource = "#version 330 cadre\n" "in vec2 position;" "void primary()" "{" " gl_Position = vec4(position, 0.0, 1.0);" "}"; m_circleVertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(m_circleVertexShader, 1, &vertexSource, Zip); glCompileShader(m_circleVertexShader); CheckShaderCompileStatus(m_circleVertexShader, "Circle Vertex Shader did non compile."); } This simple vertex shader takes the two-dimensional position of the vertex and stores information technology in the gl_Position global variable. The rest of the code you have seen in the previous posts except for the telephone call to CheckShaderCompileStatus. This method checks if the shader compiled, and throws an exception if it did not:
void CirclesAndRotatorsCanvas::CheckShaderCompileStatus(GLuint shader, const std::string& msg) const { // bank check shader compile condition, and throw exception if compile failed GLint status; glGetShaderiv(shader, GL_COMPILE_STATUS, &status); if (status != GL_TRUE) { throw std::exception(msg.c_str()); } } Note: The status returned by glGetShaderiv contains but GL_TRUE or GL_FALSE. If GL_FALSE, then you tin telephone call glGetShaderInfoLog to retrieve information on the error. Do not expect detailed mistake letters. This would mayhap be a skilful topic for a hereafter commodity.
The BuildCircleFragmentShader method determines whether the fragment (pixel) existence displayed is inside or outside the circumvolve. Here is the source code for the method:
void CirclesAndRotatorsCanvas::BuildCircleFragmentShader() { const GLchar* fragmentSource = "#version 330 cadre\n" "uniform vec2 viewDimensions;" "uniform float outerRadius;" "out vec4 outColor;" "void principal()" "{" // convert fragment coordinate (i.east. pixel) to view coordinate " float x = (gl_FragCoord.ten - viewDimensions.x / two.0f) / (viewDimensions.x / 2.0f);" " float y = (gl_FragCoord.y - viewDimensions.y / 2.0f) / (viewDimensions.y / ii.0f);" // discard fragment if exterior the circle " bladder len = sqrt(x * ten + y * y);" " if (len > outerRadius) {" " discard;" " }" // else set its colour to greenish " outColor = vec4(0.0, i.0, 0.0, 1.0);" "}"; m_circleFragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(m_circleFragmentShader, 1, &fragmentSource, Cipher); glCompileShader(m_circleFragmentShader); CheckShaderCompileStatus(m_circleFragmentShader, "Circle Fragment Shader did not compile"); } In order to determine if the fragment is within or exterior the circle, we need three values: the position of the fragment, given in gl_FragCoord, the radius of the circle, given past the compatible value outerRadius, and the dimensions of the canvas. gl_FragCoord gives the location of the pixel containing the fragment, but outerRadius is the radius of the circle in device coordinates (10 and y between -ane and +1), and so the dimensions of the canvas are required to convert between the pixel coordinates and the device coordinates.
The lines that ascertain 10 and y convert the gl_FragCoord x and y coordinates into device coordinates. The length of the vector (len) from the origin (centre of the view) to the fragment is calculated and compared with the radius of the circle. If the fragment is inside the circumvolve, then the pixel colour is set to green, and if the fragment is outside the circle, the fragment is discarded. If yous wish, rather than discard the fragment, you could set it to a different colour than light-green or the background colour and so that you can see the square that contains the circle.
The BuildCircleShaderProgram method beginning calls BuildCircleVertexShader and BuildCircleFragmentShader, then links them to create the shader program. The location of the position attribute input to the vertex shader is obtained and the enabled. The locations of the 2 compatible variables input to the fragment shader are obtained next, and finally, the size of the canvass is ready (viewDimensions in the fragment shader). Annotation: the size of the canvass is not modifiable, and then this uniform value needs to be set only once. Here is the source code for the BuildCircleShaderProgram method:
void CirclesAndRotatorsCanvas::BuildCircleShaderProgram() { // build the circle shaders BuildCircleVertexShader(); BuildCircleFragmentShader(); // create and link circle shader programme m_circleShaderProgram = glCreateProgram(); glAttachShader(m_circleShaderProgram, m_circleVertexShader); glAttachShader(m_circleShaderProgram, m_circleFragmentShader); glBindFragDataLocation(m_circleShaderProgram, 0, "outColor"); glLinkProgram(m_circleShaderProgram); // set up position attribute used in circle vertex shader GLint posAttrib = glGetAttribLocation(m_circleShaderProgram, "position"); glEnableVertexAttribArray(posAttrib); glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0); // gear up upwards the compatible arguments m_circleOuterRadius = glGetUniformLocation(m_circleShaderProgram, "outerRadius"); m_viewDimensions = glGetUniformLocation(m_circleShaderProgram, "viewDimensions"); // The canvas size is fixed (and should be square), and then initialize the value here glUseProgram(m_circleShaderProgram); wxSize canvasSize = GetSize(); glUniform2f(m_viewDimensions, static_cast(canvasSize.x), static_cast(canvasSize.y)); } The fragment shader determines if the a fragment is inside or exterior of the circumvolve. Only to become a fragment to determine this, we have to define the square that contains the circle. This is done in the CreateSquareForCircleMethod:
void CirclesAndRotatorsCanvas::CreateSquareForCircle() { // define vertices for the ii triangles float points[] = { -0.2f, -0.2f, 0.2f, -0.2f, 0.2f, 0.2f, -0.2f, 0.2f }; // ascertain the indices for the triangles GLuint elements[] = { 0, 1, two, 2, iii, 0 }; // setup vertex assortment object glGenVertexArrays(1, &m_circleVao); glBindVertexArray(m_circleVao); // upload vertex data glGenBuffers(1, &m_circleVbo); glBindBuffer(GL_ARRAY_BUFFER, m_circleVbo); glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW); // upload element data glGenBuffers(1, &m_circleEbo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_circleEbo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW); } Wait a minute. To form a foursquare, we need two triangles which take a total of six vertices, but the points assortment only contains iv vertices. Yes, that is true, but note that the first triangle is defined by the vertices v0, v1, and v2, and the second triangle is defined by the vertices v2, v3, and v0. Rather than requiring that these vertices be restated, OpenGL has the concept of elements. Note that the elements array contains 6 values that stand for to the six vertex numbers for the two triangles. Beneath these definitions, in that location are 2 calls to glBindBuffer and glBufferData, one for the points assortment that specifies the blazon as GL_ARRAY_BUFFER, and the second for the elements array that specifies the type as GL_ELEMENT_ARRAY_BUFFER. This tells the GPU that the first buffer contains vertex data and the second buffer contains an array that specifies which vertices to use when cartoon.
That seems like extra work, and more buffer infinite in the GPU. Assuming 4 bytes required for each float and each unsigned int in the GPU, defining vi vertices results in 48 bytes of buffer space. Using iv vertices and 6 elements, there is a total of 56 bytes, so there is more buffer space required in this case. But what happens if the vertices are specified in 3D, as would be the case in well-nigh OpenGL programs? For just these two triangles, specifying the triangles using just the points assortment uses 72 bytes; specifying the triangles using both points and elements arrays, over again uses 72 bytes. Now add a tertiary triangle that shares 2 vertices with other triangles: nosotros have 108 bytes versus 96 bytes. Equally the number of shared vertices increases, the use of elements increases the savings. Since a normal OpenGL plan will define hundreds or even thousands of fastened triangles, the saving can become quite substantial.
Finally, here is the lawmaking that draws the rectangle resulting in the circumvolve:
void CirclesAndRotatorsCanvas::OnPaint(wxPaintEvent& event) { SetCurrent(*m_context); // prepare background to black glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // use the circleShaderProgram glUseProgram(m_circleShaderProgram); // set outer radius for circle here. Nosotros volition exist modulating it in later // instance glUniform1f(m_circleOuterRadius, 0.2f); // depict the square that will comprise the circle. // The circumvolve is created inside the square in the circle fragment shader glDrawElements(GL_TRIANGLES, vi, GL_UNSIGNED_INT, 0); glFlush(); SwapBuffers(); } We take seen most of this before. The only differences are the three lines:
glUseProgram(m_circleShaderProgram); glUniform1f(m_circleOuterRadius, 0.2f); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
In previous example programs, glUseProgram was chosen immediately after the shader programme was linked. In those cases, just 1 shader programme was created. As we develop the CirclesAndRotators program further, we volition create boosted shader programs. 1 shader program volition be used for drawing some shapes, and additional shader programs will exist used when cartoon other shapes. Hence, we need to telephone call glUseProgram for the appropriate shader program before drawing whatsoever objects that use that shader plan.
If previous examples, glDrawArrays was called to depict the objects. If we called glDrawArrays here, only ane triangle would be drawn. Endeavour information technology and run into. To apply elements, we must call glDrawElements instead.
The only remaining job is to release the GPU resources in the CirclesAndRotatorsCanvas destructor.
Here is the resulting display:
The source code for the program is provided in the master co-operative on GitHub.
Related Articles
This commodity is built on code and data that was provided in:
- OpenGL Shaders
which in turn was built from code and information provided in:
- Creating wxWidgets Programs with Visual Studio 2017 – Function 1
- Visual Studio, wxWidgets and OpenGL
- Hello Triangle: OpenGL with wxWidgets
The lawmaking provided is further adult in:
- Device Coordinates and Object Coordinates
- Moving the Circle Off Centre
- 2 Rotating Circles
- Adding a Moving Triangle
- Circles and Rotators Design and Coding Decisions
pattonintentookey.blogspot.com
Source: https://computingonplains.wordpress.com/drawing-circles-with-opengl/
0 Response to "Draw Circles Java Site Stackoverflow.com"
Post a Comment