Three.js: 法线在具有双面材质的网格的某些部分上翻转

创建于 2019-10-23  ·  36评论  ·  资料来源: mrdoob/three.js

问题描述

从107升级到108,我注意到模型的某些部分现在看起来像是翻转了法线。 这仅在双面材料中发生。
看到这里: https :

这是应该看起来像的样子,两个车轮上都有凹痕。 那就是107年的样子
Screen Shot 2019-10-23 at 3 51 35 PM

在108个轮子中,有一个看上去像是突然冒出来的:
Screen Shot 2019-10-23 at 3 51 27 PM

Three.js版本
  • [x] r108
浏览器
  • [x]全部
操作系统
  • [x]全部
  • [] Windows
  • [ ] 苹果系统
  • [] Linux
  • [] Android
  • [] iOS
Bug Regression

最有用的评论

修复它!
Screen Shot 2019-11-21 at 10 02 54 AM

所有36条评论

@pushmatrix您可以确认此模型是否提供自己的切线吗? 我很好奇这是否与#11438有关。

我不认为它指定了自己的切线

使用不同的测试用例,git bisect指向#17586作为PR,如果网格是双面的并且具有负比例X,则会引发问题。但是,这在r.109中,而不是r.108中。

未在此PR的模型上对此进行测试,因为该模型不可用。

这是测试玻璃
wheels.glb.zip

从3年前开始: https :

基本上看来,... gl_FrontFace在Adreno GPU上无法使用双面材料正常工作。

这是我们需要解决的一个问题吗?

//

如果我们删除normalmap_pars_fragment中的Adreno解决方法,此模型似乎可以在我的机器上正确渲染:

#ifdef DOUBLE_SIDED

    // Workaround for Adreno GPUs gl_FrontFacing bug. See #15850 and #10331

    bool frontFacing = dot( cross( S, T ), N ) > 0.0;

    mapN.xy *= ( float( frontFacing ) * 2.0 - 1.0 );

#else

    mapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );

#endif

嗯,我也记得读过那条评论; 我认为我在查看此错误时遇到了它,该错误显然已在r108中修复(至少是升级为我们修复了): https :

也许是相关的? FWIW,我收到了有关旧Adreno GPU的一些反馈,因此显然它们仍然相当普遍。

只是为了确认,这仍然会在dev

Screen Shot 2019-10-25 at 4 06 51 PM

只是为了确认,这仍然发生在dev中:

对。 但是,如果您删除Adreno错误解决方法,则不会。

但是,如果您删除Adreno错误解决方法,则不会。

现在如何删除解决方法,然后搜索其他解决方案? 无论您使用哪种平台,当前的实现都会导致错误的视觉效果。

@ Mugen87在这种特殊情况下,我相信几何形状是彼此的镜像,但是它们共享相同的法线贴图。

我同意你的看法。 我花了很多时间试图找到与Adreno兼容的解决方法,该解决方法在每种用例中都是正确的。

检查车轮模型模型,每个车轮都有自己的UV壳。 它不共享一个。
与顶点顺序相反。

但是,至少在Blender中,脸部方向是相同的。

Screen Shot 2019-11-18 at 11 21 05 AM

因此,我不确定这是r108中的错误还是r108现在运行正常。 ¯_(ツ)_ /¯

可以将

@mrdoob

搅拌机2.8

Screen Shot 2019-11-20 at 8 27 27 AM

统一

Screen Shot 2019-11-20 at 8 40 30 AM

Sketchfab

Screen Shot 2019-11-20 at 8 32 48 AM

@pushmatrix

很难看到Unity,因为光线与相机的方向相同,但是看起来Unity也错了吗? 🤔

@mrdoob

是的,它确实取决于照明,最终变成一种幻觉,看起来好像在某些地方突然出现了。 但是,当您旋转时,它消失了。

换个角度看,这里看起来正确
Screen Shot 2019-11-20 at 2 36 16 PM

@mrdoob正面在three.js中具有逆时针缠绕顺序。 通常,每个面的3个顶点的UV在UV贴图上也具有逆时针缠绕顺序。

在此示例中,我的_conjecture_是左侧的模型具有逆时针UV,而右侧的模型具有_clockwise_ UV。 当doubleSidetrue时,正确的模型在Three.js中呈现不正确。

AFAIK,删除Adreno解决方法可解决非Adreno GPU的问题。

@pushmatrix您的Unity示例似乎具有来自两个方向的定向光。 这使得很难识别正在发生的事情。 单个灯可能是优选的。

@WestLangley我正在使用与模型查看器相同的环境贴图,但可能没有相同的旋转角度。 我会尝试一盏灯。

@WestLangley旋转的单向光。 我觉得我在看错觉

unity

似乎Unity会根据光线的照射方式使凹槽弹出和弹出,但至少两者是一致的。

Threejs也是一致的,但是肯定会弹出:
wheels

我觉得Unity里有什么问题...
喜欢它需要一些东西。 material.normalMapScale.x = -1

@WestLangley

@mrdoob正面在three.js中具有逆时针缠绕顺序。 通常,每个面的3个顶点的UV在UV贴图上也具有逆时针缠绕顺序。

