在swift SceneKit中绘制带有顶点的自定义节点的示例是什么? [英] What is an example of drawing custom nodes with vertices in swift SceneKit?

查看:78
本文介绍了在swift SceneKit中绘制带有顶点的自定义节点的示例是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

几乎没有在线记录此区域,很高兴看到一个有效的Swift 3示例,例如,带有手动SCNvector3s的自定义绘制立方体.在Objective-C中有此功能,但Swift没有.这可能不是通常的问题形式,但我知道这会帮助很多人.如果有我想念的地方,请提及.

This area is hardly documented online and it would be great to see a working Swift 3 example, of say, a custom drawn cube with manual SCNvector3s. There is this in objective-C but not Swift. This might not be a usual form of question but I know it would help many. If there is somewhere I missed, please mention.

该文档不是很有帮助

scngeometrysource等

scngeometrysource, etc.

谢谢

推荐答案

自定义几何由一组顶点和法线构成.

A custom geometry is constructed from a set of vertices and normals.

顶点

在这种情况下,顶点是两条或多条线相交的点.对于立方体,顶点是下图所示的角

In this context, a vertex is a point where two or more lines intersect. For a cube, the vertices are the corners shown in the following figure

我们通过用一组三角形(每个面两个三角形)构建立方体的面来构造几何.如下图所示,我们的第一个三角形由顶点0、2和3定义,而第二个三角形由顶点0、1和2定义.需要注意的是,每个三角形都有正面和背面.三角形的边由顶点的顺序确定,其中前边以逆时针顺序指定.对于我们的多维数据集,正面将始终位于多维数据集的外部.

We construct the geometry by building the cube's faces with a set of triangles, two triangles per face. Our first triangle is defined by vertices 0, 2, and 3 as shown in the below figure, and the second triangle is defined by vertices 0, 1, and 2. It is important to note that each triangle has a front and back side. The side of the triangle is determined by the order of the vertices, where the front side is specified in counter-clockwise order. For our cube, the front side will always be the outside of the cube.

如果立方体的中心是原点,则可以通过以下方式定义定义一个立方体面的六个顶点

If the cube's center is the origin, the six vertices that define one of the cube's face can be defined by

let vertices:[SCNVector3] = [
        SCNVector3(x:-1, y:-1, z:1),    // 0
        SCNVector3(x:1, y:1, z:1),      // 2
        SCNVector3(x:-1, y:1, z:1)      // 3

        SCNVector3(x:-1, y:-1, z:1),    // 0
        SCNVector3(x:1, y:-1, z:1),     // 1
        SCNVector3(x:1, y:1, z:1)       // 2
]

我们通过创建顶点源

let vertexSource = SCNGeometrySource(vertices: vertices)

至此,我们有了一个顶点源,可以用来构造立方体的一个面;但是,SceneKit不知道三角形应如何对场景中的光源做出反应.为了正确反射光,我们需要为我们的几何图形的每个顶点提供至少一个法向矢量.

At this point, we have a vertex source that can be use to construct a face of the cube; however, SceneKit doesn't know how the triangle should react to light sources in the scene. To properly reflect light, we need to provide our geometry with a least one normal vector for each vertex.

常态

normal 是一个向量,它指定影响光如何从相应三角形反射的顶点的方向.在这种情况下,三角形的六个顶点的法线向量相同.它们都指向正z方向(即x = 0,y = 0和z = 1);请参见下图中的红色箭头.

A normal is a vector that specifies the orientation of a vertex that affects how light reflects off the corresponding triangle. In this case, the normal vectors for the six vertices of the triangle are the same; they all point in the positive z direction (i.e., x = 0, y = 0, and z = 1); see the red arrows in the below figure.

法线定义为

let normals:[SCNVector3] = [
        SCNVector3(x:0, y:0, z:1),      // 0
        SCNVector3(x:0, y:0, z:1),      // 2
        SCNVector3(x:0, y:0, z:1),      // 3

        SCNVector3(x:0, y:0, z:1),      // 0
        SCNVector3(x:0, y:0, z:1),      // 1
        SCNVector3(x:0, y:0, z:1)       // 2
]

并且源由

let normalSource = SCNGeometrySource(normals: normals)

