Странное поведение функции HLSL pow() с использованием DirectX 11
Я программирую шейдерный корпус DX11 SM5.0 по многим примерам, таким как Фрэнк Луна. Исследуя причину сумасшедшего мерцания (каркасного) ландшафта, я выяснил, что, по-видимому, является проблемой с функцией pow().
Мой код для расчета факторов тесселяции:
float CalcTessFactor(float3 p)
{
float d = distance(p, cameraPosition);
float s = saturate((d - 1000.0f) / (5000.0f - 1000.0f));
//return pow(2, (lerp(6, 1, s)));
return saturate((5000.0f - d) / 5000.0f)*64.0f;
}
Жестко запрограммированные числовые константы являются частью моего сокращения отладки. Закомментированная строка: "//return pow(...") - это исходный код, который я заменил следующей строкой.
С этой заменой тесселяция полностью стабильна и уменьшается с расстоянием от камеры. Как и ожидалось, уменьшение является только линейным, а не логарифмическим, но, по крайней мере, оно работает, хорошо сочетается и не имеет признаков мерцания.
В исходном коде сетка, по-видимому, переключалась с частотой кадров между, по-видимому, случайными факторами тесселяции.
Кто-нибудь может подсказать, что может пойти не так?
Моя постоянная функция патча:
struct HullInputType
{
float3 position : POSITION;
float4 color : COLOR;
};
struct ConstantOutputType
{
float edges[4] : SV_TessFactor;
float inside[2] : SV_InsideTessFactor;
};
ConstantOutputType TerrainPatchConstantFunction(InputPatch<HullInputType, 4> patch, uint patchId : SV_PrimitiveID)
{
ConstantOutputType output;
// Compute midpoint on edges, and patch center
// order of vertices is: 0 1
// 2 3
float3 e0 = 0.5f*(patch[0].position + patch[2].position);
float3 e1 = 0.5f*(patch[0].position + patch[1].position);
float3 e2 = 0.5f*(patch[1].position + patch[3].position);
float3 e3 = 0.5f*(patch[2].position + patch[3].position);
float3 c = 0.25f*(patch[0].position + patch[1].position + patch[2].position + patch[3].position);
// Set the tessellation factors for the four edges of the quad.
output.edges[0] = CalcTessFactor(e0);
output.edges[1] = CalcTessFactor(e1);
output.edges[2] = CalcTessFactor(e2);
output.edges[3] = CalcTessFactor(e3);
// Set the tessellation factor for tessallating inside the quad.
output.inside[0] = CalcTessFactor(c);
output.inside[1] = output.inside[0];
return output;
}
1 ответ
Глядя на ваше возвращаемое значение. Похоже, ты делаешь тесселяцию задом наперед. Раскомментируйте цену кода. Жестко закодируйте значение расстояния, скажем, 1000. Вы должны получить последовательное тесселяцию. Если вы это сделаете, то не должны мерцать. Если вы этого не сделаете, то это что-то с степенной функцией, как вы утверждаете, или нет, тогда ваши векторы расстояния являются фанки.
Изменить: Добавлена моя функция тесселяции для справки.
struct VertexOut
{
float4 PosW : POSITION0;
float4 waterAttributes : POSITION2;
float4 direction : POSITION1;
// float4 wind : POSITION2;
float tessFactor : TESS;
};
//========================================================================================================================
[domain("tri")]
[partitioning("integer")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(3)]
[patchconstantfunc("PatchHS")]
HullOut HSMain(InputPatch<VertexOut, 3> p,
uint i : SV_OutputControlPointID,
uint patchId : SV_PrimitiveID)
{
HullOut hout;
// Pass through shader.
hout.PosW = p[i].PosW;
hout.direction = p[i].direction;
hout.waterAttributes = p[i].waterAttributes;
// hout.wind = p[i].wind;
return hout;
}
PatchTess PatchHS(InputPatch<VertexOut, 3> patch,
uint patchID : SV_PrimitiveID)
{
PatchTess pt;
// Average tess factors along edges, and pick an edge tess factor for
// the interior tessellation. It is important to do the tess factor
// calculation based on the edge properties so that edges shared by
// more than one triangle will have the same tessellation factor.
// Otherwise, gaps can appear.
pt.EdgeTess[0] = 0.5f * (patch[1].tessFactor + patch[2].tessFactor);
pt.EdgeTess[1] = 0.5f * (patch[2].tessFactor + patch[0].tessFactor);
pt.EdgeTess[2] = 0.5f * (patch[0].tessFactor + patch[1].tessFactor);
pt.InsideTess = pt.EdgeTess[0];
return pt;
}