iOS+SceneKit: How to apply toon shader on texture?


I want to use a toon-shader with SceneKit on iOS8+ to render a sphere with an Earth texture on it. I also want to add a toon shader for rendering the Earth. So far the shader works on the lighting, but the texture isn't shaded by the toon-shader (cp. to the image below, the texture should also be "tooned").

Someone any ideas?

enter image description here

Here's my view controller code (self.sceneKitView is an instance of SCNView):

@implementation ToonViewController

- (void)viewDidLoad {

    [super viewDidLoad];

    SCNScene *scene = [SCNScene scene];

    // create and add a camera to the scene
    SCNNode *cameraNode = [SCNNode node]; = [SCNCamera camera];
    [scene.rootNode addChildNode:cameraNode];
    // place the camera
    cameraNode.position = SCNVector3Make(0, 0, 15);

    // create and add a light to the scene
    SCNNode *lightNode = [SCNNode node];
    lightNode.light = [SCNLight light];
    lightNode.light.type = SCNLightTypeOmni;
    lightNode.position = SCNVector3Make(0, 10, 10);
    [scene.rootNode addChildNode:lightNode];

    // create and add an ambient light to the scene
    SCNNode *ambientLightNode = [SCNNode node];
    ambientLightNode.light = [SCNLight light];
    ambientLightNode.light.type = SCNLightTypeAmbient;
    ambientLightNode.light.color = [UIColor darkGrayColor];
    [scene.rootNode addChildNode:ambientLightNode];

    // set up the scene
    self.sceneKitView.scene = scene;
    self.sceneKitView.allowsCameraControl = YES;
    self.sceneKitView.showsStatistics = NO;
    self.sceneKitView.backgroundColor = [UIColor clearColor];

    NSMutableDictionary* shaders = [[NSMutableDictionary alloc] init];
    shaders[SCNShaderModifierEntryPointLightingModel] = [[NSString alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"fixed_toon" withExtension:@"shader"]

    SCNNode* earth = [SCNNode nodeWithGeometry:[SCNSphere sphereWithRadius:5.0]];
    earth.position = SCNVector3Make(0.0, 0.0, 0.0);
    [scene.rootNode addChildNode:earth];

    [earth runAction:[SCNAction repeatActionForever:[SCNAction rotateByX:0.0 y:0.25 z:0.0 duration:1.0]]];

    SCNMaterial* earthMaterial = [SCNMaterial material];
    earthMaterial.diffuse.contents = [UIImage imageNamed:@"Earth.png"];
    earthMaterial.specular.contents = [UIColor whiteColor];
    earthMaterial.specular.intensity = 0.2;
    earthMaterial.locksAmbientWithDiffuse = NO;
    earthMaterial.shaderModifiers = shaders;

    earth.geometry.firstMaterial = earthMaterial;



And this is the fixed_toon.shader file:

vec3 lDir = normalize(vec3(0.1, 1.0, 1.0));
float dotProduct = dot(_surface.normal, lDir);

_lightingContribution.diffuse += (dotProduct*dotProduct*_light.intensity.rgb);
_lightingContribution.diffuse = floor(_lightingContribution.diffuse*4.0)/3.0;

vec3 halfVector = normalize(lDir + _surface.view);

dotProduct = max(0.0, pow(max(0.0, dot(_surface.normal, halfVector)), _surface.shininess));
dotProduct = floor(dotProduct*3.0)/3.0;

//_lightingContribution.specular += (dotProduct*_light.intensity.rgb);
_lightingContribution.specular = vec3(0,0,0);

The shader you have is only a lighting shader. If you want the earth to be tooned, you need a fragment shader.

Look at the shader file all of the math is related to light. You need something that will adjust the pixel color of the texture. Then connect it using the SCNShaderModifierEntryPointFragment entry point.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at


Login to comment


TOP Ranking