Three.js: 远离场景根(0,0,0)时的SkinnedMesh错误

创建于 2018-02-09  ·  113评论  ·  资料来源: mrdoob/three.js

我认为我发现了有关您的SkinnedMesh的错误(已在iPhone 6和8上测试)。

如果已经报告了,很抱歉,我没有在问题列表中找到它:(

看来gpu外观无法正常运行,并且在移动设备上变得疯狂。
当SkinnedMesh移动或移动到高值位置(例如x:0,y:0,z:1000)时,蒙皮不再准确,并开始蜘蛛跳舞。

网格的规模正在影响该错误。

似乎在每帧中都没有正确计算骨骼的骨骼值,并且蒙皮着色器上的bonesTexture / bonesMatrix将顶点推入错误的位置。
当然,这只是我的感觉。

在发布此消息之前,我进行了很多测试...在动画导出中寻找线索,但是我发现Bug发生在任何格式(GLTF,FBX,Collada,JSON等)和ThreeJS回购模型中。

这很烦人,因为这意味着如果没有这个问题,我们将无法开发一个运行有头像的简单亚军游戏(avatar.position.z随后增加):((
我仍然不知道如何管理它,因为morphTargets不是一种选择:(

希望你们能在这里提供帮助。

我用干净的资料制作了清晰的示例来揭示问题。 在智能手机上验证它非常容易:

仅出现在移动设备上(z = 10000):
http://cornflex.org/webgl/skinning-bug.html

将floatVertexTextures设置为false(z = 10000):
http://cornflex.org/webgl/skinning-bug2.html

随着距离变差(z增大):
http://cornflex.org/webgl/skinning-bug3.html

距中心非常远(z = 70000000)>错误也出现在桌面上,但肯定是由于浮动精度问题:
http://cornflex.org/webgl/skinning-bug4.html

我的游戏环境中的视频预览:
这是一个现实的比例世界(1.0m = 1.0 threejs单位)。
错误仅在距场景根50-60m之后出现,并且随着距离的增加而恶化:
http://cornflex.org/webgl/skin-bug.mp4

很重要
ThreeJS回购中使用的网格太大。 大约20m高。
这就是为什么z值必须更大才能看到该错误的原因。
如果按实际大小按比例缩小该网格,则即使在100m处,该漏洞也开始出现。

Three.js版本
  • [x]开发
  • [x] r89
  • [X] ...
浏览器
  • [ ] 他们全部
  • [] Chrome
  • []火狐
  • [ ] IE浏览器
  • [x] Safari
操作系统
  • [ ] 他们全部
  • [] Windows
  • [ ] 苹果系统
  • [] Linux
  • [] Android
  • [x] iOS
硬件要求(图形卡,VR设备等)

iPhone 6、8

最有用的评论

我想强调用户zeoverlord的这一部分:

抖动只是浮点数的自然现象,数值越大,变量将失去精度,因此精度越接近1.0越好。 现在,这并不是一个真正的问题,但这确实意味着,如果您要进行大量的矩阵计算,那么精度将大大降低(又称抖动)。 因此,您需要使用合理的数字围绕原点进行所有数学运算,然后将其转换掉

所有113条评论

嗯,您的演示在我的Pixel上看起来不错。

我的iPhone SE上的已确认问题-

img_6324

iOS中的WebGL精度问题

但是iOS设备实际上使用外观实现的基于浮动纹理的代码路径,对吗? 您可以通过以下一致性测试来验证吗?

https://www.khronos.org/registry/webgl/conformance-suites/1.0.3/conformance/extensions/oes-texture-float.html

iPhone SE在该页面上有五个故障。 😕

我做了一个小截屏视频,向您展示了我的项目:
http://cornflex.org/webgl/skin-bug.mp4

如果化身离0,0,0太远,您所看到的皮肤就会开始变得虫洞。
我对骨骼和骨骼进行了深入的分析。 除了几何以某种方式被“拉回”外,其他一切似乎都很好……尽管动画根源很差,但同样,在Threejs中一切都还不错……

这个问题显然与Skinning着色器的Skeleton和bonesTexture关联。
我也谈到精度,但正如Mugen所说,iOS设备应轻松支持这一点。

...为什么只在iPhone上:/

我很困...我将重定向到png序列作为备份计划... :(

这很可能是由于iPhone 6无法支撑足够的骨骼。

我有同样的问题。

在此处检查您的骨骼限制: https :

我不这么认为。
如果skinnedmesh保持在0,0,0,则根本没有问题:/
我什至在考虑移动所有资产,而不是化身...(这是我的解决方法2),但是我当然希望骨架能够像台式机一样工作。

一位朋友刚刚在iPhone 8上报告了相同的错误

在查看ThreeJS的源代码2天之后...我认为更新bonesTexture时可能会出现问题。
看来此纹理未正确铺贴,然后将顶点推回原始位置...但是我当然可能错了。

img_1411

嗯...这里我有些失败了,看:

img_1412

也许问题与这些失败有关。 例如我的像素通过所有测试。

让我们尝试一下:转到WebGLCapabilities并将floatVertexTextures的值设置为false (这将防止使用float纹理)。 进行构建并在您的应用中使用此three.js版本。 我很好奇会发生什么事。

https://github.com/mrdoob/three.js/blob/099e4364541502fdf22fc7b1c0f54239d2ba1708/src/renderers/webgl/WebGLCapabilities.js#L105

已经在渲染器上尝试过floatVertexTextures = false。
皮肤不再发疯了,但是再也没有动画了:/
我将推样品。

这个给你:
http://cornflex.org/webgl/skinning-bug2.html

renderer.capabilities.floatVertexTextures = false;

=>不再运行动画

img_1413

是的,在我的Pixel上也一样(台式机正常工作)。 我想我们正在达到统一的极限。

我做了最后一个示例,错误逐渐出现:
http://cornflex.org/webgl/skinning-bug3.html

从0,0,0开始,一直向前...等待几秒钟...皮肤开始变得疯狂。

很奇怪,在0,0,0都可以。 是不是

z:1255>仍然可以
z:18870>疯狂的皮肤

img_1415

img_1414

如我所说,我对CPU侧的所有骨骼和骨骼位置进行了深度剖析。 所有值似乎都还可以。 我唯一的线索是当网格物体离0、0、0越来越远时,iOS上的bonesTextures和bonesMatrixes无法正常工作。

我检查了骨骼的位置,因为这是根节点的稳定骨骼或诸如此类的事情的典型行为。

我检查了皮肤着色器中GPU端的浮动精度,但再次...似乎没有影响。

非常奇怪的是没有人在场景中移动过SkinnedMesh却从未报告过这个:/

还有一个问题:Chrome是否有相同的问题?

同样的概率。

img_1416

听起来像是一个精度问题。 您是否尝试过缩小场景? (11195是11公里)。

另一种选择是移动场景而不是角色。 倾向于成为大场景的通用解决方案。

另外,我猜想皮肤代码在世界空间中。 我们可以对此进行调查。

我看你的骨数是67。

我的(妻子)iphone 6的最大硬件骨骼限制为27。

我看到的变形与我在游戏中在手机上看到的变形是相同的(以及动画师修复网格物体之前遇到的相同问题)。 如果这不是您问题的至少一部分,我会感到惊讶。

为什么随着时间的流逝会变得更糟? 不知道。 其他人提到了类似的内容,不确定是否相关: https :

我在iPhone上发现的另一件烦人的事情(至少是iPhone 6):我必须使用highp着色器精度,medium和lowp不得以相同的可怕外观扭曲网格(就像我手机上的骨头问题一样),但纹理看起来动画时发生怪异和乱码/像素化。

您要测试的设备的硬件限制是多少?

@mrdoob我已经尝试缩小比例,但是
如果缩小到0.1,则该错误的出现速度会提高10倍。

我在这里用来解释的演示来自threejs示例。
在我的游戏中,比例不是很大,但错误是相同的,只是出现得更快。

的确,蒙皮似乎是在世界空间或局部空间中完成的,但是当远离中心移动时,蒙皮就会变得张紧。 这就是为什么它在0,0,0时运行得很好

移动工作世界而不是化身是我的工作#2。
您必须承认,当您已经使用物理方法和所有方法开发了世界空间中所有跑步游戏的例程时,这是一个错误的选择。 z = 11000对于亚军游戏来说不是那么远:/ ...而且它只是奔跑的人,而不是飞船。

我使用ThreeJS做了大量游戏,但这是我第一次使用skinnedmesh。 这个iOS错误真让人讨厌。

Workaroung#1:我将制作6个png序列作为spritesheet动画。 然后,我可以保留世界空间逻辑。 截止日期不远:(

@titansoftime问题也出现在我妻子的iPhone 8上。 这不仅与iPhone 6有关。
另外,如果您遇到最大骨骼问题,那么从一开始它就是马车。 在这里,您可以看到它不是0,0,0的越野车。 那么骨头的限制不是概率。 蒙皮着色器中骨骼和bonesMatrix的世界空间计算是IMO。

iPhone 8的最大硬件骨骼是多少?

我不知道。 而且我不确定这取决于设备。

但是,再次……IMO,它根本与maxbones值无关。

仅当SkinnedMesh保持在0,0,0时,该示例才能在iPhone 6,8,X ...甚至5 ...上正常工作
https://threejs.org/examples/webgl_loader_fbx.html

如果maxbones是一个问题,那么在0,0,0上我们都不会有很好的蒙皮。

我想强调用户zeoverlord的这一部分:

抖动只是浮点数的自然现象,数值越大,变量将失去精度,因此精度越接近1.0越好。 现在,这并不是一个真正的问题,但这确实意味着,如果您要进行大量的矩阵计算,那么精度将大大降低(又称抖动)。 因此,您需要使用合理的数字围绕原点进行所有数学运算,然后将其转换掉

嗯,非常有趣@ Mugen87! 听起来您发现了泄漏。

z:1255>仍然可以
z:18870>疯狂的皮肤

该错误可能在您这边。
一个常见的错误:皮肤修改器未正确应用。
错误1:受太多骨骼控制的顶点
错误2:没有权重(或权重很小)的顶点。

当SkinnedMesh接近原点(0,0,0)时,您将不会注意到这些错误。
但是,当移动的距离很远时...您会责怪移动设备的精度。
因此,首先要做的是重新设计外观修改器(这次是适当的)。

@RemusMar您是否看过页面的来源?
我公开的示例直接来自ThreeJS来源。

我的描述中提到的很好;)

在发布此消息之前,我进行了许多测试...在动画导出中寻找线索,但是我发现该错误发生在任何格式(GLTF,FBX,Collada,JSON等)中。

我用干净的资源做了一个清晰的例子来揭示问题。 在智能手机上验证它非常容易:

http://cornflex.org/webgl/skinning-bug.html

我公开的示例直接来自ThreeJS来源。

所以呢?

在ThreeJS的所有skinnedmesh示例中发生这种情况时,错误在我这一边怎么可能:)

你说:

该错误可能在您这边。
一个常见的错误:皮肤修改器未正确应用。
错误1:受太多骨骼控制的顶点
错误2:没有权重(或权重很小)的顶点。

FBX来自ThreeJS ...,您可以尝试使用GLTF或任何其他格式。 概率是一样的。

var loader = new THREE.FBXLoader();
loader.load('https://threejs.org/examples/models/fbx/xsi_man_skinning.fbx',OnFBXLoaded);

@ Mugen87找到了一个线索。 让我们希望制作gpu蒙皮网格物体的人能够修复它。

在ThreeJS的所有skinnedmesh示例中发生这种情况时,错误在我这边是怎么回事

我说:“错误可能在您这边。”
底线:
使用带有正确应用的皮肤修改器的简单SkinnedMesh:

  • 每个顶点最多4个骨骼
  • 所有权重= 1.0000

看看是否可以重现该错误。

你生气吗? :)
这个错误不能站在我这一边...模型(fbx,gltf,dae等)和代码源均来自ThreeJS。

请阅读@ Mugen87帖子。

使用带有正确应用的皮肤修改器的简单SkinnedMesh:

  • 每个顶点最多4个骨骼
  • 所有权重= 1.0000

看看是否可以重现该错误。

我得走了。
干杯

嗯你知道什么家伙吗? 这也在台式机上发生:(

由于ThreeJS示例网格非常大(高100m),我将其放置得非常远:z = 10000000
看看,同样的概率:
http://cornflex.org/webgl/skinning-bug4.html

无疑,这与世界空间骨骼位置和bonesMatrix计算有关,如@ Mugen87所公开

https://www.opengl.org/discussion_boards/archive/index.php/t-159613.html
https://www.opengl.org/discussion_boards/archive/index.php/t-159364.html

如之前对@mrdoob所述,我已经尝试过缩小网格的大小,但问题甚至更糟……甚至在台式机上,您遇到的bug距离0,0,0也不远。

在我自己的游戏中(现实比例为1:1),该错误已经出现在z:100处。

您继续使用设计不良的蒙皮网格物体...
无论如何,要结束这个主题,这里是1到1,000,000(一百万!!!)的案例研究:
http://necromanthus.com/Test/html5/Lara_1000000.html
单击舞台以在Y = 0和Y = 1000000之间切换
每个开关可进行较小的全局照明更改。
因此,如果正确设计了蒙皮网格,则结果是(接近)完美的。
干杯

我们将在本月发布后进行调查。

@mrdoob谢谢。

@RemusMar您将继续忽略此处所说的内容。 请再次阅读整个主题:)

我只是给了你一个可行的例子,但你还是不明白。
http://necromanthus.com/Test/html5/Lara_1000000.html

并且您继续谈论不良做法
请记住以下几点:
单精度浮点位数为7。
涵盖1234567和123456.7
大多数的权重图都带有4个小数,但即使是单个小数也可以提供不错的结果。
因此,所有3D引擎的世界尺寸建议最大值为10,000。
从0000.001到9999.999
我们都想要“无限”或巨大的3D世界,但这是不可能的。
从许多角度来看,您在做什么是完全错误的:
游戏设计,表演,动画和碰撞。
希望您现在掌握了主要图片。

可能相关: http

@RemusMar
我很了解您说的内容,但是很遗憾,您的模型也存在同样的问题……程度较低,但仍然存在:
http://cornflex.org/webgl/skin-bug2.mp4

资源:
http://cornflex.org/webgl/skinning-bug5.html

如果我给的位置高于z = 60000,那么情况会变得更糟...直到100000,它是完全不可见的。

我们都想要“无限”或巨大的3D世界,但这是不可能的。

大声笑,我不需要无限的广阔世界……我只想做一个跑步游戏,就像我之前在ThreeJS上做过很多次一样……但是这次我需要一个skinnedmesh作为头像。

我的场景: http :

如果我们无法为超过几米的化身制作动画……那有什么意义呢? (以1m = 1 threejs单位的实际比例,该错误已从100开始出现)。

顺便说一句,您的模型高约150m ...这不是现实的比例。
编辑:
这是模型上具有比例(0.01,0.01,0.01)的同一场景,以使其具有逼真的尺寸(然后约为1.5m)。 如您所见,它已经在移动设备上以z = 300出现错误:
http://cornflex.org/webgl/skin-bug3.mp4

从许多角度来看,您在做什么是完全错误的:
游戏设计,表演,动画和碰撞。

大声笑大声笑...我建议访问我的网站和有关制作游戏的博客(http://quentinlengele.com、http://cornflex.org、http://www.ddrsa.com、http://br9732.com )

编辑:您的场景在iOS(空白屏幕)上不可见(http://necromanthus.com/Test/html5/Lara_1000000.html)。
img_1418

蒙皮似乎是在世界空间或局部空间中完成的,但是当远离中心移动时会变得绷紧。 这就是为什么它在0,0,0时运行得很好

让我们来看看:

vec3 transformed = vec3( position );
...
#ifdef USE_SKINNING
    vec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );
    vec4 skinned = vec4( 0.0 );
    skinned += boneMatX * skinVertex * skinWeight.x;
    skinned += boneMatY * skinVertex * skinWeight.y;
    skinned += boneMatZ * skinVertex * skinWeight.z;
    skinned += boneMatW * skinVertex * skinWeight.w;
    transformed = ( bindMatrixInverse * skinned ).xyz;
#endif

在我看来不像世界空间吗? 在常规网格中,将transformed设置为position属性-即本地坐标。

因此无论发生什么事情,js端都会发生,其中将计算绑定和骨骼矩阵。 也许绑定矩阵会进行很多拉伸,并且可以对骨骼矩阵进行篡改以在绑定矩阵中不需要那么多拉伸的其他坐标中进行操作……

(编辑:nvm,我想我错了)

me

@makc不幸的是,我在蒙皮着色器的复制/粘贴中看不到足够的回收数据来判断该计算是在本地还是世界空间坐标中完成的。

正如我所说,骨骼矩阵的计算肯定存在问题,或者这些矩阵的计算顺序不正确。 正如您在OpenGL论坛上看到的和@ Mugen87所提到的,这是最陈旧的线索,至少对我而言:

抖动只是浮点数的自然现象,数值越大,变量将失去精度,因此精度越接近1.0越好。 现在,这并不是一个真正的问题,但这确实意味着,如果您要进行大量的矩阵计算,那么精度将大大降低(又称抖动)。 因此,您需要使用合理的数字围绕原点进行所有数学运算,然后将其转换掉

再次,如所解释的,对象的规模正在影响该错误。
使用ThreeJS源的示例仅在z = 100000处存在该错误,但这是因为网格的大小(也来自ThreeJS源)很大。 奔跑的男孩身高150m。

当您在做游戏时,您当然不会使用这种规模。 您始终尝试使世界保持1m = 1unit。 为了获得良好的物理和行为,这甚至是必需的。

这里的问题是当您使用具有实际大小的SkinnedMesh时:该错误已经出现在z = 300处。

在任何引擎中,都可以将SkinnedMesh放置在x:30000,y:60000,z:140000000处,并且没有骨头和皮肤的问题。 没有动摇。

我当然很了解,我们在这里正在开发Javascript核心...但仍然如此。

这里的巨魔假装“我们都想要无限的世界,但这是不可能的”,需要回到学校学习矩阵变换。 或者更好地看开放世界的游戏,问他们自己如何将他们的化身“剥皮”,远离场景根0,0,0 ......

我不得不说,这个错误很有趣。 在这里,我可以在桌面上重现它,但是60K不足以耗尽精度:
needs more zeroes

好的,所以在z = 1e8处,这是当前着色器的功能:

screen shot 2018-02-14 at 1 15 56

这就是我们将着色器更改为此的结果(上面编辑的我的头顶测试的细微变化):

#ifdef USE_SKINNING
    vec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );
    vec4 skinned = vec4( 0.0 );
    skinned += ( bindMatrixInverse * boneMatX ) * skinVertex * skinWeight.x;
    skinned += ( bindMatrixInverse * boneMatY ) * skinVertex * skinWeight.y;
    skinned += ( bindMatrixInverse * boneMatZ ) * skinVertex * skinWeight.z;
    skinned += ( bindMatrixInverse * boneMatW ) * skinVertex * skinWeight.w;
    transformed = skinned.xyz;
#endif

screen shot 2018-02-14 at 1 16 54

仍然不稳定,但看起来更好:)现在,在此问题的背景下这意味着什么?

首先,您不能只将此hack复制粘贴到着色器中。 我的意思是,您可以,但是它将1矩阵乘法替换为4。我建议的替代方法是:a)在js侧将骨矩阵与绑定矩阵的逆矩阵合并,并作为单个制服传递,或者b)为此创建另一个制服着色器。 然后,它既可以(一定程度上)解决此问题,又可以减少着色器中矩阵乘法的次数(减少1)。

