I have a floor node
, on which I need to cast shadow from directional light
. This node needs to be transparent (used in AR
environment)
It's been awhile since this was posted but maybe someone will find this alternative solution useful. I encountered a similar situation and what I ended up doing was rendering using multiple passes via SCNTechnique
. First I rendered a floor with a solid white diffuse
and then I rendered the rest of the scene without the floor. To do this I set the categoryBitMask
of my SCNFloor
to 3 and left the others with the default value of 1.
Next I created my SCNTechnique
with this definition which renders the floor and the rest of the scene into separate buffers and then combines them together into the final scene:
self.sceneView.technique = SCNTechnique(dictionary: [
"passes" : [
"store-floor": [
"draw" : "DRAW_NODE",
"node" : "floor-node",
"inputs" : [],
"outputs" : [ "color" : "color_floor" ]
],
"store-scene": [
"draw" : "DRAW_SCENE",
"excludeCategoryMask" : 2,
"inputs" : [],
"outputs" : [ "color" : "color_scene" ]
],
"recall-scene": [
"draw" : "DRAW_QUAD",
"metalVertexShader" : "vertex_tecnique_basic",
"metalFragmentShader" : "fragment_tecnique_merge",
"inputs" : [ "alphaTex" : "color_floor", "sceneTex" : "color_scene" ],
"outputs" : [ "color" : "COLOR" ]
]
],
"symbols" : [
"vertexSymbol" : [ "semantic" : "vertex" ]
],
"targets" : [
"color_floor" : [ "type" : "color" ],
"color_scene" : [ "type" : "color" ],
],
"sequence" : [
"store-floor",
"store-scene",
"recall-scene"
]
])
Next the Metal share code that takes those two buffers and combines them together where the alpha value ranges from 0 for white to 1 for black.
using namespace metal;
#include
struct TechniqueVertexIn
{
float4 position [[attribute(SCNVertexSemanticPosition)]];
};
struct TechniqueVertexOut
{
float4 framePos [[position]];
float2 centeredLoc;
};
constexpr sampler s = sampler(coord::normalized, address::repeat, filter::linear);
vertex TechniqueVertexOut vertex_tecnique_basic(
TechniqueVertexIn in [[stage_in]],
constant SCNSceneBuffer& scnFrame [[buffer(0)]])
{
TechniqueVertexOut vert;
vert.framePos = float4(in.position.x, in.position.y, 0.0, 1.0);
vert.centeredLoc = float2((in.position.x + 1.0) * 0.5 , (in.position.y + 1.0) * -0.5);
return vert;
}
fragment half4 fragment_tecnique_merge(
TechniqueVertexOut vert [[stage_in]],
texture2d alphaTex [[texture(0)]],
texture2d sceneTex [[texture(1)]])
{
float4 alphaColor = alphaTex.sample(s, vert.centeredLoc);
float4 sceneColor = sceneTex.sample(s, vert.centeredLoc);
float alpha = 1.0 - max(max(alphaColor.r, alphaColor.g), alphaColor.b); // since floor should be white, could just pick a chan
alpha *= alphaColor.a;
alpha = max(sceneColor.a, alpha);
return half4(half3(sceneColor.rgb * alpha), alpha);
}
Lastly here's an example of what that ends up looking like with all the pieces put together.