将 SCNGeometryTessellator 与使用自定义 SCNProgram 的 SCNGeometry 一起使用?
Using SCNGeometryTessellator with a SCNGeometry that uses a custom SCNProgram?
我正在尝试向某些使用自定义 SCNProgram
的 SceneKit 几何体添加 SCNGeometryTessellator
。我的几何体渲染正常,但只要我添加 SCNGeometryTessellator
,我就会看到这个错误:
[SceneKit] Error: Compiler error while building render pipeline state for node <C3DNode:0x1053e9700 "(null)"
geometry: <C3DParametricGeometry<Plane>:0x1053e9160 "(null)"
mesh: <C3DMesh 0x282590620 "(null)"
element0: <C3DMeshElement 0x2823922b0 type:triangles primCount:200 channels:1 indexBytes:2 offset:0 acmr:0.605000 inst:1 dataSize:1200 shared:0x0>
source position (channel:0) : <C3DMeshSource 0x2837fbbf0(position) data:(0x281009ce0) mut:0 count:121 type:float3 divisor:0 mtl:0 offset:0 stride:32>
source normal (channel:0) : <C3DMeshSource 0x2837fb480(normal) data:(0x281009ce0) mut:0 count:121 type:float3 divisor:0 mtl:0 offset:12 stride:32>
source texcoord (channel:0) : <C3DMeshSource 0x2837fbb80(texcoord) data:(0x281009ce0) mut:0 count:121 type:float2 divisor:0 mtl:0 offset:24 stride:32>
renderable element0: <C3DMeshElement 0x2823922b0 type:triangles primCount:200 channels:1 indexBytes:2 offset:0 acmr:0.605000 inst:1 dataSize:1200 shared:0x0>
renderable source position: <C3DMeshSource 0x2837fbbf0(position) data:(0x281009ce0) mut:0 count:121 type:float3 divisor:0 mtl:0 offset:0 stride:32>
renderable source normal: <C3DMeshSource 0x2837fb480(normal) data:(0x281009ce0) mut:0 count:121 type:float3 divisor:0 mtl:0 offset:12 stride:32>
renderable source texcoord: <C3DMeshSource 0x2837fbb80(texcoord) data:(0x281009ce0) mut:0 count:121 type:float2 divisor:0 mtl:0 offset:24 stride:32>
>
mat0: <C3DMaterial 0x2837159d0 : "(null)", custom <C3DFXTechnique>>
>
>:
Error Domain=AGXMetalA14 Code=3 "Attribute 0 incompatible with MTLStepFunctionPerPatchControlPoint." UserInfo={NSLocalizedDescription=Attribute 0 incompatible with MTLStepFunctionPerPatchControlPoint.}
[SceneKit] Error: _executeProgram - no pipeline state
以下是我创建几何体的方法:
let program = SCNProgram()
program.vertexFunctionName = "myVertexShader"
program.fragmentFunctionName = "myFragmentShader"
let mat = SCNMaterial()
mat.program = previewProgram
let plane = SCNPlane()
plane.widthSegmentCount = 1
plane.heightSegmentCount = 1
plane.firstMaterial = mat
let tessellator = SCNGeometryTessellator()
tessellator.edgeTessellationFactor = 10.0
tessellator.insideTessellationFactor = 10.0
tessellator.smoothingMode = .pnTriangles
plane.tessellator = tessellator
// add plane node to scene...
如果我删除自定义 material,细分器实际上可以工作,但我需要使用 SCNProgram。
是什么导致了这个错误,我该如何使用 SCNGeometryTessellator
?
添加 tessellator
和 SCNGeometry
后,您的 SCNProgram
需要使用 post-tessellation 顶点函数而不是标准顶点函数。我发现唯一真正涵盖此内容的文档是 Apple 的 metal tessellation programming guide
虽然我对 Metal tessellation 不是很期待,但这是我对这个问题的理解:
假设您的普通顶点函数如下所示:
struct VertexInput {
float3 position [[attribute(SCNVertexSemanticPosition)]];
float3 normal [[attribute(SCNVertexSemanticNormal)]];
float2 texCoords [[attribute(SCNVertexSemanticTexcoord0)]];
};
vertex ColorInOut myVertexShader(VertexInput in [[ stage_in ]], ...) {
...
}
有关 Attribute 0 incompatible with MTLStepFunctionPerPatchControlPoint
的错误说明您的输入类型 (VertexInput
) 与当前渲染管线的预期顶点输入不匹配。这是因为一旦添加曲面细分,渲染管线就会更改为使用特殊的 post 曲面细分顶点函数而不是标准顶点函数。
post 曲面细分顶点函数从曲面细分器而不是您的几何图形中获取输入。这是将上面的顶点着色器转换为 post 曲面细分顶点函数:
struct PatchIn {
patch_control_point<VertexInput> control_points;
};
[[patch(triangle, 3)]]
vertex ColorInOut myVertexShader(PatchIn patchIn [[stage_in]],
float3 patch_coord [[ position_in_patch ]], ...)
{
// We have to compute the correct input positions from the tessellation data
// Note that there's probably a cleaner/better way to do this
// Barycentric coordinates
float u = patch_coord.x;
float v = patch_coord.y;
float w = patch_coord.z;
// Convert to cartesian coordinates
const float3 pos = float3(
u * patchIn.control_points[0].position.x + v * patchIn.control_points[1].position.x + w * patchIn.control_points[2].position.x,
u * patchIn.control_points[0].position.y + v * patchIn.control_points[1].position.y + w * patchIn.control_points[2].position.y,
u * patchIn.control_points[0].position.z + v * patchIn.control_points[1].position.z + w * patchIn.control_points[2].position.z);
...
}
将顶点函数重写为 post 曲面细分顶点函数后,您的几何体应该使用曲面细分和自定义 SCNProgram
渲染
我正在尝试向某些使用自定义 SCNProgram
的 SceneKit 几何体添加 SCNGeometryTessellator
。我的几何体渲染正常,但只要我添加 SCNGeometryTessellator
,我就会看到这个错误:
[SceneKit] Error: Compiler error while building render pipeline state for node <C3DNode:0x1053e9700 "(null)"
geometry: <C3DParametricGeometry<Plane>:0x1053e9160 "(null)"
mesh: <C3DMesh 0x282590620 "(null)"
element0: <C3DMeshElement 0x2823922b0 type:triangles primCount:200 channels:1 indexBytes:2 offset:0 acmr:0.605000 inst:1 dataSize:1200 shared:0x0>
source position (channel:0) : <C3DMeshSource 0x2837fbbf0(position) data:(0x281009ce0) mut:0 count:121 type:float3 divisor:0 mtl:0 offset:0 stride:32>
source normal (channel:0) : <C3DMeshSource 0x2837fb480(normal) data:(0x281009ce0) mut:0 count:121 type:float3 divisor:0 mtl:0 offset:12 stride:32>
source texcoord (channel:0) : <C3DMeshSource 0x2837fbb80(texcoord) data:(0x281009ce0) mut:0 count:121 type:float2 divisor:0 mtl:0 offset:24 stride:32>
renderable element0: <C3DMeshElement 0x2823922b0 type:triangles primCount:200 channels:1 indexBytes:2 offset:0 acmr:0.605000 inst:1 dataSize:1200 shared:0x0>
renderable source position: <C3DMeshSource 0x2837fbbf0(position) data:(0x281009ce0) mut:0 count:121 type:float3 divisor:0 mtl:0 offset:0 stride:32>
renderable source normal: <C3DMeshSource 0x2837fb480(normal) data:(0x281009ce0) mut:0 count:121 type:float3 divisor:0 mtl:0 offset:12 stride:32>
renderable source texcoord: <C3DMeshSource 0x2837fbb80(texcoord) data:(0x281009ce0) mut:0 count:121 type:float2 divisor:0 mtl:0 offset:24 stride:32>
>
mat0: <C3DMaterial 0x2837159d0 : "(null)", custom <C3DFXTechnique>>
>
>:
Error Domain=AGXMetalA14 Code=3 "Attribute 0 incompatible with MTLStepFunctionPerPatchControlPoint." UserInfo={NSLocalizedDescription=Attribute 0 incompatible with MTLStepFunctionPerPatchControlPoint.}
[SceneKit] Error: _executeProgram - no pipeline state
以下是我创建几何体的方法:
let program = SCNProgram()
program.vertexFunctionName = "myVertexShader"
program.fragmentFunctionName = "myFragmentShader"
let mat = SCNMaterial()
mat.program = previewProgram
let plane = SCNPlane()
plane.widthSegmentCount = 1
plane.heightSegmentCount = 1
plane.firstMaterial = mat
let tessellator = SCNGeometryTessellator()
tessellator.edgeTessellationFactor = 10.0
tessellator.insideTessellationFactor = 10.0
tessellator.smoothingMode = .pnTriangles
plane.tessellator = tessellator
// add plane node to scene...
如果我删除自定义 material,细分器实际上可以工作,但我需要使用 SCNProgram。
是什么导致了这个错误,我该如何使用 SCNGeometryTessellator
?
添加 tessellator
和 SCNGeometry
后,您的 SCNProgram
需要使用 post-tessellation 顶点函数而不是标准顶点函数。我发现唯一真正涵盖此内容的文档是 Apple 的 metal tessellation programming guide
虽然我对 Metal tessellation 不是很期待,但这是我对这个问题的理解:
假设您的普通顶点函数如下所示:
struct VertexInput {
float3 position [[attribute(SCNVertexSemanticPosition)]];
float3 normal [[attribute(SCNVertexSemanticNormal)]];
float2 texCoords [[attribute(SCNVertexSemanticTexcoord0)]];
};
vertex ColorInOut myVertexShader(VertexInput in [[ stage_in ]], ...) {
...
}
有关 Attribute 0 incompatible with MTLStepFunctionPerPatchControlPoint
的错误说明您的输入类型 (VertexInput
) 与当前渲染管线的预期顶点输入不匹配。这是因为一旦添加曲面细分,渲染管线就会更改为使用特殊的 post 曲面细分顶点函数而不是标准顶点函数。
post 曲面细分顶点函数从曲面细分器而不是您的几何图形中获取输入。这是将上面的顶点着色器转换为 post 曲面细分顶点函数:
struct PatchIn {
patch_control_point<VertexInput> control_points;
};
[[patch(triangle, 3)]]
vertex ColorInOut myVertexShader(PatchIn patchIn [[stage_in]],
float3 patch_coord [[ position_in_patch ]], ...)
{
// We have to compute the correct input positions from the tessellation data
// Note that there's probably a cleaner/better way to do this
// Barycentric coordinates
float u = patch_coord.x;
float v = patch_coord.y;
float w = patch_coord.z;
// Convert to cartesian coordinates
const float3 pos = float3(
u * patchIn.control_points[0].position.x + v * patchIn.control_points[1].position.x + w * patchIn.control_points[2].position.x,
u * patchIn.control_points[0].position.y + v * patchIn.control_points[1].position.y + w * patchIn.control_points[2].position.y,
u * patchIn.control_points[0].position.z + v * patchIn.control_points[1].position.z + w * patchIn.control_points[2].position.z);
...
}
将顶点函数重写为 post 曲面细分顶点函数后,您的几何体应该使用曲面细分和自定义 SCNProgram