哦,还有

巨魔在这里假装“我们都想要无限的世界,但这是不可能的”

我认为他们想说的是,您可以解决问题而无需将库固定在身边。 没有必要,但可以。

@makc非常感谢您的
不幸的是,为时已晚。 我必须星期五送货。 我使用PNG序列作为解决方法。

如果要对此进行足够深入的调试。 您可以尝试使用实际的网格尺寸吗?
同样,如果我记不清楚的话,这个劳拉模型也高约60m。

当然,我很好奇您的补丁是否也可以在实际规模上工作:)

哦,...您是否正在iOS下进行测试?
如本主题所述,这主要发生在iOS设备上(6,8)。
在桌面上,只有非常非常大的值才会带来问题。

再次感谢

@OrtOfOn您可以通过在代码顶部添加以下内容来尝试@makc修补程序:

THREE.ShaderChunk.skinning_vertex = `
#ifdef USE_SKINNING
    vec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );
    vec4 skinned = vec4( 0.0 );
    skinned += ( bindMatrixInverse * boneMatX ) * skinVertex * skinWeight.x;
    skinned += ( bindMatrixInverse * boneMatY ) * skinVertex * skinWeight.y;
    skinned += ( bindMatrixInverse * boneMatZ ) * skinVertex * skinWeight.z;
    skinned += ( bindMatrixInverse * boneMatW ) * skinVertex * skinWeight.w;
    transformed = skinned.xyz;
#endif
`;

