سؤال

أنا أقرأ حاليا من نسيج عمق في عمق PostProcess من Shader الحقل باستخدام رمز GLSL التالي:

vec4 depthSample = texture2D(sDepthTexture, tcScreen);
float depth = depthSample.x * 255.0 / 256.0 +
              depthSample.y * 255.0 / 65536.0 +
              depthSample.z * 255.0 / 16777216.0;

ثم تحويل قيمة العمق إلى مسافة عرض المسافة بناء على مسافات الطائرة القريبة والمسيرة:

float zDistance = (zNear * zFar) / (zFar - depth * (zFar - zNear));

يبدو أن كل ذلك يعمل بشكل جيد إلى حد ما، ولكنني مهتم بمعرفة كيفية القيام بالحساب المذكور أعلاه فقط على مصفوفة الإسقاط الحالية دون الحاجة إلى منفصلة zNear و zFar القيم.

بلدي المحاولة الأولية تضرب (vec4(tcscreen.x, tcScreen.y, depth, 1.0) * 2.0 - 1.0) من قبل عكس مصفوفة الإسقاط، تقسم النتيجة من خلال w, ، ثم أخذ الناتجة z القيمة كمسافة، ولكن هذا لا يبدو أن هذا يعمل. ما هو النهج الصحيح هنا؟

أيضا، عند استخدام قصبة الأصدقاء المائل لتحويل الطائرة القريبة على متن طائرة لقطة مختارة هي المسافة القريبة من الطائرة الآن يحتمل أن تكون مختلفة لكل بكسل؟ وإذا كان الأمر كذلك، فهل هذا يعني أن أي تظليل يحسب مسافة من نسيج عمق بحاجة إلى أن تكون على دراية بهذه العلبة ولا تفترض مسافة قريبة من الطائرة؟

شكرا!

هل كانت مفيدة؟

المحلول

اتضح أنني نسيت نفي قيمة Z النهائية للحصول على مسافة إيجابية أمام الطائرة القريبة (تنظر كاميرا OpenGL إلى أسفل). مرجع في المستقبل رمز GLSL للحصول على المسافة أمام الطائرة القريبة هو:

float depth = /* sampled from depth texture as in the original question */ ;

vec4 screenPos = vec4(tcScreen.x, tcScreen.y, depth, 1.0) * 2.0 - 1.0;
vec4 viewPosition = projectionMatrixInverse * screenPos;

float z = -(viewPosition.z / viewPosition.w);

إذا كنت ترغب في وضع مساحة عالمية بدلا من ذلك (مثل SuperPro يستخدم)، فيمكن العثور عليه من خلال الجمع بين مصفوفات العرض والاستباطات ثم باستخدام عكس تلك المصفوفة بدلا من استخدام مصفوفة الإسقاط العكسية.

لأن مكونات Z و W من viewPosition هناك حاجة إلى GLSL أعلاه للحوسبة viewPosition يمكن تبسيطها إلى حد ما. سوف تكفي منتجات DOT بدلا من مضاعفة مصفوفة كاملة، وليس هناك حاجة لإطعام مصفوفة الإسقاط العكسية الكاملة في التظليل حيث هناك حاجة إلى صفين أسفل فقط:

vec2 viewPositionZW = vec2(
    dot(projectionMatrixInverseRow2, screenPos),
    dot(projectionMatrixInverseRow3, screenPos)
);

float z = -(viewPositionZW.x / viewPositionZW.y);

أداء ذلك هو أسوأ من استخدام المسافات القريبة والمتباعدة، بسبب منتجات النقطة الإضافية، وحصلت على تخفيض ~ 5٪. يمكن أيضا تحسين الرياضيات القريبة والعد البعيدة عن طريق التغذية (zNear * zFar) و (zFar - zNear) في الثوابت، لكنني لم أر أي تحسن قابل للقياس من خلال القيام بذلك.

ومن المثير للاهتمام، عندما تجمع بين ما سبق مع مصفوفة الإسقاط يستخدم لقطة الأصدقاء المائلة، لا أستطيع الحصول على أي شيء معقول منه، لكنني أحصل على إخراج معقول عند استخدام معادلة المسافة القريبة والبعيدة مع نفس مصفوفة الإسقاط، وإن كان ذلك ما يبدو أنه بعض التشويه لقيم العمق (على الرغم من أن هذا قد يكون فقط بسبب فقدان العمق الدقة المتأصلة في لقطة الذوبان المائلة). إذا كان أي شخص يستطيع إلقاء بعض الضوء على ما يدور بالضبط هنا، فأنا أقدر ذلك، على الرغم من أنه يجب أن يكون ذلك في سؤال مختلف.

نصائح أخرى

يمكنني استخدام التعليمات البرمجية التالية في Shader Lightning، من أجل حساب اتجاه البرق. يتم احتساب وضع Wold أيضا عن طريق ضرب موضع الشاشة مع عكس مصفوفة الإسقاط.

لسوء الحظ HLSL:

float depth = tex2D(DepthMapSampler, PSIn.TexCoord).r;

float4 screenPos;
screenPos.x = PSIn.TexCoord.x*2.0f-1.0f;
screenPos.y = -(PSIn.TexCoord.y*2.0f-1.0f);
screenPos.z = depth;
screenPos.w = 1.0f; 

float4 worldPos = mul(screenPos, xViewProjectionInv);
worldPos /= worldPos.w;

يعمل بشكل جيد، لذلك أفترض أن الانتظار صحيح!

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top