1

I need some help trying to move my circle with view matrix. I can position the circle but cant move it. How can i make this happen?

Right now the the bounding rectangle moves but not the circle.

I've tried to center the circle in the rectangle and but this doesnt work.

Any help is appreciated!

#include <glew.h>
#include "circle.h"

Circle::Circle()
{
    const std::string vertexShaderSource = R"END(

        #version 330 core
        layout (location = 0) in vec4 vertex; // <vec2 position, vec2 texCoords>

        uniform mat4 model;
        uniform mat4 projection;
        uniform mat4 view;

        void main()
        {
            gl_Position = projection * view * model * vec4(vertex.xy, 0.0, 1.0);
        }

        )END";

    const std::string fragmentShaderSource = R"END(

        #version 330 core

        out vec4 color;
        uniform vec2 dim;
        uniform vec2 pos;

        /**
         * Convert r, g, b to normalized vec3
         */
        vec3 rgb(float r, float g, float b) {
            return vec3(r / 255.0, g / 255.0, b / 255.0);
        }

        /**
         * Draw a circle at vec2 `pos` with radius `rad` and
         * color `color`.
         */
        vec4 circle(vec2 uv, vec2 pos, float rad, vec3 color) {
            float d = length(pos - uv) - rad;
            float t = clamp(d, 0.0, 1.0);
            return vec4(color, 1.0 - t);
        }

        void main() {

            vec2 uv = gl_FragCoord.xy;
            float radius = 60;

            vec2 center = pos;

            // Background layer
            vec4 layer1 = vec4(rgb(210.0, 222.0, 228.0), 0.3);
            
            // Circle
            vec3 red = rgb(225.0, 95.0, 60.0);
            vec4 layer2 = circle(uv, center, radius, red);
            
            // Blend the two
            color = mix(layer1, layer2, layer2.a);
        }

        )END";

    shader.Compile(vertexShaderSource.c_str(), fragmentShaderSource.c_str());

    // Configure VAO etc..
}

void Circle::Update(float deltaTime, int width, int height)
{
    // Activate shader
    shader.Activate();

    auto camera = Services::Get<RenderService>()->camera;

    glm::mat4 model = glm::mat4(1.0f);
    glm::mat4 view;

    if (skipPan == false)
    {
        view = camera.GetViewMatrix();
    }
    else
    {
        view = glm::mat4{1.0f};
    }

    projection = glm::ortho(0.0f, static_cast<float>(width),
                            static_cast<float>(height), 0.0f, -1.0f, 1.0f);

    model = glm::translate(model, glm::vec3(transform.position.x, transform.position.y, 0.0f));
    model = glm::scale(model, glm::vec3(transform.dimension.width, transform.dimension.height, 1.0f));

    shader.setMat4("projection", projection);
    shader.setMat4("model", model);
    shader.setMat4("view", view);
    shader.setVec2("dim", glm::vec2{transform.dimension.width, transform.dimension.height});
    shader.setVec2("pos", glm::vec2{transform.position.x, transform.position.y});
    shader.setVec4("spriteColor", glm::vec4{style.Background.r, style.Background.g, style.Background.b, style.Background.a});

    glBindVertexArray(vao);
    glDrawArrays(GL_TRIANGLES, 0, 6);
}

This is an issue i've been struggeling with for some time now. This applies to other shapes aswell that renders with SDF and such.

// configure VAO/VBO
const float vertices[] = {
    0.0f, 1.0f, 0.0f,
    1.0f, 0.0f, 1.0f,
    0.0f, 0.0f, 0.0f,
    0.0f, 1.0f, 0.0f,
    1.0f, 1.0f, 1.0f,
    1.0f, 0.0f, 1.0f};

glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);

glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

First picture Pan right

J.Wennergren
  • 145
  • 14
  • can you confirm `glDrawArrays` calling one time is enough ? for two object, are those two object belongs to single array ? – Dickens A S Jan 09 '23 at 13:29
  • I am asking this question, the reason I see only one `glBindVertexArray` – Dickens A S Jan 09 '23 at 13:31
  • Yes the two objects belongs to the same vertices array. – J.Wennergren Jan 09 '23 at 13:34
  • so it is the problem with your array only which confuses `gl_Position` – Dickens A S Jan 09 '23 at 13:37
  • Hmm you're right. but i'm not sure how to fix it. – J.Wennergren Jan 09 '23 at 13:44
  • can you confirm after you call `useProgram` did you bind the `pos` attribute using `glGetAttribLocation` method ? and also confirm you are using `glGetUniformLocation` to bind your `glUniformMatrix` – Dickens A S Jan 09 '23 at 14:02
  • No i havnt bound pos attribute with that method. I thought i didnt need to since i'm using uniforms. – J.Wennergren Jan 09 '23 at 14:06
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/250972/discussion-between-dickens-a-s-and-j-wennergren). – Dickens A S Jan 09 '23 at 15:28
  • Why `uv = gl_FragCoord.xy`? why not uv coordinates from the vertices? (gl_MultiTexCoord0; or from the vertex shader, which is the ubiquitous technique). By using gl_FragCoord, you've inadvertently done what [this answer](https://stackoverflow.com/a/7781979/1563833) suggests. But you actually need the opposite of what is suggested there, i.e., just use UV texture coordinates the usual way. Don't worry, you're [not the first](https://stackoverflow.com/questions/65481082/glsl-fit-fragment-shader-mask-into-vertex-coordinates) – Wyck Jan 09 '23 at 16:02

1 Answers1

1

You say that you're trying to move the circle with the view matrix. You indeed pass that matrix to your vertex shader and use it in the computation of gl_Position. However, your fragment shader calculation is based on gl_FragCoord and doesn't incorporate the view matrix in any way. Remember that gl_FragCoord is the fragment coordinates relative to the framebuffer bottom-left corner (usually), and is therefore not affected by the model/view/projection transformations.

To solve this, you can do any of the following:

  • Calculate the fragment coordinates of the center of your circle in Circle::Update and pass that to the pos uniform:

    glm::vec4 pos = view*glm::vec4{transform.position.x, transform.position.y, 0.0f, 1.0f};
    shader.setVec2("pos", pos.xy);
    
  • Apply the viewport transformation in the fragment shader -- same as above but done in the shader. This is kinda ugly as you would be applying view but not model because the later is already accounted for in the value of pos. Also it involves more calculations in the fragment shader.

  • Change your fragment shader to work off texture coordinates instead of gl_FragCoord. If you set fixed texture coordinates at the vertices of the quad, then the interpolated coordinates within the quad will transform correctly with regards to any of the view/model/projection, thus handling scaling or even perspective projections out-of-the-box. This would probably be the neatest solution in your case. (That being said, rasterization based on gl_FragCoord is sometimes necessary to avoid artifacts on the seam between the two triangles of the quad.)

Yakov Galka
  • 70,775
  • 16
  • 139
  • 220