Рисование грубых линий

#c #opengl

#c #opengl

Вопрос:

Я создал несколько гор и сетку-пол в стиле synthwave, используя OpenGL. Единственный эффект, создаваемый после обработки, — это небольшое размытие, но что-то не так с линиями:

Линии быстро начинают рисоваться очень плохо, когда я смотрю дальше. иногда они не рисуются или просто представляют собой фрагмент. Эти линии даже рисуются по-разному, если я поворачиваю камеру.

И чем больше я прижимаю камеру к полу, тем хуже становится:

Пример

Я попробовал несколько вещей: отключить сглаживание моего GC (NVidia), установить для каждой текстуры фильтра значение GL_LINEAR вместо GL_NEAREST, точность буфера глубины 32 бита вместо 24. Ни один из них не сработал.

Что может быть не так?

Вот код, я попытался удалить как можно больше кода

Функция инициализации:

 void initBase(int argc, char* argv[]) {

        YLogConsole::createInstance();

        glutInit(amp;argc, argv);
        glutSetOption(
            GLUT_ACTION_ON_WINDOW_CLOSE, 
            GLUT_ACTION_GLUTMAINLOOP_RETURNS
        );

        glutInitWindowSize(BaseWidth, BaseHeight);
        glutInitWindowPosition(0, 0);
        glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);

        YLog::log(YLog::ENGINE_INFO, (toString(argc)   " arguments en ligne de commande.").c_str());
        FullScreen = false;
        for (int i = 0; i<argc; i  )
        {
            if (argv[i][0] == 'f')
            {
                YLog::log(YLog::ENGINE_INFO, "Arg f mode fullscreen.n");
                FullScreen = true;
            }
        }

        MainWindowId = glutCreateWindow("Yocto");
        glutReshapeWindow(BaseWidth, BaseHeight);
        setFullScreen(FullScreen);

        if (MainWindowId < 1)
        {
            YLog::log(YLog::ENGINE_ERROR, "Erreur creation de la fenetre.");
            exit(EXIT_FAILURE);
        }

        GLenum glewInitResult = glewInit();
        if (glewInitResult != GLEW_OK)
        {
            YLog::log(YLog::ENGINE_ERROR, ("Erreur init glew "   std::string((char*)glewGetErrorString(glewInitResult))).c_str());
            exit(EXIT_FAILURE);
        }

        //Affichage des capacités du système
        YLog::log(YLog::ENGINE_INFO, ("OpenGL Version : "   std::string((char*)glGetString(GL_VERSION))).c_str());

        glutDisplayFunc(updateBase);
        glutReshapeFunc(resizeBase);
        glutKeyboardFunc(keyboardDown);
        glutKeyboardUpFunc(keyboardUp);
        glutSpecialFunc(specialDown);
        glutSpecialUpFunc(specialUp);
        glutMouseFunc(mouseClick);
        glutMotionFunc(mouseMoveActive);
        glutPassiveMotionFunc(mouseMovePassive);
        glutIgnoreKeyRepeat(1);

        //Initialisation du YRenderer
        Renderer = YRenderer::getInstance();
        Renderer->setRenderObjectFun(renderObjectsBase);
        Renderer->setRender2DFun(render2dBase);
        Renderer->setBackgroundColor(YColor());
        Renderer->initialise(amp;TimerGPURender);

        //On applique la config du YRenderer
        glViewport(0, 0, Renderer->ScreenWidth, Renderer->ScreenHeight);
        Renderer->resize(Renderer->ScreenWidth, Renderer->ScreenHeight);

        //Ecrans de jeu
        ScreenManager = new GUIScreenManager();
        uint16 x = 10;
        uint16 y = 10;
        ScreenJeu = new GUIScreen();
        ScreenStats = new GUIScreen();

        //Bouton pour afficher les params
        GUIBouton * btn = new GUIBouton();
        btn->Titre = std::string("Params");
        btn->X = x;
        btn->Y = y;
        btn->setOnClick(clickBtnParams);
        ScreenJeu->addElement(btn);

        y  = btn->Height   5;

        btn = new GUIBouton();
        btn->Titre = std::string("Stats");
        btn->X = x;
        btn->Y = y;
        btn->setOnClick(clickBtnStats);
        ScreenJeu->addElement(btn);

        y  = btn->Height   1;

        //Ecran de stats
        y = btn->Height   15;

        LblFps = new GUILabel();
        LblFps->Text = "FPS";
        LblFps->X = x;
        LblFps->Y = y;
        LblFps->Visible = true;
        ScreenStats->addElement(LblFps);

        //Ecran de parametrage
        x = 10;
        y = 10;
        ScreenParams = new GUIScreen();

        GUIBouton * btnClose = new GUIBouton();
        btnClose->Titre = std::string("Close");
        btnClose->X = x;
        btnClose->Y = y;
        btnClose->setOnClick(clickBtnClose);
        ScreenParams->addElement(btnClose);
        ScreenStats->addElement(btnClose);

        //Ecran a rendre
        ScreenManager->setActiveScreen(ScreenJeu);

        //Init YCamera
        Renderer->Camera->setPosition(YVec3f(320, 320, 320));
        Renderer->Camera->setLookAt(YVec3f(0, 0, 0));
        Renderer->Camera->setProjectionPerspective(Instance->Fov,
            (float)Instance->Renderer->ScreenWidth / (float)Instance->Renderer->ScreenHeight,
            Instance->NearPlane, Instance->FarPlane);

        //Init YTimer
        Timer = new YTimer();

        //Chargement des shaders
        Instance->loadShaders();

        //Init pour classe fille
        init();

        //On start le temps
        Timer->start();

        YLog::log(YLog::ENGINE_INFO, "[   Yocto initialized   ]nPress : n - f to toggle fullscreenn - F1 for png screen shotn - F5 to hot-reload shaders");

    }
  