THREE.WebGLShader:Shader无法编译。 :/

patch

天啊。 您最终得到错误的引号和单行格式。 您如何复制粘贴?

另外,我有点想看这些古怪的图像,这满足了我的好奇心。 我相信别人会从这里拿走:)

@makc CTRL + C / CTRL + V ...从这里开始...:/

不幸的是,该漏洞没有以前那么强大,但仍然存在:(

在iOS上测试(已应用补丁):

网格尺寸为1.0(化身精确约20m高),位置z = 10000
http://cornflex.org/webgl/skin-patch1.mp4

网格尺寸为0.1(头像约2m高),位置z = 3000
http://cornflex.org/webgl/skin-patch2.mp4

@mrdoob我将尝试重现:)它出现在一行中。 当我看到您的回复突然出现时,我正在页面上书写,但它并没有像通常那样出现,我保证:p ...我将获得这些加分,您将看到:)

编辑:顺便说一句,您编辑了您的帖子? :)

我相信残留效果可能与蒙皮无关,实际上会影响所有内容,但是您没有注意到,因为没有动画。

@OrtOfOn在您的位置,我会尝试将您的整个场景(用相机)包装在额外的Object3D中,并将此对象坐标设置为每帧-1 *头像坐标。 这将使其永远保持在0,0,0的世界坐标中。

