Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: Setting SCNMaterial works for SCNBox but not for SCNGeometry loaded from Wings3D DAE

This code excerpt (scene, camera, light, etc. cut out of the code) works in Swift on an iOS simulator:

    let boxNode = SCNNode()

    // Create a box
    boxNode.geometry = SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0.1)
    let numFaces = 6

    scene.rootNode.addChildNode(boxNode)

    // create and configure a material for each face
    var materials: [SCNMaterial] = Array()

    for i in 1...numFaces
    {
        let material = SCNMaterial()
        material.diffuse.contents = UIImage(named: "texture")
        materials += material
    }

    // set the material to the 3d object geometry
    boxNode.geometry.materials = materials

It generates a box with each face being the checkered image.

SCNBox in App

Trying the same thing with a simple stock geometry created in Wings3D, saved to a DAE, and loaded in the app gives me an appropriate shape, but no shading and image on the faces:

    let boxNode = SCNNode()

    // Load the geometry
    let urlToColladaFile = NSBundle.mainBundle().URLForResource("Objects", withExtension:"dae")
    let sceneSource = SCNSceneSource(URL:urlToColladaFile, options:nil)

    boxNode.geometry = sceneSource.entryWithIdentifier("dodecahedron3-0", withClass:SCNGeometry.self) as SCNGeometry
    let numFaces = 10

    scene.rootNode.addChildNode(boxNode)

    // create and configure a material for each face
    var materials: [SCNMaterial] = Array()

    for i in 1...numFaces
    {
        let material = SCNMaterial()
        material.diffuse.contents = UIImage(named: "texture")
        materials += material
    }

    // set the material to the 3d object geometry
    boxNode.geometry.materials = materials

Dodecahedron from Wings3D

What am I missing?

like image 223
henryaz Avatar asked Jul 12 '14 07:07

henryaz


2 Answers

does your geometry have texture coordinates? You can verify this programmatically (by checking if a source with the SCNGeometrySourceSemanticTexcoord semantic exists) or in the SceneKit editor built into Xcode.

Also note that you don't have to create one material per geometry element. If they are all the same, just build an array of one material and it will be used for the entire geometry.

like image 164
mnuages Avatar answered Oct 09 '22 18:10

mnuages


Thanks, mnuages & rickster. Your deductions led me to researching my options within Wings3D, and I was able to solve the problem within Wings3D.

In short, I need to create a UV Mapping for each face of the solid.

For a regular polyhedra, I had multiple options:

  • Select the whole body (and hence all of the faces), do a single UV Mapping of it, and have one image which was stretched over all of the faces. There are online tutorials for how to do this.
  • For each face, select it, do a UV Mapping (I typically chose Projection Normal to do it), and then each face will get the same mapping, no matter how many images you put into the materials array in my code.
  • For each face, do the above first. Then go into the Outliner window, and duplicate the AUV (Automatic UV) file so that there is a unique one for each face. Then select each AUV and assign it to a different face. That would give me as many faces as I wanted, allowing me, for instance, to create a new image for each face of a die. This I had to figure out -- there seems to be a one-to-one mapping of AUV mappings within Wings3D to what SceneKit calls Geometry Elements when setting the Materials.
  • A combination of the above, so that multiple faces could share the same mapping and then be assigned the same image automatically.

This all becomes a little more complicated if I started adding bezels or smoother chamfers to the edges, for now I need to make sure that the UV Mapping makes sense for each set of faces I work on. Again, there are tutorials on this on the web.

Thanks again!

Cheers, Henry

like image 33
henryaz Avatar answered Oct 09 '22 18:10

henryaz