Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Selective lighting #5180

Closed
goodsign opened this issue Aug 10, 2014 · 109 comments
Closed

Selective lighting #5180

goodsign opened this issue Aug 10, 2014 · 109 comments
Milestone

Comments

@goodsign
Copy link

goodsign commented Aug 10, 2014

I'm not sure whether this is already a planned feature or maybe even a finished one, so I'll try to explain the task first.

I need to do selective lighting for different rooms. For example, I have two rooms. One light must only affect objects and inner walls of one room. The second room must not be affected by this light.

Currently, if I add a light to the scene, it affects all objects in its distance. And I get strange effect when light comes "through the wall" of the second room.

So I think I need some kind of groups or channels for lighting, so that I could set the objects that are affected by one light source and objects that are affected by another.

I haven't found anything like that in either lights or objects, so I thought that maybe it could be a good feature to have.

And, btw, if it is not implemented yet, what is the recommended approach to solve such tasks using current state of three.js?

@goodsign
Copy link
Author

What I am saying is basically having a channel field in THREE.Light and lightChannel field in THREE.Mesh or something like that. If the latter is null then it is affected by all light sources. If the latter is not null then it is affected only the the light channels with the same value.

Or maybe it could be added not to the Mesh itself, but to separate faces of the mesh geometry.

@mrdoob
Copy link
Owner

mrdoob commented Aug 11, 2014

Sounds like you want to use shadows?

@goodsign
Copy link
Author

Well, I could achieve something like that with shadows (and I've already tried), but it gives different side effects and I feel that it is a hack, because I don't need to light some objects and then cast shadow on them. I must not light them in the first place.

What I need is that a specific light source doesn't affect one set of meshes, but affects the other set.

Usually I do this using a technique like that: Example discussion thread:

glEnable(GL_LIGHT0);
//...
glEnable(GL_LIGHTn);

// Draw the walls to room 1
DrawWalls(room[0]);

// Draw the contents of room 1
DrawContents(room[0]);

glDisable(GL_LIGHT0);
//...
glDisable(GL_LIGHTn);

// Draw the walls to room 2
DrawWalls(room[1]);

// Draw the contents of room 2
DrawContents(room[1]);

So it looks like a different feature than just shadows. Or am I missing something?

@mrdoob
Copy link
Owner

mrdoob commented Aug 11, 2014

Yes... I think this can indeed be handy. Not sure how the API for it should look like though.

@goodsign
Copy link
Author

Maybe the most simple solution could be the most effective here:

  1. Add a channel (or group) to THREE.Light
  2. Add a affectedByLightChannel (or affectedByLightGroup) to THREE.Mesh (Or maybe even to a face in the geometry)

What do you think?

@goodsign
Copy link
Author

Maybe the 'affectedByLightChannel' is too long and something like 'lightChannel' would do, but I think it would be convenient: just channel numbers on light source and receivers.

Like that:

    light = new THREE.PointLight(0xFFF7D6, 1.0, 15)
    light.channel = 123
    testScene.add(light)

    testScene = new THREE.Scene
    geometry = new THREE.BoxGeometry(2,2,2)
    material = new THREE.MeshLambertMaterial 
        color: 0xffffff

    cube = new THREE.Mesh(geometry, material)
    cube.lightChannel = 123
    testScene.add(cube)

@goodsign
Copy link
Author

If lightChannel is equal to 0, then it is affected by all channels. If channel is equal to 0, then it affects all meshes.

So it would be fully backward compatible with current behavior.

@mrdoob
Copy link
Owner

mrdoob commented Aug 11, 2014

That may be a bit too hard to understand... Maybe it's better something like this:

cube.lightInfluences = [ light1, light2 ];

@goodsign
Copy link
Author

Seems absolutely fine to me.

Maybe it is a bit more difficult to use in some cases, but it is easier to understand, obviously.

@satori99
Copy link
Contributor

What about a simple integer mask property for meshes and lights?

light = new THREE.PointLight(0xFFF7D6, 1.0, 15)
light.mask = 0xffffffff; // default mask
testScene.add(light);

cube = new THREE.Mesh(geometry, material)
cube.mask = 0xffffffff; // default
testScene.add(cube);

Objects are then only lit by lights if the logical AND of their masks is non- zero.
This would allow lights to be influenced by more than one channel, with no extra methods on the objects.

A mask default of 0xffffffff would not affect existing code.

@WestLangley
Copy link
Collaborator

What @satori99 said.

Although, I think mask should be a property of Light and Mesh*Material, instead. (Only those materials affected by lights.)

Also, the property could alternatively be named lightMask, lightChannel, or channel.

@mrdoob
Copy link
Owner

mrdoob commented Aug 11, 2014

The problem of the channel/mask approach is that the user will need to understand bitwise operations. A bit too intense if you compare it to the rest of the API.

What's something you can do with masks that you can't do with the array approach?

@goodsign
Copy link
Author

I could give an example from the task with two rooms above.

The main point of using the channel approach over the array approach is that simple operations like 'move light1 from room 1 to room 2' become more complicated if you use arrays.

Instead of just setting

light1.channel = 2

(previously it was set to 1)

you would have to find all objects in room 1 that had light1 in lightInfluences array previously, then remove the light from their arrays, then add it to all objects in the room 2.

Same story with the simple operation like 'move object 1 from room 1 to room 2'. Instead of setting its influenceChannel from 1 to 2, you would need to find all the lights in that room, then remove them from its influence array, then find all lights in room two and add them.

It's not that it can't be done, that's why I said that the lightInfluences approach is absolutely fine to me. But the channel stuff would be the first thing that I would implement above it for myself just to make common operations as simple as 1 assignment.

@WestLangley
Copy link
Collaborator

I think it should be implemented as a mask. (Whether is it implemented on the CPU or GPU is an issue for later discussion.)

We can show via examples how to set it, and users can follow the pattern.

If you think that is still too complicated, then we can create a THREE.Channels API for it.

light.channels = new THREE.Channels();
...
light.channels.clear();
light.channels.add( channel );
light.channels.remove( channel );
light.channels.all();

Same methods for Mesh*Material.

@mrdoob
Copy link
Owner

mrdoob commented Aug 11, 2014

I like that API :)
I can see this working for objects and lights, but how do you see it working for materials?