我们现在有了构造有限的几何形状(即一个立方体面(两个三角形))所需的源(顶点和法线).最后一步是创建一个指向顶点和法线数组的索引数组.在这种情况下,索引是顺序的,因为顶点按其使用的顺序排列.

We now have the sources (vertices and normals) needed to construct a limited geometry, i.e., one cube face (two triangles). The final piece is to create an array of indices into the vertex and normal arrays. In this case, the indices are sequential because the vertices are in the order they are used.

let indices:[Int32] = [0, 1, 2, 3, 4, 5]

根据索引,我们创建一个几何元素.由于SCNGeometryElement需要一个NSData作为参数,因此设置过程会更加复杂.

From the indices, we create an geometry element. The setup is a bit more involved because SCNGeometryElement requires an NSData as a parameter.

let pointer = UnsafeRawPointer(indices)
let indexData = NSData(bytes: pointer, length: MemoryLayout<Int32>.size * indices.count)

let element = SCNGeometryElement(data: indexData as Data, primitiveType: .triangles, primitiveCount: indices.count, bytesPerIndex: MemoryLayout<Int32>.size)

我们现在可以使用创建自定义几何

We can now create the custom geometry with

let geometry = SCNGeometry(sources: [vertexSource, normalSource], elements: [element])

最后创建一个节点,并将自定义几何分配给其geometry属性

and lastly create a node and assign the custom geometry to its geometry property

let node = SCNNode()
node.geometry = geometry

scene.rootNode.addChildNode(node)

我们现在将顶点和法线扩展到包括所有立方体面:

We now extend the vertices and normals to including all of the cube faces:

    // The vertices
    let v0 = SCNVector3(x:-1, y:-1, z:1)
    let v1 = SCNVector3(x:1, y:-1, z:1)
    let v2 = SCNVector3(x:1, y:1, z:1)
    let v3 = SCNVector3(x:-1, y:1, z:1)

    let v4 = SCNVector3(x:-1, y:-1, z:-1)
    let v5 = SCNVector3(x:1, y:-1, z:-1)
    let v6 = SCNVector3(x:-1, y:1, z:-1)
    let v7 = SCNVector3(x:1, y:1, z:-1)

    // All the cube faces
    let vertices:[SCNVector3] = [
        // Front face
        v0, v2, v3,
        v0, v1, v2,

        // Right face
        v1, v7, v2,
        v1, v5, v7,

        // Back
        v5, v6, v7,
        v5, v4, v6,

        // Left
        v4, v3, v6,
        v4, v0, v3,

        // Top
        v3, v7, v6,
        v3, v2, v7,

        // Bottom
        v1, v4, v5,
        v1, v0, v4
    ]

    let normalsPerFace = 6
    let plusX = SCNVector3(x:1, y:0, z:0)
    let minusX = SCNVector3(x:-1, y:0, z:0)
    let plusZ = SCNVector3(x:0, y:0, z:1)
    let minusZ = SCNVector3(x:0, y:0, z:-1)
    let plusY = SCNVector3(x:0, y:1, z:0)
    let minusY = SCNVector3(x:0, y:-1, z:0)

    // Create an array with the direction of each vertex. Each array element is
    // repeated 6 times with the map function. The resulting array or arrays
    // is then flatten to an array
    let normals:[SCNVector3] = [
        plusZ,
        plusX,
        minusZ,
        minusX,
        plusY,
        minusY
        ].map{[SCNVector3](repeating:$0,count:normalsPerFace)}.flatMap{$0}

    // Create an array of indices [0, 1, 2, ..., N-1]
    let indices = vertices.enumerated().map{Int32($0.0)}

    let vertexSource = SCNGeometrySource(vertices: vertices)

    let normalSource = SCNGeometrySource(normals: normals)

    let pointer = UnsafeRawPointer(indices)
    let indexData = NSData(bytes: pointer, length: MemoryLayout<Int32>.size * indices.count)

    let element = SCNGeometryElement(data: indexData as Data, primitiveType: .triangles, primitiveCount: indices.count/3, bytesPerIndex: MemoryLayout<Int32>.size)

    let geometry = SCNGeometry(sources: [vertexSource, normalSource], elements: [element])

    // Create a node and assign our custom geometry
    let node = SCNNode()
    node.geometry = geometry

    scene.rootNode.addChildNode(node)

这篇关于在swift SceneKit中绘制带有顶点的自定义节点的示例是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