【问题标题】:Multi-pass accumulative rendering in three.jsThree.js中的多遍累积渲染
【发布时间】:2018-09-08 21:13:08
【问题描述】:

我已经编写了代码来渲染包含像投影仪一样工作的灯光的场景。但是它们有很多(在单个着色器中可以用固定数量的灯光来表示更多)。所以现在我通过创建一个自定义着色器并为每个灯光渲染一次场景来渲染它。每次通过片段着色器确定该光的贡献,并且混合器将该贡献添加到后缓冲区。我发现在three.js中设置这真的很尴尬。我找不到像这样进行多次通过的方法,因为不同的通过需要不同的材料和不同的几何形状。我必须通过多个场景来做到这一点。那里的问题是我不能有一个在多个场景中的object3d(如果我错了,请纠正我)。所以我需要创建对象的副本——它所在的每个场景都有一个。这一切都很快开始看起来很hacky。太特别了,好像和 VR Rendering 等各种 Three.js 框架特性不兼容。每个灯光都需要阴影,但我没有每个灯光的阴影缓冲区的内存,所以它交替渲染灯光的阴影缓冲区,然后是该灯光的累积阶段,然后是下一个灯光的阴影缓冲区,然后蓄电池下一个灯,等等。

我宁愿以更“三个.js”的方式进行设置。我似乎正在编写 hack on hack 以使其正常工作,每次都放弃另一个无法与我的多通道技术一起正常工作的 three.js 框架功能。但我的所作所为似乎并没有那么不寻常。

令我惊讶的是,我想不出一种方法来设置一个多通道场景来执行此来回渲染和累积。我的第二个惊喜是我创建的 Object3D 不喜欢同时添加到多个场景中,因此我必须为每个想要进入的场景创建每个对象的副本,以防止它们的状态互相干扰。

那么有没有办法更好地渲染这种多通道累积场景呢?同样,我将其描述为一个场景,其中 > 单个着色器通道中允许的最大灯光数量,因此它们的贡献需要交替渲染(阴影缓冲区),然后在多个通道中累加累加。这些灯的工作原理类似于投影图像的典型电影放映机(而不是统一的纯色光源)。

我怎样才能像这样进行多通道渲染,同时仍然利用良好的框架功能,例如用于 VR 的立体渲染和自动阴影缓冲区创建?

这是一个简化的 sn-p,演示了所涉及的场景:

  renderer.render(this.environment.scene, camera, null);
  for (let i = 0, ii = this.projectors.length; i < ii; ++i) {
    let projector = this.projectors[i];
    renderer.setClearColor(0x000000, 1);
    renderer.clearTarget(this.shadowRenderTarget, true, true, false);
    renderer.render(projector.object3D.depthScene, projector.object3D.depthCamera, this.shadowRenderTarget);
    renderer.render(projector.object3D.scene, camera);
  }

  renderer.render(this.foreground.scene, camera, null);

有一个场景从环境中渲染光照(使用普通光照完成),然后每个投影仪都有一个场景计算投影仪的阴影贴图,然后添加来自每个投影仪的光贡献,然后有一个“前景”场景,其中包含叠加层和 UI 内容。

还有没有更“三.js”的方式?

【问题讨论】:

  • THREE.EffectsComposer 用于进行多通道渲染,但仅用于后期处理。老实说,您正在做的是相当低级的事情......可能值得使用较低级别的框架,或者从渲染器中获取 .gl 上下文并对其进行自己的处理。还有一个名为 .onbeforerender 的对象回调,您可以在场景管道确定您的对象将被渲染之前将函数插入到修改参数中。您也许可以在那里进行材质交换/逻辑。

标签: three.js rendering


【解决方案1】:

不幸的是,我认为答案是no

我宁愿以更“三个.js”的方式进行设置。我似乎正在编写hack on hack以使其正常工作,

欢迎来到three.js 开发的世界:)

场景图

您不能让一个节点属于多个父节点。我相信三也不允许你这样做:

const myPos = new THREE.Vector3()

myMesh_layer0.position = myPos
myMesh_layer1.position = myPos

它不适用于欧拉、四元数或矩阵。

管理多个场景中的矩阵更新也很棘手。

three.js 方式

除非你开始破解核心,否则没有办法进行“hack on hack”。

请注意,现在是 2018 年,但将three.js 包含到您的网络应用程序中的官方方式是通过&lt;src&gt; 标签。

这是一个很好的例子,说明最好不要做 the three.js way 而是 modern javascript way 即使用导入、npm 安装等。

Three.js 也没有一个强大的核心,让您可以灵活地处理围绕它的代码。它与暴露的有限数量的钩子非常混淆和混为一谈,这些钩子允许您编写您想要的效果。

Three 经常与它的示例混为一谈,如果你随机选择一个,它将以 three.js 的方式编写,但至少在今天,这与最好的 javascript/编码实践相去甚远。

您经常会发现大型单体文件,这些文件会从拆分中受益。

我相信将示例作为模块导入仍然是不可能的。

查看材料扩展示例并考虑是否要在项目中应用该模式。

您可能会遇到更多痛点,但这足以说明three.js way 可能并不总是可取的。

补救措施

少之又少。我花了一年多的时间尝试推送onBeforeRenderonAfterRender 钩子。它看起来很有用并且允许进行一些重构,但是必须首先删除另一个功能。

另一个功能在那一年进行了迭代,只解决了一个示例,直到很明显onBeforeRender 将解决这两个示例,并允许更多。

不幸的是,这似乎也是three.js的方式。由于基础如此之大并且包含如此多的示例,因此更有可能有人会尝试优化单个示例,然后尝试找到一种通用模式来重构一大堆示例。

您可以在 github 上提出问题,但很难为像这样的通用内容争论不休。您很可能必须编写一些代码作为提案。

这很快就会变得很麻烦,因为它可能会被拒绝、忽略,或者可能会要求您提供示例或重构现有示例。

您提到您的 hack 无法与 VR 等各种三个功能一起使用。我认为这是三个问题,至少在过去几年中,VR 一直是开发的重点,但从未解决核心问题。

好消息是,3 比以往任何时候都更加模块化,因此您可以分叉项目并调整您需要的部分。三个比的问题可能会上升到更高的层次,例如,如果您在渲染器中发现一些耦合使得难以同步您的 fork,那么解释起来会比您特定项目的整个目标更容易。

【讨论】:

    猜你喜欢
    • 2012-04-12
    • 2019-02-01
    • 2014-05-05
    • 2012-02-05
    • 1970-01-01
    • 1970-01-01
    • 2012-09-22
    • 2015-09-26
    • 1970-01-01
    相关资源
    最近更新 更多