如何在SCNScene / SCNView中连续动画SCNProgram着色器?

时间:2017-05-19 22:20:15

标签: scenekit metal

在MacOS应用程序中,我有一个由SCNProgram定义的模式,该模式映射到SCNPlane。

看起来像这样:

enter image description here

着色器应该使三角形行移动,就像在这个视频中一样。该视频是在MTKview内部运行的同一着色器的屏幕抓取。

animated texture

在此着色器的SceneKit版本中,着色器仅在我单击视图中的平面时动画。

如何让SceneKit视图(或Scene?)一直为着色器设置动画?这个应用程序再次在MacOS上。我试过设置

self.gameView!.isPlaying = true

但这似乎无法解决问题

这是Metal 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;

static float rand(float2 uv)
{
    return fract(sin(dot(uv, float2(12.9898, 78.233))) * 43758.5453);
}

static float2 uv2tri(float2 uv)
{
    float sx = uv.x - uv.y / 2;
    float sxf = fract(sx);
    float offs = step(fract(1 - uv.y), sxf);
    return float2(floor(sx) * 2 + sxf + offs, uv.y);
}

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

vertex SimpleVertexWithUV trianglequiltVertex(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);
    vert.uv = in.texCoords;
    return vert;
}

fragment float4 trianglequiltFragment(SimpleVertexWithUV in [[stage_in]],
                             constant SCNSceneBuffer& scn_frame [[buffer(0)]],
                             constant myPlaneNodeBuffer& scn_node [[buffer(1)]])
{
    float4 fragColor;
    float2 uv = in.uv*10;
    float timer = scn_frame.time;
    uv.y += timer;

    float t = timer * 0.8;
    float tc = floor(t);
    float tp = smoothstep(0, 0.8, fract(t));

    float2 r1 = float2(floor(uv.y), tc);
    float2 r2 = float2(floor(uv.y), tc + 1);
    float offs = mix(rand(r1), rand(r2), tp);

    uv.x += offs * 8;

    float2 p = uv2tri(uv);
    float ph = rand(floor(p)) * 6.3 + p.y * 0.2;
    float c = abs(sin(ph + timer));

    fragColor = float4(c, c, c, 1);
    return(fragColor);

}

这是视图控制器:

import SceneKit
import QuartzCore

class GameViewController: NSViewController {


    @IBOutlet weak var gameView: GameView!

    override func awakeFromNib(){
        super.awakeFromNib()

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

        Swift.print(gameView.colorPixelFormat.rawValue)

    // 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

    // play it always?
        self.gameView!.isPlaying = true

        var geometry:SCNGeometry

        geometry = SCNPlane(width:10, height:10)

        let geometryNode = SCNNode(geometry: geometry)


        let program = SCNProgram()
        program.fragmentFunctionName = "trianglequiltFragment"
        program.vertexFunctionName = "trianglequiltVertex"

        let gradientMaterial = SCNMaterial()
        gradientMaterial.program = program
        gradientMaterial.specular.contents = NSColor.black
        gradientMaterial.locksAmbientWithDiffuse = true
        geometry.materials = [gradientMaterial]
        geometryNode.geometry?.firstMaterial?.lightingModel = .constant

        scene.rootNode.addChildNode(geometryNode)

    }

}

1 个答案:

答案 0 :(得分:1)

尝试设置:

gameView?.rendersContinuously = true

(你不需要那些额外的'自我。也是。)