Процедурная сетка не рендерит освещение [SceneKit - Xcode] - PullRequest
0 голосов
/ 22 января 2019

Я довольно новичок в Swift и XCode, однако, я программирую на других языках уже несколько лет.Я пытаюсь процедурно создать 3D-сетку в SceneKit (iOS).Мой код работает, как и ожидалось, однако, при запуске приложения сгенерированный объект отображает плоский черный цвет, игнорируя все освещение.Я также добавил куб в сцену, чтобы показать, что освещение сцены работает.

Я мог бы предположить, что либо есть проблема с шейдером, либо мне нужно определить нормали геометрии, чтобы это исправить,Я попытался поиграться с некоторыми свойствами SCNMaterial, но, похоже, они ничего не меняют.

Если это всего лишь случай определения нормалей, пожалуйста, не могли бы вы посоветовать, как мне это сделать вSwift / SceneKit.Или, может быть, я что-то упустил, любая помощь будет высоко ценится.

Снимок экрана ниже: Rendering black, unlit

Мой код ниже:

  public static func CreateMesh (size: CGFloat, resolution: CGFloat) -> SCNNode? {
    let axisCount = Int(floor(size / resolution))
    let bottomLeft = CGVector(
        dx: CGFloat(-(axisCount / 2)) * resolution,
        dy: CGFloat(-(axisCount / 2)) * resolution
    )

    var verts = Array(
        repeating: Array(
            repeating: (i: Int(0), pos: SCNVector3.init(x: 0, y: 0, z: 0)),
            count: axisCount),
        count: axisCount
    )
    var vertsStream = [SCNVector3]()

    var i : Int = 0
    for x in 0...axisCount-1 {
        for y in 0...axisCount-1 {
            verts[x][y] = (
                i,
                SCNVector3(
                    x: Float(bottomLeft.dx + CGFloat(x) * resolution),
                    y: Float.random(in: 0..<0.1),
                    z: Float(bottomLeft.dy + CGFloat(y) * resolution)
                )
            )
            vertsStream.append(verts[x][y].pos)

            i += 1
        }
    }

    var tris = [(a: Int, b: Int, c: Int)]()
    var trisStream = [UInt16]()
    for x in 0...axisCount - 2 {
        for y in 0...axisCount - 2 {
            // Quad
            tris.append((
                a: verts[x][y].i,
                b: verts[x][y+1].i,
                c: verts[x+1][y+1].i
            ))
            tris.append((
                a: verts[x+1][y+1].i,
                b: verts[x+1][y].i,
                c: verts[x][y].i
            ))
        }
    }
    for t in tris {
        trisStream.append(UInt16(t.a))
        trisStream.append(UInt16(t.b))
        trisStream.append(UInt16(t.c))
    }

    // Create scene element
    let geometrySource = SCNGeometrySource(vertices: vertsStream)
    let geometryElement = SCNGeometryElement(indices: trisStream, primitiveType: .triangles)
    let geometryFinal = SCNGeometry(sources: [geometrySource], elements: [geometryElement])
    let node = SCNNode(geometry: geometryFinal)

    ////////////////////////
    // FIX MATERIAL
    ////////////////////////
    let mat = SCNMaterial()
    mat.diffuse.intensity = 1
    mat.lightingModel = .blinn
    mat.blendMode = .replace

    node.geometry?.materials = [mat]

    return node
}

1 Ответ

0 голосов
/ 27 января 2019

После долгих поисков мне удалось найти сообщение со строкой кода, которая выглядит примерно так:

let gsNormals = SCNGeometrySource(normals: normalStream)

Итак, мне удалось выяснить, как установить нормали поверхности.Кажется, что на самом деле не так много онлайн-контента / учебных материалов, когда речь идет о более сложных темах, подобных этой, в Xcode / Swift, что весьма прискорбно.

