Shadow Acne/Banding; What I learned

I spent several hours today trying to figure out how to fix shadow acne in my scene. After looking at many topics on the forums, I finally figured out what I was doing wrong. To save anyone who is having problems with this time, I’ve listed a some properties and other things I learned below. If anything is wrong or you noticed anything else about shadows, please comment below. (I am using version 141.0)

Basic Shadow Stuff

  • renderer.shadowMap.enabled must be set to true
  • materials must support shadows (look at the three.js docs)
  • you must have a light
  • you must set mesh.castShadow and mesh.receiveShadow according to your wishes
  • light.castShadow must be set to true
  • light.camera.mapSize .width and .height change the shadow resolution
  • your light.shadow.camera must be looking at whatever you wish to have a shadow on and have the near,far,left,right,bottom, and top set to fit your object. A CameraHelper greatly helps with figuring out where your light is(see three.js docs). For some lights, like DirectionalLight , the rotation must be set using light.target.position.set(x,y,z), again see the docs)

Some less known properties

  • setting both mesh.castShadow and mesh.receiveShadow to true can cause shadow acne
  • setting material.side = THREE.DoubleSide can cause shadow acne
  • changing the light.shadow.bias to a small number (0.0001) and maybe negative or the light.shadow.radius may help depending on your situation(none of these helped for me).
  • spheres might be a pain? see this thread

Really Weird Case

I discovered this when one of my imported assets was having shadow acne while all of my other ones were fine. This happened for me in blender shading if I connected the my image(color map) to a Principled BSDF to the Material Output, instead of connecting the image directly to the Material Output.
(In this scene, all of my objects have castShadow and receiveShadow set to true)
It seems that the material imports as a MeshStandardMaterial rather than a MeshBasicMaterial when a Principled BSDF is connected. Screenshots:

with Principled BSDF without Principled BSDF

with Principled BSDF without Principled BSDF

Material JSON data:

with Principled BSDF
"_alphaTest": 0,
"alphaToCoverage": false,
"aoMapIntensity": 1,
"blendDst": 205,
"blendEquation": 100,
"blending": 1,
"blendSrc": 204,
"bumpScale": 1,
"clipIntersection": false,
"clipShadows": false,
"colorWrite": true,
"depthFunc": 3,
"depthTest": true,
"depthWrite": true,
"displacementBias": 0,
"displacementScale": 1,
"dithering": false,
"emissiveIntensity": 1,
"envMapIntensity": 1,
"flatShading": false,
"fog": true,
"isMaterial": true,
"isMeshStandardMaterial": true,
"lightMapIntensity": 1,
"metalness": 0,
"name": "Material",
"normalMapType": 0,
"opacity": 1,
"polygonOffset": false,
"polygonOffsetFactor": 0,
"polygonOffsetUnits": 0,
"premultipliedAlpha": false,
"roughness": 0.4000000059604645,
"side": 2,
"stencilFail": 7680,
"stencilFunc": 519,
"stencilFuncMask": 255,
"stencilRef": 0,
"stencilWrite": false,
"stencilWriteMask": 255,
"stencilZFail": 7680,
"stencilZPass": 7680,
"toneMapped": true,
"transparent": false,
"type": "MeshStandardMaterial",
"uuid": "1d8e6204-c9f3-41b0-b316-14aede7c6e71",
"version": 0,
"vertexColors": false,
"visible": true,
"wireframe": false,
"wireframeLinecap": "round",
"wireframeLinejoin": "round",
"wireframeLinewidth": 1
without Principled BSDF
"_alphaTest": 0,
"alphaToCoverage": false,
"aoMapIntensity": 1,
"blendDst": 205,
"blendEquation": 100,
"blending": 1,
"blendSrc": 204,
"clipIntersection": false,
"clipShadows": false,
"colorWrite": true,
"combine": 0,
"depthFunc": 3,
"depthTest": true,
"depthWrite": true,
"dithering": false,
"fog": true,
"isMaterial": true,
"isMeshBasicMaterial": true,
"lightMapIntensity": 1,
"name": "Material",
"opacity": 1,
"polygonOffset": false,
"polygonOffsetFactor": 0,
"polygonOffsetUnits": 0,
"premultipliedAlpha": false,
"reflectivity": 1,
"refractionRatio": 0.98,
"side": 2,
"stencilFail": 7680,
"stencilFunc": 519,
"stencilFuncMask": 255,
"stencilRef": 0,
"stencilWrite": false,
"stencilWriteMask": 255,
"stencilZFail": 7680,
"stencilZPass": 7680,
"toneMapped": true,
"transparent": false,
"type": "MeshBasicMaterial",
"uuid": "0831d3f1-cdad-455e-affa-61b7f3e2e493",
"version": 0,
"vertexColors": false,
"visible": true,
"wireframe": false,
"wireframeLinecap": "round",
"wireframeLinejoin": "round",
"wireframeLinewidth": 1

possibly helpful link: techniques-to-improve-shadow-depth-maps by microsoft

I hope this helps :slight_smile:

3 Likes

in most cases it has to be a negative, small value. shadow artefacts are almost exclusively related to bias, and fixed with it.

btw, there is something very interesting, people usually try to avoid artefacts but for dark scenes it can create something like a very cheap, good looking AO effect.

https://twitter.com/0xca0a/status/1440045867814195204

2 Likes

This helped me @WilliamBagel thanks! In particular the tip about DoubleSide.