Volumes with space-dependent light intensity

I would like to ask about the possibility of creating objects “made of light” with Three.js. The context would be exactly the one described in https://blender.stackexchange.com/questions/103154/volumes-with-space-dependent-light-intensity and implemented in https://www.youtube.com/channel/UCe5LqHakyOBfOAeZYgPJ1Yg (the wavefunctions) for Blender, but for direct rendering and interactivity in the browser. The key is to be able to build light-emitting volumes whose intensity (and perhaps hue) varies in space. How could this be done in Three.js?

The only thing I could think of is godrays.


is it what you’re looking for?

Are you familiar with shadertoy? A lot of examples there use signed distance fields and Ray marching. I think it is aplicable. Otherwise you could slice through your function with a plane. Possibly also stack planes and mimick volumes.

1 Like

As @pailhead said it can be done with ray marching, but if the light should be affected by objects you would need the depth target. Since it’s only light, the resolution can be quite low. Basically it would be similar to deferred lights.

@prisoner849 @Fyrestar @pailhead Thank you very much for your ideas :smile:

Godrays are very interesting, but I’m looking for the lighting of the object itself, not the lighting of the environment. The intended result is similar to rendering fire: each “particle” is bright and visible, and doesn’t block the light from particles behind: all lights mix up.

One simple approach I imagine is to divide some bounded space into a grid of cubes; then one would require that one cube is visible with a given intensity and color (perhaps Lambert material with emission?) without blocking the “light” from cubes behind.

How could this be done? :thinking: Thank you again

With ray marching you could archive “volumetric light objects”, not only lighting of the scene, though optimizations should be considered depending on what you’ll use it for. Using a lowres target is one of those, since it’s only light. For example volumetric clouds/smoke/fire etc. can be archived very realistic in this way too, but it’s a rather advanced approach and requires optimizations.

1 Like

I would go for a particle system to do this. Use additive blend mode. If you want to be clever about it you can simulate the physics in the shader, it took me a few weeks to figure out how to do that type of stuff but it’s pretty great once it begins to work.

2 Likes

@Oskasb Could you show some pictures with the result?

1 Like

There are a few examples of particle effect systems built on three. They got examples like this: image

https://a-jie.github.io/three.proton/

I think the meshzone example might be a decent fit for your type of problem.

If you want a lower level approach you can start from the example https://threejs.org/examples/webgl_gpu_particle_system.html and work from there.

1 Like

I thought you’ve meant something like that :slight_smile:

1 Like

@Oskasb @prisoner849 Looks great!! To focus on a specific minimal working example, suppose we would like to render an sphere of light in which

  1. Light intensity is 1-x^2-y^2-z^2 (that is, brighter in the center, darker in the boundary, no light out of the sphere)
  2. Hue is proportional to x (so if seen from the y or z axis, we perceive a rainbow effect)

Could this be done with proton?

Probably, you do get all sorts of exciting effects from the additive blend mode. If each particle contains the whole gradient (black at the edge and the brighter in the center) I think this is what you get as a default if you scatter them around a spherical distribution. (If you need a very specific type of control you can extend the shader to manipulate colors based on position but I would consider that to require quite a bit more studies and work around how shaders work.)

I have not used the proton library myself but it looks to be similar to my own hack.

I was asking about pictures with the result of your solution :slight_smile: I’ve seen those examples with Proton before.

image
this is from a very quick and dirty test of switching one of my particle sprites for this purpose.

The sprite looks like this x

1 Like

This thread inspired me to make an example, where we have not a volume light, but kind of an electron cloud:

https://jsfiddle.net/prisoner849/ufaxft2e/

The example also has the XY-plane, which you can move along Z-axis. It uses the same code for its fragment shader as the code for the points, thus you can kind of to slice the cloud and see how the colors and transparency change in space.
Criticism and advice are very welcomed :slight_smile:

4 Likes

You might consider a custom shader so the ShaderToy route as those raymarching demos explained above.
Here is one that get’s 0.1 FPS, while other examples might just crash chrome desktop, still there’s something to learn from them.
https://www.shadertoy.com/view/XlBSRz

code links here

This one is more about how light penitrates and how shadows are incorporated.
Your looking more for just the length of the ray from surface-in to surface-out for a simple sphere so much easier, but as to the harmonics or orbitals you’ll likely need to compute that weight differently (for extra marks with no geo really).
https://www.falstad.com/qmatom/ [check out real combinations and click little circles {vector knobs!} at bottom, also 3d mouse movements]
Still maybe you just have a shape and back to the distance inside geo calculation, so maybe the full concept of ray marching is not needed.
so maybe this is also helpful
http://www.chemtube3d.com/orbitals-d.htm

so in THREE js you have ShaderMaterial
https://threejs.org/docs/#api/materials/ShaderMaterial

You need a VertexShader and a FragmentShader this is a good explaination here…
http://blog.cjgammon.com/threejs-custom-shader-material

If when the Fragment Shader is triggered you could then render only that ray again with the same scene object geometry with inverted normals, then you’d get the other side’s exit ray location, so you can then calculate the difference in Z from camera and calculate with a log function that gives you the right density for the look you want. Should be faster then the shadows in the above example I suspect.

Maybe there’s a better example but I didn’t find one in a quick search.
Here’s another one https://github.com/huwb/volsample

1 Like

I get solid 60 FPS :joy: (TitanX)

:smile: 5 fps on iPad mini 3.

Wow right I’m getting 22 fps on the samsung note 8. [My desktop is a GTX 780 Ti so that’s odd. I’ll look into it also note its chrome 66. Firefox gets 60 FPS?] Anyway it’s a better example then I thought.

Okay so it seems ShaderToy can have certain shaders that permanently damage the ability to render until restart etc.
I was looking at ones under the search of ‘volume’ and on this second or third page it seems to crash the GL connection of either Firefox or Chrome must be the second one on that page or just all of them on a page loading together is too much. So anyway that’s how the system was damaged and only played 0.1 FPS if I restart Chrome it also gets 60 FPS on that particular one. Alas if I open this page it’s lights out.
https://www.shadertoy.com/results?query=volume&sort=popular&from=24&num=12

Anyway it does say BETA.