【问题标题】:How to make new instances of a SCNNode with different texture如何制作具有不同纹理的 SCNNode 的新实例
【发布时间】:2014-10-04 00:13:19
【问题描述】:

我将 COLLADA 文件中的网格加载到 SceneKit 中。假设我有一个立方体,其材质具有一定的纹理。然后在代码中,我想制作这个 SCNNode 的新副本——到目前为止我已经使用了clone——然后我需要设置一个新的纹理。这就是问题所在,因为如果我获得其中一个克隆立方体的命名材质并更新其纹理 (thematerialofmycube.diffuse.contents = @"somefile.png"),将为立方体的所有实例设置相同的纹理。 clone 显然不会深度复制几何、材质和纹理等内容。所以我尝试的是制作几何体本身的副本,并尝试制作新材质,为新材质设置新纹理,并将该材质添加到新几何体的材质数组中,同时移除旧材质.似乎没有直接的方法可以这样做(材料被命名,但存在于一个数组中,因此理论上几种材料可以具有相同的名称 - 这会导致从数组中添加/删除一些庞大的对象),以及何时我这样做了,新的纹理出现了,但它们倒置了,而且材料的顺序似乎不正确,因为我用“背面”纹理代替了正面纹理,反之亦然。我希望我不必在我的 3d 编辑器中绘制所有这些东西,一定有一种很好的方法可以在代码中创建具有任意指定纹理的新实例。

我具体做的是在我的 3d 编辑器中画了一张王牌,并将其导出到 COLLADA。现在我有 52 个 png 的王牌面孔 - 我显然需要替换新的王牌实例的面孔。

【问题讨论】:

    标签: ios 3d scenekit


    【解决方案1】:

    似乎该数组中材料的顺序(非常)重要。如果我将具有更新纹理的新材料插入与我删除的相同的数组索引中,本质上是进行替换,那么纹理会显示在正确的面上并且不会倒置 - 即它们的显示方式与与源 SCNNode。我还没有运行它更长的时间,看看它是否能始终如一地工作。

    【讨论】:

    • 物料顺序确实很重要。这里解释了几何元素和材质之间的关联:developer.apple.com/Library/mac/documentation/SceneKit/…
    • "如果一个几何体的材质数与它的几何体元素数相同,则材质索引对应于元素索引。对于材质少于元素的几何体,Scene Kit 确定每个元素的材质索引通过计算该元素的索引以材料的数量为模。例如,在具有六个元素和三种材料的几何体中,Scene Kit 使用索引 5 % 3 = 2 处的材料渲染索引 5 处的元素。"
    • 我仍然无法在 SCNNode 的子类中复制现有 SCNNode 及其现有几何形状。 [node nodeWithGeometry:] 总是返回 SCNNode 类,即使在它的子类中也是如此。稍后设置几何图形(在构造函数之后)不会更改“默认”几何图形,它只是一个盒子。
    【解决方案2】:

    [SCNNode clone] 这样做是出于效率原因。试试这个代码(如果你想创建一个 SCNNode 类别:

    //********************************************************
    //<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    // SCNNode duplicate
    //********************************************************
    //<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    - (SCNNode *)duplicateNode:(SCNNode *)node
    {
        SCNNode *newNode = [node clone];
        newNode.geometry = [node.geometry copy];
        newNode.geometry.firstMaterial = [node.geometry.firstMaterial copy];
    
        return newNode;
    }
    

    【讨论】:

      【解决方案3】:

      快速回答:

      fileprivate func deepCopyNode(node: SCNNode) -> SCNNode {
          let clone = node.clone()
          clone.geometry = node.geometry?.copy() as? SCNGeometry
          if let g = node.geometry {
              clone.geometry?.materials = g.materials.map{ $0.copy() as! SCNMaterial }
          }
          return clone
      }
      

      【讨论】:

        【解决方案4】:

        很久没有人问了。但我想我会提供一个辅助功能:

        func deepCopyNode(_ node: SCNNode) -> SCNNode {
          
          // internal function for recurrsive calls
          func deepCopyInternals(_ node: SCNNode) {
            node.geometry = node.geometry?.copy() as? SCNGeometry
            if let g = node.geometry {
              node.geometry?.materials = g.materials.map { $0.copy() as! SCNMaterial }
            }
            for child in node.childNodes {
              deepCopyInternals(child)
            }
          }
          
          // CLONE main node (and all kids)
          // issue here is that both geometry and materials are linked
          // still. In our deepCopyNode we want new copies of everything
          let clone = node.clone()
          
          // we use this internal function to update both
          // geometry and materials, as well as process all children
          // this is the *deep* part of "deepCopy"
          deepCopyInternals(clone)
          
          return clone
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-01-26
          • 2015-03-19
          • 2020-03-09
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多