سؤال

أحتاج إلى تصحيح برنامج GLSL ولكني لا أعرف كيفية إخراج النتيجة الوسيطة. هل من الممكن إجراء بعض آثار التصحيح (مثل مع printf) مع GLSL؟

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

المحلول

لا يمكنك التواصل بسهولة إلى وحدة المعالجة المركزية من داخل GLSL. يعد استخدام GLSLDEVIL أو أدوات أخرى أفضل رهان.

سوف تتطلب printf محاولة العودة إلى وحدة المعالجة المركزية من وحدة معالجة الرسومات التي تعمل على تشغيل رمز GLSL. بدلاً من ذلك ، يمكنك محاولة الدفع إلى الشاشة. بدلاً من محاولة إخراج النص ، إخراج شيء مميز بصريًا على الشاشة. على سبيل المثال ، يمكنك رسم شيء محدد فقط إذا وصلت إلى نقطة الكود الخاص بك حيث تريد إضافة printf. إذا كنت بحاجة إلى طباعة قيمة ، فيمكنك تعيين اللون وفقًا لتلك القيمة.

نصائح أخرى

void main(){
  float bug=0.0;
  vec3 tile=texture2D(colMap, coords.st).xyz;
  vec4 col=vec4(tile, 1.0);

  if(something) bug=1.0;

  col.x+=bug;

  gl_FragColor=col;
}

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

هنا هو رابط آخر إلى برنامج تعليمي حول تحويلات التحويل.

إذا كنت ترغب في تصور الاختلافات في القيمة عبر الشاشة ، فيمكنك استخدام وظيفة خريطة الحرارة مماثلة لهذا (كتبت في HLSL ، لكن من السهل التكيف مع GLSL):

float4 HeatMapColor(float value, float minValue, float maxValue)
{
    #define HEATMAP_COLORS_COUNT 6
    float4 colors[HEATMAP_COLORS_COUNT] =
    {
        float4(0.32, 0.00, 0.32, 1.00),
        float4(0.00, 0.00, 1.00, 1.00),
        float4(0.00, 1.00, 0.00, 1.00),
        float4(1.00, 1.00, 0.00, 1.00),
        float4(1.00, 0.60, 0.00, 1.00),
        float4(1.00, 0.00, 0.00, 1.00),
    };
    float ratio=(HEATMAP_COLORS_COUNT-1.0)*saturate((value-minValue)/(maxValue-minValue));
    float indexMin=floor(ratio);
    float indexMax=min(indexMin+1,HEATMAP_COLORS_COUNT-1);
    return lerp(colors[indexMin], colors[indexMax], ratio-indexMin);
}

ثم في تظليل بكسلك ، يمكنك فقط إخراج شيء مثل:

return HeatMapColor(myValue, 0.00, 50.00);

ويمكن أن تحصل على فكرة عن كيفية اختلافها عبر وحدات البكسل الخاصة بك:

enter image description here

بالطبع يمكنك استخدام أي مجموعة من الألوان التي تريدها.

صندوق الرمل GLSL لقد كان مفيدًا جدًا بالنسبة لي للتظليلات.

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

قم بإعداد عدم الاتصال بالملمس وتقييم بيانات الملمس. يمكنك العثور على التعليمات البرمجية ذات الصلة عن طريق googling لـ "Render to texture" OpenGL ثم استخدام glreadpixels لقراءة الإخراج في صفيف وإجراء تأكيدات عليه (لأن النظر في مثل هذه الصفيف الضخم في مصحح الأخطاء عادة ما يكون مفيدًا حقًا).

كما قد ترغب في تعطيل التثبيت على قيم الإخراج التي لا تتراوح بين 0 و 1 ، والتي يتم دعمها فقط قوام النقطة العائمة.

أنا شخصياً أزعجت مشكلة تصحيح التظليلات بشكل صحيح لفترة من الوقت. لا يبدو أن هناك طريقة جيدة - إذا وجد أي شخص تصحيح أخطاء جيد (وليس قديمة/تم إهماله) ، فيرجى إخبارنا بذلك.

