Custom Variable Declarations Using Metal With Scene Kit Shader Modifiers

假如想象 提交于 2020-01-05 04:58:53

问题


I am having difficulty passing uniforms to Scene Kit's shader modifiers. This seems to work fine when using OpenGL but not when using Metal.

I have used SCNProgram successfully before but wanted to take advantage of SceneKit's tessellator instead of setting up compute shaders for tessellation.

But I want to use the code I have already written in Metal rather than using OpenGL.

There is unfortunately not a great deal of examples of how to do this. This Swift Playground illustrates how to do this nicely in OpenGL.

https://github.com/markpmlim/Twister/blob/master/Twister.playground/Contents.swift

//Geometry - Metal will translate the OpenGL code.
let geometryShaderModifier =
"uniform float twistFactor;\n" +
"mat4 rotationAroundX(float angle) {\n" +
"return mat4(1.0,    0.0,         0.0,        0.0,\n" +
"            0.0,    cos(angle), -sin(angle), 0.0,\n" +
"            0.0,    sin(angle),  cos(angle), 0.0,\n" +
"            0.0,    0.0,         0.0,        1.0);\n" +
"}\n" +
"#pragma body\n" +
"float rotationAngle = _geometry.position.x * twistFactor;\n" +
"mat4 rotationMatrix = rotationAroundX(rotationAngle);\n" +
"_geometry.position *= rotationMatrix;\n" +
"vec4 twistedNormal = vec4(_geometry.normal, 1.0) * rotationMatrix;\n" +
"_geometry.normal   = twistedNormal.xyz;\n"

But when I change it to Metal it doesn't work:

let geometryShaderModifier =
"#pragma arguments \n" +
"float twistFactor;\n" +
"float4x4 rotationAroundX(float angle) {\n" +
"return float4x4(1.0,    0.0,         0.0,        0.0,\n" +
"                0.0,    cos(angle), -sin(angle), 0.0,\n" +
"                0.0,    sin(angle),  cos(angle), 0.0,\n" +
"                0.0,    0.0,         0.0,        1.0);\n" +
"}\n" +
"#pragma body\n" +
"float rotationAngle = _geometry.position.x * twistFactor;\n" +
"float4x4 rotationMatrix = rotationAroundX(rotationAngle);\n" +
"_geometry.position *= rotationMatrix;\n" +
"float4 twistedNormal = float4(_geometry.normal, 1.0) * rotationMatrix;\n" +
"_geometry.normal   = twistedNormal.xyz;\n"

This is how I'm providing the value, using key-value coding:

 // The uniform "twistFactor" must be assigned a value.
 torus.setValue(1.0, forKey: "twistFactor")

I guess I could just switch back to using OpenGL to get round this but it's a little frustrating that the first couple of lines from Apple's shader modifier documentation are so tricky to get working.

// For Metal, a pragma directive and one custom variable on each line:
#pragma arguments
float intensity;

I've seen various posts floating around different forums with the same basic issue, it'd be great if they could provide clearer documentation for this.

I get the following error message:

program_source:2566:50: error: use of undeclared identifier 'twistFactor'

Thanks in advance for any help!


回答1:


You can use the #pragma declaration marker to help SceneKit differentiate the shader modifier arguments from local functions:

let geometryShaderModifier =
    "#pragma arguments\n" +
     "float twistFactor;\n" +
     "#pragma declaration\n" + // HERE
     "float4x4 rotationAroundX(float angle) {\n" +
     "return float4x4(1.0,    0.0,         0.0,        0.0,\n" +
     "                0.0,    cos(angle), -sin(angle), 0.0,\n" +
     "                0.0,    sin(angle),  cos(angle), 0.0,\n" +
     "                0.0,    0.0,         0.0,        1.0);\n" +
     "}\n" +
     "#pragma body\n" +
     "float rotationAngle = _geometry.position.x * twistFactor;\n" +
     "float4x4 rotationMatrix = rotationAroundX(rotationAngle);\n" +
     "_geometry.position *= rotationMatrix;\n" +
     "float4 twistedNormal = float4(_geometry.normal, 1.0) * rotationMatrix;\n" +
     "_geometry.normal   = twistedNormal.xyz;\n"


来源:https://stackoverflow.com/questions/57450557/custom-variable-declarations-using-metal-with-scene-kit-shader-modifiers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!