Рисование валовой линии - PullRequest
0 голосов
/ 04 марта 2019

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

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

И чем хуже я прижимаю камеру к полу:

An example

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

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

Вот код, я пытался удалить столько кода, сколько мог

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

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

        YLogConsole::createInstance();

        glutInit(&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(&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 fullscreen\n - F1 for png screen shot\n - 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();
        }

Функция рендеринга (VBO), textureIndex и textureCubeIndex всегда равны 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);

}

вершинный шейдер 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 && 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 Ответ

0 голосов
/ 04 марта 2019

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...