أنا أشارك مثال تظليل الشظية ، كيف أقوم بالفعل بتصحيح.

#version 410 core

uniform sampler2D samp;
in VS_OUT
{
    vec4 color;
    vec2 texcoord;
} fs_in;

out vec4 color;

void main(void)
{
    vec4 sampColor;
    if( texture2D(samp, fs_in.texcoord).x > 0.8f)  //Check if Color contains red
        sampColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);  //If yes, set it to white
    else
        sampColor = texture2D(samp, fs_in.texcoord); //else sample from original
    color = sampColor;

}

enter image description here

يمكنك تجربة هذا: https://github.com/msqrt/shader-printf وهو تطبيق يسمى بشكل مناسب "وظيفة printf بسيطة لـ GLSL."

قد ترغب أيضًا في تجربة Shadertoy ، وربما مشاهدة مقطع فيديو مثل هذا (https://youtu.be/ebradahftuo) من قناة "فن الرمز" على YouTube حيث يمكنك رؤية بعض التقنيات التي تعمل بشكل جيد لتصحيح الأخطاء والتصور. أستطيع أن أوصي بشدة بقنته لأنه يكتب بعض الأشياء الجيدة حقًا ولديه موهبة لتقديم أفكار معقدة في الرواية ، والجذابة للغاية وسهلة الهضم (فيديو Mandelbrot له مثال رائع على ذلك بالضبط: https://youtu.be/6iwxkv82oyy)

آمل أن لا أحد يمانع في هذا الرد المتأخر ، لكن السؤال يحتل المرتبة العالية على عمليات البحث عن Google عن تصحيح الأخطاء GLSL ، وقد تغير الكثير بالطبع منذ 9 سنوات :-)

ملاحظة: يمكن أيضًا أن تكون بدائل أخرى هي Nvidia nsight و AMD ShaderAnalyzer التي تقدم تصحيح تصحيح كامل للتظليل.

الإجابات الحالية كلها أشياء جيدة ، لكنني أردت أن أشارك جوهرة صغيرة أخرى كانت ذات قيمة في تصحيح القضايا الدقيقة الصعبة في تظليل GLSL. مع الأرقام الكبيرة جدًا التي تم تمثيلها كنقطة عائمة ، يحتاج المرء إلى الاهتمام باستخدام الطابق (N) والأرضية (N + 0.5) بشكل صحيح لتنفيذ الجولة () إلى int دقيقة. من الممكن بعد ذلك تقديم قيمة تعويم تمثل int دقيقة من خلال المنطق التالي لتعبئة مكونات البايت في قيم الإخراج R و G و B.

  // Break components out of 24 bit float with rounded int value
  // scaledWOB = (offset >> 8) & 0xFFFF
  float scaledWOB = floor(offset / 256.0);
  // c2 = (scaledWOB >> 8) & 0xFF
  float c2 = floor(scaledWOB / 256.0);
  // c0 = offset - (scaledWOB << 8)
  float c0 = offset - floor(scaledWOB * 256.0);
  // c1 = scaledWOB - (c2 << 8)
  float c1 = scaledWOB - floor(c2 * 256.0);

  // Normalize to byte range
  vec4 pix;  
  pix.r = c0 / 255.0;
  pix.g = c1 / 255.0;
  pix.b = c2 / 255.0;
  pix.a = 1.0;
  gl_FragColor = pix;

في أسفل هذه الإجابة ، يوجد مثال على رمز GLSL الذي يسمح بإخراج الكامل float قيمة اللون ، ترميز IEEE 754 binary32. أنا أستخدمه كما يلي (يعطي هذا المقتطف yy مكون من ModelView Matrix):

vec4 xAsColor=toColor(gl_ModelViewMatrix[1][1]);
if(bool(1)) // put 0 here to get lowest byte instead of three highest
    gl_FrontColor=vec4(xAsColor.rgb,1);
else
    gl_FrontColor=vec4(xAsColor.a,0,0,1);

