在OpenGL程序中,您通常在顶点着色器中声明类似的内容
varying bool aBooleanVariable;
然后读取片段着色器中的值。你如何在SCNShadable
入口点的框架内做到这一点?例如,从SCNShaderModifierEntryPointGeometry
到SCNShaderModifierEntryPointFragment
。
接收参数似乎是通过使用pragma参数定义的,我提供了我的测试SCNShaderModifierEntryPointFragment
来说明。
#pragma arguments
bool clipFragment
#pragma body
if (clipFragment) {
discard_fragment();
}
但是,参数pragma不能用于输出SCNShaderModifierEntryPointGeometry
入口点中的值。
我found an article表示它可以用GLSL语法完成,但我试图找到Metal方式,我甚至无法重现结果。
答案 0 :(得分:3)
如果将SCNView
渲染API切换为OpenGL ES,则可以使其正常工作。然后它将接受包含变化限定符的GLSL代码。
varying float clipFragment;
#pragma body
clipFragment = 1.0;
varying float clipFragment;
#pragma body
if (clipFragment > 0.0) {
discard;
}
我向Apple开了一张票,得到了以下回复 -
这是对的。 SceneKit团队已经开放了一个正式的增强请求(错误#28206462),以调查将此功能添加到Metal。在此之前,您必须选择使用OpenGL渲染器。
答案 1 :(得分:3)
我有类似的问题,并设法找出解决方案。我不知道它的工作原理有多远,但它可以在iOS 11的XCode 9上运行。以下是使用变量float3为坐标查找自定义立方体贴图纹理的示例。
几何修改器:
#include <metal_stdlib>
#pragma varyings
float3 cubemapCoord;
#pragma body;
out.cubemapCoord = _geometry.normal;
表面修饰符:
#include <metal_stdlib>
#pragma arguments
texturecube<float> texture;
#pragma body
constexpr sampler s(filter::linear, mip_filter::linear);
_surface.diffuse = texture.sample(s, in.cubemapCoord);
用于分配材料的Swift代码:
do {
let loader = MTKTextureLoader.init(device: MTLCreateSystemDefaultDevice()!)
let url = Bundle.main.url(forResource: "cubemap", withExtension: "pvr", subdirectory: "art.scnassets")!
let texture = try loader.newTexture(URL: url, options: nil)
let materialProperty = SCNMaterialProperty.init(contents: texture)
geometry.setValue(materialProperty, forKey: "texture")
} catch {
print(error.localizedDescription)
}
答案 2 :(得分:2)
在某些时候,您将遇到SCNShadable
可以完成的限制,需要转到SCNProgram
。遗憾的是,这样做意味着您需要提供顶点和片段着色器的完整实现。从积极的方面来说,将值从顶点传递到片段着色器非常简单。您只需将变量添加到使用stage_in
限定符标识的结构中(假设您使用的是Metal)。但这并不是你所要求的,而且有一种解决方法。
#pragma arguements
在这种情况下不会工作;它是用于传递在渲染过程中不变的常量。
相反,我建议您重新调整一下SceneKit在其着色器中使用的现有变量之一。到目前为止,毫无疑问,当SceneKit无法编译时,它会将其着色器源代码转储到stdout。 Metal着色器定义了一个commonprofile_io
结构,它从顶点传递到片段着色器,它包括:位置,颜色,纹理坐标,法线等。如果你没有使用顶点颜色,那么就可以使用它存储4个浮点值(rgba)。需要注意的是,SceneKit会优化要渲染的几何体源的着色器;如果几何源不包含顶点颜色,则commonprofile_io
结构将不会有vertexColor
变量。
非常有兴趣了解更好的解决方案。
答案 3 :(得分:0)
我也在这个问题上苦苦挣扎,而且我最近发现了这个东西,这让我大开眼界。它极大地帮助了我掌握SceneKit,着色器,着色器修改器和OpenGL / Metal的协同工作,以及在编写着色器修改器时可以使用的工具/方法。 此外,我相信当前接受的答案不再正确(幸运的是!?)。
SceneKit提供默认的顶点和片段Metal着色器。将着色器修改器注入到这些着色器中。
在Xcode中捕获GPU帧时,可以找到这些默认的Metal着色器。
双击commonprofile_vert
或commonprofile_frag
(两个着色器都在同一“文件”中,如“详细信息”列中的相同值所示)。
此文件中包含很多信息,它演示了SceneKit在渲染时如何与GPU对话的一些内部工作原理。 This is an example of the file(尽管此版本已有两年的历史了,但仍是典范)。
请注意以下几行是着色器修改器的注入位置。
// DoLightModifier START
// DoLightModifier END
...
// DoGeometryModifier START
// DoGeometryModifier END
...
// DoSurfaceModifier START
// DoSurfaceModifier END
...
// DoFragmentModifier START
// DoFragmentModifier END
您将看到您的着色器修改器已放置在此处。
寻找#ifdef USE_EXTRA_VARYINGS
。您在geometry修改器中声明的所有varying
变量都显示为commonprofile_io
结构上的属性。您将使用以下实例:commonprofile_io out;
。
此文件还演示了为什么需要varyings
才能在几何体和片段着色器之间进行通信。以及为什么在片段着色器中可以访问_surface
:片段修改器和表面修改器具有相同的作用域。
我绝对为苹果没有记录或暗示这些东西而感到困惑,除了一些隐藏的WWDC幻灯片。我不知道没有几个空闲时间的人应该怎么弄清楚这是怎么回事。