使用SceneKit线条原始类型时的笔划宽度

9

我正在尝试使用场景工具(Scene Kit)复制这个立方体图像形状(在获得原始创作者的许可后)。

enter image description here

到目前为止,我已经有了线条和顶点的绘图代码。 我不能使用图像,因为背景必须是透明的。

我现在要解决的问题是如何编辑 SCNGeometryPrimitiveType.Line 元素的笔画宽度。

我创建线条的基本方法如下:

private func squareVertices(length: Float) -> [SCNVector3] {
    let m = length/Float(2)

    let topLeft =       SCNVector3Make(-m-q,  m+q, m+q)
    let topRight =      SCNVector3Make( m+q,  m+q, m+q)
    let bottomLeft =    SCNVector3Make(-m-q, -m-q, m+q)
    let bottomRight =   SCNVector3Make( m+q, -m-q, m+q)

    return [topLeft, topRight, bottomLeft, bottomRight]
}

private func cubeFace() -> SCNGeometry {

    let vertices : [SCNVector3] = squareVertices(l)
    let geoSrc = SCNGeometrySource(vertices: UnsafePointer<SCNVector3>(vertices), count: vertices.count)

    // index buffer
    let idx1 : [Int32] = [0, 3]
    let data1 = NSData(bytes: idx1, length: (sizeof(Int32) * idx1.count))
    let geoElements1 = SCNGeometryElement(data: data1, primitiveType: SCNGeometryPrimitiveType.Line, primitiveCount: idx1.count, bytesPerIndex: sizeof(Int32))

    let idx2 : [Int32] = [1, 2]
    let data2 = NSData(bytes: idx2, length: (sizeof(Int32) * idx2.count))
    let geoElements2 = SCNGeometryElement(data: data2, primitiveType: SCNGeometryPrimitiveType.Line, primitiveCount: idx2.count, bytesPerIndex: sizeof(Int32))

    let geo = SCNGeometry(sources: [geoSrc], elements: [geoElements1, geoElements2])

    return geo
}

    private func setupFaceNodes() {
    // sides
    for i in 0..<4 {
        let face = SCNNode(geometry: cubeFace())
        face.rotation = SCNVector4Make(0, 1, 0, Float(i) * Float(M_PI_2))
        rootNode.addChildNode(face)
    }
    // top/bottom
    for i in [1, 3] {
        let face = SCNNode(geometry: cubeFace())
        face.rotation = SCNVector4Make(1, 0, 0, Float(i) * Float(M_PI_2))
        rootNode.addChildNode(face)
    }
}

我有一个与正确的整体形状相似的东西:

enter image description here

但我无法弄清楚如何使用SceneKit增加正在绘制的线的宽度。我该怎么做呢?

对于那些感兴趣的人,这里是一个示例项目。

2个回答

9

SceneKit不提供此类控件。但是,SceneKit使用OpenGL ES进行绘图。

当您使用GL以 GL_LINES 模式绘制时,glLineWidth调用将更改线条宽度。(注意:参数是实际像素,而不是UI布局点,因此如果您不希望在Retina显示器上出现超薄发丝,则需要比您想象的宽度更大)。

那么,在您的SceneKit应用程序中何时调用呢?你有几个选项。在像你这样的简单场景中,你只渲染一件事物,你可以在场景渲染前设置它。为视图设置一个代理,然后实现renderer:willRenderSceneAtTime:并在那里调用glLineWidth

然而,OpenGL线条渲染非常有限——如果您想要自定义渲染,您需要采用不同的方法。哪种方法最好取决于您想要实现的具体效果,因此这里有一些供您研究的想法:

  • 使用狭窄三角形条制作您的“线”
  • 使用像盒子和圆柱体这样的基本SCN几何体制作它们
  • 保留一个简单的立方体几何体,但使用片段着色器(或着色器修改器片段)仅绘制每个多边形的边缘附近

保持简单的立方体几何形状,但使用片段着色器(或着色器修改器代码片段)仅绘制每个多边形附近的边缘。您如何使用片段着色器实现此操作?使用着色器绘制线框不是更难解决的问题吗?[线框着色器](http://codeflow.org/entries/2012/aug/02/easy-wireframe-display-with-barycentric-coordinates/) - tsp
它可以更加复杂,但也允许更多的灵活性——例如模糊/发光边缘。根据您的需求,您不需要将另一个属性(SceneKit中的几何源)传递到管道中以获取重心坐标——如果您想突出四边形的边缘,请忘记它实际上是两个三角形,并只查看纹理坐标。(假设您的纹理坐标设置为遵循四边形。) - rickster
我尝试了在委托方法中添加glLineWidth调用的方法,它在模拟器上运行良好,但在设备上没有效果。你们有没有遇到过相同的情况?奇怪的是,如果我直接使用GLES而不是SceneKit,我可以在设备上使用非常粗的线条使glLineWidth正常工作。 - eddy
2
@eddy:在你的设备上,SceneKit是否正在使用GL渲染器?glLineWidth对于Metal无效(也没有Metal等效物)。 - rickster
glLineWidth也因设备而异。我在iOS上使用它时从未成功过,所以转而使用其他方法。 - Wil Shipley
1
我们可以在SceneKit中这样指定OpenGL:[[SCNView alloc] initWithFrame:CGRectZero options:@{SCNViewOptionPreferredRenderingAPI:@(SCNRenderingAPIOpenGLES2)}]; - CocoaBob

5
你可以使用glLineWidth来设置线宽。
确保在你的项目中包含了OpenGLES。

Line Width 8

这是您的立方体线宽设置为8的外观。

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