Shadow-Only Material

Hi, I’m wondering if there’s a way to have a transparent plane that still receives and displays shadows? Similar to babylon.js shadow only material: ShadowOnly Material | Babylon.js Documentation

This is for an AR project for context, since 8th wall just released support for PlayCanvas.

Thanks! :slight_smile:

EDIT: Just saw this is already supported by 8th Wall :man_facepalming:

1 Like

Check out the 8th Wall starter projects: https://playcanvas.com/the8thwall

The “AR World Tracking Starter Kit” has this built in: https://playcanvas.com/project/631719/overview/ar-world-tracking-starter-kit

4 Likes

Yes, or at least very close to that. I’ve used it effectively to give the impression that a background landscape image that is mapped to a vertical plane is receiving a shadow on the ground in that vertically oriented image. But in fact, the shadow is being cast on a clear horizontal plane.

  1. Make a horizontal plane and set it to receive shadows. Turn off cast shadows. Make a material and apply it to your plane.
  2. Go to your material and turn off all specularity and reflection. That means glossiness to zero.
  3. Set your diffuse to some middle gray value like 127,127,127. Set your emmisive color to black and amount to zero.
  4. This is the fun part, change your BlendType from “none” to “Modulate 2x.” You should have something very close to what you are looking for, a transparent ground that is receiving a shadow.

But it probably won’t be perfect. It will likely be either darkening or brightening the image behind it a bit. You can adjust that most easily with realtime feedback by tweaking your diffuse color or possibly your emmisive level.

This may not be good enough for a solid color background, but it works just fine for landscapes that have detail in them.

In the attached image the background is a cubemap, not an image on a vertical plane. The ground plane is actually part of the FBX import mesh with a material applied to it as I described. Any imperfection in the transparency is masked by our eye’s expectation of horizontal components in the landscape image. The plane could have been added separately as well. Also, the shadow can be lightened up by adding a fill light that doesn’t cast shadows. But I left it dark here to match the shadows cast by the bushes.

2 Likes

Trying to use the 8th Wall solution, I’m getting shader errors at runtime:

ERROR: 0:173: 'getShadowPCF3x3VS' : no matching overloaded function found

Error in material "mat_env" with flags 65548

This appears to only work with Shadow Map PCF 3x3…?

Is there no better way to do a shadow only material?

1 Like

Did you try the method I outlined above?

Yes, it didn’t appear to work that well since I’m using a solid background colour. The background colour was highlighted in the area overlayed by the plane, making it very noticeable.

Bummer. Yeah, I noticed that it is difficult or simply not possible to get a perfect match with solid backgrounds - especially if you don’t have an obvious horizon line.

I’ve found a way to fix this problem, just download the newest 8th wall “xrextra.js”, replace this shader chunks (search “t.chunks.emissivePS=” and replace its content) into below fix the shadow problem (using VSM 32 shadow as an example):

    "\n"+
    "\t#ifdef GL2\n"+
    "\t#define SHADOW_SAMPLERVS sampler2DShadow\n"+
    "\t#else\n"+
    "\t#define SHADOW_SAMPLERVS sampler2D\n"+
    "\t#endif\n"+
    // VSM 32 means Variance Shadow Map (32bit), which the same as 16 bit, 8bit, etc.
    // If you need to use PCF 5x5 shadow, just replace all "3x3" to "5x5" without replacing whole chunk
    "\tfloat getShadowVSM32VS(sampler2D shadowMap, vec3 shadowParams, float exponent);\n"+
    "\tvec3 getEmission() {\n"+
    "\t\tfloat shadow = getShadowVSM32VS(light0_shadowMap, light0_shadowParams, 15.0);\n"+
    "\t\tdAlpha = 1. - clamp(shadow + 0.5, 0., 1.);\n"+
    "\t\treturn -gl_FragColor.rgb;\n"+
    "\t}"

After the chunk replaced, you need to delete the external scripts and upload the new “xrextra.js” to your project. Ensure it will be loaded first like this:

image

1 Like