问题
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