@markc我真的不喜欢这样作弊。 游戏玩法和场景并非旨在像这样折磨,而且作为移动第一款游戏,性能当然必须是最佳的。

另外...不是我的情况,但可以想象来自各个地方的SkinnedMesh中的几个敌人...

我别无选择,因为最后期限让我用Spritesheet动画替换了SkinnedMesh(客户端可以)。 否则我只会遇到类似的事情。 我几乎在每个Web项目中都使用ThreeJS,对此我感到非常满意。

我们不需要“无限世界”,但我们希望能够在世界空间坐标中使用这些漂亮的SkinnedMesh和动画功能,就像在著名引擎中一样:)

我有点失望……因为我基于交叉淡入淡出功能制作了一个很酷的Animator脚本,并受到了mecanim的启发。

@markc我真的不喜欢这样作弊。

我认为这根本没有作弊。 这就是所有空间模拟的工作方式。 实际上,实时3D渲染基本上会偏移整个场景,因此中心就是摄影机所在的位置。

@mrdoob是的,我知道相机甚至不存在。 矩阵的力量:)(我自己做了一些本地WebGL / OpenGL开发人员)。

无论如何,将所有场景都放入游戏对象中对我来说似乎有些无聊……尤其是要使蒙皮动画生效。

@OrtOfOn实际上您可以使用场景本身。 例如在劳拉示例中,执行以下操作:

