why is metal shader gradient lighter as a SCNProgram applied to a SceneKit Node than it is as a MTKView?

Viewed 1588

I have a gradient, generated by a Metal fragment shader that I've applied to a SCNNode defined by a plane geometry.

It looks like this:

scenekit gradient plane node

When I use the same shader applied to a MTKView rendered in an Xcode playground, the colors are darker. What is causing the colors to be lighter in the Scenekit version?

enter image description here

Here is the Metal shader and the GameViewController.

Shader:

#include <metal_stdlib>
using namespace metal;
#include <SceneKit/scn_metal>

struct myPlaneNodeBuffer {
    float4x4 modelTransform;
    float4x4 modelViewTransform;
    float4x4 normalTransform;
    float4x4 modelViewProjectionTransform;
    float2x3 boundingBox;
};

typedef struct {
    float3 position [[ attribute(SCNVertexSemanticPosition) ]];
    float2 texCoords [[ attribute(SCNVertexSemanticTexcoord0) ]];
} VertexInput;

struct SimpleVertexWithUV
{
    float4 position [[position]];
    float2 uv;
};


vertex SimpleVertexWithUV gradientVertex(VertexInput in [[ stage_in ]],
                         constant SCNSceneBuffer& scn_frame [[buffer(0)]],
                         constant myPlaneNodeBuffer& scn_node [[buffer(1)]])
{
    SimpleVertexWithUV vert;

    vert.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0);

    int width = abs(scn_node.boundingBox[0].x) + abs(scn_node.boundingBox[1].x);
    int height = abs(scn_node.boundingBox[0].y) + abs(scn_node.boundingBox[1].y);

    float2 resolution = float2(width,height);

    vert.uv = vert.position.xy * 0.5 / resolution;

    vert.uv = 0.5 - vert.uv;

    return vert;
}

fragment float4 gradientFragment(SimpleVertexWithUV in [[stage_in]],
                           constant myPlaneNodeBuffer& scn_node [[buffer(1)]])
{
    float4 fragColor;
    float3 color = mix(float3(1.0, 0.6, 0.1), float3(0.5, 0.8, 1.0), sqrt(1-in.uv.y));
    fragColor = float4(color,1);
    return(fragColor);
}

Game view controller:

import SceneKit
import QuartzCore


class GameViewController: NSViewController {

@IBOutlet weak var gameView: GameView!

override func awakeFromNib(){
    super.awakeFromNib()

    // create a new scene
    let scene = SCNScene()

    // create and add a camera to the scene
    let cameraNode = SCNNode()
    cameraNode.camera = SCNCamera()
    scene.rootNode.addChildNode(cameraNode)

    // place the camera
    cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)

    // turn off default lighting
    self.gameView!.autoenablesDefaultLighting = false

    // set the scene to the view
    self.gameView!.scene = scene

    // allows the user to manipulate the camera
    self.gameView!.allowsCameraControl = true

    // show statistics such as fps and timing information
    self.gameView!.showsStatistics = true

    // configure the view
    self.gameView!.backgroundColor = NSColor.black

    var geometry:SCNGeometry

    geometry = SCNPlane(width:10, height:10)
    let geometryNode = SCNNode(geometry: geometry)

    let program = SCNProgram()
    program.fragmentFunctionName = "gradientFragment"
    program.vertexFunctionName = "gradientVertex"

    let gradientMaterial = SCNMaterial()
    gradientMaterial.program = program
    geometry.materials = [gradientMaterial]


    scene.rootNode.addChildNode(geometryNode)

    }

}
3 Answers
Related