Open goodsign opened 10 years ago
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.
Sounds like you want to use shadows?
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?
Yes... I think this can indeed be handy. Not sure how the API for it should look like though.
Maybe the most simple solution could be the most effective here:
channel
(or group
) to THREE.Light
affectedByLightChannel
(or affectedByLightGroup
) to THREE.Mesh
(Or maybe even to a face in the geometry)What do you think?
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)
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.
That may be a bit too hard to understand... Maybe it's better something like this:
cube.lightInfluences = [ light1, light2 ];
Seems absolutely fine to me.
Maybe it is a bit more difficult to use in some cases, but it is easier to understand, obviously.
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.
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
.
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?
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.
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
.
I like that API :) I can see this working for objects and lights, but how do you see it working for materials?
Only materials respond to lights. This would have to be a property of the material, I would think.
I agree on this with @westlangley. Lights are dependent on materials.
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.
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.
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.
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?
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.
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?
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.
Shadows attributes should really be on the materials and not the objects for the same reasons as above in this thread.
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!
Are there any plans for including this feature (like a planned target release for the first draft)?
As a work-around, can you achieve most of your requirements by having a separate scene for each room (and its lights)?
renderer.autoClear = false;
...
renderer.render( scene1, camera );
renderer.render( scene2, camera );
Hmm, I'll try this approach!
Selective lighting / shadows is a must for future versions IMO.
BIG +9999 for this one, I would love to be able to select if a material casts a shadow from light source A or from light source B. Anyone got a solution currently other than two scenes? That's gonna make things pretty painful for me...
holy crap how is this still not implemented? after +9999 from rohan )
Haha my guess is that it's kind of hard to implement @tsone can you provide some info on that commit? Browsing on a phone client right now
how is it hard to implement if these are just uniforms they pass to materials. all they have to do is substitude global list of lights with the one defined in material, if it exists, somewhere deep in webgl renderer.
Here is a simple JSFiddle that tests the Dev branch's Layers implementation: https://jsfiddle.net/Angrypickle/t8f7q3vo/4/ Unfortunately, as of this moment, it doesn't look as though it's working properly. Or am I doing something wrong?
Yes. Layers don't work with lights yet. They do work with camera/object though! 😊
Roger that sir! Here is an updated JSFiddle that uses overlapping cameras to achieve selective lighting with layers: https://jsfiddle.net/Angrypickle/t4a1eusL/ It seems to work properly on desktop and mobile. Anyone see anything profoundly bad with this approach? At least until lights are tied into the layers functionality?
Anyone see anything profoundly bad with this approach?
of course it is bad. rather than having single camera navigating the scene, people will now have to do things camera1.add( camera2 );
I mean this is WTF when I look at it. Like... what? camera in my camera? what if I have dozens of rooms that need to be individually lit? how many cameras do I need? and layers... there were no layers yesterday, right, and now I have to l̲e̲a̲r̲n̲ about them.
rant over, not to say I have the perfect solution for this. e g alternativa3d people used to put lights on stuff that was in light's bounding boxes. this had an advantage of next-to-0 setup for end users, but it was falling apart when the border between lights had to be at the angle. but still, if I had to solve this problem in actual project right now, I would most probably resolve to scraping used standard materials into ShaderMaterial-s and passing the lights I want to by hand there.
@makc layers are actually super simple (and powerful)! @Zob1's approach is definitely not the right approach. Hopefully it won't take long until layers also work with lights.
Guys just to make sure I am following correctly; let's say I have a single scene and a "main" light source. Is it possible with this technique to have certain materials ignore this main light source, while also casting shadows from a different light source?
Well, for that we'll also have to add layers support to materials.
What we can do at the moment is show/hide objects from the camera:
Say that you are doing a game and, in the editor, you use spheres to display colliders. Those spheres could be set to layer 1, the camera's editor could have layers 0 and 1 enabled, but the game camera could have be set to layer 0. That way, in your editor you see all the dummies, but in the game they're gone.
I think this will make more sense whenever I add the functionality to the editor itself. We should probably do some examples too.
Right! So basically what I am wanting to do is, I have 2D characters in my Three JS world. These characters need "spot" shadows to make them look like they are part of the environment. I am currently achieving this using transparent black circle geometries placed at their feet and some fairly hacky stuff to get it working at angles. Even then it doesn't work well at all on complex surfaces.
My original idea was to have invisible circle geometries places as "halos" above each character and create a light that is pointing directly down, covering the whole scene. These halos would only cast shadows from this light source while everything else in the scene would cast shadows from the "main" light source.
I guess for this idea to work, we need layers right?
These halos would only cast shadows from this light source while everything else in the scene would cast shadows from the "main" light source.
We used to have a shadowOnly
option, but it was removed.
FWIW, there is this approach to creating shadows...
Ah but shadowOnly wouldn't really work because then the halos would cast shadows from both light sources, I only want them to cast shadows from one.
I will check out that example, on the phone right now but looks promising.
Edit Hmm but if that sphere changed its position in the scene and the ground mesh had varying heights, would its shadow match the surface normals of the ground correctly?
Nope...
Yeah thought so. Need layers! Hehe
Hi @rohan-deshpande ,
Yes for your use case, you're going to need layers of some sort. I was the one who implemented the shadowmesh feature a while back. They were meant to be used for a scene containing a flat floor or ground, because they are single-planar shadows. However, if you ever need fast, cheap (but correct) single plane shadows, these are hard to beat performance-wise. The reason I added these was because even for simple demo scenes, shadowmaps dropped my framerate considerably. Shadowmeshes on the other hand run fast even on my phone.
You can check out my game that uses them here:
https://github.com/erichlof/3dLightCycles
I'm rendering the scene twice through 2 different viewports and all game objects (cycles and trail walls) have correct shadows. It runs silky-smooth on my smartphone, which would be impossible with shadowmaps for 2 scene renderings every frame.
+1 here for layers in the future :)
@erichlof game looks and runs great on iPhone6 man.
Okay I guess I'll wait for layers. Until then my hacky solution will have to suffice.
Hey guys Is this thing implemented? http://stackoverflow.com/questions/33689781/casting-shadows-based-on-a-specific-light?noredirect=1#comment55153706_33689781
No it hasn't been implemented yet. You'll have to wait for layers or try one of the solutions listed in ITT (separate scenes for example).
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?