使用投影矩阵移动圆形。

huangapple go评论81阅读模式
英文:

Move circle with Projection matrix

问题

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);

使用投影矩阵移动圆形。
使用投影矩阵移动圆形。

英文:

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 &lt;glew.h&gt;
#include &quot;circle.h&quot;
Circle::Circle()
{
const std::string vertexShaderSource = R&quot;END(
#version 330 core
layout (location = 0) in vec4 vertex; // &lt;vec2 position, vec2 texCoords&gt;
uniform mat4 model;
uniform mat4 projection;
uniform mat4 view;
void main()
{
gl_Position = projection * view * model * vec4(vertex.xy, 0.0, 1.0);
}
)END&quot;;
const std::string fragmentShaderSource = R&quot;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&quot;;
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&lt;RenderService&gt;()-&gt;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&lt;float&gt;(width),
static_cast&lt;float&gt;(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(&quot;projection&quot;, projection);
shader.setMat4(&quot;model&quot;, model);
shader.setMat4(&quot;view&quot;, view);
shader.setVec2(&quot;dim&quot;, glm::vec2{transform.dimension.width, transform.dimension.height});
shader.setVec2(&quot;pos&quot;, glm::vec2{transform.position.x, transform.position.y});
shader.setVec4(&quot;spriteColor&quot;, 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, &amp;vao);
glGenBuffers(1, &amp;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);

使用投影矩阵移动圆形。
使用投影矩阵移动圆形。

答案1

得分: 1

你说你要使用视图矩阵来移动圆形。你确实将该矩阵传递到顶点着色器,并在计算gl_Position时使用它。然而,你的片元着色器计算是基于gl_FragCoord的,没有以任何方式合并视图矩阵。请记住,gl_FragCoord是相对于帧缓冲区左下角(通常是这样)的片元坐标,因此不受模型/视图/投影变换的影响。

要解决这个问题,你可以执行以下任一操作:

  • Circle::Update中计算圆的中心的片元坐标,并将该坐标传递给pos uniform:

    glm::vec4 pos = view*glm::vec4{transform.position.x, transform.position.y, 0.0f, 1.0f};
    shader.setVec2("pos", pos.xy);
    
  • 在片元着色器中应用视口变换——与上述操作相同,但在着色器中执行。这有点丑陋,因为你将应用view但不应用model,因为后者已经包含在pos的值中。此外,这涉及更多在片元着色器中的计算。

  • 更改你的片元着色器以使用纹理坐标而不是gl_FragCoord。如果你在四边形的顶点上设置了固定的纹理坐标,那么四边形内部的插值坐标将根据视图/模型/投影之一进行正确变换,因此可以处理缩放甚至透视投影。这可能是你的情况中最干净的解决方案。(尽管如此,基于gl_FragCoord的光栅化有时是必要的,以避免在四边形的两个三角形之间的接缝上出现伪影。)

英文:

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(&quot;pos&quot;, 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.)

huangapple
  • 本文由 发表于 2023年1月9日 18:52:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/75056211.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定