在 SceneKit 中,如何在保持最小绘制调用的同时在不同大小的对象上平铺纹理?

In SceneKit, how can one tile a texture on differently sized objects while keeping draw calls minimal?

为了在 SceneKit 场景中改进 performance/fps,我想尽量减少绘制调用的次数。该场景包含一个程序生成的城市,为此我生成了随机高度的房屋(每个房屋都是一个 SCNBox),并用一个相同的重复立面纹理平铺它们,如下所示:

应用纹理的正确方法如下:

let material = SCNMaterial()
material.diffuse.contents = image
material.diffuse.wrapS = SCNWrapMode.repeat
material.diffuse.wrapT = SCNWrapMode.repeat
buildingGeometry.firstMaterial = material

这行得通。但是正如所写的那样,它会拉伸 material 以适应盒子表面的大小。要调整纹理大小以保持纵横比,需要添加以下代码:

material.diffuse.contentsTransform = SCNMatrix4MakeScale(sx, sy, sz)

其中 sxsysz 是从几何中面的大小导出的适当比例因子。这也有效。

但后一种方法意味着每个节点都需要一个自定义 material,这反过来意味着我不能为所有房屋重复使用一个 material,这又意味着每个节点都需要额外的绘制调用。

有没有办法使用单一纹理 material 平铺所有房屋(不拉伸纹理)?

使用表面着色器修改器 (SCNShaderModifierEntryPointSurface),您可以根据 scn_node.boundingBox.

修改 _surface.diffuseTexcoord

由于边界框被动态地馈送到着色器,因此所有对象都将使用相同的着色器并将受益于实例化(减少绘制调用的数量)。

SCNShadable.h 头文件对此有更多详细信息。