简体   繁体   English

如何避免在 OpenGL 中使用着色器消失线?

[英]How I can avoid in OpenGL disappearing lines using a shader?

So I'm drawing some lines by just using a fragment shader.所以我只使用片段着色器来绘制一些线条。 The vertex it's just an empty quad.顶点只是一个空的四边形。

The issue I have is that when I zoom out the camera and the lines get smaller they sometimes appear and disappear and I don't understand why.我遇到的问题是,当我缩小相机并且线条变小时,它们有时会出现和消失,我不明白为什么。

This is how it looks without zooming这是没有缩放的样子

在此处输入图像描述

and this is how it looks when the camera is far away from them这就是相机远离他们时的样子

在此处输入图像描述

The more far away I get from them the more artefacts appear.我离他们越远,出现的人工制品就越多。

This is how my vertex shader looks这就是我的顶点着色器的样子

#version 330 core

layout(location = 0) in vec2 _position;

out vec2 position;

uniform mat4 uCameraView;

void main() {
  gl_Position = uCameraView * vec4(_position.x, _position.y, 0.0f, 1.0f);
  position = _position;
}

And this is the fragment这是片段

#version 330 core

in vec2 position;

uniform vec4 uGridColor;
uniform float uTileSize;
uniform float uGridBorderSize;

out vec4 fragColor;

void main() {
  vec2 uv = mod(position, uTileSize);
  vec2 border = mod(uv + (uGridBorderSize / 2.0), uTileSize);
  border -= mod(uv - (uGridBorderSize / 2.0), uTileSize);

  if (length(border) > uTileSize - uGridBorderSize) {
    fragColor = uGridColor;
  } else {
    fragColor = vec4(0.0);
  }
}

Why it's this happening?为什么会这样? maybe is something related to antialiasing?也许与抗锯齿有关? My OpenGL setup it's just the default one.我的 OpenGL 设置它只是默认设置。

Your current code is making a binary decision "yes line" / "no line".您当前的代码正在做出二进制决定“是行”/“否行”。 However beyond a certain point (line width < pixel width) you're effectivly dealing with spatial frequencies above the Nyquist limit.但是,超出某个点(线宽 < 像素宽度),您正在有效地处理高于奈奎斯特极限的空间频率。

Instead of using a binary "yes"/"no" you need to calculate the pixel coverage, ie how much line is inside a pixel.您需要计算像素覆盖率,即像素内有多少行,而不是使用二进制“是”/“否”。 For that you'd normally use a unsigned distance function (UDF).为此,您通常会使用无符号距离 function (UDF)。 Here's some GLSL code for UDF lines in pixel space (you can also use them in normalized space, but then you'll have to adjust the smoothstep parameters).这是像素空间中 UDF 线的一些 GLSL 代码(您也可以在标准化空间中使用它们,但是您必须调整平滑步长参数)。 Try this on https://shadertoy.comhttps://shadertoy.com上试试这个

float lsd(vec2 a, vec2 b, vec2 p, float w){
    w *= 0.5;
    vec2  n = normalize(b-a);
    float l = length(b-a);
    float t = dot((p-a),n);
    float d = length((a-p)+t*n);
    float e = min(length(p-a)+w, length(p-b)+w);
    return (t > w && t < l-w) ? d : e;
}

float line(vec2 a, vec2 b, float width, vec2 fragcoord){
    return max(0., 1.-smoothstep(0., 1., lsd(a, b, fragcoord, width)-0.5*width));
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    float l =
          line(vec2(8.,8.), vec2(128.,33.), 1., fragCoord)
        + line(vec2(33.,220.), vec2(260.,20.), 4., fragCoord);
    fragColor = vec4(l,l,l,1.0);
}

It is hard to tell based on your shaders alone, so here is an example of how to zoom and pan around a line grid.仅根据您的着色器很难判断,所以这里有一个如何围绕线网格缩放和平移的示例。 It uses a projection matrix to zoom which looks slightly different to how you implemented the zoom, but the important bit is that it doesn't have any artefacts of lines thinning when zooming/panning.它使用投影矩阵进行缩放,看起来与您实现缩放的方式略有不同,但重要的是它在缩放/平移时没有任何线条变细的伪影。

Here is a demonstration, hopefully the GIF shows it, but the grid lines are constant thickness as you zoom in and out:这是一个演示,希望 GIF 显示它,但是当您放大和缩小时,网格线的粗细是恒定的:

#include <iostream>
#include <vector>

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/string_cast.hpp>

using std::vector;
using glm::mat4;
using glm::vec3;
using glm::vec4;

void processInput(GLFWwindow *window);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 2.0f;
bool firstMouse = true;

// timing
float deltaTime = 0.0f;
float lastFrame = 0.0f;

vec3 rayCast(double xpos, double ypos, mat4 projection, mat4 view) {
    // converts a position from the 2d xpos, ypos to a normalized 3d direction
    float x = (2.0f * xpos) / SCR_WIDTH - 1.0f;
    float y = 1.0f - (2.0f * ypos) / SCR_HEIGHT;
    float z = 1.0f;
    vec3 ray_nds = vec3(x, y, z);
    vec4 ray_clip = vec4(ray_nds.x, ray_nds.y, -1.0f, 1.0f);
    // eye space to clip we would multiply by projection so
    // clip space to eye space is the inverse projection
    vec4 ray_eye = inverse(projection) * ray_clip;
    // convert point to forwards
    ray_eye = vec4(ray_eye.x, ray_eye.y, -1.0f, 0.0f);
    // world space to eye space is usually multiply by view so
    // eye space to world space is inverse view
    vec4 inv_ray_wor = (inverse(view) * ray_eye);
    vec3 ray_wor = vec3(inv_ray_wor.x, inv_ray_wor.y, inv_ray_wor.z);
    ray_wor = normalize(ray_wor);
    return ray_wor;
}

class Line {
    int shaderProgram;
    unsigned int VBO, VAO;
    vector<float> vertices;
    vec3 startPoint;
    vec3 endPoint;
    mat4 MVP;
    vec3 lineColor;
public:
    Line(vec3 start, vec3 end) {

        startPoint = start;
        endPoint = end;
        lineColor = vec3(1,1,1);

        const char *vertexShaderSource = "#version 330 core\n"
            "layout (location = 0) in vec3 aPos;\n"
            "uniform mat4 MVP;\n"
            "void main()\n"
            "{\n"
            "   gl_Position = MVP * vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
            "}\0";
        const char *fragmentShaderSource = "#version 330 core\n"
            "out vec4 FragColor;\n"
            "uniform vec3 color;\n"
            "void main()\n"
            "{\n"
            "   FragColor = vec4(color, 1.0f);\n"
            "}\n\0";

        // vertex shader
        int vertexShader = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
        glCompileShader(vertexShader);
        // check for shader compile errors
        int success;
        char infoLog[512];
        glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
        if (!success)
        {
            glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
            std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
        }
        // fragment shader
        int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
        glCompileShader(fragmentShader);
        // check for shader compile errors
        glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
        if (!success)
        {
            glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
            std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
        }
        // link shaders
        shaderProgram = glCreateProgram();
        glAttachShader(shaderProgram, vertexShader);
        glAttachShader(shaderProgram, fragmentShader);
        glLinkProgram(shaderProgram);
        // check for linking errors
        glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
        if (!success) {
            glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
            std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
        }
        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);

        vertices = {
             start.x, start.y, start.z,
             end.x, end.y, end.z,

        };
        
        glGenVertexArrays(1, &VAO);
        glGenBuffers(1, &VBO);
        glBindVertexArray(VAO);

        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices.data(), GL_STATIC_DRAW);

        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
        glEnableVertexAttribArray(0);

        glBindBuffer(GL_ARRAY_BUFFER, 0); 
        glBindVertexArray(0); 

    }

    int setMVP(mat4 mvp) {
        MVP = mvp;
    }

    int setColor(vec3 color) {
        lineColor = color;
    }

    int draw() {
        glUseProgram(shaderProgram);
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "MVP"), 1, GL_FALSE, &MVP[0][0]);
        glUniform3fv(glGetUniformLocation(shaderProgram, "color"), 1, &lineColor[0]);

        glBindVertexArray(VAO);
        glDrawArrays(GL_LINES, 0, 2);
        return 0;
    }

    ~Line() {
        // optional: de-allocate all resources once they've outlived their purpose:
        // ------------------------------------------------------------------------
        glDeleteVertexArrays(1, &VAO);
        glDeleteBuffers(1, &VBO);
        glDeleteProgram(shaderProgram);
    }
};

