原文
float与double
- cpp中数字默认是double,要float的话,3.14f可以这样
- JavaScript 中的Number类型精度为double类型,而一般GPU的图形接口api(如opengl、DirectX等)中浮点数精度为float,所以数据在cpu传入GPU做渲染过程中会有精度损失,从而导致了渲染中的闪动问题。
- float为单精度浮点数,double是双精度浮点数
- 半精度有效数字
- 16位浮点数 1+8+7
- 2个有效数字
| 符号位 | 指数位 | 尾数部分 |
| --- | --- | --- |
| 1 | 8 | 7 |
- float类型的具体位数描述:
- 32位浮点数 1+8+23
- 指数: 2的7次方即-127~128
- 尾数: 2^23 = 8388608
- 即float的精度为6~7位有效数字
| 符号位 | 指数位 | 尾数部分 |
| --- | --- | --- |
| 1 | 8 | 23 |
- double类型的具体位数描述:
- 64位浮点数 1+11+52
- 指数: 2的10次方即-1023~1024
- 尾数: 2^52 = 4503599627370496
- 即float的精度为15~16位有效数字
| 符号位 | 指数位 | 尾数部分 |
| --- | --- | --- |
| 1 | 11 | 52 |
- 浮点数,浮点数的小数点是浮动的,小数点后面的小数位数不固定
shader精度
precision highp float;
precision highp int;
precision lowp sampler2D;
precision lowp samplerCube;
precision mediump int;
precision lowp sampler2D;
precision lowp samplerCube;
问题重现
var vertices = [
5000000.5, 0.5, 0.5, 5000000.5, 0.5, -0.5, 5000000.5, -0.5, 0.5,
5000000.5, -0.5, -0.5, 4999999.5, 0.5, -0.5, 4999999.5, 0.5, 0.5,
4999999.5, -0.5, -0.5, 4999999.5, -0.5, 0.5, 4999999.5, 0.5, -0.5,
5000000.5, 0.5, -0.5, 4999999.5, 0.5, 0.5, 5000000.5, 0.5, 0.5,
4999999.5, -0.5, 0.5, 5000000.5, -0.5, 0.5, 4999999.5, -0.5, -0.5,
5000000.5, -0.5, -0.5, 4999999.5, 0.5, 0.5, 5000000.5, 0.5, 0.5,
4999999.5, -0.5, 0.5, 5000000.5, -0.5, 0.5, 5000000.5, 0.5, -0.5,
4999999.5, 0.5, -0.5, 5000000.5, -0.5, -0.5, 4999999.5, -0.5, -0.5]
- float里有效数字最多7位,存在有效数字为8位,导致精度的丢失,从而导致组成的立方体会不规则。
精度问题的解决方案
- RTC方案
- RTC(Relative To Center)的方案将模型的顶点信息,转化为相对于某个中心点的坐标,
var vertices = [
0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, 0.5
...
]
- 使用2个float传高精度的数据
- 这种方式保证精度的同时也会增加数据量,造成数据带宽瓶颈,具体要视情况而定。
function doubleToTwoFloats(value) {
var high;
var low;
if (value >= 0) {
tempHigh = Math.floor(value / 65536) * 65536;
high = tempHigh;
low = value - tempHigh;
} else {
tempHigh = Math.floor(-value / 65536) * 65536;
high = -tempHigh;
low = value + tempHigh;
}
return [high, low];
}
uniform vec3 uViewerHigh;
uniform vec3 uViewerLow;
void main(void)
{
vec3 highDifference = vec3(gl_VertexHigh - uViewerHigh);
vec3 lowDifference = vec3(gl_VertexLow.xyz - uViewerLow);
gl_Position = gl_ModelViewProjectionMatrix *
vec4(highDifference + lowDifference, 1.0);
}