#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 для текстуры. Спасибо