5
votes

trying to figure out how I can render a shadow on an invisible plane, so the background of my sceneView shows through.

THREE.js has a ShadowMaterial which does exactly this - only the shadow is rendered.

Current thinking is to make a custom Metal shader which looks straightforward, but i'm unsure how to go about knocking out the floor to show everything aside from the shadow.

Here's an example of a shadow catcher: https://knowledge.autodesk.com/search-result/caas/sfdcarticles/sfdcarticles/Maya-2015-Shadow-Catching-with-Use-Background-material.html

1
What kind of shadows are you using? Shadow mapping, shadow volumes? Also, are you currently able to draw over your sceneView 3d objects?James Poag
dyanmic shadows using the ambient and spotlight SNNodes, unsure what apple is doing under the hood. I am able to place UIViews over my SceneKit viewjfisk

1 Answers

4
votes

Ok, so check out this example project on Github:

https://github.com/carolight/Metal-Shadow-Map/blob/master/Shadows/Shader.metal#L67

That link is to the shader that performs the shadow map testing. Basically, it normalizes the Z position of the fragment being rendered and compares it to the Z-Buffer of the shadow map. If it is less than the shadow-Z, the pixel is fully lit (line 67) else it is tinted slightly (line 69).

What you want to do instead is write (0,0,0, shadow_opacity) for line 69 and (0,0,0,0) for line 67. This should emit transparent pixels. Set shadow_opacity as a uniform from [0.0..1.0].

The rest of the setup is shown in the example. Tilt the plane/camera to the desired setting, skip drawing the cube/vase/whatever in the main pass if you don't really want it in the scene (line 279). (However, note the shadow pass and keep it there).