سؤال

أحاول أن ألف رأسي حول التظليلات في GLSL ، وقد وجدت بعض الموارد والبرامج التعليمية المفيدة ، لكني أستمر في الركض في جدار لشيء يجب أن يكون أساسيًا وتافليًا: كيف يسترجع شظايا بلدي لون لون الشظية الحالية؟

قمت بتعيين اللون النهائي بالقول gl_FragColor = whatever, ، ولكن على ما يبدو هذه قيمة الإخراج فقط. كيف تحصل على اللون الأصلي للمدخلات حتى تتمكن من إجراء العمليات الحسابية عليه؟ يجب أن يكون ذلك في متغير في مكان ما ، ولكن إذا كان هناك أي شخص يعرف اسمه ، فلا يبدو أنه سجله في أي برنامج تعليمي أو وثائق أركضتها حتى الآن ، وهي تقودني إلى أعلى الحائط.

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

المحلول

يتلقى تظليل الشظية gl_Color و gl_SecondaryColor كما سمات قمة الرأس. كما يحصل على أربعة متغيرات مختلفة: gl_FrontColor, gl_FrontSecondaryColor, gl_BackColor, ، و gl_BackSecondaryColor أنه يمكن أن يكتب القيم ل. إذا كنت ترغب في تمرير الألوان الأصلية مباشرة ، فستفعل شيئًا مثل:

gl_FrontColor = gl_Color;
gl_FrontSecondaryColor = gl_SecondaryColor;
gl_BackColor = gl_Color;
gl_BackSecondaryColor = gl_SecondaryColor;

تعمل الوظائف الثابتة في خط الأنابيب بعد قمة التظليل بعد ذلك إلى وضعها على النطاق [0..1] ، واكتشف ما إذا كان القمة مواجهة أماميًا أم لا. بعد ذلك سوف يتنازل عن اللون المختار (الأمامي أو الخلف) كالمعتاد. سيتلقى تظليل الشظية بعد ذلك الألوان المختارة والمثبتة والتحريف gl_Color و gl_SecondaryColor.

على سبيل المثال ، إذا رسمت "مثلث الموت" القياسي مثل:

glBegin(GL_TRIANGLES);
    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f(-1.0f, 0.0f, -1.0f);
    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f(1.0f, 0.0f, -1.0f);
    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex3d(0.0, -1.0, -1.0);
glEnd();

ثم تظليل قمة الرأس مثل هذا:

void main(void) {
    gl_Position = ftransform();
    gl_FrontColor = gl_Color;
}

مع تظليل جزء مثل هذا:

void main() {
    gl_FragColor = gl_Color;
}

سوف تنقل الألوان من خلال ، تمامًا كما لو كنت تستخدم خط أنابيب الوظائف الثابتة.

نصائح أخرى

إذا كنت ترغب في القيام بتقديم متعدد التمريرات ، أي إذا كنت قد قدمت إلى FrameBuffer وترغب في الحصول على تمريرة عرض ثانية حيث تستخدم العرض السابق من الإجابة هو:

  1. تقديم التمريرة الأولى إلى نسيج
  2. ربط هذا الملمس للممر الثاني
  3. الوصول إلى البيكسل المقدم بشكل خاص في التظليل

رمز التظليل لـ 3.2:

uniform sampler2D mytex; // texture with the previous render pass

layout(pixel_center_integer) in vec4 gl_FragCoord;
// will give the screen position of the current fragment

void main()
{
  // convert fragment position to integers
  ivec2 screenpos = ivec2(gl_FragCoord.xy);
  // look up result from previous render pass in the texture
  vec4 color = texelFetch(mytex, screenpos, 0);
  // now use the value from the previous render pass ...
}

طرق أخرى لمعالجة الصورة المقدمة ستكون opencl مع OpenGL -> opencl interop. هذا يسمح لمزيد من وحدة المعالجة المركزية مثل الحساب.

إذا كان ما تسميه "القيمة الحالية للشظية" هو قيمة لون البكسل التي كانت في هدف العرض قبل تشغيل تظليل الشظية ، فلا يكون ذلك غير متوفر.

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

