Я только начал с тесселяции OpenGL и столкнулся с небольшой проблемой. Я тестирую серию патчей, образованных одной вершиной каждая. Эти вершины / участки структурированы в виде сетки, чтобы впоследствии сформировать ландшафт, генерируемый Perlin Noise.
Проблема, с которой я столкнулся, заключается в том, что начиная со второго патча, и каждые 5го После этого патча иногда бывает много тесселяции (не так, как я настроил), но большую часть времени она вообще не получает тесселяцию.
Два белых кружка обозначают сильно / над мозаичными пятнами. Также обратите внимание на шаблон нецелевых патчей.
Странно то, что он работает на моем Surface Pro 2 (графика Intel HD4400), но на моем главном настольном компьютере (на графике AMD HD6950) возникают ошибки. Возможно ли плохое оборудование?
vec4* patches = new vec4[m_patchesWidth * m_patchesDepth];
int c = 0;
for (unsigned int z = 0; z < m_patchesDepth; ++z) {
for (unsigned int x = 0; x < m_patchesWidth; ++x) {
patches[c] = vec4(x * 1.5f, 0, z * 1.5f, 1.0f);
c++;
}
}
m_fxTerrain->Apply();
glGenBuffers(1, &m_planePatches);
glBindBuffer(GL_ARRAY_BUFFER, m_planePatches);
glBufferData(GL_ARRAY_BUFFER, m_patchesWidth * m_patchesDepth * sizeof(vec4), patches, GL_STATIC_DRAW);
GLuint loc = m_fxTerrain->GetAttrib("posIn");
glEnableVertexAttribArray(loc);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vec4), nullptr);
delete(patches);
glPatchParameteri(GL_PATCH_VERTICES, 1);
glBindVertexArray(patches);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDrawArrays(GL_PATCHES, 0, nrOfPatches);
#version 430 core
in vec4 posIn;
out gl_PerVertex {
vec4 gl_Position;
};
void main() {
gl_Position = posIn;
}
#version 430
#extension GL_ARB_tessellation_shader : enable
layout (vertices = 1) out;
uniform float OuterTessFactor;
uniform float InnerTessFactor;
out gl_PerVertex {
vec4 gl_Position;
} gl_out[];
void main() {
if (gl_InvocationID == 0) {
gl_TessLevelOuter[0] = OuterTessFactor;
gl_TessLevelOuter[1] = OuterTessFactor;
gl_TessLevelOuter[2] = OuterTessFactor;
gl_TessLevelOuter[3] = OuterTessFactor;
gl_TessLevelInner[0] = InnerTessFactor;
gl_TessLevelInner[1] = InnerTessFactor;
}
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
#version 430
#extension GL_ARB_tessellation_shader : enable
layout (quads, equal_spacing, ccw) in;
uniform mat4 ProjView;
uniform sampler2D PerlinNoise;
out vec3 PosW;
out vec3 Normal;
out vec4 ColorFrag;
out gl_PerVertex {
vec4 gl_Position;
};
void main() {
vec4 pos = gl_in[0].gl_Position;
pos.xz += gl_TessCoord.xy;
pos.y = texture2D(PerlinNoise, pos.xz / vec2(8, 8)).x * 10.0f - 10.0f;
Normal = vec3(0, 1, 0);
gl_Position = ProjView * pos;
PosW = pos.xyz;
ColorFrag = vec4(pos.x / 64.0f, 0.0f, pos.z / 64.0f, 1.0f);
}
#version 430 core
in vec3 PosW;
in vec3 Normal;
in vec4 ColorFrag;
in vec4 PosH;
out vec3 FragColor;
out vec3 FragNormal;
void main() {
FragNormal = Normal;
FragColor = ColorFrag.xyz;
}
Я пытался жестко закодировать различные уровни тесселяции, но это не помогло. Я недавно начал с OpenGL, поэтому, пожалуйста, дайте мне знать, если я делаю что-то глупое.
Так кто-нибудь имеет какие-либо идеи, что может быть причиной «мерцания» определенных участков?
Обновить: У меня был друг, управляющий проектом, и он получил ту же самую картину мерцания тесселяции, но провальные патчи не были нарисованы вообще, за исключением случаев чрезмерной тесселяции. У него та же видеокарта, что и у меня (AMD HD6950).
Вы должны использовать тесселяцию треугольника / квадрата, в которой каждый патч имеет 3 или 4 вершины. Как я вижу, вы используете квады (я тоже их использую). В этом случае вы можете установить его так:
glPatchParameteri(GL_PATCH_VERTICES,4);
glBindVertexArray(VertexArray);
(СОВЕТ: используйте драументы для вашей местности, гораздо лучшую производительность для сетки на основе 2D-смещения.)
В контрольном шейдере используйте
layout (vertices = 4) out;
так как ваш патч имеет 4 контрольных точки. Порядок все еще важен (CCW / CW).
Лично я не люблю использовать встроенные переменные, поэтому для вершинного шейдера вы можете отправить свои данные вершины в tesscontrol следующим образом:
layout (location = 0) out vec3 outPos;
....
outPos.xz = grid.xy;
outPos.y = noise(outPos.xz);
Тесс контроль:
layout (location = 0) in vec3 inPos[]; //outPos (location = 0) from vertex shader
//'collects' the 4 control points to an array in the order they're sended
layout (location = 0) out vec3 outPos[]; //send the c.points to the ev. shader
...
gl_TessLevelOuter[0] = outt[0];
gl_TessLevelOuter[1] = outt[1];
gl_TessLevelOuter[2] = outt[2];
gl_TessLevelOuter[3] = outt[3];
gl_TessLevelInner[0] = inn[0];
gl_TessLevelInner[1] = inn[1];
outPos[ID] = inPos[ID];//gl_invocationID = ID
Обратите внимание, что как входные, так и исходящие данные вершин являются массивом.
Тессев прост:
layout (location = 0) in vec3 inPos[]; //the 4 control points
layout (location = 0) out vec3 outPos; //this is no longer array, next is the fragment shader
...
//edit: do not forgot to add the next line
layout (quads) in;
vec3 interpolate3D(vec3 v0, vec3 v1, vec3 v2, vec3 v3) //linear interpolation for x,y,z coords on the quad
{
return mix(mix(v0,v1,gl_TessCoord.x),mix(v3,v2,gl_TessCoord.x),gl_TessCoord.y);
};
...main{...
outPos = interpolate3D(inPos[0],inPos[1],inPos[2],inPos[3]); //the four control points of the quad. Every other point is linearly interpolated between them according to the TessCoord.
gl_Position = mvp * vec4(outPos,1.0f);
Хорошее представление четырехъядерного домена: http://ogldev.atspace.co.uk/www/tutorial30/tutorial30.html.
Я думаю, что проблема с вашим вершинным патчем. Я не могу представить, как один вершинный путь можно разделить на треугольники, я не знаю, как он работает на другом оборудовании. Тесселяция предназначена для разделения примитивов на другие простые примитивы на треугольники в случае OGL, поскольку с ними можно легко справиться с помощью графического процессора (3 точки всегда лежат в плоскости). Таким образом, минимальное количество вершин патча должно быть 3 для треугольника. Мне нравятся четырехугольники, потому что их проще индексировать, а стоимость памяти меньше. Он также будет разделен на треугольники во время тесселяции. http://www.informit.com/articles/article.aspx?p=2120983
Кроме того, есть другой тип, тесселяция изолинии. (проверьте ссылки, второе довольно хорошо.)
В общем, попробуйте это с квадратами или треугольниками, и установите контрольные вершины в 4 (или 3). Мой (довольно сложный) шейдер рельефа здесь с отбраковкой усеченного конуса, тесселяционным отбрасыванием шейдера для ландшафта на основе геоклипмапа. Кроме того, без тесселяции он работает с морфой вершины в вершинном шейдере. Может быть, какая-то часть этого кода будет полезна. http://speedy.sh/TAvPR/gshader.txt
Сцена с тесселяцией со скоростью около 4 пикселей / треугольник работает со скоростью 75 кадров в секунду (с кадрами) с нормальным вычислением во время выполнения и бикубическим сглаживанием и другими вещами. Я использую AMD HD 5750. Он все еще может быть намного быстрее с лучшим кодом и предварительно запеченными нормалями: D. (работает до 120 без нормального расчета.)
Да, и вы можете отправлять координаты x и z, только если вы смещаете вершину в шейдере. Это тоже будет быстрее.
Много вершин.
Других решений пока нет …