floatの小数部分がシェーダーの不具合を直した話
When the fractional part of a float fixes your shader

Voronoiノイズを使ったシェーダーを制作中、特定のWindows PC(RTX 4070)でのみアニメーションがカクつく問題が発生。複数のデバイスで再現しない中、LLMの提案でfract(x)をx - floor(x)に置き換えると症状が消えた。しかし、その後の検証でLLMの仮説は誤りと判明。手作業でのデバッグと逆アセンブルを通じて、思わぬ原因にたどり着くまでの一部始終を綴る。
コンパイラが同じ数式を、出力する命令によって異なる計算結果にするのは、定義上、誤コンパイルである。
HNでの議論
11- earth-tattoo
素晴らしい記事。読んでいてとても楽しかった。数年前までのHacker Newsを思い出すよ!
しばらくopengl/シェーダーを触っていなかったけど、昨日シャワーを浴びているときに数年前に書いたあるアルゴリズムのことを考えていた。シェーダーの概念全体を初めて理解するのがどれほど大変だったかを思い出したよ。基本的にmain関数もなければ、forループもない。シェーダーは各ピクセルごとに、毎フレーム呼び出される。今の時代ならどれほど簡単だっただろうかと思った。かつて2ヶ月もかけたものが、今ではただのプロンプトだ。
- Sharlin
`fract(x)` は x >= 0 の場合にのみ `x - floor(x)` と等価である点に注意すべきだ。このケースではそうだったが、負の値も可能または想定されることが多く、その場合は後者を使うべきだ。これは犯しやすい間違いだ。
- flohofwoe
結局は別の原因だったが、シェーダー出力の差異のもう一つのずっと一般的な原因は、float値が整数にクランプされる(値が最も近い整数に非常に近い)ときに、そのクランプされた値をインデックス(またはフィルタリングなしのサンプラーでのテクスチャ座標)として使う場合だ。これにより、一部のGPU/ドライバの組み合わせではオフバイワンエラーが発生するが、他では発生しないことがある。なぜ起こるかは完全に理解できるが、幅広いGPUとドライバでテストしない限り見つけるのは難しい。
TL;DR: GPU上の浮動小数点演算が厳密にIEEE-754準拠であるとは期待しないこと