I have to build a Swift app that can color a 3D object with various gestures. I have a Collada file that I imported as a SceneKit object. I can't find a way to color it with tap. I tried to convert Obj-C from the WWDC example but it's not working for me.
I tried to apply a SpriteKit as texture on the 3D object but that's the result:
As the user taps the screen, the app should take the coordinates of the texture of the 3D object and then add in that point a SpriteKit node.
Before:
After:
I don't know why the texture explode in that way.
Thank you!
The SpriteKit scene coordinate system doesn't map to texture coordinates in the same way an image does. Pixel coordinates in an image have the y-axis increasing downward; in a SpriteKit scene, the y-axis goes up.
This is a lot more apparent if you just map that SpriteKit scene onto an SCNPlane
that's the only thing in a SceneKit scene — you'll see that the image is flipped.
Left: Image as loaded from bundle, Right: Image filling an SKScene
mapped to a plane (with annotations)
To fix this, you'll need a two-step coordinate transformation:
SKScene
You can do this either within the SKScene
, or in the SCNMaterialProperty
that texture-maps the SpriteKit content onto a SceneKit object. I favor the SCNMaterialProperty
approach — just set the appropriate matrix for its contentsTransform
property:
let translate = SCNMatrix4MakeTranslation(0, 1, 0)
let yFlippedTranslate = SCNMatrix4Scale(translate, 1, -1, 1)
material.diffuse.contentsTransform = yFlippedTranslate
Note that if you're also trying to map touch/click events into the SpriteKit scene using the material's texture coordinates (via SCNHitTestResult
), you'll need to perform a similar transformation there:
let texcoord = result.textureCoordinatesWithMappingChannel(0)
sprite.position.x = texcoord.x * skScene.size.width
sprite.position.y = (1 - texcoord.y) * skScene.size.height