Harrison
Harrison

Reputation: 69

Custom Geometry Mesh -- How to Triangulate in Order to Look Smooth

EDIT: Altering the subdivision count seems to have smoothened the surface. However, my surface now seems to have shrunk... I can't seem to get it back to it's normal size. Why does this happen and how can I fix the effect?

I'm hoping to draw hundreds of smooth-looking planes sequentially in 3D space to model data. These planes will all look slightly different, but for each one I am only given the 4 corners of the plane -- plus an arbitrary point in the middle of the plane to give the surface a slight curvature for aesthetic appeal.

Thanks to help from this site, I've triangulated a surface somewhat, but it looks like a pyramid. Here's what I have so far:

    var vertices = [SCNVector3(x: -5, y: 5, z: 0),
                    SCNVector3(x: 0, y: 5, z: -5),
                    SCNVector3(x: 5, y: 5, z: 0),

                    SCNVector3(x: 0, y: 5, z: 5),
                    SCNVector3(x: 0, y: 7, z: 0)]

    var indices : [CInt] = [4,0,1,
                            4,1,2,
                            4,2,3,
                            4,3,0]

    var normals = [SCNVector3]()
    var normalMap = [Int : SCNVector3]()
    for (var i = 0; i < vertices.count; i++) {
        var origVec = SCNVector3(x: 0.0, y: 0.0, z: 0.0)
        normalMap.updateValue(origVec, forKey: i)
    }


    //CALCULATE FACE NORMALS -->
    for (var i = 0; i < vertices.count - 2; i++) {
        var p1 = vertices[i] //B
        var p2 = vertices[i + 1] //A
        var p3 = vertices[vertices.count - 1] //C

        var vector1 = SCNVector3(x: 0, y: 0, z: 0)
        var vector2 = SCNVector3(x: 0, y: 0, z: 0)

        vector1.x = p1.x - p2.x
        vector1.y = p1.y - p2.y
        vector1.z = p1.z - p2.z

        vector2.x = p3.x - p2.x
        vector2.y = p3.y - p2.y
        vector2.z = p3.z - p2.z

        var faceNormal = crossProduct(vector1, v2: vector2)
        ((normalMap[i]!).x) += faceNormal.x
        ((normalMap[i]!).y) += faceNormal.y
        ((normalMap[i]!).z) += faceNormal.z
        ((normalMap[i + 1]!).x) += faceNormal.x
        ((normalMap[i + 1]!).y) += faceNormal.y
        ((normalMap[i + 1]!).z) += faceNormal.z
        ((normalMap[vertices.count - 1]!).x) += faceNormal.x
        ((normalMap[vertices.count - 1]!).y) += faceNormal.y
        ((normalMap[vertices.count - 1]!).z) += faceNormal.z
    }

    for (var i = 0; i < vertices.count; i++) {
            normals.append(normalize(normalMap[i]!))
    }



    //VERTEX SOURCE -->
    var vertexSource = SCNGeometrySource(vertices: vertices, count: 5)

    //NORMAL SOURCE -->
    var normalSource = SCNGeometrySource(normals: normals, count: 5)

    //INDICES AS DATA -->
    var data = NSData(bytes: indices, length: countElements(indices) * sizeof(Int))

    //GEOMETRY ELEMENT -->
    var geometryElement = SCNGeometryElement(data: data, primitiveType: .Triangles, primitiveCount: 4, bytesPerIndex: sizeof(CInt))

    //GEOMETRY -->
    var geometry = SCNGeometry(sources: [vertexSource, normalSource], elements: [geometryElement])

    geometry.firstMaterial?.doubleSided = true
    let node = SCNNode(geometry: geometry)
    self.rootNode.addChildNode(node)

Since I would like for this pyramid-ish shape to look smooth, do I just need to hardwire many more triangles? If so, what's the "magic number?"

Or, is there some way to automate that triangulation process?

Or, perhaps I am barking up the wrong tree and merely need to look to improve the look of the model with lighting or shading or something of that nature. Would altering the subdivision count offer any sort of help?

Thanks for any and all help; I have never built custom geometries before.

Upvotes: 0

Views: 1341

Answers (1)

reden
reden

Reputation: 1003

The usual way to achieve smooth results without subdivision is to average the normals of the vertices touching the adjacent planes. Ie, get the average of all normals in the same location. It is not clear from the question whether this is an acceptable solution or whether each plane needs to be clearly distinguishable.

Here is a link describing the process (look at the bottom): http://www.lighthouse3d.com/opengl/terrain/index.php3?normals

In conclusion, each vertex should have the average normal vector of the surrounding polygons.

Upvotes: 1

Related Questions