读取有损文件格式(PRC),导致精度问题
Reading lossy file format (PRC), resulting in precision problems
我着手制作各种 3D 文件格式的查看器,我以前使用的那些格式都没有问题,直到我遇到 PRC 文件(它是可以支持的 3D 格式之一)嵌入 PDF 中)。我可以从 PDF 中提取所有数据并显示那些以无损方式编码的模型,但是当我试图解码他们所谓的 "Highly Compressed Tesselations" 时,我 运行 变成了一个我认为是精度问题,但我不太清楚如何解决它或在哪里寻找解决方案。
本质上它是一种有损格式,他们所做的是采用原始(基于浮点数的)顶点坐标,并使用公差值将这些坐标除以它,并将结果四舍五入为最接近的整数。在遍历网格对所有三角形进行编码时,只有第一个三角形存储绝对值,其余三角形始终基于之前的相邻三角形并构建以共享边的中间为原点的局部坐标系,向量沿共享边为 x 轴,三角形法线为 z 轴。 y 轴只是它们的叉积的结果,并使用这 3 个局部轴存储新三角形的第三个点的坐标。
我的系统正常工作,对于没有太多三角形的简单模型,它也工作得很好,但是一旦模型变得更复杂,结果就全错了,而且似乎离最后一个越来越远绝对坐标,偏差越大。
在下面的示例图片中,您可以在左侧看到预期结果(在 Adobe Reader 中呈现),在右侧看到我的结果。这个模型本质上有一个内部部分和一个我们的部分,在这种情况下,内部部分由一个绝对三角形和相对三角形组成(而外部部分主要由绝对坐标组成,这就是为什么它在我看来是正确的),和从内环到外环的遍历。在 Adobe 渲染中,您可以看到线条应该或多或少地径向向外指向,而在我的渲染中,从大约第四个 "circle" 开始,事情开始出错:
Expected result on the left, my result on the right
我目前卡在这个问题上,不太清楚如何解决这个问题。我发现做一些小的改变(比如将 double 改为 float,反之亦然)对结果有很大的影响,很快就会变得更糟。但基本上我遵循规范,它说对所有计算使用双精度浮点变量,并且还使用他们自己的计算平方根的实现(标准化轴所需)。例如,通过使用他们的 sqrt 函数而不是普通数学库中的函数,结果已经更好了(如果没有它,我什至不会像上图那样接近)。
但我想知道是否有某种数学方面我没有掌握在这里?或者其他一些可能有帮助的想法?同样在那个特定的模型中,这些值似乎都足够大,因此它不应该是由于浮点格式精度不足而导致数据丢失的问题。规范中也有一些特殊情况,如果 y 轴或 z 轴太短 (< FLT_EPSILON),则必须使用另一个解决方案,但在这个特定模型中,如果 < FLT_EPSILON案件永远不会被触发。
仅供参考,这里是关于点编码的描述(但没有更多关于解码细节的信息):
info from the PRC spec on how to encode points
如有任何意见,我们将不胜感激。如果需要,我可以提供更多数据、信息、示例、规范摘录等。
根据我以前使用 PRC 的经验,这看起来很像是对象偏移(我认为它被称为原点偏移)应用在错误位置的问题。
由于每个新的顶点都是基于前一个顶点,使用基于最后一个三角形的局部坐标系来得到新三角形的第三个点,错误似乎增长得非常非常快这种格式,并且是一种有损格式也无济于事。在我最初的方法中,我尝试计算所有的三角形,然后在最后应用偏移量以将其放入正确的位置,导致看起来与您的问题类似的问题。
通过更改它以将偏移量应用到 "absolute vertices"(即那些未修改的读入,并且在新三角形开始时充当 "anchor points")我能够修复问题。
当然,作为中华人民共和国,还有很多其他的事情你可能需要解决,我不确定你是否已经解决了。官方 ISO 规范中的很多东西都是完全错误的,其他的没有提到(例如,当你应该重新计算法线而不是从文件中获取显式法线时),霍夫曼压缩之类的东西有错误等。如果你能避免它,然后最好不要实施它 ;-)
我着手制作各种 3D 文件格式的查看器,我以前使用的那些格式都没有问题,直到我遇到 PRC 文件(它是可以支持的 3D 格式之一)嵌入 PDF 中)。我可以从 PDF 中提取所有数据并显示那些以无损方式编码的模型,但是当我试图解码他们所谓的 "Highly Compressed Tesselations" 时,我 运行 变成了一个我认为是精度问题,但我不太清楚如何解决它或在哪里寻找解决方案。
本质上它是一种有损格式,他们所做的是采用原始(基于浮点数的)顶点坐标,并使用公差值将这些坐标除以它,并将结果四舍五入为最接近的整数。在遍历网格对所有三角形进行编码时,只有第一个三角形存储绝对值,其余三角形始终基于之前的相邻三角形并构建以共享边的中间为原点的局部坐标系,向量沿共享边为 x 轴,三角形法线为 z 轴。 y 轴只是它们的叉积的结果,并使用这 3 个局部轴存储新三角形的第三个点的坐标。
我的系统正常工作,对于没有太多三角形的简单模型,它也工作得很好,但是一旦模型变得更复杂,结果就全错了,而且似乎离最后一个越来越远绝对坐标,偏差越大。
在下面的示例图片中,您可以在左侧看到预期结果(在 Adobe Reader 中呈现),在右侧看到我的结果。这个模型本质上有一个内部部分和一个我们的部分,在这种情况下,内部部分由一个绝对三角形和相对三角形组成(而外部部分主要由绝对坐标组成,这就是为什么它在我看来是正确的),和从内环到外环的遍历。在 Adobe 渲染中,您可以看到线条应该或多或少地径向向外指向,而在我的渲染中,从大约第四个 "circle" 开始,事情开始出错:
Expected result on the left, my result on the right
我目前卡在这个问题上,不太清楚如何解决这个问题。我发现做一些小的改变(比如将 double 改为 float,反之亦然)对结果有很大的影响,很快就会变得更糟。但基本上我遵循规范,它说对所有计算使用双精度浮点变量,并且还使用他们自己的计算平方根的实现(标准化轴所需)。例如,通过使用他们的 sqrt 函数而不是普通数学库中的函数,结果已经更好了(如果没有它,我什至不会像上图那样接近)。
但我想知道是否有某种数学方面我没有掌握在这里?或者其他一些可能有帮助的想法?同样在那个特定的模型中,这些值似乎都足够大,因此它不应该是由于浮点格式精度不足而导致数据丢失的问题。规范中也有一些特殊情况,如果 y 轴或 z 轴太短 (< FLT_EPSILON),则必须使用另一个解决方案,但在这个特定模型中,如果 < FLT_EPSILON案件永远不会被触发。
仅供参考,这里是关于点编码的描述(但没有更多关于解码细节的信息):
info from the PRC spec on how to encode points
如有任何意见,我们将不胜感激。如果需要,我可以提供更多数据、信息、示例、规范摘录等。
根据我以前使用 PRC 的经验,这看起来很像是对象偏移(我认为它被称为原点偏移)应用在错误位置的问题。
由于每个新的顶点都是基于前一个顶点,使用基于最后一个三角形的局部坐标系来得到新三角形的第三个点,错误似乎增长得非常非常快这种格式,并且是一种有损格式也无济于事。在我最初的方法中,我尝试计算所有的三角形,然后在最后应用偏移量以将其放入正确的位置,导致看起来与您的问题类似的问题。
通过更改它以将偏移量应用到 "absolute vertices"(即那些未修改的读入,并且在新三角形开始时充当 "anchor points")我能够修复问题。
当然,作为中华人民共和国,还有很多其他的事情你可能需要解决,我不确定你是否已经解决了。官方 ISO 规范中的很多东西都是完全错误的,其他的没有提到(例如,当你应该重新计算法线而不是从文件中获取显式法线时),霍夫曼压缩之类的东西有错误等。如果你能避免它,然后最好不要实施它 ;-)