@WestLangley
Copy link
Collaborator

Only materials respond to lights. This would have to be a property of the material, I would think.

@gero3
Copy link
Contributor

gero3 commented Aug 11, 2014

I agree on this with @WestLangley. Lights are dependent on materials.

@WestLangley
Copy link
Collaborator

Same story with the simple operation like 'move object 1 from room 1 to room 2'.

Well, that's a problem. Channels would not be object-based.

@goodsign
Copy link
Author

Well, that's a problem. Channels would not be object-based.

But why? Is it a technical limitation?

Because it kind of invalidates the whole idea of all that. Because there can be different objects, which reuse the same material, but one of them should be lit and the other -- shouldn't.

@WestLangley
Copy link
Collaborator

But why? Is it a technical limitation?

No. It is because objects do not respond to lights. Only materials do.

Because there can be different objects, which reuse the same material, but one of them should be lit and the other -- shouldn't.

You can use the same material for all objects in the scene -- just clone the material for objects whose material requires different uniform values. There should still be only one shader program shared by all.

@mrdoob
Copy link
Owner

mrdoob commented Aug 11, 2014

I think it should be implemented as a mask. (Whether is it implemented on the CPU or GPU is an issue for later discussion.)

Can this be handled somewhat easily in the GPU directly?

@WestLangley
Copy link
Collaborator

Can this be handled somewhat easily in the GPU directly?

Yes, you would need to pass in the additional channels uniforms for the lights and materials.

@pailhead
Copy link
Contributor

How about a layer management system? I'd group the meshes into layers and apply the masks from there (could affect lights, shadows, visibility, etc), unity would be a good example?

@goodsign
Copy link
Author

goodsign commented Sep 6, 2014

Shadows is also a related topic. I think there should also be something like selective shadow casting. Like 'receiveShadowFrom = ...' (and list of sources) instead of just 'receiveShadow = true'.

Because when you set lights that only affect a specific room (in my example), you would also immediately want those lights to cast shadows only on this room objects.

@satori99
Copy link
Contributor

satori99 commented Sep 7, 2014

Shadows attributes should really be on the materials and not the objects for the same reasons as above in this thread.

@goodsign
Copy link
Author

goodsign commented Sep 7, 2014

Shadows attributes should really be on the materials and not the objects for the same reasons as above in this thread.

Yes, it makes sense!

@goodsign
Copy link
Author

goodsign commented Sep 8, 2014

Are there any plans for including this feature (like a planned target release for the first draft)?

@mrdoob
Copy link
Owner

mrdoob commented Jun 14, 2018

@ErikBehar a PR would be great!

@ErikBehar
Copy link

