WebGL着色器32位浮点数精度损失问题
问题
WebGL浮点数精度最大的问题是就是因为js是64位精度的,js往着色器里面穿的时候只能是32位浮点数,有效数是8位,精度丢失比较严重。

分析

继续尝试发现mapbox中也有类似问题:https://github.com/mapbox/mapbox-gl-js/issues/7268
map.renderEngin.gl.getShaderPrecisionFormat( map.renderEngin.gl.VERTEX_SHADER, map.renderEngin.gl.HIGH_FLOAT )

解决


getDistanceScales() {
// {latitude, longitude, zoom, scale, highPrecision = false}
let center = this.center;
let latitude = center.lat;
let longitude = center.lng;
let scale = this.zoomScale(this.zoom);
let highPrecision = true;
// Calculate scale from zoom if not provided
scale = scale !== undefined ? scale : this.zoomToScale(zoom);
// assert(Number.isFinite(latitude) && Number.isFinite(longitude) && Number.isFinite(scale));
const result = {};
const worldSize = TILE_SIZE * scale;
const latCosine = Math.cos(latitude * DEGREES_TO_RADIANS);
/**
* Number of pixels occupied by one degree longitude around current lat/lon:
pixelsPerDegreeX = d(lngLatToWorld([lng, lat])[0])/d(lng)
= scale * TILE_SIZE * DEGREES_TO_RADIANS / (2 * PI)
pixelsPerDegreeY = d(lngLatToWorld([lng, lat])[1])/d(lat)
= -scale * TILE_SIZE * DEGREES_TO_RADIANS / cos(lat * DEGREES_TO_RADIANS) / (2 * PI)
*/
const pixelsPerDegreeX = worldSize / ;
const pixelsPerDegreeY = pixelsPerDegreeX / latCosine;
/**
* Number of pixels occupied by one meter around current lat/lon:
*/
const altPixelsPerMeter = worldSize / EARTH_CIRCUMFERENCE / latCosine;
/**
* LngLat: longitude -> east and latitude -> north (bottom left)
* UTM meter offset: x -> east and y -> north (bottom left)
* World space: x -> east and y -> south (top left)
*
* Y needs to be flipped when converting delta degree/meter to delta pixels
*/
result.pixelsPerMeter = [altPixelsPerMeter, altPixelsPerMeter, altPixelsPerMeter];
result.metersPerPixel = [ / altPixelsPerMeter, / altPixelsPerMeter, / altPixelsPerMeter];
result.pixelsPerDegree = [pixelsPerDegreeX, pixelsPerDegreeY, altPixelsPerMeter];
result.degreesPerPixel = [ / pixelsPerDegreeX, / pixelsPerDegreeY, / altPixelsPerMeter];
/**
* Taylor series 2nd order for 1/latCosine
f'(a) * (x - a)
= d(1/cos(lat * DEGREES_TO_RADIANS))/d(lat) * dLat
= DEGREES_TO_RADIANS * tan(lat * DEGREES_TO_RADIANS) / cos(lat * DEGREES_TO_RADIANS) * dLat
*/
if (highPrecision) {
const latCosine2 = DEGREES_TO_RADIANS * Math.tan(latitude * DEGREES_TO_RADIANS) / latCosine;
const pixelsPerDegreeY2 = pixelsPerDegreeX * latCosine2 / ;
const altPixelsPerDegree2 = worldSize / EARTH_CIRCUMFERENCE * latCosine2;
const altPixelsPerMeter2 = altPixelsPerDegree2 / pixelsPerDegreeY * altPixelsPerMeter;
result.pixelsPerDegree2 = [, pixelsPerDegreeY2, altPixelsPerDegree2];
result.pixelsPerMeter2 = [altPixelsPerMeter2, , altPixelsPerMeter2];
}
// Main results, used for converting meters to latlng deltas and scaling offsets
return result;
}
对于project_uCommonUnitsPerWorldUnit来说就是计算在精度和纬度上,一度代表的瓦片像素数目。对于project_uCommonUnitsPerWorldUnit2来说这里面用了一个泰勒级数的二阶展开(咨询了下管戈,泰勒级数展开项越多代表模拟值误差越小,这里用到了第二级)主要是在着色器中在`project_uCommonUnitsPerWorldUnit + project_uCommonUnitsPerWorldUnit2 * dy`这里做精度补偿
gl.uniform3f(this.project_uCommonUnitsPerWorldUnit, distanceScles.pixelsPerDegree[], distanceScles.pixelsPerDegree[], distanceScles.pixelsPerDegree[]);

vec2 project_offset(vec2 offset) {
float dy = offset.y;
// if (project_uCoordinateSystem == COORDINATE_SYSTEM_LNGLAT_AUTO_OFFSET) {
dy = clamp(dy, -., .);
// }
vec3 commonUnitsPerWorldUnit = project_uCommonUnitsPerWorldUnit + project_uCommonUnitsPerWorldUnit2 * dy;
// return vec4(offset.xyz * commonUnitsPerWorldUnit, offset.w);
return vec2(offset.xy * commonUnitsPerWorldUnit.xy);
}
// 返回在v3 api中的3d坐标系下的坐标, 采用高精度模式
vec2 project_view_local_position3(vec2 latlngHigh, vec2 latlngLow) {
vec2 centerCoordHigh = project_position(center.xy + center.zw, zoom);
// Subtract high part of 64 bit value. Convert remainder to float32, preserving precision.
float X = latlngHigh.x - center.x;
float Y = latlngHigh.y - center.y;
return project_offset(vec2(X + latlngLow.x, Y + latlngLow.y));
}
最终效果:

WebGL着色器32位浮点数精度损失问题的更多相关文章
- 并行计算提升32K*32K点(32位浮点数) FFT计算速度(4核八线程E3处理器)
对32K*32K的随机数矩阵进行FFT变换,数的格式是32位浮点数.将产生的数据存放在堆上,对每一行数据进行N=32K的FFT,记录32K次fft的时间. 比较串行for循环和并行for循环的运行时间 ...
- WebGL 着色器语言(GLSL ES)
1.类型转换内置函数 转换/函数/描述 转换为整形数/int(float)/将浮点数的小数部分删去,转换为整形数(比如,将3.14转换为3) 转换为整形数/intl(bool)/true被转换为1,f ...
- WebGL 着色器偏导数dFdx和dFdy介绍
本文适合对webgl.计算机图形学.前端可视化感兴趣的读者. 偏导数函数(HLSL中的ddx和ddy,GLSL中的dFdx和dFdy)是片元着色器中的一个用于计算任何变量基于屏幕空间坐标的变化率的指令 ...
- IEEE754 32位浮点数表示范围
6.1浮点数的数值范围 根据上面的探讨,浮点数可以表示-∞到+∞,这只是一种特殊情况,显然不是我们想要的数值范围. 以32位单精度浮点数为例,阶码E由8位表示,取值范围为0-255,去除0和255这两 ...
- WebGL着色器渲染小游戏实战
项目起因 经过对 GLSL 的了解,以及 shadertoy 上各种项目的洗礼,现在开发简单交互图形应该不是一个怎么困难的问题了.下面开始来对一些已有业务逻辑的项目做GLSL渲染器替换开发. 起因是看 ...
- OpenGL ES着色器语言之变量和数据类型(二)(官方文档第四章)
OpenGL ES着色器语言之变量和数据类型(二)(官方文档第四章) 4.5精度和精度修饰符 4.5.1范围和精度 用于存储和展示浮点数.整数变量的范围和精度依赖于数值的源(varying,unifo ...
- 着色器语言 GLSL (opengl-shader-language)入门大全
基本类型: 类型 说明 void 空类型,即不返回任何值 bool 布尔类型 true,false int 带符号的整数 signed integer float 带符号的浮点数 floating s ...
- java float double精度为什么会丢失?浅谈java的浮点数精度问题 【转】
由于对float或double 的使用不当,可能会出现精度丢失的问题.问题大概情况可以通过如下代码理解: public class FloatDoubleTest { public static vo ...
- Python之☞float浮点数精度问题
Python的浮点数损失精度问题(转) 一个简单的面试题: >>>0.1+0.1+0.1 0.2 >>>0.1+0.1+0.1 0.3000000000000000 ...
随机推荐
- 3023Java_控制语句
控制语句 0.前定义 语句块(有时叫做复合语句),是用花括号扩起的任意数量的简单Java语句. 块确定了局部变量的作用域.块中的程序代码,作为一个整体,是要被一起执行的. 块可以被嵌套在另一个块中,但 ...
- Binary classification - 聊聊评价指标的那些事儿【回忆篇】
在解决分类问题的时候,可以选择的评价指标简直不要太多.但基本可以分成两2大类,我们今分别来说道说道 基于一个概率阈值判断在该阈值下预测的准确率 衡量模型整体表现(在各个阈值下)的评价指标 在说指标之前 ...
- RocketMQ(5)---RocketMQ重试机制
RocketMQ重试机制 消息重试分为两种:Producer发送消息的重试 和 Consumer消息消费的重试. 一.Producer端重试 Producer端重试是指: Producer往MQ上发消 ...
- unity中实现物体在一定角度范围内来回旋转
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Rotate : ...
- PATA 1009. Product of Polynomials (25)
1009. Product of Polynomials (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yu ...
- vSphere Client克隆虚拟机
免费的VMWare ESXi5.5非常强大,使用ESXi经常会遇到这样的问题,我需要建立多个虚拟机,系统一个一个安装很麻烦.VMware ESXi.VMware vCenter Server 和 vS ...
- There is no getter for property named 'username' in 'class Model1.User'-----报错解决
There is no getter for property named 'username' in 'class Model1.User' -----Model Model1.User'中没有名为 ...
- cat more less 命令混用
在Linux系统中有三种命令可以用来查阅全部的文件,分别是cat.more和less命令.它们查阅文件的使用方法也比较简单都是 命令 文件名 ,但是三者又有着区别. 1.cat命令可以一次显示整个文件 ...
- ES5_04_Array扩展
介绍什么是Array对象? # Array 对象用于在单个的变量中存储多个值 1. 创建 Array 对象的语法: 2. Array 对象属性 3. Array 对象方法 补充: 1. Array.p ...
- 我把代码开源、托管到了GitHub、码云
前言 学习了那么多知识点,写了那么多代码,一直都没有时间整理,之前都是新学一个知识点就在同一个工程项目中进行实践测试,导致这个工程越来越臃肿.越来越乱,连我自己都快看不懂了... 这段时间整理了部分代 ...