Основной цикл:

 void SynthEngine::renderObjects()
{
    Renderer->updateMatricesFromOgl();
    glUseProgram(shaderWorld);
    Renderer->sendMatricesToShader(shaderWorld);
    dec->getGround()->render();
}
  

UpdateMatriceFromOgl:

 void updateMatricesFromOgl() {
            float matMvTab[16];
            glGetFloatv(GL_MODELVIEW_MATRIX, matMvTab);
            memcpy(MatMV.Mat.t, matMvTab, 16 * sizeof(float));
            MatMV.transpose();

            float matProjTab[16];
            glGetFloatv(GL_PROJECTION_MATRIX, matProjTab);
            memcpy(MatP.Mat.t, matProjTab, 16 * sizeof(float));
            MatP.transpose();

            MatMVP = MatP;
            MatMVP *= MatMV;

            MatV.createViewMatrix(Camera->Position, Camera->LookAt, Camera->UpVec);

            MatIV = MatV;
            MatIV.invert();

            MatM = MatIV;
            MatM *= MatMV;

            MatIM = MatM;
            MatIM.invert();

            MatNorm = MatM;
            MatNorm.invert();
            MatNorm.transpose();

            MatIP = MatP;
            MatIP.invert();
        }
  

The render function (VBO) , textureIndex and textureCubeIndex are always 0:

 void YVbo::render(GBuffer * inBuffer) {

//La stat globales
YRenderer::NbVBOFacesRendered  = NbVertices / 3;

if (textureIndex)
{
    glBindTexture(GL_TEXTURE_2D, textureIndex);
}

if (textureCubeIndex)
{
    glBindTexture(GL_TEXTURE_CUBE_MAP, textureCubeIndex);
}

glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);

for (int i = 0; i<NbElements; i  )
    glEnableVertexAttribArray(i);

if (StorageMethod == PACK_BY_ELEMENT_TYPE) {
    for (int i = 0; i<NbElements; i  )
        glVertexAttribPointer(i, Elements[i].NbFloats, GL_FLOAT, GL_FALSE, 0, (void*)(Elements[i].OffsetFloats * sizeof(float)));
} else {
    for (int i = 0; i<NbElements; i  )
        glVertexAttribPointer(i, Elements[i].NbFloats, GL_FLOAT, GL_FALSE, TotalNbFloatForOneVertice * sizeof(float), (void*)(Elements[i].OffsetFloats * sizeof(float)));
}

