如何在SceneKit中绘制箭头?

3

我试图使用SCNGeometrySource和SCNGeometryElement绘制箭头,但无法像下面的图像一样准确地绘制箭头。

是否可能使用类似下面图像中的箭头来绘制简单的箭头线或箭头?

我尝试了下面的代码,但这不起作用。

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

enter image description here

2个回答

16

如果箭头始终面向相机(如您附加的图像),则可以使用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语言,但是应用程序一直崩溃。你能帮帮我吗? - imjaydeep
嗨,我会在今天或明天用Swift代码更新答案。我刚刚注意到顶点列表中缺少一些逗号。 - Xartec

4

对于这样的形状,最好创建一个平面的 UIBezierPath 用于箭头,然后通过将路径挤出来获得三维几何体来创建 SCNShape


但是如何做到呢? - Bijender Singh Shekhawat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接