9 ответов:
вы не можете легко связаться с процессором из 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);и может получить представление о том, как он меняется в разных пикселях:
конечно, вы можете использовать любой набор цветов.
GLSL Sandbox было довольно удобно для меня для шейдеров.
не отладка как таковая (которая была отвечена как неспособная), но удобно видеть изменения в выводе быстро.
сделать автономный рендеринг на текстуру и оценить данные текстуры. Вы можете найти связанный код, погуглив для" 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; }
существующие ответы - это все хорошие вещи, но я хотел бы поделиться еще одним маленьким драгоценным камнем, который был ценен при отладке сложных проблем точности в шейдере GLSL. При очень больших числах 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 754binary32. Я использую его следующим образом (этот фрагмент выдаетyyкомпонент матрицы modelview):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 754binary32.вот фактическая реализация
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.; }


Comments