Проблема
Я создал минимальный проект SceneKit со сценой, которая содержит сферу, плоскость и один направленный источник света.Направленный свет отбрасывает тени, и для shadowMode
установлено значение deferred
.Все работает как надо.Сцена освещена, и сфера отбрасывает тень на плоскость.
Когда я устанавливаю минимальное наложение цвета SCNTechnique
и назначаю его для свойства SCNView
technique
, консоль заливается этимсообщение:
[SceneKit] Error: Pass DeferredShadow is not linked to the rendering graph and will be ignored check it's input/output
Тем не менее, техника работает и отображает наложение цвета и тень:
![The rendered scene](https://i.stack.imgur.com/50FtV.png)
Когда я фиксирую кадр в отладчике шейдеров, все выглядит нормально:
![The rendering graph](https://i.stack.imgur.com/GttoJ.png)
В Навигаторе отладки также нет ничего очевидного:
![The debug navigator](https://i.stack.imgur.com/EHTOH.png)
Вопрос
Есть ли что-то очевидное, что я упускаю?Визуально все работает, но я хотел бы знать, пропустил ли я важный шаг или нет, чтобы предотвратить возникновение этой ошибки.
PS Я знаю, что тот же результат может быть достигнут с модификатором шейдера, но я хочуиспользуйте SCNTechnique для создания эффектов постобработки.
Код
Вот краткий обзор важных битов.Если вы хотите запустить пример, вы можете клонировать репозиторий GitHub .
Вот как настраиваются SCNView
и directional SCNLight
:
view.allowsCameraControl = true
view.showsStatistics = true
view.backgroundColor = UIColor.black
let dirLight = SCNLight()
dirLight.type = .directional
dirLight.castsShadow = true
dirLight.shadowMode = .deferred
dirLight.shadowColor = UIColor.black.withAlphaComponent(0.75)
let dirLightNode = SCNNode()
dirLightNode.light = dirLight
dirLightNode.eulerAngles = SCNVector3(-Float.pi / 2, 0, 0)
Техника имеет два прохода.Один, который рисует наложение цвета на объекты, для которого categoryBitmask
установлено значение 2
, а другой другой проход, который рисует всю сцену к цели цветопередачи.Это файл .plist
этой техники:
<dict>
<key>passes</key>
<dict>
<key>pass_draw_overlay</key>
<dict>
<key>draw</key>
<string>DRAW_SCENE</string>
<key>program</key>
<string></string>
<key>metalVertexShader</key>
<string>colour_overlay_vertex</string>
<key>metalFragmentShader</key>
<string>colour_overlay_fragment</string>
<key>includeCategoryMask</key>
<string>2</string>
<key>inputs</key>
<dict>
<key>colorSampler</key>
<string>COLOR</string>
</dict>
<key>outputs</key>
<dict>
<key>color</key>
<string>OVERLAY</string>
</dict>
</dict>
<key>pass_combine</key>
<dict>
<key>colorStates</key>
<dict>
<key>clear</key>
<false/>
</dict>
<key>inputs</key>
<dict>
<key>colorSampler</key>
<string>COLOR</string>
<key>overlaySampler</key>
<string>OVERLAY</string>
</dict>
<key>outputs</key>
<dict>
<key>color</key>
<string>COLOR</string>
</dict>
<key>metalFragmentShader</key>
<string>combine_fragment</string>
<key>metalVertexShader</key>
<string>combine_vertex</string>
<key>program</key>
<string></string>
<key>draw</key>
<string>DRAW_QUAD</string>
</dict>
</dict>
<key>sequence</key>
<array>
<string>pass_draw_overlay</string>
<string>pass_combine</string>
</array>
<key>targets</key>
<dict>
<key>OVERLAY</key>
<dict>
<key>type</key>
<string>color</string>
</dict>
</dict>
</dict>
Используемые металлические шейдеры:
vertex VertexOut colour_overlay_vertex(VertexIn in [[stage_in]],
constant CustomNode& scn_node [[buffer(0)]])
{
VertexOut out;
out.position = scn_node.modelViewProjectionTransform * float4(in.position.xyz, 1.0);
return out;
};
fragment half4 colour_overlay_fragment(VertexOut in [[stage_in]],
texture2d<float, access::sample> colorSampler [[texture(0)]])
{
return half4(0.0, 1.0, 0.0, 1.0);
};
vertex VertexOut combine_vertex(VertexIn in [[stage_in]],
constant SCNSceneBuffer& scn_frame [[buffer(1)]])
{
VertexOut out;
out.position = in.position;
out.uv = float2( (in.position.x + 1.0) * 0.5, 1.0 - (in.position.y + 1.0) * 0.5 );
return out;
};
fragment half4 combine_fragment(VertexOut vert [[stage_in]],
texture2d<float, access::sample> colorSampler [[texture(0)]],
texture2d<float, access::sample> overlaySampler [[texture(1)]])
{
float4 fragmentColor = colorSampler.sample(s, vert.uv);
float4 overlayColor = overlaySampler.sample(s, vert.uv);
if (overlayColor.g < 1.0 ) {
return half4(fragmentColor);
}
return half4(overlayColor);
}