簡體   English   中英

WebGL2 和 C++ 上浮點計算的不同結果

[英]Different results in floating-point calculations on WebGL2 and C++

我正在嘗試對 WebGL2 中的片段着色器進行計算。 而且我注意到那里的計算不如 C++ 精確。 我知道在片段着色器或 C++ 中,高精度浮點數包含 32 位。

我正在嘗試計算 1.0000001^(10000000) 並在 C++ 上獲得大約 2.8,在着色器上獲得大約 3.2。 你知道片段着色器計算不如C++上的相同計算精確的原因嗎?

C++ 上的代碼

#include <iostream>
void main()
{
  const float NEAR_ONE = 1.0000001;
  float result = NEAR_ONE;

  for (int i = 0; i < 10000000; i++)
  {
    result = result * NEAR_ONE;
  }

  std::cout << result << std::endl; // result is 2.88419
}

片段着色器代碼:

#version 300 es
precision highp float;
out vec4 color;
void main()
{
  const float NEAR_ONE = 1.0000001;
  float result = NEAR_ONE;

  for (int i = 0; i < 10000000; i++)
  {
    result = result * NEAR_ONE;
  }    

  if ((result > 3.2) && (result < 3.3))
  {
    // The screen is colored by red and this is how we know 
    // that the value of result is in between 3.2 and 3.3
    color = vec4(1.0, 0.0, 0.0, 1.0); // Red
  }
  else
  {
     // We never come here. 
     color = vec4(0.0, 0.0, 0.0, 1.0); // Black
  }
}

更新在這里可以找到包含 WebGL2 示例完整代碼的 html 文件

WebGL2 所基於的 OpenGL ES 3.0 不需要 GPU 上的浮點數來像在 C++ 中一樣工作

規范

2.1.1 浮點計算

GL 在其操作過程中必須執行許多浮點運算。 在某些情況下,此類操作的表示和/或精度是被定義或限制的; 由 OpenGL ES 着色語言規范用於着色器中的操作,並且在某些情況下受到 GL 消耗的頂點、紋理或渲染緩沖區數據的指定格式的隱式限制。 否則,不會指定此類浮點數的表示形式以及如何對其執行操作的詳細信息 我們只要求數字的浮點部分包含足夠的位,並且它們的指數字段足夠大,以便浮點運算的單個結果精確到大約 10 5 的1 部分。 所有浮點值的最大可表示幅度必須至少為 2 32 x·0 = 0 ·x = 0 對於任何非無限和非 NaN x。 1·x = x· 1 = x。 x + 0 = 0 + x = x。 0 0 = 1。(有時會指定進一步的要求。)大多數單精度浮點格式都滿足這些要求。

只是為了好玩,讓我們這樣做並打印結果。 使用 WebGL1 可以在更多設備上進行測試

 function main() { const gl = document.createElement('canvas').getContext('webgl'); const ext = gl.getExtension('OES_texture_float'); if (!ext) { return alert('need OES_texture_float'); } // not required - long story gl.getExtension('WEBGL_color_buffer_float'); const fbi = twgl.createFramebufferInfo(gl, [ { type: gl.FLOAT, minMag: gl.NEAREST, wrap: gl.CLAMP_TO_EDGE, } ], 1, 1); const vs = ` void main() { gl_Position = vec4(0, 0, 0, 1); gl_PointSize = 1.0; } `; const fs = ` precision highp float; void main() { const float NEAR_ONE = 1.0000001; float result = NEAR_ONE; for (int i = 0; i < 10000000; i++) { result = result * NEAR_ONE; } gl_FragColor = vec4(result); } `; const prg = twgl.createProgram(gl, [vs, fs]); gl.useProgram(prg); gl.viewport(0, 0, 1, 1); gl.drawArrays(gl.POINTS, 0, 1); const values = new Float32Array(4); gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.FLOAT, values); console.log(values[0]); } main();
 <script src="https://twgljs.org/dist/4.x/twgl.js"></script>

我的結果:

Intel Iris Pro          : 2.884186029434204
NVidia GT 750 M         : 3.293879985809326
NVidia GeForce GTX 1060 : 3.2939157485961914
Intel UHD Graphics 617  : 3.292219638824464 

區別在於精度。 事實上,如果您使用 double(64 位浮點,53 位尾數)而不是 float(32 位浮點,24 位尾數)編譯 c++ 片段,您將獲得結果 3.29397,即是使用着色器得到的結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM