SceneKit shadow on a transparent SCNFloor()

前端 未结 2 1981
独厮守ぢ
独厮守ぢ 2021-01-05 10:51

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)

2条回答
  •  一向
    一向 (楼主)
    2021-01-05 10:58

    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.

提交回复
热议问题