Скрытие треугольников в треугольной полосе? (Программное скрытие частей модели)

У меня есть модель робота KUKA в формате DAE, сконвертированная из STEP. Модель сегментируется по материалу (просто плоский цвет) на дочерние элементы корневого узла. Например, все части робота-манипулятора включаются вместе как единый геометрический объект, и к ним применяется зеленый материал. Базовые элементы представляют собой одну большую треугольную полосу.

Мне нужно разделить все части робота, чтобы я мог правильно их анимировать. Между большинством частей, которые я планирую разделить, есть визуальные промежутки. Моей первой мыслью было поискать пробелы в треугольной полосе, но я не знаю, как определить, где расположены пробелы. (Следствие: как треугольная полоса может иметь пробелы?)

Вторая мысль заключалась в том, чтобы выбрать диапазоны элементов для рендеринга (я полагаю, стиль бинарного поиска, ручная настройка чисел или использование элемента управления на экране). Это было бы наиболее полезно в местах, где геометрия визуально смежна, но части нужно разделить.

Вопрос 1: есть ли способ определить, где существуют промежутки в треугольной полосе?

Вопрос 2: существует ли API для выбора подмножества элементов для рендеринга? Это, конечно, можно было бы написать, но похоже, что это много работы (выбор элементов, связанных источников, наложение текстур, вероятно, будет правильным...)


person Shon    schedule 25.11.2014    source источник


Ответы (2)


SceneKit не предлагает инструментов для проверки топологии вашей сетки и обнаружения пробелов. Если ваша исходная модель не имеет этих пробелов, попробуйте найти проблему в конвертере STEP в DAE.

Не существует удобного метода рисования только некоторых элементов вашей геометрии. Создать новую геометрию только с интересующими вас элементами довольно просто. Если вы хотите что-то быстрое и грязное, вы также можете написать SCNProgram, который ничего не делает в вершинном шейдере и отбрасывает фрагмент в шейдере фрагментов. Создайте массив материалов в соответствии с вашими потребностями и установите его для геометрии.

person mnuages    schedule 28.11.2014
comment
Насколько я могу судить, это файл STEP, который неправильно определяет геометрию. Я не знаю, сделано ли это намеренно (возможно, это способ побудить людей покупать программное обеспечение производителя для моделирования? Я не знаю...) или человек, выполняющий экспорт, просто совершил ошибку. Во всяком случае, я думаю, что с тех пор я решил, что просто прятаться не входит в мои намерения. Мне нужно сериализовать выбранную геометрию. - person Shon; 02.12.2014

Хотя ответ 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
    }

}
person Shon    schedule 02.12.2014