我需要調試一個GLSL程序,但我不知道如何輸出中間結果。 是否可以使用GLSL進行一些調試跟蹤(如使用printf)?如何調試GLSL着色器?
回答
您不能輕鬆地從GLSL內部傳回CPU。使用glslDevil或其他工具是你最好的選擇。
printf將需要嘗試從運行GLSL代碼的GPU返回CPU。相反,您可以嘗試推進顯示。不要嘗試輸出文本,而是輸出視覺上與屏幕不同的內容。例如,只有在達到要添加printf的代碼點時纔可以繪製特定顏色。如果您需要打印一個值,您可以根據該值設置顏色。
對紋理進行離線渲染並評估紋理的數據。 您可以通過搜索「渲染到紋理」來查找相關的代碼。然後使用glReadPixels將輸出讀入數組並在其上執行斷言(因爲在調試器中查看如此巨大的數組通常不是很有用)。
此外,您可能希望禁用鉗位,以輸出不在0和1之間的值,該值僅在floating point textures受支持。
我個人一直在糾正着色器的問題。似乎沒有什麼好方法 - 如果任何人發現一個好的(並且不是過時的/不贊成的)調試器,請告訴我。
任何回答或評論說「谷歌xyz」應該被禁止或從Stackoverflow投票。 – gregoiregentil 2016-08-27 00:23:57
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;
}
我發現Transform Feedback是調試頂點着色器的有用工具。您可以使用它來捕獲VS輸出的值,並在CPU端讀取它們,而無需通過光柵化器。
Here是轉換反饋教程的另一個鏈接。
我在分享一個片段着色器的例子,我是如何調試的。
#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;
}
如果你希望顯示在屏幕上的值的變化,可以使用類似這樣的熱圖功能(我寫的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對於着色器來說我已經非常方便了。
本身沒有進行調試(已被回答爲無能力),但很方便快速查看輸出的變化。
現有的答案都是很好的東西,但我想分享一個在調試GLSL着色器中棘手的精度問題方面有價值的小寶石。將非常大的int數表示爲浮點數時,需要注意正確地使用floor(n)和floor(n + 0.5)來實現round()。然後可以通過以下邏輯呈現一個精確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
分量):
你在屏幕上之後,你可以採取任何顏色選擇器,格式化顏色爲HTML(附加00
到rgb
值,如果你不需要更高的精度,並且如果你這樣做了第二遍以得到低字節),並且你得到作爲IEEE 754 binary32
的float
的十六進制表示。
下面是實際執行的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.;
}
- 1. GLSL:頂點着色器無片段着色片段着色器
- 2. 如何編寫通用GLSL着色器來着色對象
- 3. GLSL - 在GLSL 1.2統一地點和着色器深度測試
- 4. 你如何測試用GLSL編寫的OpenGL着色器?
- 5. 如何調試着色器在Android
- 6. 使用lines_adjacency的GLSL幾何着色器
- 7. GLSL直通幾何着色器
- 8. GLSL將着色的法線傳遞給着色器
- 9. 通用GLSL照明着色器
- 10. GLSL着色器分析工具
- 11. Vulkan中的實例化GLSL着色器?
- 12. GLSL頂點着色器崩潰電腦
- 13. GLSL頂點着色器gl_Position值
- 14. 着色器太陽位置 - glsl
- 15. GLSL頂點着色器編譯錯誤
- 16. GLSL着色器和WebGL問題
- 17. GLSL片段着色器語法錯誤
- 18. GLSL點燃頂點着色器
- 19. LWJGL GLSL着色器沒有編譯
- 20. C++在OpenGL着色器(GLSL)位標誌
- 21. 影子着色器優化(GLSL)
- 22. 三角圖案GLSL着色器
- 23. GLSL着色器加載程序問題
- 24. 從GLSL着色器發送日誌
- 25. SceneKit和GLSL - 如何將着色器(GLSL)添加到幾何圖形
- 26. 如何檢查GLSL着色器是否處於原始限制?
- 27. GLSL如何在着色器處理後檢索頂點位置?
- 28. GLSL着色器 - 如何計算紋理的高度?
- 29. 如何將每個頂點屬性傳遞給GLSL着色器
- 30. Pix,無法調試着色器
...無需使用外部軟件,如glslDevil。 – 2010-03-24 15:13:06
看看這個[從GLSL碎片着色器調試浮點變量和文本的打印](https://stackoverflow.com/a/44797902/2521214)你只需要單個備用紋理單元用於輸出值的字體和常量狀態打印區域 – Spektre 2017-06-29 07:55:30