无法解析顶点和索引数据,寻找更有效的方法

时间:2016-11-22 02:54:16

标签: arrays swift scenekit metal

我编写了一个解析包含顶点数据的数组的方法。该方法的目标是从该数据生成一个新的唯一顶点数组和一个新索引。

这是我用来在数组中存储顶点的结构。

struct Vertex: Hashable {
    var x, y, z,
    nx, ny, nz,
    s, t: Float

    var hashValue: Int {
        return "\(self.x),\(self.y),\(self.z),\(self.nx),\(self.ny),\(self.nz),\(self.s),\(self.t),".hashValue
    }

    static func ==(lhs: Vertex, rhs: Vertex) -> Bool {
        return lhs.hashValue == rhs.hashValue
    }
}

这是我用来创建唯一顶点数组和新索引的方法。该方法的第一个参数采用一个数组,其顶点数据已经由原始索引排序。

func makeVertexIndex(_ array: [Float]) -> ([Vertex], [Int]) {
    var counter = 0
    var indexCounter = 0
    var holder = [Float]()
    var vertices = [Vertex]()
    var index = [Int]()

    for i in array {
        counter += 1

        if counter == 8 {
            counter = 0
            holder.append(i)
            let vertex = Vertex(x: holder[0], y: holder[1], z: holder[2],
                                nx: holder[3], ny: holder[4], nz: holder[5],
                                s: holder[6], t: holder[7])

            if vertices.contains(vertex) {
                guard let match = vertices.index(of: vertex) else { continue }
                index.append(match)
            } else {
                vertices.append(vertex)
                index.append(indexCounter)
                indexCounter += 1
            }

            holder.removeAll()
        } else {
            holder.append(i)
        }
    }

    return (vertices, index)
}

我能够成功解析下三角计数网格,但是当我尝试在更高的三角形计数网格上运行时,它花了一个多小时才能运行。

我对编码很陌生,Swift是我的第一语言,但我怀疑它不应该花这么长时间来完成这项任务而且我可能只是写了我的方法真的效率低下或者可能在那里'我完全可以解决这个问题。

无论如何,我很感激能得到的任何帮助。谢谢你的阅读。

更新1: 我重新编写了我的方法来创建顶点数组,然后将其更改为一个集合,使值唯一并返回到数组,然后通过vertexArray循环运行它,查找唯一顶点数组中的匹配项。此版本的方法将处理时间从我的测试网格上的21秒减少到大约12秒。

func makeVertexIndex(_ array: [Float]) -> ([Vertex], [Int]) {
    var counter = 0
    var holder = [Float]()
    var vertexArray = [Vertex]()
    var vertices = [Vertex]()
    var index = [Int]()

    for i in array {
        counter += 1

        if counter == 8 {
            counter = 0
            holder.append(i)
            let vertex = Vertex(x: holder[0], y: holder[1], z: holder[2],
                                nx: holder[3], ny: holder[4], nz: holder[5],
                                s: holder[6], t: holder[7])

            vertexArray.append(vertex)

            holder.removeAll()
        } else {
            holder.append(i)
        }
    }

    let vertexSet = Set(vertexArray)
    vertices = Array(vertexSet)

    for v in vertexArray {
        guard let match = vertices.index(of: v) else { continue }
        index.append(match)
    }

    return (vertices, index)
}

更新2:

这是我在实施一些推荐的解决方案后更新的结构和方法。

STRUCT:

struct Vertex: Hashable {
    var x, y, z,
    nx, ny, nz,
    s, t: Float

    var hashValue: Int {
        return "\(self.x),\(self.y),\(self.z),\(self.nx),\(self.ny),\(self.nz),\(self.s),\(self.t)".hashValue
    }

    static func ==(lhs: Vertex, rhs: Vertex) -> Bool {
        return (lhs.x == rhs.x) && (lhs.y == rhs.y) && (lhs.z == rhs.z) && (lhs.nx == rhs.nx) &&
            (lhs.ny == rhs.ny) && (lhs.nz == rhs.nz) && (lhs.s == rhs.s) && (lhs.t == rhs.t)
    }
}

方法:

    func makeVertexIndex(_ array: [Float]) -> ([Vertex], [Int]) {
        var vertexArray = [Vertex]()
        vertexArray.reserveCapacity(array.count / 8)

        var vertices = [Vertex]()
        var index = [Int]()

        // Creating an array of Vertex from an array containing 
        // position/normal/texcoord in correct order.
        for i in stride(from: 0, to: array.count, by: 8) {
            let vertex = Vertex(x: array[i], y: array[i + 1], z: array[i + 2],
                                nx: array[i + 3], ny: array[i + 4], nz: array[i + 5],
                                s: array[i + 6], t: array[i + 7])

            vertexArray.append(vertex)
        }

        // Making the Vertex array unique by converting to set and back to array.
        let vertexSet = Set(vertexArray)
        vertices = Array(vertexSet)

        // Making new index by finding the matching vertex in the 
        // unique vertex array and adding that array index to the new index
        for v in vertexArray {
            guard let match = vertices.index(of: v) else { continue }
            index.append(match)
        }

        return (vertices, index)
    }

在尝试推荐的解决方案的各个部分后,该方法能够在13分钟内处理具有70K三角形的模型,之前花费了超过一个半小时。

所以这是一个巨大的改进,欣赏到目前为止的所有解决方案,将保持开放可能一两天,看看是否有任何其他建议。

2 个答案:

答案 0 :(得分:2)

为什么你的==代码比较哈希而不是每个属性?即。

SELECT * FROM before JOIN after ON before.Lotname = LEFT(after.Lotname,4)

如果static func ==(lhs: Vertex, rhs: Vertex) -> Bool { return (lhs.x == rhs.x) && (lhs.y == rhs.y) && (lhs.z == rhs.z) && (lhs.nx == rhs.nx) && ...etc } 不等于lhs.x,代码将很快失败并继续下一步。目前,您必须一次又一次地创建哈希值。或者,您可以通过在构造函数中计算一次哈希来加速当前代码(并且,比如,在下面的简化示例中创建所有属性rhs.x)。

private(set)

答案 1 :(得分:0)

看起来你正试图以一组新的顶点和一组索引结束。如果新的顶点集包含重复项,请从顶点列表中删除该顶点,并将重复项的索引加倍。从你的第一个功能来判断。你的第二个只在匹配时添加了一个索引。你是什​​么意思?

从第一个开始......如果你有V1 V2 V3 V4,而V4 = V1,你需要索引[0,0,1,2]。

这是对的吗?我会通过一次迭代浮点数组8来清理它,然后确定是否有重复项,如果是这样,找出哪些是重复项,然后创建最后两个数组。这是我的看法..

List<string> choices = new List<string>();
Random rnd = new Random(DateTime.Now.Millisecond);
public void PopulateChoices()
{
    choices.Clear();
    for(char i = '0'; i < ':';i++)
    {
        for(char j = 'A'; j < 'C'; j++)
        {
            choices.Add(new string(new char[] { j, i }));
        }
    }
}
public List<string> MakeRandColl(int size)
{
    List<string> randChoices = choices;
    List<string> retVal = new List<string>();
    for(int i = 0; i < size; i++)
    {
        string temp = randChoices[rnd.Next(0, randChoices.Count)];
        retVal.Add(temp);
        randChoices.Remove(temp);
    }
    return retVal;
}
public void DeleteChoice(string choice)
{
    choices.Remove(choice);
}