在三角形条中隐藏三角形? (以编程方式隐藏模型的各个部分)

时间:2014-11-25 19:46:21

标签: swift osx-yosemite scenekit

我有一个从STEP转换而来的DAE格式的KUKA机器人模型。模型按材质(仅为平面颜色)分割为根节点的子节点。例如,所有被认为是机器人手臂的部件被包括在一起作为单个几何对象并且应用绿色材料。底层元素是一个大的三角形条带。

我需要将机器人的所有部分分开,以便我可以正确地为它们设置动画。我计划分离的大部分零件之间存在视觉差距。我的第一个想法是寻找三角形带中的间隙,但我不知道如何判断间隙的位置。 (推论:三角形带如何有间隙?)

第二个想法是选择要渲染的元素范围(我猜想二元搜索样式,手动调整数字或使用屏幕控制。)这在几何图形相邻的地方最有用,但是部分需要分离。

问题1:有没有一种方法可以确定三角形带中存在间隙的位置?

问题2:是否存在用于选择要渲染的元素子集的API?写这个肯定是可能的,但看起来很多工作(选择元素,相关来源,纹理映射可能会出来......)

2 个答案:

答案 0 :(得分:0)

SceneKit不提供检查网格拓扑和检测间隙的工具。如果您的原始模型没有这些间隙,那么应该尝试在STEP到DAE转换器中找到问题。

没有方便的方法只能绘制几何体的某些元素。仅使用您感兴趣的元素即可轻松创建新几何体。如果你想要快速和肮脏的东西,你也可以写一个在顶点着色器中什么都不做的SCNProgram并丢弃片段着色器中的片段。根据您的需要创建一系列材料并将其设置为几何体。

答案 1 :(得分:0)

虽然mnuages的回答提供了一个合适的标题答案(实际上是'隐藏'几何的几何部分),但我意识到这是不够的,因为我想要以编程方式将剩余的几何序列化为场景中的节点。

为了回答我的“问题2”,我编写了对SceneKit类的补充,这些类可以让我生成具有原始对象的基元范围的新SCNGeometry对象。它在材料方面可能相当天真(我的模型使用简单的颜色;这段代码可能还没有正确处理其他纹理);它可能不适用于三角形条以外的图元。

该代码在GitHub https://github.com/Fyrestead/PartialGeometry

中提供

为完整起见,初始版本粘贴在下面。

SCNGeometry补充:

//
//  SCNGeometry.swift
//
//  Created by Shon Frazier on 11/22/14.
//  Copyright (c) 2014 Fyrestead, LLC. All rights reserved.
//

import Foundation
import SceneKit

let allSemantics = [
    SCNGeometrySourceSemanticVertex,
    SCNGeometrySourceSemanticNormal,
    SCNGeometrySourceSemanticColor,
    SCNGeometrySourceSemanticTexcoord,
    SCNGeometrySourceSemanticVertexCrease,
    SCNGeometrySourceSemanticEdgeCrease,
    SCNGeometrySourceSemanticBoneWeights,
    SCNGeometrySourceSemanticBoneIndices
]


extension SCNGeometry {

    func geometryForRangeOfPrimitives(range: NSRange) -> SCNGeometry? {

        var primitiveType: SCNGeometryPrimitiveType

        var allElements: [SCNGeometryElement] = [SCNGeometryElement]()

        for i in 0..<self.geometryElementCount {
            let element = self.geometryElementAtIndex(i)
            if element == nil {
                continue
            }

            var newElement = element!.geometryElementForRangeOfPrimitives(range)

            if newElement != nil {
                allElements += [newElement!]
            }
        }


        var allSources: [SCNGeometrySource] = [SCNGeometrySource]()

        for semantic in allSemantics {
            var sources = self.geometrySourcesForSemantic(semantic)
            if sources == nil {
                continue
            }

            for source in sources! as [SCNGeometrySource] {
                var range: NSRange = NSRange(location: 0, length: 5)

                let newSource = source.geometrySourceForRangeOfPrimitives(range, primitiveType: SCNGeometryPrimitiveType.TriangleStrip)

                allSources += [newSource!]
            }
        }


        var newGeometry = SCNGeometry(sources: allSources, elements: allElements)
        newGeometry.materials = materials

        return newGeometry
    }
}

SCNGeometryElement补充:

//
//  SCNGeometryElement.swift
//
//  Created by Shon Frazier on 11/23/14.
//  Copyright (c) 2014 Fyrestead, LLC. All rights reserved.
//

import Foundation
import SceneKit

extension SCNGeometryElement {

    func geometryElementForRangeOfPrimitives(range: NSRange) -> SCNGeometryElement? {

        if data == nil {
            return nil
        }

        let newCount = range.length
        let newLocation = range.location * bytesPerIndex
        let newLength = range.length * bytesPerIndex
        let newRange = NSRange(location: newLocation, length: newLength)
        let newData = data!.subdataWithRange(newRange)

        let newElement = SCNGeometryElement(
            data: newData,
            primitiveType: primitiveType,
            primitiveCount: newCount,
            bytesPerIndex: bytesPerIndex
        )

        return newElement
    }

}

SCNGeometrySource补充:

//
//  SCNGeometrySource.swift
//
//  Created by Shon Frazier on 11/23/14.
//  Copyright (c) 2014 Fyrestead, LLC. All rights reserved.
//

import Foundation
import SceneKit

extension SCNGeometrySource {

    /* Preserves use of existing data buffer by changing only the offset */
    func geometrySourceForRangeOfVectors(range: NSRange) -> SCNGeometrySource? {

        if data == nil {
            return nil
        }

        let newOffset = dataOffset + range.location * (dataStride + bytesPerComponent * componentsPerVector)

        return SCNGeometrySource(
            data: data!,
            semantic: semantic,
            vectorCount: range.length,
            floatComponents: floatComponents,
            componentsPerVector: componentsPerVector,
            bytesPerComponent: bytesPerComponent,
            dataOffset: newOffset,
            dataStride: dataStride)
    }

    func geometrySourceForRangeOfPrimitives(range: NSRange, primitiveType: SCNGeometryPrimitiveType) -> SCNGeometrySource? {

        var newGSource: SCNGeometrySource?

        switch primitiveType {
        case .TriangleStrip, .Point:
            newGSource = geometrySourceForRangeOfVectors(range)

        case .Triangles:
            let newRange = NSRange(location: range.location * 3, length: range.length * 3)
            newGSource = geometrySourceForRangeOfVectors(newRange)

        case .Line:
            let newRange = NSRange(location: range.location * 2, length: range.length * 2)
            newGSource = geometrySourceForRangeOfVectors(newRange)
        }

        return newGSource
    }

}