scene.add(camera);
scene.position.z = -60000;

没关系(编辑:但是,执行此操作时灯光有些问题.... @mrdoob吗?)

@makc再次感谢您提出补丁。

我根本不想变得悲观,但是有一些事情告诉我,通过这种操作,照明不是唯一的问题。 这就是为什么我称这些技巧和作弊为原因,因为结果的不确定性以及对管道其他部分的后果。

不幸的是,制作游戏的人具有物理学,光线投射器,粒子等……很多东西都是经过设计的,必须将它们设计成具有现实比例的世界空间。

另外,我很好奇看到这些补丁与多个SkinnedMesh一起运行时,就像敌人在场景中的某些地方隐藏或生成一样。 因为限制在0,0,0的单个skinnedmesh化身有什么意义呢?

我将尽快深入研究源代码,但我必须在2天内交付一些内容……因此,希望现在我的Spritesheet动画效果还不错。

因为限制在0,0,0的单个skinnedmesh化身有什么意义呢?

关键是您极不可能同时渲染外观为0,0,0的皮肤和另一外观为z = 60000的皮肤。 0,0,0周围只有很少的皮肤可以进入屏幕,并且它们的距离不足以触发该错误。

@makc同样,您的补丁程序在台式机上也有效,但是您没有在iOS设备上测试该情况,在实际缩放网格中,该错误已经出现在距0,0,0几米处的位置。 我向它展示了足够的视频。 例如,此代码仅在z = 100时显示错误:/
http://cornflex.org/webgl/skin-bug.mp4

您是否一直在游戏中使用身高20m的化身? :)
因为您关注的数字(60000)仅用于暴露台式机上的错误(具有非常大的lara或庞大的threejs fbx示例)...而不能用于移动设备。 而且我的头像当然不会走那么远...

我确认这是iOS问题。 自从至少6S / 6S +世代以来,iOS一直存在floatVertexTextures的问题。 我们一直在使用的修复方法是在iOS上禁用该功能。 这限制了我们可以使用的骨骼,但是无论如何我们都必须限制它们以支持更糟糕的手机。

由于iOS设备未通过@ Mugen87发布的一致性测试,因此默认情况下,最好在iOS上禁用floatVertexTextures或什至floatFragmentTextures,因为它显然不能正确实现广告支持的功能。

@ daniel-nth我想这很有道理。 但是... @OrtOfOn表示z = 60K可以在台式机上重现问题... 60K的台式机我没有任何问题,只有1e8足以让我“重现”。 因此,也许这个问题实际上至少是3个独立的问题:

  • 在iOS上浮动纹理,
  • @OrtOfOn桌面上的60K的东西,
  • 由于骨骼着色器位(我在上面弄乱的那个)的矩阵乘法顺序不正确,导致1e8的精度用尽,
  • 顶点着色器中可能还有其他内容,因为女孩在贴片之后仍然有些发抖。

嗨,大家好,
首先,感谢您回到此错误。 我仍然没有时间去挖掘它:(

@ daniel-nth对象的规模正在影响该错误:

在iOS上,使用这个非常大的“ Lara”对象(高度= 120,比例= 1),该错误确实出现在z = 60000处。 但是,如果您采用实际大小的网格(高度= 1.8,比例= 1),则它仅会出现在z = 100处。

Skinnedmesh越大,翻译必须进一步以查看错误。

正如已经在该线程中进行测试和报告的那样,在iOS结果上禁用floatTextures根本没有皮肤。

我还怀疑骨骼矩阵的矩阵乘法错误或条形乘法。

在iOS上,使用这个非常大的“ Lara”对象(高度= 120,比例= 1),该错误出现在z = 60000

@OrtOfOn等一下,在ios上呢? 但是你也说:

您关注的数字(60000)仅用于暴露台式机上的错误(具有非常大的lara或庞大的threejs fbx示例)...而不能用于移动设备。

在iOS上,使用这个非常大的“ Lara”对象(高度= 120,比例= 1),该错误确实出现在z = 60000处。

它根本不大。
而且您仍然不了解模型大小与世界规模之间的关系。
最后一次:
http://necromanthus.com/Test/html5/Lara_1000000.html
现代高度大约= 75,世界范围= 9,999,999。
从Z = 0到Z = 1,000,000(一百万!!!)
因为单精度浮点数字的位数是7,所以根本没有小数!
它可以在我拥有的所有笔记本电脑和台式机上完美运行。
更:
它可以在Android 6和7以及各种三星手机上完美运行。

lara_1000000

在您的示例中, @ RemusMar将其输入到控制台中:

camera.position.z += 1e8;
scene.children[2].position.z += 1e8;

您将看到以下内容:
screen shot 2018-03-03 at 15 48 53

screen shot 2018-03-03 at 15 51 41
真是令人毛骨悚然

我给你z = 1e6看起来也不错。 1e7左右已经很明显了,而1e8简直是疯了

@OrtOfOn在iOS上,将capabilitys.floatVertexTextures设置为false

我给你z = 1e6看起来也不错。 1e7左右已经很明显了,而1e8简直是疯了

我知道,但是对于这些值,您不够精确。
对于蒙皮的网格顶点权重精度,最大世界尺寸为9.999.999
这意味着最大距离为几百万,仅此而已。
干杯

@makc确实,我为台式机输入了错误的数字。 它必须非常大,您是对的,事实上我早些时候在线程中提到过:/ https://github.com/mrdoob/three.js/issues/13288#issuecomment -364650679

@ daniel-nth很高兴知道,但是您确定吗? 这是我在此线程中进行的测试,使用了threejs来源的3d模型。 您仍然可以查看代码。 @ Mugen87也做出了相同的反馈,该模型没有动画。 https://github.com/mrdoob/three.js/issues/13288#issuecomment -364572653

哦,我看到模型不存在了。 网址为https://threejs.org/examples/models/fbx/xsi_man_skinning.fbx上的404

@ daniel-nth如果您使用的骨头较少的新型号,那么我相信您;)

@RemusMar Quite与您同意最新文章中提到的距离。 数字(1e6,1e8,1e9,...)肯定会导致精度下降。 毫无疑问。 但是请停止拖曳我。 不要假装我什么都不懂,问问自己,身高为120的头像网格是否不大。 对我来说,它非常庞大,在Gamedev中不能与其他由艺术家,射线广播,物理,照明等现实可缩放比例的对象一起使用,并且要在3周内交付。

我坚持认为:以公制单位保持现实规模的资产是正确构建基于物理的游戏的必要条件:)

太糟糕了,在iOS上,在这些现实的比例条件下,我的头像无法运行超过100m:/

更新:无论如何,@ daniel-nth似乎告诉我们它现在正在关闭floatTextures,并且骨骼数量非常有限。

但请不要再拖钓我
我坚持认为:以公制单位保持现实规模的资产是正确构建基于物理的游戏的必要条件:)

我不是在骗你。
但是1.5单位并不意味着1.5米
干杯

@OrtOfOn

我坚持认为:以公制单位保持现实规模的资产是正确构建基于物理的游戏的必要条件:)

但是这个标度是一些任意的自我施加值。 您也可以决定使用厘米,然后“高度为120的头像网格”实际上小于平均值。

@makc当然可以,但是物理引擎/库希望您使用度量值。 您是否已经尝试过对比例对象或非度量值进行物理处理? 开发变得非常糟糕,您会得到意想不到的不切实际的结果。 您的所有部队也必须进行审查和调整。 它将起作用,但不准确。

当然,这取决于您需要达到的精度水平,并且诸如1e6、1e7等值太大,并且会出现精度问题。 而且您永远不需要将skinnedmesh移得那么远。 我们对此表示同意。 但是,在iOS上,我们应该至少能够将gpu skinnedmesh(高1.5个单位)移动几百个单位。

但是物理引擎/库希望您使用指标值。

这不是真的。
米,厘米,英寸等无关紧要。
正如我之前(几次)所说,重要的是世界的大小(比例)和准确性。
请注意以下几点:
如果您的蒙皮网格物体的高度= 1.5个单位,则顶点权重图将强制您至少使用2-3个小数。
对于物理引擎(如果有),您可能需要3-4位小数才能获得可接受的结果。
如果全局精度要求小数点后4位,则您的最大世界大小为999(因为单精度浮点数为7)。
换句话说,如果您要获得体面的动画和体面的物理效果,则可以使用几百个距离。
希望这次您能了解整个情况。
干杯

@RemusMar我会在这里停止。 似乎您不想或不想在iOS设备上测试您的情况。 您不能在具有gpu skinnedmeshes的设备上使用“几百个距离”。 网格很快变得疯狂。 这就是该主题的重点,我只想在开始时进行报告。 就是这样了。

我希望您得到这样一个事实,即您的所有主张和示例都无法在iOS设备上运行,正如此处其他人和我的屏幕截图所报告的那样:/

您不能在具有gpu skinnedmeshes的设备上使用“几百个距离”。

你又错了。
请参见上面的屏幕截图(Android 7-三星手机)。
模型高度= 75(边界球半径约38),距离1,000,000(一百万!!!)
或模型高度= 1.5,距离为20,000。

ps
我的问题不是iOS始终是错误的集合。

@RemusMar我没错,你是巨魔。 我说的是iOS,而你说的是另一台设备...你生气了吗?

如果您如此讨厌苹果,那不是我的概率。 当我的一位客户想要用ThreeJS完成基于3D网络的游戏时,我不告诉他“用你的iphone操你”……如果你这样做,我为你感到抱歉。

传输结束在这里...我不能再继续了。

@OrtOfOn是的,我使用的模型有19条骨头,404 fbx有67条骨头。

https://github.com/mrdoob/three.js/issues/13288#issuecomment -364550036包含指向显示统一骨限制的页面的链接。 该页面使用的公式是Math.floor((data.webgl.params.MAX_VERTEX_UNIFORM_VECTORS - 20) / 4);不知道three.js是否100%准确,但是即使在iPhone X上它也报告27,不幸的是,它甚至不到Galaxy S3的一半,但是对于移动WebGL游戏。 我快速浏览了我的工作文件夹,并在26个WebGL项目中,只有一个模型具有更多骨骼,并且该模型保持为0,0,0。

@OrtOfOn :我在固定场景中遇到类似的问题,并且在场景中四处移动皮肤角色。 角色在ios上非常抖动。 骨骼数为22。场景的尺寸是合理的。 我相信问题在于,使用顶点纹理会将您限制为32位浮点数,再加上上面的断言,Threejs计算了世界空间中的蒙皮!

我现在正在研究世界空间断言,并希望将实现正确的方法来计算局部空间中的顶点位置,然后平移对象-应当如此。 我从未听说有人使用蒙皮将对象放置在世界空间中,因此我不确定实现者为什么会这样做。

如果有解决方案,我会回发。

只是因为,iOS上的浮动纹理不仅被顶点着色器破坏了。 我最近将浮动纹理更改为整数纹理,以修复ios上的色带,因此这是普遍的ios问题。 如果您确实想要的话,也可以使用整数纹理来固定ios上的骨骼-这是别人的着色器的相关代码段:

vec2 encodeFloatRG( float v )
{
    vec2 kEncodeMul = vec2(1.0, 255.0);
    float kEncodeBit = 1.0/255.0;
    vec2 enc = kEncodeMul * v;
    enc = fract (enc);
    enc.x -= enc.y * kEncodeBit;
    return enc;
}

float decodeRGFloat( vec2 enc )
{
    vec2 kDecodeDot = vec2(1.0, 1.0/255.0);
    return dot( enc, kDecodeDot );
}

...实际上,如果您接受ios precision作为全局精度限制并在纹理中存储两个float而不是一个,那么您可能(我在这里假设,并没有真正尝试类似的事情)也可以使float骨骼纹理起作用

我已经通过让threejs在本地空间(它所属的地方)中进行蒙皮计算,并通过世界空间矩阵以标准方式将模型转换为现实坐标,从而完全解决了该问题。

上面的问题已完全修复,可以在iOS上换肤。 我还应该指出,该解决方案是通用的-在所有台式机浏览器以及经过测试的Android设备上均可完美运行。 在几乎所有情况下,恕我直言,局部空间换肤都是正确的方法,并且此方法应该是ThreeJS的默认设置。 @mrdoob :您对此有何看法?

mesh = new THREE.SkinnedMesh(geo.geometry, mat);
mesh.bindMode = 'detached';
var skel = new THREE.Skeleton(bones, boneInvs);
var bsm = new THREE.Matrix4().fromArray(geoPrims.bsm);
mesh.bind(skel, bsm);

// make bsmInv identity for models that have multiple skins
mesh.bindMatrixInverse = new THREE.Matrix4();

// patch SkinnedMesh's updateMtxWorld:
// we're using local skinning, so don't keep resetting binMatrixInverse (leave identity)
// the reason we're using .bind here is for models that have more than one skin
mesh.updateMatrixWorld = PatchSkinnedMeshUpdateMW.bind(mesh);

// re-normalize since input data has been compressed
mesh.normalizeSkinWeights();

// remove bone roots and add to bone root list
for (var bi = 0, bl = bones.length ; bi < bl ; bi++) {
    if (bones[bi].parent && !bones[bi].parent.isBone) {
        bones[bi].parent.remove(bones[bi]);
        boneRoots.push(bones[bi]);
    }
}

应该在哪里将“ boneRoots”添加到根场景对象(以便它们获取矩阵更新,但不继承导致实际skinnedmesh的层次结构中的所有矩阵)。 将这些boneRoots添加到场景根(代码未显示)。

这是用于替换threeJS的SkinnedMesh实现的补丁(请注意,这仅是必需的,因为Threejs的updatematrixworld破坏了我们希望保留为身份的bindMatrixInverse)。 或者,您可以直接绑定到THREE.Mesh..prototype.UpdateMatrixWorld,而无需使用修补程序功能。

function PatchSkinnedMeshUpdateMW( force ) {
    THREE.Mesh.prototype.updateMatrixWorld.call( this, force );
}

@ denbo-ft我认为这对我来说很好。 您要为此创建PR吗?

@ denbo-ft非常感谢您的努力。 抱歉,我无法再关注此帖子了。

我们的产品中也存在这个问题-任何浏览器(如果您距离0,0,0都足够远),但在iOS上更明显,因为它距您大约2-3个单位就会发生。 对我们很关键,但至少当我们看到这一点时,我们会很开心
image

好吧,似乎有更多的人需要这个。 我从未为github开源项目做过任何贡献,但我对git熟悉并且将尝试创建PR。 :)

同样在这里。 我的SkinnedMesh看上去就像是iPhone专业治疗师Katz博士的一集。

仅供参考,我从5月21日起的帖子将提供完整的解决方案。 ThreeJS源代码没有太多修复程序-大多数修复程序属于您的单个项目的加载器和/或场景设置代码。

基本修复方法是使用“分离”模式(未记录,顺便说一句),并将骨骼层次结构放置在根场景级别的场景中-不在实际的可渲染角色层次结构中。 然后从引擎(SkinnedMesh.update)修补一件简单的事情,您应该会做得很好。

编辑:
我们为TJS提供了完全自定义的文件格式和加载程序,因此,不幸的是,为了通过示例解决方案创建完整的PR,我必须修复其中一个罐装加载程序(例如Collada)。 我现在会考虑这样做

谢谢,我将花一些时间尝试理解并以更通用的方式应用您的解决方案(您的项目似乎有些特定)。 您能否为代码共享更多上下文?

Katz博士,专业治疗师

我什么也没迷,但是该死

编辑:

我已经成功创建了一个拉取请求-让我知道我还有什么可以做的。

原始帖子:

我有一个本地分支,但有更改,但似乎无法推向原点。 即使提供我的github信誉,我也会收到此错误:

推送到https://github.com/mrdoob/three.js.git
远程:拒绝denbo-ft对mrdoob / three.js.git的许可。
严重:无法访问“ https://github.com/mrdoob/three.js.git/ ”:请求的URL返回错误:403

希望得到一些建议,因为这是我对github的第一项贡献。 谢谢!

仅供参考,如果PR适用于mrdoob并已集成,则存在支持此更改的新绑定模式“本地”。 我不想修补或更改未记录的“分离的”绑定模式,因为没有迹象表明谁在使用它,我也不想破坏我不知道的东西。 但是在我看来,它可能是为此目的而设计的。

所有binMode =“ local”都不会在更新过程中更改bindMatrixInverse,这与“ detached”不同,后者将其重置为bindMatrix的逆数,而不是保持身份不变。

请参阅此PR中的webgl_loader_collada_skinning.html示例,以查看场景级别必要的一些更改,以便对在场景中移动的角色获得适当的本地外观。

突击队员DAE加载程序演示用于测试此修复程序。 在这些测试中,角色从原点移开了2000个单位。 下面的截图。

下面的照片来自iPhone X / Safari 11

进行此更改之前(在2000、2000、2000年):
img_0658

更改之后:
img_0659

您是否认为有一种方法可以在不使骨骼处于根场景层和(0,0,0)的情况下实现这一目标? 我正在用骨头将东西附加到头像上,使其看起来像点,等等。我想我不是唯一的一个

您有两种选择:

1)如在threejs中所实现的那样,将骨骼留在世界的根中以从局部蒙皮中受益。 如果您绝对需要将武器附加到骨骼上,例如将其带入虚拟角色空间,则进行额外的变换。

2)将骨骼保留在头像空间中,并在ios上变形。

我肯定会做#1。 当您已经具有骨骼位置和角色位置时,始终可以进行数学运算来确定可附加对象在任何给定帧处的位置。 但是,#2没有解决方法,因为翘曲是由在iOS设备的HAL级别打包引起的,您对此无能为力。 当然,您可以通过尝试使用上述各种HalfWord包装等方式来添加其他技巧,但它们都可以减轻问题,而不是使问题消失。 如果您在本地空间中进行蒙皮,则ios上的蒙皮问题将完全消失(更具体地说,使骨骼以世界原点为中心,以使数字尽可能小)。 然后将xform插入字符空间以进行附件。

更多信息:

在TJS中实现它的方式的问题不是TJS特有的,而是为了解决由于每个着色器程序的制服数量受限制而导致的骨骼限制问题,正在使用BoneTextures。 这是非常标准的解决方案。 但是,在iOS上,纹理中的浮点被量化(打包/压缩)成小于32位的大小。 当数字的大小/幅度为“大”(即几百以上)时,这会导致字符的“螳螂”或其他古怪的效果。

好的,我们现在要做什么? 好吧,游戏的每个重要功能(实际上是游戏引擎)通常都需要一个实践标准。 示例:告诉艺术家将角色的起源放在中心位置。 将角色的根节点放在脚/地面上,以特殊方式绘制骨骼和皮肤。 然后编写一个知道您的处理规则的导出器(或TJS情况下的导入器)和一个导入器。 然后在加载具有此配置的资产时在引擎中支持最终功能。 这就是我们在游戏行业中做事的方式。

期望任何创作方法,任何文件格式和任何通用加载程序都能完美地处理游戏的所有功能,这是难以控制和不确定的(对游戏开发而言都是很糟糕的事情)。 整个过程中必须有一些标准和流程。

如果您的角色使用蒙皮,并且还需要附加地理信息以获取武器或其他东西,请考虑一下引擎完全蒙皮所需的内容,然后使用该蒙皮。 我提供了一个这样的解决方案作为示例。 不幸的是,PR未被接受,因为他们出于某种原因不想更换装载机。 无论如何,我希望我已经解释了问题,上面线程中的解决方案以及我提交的PR。

我对这方面的贡献实在无法超过。 我希望我已经帮助了一些人...

祝好运!

如果您在本地空间进行蒙皮,则ios上的蒙皮问题将完全消失

正如我从一开始就说的那样,这是解决iOS限制(错误)的方法,您必须为此浪费处理能力。
那不是解决方案!
真正的解决方案是提高iOS上的浮点精度(达到7位数的正常值)。
http://davenewson.com/posts/2013/unity-coordinates-and-scales.html

@ denbo-ft我实际上实现了您的PR(我们有我们自己的装载程序),因此感谢您的贡献。 我希望有另一种方法,因为我们的场景中有多个化身,它们会四处走动,抓取物品,彼此互动等。将骨骼设置为0,0,0会迫使我们更改很多东西代码,冒新问题等风险。

我花了一些时间思考这个问题,但是并没有提出更好的解决方案。 (仍然在尝试)

@RemusMar

真正的解决方案是提高iOS上的浮点精度

也许有人应该第一时间问@grorg和co,那里的浮动纹理处理了什么,怎么会这样呢? 因为我感觉这不仅是错误,而且是苹果针对其他问题的“解决方案”

我觉得这不仅是一个错误,而且是苹果针对其他问题的“解决方案”

可能是真的。
与Firefox Android上的问题类似:已报告错误,由开发人员验证,但在过去5个月(2个发行版)中未解决!

这几天软件开发的工作方式如下:
而不是在正确的位置进行修复,第3方中有解决方法。
最终结果:错误,浪费的资源和过时的软件的集合!!!

@jfcampos
我建议将骨骼层次结构保留在根中,并简单地添加一个函数,通过将其乘以虚拟角色实际位置矩阵的martixWorld来获取任何骨骼的最终WS位置。 它非常简单,可以将修复前的内容带给您。

或者,如果您有印章,则可以返回到原始方法(带有bug),将局部矩阵包含在骨骼纹理中,使其纹理使用量增加一倍,然后修改着色器片段以在蒙皮过程中对gpu进行额外的计算。 请记住,尽管从代码角度来看,这种解决方案“更干净”,但每帧上载到GPU的纹理数量却翻了一番(可能是四倍),因此效率比上面的建议低得多。 但是无论出于什么原因,我都不知道,以这种方式进行操作可能对您更有利。

从以前没有的解决方案开始,现在这里有几个选项可以与ALL设备兼容,这对于大多数项目来说显然是必需的。

似乎我必须在0,0,0处使用骨骼,并对其他内容进行一些额外的矩阵计算。 谢谢!

@ denbo-ft是正确的。 这是由于世界空间蒙皮引起的Three.js问题。

作为参考,这是对world-space-skinning进行更改的地方: https :

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

jlaquinte picture jlaquinte  ·  3评论

boyravikumar picture boyravikumar  ·  3评论

fuzihaofzh picture fuzihaofzh  ·  3评论

Bandit picture Bandit  ·  3评论

zsitro picture zsitro  ·  3评论