【问题标题】:How to calculate normal vector of a SCNPlane?如何计算 SCNPlane 的法线向量?
【发布时间】:2021-04-18 21:59:49
【问题描述】:

目标:定义由SCNPlane 表示的平面的法线向量。

正如 Apple 的文档 Working with Vectors - Calculate the Normal of a Triangle 中所述,我可以根据平面上的 3 个点计算法线向量。这里的问题是我不知道我如何才能得到 3 分,他们构成了正确的三角形。我注意到SCNPlane 有一个属性boundingBox,它可以代表两个三角形顶点(minmax)。如何找到位于SCNPlane 上的第三个顶点?我不能使用SCNPlane 的中心,因为它会创建一条线以及来自boundingBoxminmax 点。

还有其他方法可以帮助我检索SCNPlane 的法线向量吗?

【问题讨论】:

    标签: ios swift scenekit arkit


    【解决方案1】:

    documentation 我们了解到

    表面是单面的。它的表面法向量指向其局部坐标空间的正z轴方向,因此默认情况下只能从该方向可见。

    SCNPlane 的法线在本地空间中始终为(0, 0, 1),并且无法更改。

    当它附加到一个节点时,该节点的方向决定了另一个坐标系中的法线。您可以使用simdConvertVector:toNode:在坐标空间之间进行转换:

    // normal expressed in world space
    let normal = simd_normalize(node.simdConvertVector(simd_float3(0, 0, 1), to: nil))
    

    【讨论】:

      【解决方案2】:

      要添加到已接受的答案,为了检索定义平面的点,您可以查询平面的几何源。

      let plane = SCNPlane(width: 100, height: 20)
      print("Sources for normal: \(vertices(sources: plane.sources(for: .normal)))")
      print("Sources for vertex: \(vertices(sources: plane.sources(for: .vertex)))")
      
      extension UnsafeRawPointer {
          func loadUnaligned<T>(as: T.Type, count: Int) -> [T] {
              assert(_isPOD(T.self)) // relies on the type being POD (no refcounting or other management)
              let buffer = UnsafeMutablePointer<T>.allocate(capacity: count)
              defer { buffer.deallocate() }
              memcpy(buffer, self, MemoryLayout<T>.size * count)
              return (0..<count).map({ index in buffer.advanced(by: index).pointee })
          }
      }
      
      func vertices(sources: [SCNGeometrySource]) -> [[SCNVector3]] {
      
          var result = [[SCNVector3]]()
          result.reserveCapacity(sources.count)
          for source in sources {
              precondition(source.usesFloatComponents == true, "SCNVector3 can handle only three-component vectors whose components are floating-point values, i.e., floats or doubles")
              precondition(source.componentsPerVector == 3, "SCNVector3 can only be used for three components per vector")
              
              let shouldUseFloatNotDouble: Bool
              if source.bytesPerComponent == 4 {
                  shouldUseFloatNotDouble = true
              }
              else if source.bytesPerComponent == 8 {
                  shouldUseFloatNotDouble = false
              }
              else {
                  assert(false, "The SCNGeometrySource has reported an unexpected byte size for its vector components, not 4 bytes (float) or 8 bytes (double) but \(source.bytesPerComponent). I am not equipped for this so I am going to use floats and hope for the best. This will probably not work. Sorry.")
                  shouldUseFloatNotDouble = true
              }
              
              let vectors = source.data.withUnsafeBytes {
                  (p: UnsafeRawBufferPointer) -> [SCNVector3] in
                  if (shouldUseFloatNotDouble) {
                      let simdArray = (p.baseAddress! + source.dataOffset).loadUnaligned(as: SIMD3<Float>.self, count: source.vectorCount)
                      return simdArray.map { simd in SCNVector3(simd)}
                  } else {
                      let simdArray = (p.baseAddress! + source.dataOffset).loadUnaligned(as: SIMD3<Double>.self, count: source.vectorCount)
                      return simdArray.map { simd in SCNVector3(simd)}
                  }
              }
              result.append(vectors)
          }
          return result
      }
      

      输出:

      Sources for normal: [[__C.SCNVector3(x: 0.0, y: 0.0, z: 1.0), __C.SCNVector3(x: 1.0, y: 0.5, z: -0.5), __C.SCNVector3(x: 0.0, y: 0.0, z: 1.0), __C.SCNVector3(x: 1.0, y: -0.5, z: 0.5)]]
      Sources for vertex: [[__C.SCNVector3(x: -0.5, y: -0.5, z: 0.0), __C.SCNVector3(x: 0.0, y: 1.0, z: 0.0), __C.SCNVector3(x: 0.5, y: -0.5, z: 0.0), __C.SCNVector3(x: 0.0, y: 1.0, z: 1.0)]]
      

      【讨论】:

      • 感谢您的回答,特别是因为它针对我关于在飞机上找到 3 个点的问题。这看起来很好,但我还有几个问题。 .normal 语义的顶点是什么?我试图将它们形象化,但无法弄清楚。我改变了平面的大小,来自 .vertex 的 3 个点在平面之外。为什么?最后一个问题,它是如何工作的?你有什么资料可以让我找到详细的解释吗?
      • 虽然它们在平面边界之外,但它们可能仍然这样定义平面,这足以计算法线。我的回答主要基于直觉,我扫描了文档并在几何来源上搜索了任何材料,但找不到任何可以回答您问题的内容。
      猜你喜欢
      • 2021-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多