在此示例中,我的_conjecture_是左侧的模型具有逆时针UV,而右侧的模型具有_clockwise_ UV。 当doubleSidetrue时,正确的模型在Three.js中呈现不正确。

AFAIK,删除Adreno解决方法可解决非Adreno GPU的问题。

谢谢,这很有意义。 我认为它仍然值得更多的调查。 如果Sketchfab在所有设备中看起来都是正确的,我们可能必须查看其着色器。

今天,我看了看各自的着色器代码,看来它们没有使用“每像素切线空间法线贴图”。

根据这篇文章,Sketchfab期望资产中的切线定义,或者这些数据是
根据uv坐标生成。 这与我在GLSL代码中看到的相对应。

如果我通过BufferGeometryUtils.computeTangents()将切线添加到模型并将Material.vertexTangentstrue ,则结果似乎很好:

image

顺便说一句:可以在这篇文章中分享来自Sketchfab的代码片段^^吗? 毕竟,它不是开源的。

为了保持一致性,以下是Sketchfab的1个定向光来回移动:

sketchfab

是的,要记住的一件事是,当您上传模型时,Sketchfab确实会在其末端进行处理,因此很有可能它们会生成事物/更改事物。 您正在查看的不是glTF,而是转换成其自身格式的glTF文件。

@pushmatrix您可以_please_证明#17958适用于您的模型吗?

three.js在片段着色器中计算切线。 我认为,如果删除了容纳某些错误的Adreno GPU的黑客程序,它就可以正常工作。 请参阅#17958。

//

当需要切线而不是模型提供切线时,Sketchfab会在CPU上计算切线。 ( @donmccurdy这是glTF规范要求的。)

three.js也可以做到这一点,但这将意味着向所有内置几何图形添加正确的切线。 three.js还必须实现MIKKTSpace算法来替换ComputeTangents() 。 由于three.js支持索引和非索引几何,因此我预计这将需要大量的工作。

修复它!
Screen Shot 2019-11-21 at 10 02 54 AM

好的,看起来这里的解决方案是还原Adreno解决方法(#17958),并建议人们在模型没有切线且目标是支持Adreno GPU(#15850)时使用BufferGeometryUtils.computeTangents()

听起来不错?

另一个解决方案是在未提供时自动在引擎中调用BufferGeometryUtils.computeTangents()并删除所有在片段着色器中计算切线的代码...🤔

BufferGeometryUtils.computeTangents()当前需要一个索引,因此不能在核心中使用。 但是,我认为,如果three.js可以在某些时候根据MIKKTSpace生成切线,然后删除perturbNormal2Arb() ,那将是更好的选择。

@WestLangley写道:

这意味着向所有内置几何图形添加正确的切线。

改变主意...切线不是必需的。 取而代之的是,我将还原方法BufferGeometry.computeTangents()并针对所有内置几何“覆盖”该方法,我们可以通过分析来设置精确的切线。

//

另一个解决方案是在未提供时自动在引擎中调用BufferGeometryUtils.computeTangents()并删除所有在片段着色器中计算切线的代码...

对我来说听起来不错。

BufferGeometryUtils.computeTangents()当前需要一个索引,因此不能在核心中使用。

我认为这很容易解决。 并且必须对其进行修复以支持https://github.com/mrdoob/three.js/issues/17804#issuecomment -557135610。

如果three.js可以根据MIKKTSpace在某个时候生成切线然后删除perturbNormal2Arb()...

我不知道MikkTSpace是否一定要替换片段着色器计算。 该着色器几乎没有性能成本,并且可以在大多数型号上正常工作。 预先计算切线每次都具有每个顶点的前期成本,除非在这些特定情况下,否则没有任何好处。 the尽管glTF规范说了什么,但我很难证明默认情况下这样做是合理的。

如果BufferGeometryUtils.computeTangents可以实现MikkTSpace方法,那就太好了-如果您必须预先计算它们,那是最好的算法。 但是将MikkTSpace放到glTF-Pipeline或gltfpack之类的工具中可能会更容易,它们可以使用现有的本机实现,并且可以离线预先进行计算。

@donmccurdy

但是,说...在<model-viewer>用例中,我认为没有一种可靠的方法可以知道用户是否拥有Adreno GPU,但我们希望看起来正确(https:// github。 com / GoogleWebComponents / model-viewer / issues / 740)。

如果未提供切线, <model-viewer> (以及其他需要x-gpu支持的项目)应该调用BufferGeometryUtils.computeTangents还是三?

@pushmatrix

哈哈,我刚刚意识到这些轮子来自哪里

https://bumbleride.com/products/era?variant=20719969599599

Screen Shot 2019-11-22 at 3 52 19 PM

@ mrdoob🕵

好的,让我们暂时恢复解决方法。

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

相关问题

zsitro picture zsitro  ·  3评论

ghost picture ghost  ·  3评论

yqrashawn picture yqrashawn  ·  3评论

fuzihaofzh picture fuzihaofzh  ·  3评论

danieljack picture danieljack  ·  3评论