@tiesselune I'll look into moving it as you suggest, or feel free to push a PR on my fork lol = ] and I'll post the PR soon @mrdoob

@VaelynPhi
Copy link

VaelynPhi commented Oct 17, 2018

What's the status on this? I've merged the r94dev code from @ErikBehar into r94, then merged r97 into it, only a couple very straightforward conflicts (version change, a few variables for selective lighting, and the hash creation in renderers/WebGLRenderer.js; I'd be happy to put in a PR. @tiesselune if you can give me some idea where you intended the selective lighting state to go, I'd be happy to move it, test, and put in a PR.

EDIT:
A little later: I see that this needs some work to function, now, with the new lighthash.

@makc
Copy link
Contributor

makc commented Oct 18, 2018

@VaelynPhi I'd think that, regardless of whether they are willing to accept @ErikBehar 's code or not, it is good idea to submit the PR, just to replace the outdated one in case other people will want it, like you yourself did

@ErikBehar
Copy link

Sorry to drop the ball on this guys = / ... @VaelynPhi can you post your fork / branch ?

@VaelynPhi
Copy link

No worries; I understand being busy. Alas, I couldn't get even the branch you had working, @ErikBehar; I settled on reading through the code to try and break it down so I could move the state to the appropriate location and hopefully fix any bugs. I have yet to get to a working port state even on v94. Perhaps I can clean it up and put in the PR just to update it as @makc suggests. Give me a bit; I'm super busy. :) At the very least maybe that'll help highlight the changes that need to be made to pull selective lighting into the recent version.

@byondrnd
Copy link

byondrnd commented Nov 8, 2018

added a PR based on:
ErikBehar@ac0499b#diff-5e43a0b5002eb2c419def3baf67d4e67
by @ErikBehar
can anyone give a hand with some review and the example ?

#15223

@Flyrell
Copy link

Flyrell commented Feb 17, 2019

Hey guys, what's the status on this one? @tiesselune @ErikBehar Might I help you with something? Would be nice to implement it finally after 4 years 😄💯

@ErikBehar
Copy link

@Flyrell I think we could maybe close this issue since it seems to be closer to done over in #15223 maybe ?

@ttiimmaacc

This comment was marked as abuse.

@makc
Copy link
Contributor

makc commented Aug 13, 2022

@ttiimmaacc it is pretty much "nice to have, but please just use multiple scenes instead"

@aditya03av
Copy link

@makc while using multiple scenes, without setting any background it works fine. But once I change the Background it does not, do you have any idea?

@makc
Copy link
Contributor

makc commented Aug 9, 2023

@adityakailash0399 Idk, have an empty scene with the background set render before all the others, maybe

@gillesboisson
Copy link

Hi, I also checking on the selective light feature for baked / dynamic light system , by mistake I thought it was supported on three js layer, but layers is only camera <> object filter and not light <> object <> camera.
What do you think of this approach, for me it makes more sense than having an extra channel property and it would use bitwise / flags based operation.

@Ctrlmonster
Copy link

Ctrlmonster commented Mar 15, 2024

+1 on the need for selective lighting. This would also enable cool stuff via Spotlight texture projection (similarly to how the shadow projector works in Unity). For example, you could render your character top-down into a render texture, paint it black and project that onto to the environment to have a dynamic character shadow, while keeping receiveShadow=false on all meshes. The only thing that's missing for this is to be able to specify that a spotlight should not affect a specific mesh (the character)🙏
tex-proj

@FarazzShaikh
Copy link
Contributor

three.js.examples.-.Google.Chrome.2024-06-12.20-47-08.mp4

Just got this working for Point Lights. Going to make a draft PR shortly. Works by adding uniforms and testing the light mask vs the object mask in shader.

ThomasGITH pushed a commit to Thiesjoo/PSE that referenced this issue Jun 19, 2024
Some issues: satellites are not really clear in the night:
I cannot add an ambient light because of this:
mrdoob/three.js#5180
@Mugen87
Copy link
Collaborator

Mugen87 commented Oct 30, 2024

Selective lighting is supported in WebGPURenderer, so the issue can be considered as fixed. Besides, sine we want to focus our efforts on WebGPURenderer, WebGLRenderer won't support this feature.

WebGPURenderer has a WebGPU and WebGL 2 backend and supports selective lighting for both. The respective demo is:

https://threejs.org/examples/webgpu_lights_selective

@Mugen87 Mugen87 closed this as completed Oct 30, 2024
@Mugen87 Mugen87 modified the milestones: r???, r170 Oct 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests