Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scenekit Shader - Turn off smooth shading, and any normal interpolation

Tags:

scenekit

I have an animated model (collada) exported from Blender. From my understanding the shader tries interpolate the normal during animation and I want to prevent that from happening. My model is very blocky but Scenekit makes it smooth like Apple Product. I want it to look like minecraft.

like image 925
40pro Avatar asked Mar 09 '17 07:03

40pro


1 Answers

I'm assuming you're going after a flat shaded low poly kind of look similar to that shown to the left below.

Flat and smooth shaded

This example uses a SCNSphere as the geometry source, but it should also work on the geometry you've loaded from the dae file.

The model you've loaded, and the default SCNSphere are made up of many faces. In the case of smooth models vertexes are often shared across faces, each vertex can only have one normal. What we need to do is ensure each face does not share vertices with neighbouring faces, and that the normal used on each vertex is calculated based on the normal direction of the face only.

SceneKit doesn't have any native functionality to do this itself, however another one of Apple's frameworks does... ModelIO.

You'll need to import ModelIO.

import ModelIO
import SceneKit.ModelIO

The code I used to generate the two spheres above is shown below.

let geom = SCNSphere(radius: 0.5)

// convert SceneKit geometry to ModelIO mesh object
let modelMesh = MDLMesh(scnGeometry: geom)
// ensure vertices are not shared with neighbouring faces
modelMesh.makeVerticesUnique()
// replace existing 'smooth' normal definition with an 'non-smoothed' normal
modelMesh.addNormals(withAttributeNamed: "normal", creaseThreshold: 1.0)

// create SceneKit geometry from ModelIO mesh object
let flattenedGeom = SCNGeometry(mdlMesh: modelMesh)
let flattenedNode = SCNNode(geometry: flattenedGeom)
scene.rootNode.addChildNode(flattenedNode)

// smooth sphere for comparison only
let sphereNodeSmooth = SCNNode(geometry: SCNSphere(radius: 0.5))
sphereNodeSmooth.position = SCNVector3Make(0, 1.2, 0)
scene.rootNode.addChildNode(sphereNodeSmooth)

Of course I'd probably recommend that you modify your model in Blender to be exported in this manner (unique vertices, non-smoothed normals). This would save your application from having to do more processing than is needed when loading assets. Unfortunately my Blender knowledge is lacking somewhat.

like image 185
lock Avatar answered Nov 20 '22 01:11

lock