Make DOM element receive shadow and shine from PointLight

I’m making a PointLight shadow “onto a DOM element” like this:

However, if we rotate the scene by 45 deg (line 23), then the Sphere’s shadow is no longer displayed properly like before:

I was expecting the Sphere’s shadow to remain visible like it was without the rotation.

Do you know why this is? To me it seems like the shadow is only being drawn on the area where the light shines, and since when we rotate the scene the shine of the light is no longer drawn in the center of the square, but to the left side of the square where we continue to see the Sphere’s shadow.

Hmmm, if I change the color of the transparent Mesh (that covers the DOM element) to something other than black (line 49), then the shadow is rendered:

But, even with opacity way down low at 0.05 (line 48), the square appears too shiny.

How can we achieve a similar effect like when the color is black, but still have the shadow be visible?

If you can’t tell, what I’m trying to do is make it seem like a DOM element receives a shadow and shine. When the color is black and the rotation of the scene is zero, it looks fairly convincing! Adding the rotation destroys the effects. I’d like to achieve the same effect but without this limitation, but I’m not a Three wizard yet.

Maybe adjusting the specularMap would help here?

Aha! Found one way to make it work by using a color similar to black but not exactly (f.e. 0x111111 on line 49):

I’m still curious about the specularMap though. I’ve never missed with that before.

Aaaah! In fact, setting the opacity to 0 (line 48) completely removes the blocking of the DOM element’s color but still leaves the shadow and shine behind. Cool!

Looks great!

BTW why are you doing bitwise ops on your functions?

~function() {}

As, I see - it allows to to make an IIFE by doing:

~function(){}()

Neat!

1 Like

I really like this solution. It would be awesome if we could access DOM layers texture buffer with WebGL, besides finally capturing DOM one could create awesome interactive effects. There will be CSS shaders but it isn’t the same.

1 Like

Alright, I added <button> element but it won’t cast a shadow onto the background element:

I also tried upping the opacity from 0 to 0.8 (line 139) but still no shadow is cast from the “button”:

I’m expecting there to be a rectangular shadow from the button. If you look at line 146 you see that I have

    mesh.castShadow = true;
    mesh.receiveShadow = true;

both true.

@looeee @Fyrestar Any idea why the button’s shadow is not appearing?

Maybe NoBlend objects can not cast a shadow?

Nope, that’s not it, here’s one showing that the red non-NoBlend PlaneGeometry Meshes still don’t cast any shadow, and only the SphereGeometry Mesh casts a shadow (move the sphere out of the way and observe the red shadowless Planes):

Why can’t I get them to cast a shadow?

Okay, if I scroll to the edges of the view in that last demo, sometimes I see a red square receiving a shadow. This seems strange.

Ah, it’s a bug.

Here’s the demo with red squares made from thin BoxGeometries instead of PlaneGeometries, and shadow casting now somewhat works with some obvious glitchyness, and the polygon count increased by a factor of 6:

Here’s another demo more clearly showing the glitchy shadow effect when the Plane (Box) is not thick enough (line 145):

Would you consider these glitchy effects a bug?

Using a shadow bias of -0.001 fixes the glitch, though i wonder why it needs to be negative. Using “transform: scale(1.0);” for #css fixes some issue in the background i had (gray strokes).

Using a box of 0.1 causes the glitch for sure. You should probably use a plane instead :grin:

1 Like

But this affect how all other objects’ shadows are rendered as well. I only want to fix up these Plane meshes that I’m aligning with the DOM. It would make sense if I could use a different light just for the DOM elements, but “selective lighting” is not supported yet.

And then I’m back at Planes not casting shadows! :frowning:

I would really like these things to be solved in Three.js:

  • Planes should cast shadows, which is something one can intuitively expect
  • Selective lighting, which can help us achieve single-light effects which are actually composed of multiple lights.

It fixed this special case, because you’re using a super thin box what causes issues for calculating the shadow visibility from the depth buffer.

Planes actually cast shadows, basically shadows are nothing but the same mesh renderered from the position of the light.

I didn’t understand this as well as your thread about that, but the Github issue clarifies it for me.

I also faced this before, for building houses like in The Sims. I didn’t read the whole thread, but the best way to do it is by using shadows. THREE by default actually just applies any light to all meshes in the scene, i modified THREE to use a spatial manager for it, like lights of limited range.

You can limit it by rooms but: it depends if you want doors or windows, as light will shine into corridors or across rooms.

If you want them, then you should include at least the connected building parts (not their interiors) to ensure light won’t just cuttoff.