Я настроил его для созданияплоскость параболической формы, просто для испытаний.Но этот код будет использоваться для генерации сетки из карты высот, которую теперь легко реализовать.Я думаю, что это довольно полезный код, поэтому я включил его ниже на тот случай, если у кого-то еще возникнет та же проблема, что и у меня.

fixed normals, correct lighting

public static func CreateMesh (size: CGFloat, resolution: CGFloat) -> SCNNode? {
    let axisCount = Int(floor(size / resolution))
    let bottomLeft = CGVector(
        dx: CGFloat(-(axisCount / 2)) * resolution,
        dy: CGFloat(-(axisCount / 2)) * resolution
    )

    /// Verticies ///
    var verts = Array(
        repeating: Array(
            repeating: (i: Int(0), pos: SCNVector3.init(x: 0, y: 0, z: 0)),
            count: axisCount),
        count: axisCount
    )
    var vertsStream = [SCNVector3]()

    var i = 0
    for x in 0...axisCount - 1 {
        for y in 0...axisCount - 1 {
            var dx = axisCount / 2 - x
            dx = dx * dx
            var dy = axisCount / 2 - y
            dy = dy * dy
            let yVal = Float(Double(dx + dy) * 0.0125)
            verts[x][y] = (
                i: i,
                pos: SCNVector3(
                    x: Float(bottomLeft.dx + CGFloat(x) * resolution),
                    //y: Float.random(in: 0..<0.1),
                    y: yVal,
                    z: Float(bottomLeft.dy + CGFloat(y) * resolution)
                )
            )

            vertsStream.append(verts[x][y].pos)

            i += 1
        }
    }
    ///

    /// Triangles ///
    var tris = [(a: Int, b: Int, c: Int)]()
    var trisStream = [UInt32]()
    for x in 0...axisCount - 2 {
        for y in 0...axisCount - 2 {
            // Quad
            tris.append((
                a: verts[x][y].i,
                b: verts[x][y+1].i,
                c: verts[x+1][y].i
            ))
            tris.append((
                a: verts[x+1][y].i,
                b: verts[x][y+1].i,
                c: verts[x+1][y+1].i
            ))
        }
    }
    for t in tris {
        trisStream.append(UInt32(t.a))
        trisStream.append(UInt32(t.b))
        trisStream.append(UInt32(t.c))
    }
    ///

    /// Normals ///
    var normalStream = [SCNVector3]()
    for x in 0...axisCount - 1 {
        for y in 0...axisCount - 1 {
            // calculate normal vector perp to average plane
            let leftX = x == 0 ? 0 : x - 1
            let rightX = x == axisCount - 1 ? axisCount - 1 : x + 1
            let leftY = y == 0 ? 0 : y - 1
            let rightY = y == axisCount - 1 ? axisCount - 1 : y + 1

            let avgXVector = float3(verts[rightX][y].pos) - float3(verts[leftX][y].pos)
            let avgYVector = float3(verts[x][rightY].pos) - float3(verts[x][leftY].pos)

            // If you are unfamiliar with how to calculate normals
            // search for vector cross product, this is used to find
            // a vector that is orthogonal to two other vectors, in our
            // case perpendicular to the surface
            let normal = cross(
                normalize(avgYVector),
                normalize(avgXVector)
            )

            normalStream.append(SCNVector3(normal))
        }
    }
    ///

    // Create scene element
    let gsGeometry = SCNGeometrySource(vertices: vertsStream)
    let gsNormals = SCNGeometrySource(normals: normalStream)

    let geometryElement = SCNGeometryElement(indices: trisStream, primitiveType: .triangles)
    let geometryFinal = SCNGeometry(sources: [gsGeometry, gsNormals], elements: [geometryElement])

    let node = SCNNode(geometry: geometryFinal)

    let mat = SCNMaterial()
    mat.isDoubleSided = true
    mat.lightingModel = .blinn

    node.geometry?.materials = [mat]

    return node
}
...