بعد الحصول على هذا على الشاشة ، يمكنك فقط أخذ أي منتقي ألوان ، وتنسيق اللون على أنه HTML (إلحاق 00 إلى rgb القيمة إذا لم تكن بحاجة إلى دقة أعلى ، وقم بتمريرة ثانية للحصول على البايت السفلي إذا قمت بذلك) ، وستحصل على التمثيل السداسي ل float كما IEEE 754 binary32.

إليك التنفيذ الفعلي لـ toColor():

const int emax=127;
// Input: x>=0
// Output: base 2 exponent of x if (x!=0 && !isnan(x) && !isinf(x))
//         -emax if x==0
//         emax+1 otherwise
int floorLog2(float x)
{
    if(x==0.) return -emax;
    // NOTE: there exist values of x, for which floor(log2(x)) will give wrong
    // (off by one) result as compared to the one calculated with infinite precision.
    // Thus we do it in a brute-force way.
    for(int e=emax;e>=1-emax;--e)
        if(x>=exp2(float(e))) return e;
    // If we are here, x must be infinity or NaN
    return emax+1;
}

// Input: any x
// Output: IEEE 754 biased exponent with bias=emax
int biasedExp(float x) { return emax+floorLog2(abs(x)); }

// Input: any x such that (!isnan(x) && !isinf(x))
// Output: significand AKA mantissa of x if !isnan(x) && !isinf(x)
//         undefined otherwise
float significand(float x)
{
    // converting int to float so that exp2(genType) gets correctly-typed value
    float expo=float(floorLog2(abs(x)));
    return abs(x)/exp2(expo);
}

// Input: x\in[0,1)
//        N>=0
// Output: Nth byte as counted from the highest byte in the fraction
int part(float x,int N)
{
    // All comments about exactness here assume that underflow and overflow don't occur
    const float byteShift=256.;
    // Multiplication is exact since it's just an increase of exponent by 8
    for(int n=0;n<N;++n)
        x*=byteShift;

    // Cut higher bits away.
    // $q \in [0,1) \cap \mathbb Q'.$
    float q=fract(x);

    // Shift and cut lower bits away. Cutting lower bits prevents potentially unexpected
    // results of rounding by the GPU later in the pipeline when transforming to TrueColor
    // the resulting subpixel value.
    // $c \in [0,255] \cap \mathbb Z.$
    // Multiplication is exact since it's just and increase of exponent by 8
    float c=floor(byteShift*q);
    return int(c);
}

// Input: any x acceptable to significand()
// Output: significand of x split to (8,8,8)-bit data vector
ivec3 significandAsIVec3(float x)
{
    ivec3 result;
    float sig=significand(x)/2.; // shift all bits to fractional part
    result.x=part(sig,0);
    result.y=part(sig,1);
    result.z=part(sig,2);
    return result;
}

// Input: any x such that !isnan(x)
// Output: IEEE 754 defined binary32 number, packed as ivec4(byte3,byte2,byte1,byte0)
ivec4 packIEEE754binary32(float x)
{
    int e = biasedExp(x);
    // sign to bit 7
    int s = x<0. ? 128 : 0;

    ivec4 binary32;
    binary32.yzw=significandAsIVec3(x);
    // clear the implicit integer bit of significand
    if(binary32.y>=128) binary32.y-=128;
    // put lowest bit of exponent into its position, replacing just cleared integer bit
    binary32.y+=128*int(mod(float(e),2.));
    // prepare high bits of exponent for fitting into their positions
    e/=2;
    // pack highest byte
    binary32.x=e+s;

    return binary32;
}

vec4 toColor(float x)
{
    ivec4 binary32=packIEEE754binary32(x);
    // Transform color components to [0,1] range.
    // Division is inexact, but works reliably for all integers from 0 to 255 if
    // the transformation to TrueColor by GPU uses rounding to nearest or upwards.
    // The result will be multiplied by 255 back when transformed
    // to TrueColor subpixel value by OpenGL.
    return vec4(binary32)/255.;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top