Случайные отсутствующие полигоны, рисующие небесную сферу (в дальней плоскости)

Я рисую небесную сферу в качестве фона для 3D-вида. Иногда при навигации по представлению возникает визуальный сбой, который появляется:

Черный или отсутствующий многоугольник посреди голубого неба

Пример сбоя: черная фигура, фрагменты которой при рендеринге явно не отображаются на экране

  • Черный — это цвет, на который устройство очищается в начале каждого кадра.
  • Форма черной области каждый раз разная, и иногда видно много полигонов. Они всегда сосредоточены вокруг общей точки, обычно близкой к центру экрана.
  • Перерисовка без изменения навигации (положения глаз и взгляда) не устраняет глюк, т. е. похоже, что он зависит от конкретной навигации.
  • В тот момент, когда навигация изменяется, пусть даже незначительно, она исчезает, и небо рисуется целиком. Подавляющее большинство рисунков правильно. В конце концов, когда вы будете двигаться, вы заметите еще один глюк.
  • Изменение радиуса сферы (например, до 0,9 расстояния в ближней/дальней плоскости), похоже, не устраняет сбои.
  • Изменение записи Z-буфера или теста Z в технике эффекта не имеет значения
  • Выходные данные отладки DX отсутствуют (при работе с отладочной версией среды выполнения, максимальной проверкой и включенной отладкой шейдеров).

В чем может быть причина этих глюков?

Я использую Direct3D9 (июнь 2010 SDK), шейдеры, скомпилированные в SM3, и сбой наблюдался на картах ATI и виртуальных картах VMWare Fusion в Windows 7 и XP.

Пример кода

Небо рисуется как сфера (проверка ошибок и т. д. удалена из приведенного ниже кода):

Чтобы создать

const float fRadius = GetScene().GetFarPlane() - GetScene().GetNearPlane()*2;
D3DXCreateSphere(GetScene().GetDevicePtr(), fRadius, 64, 64, &m_poSphere, 0);

Изменение радиуса, похоже, не влияет на наличие глюков.

Вершинный шейдер

OutputVS ColorVS(float3 posL : POSITION0, float4 c : COLOR0) {
   OutputVS outVS = (OutputVS)0;
   // Center around the eye
   posL += g_vecEyePos; 
   // Transform to homogeneous clip space.
   outVS.posH = mul(float4(posL, 1.0f), g_mWorldViewProj).xyzw; // Always on the far plane

Пиксельный шейдер

Не имеет значения, даже тот, который выводит сплошной цвет, будет глючить:

float4 ColorPS(float altitude : COLOR0) : COLOR {
   return float4(1.0, 0.0, 0.0, 1.0);

То же изображение с однотонным пиксельным шейдером

То же изображение со сплошным пиксельным шейдером, чтобы убедиться, что PS не является причиной проблемы

Техника

technique BackgroundTech {
    pass P0     {
        // Specify the vertex and pixel shader associated with this pass.
        vertexShader = compile vs_3_0 ColorVS();
        pixelShader  = compile ps_3_0 ColorPS();

        // sky is visible from inside - cull mode is inverted (clockwise)
        CullMode = CW;
    }
}

Я попытался добавить в настройки состояния, влияющие на глубину, такие как ZWriteEnabled = false. Ничто не имело никакого значения.


person David    schedule 16.08.2012    source источник
comment
Похоже, это вызвано вашей дальней плоскостью отсечения. Какова его текущая стоимость? Меняй и смотри.   -  person Ani    schedule 16.08.2012
comment
Текущее значение ближних/дальних плоскостей составляет 1-5000. Если я немного изменю дальний план (например, 5050), разницы нет. Много (20 000, но с сохранением радиуса сферы 5 000) это так: но я не хочу оставлять это так, поскольку это приведет к огромной потере точности для видимых объектов. Радиус сферы в любом случае определенно меньше, чем расстояние отсечения... так почему это должно влиять на него?   -  person David    schedule 16.08.2012
comment
Итак, это и есть дальняя плоскость отсечения, теперь мы это знаем. :) Теперь вы держите небесную сферу на постоянном расстоянии от камеры? Что это за расстояние?   -  person Ani    schedule 16.08.2012
comment
outVS.posH = mul(float4(posL, 1.0f), g_mWorldViewProj).xyzw; // Всегда на дальнем плане ‹- эта линия кажется мне подозрительной   -  person Ani    schedule 17.08.2012
comment
Что подозрительного в этой строке? Расстояние заключается в том, что оно переводится как центр вокруг камеры и имеет фиксированный радиус.   -  person David    schedule 20.08.2012
comment
@ananthonline: Кроме того, изменение его радиуса на 0,5 ближнего/дальнего расстояния по-прежнему создает артефакты. Это хорошо в пределах расстояния, которое должно правильно рисовать.   -  person David    schedule 21.08.2012


Ответы (1)


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

Убедитесь, что вы правильно инициализируете константу g_vecEyePos (может быть, вы неправильно написали ее в одной из функций DirectX SetShaderConstant?).

Кроме того, если вы включили перевод положения глаза в мировую матрицу g_mWorldViewProj, вы не должны делать posL += g_vecEyePos; в своей VS, потому что это приводит к перемещению вершины в два раза по положению глаза.

Другими словами, вы должны выбрать один из следующих вариантов:

  1. g_mWorldViewProj = mCamView * mCamProj; и posL += g_vecEyePos;

  2. g_mWorldViewProj = MatrixTranslation(g_vecEyePos) * mCamView * mCamProj;

person miloszmaki    schedule 21.08.2012
comment
Кстати, я думаю, что радиус сферы должен быть const float fRadius = GetScene().GetFarPlane();, это расстояние от глаза до дальней плоскости. - person miloszmaki; 22.08.2012
comment
Ни один из них не сработал, то есть оба привели к черному фону без видимых полигонов. Я "решил" это, добавив строку outVS.posH.w *= 1.01; - мне это кажется очень подозрительным, но это работает. - person David; 10.09.2012