YEngine::Instance->TimerGPURender.startAccumPeriod();
glDrawArrays(GL_TRIANGLES, 0, NbVertices);
YEngine::Instance->TimerGPURender.endAccumPeriod();

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
  

}

vertex shader of ShaderWorld :

 #version 400

uniform mat4 mvp;
uniform float elapsed;

layout(location = 0) in vec3 position_in;
layout(location = 1) in vec4 color_border_in;
layout(location = 2) in vec4 color_fill_in;

out VertexAttrib
{
vec4 colorFill;
vec4 colorBorder;
} vertex;

void main()
{
gl_Position = mvp * vec4(position_in, 1);
vertex.colorBorder = color_border_in;
vertex.colorFill = color_fill_in;
}
  

геометрический шейдер

     #version 400

out vec4 color_border;
out vec4 color_fill;
out vec3 bary;

in VertexAttrib
{
    vec4 colorFill;
    vec4 colorBorder;
} vertex[];

layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;

void main()
{
    for (int i = 0; i < 3; i  )
    {
        color_border = vertex[i].colorBorder;
        color_fill = vertex[i].colorFill;
        gl_Position = gl_in[i].gl_Position;

        if (i == 0)
            bary = vec3(0, 0, 1);
        if (i == 1)
            bary = vec3(0, 1, 0);
        if (i == 2)
            bary = vec3(1, 0, 0);

        EmitVertex();
    }
    EndPrimitive();
}
  

шейдер фрагментов :

 #version 400

in vec4 color_border;
in vec4 color_fill;
in vec3 bary;

layout (location = 0) out vec4 color;
layout (location = 1) out vec4 passColor;

float toleranceLight = 0.7;

void main()
{
    vec4 interColor;
    if ((bary.x) < 0.01 || (bary.y) < 0.01 || ((bary.z) < 0.01 amp;amp; color_border.r == 0))
    {
        interColor = color_border;
    }
    else
    {
        interColor = color_fill;
    }

    if (max(interColor.r,max(interColor.g, interColor.b)) > toleranceLight)
    {
        passColor = interColor;
    }
    else
    {
        passColor = vec4(0,0,0,1);
    }
    color = interColor;
}
  

Комментарии:

1. Показанные вами шейдеры не используют никаких текстур, так почему filter texture to GL_LINEAR instead of GL_NEAREST это должно иметь отношение к вашей проблеме?

2. Где именно вы отображаете сетку, как вы определяете, отображается цвет сетки или нет?

3. Хорошо, теперь я понял, каждая ячейка сетки представляет собой группу из 2 треугольников и bary используется для окрашивания границ каждой ячейки. Но вам не следует выполнять двоичную раскраску, вместо этого вам нужно добавить градиент к границе. В текущей форме ваш фрагментный шейдер аналогичен тому, что произошло бы, если бы у вас был GL_NEAREST для текстур.

4. » отключить сглаживание изображений » — это противоположность устранению проблемы.

5. @NicolBolas я пробовал включать и отключать, это ничего не изменило. Я забыл упомянуть, но там вообще нет текстуры, только цвета

Ответ №1:

Ваша основная проблема здесь заключается в интерполяции перспективы в vec3 bary и ее логической природе, вызывающей артефакты по краям color_border и color_fill . Рассмотрим своего рода интерполяцию между цветом края и заливки на основе интерполяции bary.

В качестве альтернативы вы можете рассмотреть возможность отображения текстуры маски, указывающей границы или заливку. Вам нужно убедиться, что вы создаете mipmaps и используете его во время выполнения с анизотропным фильтром.

Отдельно отметим, что в этом случае вам вообще не нужен геометрический шейдер. Просто используйте gl_VertexID % 3 непосредственно из вершинного шейдера и выводите оттуда bary.

Комментарии:

1. Хорошо, я решил свою проблему, я установил min_filter в GL_NEAREST_MIPMAP_LINEAR вместо GL_LINEAR для текстуры. Спасибо