如何debuggingGLSL着色器?

我需要debugging一个GLSL程序,但我不知道如何输出中间结果。 是否有可能使用GLSL进行一些debugging跟踪(如使用printf)?

您不能轻松地从GLSL内部传回CPU。 使用glslDevil或其他工具是你最好的select。

printf将需要尝试从运行GLSL代码的GPU返回到CPU。 相反,您可以尝试推进显示。 输出文字,而不是输出一些视觉上与屏幕不同的东西。 例如,只有当你到达要添加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; } 

我发现“ 变换反馈”是debugging顶点着色器的有用工具。 您可以使用它来捕获VS输出的​​值,并在CPU端读取它们,而无需通过光栅化器。

这是转换反馈教程的另一个链接。

如果你想要在屏幕上显示一个值的变化,你可以使用类似于这个的热图函数(我在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); 

并且可以了解它在像素中的变化情况:

在这里输入图像说明

当然,你可以使用任何你喜欢的颜色。

GLSL Sandbox对于着色器来说非常方便。

不是本身debugging(已经被认为是无能为力),而是很方便地看到输出的变化。

对纹理进行离线渲染并评估纹理的数据。 你可以通过googling查找“渲染到纹理”的相关代码opengl然后使用glReadPixels读取输出到一个数组并在其上执行断言(因为在debugging器中查看如此巨大的数组通常不是很有用)。

此外,您可能希望禁用夹持以输出不在0和1之间的值,该值仅在浮点纹理中受支持。

我个人一直在纠正着色器的问题。 似乎没有一个好方法 – 如果有人发现一个好的(而不是过时的/不赞成的)debugging器,请让我知道。

我正在分享一个片段着色器的例子,我如何debugging。

 #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; } 

在这里输入图像说明

现有的答案都是好东西,但是我想分享一个在GLSL着色器中debugging棘手的精度问题时有价值的gem。 以非常大的int数表示为浮点数时,需要小心地使用floor(n)和floor(n + 0.5)来实现round()到一个确切的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 。 我用它如下(这个片段给出了模型视图matrix的yy组件):

 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); 

在屏幕上显示之后,您可以使用任何颜色select器,将颜色格式化为HTML(如果您不需要更高的精度,则将00附加到rgb值,如果是这样,则进行第二步以获取较低的字节) ,并获得float的hex表示forms为IEEE 754 binary32

以下是toColor()的实际实现:

 #version 120 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=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 int 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(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 binary32/255.; }