【问题标题】:how to draw an arrow in SceneKit?如何在 SceneKit 中绘制箭头?
【发布时间】:2017-11-15 05:27:07
【问题描述】:

我正在尝试使用 SCNGeometrySource、SCNGeometryElement 绘制箭头。但无法绘制如下图所示的精确箭头。

是否可以像下图那样用头部或箭头绘制简单的箭头线?

我尝试了下面的代码,但那行不通。

let indices: [Int32] = [0, 1,1]
        let source = SCNGeometrySource(vertices: [vector1, vector2])
        let element = SCNGeometryElement(indices: indices, primitiveType: .triangles)

【问题讨论】:

    标签: swift scenekit arkit


    【解决方案1】:

    如果箭头始终朝向相机,就像您附加的图像中一样,您可以使用 SCNPlane 并将箭头图像用作纹理。

    如果它不总是面向相机,你可能想给它一些厚度。如果操作正确,我不同意另一个答案是比您尝试的方法“更好”的解决方案。

    Obj C 代码(编辑:在下面添加了 swift 版本)

    int vertcount = 48;
    float verts[] = { -14.923, 11.824, 25.000, -64.923, 0.000, 0.000, -14.923, -11.824, 25.000, 46.077, -5.812, 16.800, 46.077, -5.812, -16.800, 46.077, 5.812, -16.800, 46.077, 5.812, 16.800, -14.923, -11.824, -25.000, -14.923, 11.824, -25.000, -14.923, 4.974, -9.969, -14.923, 4.974, 9.969, -14.923, -4.974, 9.969, -14.923, -4.974, -9.969 };
    
    int facecount = 13;
    int faces[] = {  3, 4, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 0, 1, 2, 3, 4, 5, 6, 7, 1, 8, 8, 1, 0, 2, 1, 7, 9, 8, 0, 10, 10, 0, 2, 11, 11, 2, 7, 12, 12, 7, 8, 9, 9, 5, 4, 12, 10, 6, 5, 9, 11, 3, 6, 10, 12, 4, 3, 11};
    
    NSData *vertsData = [NSData dataWithBytes:&verts length:sizeof(verts)];
    
    SCNGeometrySource *vertexSource = [SCNGeometrySource geometrySourceWithData: vertsData 
    semantic:SCNGeometrySourceSemanticVertex
    vectorCount:vertcount
    floatComponents:YES
    componentsPerVector:3
    bytesPerComponent:sizeof(float)
    dataOffset:0
    dataStride:sizeof(float)*3];
    
    int polyIndexCount = 61;
    NSData *indexPolyData = [NSData dataWithBytes:faces length:sizeof(int) * polyIndexCount];
    SCNGeometryElement *element1 = [SCNGeometryElement geometryElementWithData:indexPolyData
    primitiveType:SCNGeometryPrimitiveTypePolygon
    primitiveCount:facecount
    bytesPerIndex:sizeof(int)];
    
    SCNGeometry *geometry1 = [SCNGeometry geometryWithSources:@[ vertexSource ] elements:@[ element1]];
    
    //Assign the SCNGeometry to a SCNNode, for example:
    //SCNNode *aNode = [[SCNNode alloc] init];
    //aNode.geometry = geometry1;
    

    注意它使用多边形基本类型。

    可以通过对浮点数进行四舍五入来清理顶点列表。

    这将创建以下 3D 箭头(顶点和边不可见):

    编辑:SWIFT 版本:

    let vertcount = 48;
            let verts: [Float] = [ -1.4923, 1.1824, 2.5000, -6.4923, 0.000, 0.000, -1.4923, -1.1824, 2.5000, 4.6077, -0.5812, 1.6800, 4.6077, -0.5812, -1.6800, 4.6077, 0.5812, -1.6800, 4.6077, 0.5812, 1.6800, -1.4923, -1.1824, -2.5000, -1.4923, 1.1824, -2.5000, -1.4923, 0.4974, -0.9969, -1.4923, 0.4974, 0.9969, -1.4923, -0.4974, 0.9969, -1.4923, -0.4974, -0.9969 ];
    
            let facecount = 13;
            let faces: [CInt] = [  3, 4, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 0, 1, 2, 3, 4, 5, 6, 7, 1, 8, 8, 1, 0, 2, 1, 7, 9, 8, 0, 10, 10, 0, 2, 11, 11, 2, 7, 12, 12, 7, 8, 9, 9, 5, 4, 12, 10, 6, 5, 9, 11, 3, 6, 10, 12, 4, 3, 11 ];
    
            let vertsData  = NSData(
                bytes: verts,
                length: MemoryLayout<Float>.size * vertcount
            )
    
            let vertexSource = SCNGeometrySource(data: vertsData as Data,
                                                 semantic: .vertex,
                                                 vectorCount: vertcount,
                                                 usesFloatComponents: true,
                                                 componentsPerVector: 3,
                                                 bytesPerComponent: MemoryLayout<Float>.size,
                                                 dataOffset: 0,
                                                 dataStride: MemoryLayout<Float>.size * 3)
    
            let polyIndexCount = 61;
            let indexPolyData  = NSData( bytes: faces, length: MemoryLayout<CInt>.size * polyIndexCount )
    
            let element1 = SCNGeometryElement(data: indexPolyData as Data,
                                              primitiveType: .polygon,
                                              primitiveCount: facecount,
                                              bytesPerIndex: MemoryLayout<CInt>.size)
    
            let geometry1 = SCNGeometry(sources: [vertexSource], elements: [element1])
    
            let material1 = geometry1.firstMaterial!
    
            material1.diffuse.contents = UIColor(red: 0.14, green: 0.82, blue: 0.95, alpha: 1.0)
            material1.lightingModel = .lambert
            material1.transparency = 1.00
            material1.transparencyMode = .dualLayer
            material1.fresnelExponent = 1.00
            material1.reflective.contents = UIColor(white:0.00, alpha:1.0)
            material1.specular.contents = UIColor(white:0.00, alpha:1.0)
            material1.shininess = 1.00
    
            //Assign the SCNGeometry to a SCNNode, for example:
            let aNode = SCNNode()
            aNode.geometry = geometry1
            //aNode.scale = SCNVector3(0.1, 0.1, 0.1)
            scene.rootNode.addChildNode(aNode)
    

    在 Swift 代码上测试以仔细检查它是否有效:

    如果您需要它更小,请取消注释 .scale 行并尝试不同的值以查看您希望它有多小。例如,如果您最终希望它的比例为 0.06,我建议通过将其中的值乘以 0.06 来重新生成垂直列表,然后删除比例线。

    【讨论】:

    • 你有 swift 代码吗?我正在尝试将其转换为 swift 语言,但应用程序崩溃。你能帮帮我吗?
    • 嗨,我今天或明天会用 Swift 代码更新答案。我刚刚注意到顶点列表中也缺少一些逗号。
    【解决方案2】:

    对于这样的形状,您最好为箭头创建一个平面 UIBezierPath,然后通过拉伸路径来创建一个 SCNShape 以获得 3D 几何图形。

    【讨论】:

    • 但是怎么做呢?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多