Particles self shadowing

Hello folks! I was trying to get some shadows added to my particles system - I was trying to replicate a similar effect to what Edan Kwan does in this experiment but, alas, was unsuccessful (the demo is quite old and you can see the code here).
You can see an (unfortunately) messy example of what I have so far here, using custom depth and distance shaders. I can see some shadows being cast and received by the particles, but it somehow seems like these have no depth nor self-shadowing.
In short my question is: is it possible for particles to cast and receive the shadow of other particles? if so, what am I doing wrong?

In your example, I see a curlicue shape, but no particles. I am using the latest version of Chrome.

I’ve updated the codesandbox to be more clearly particles! you should be seeing the individual particles that produce that shape now

I see the particles now. They create the shape. And the shape does create a shadow.
But I can’t tell whether the points are casting a shadow on each other (which is, I believe, your question).
I would suggest changing the color of the particles to white (like in the experiment) and changing the color of the base to a slightly different color (so you can still see the particles against the base.)

Currently, particles use a defined material (PointsMaterial). But the developers are making some significant changes to three.js to allow use of WebGPU. So even if the current version of three.js does not allow self-shadows of points, future versions might.

I have a few simple particle emitters. I will see if I can get them to throw and receive some shadows.


Thank you so much for looking into this! I’ve updated the demo to use pointLight rather than spotLight, updated the customDistanceMaterial and changed the color to plain white. I can still see the shadow being cast onto the floor (although, it’s cutting off the shadow for some reason that I can’t quite understand) and it’s getting the whole particle system in shadow, without receiving any shadow within the particles. It looks like the angle from which the shadow is coming from is not exactly the angle the light is being cast from either

I was able to put together a simple example with a box and a points emitter over a flat plane.
The box casts a shadow on the flat plane. The points do not cast or receive a shadow.
The console log for Chrome states that
THREE.Material: ‘castShadow’ is not a property of THREE.PointsMaterial.
THREE.Material: ‘receiveShadow’ is not a property of THREE.PointsMaterial.

The GitHub page for the example you cited states that it “uses the the new particles which invented by Simo Santavirta @simppafi”. The page also says that the example was inspired by David Li’s Flow experiment. (David Li wrote the shaders for the wave generator that I spents several months updating.) The particles on David Li’s Flow experiment are also self-shading and cast shadows. But David Li does not use three.js. So it is possible that you could find a particle shader and adapt it for use with three.js (just like Jeremy Bouny did to make David Li’s wave generator work with three.js).

Or it is possible that this change to PointsMaterial will be made as part of the changeover to WebGPU.

Another option would be to make the particles using instancing. There are several examples of instancing in the three.js examples. I haven’t tried it, but I expect that you can use materials that are capable of casting and receiving shadows.

Now that I see that PointsMaterial does not cast or receive shadows I would also like to see that improvement. So post a demo if you figure out how to do it!

I’ve recently come back to this and got a sort of example running here. Unfortunately it’s not what I was hoping for (also doesn’t look very nice, definitely needs some tweaking): I’m calculating the shadows based on the dot product between the normal of the particle and the position of the light and blending in the distance from the camera

I’d expect that this is not what you look for. I’m sorry about this.

In any case, here are 500k particles (instanced), with lighting and self-shadowing. You need a good GPU for this, because the code is genuinely barbaric. The number of particles is set in line 59.



that’s awesome! thank you for making this. unfortunately i was looking to get a similar result with particles rather than instanced meshes

This looks great and works fine on my 5 year old GPU!
Based on your experience with instancing, do you think instancing could be used to create more cloudlike objects, like the “ghosts” in the OP?

I have never made clouds with instanced meshes. Maybe it is best to try it and see what happens.

I think I’ve got it working using points and custom shaders with the threejs shader chunk! Will share some code as soon i properly clean it up

1 Like

Hello @brcli433! I would really appreciate if you could share your code and solution. Is it using a new version of ThreeJS? I’ve tried to create the same effect based on Edan Kwan experiment, but it only worked with r74dev…

Bringing the discussion back up!

I noticed there are many discussions about achieving the stunning particle effects seen in @edankwan “The Spirit" project, but many links are outdated and lack clear solutions for recent Three.js versions.

My goal is to achieve self-shadowing particles, but I’ve only managed to get them casting shadows on other objects. Particles ShaderMaterial is based on ShadowMaterial.

Here’s my code snippet using Three.js version 0.162.0:

Additional questions:

  1. When I comment out line 61 (sphereMesh.castShadow = true;), the particles stop casting shadows. Why does this depend on the presence of another object casting shadows?
  2. When zooming out, I see multiple shadows projected on the floor. One seems to be the main one, but there are others. How can I fix this problem?

I appreciate any help and insights!

Hi, I am facing the exact same issue. @sulram did you make any further progress on this?

Hello folks! Apologies for the radio silence - i completely forgot to reply. I’ve got some code but it’s rather messy: r3f-particles-shadows/src/App.jsx at 9f617400edd69d0765346a51610f88d209328884 · frarillotta/r3f-particles-shadows · GitHub - the main thing for me was moving to directionalLight, as pointLight seemed to create artifacts and break - never really investigated as to why. You can see the working code here: .

Edit: Upon re-reading the code after not having touched it for a while, I feel there must be a way to get pointLight working with a custom distance material. Will have another go soon

1 Like