If you have been following along with the previous posts on drawing circles:

Drawing Circles With OpenGL, and

Device Coordinates and Object Coordinates,

you will note that the circle is located at the centre of the canvas (0, 0). In this post, we will move the circle away from the centre. In OpenGL, moving objects (and rotating and scaling objects) is normally done by defining a set of transformation matrices, and applying these transformations in the vertex shader.

The problem we have in the CirclesAndRotators program is that the circle is actually defined as a square, and the points that are outside the circle are discarded in the fragment shader. To determine if a point (pixel) is inside or outside the circle, the length of the vector from the origin to the fragment point is compared to the radius of the circle. So, if we transform the centre of the circle away from the centre of the canvas in the vertex shader, we must then transform each fragment point back to determine if it is inside the circle. To do that, we will have to pass the transformation matrix into the fragment shader.

Oh god, matrices, really? Well yes. Graphics programming is heavy on the mathematics, but don’t worry, there is help in the form of a matrix library written specifically for OpenGL called OpenGL Mathematics (GLM). See Transformations on learnopengl.com for a discussion of transformations, matrices, and GLM.

This post will be using that library, so go ahead and download the zip file from SourceForge, and extract it. GLM is a header only library, so there is no build to perform. Now add the location of the header files to the VC++ Include Directories list. Since you will be doing a lot of OpenGL programming, you should probably set up a Macro that defines the location where you extracted the library to, and add the include path as user-wide settings. See User-Wide Settings in Visual Studio 2015 if you do not know how to do that.

For more information on GLM, see the documentation in the `doc`

subfolder that is downloaded with the library.

In this post, the transformation will consist only of a translation (moving the circle off centre); rotations and scaling will be discussed in a future post. We will pass the transform into both the vertex and the fragment shaders as a uniform. In the vertex shader, we apply the transform to each vertex, and in the fragment shader, we apply the transform to the origin to determine the centre of the circle. We need to transform the circle back to the origin to determine if a point is inside or outside the circle.

Here is the vertex shader:

const GLchar* vertexSource = "#version 330 core\n" "in vec4 position;" "uniform mat4 transform;" "void main() "{" " gl_Position = transform * position;" "}";

Note that we apply the transformation to the vertex to determine the transformed position of the vertex.

And here is the fragment shader:

const GLchar* fragmentSource = "#version 330 core\n" "uniform vec2 viewDimensions;" "uniform float outerRadius;" "uniform mat4 transform;" "out vec4 outColor;" "void main()" "{" // transform the center of the circle. We need this later to determine if the // fragment is inside or outside the circle. " vec4 center = transform * vec4(0.0f, 0.0f, 0.0f, viewDimensions.x / 2.0f);" // translate fragment coordinate to coordinate relative to center of circle " float x = gl_FragCoord.x - center.x - viewDimensions.x / 2.0f;" " float y = gl_FragCoord.y - center.y - viewDimensions.y / 2.0f;" // discard fragment if outside the circle " float len = sqrt(x * x + y * y);" " if (len > outerRadius) {" " discard;" " }" // else set its colour to green " outColor = vec4(0.0, 1.0, 0.0, 1.0);" "}";

In this shader, the transform matrix is multiplied against the vector describing the origin. The new x and y coordinates of the origin of the circle are then subtracted from the x and y fragment coordinates. These new coordinates are used to determine if the fragment is inside or outside the circle.

In the CirclesAndRotatorsCanvas class, we only need to create the `transform`

matrix and pass it to the GPU. In the header file, add a property called `m_transform`

to the class. In the source file, retrieve the location of the transform uniform value.

Add the following lines in the header includes at the top of the source file:

#define GLM_FORCE_CXX14 #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp>

`GLM_FORCE_CXX14`

tells GLM to use the C++14 language extensions because we are using a compiler that supports C++14.

Now add the following code to `CirclesAndRotatorsCanvas::OnPaint`

:

glm::mat4 transform; transform = glm::translate(transform, glm::vec3(220.0f / w, -150.0f / w, 0.0f / w)); glUniformMatrix4fv(m_transform, 1, GL_FALSE, glm::value_ptr(transform));

This code creates a 4 by 4 matrix called `transform`

. The second line sets `transform`

to be a translate matrix that will move the circle to (220, -150). Note that the second argument to `glm::translate`

is a `vec3`

and not a `vec4`

, so the `x`

, `y`

and `z`

values must be normalized. The third line passes the transform to the GPU.

I did make one other change to the code in the class. In the `CreateSquareForCircle`

method, I changed the `points`

definition from an array of `float`

s to an array of `vec4`

s. This change is not necessary; I just did it to show a different way of defining the vertices.

The source code is in the offcenter branch on GitHub.

And here is the result of running the program. The circle has been moved from the center of the canvas (0, 0) to (220, -150).

Pingback: Two Rotating Circles | Using C++