如何避免使用着色器在 OpenGL 中消失线?
Posted
技术标签:
【中文标题】如何避免使用着色器在 OpenGL 中消失线?【英文标题】:How I can avoid in OpenGL disappearing lines using a shader? 【发布时间】:2021-01-12 23:04:21 【问题描述】:所以我只使用片段着色器来绘制一些线条。顶点只是一个空的四边形。
我遇到的问题是,当我缩小相机并且线条变小时,它们有时会出现又消失,我不明白为什么。
这是不缩放的样子
这就是相机远离他们时的样子
我离他们越远,出现的人工制品就越多。
这就是我的顶点着色器的样子
#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;
这是片段
#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);
为什么会这样?也许与抗锯齿有关?我的 OpenGL 设置只是默认设置。
【问题讨论】:
你想要的是某种抗锯齿。 我该怎么做? 我们可以看一下C++代码吗?乍一看有点难以分辨,但使用完整的代码库可能会更清楚。 我敢打赌,你现在需要有恒定的线宽(不管缩放)你在取消缩放时遇到问题,线将小于像素粗,这有时会由于锯齿效应导致不可见的线条(可见和不可见是位置的函数)。你的图像显示你的线条有 +/-1 不同的粗细,它是一样的......将它应用到你的支票上......这是有问题的,因为我们不知道什么变量是什么以及具有什么值,范围等。您还应该以像素为单位传递视图分辨率,因为这将需要... 线条消失的原因是它们变得小于一个像素。在这种情况下你希望发生什么?通常有两种方法来解决这个问题:1)不允许线条粗细小于 1 像素,2)如果线条比背景颜色细 1 像素 lerp。所以在你的情况下,当线条变得小于 1 像素时,会变成灰色 【参考方案1】:您当前的代码正在做出“是行”/“否行”的二元决定。但是,超出某个点(线宽
您需要计算像素覆盖率,即像素内有多少行,而不是使用二进制“是”/“否”。为此,您通常会使用无符号距离函数 (UDF)。这是像素空间中 UDF 线的一些 GLSL 代码(您也可以在标准化空间中使用它们,但是您必须调整平滑步长参数)。试试这个https://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);
【讨论】:
【参考方案2】:仅根据您的着色器很难判断,因此这里有一个如何围绕线网格进行缩放和平移的示例。它使用投影矩阵进行缩放,看起来与您实现缩放的方式略有不同,但重要的是它在缩放/平移时没有任何线条变细的伪影。
这是一个演示,希望 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);
【讨论】:
以上是关于如何避免使用着色器在 OpenGL 中消失线?的主要内容,如果未能解决你的问题,请参考以下文章