تحتاج إلى أخذ عينات من الإحداثيات الحالية للبكسل ، شيء من هذا القبيل

vec4 pixel_color = texture2D(tex, gl_TexCoord[0].xy);

ملاحظة ، - كما رأيت texture2d يتم إهمالها في مواصفات GLSL 4.00 - فقط ابحث عن نسيج مماثل ... جلب وظائف.

في بعض الأحيان ، من الأفضل أيضًا توفير إحداثيات بكسل الخاصة بك بدلاً من gl_texcoord [0] .xy - في هذه الحالة اكتب تظليل قمة الرأس شيء مثل:

varying vec2 texCoord;

void main(void)
{
   gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0 );
   texCoord = 0.5 * gl_Position.xy + vec2(0.5);     
}

وفي تظليل الشظايا ، استخدم متغير Texcoord بدلاً من gl_texcoord [0] .xy.

حظا طيبا وفقك الله.

النقطة الكاملة من تظليل الجزء الخاص بك هي تحديد لون الإخراج. كيف تفعل ذلك يعتمد على ما تحاول القيام به.

قد تختار إعداد الأشياء بحيث تحصل على لون محرف استنادًا إلى إخراج تظليل الرأس ، ولكن النهج الأكثر شيوعًا هو إجراء بحث ملمس في تظليل الشظايا باستخدام إحداثيات الملمس التي تم تمريرها في العوامل المتشابكة من قمة الرأس . يمكنك بعد ذلك تعديل نتيجة بحثك الملمس وفقًا لحسابات الإضاءة التي اخترتها وأي شيء آخر يُقصد به تظليلك القيام به ثم كتابته في GL_FragColor.

يحتوي خط أنابيب GPU على إمكانية الوصول إلى معلومات البكسل الأساسية على الفور بعد، بعدما تشغيل التظليل. إذا كانت المواد الخاصة بك شفافة ، فستجمع مرحلة مزج خط الأنابيب بين جميع الأجزاء.

بشكل عام ، يتم مزج الكائنات بالترتيب الذي تتم إضافته إلى مشهد ، ما لم يتم طلبها من قبل z z algo. يجب عليك إضافة كائناتك المعتمة أولاً ، ثم إضافة كائناتك الشفافة بعناية بالترتيب المراد مزجه.

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

يمنحك ضبط وظائف مزج SRC و DST للكائنات الشفافة الوصول إلى المزيج السابق بعدة طرق مختلفة.

يمكنك استخدام خاصية Alpha من لون الإخراج الخاص بك هنا للقيام بمزج فاخر حقًا. هذه هي الطريقة الأكثر فاعلية للوصول إلى مخرجات FrameBuffer (البكسل) ، لأنه يعمل في ممر واحد (الشكل 1) من خط أنابيب GPU.

enter image description here
الشكل 1 - تمريرة واحدة

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

سيؤدي التبديل الإضافي للنسخ والسياق إلى تحطيم تقديم عرض شديد. لاحظ أن خطوط أنابيب GPU متعددة الخيوط ليست مساعدة كبيرة هنا ، لأن التمريرات المتعددة تسلسل بطبيعتها.

enter image description here
الشكل 2 - تمريرة متعددة

لقد لجأت إلى وصف شفهي مع مخططات خطوط الأنابيب لتجنب الإهمال ، لأن لغة التظليل (العامية/GLSL) تخضع للتغيير.

How-do-i-get-cort-current-for-fragment

يقول البعض أنه لا يمكن القيام بذلك ، لكنني أقول إن هذا يعمل من أجلي:

//Toggle blending in one sense, while always disabling it in the other.   
void enableColorPassing(BOOL enable) {
 //This will toggle blending - and what gl_FragColor is set to upon shader execution
   enable ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
   //Tells gl - "When blending, change nothing" 
   glBlendFunc(GL_ONE, GL_ZERO); 
}

بعد تلك المكالمة ، سيساوي GL_FragColor لون المخزن المؤقت للألوان في المرة الأولى التي يتم فيها تشغيل التظليل على كل بكسل ، وسيكون الإخراج كل تشغيل الإدخال الجديد عند كل تشغيل متتالي.

حسنًا ، على الأقل يعمل بالنسبة لي.

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