带有 SceneKit SCNProgram 的金属着色器

Posted

技术标签:

【中文标题】带有 SceneKit SCNProgram 的金属着色器【英文标题】:Metal Shader with SceneKit SCNProgram 【发布时间】:2016-10-08 10:51:37 【问题描述】:

我正在寻找一个可以在带有 SCNProgram 的 SceneKit 中工作的金属着色器。

谁能告诉我正确的方法声明/如何连接它?

let program = SCNProgram()
program.vertexFunctionName = "myVertex"
program.fragmentFunctionName = "myFragment"
material.program = program

然后是着色器

//MyShader.metal

vertex something myVertex(something)

    return something;


fragment float4 myFragment(something)

    return something

我只是在寻找最基本的例子。

【问题讨论】:

【参考方案1】:

我剪掉了所有“不必要”的东西,这是最基本的,几乎就是我的第一个金属着色器。

接下来我将开始研究连接其他顶点属性(颜色、法线),并可能进行一些基本的光照计算。

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

struct MyNodeBuffer 
    float4x4 modelTransform;
    float4x4 modelViewTransform;
    float4x4 normalTransform;
    float4x4 modelViewProjectionTransform;
;

typedef struct 
    float3 position [[ attribute(SCNVertexSemanticPosition) ]];
 MyVertexInput;

struct SimpleVertex

    float4 position [[position]];
;


vertex SimpleVertex myVertex(MyVertexInput in [[ stage_in ]],
                             constant SCNSceneBuffer& scn_frame [[buffer(0)]],
                             constant MyNodeBuffer& scn_node [[buffer(1)]])

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

    return vert;


fragment half4 myFragment(SimpleVertex in [[stage_in]])

    half4 color;
    color = half4(1.0 ,0.0 ,0.0, 1.0);

    return color;

抱歉任何错别字,在我的手机上编辑了它......

【讨论】:

这真是太棒了,有没有通过SCNNode的材质设置的纹理的例子? - 目前可以理解,它只是将我的对象涂成红色。【参考方案2】:

@lock 上面的回答很棒,所以我想通过提供一个纹理示例来扩展它,正如 OP 在 cmets 中要求的那样。

以下是您如何配置材质以使用着色器并连接自定义纹理:

let program = SCNProgram()
program.fragmentFunctionName = "myFragment"
program.vertexFunctionName = "myVertex"

material.program = program

let image = UIImage(named: "diffuse")!
let imageProperty = SCNMaterialProperty(contents: image)
// The name you supply here should match the texture parameter name in the fragment shader
material.setValue(imageProperty, forKey: "diffuseTexture")

这是从纹理中采样的修改后的着色器:

#include <metal_stdlib>

using namespace metal;

#include <SceneKit/scn_metal>

struct MyNodeBuffer 
    float4x4 modelTransform;
    float4x4 modelViewTransform;
    float4x4 normalTransform;
    float4x4 modelViewProjectionTransform;
;

typedef struct 
    float3 position [[ attribute(SCNVertexSemanticPosition) ]];
    float2 texCoords [[ attribute(SCNVertexSemanticTexcoord0) ]];
 MyVertexInput;

struct SimpleVertex

    float4 position [[position]];
    float2 texCoords;
;

vertex SimpleVertex myVertex(MyVertexInput in [[ stage_in ]],
                             constant SCNSceneBuffer& scn_frame [[buffer(0)]],
                             constant MyNodeBuffer& scn_node [[buffer(1)]])

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

    return vert;


fragment half4 myFragment(SimpleVertex in [[stage_in]],
                          texture2d<float, access::sample> diffuseTexture [[texture(0)]])

    constexpr sampler sampler2d(coord::normalized, filter::linear, address::repeat);
    float4 color = diffuseTexture.sample(sampler2d, in.texCoords);
    return half4(color);

【讨论】:

谢谢谢谢谢谢!我会为此给你小费。我已经把你的书沃伦带来了,这正是我需要的! 哈哈,乐于助人。感谢您对本书的支持:) @Chris 是的,您引用的功能已打包在 SCNTechnique 类中。您也许可以依赖默认的 SceneKit 着色器,但最终可能会自己编写。 @Chris 当然可以。将对象材质设置为包含“MTLTexture”,然后通过计算着色器进行修改。运行良好,性能良好(没有 CPU 往返),并且比整理“SCNTechnique”更容易。虽然“SCNTechnique”是实现屏幕空间效果(模糊、光晕等)的方法。 虽然理论上看起来不错,但我得到的只是没有阴影或纹理的纯白色轮廓。知道我做错了什么吗?最近的 ios 版本可能发生了一些变化?

以上是关于带有 SceneKit SCNProgram 的金属着色器的主要内容,如果未能解决你的问题,请参考以下文章

使用金属顶点和片段着色器将 MTLTexture 传递给 SCNProgram

SCNProgram - 如何将“mat4”类型的制服传递给自定义着色器?

将 Metal 缓冲区传递给 SceneKit 着色器

为什么iOS 8上的SceneKit无法编译我的自定义着色器?

SpriteKit 中的顶点着色器

将带有物理的 collada 场景加载到 SceneKit