vec3 cameraPos = glm::vec3(0.0f, 0.0f, 15.0f);
vec3 cameraFront = glm::vec3(0,0,-1);
mat4 model = mat4(1.0);
glm::mat4 view;
glm::mat4 projection;
float scrollSpeed = 2.0f;
float fov = 45.0f;

int main()
{

    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "grid", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetCursorPosCallback(window, mouse_callback);
    glfwSetScrollCallback(window, scroll_callback);

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    Line x(vec3(0,0,0), vec3(1,0,0));
    x.setColor(vec3(1,0,0));
    Line y(vec3(0,0,0), vec3(0,1,0));
    y.setColor(vec3(0,1,0));

    std::vector<Line*> grid = {};
    for (int i = -5; i < 6; i++) {
        grid.push_back(new Line(vec3(-5, i, 0), vec3(5,i, 0)));
    }
    for (int j = -5; j < 6; j++) {
        grid.push_back(new Line(vec3(j, -5, 0), vec3(j,5, 0)));
    };

    while (!glfwWindowShouldClose(window))
    {

        if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
            glfwSetWindowShouldClose(window, true);

        float currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;

        glClearColor(0.0, 0.0, 0.0, 1.0);
        glClear(GL_COLOR_BUFFER_BIT);

        view = glm::lookAt(cameraPos,  cameraPos + cameraFront, vec3(0,1,0));

        projection = glm::perspective(glm::radians(fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);

        for (int i = 0; i < grid.size(); i++) {
            grid[i]->setMVP(projection * view * model);
            grid[i]->draw();
        }

        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    for (int i = 0; i < grid.size(); i++) {
        delete grid.at(i);
    }
    glfwTerminate();
    return 0;
}

void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}


void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{

    if (firstMouse)
    {
        lastX = xpos;
        lastY = ypos;
        firstMouse = false;
    }

    float xoffset = xpos - lastX;
    float yoffset = lastY - ypos; 

    lastX = xpos;
    lastY = ypos;


    int state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_MIDDLE);
    if (state == GLFW_PRESS)
    {
        glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
        cameraPos -= scrollSpeed * glm::vec3(xoffset/(float)SCR_WIDTH, yoffset/(float)SCR_WIDTH, 0);

    } else {
        glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
        firstMouse = true;
    }
}

void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
    cameraPos += (float)yoffset * rayCast(lastX, lastY, projection, view);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM