Phuein

Ambient Light Discussion

Recommended Posts

Before I get any ideas, or start trying to extend BJS, do we have an ambient light setup somewhere in the engine? To clarify, what I mean is this:

https://threejs.org/docs/#api/en/lights/AmbientLight

A light, or a few lines of code to imitate one, that just adds illumination to everything equally from all directions; no shadows.

Now, I know we have scene.ambientColor working in tandem with StandardMaterial.ambientColor, but those require modifying the material of every mesh, which is a lot of extra complexity in big scenes with many materials and meshes.

So, am I missing anything? Does it make any sense to create a BABYLON.AmbientLight object?

 

P.S. In the meanwhile, is there a way for me to set StandardMaterial's default ambientColor without overriding the engine code? I want to use many different material that all draw from it.

Share this post


Link to post
Share on other sites
11 hours ago, Phuein said:

Now, I know we have scene.ambientColor working in tandem with StandardMaterial.ambientColor, but those require modifying the material of every mesh, which is a lot of extra complexity in big scenes with many materials and meshes.

Well, hmm.  Interesting pondering, for sure, Pheuin.  Generally, I think you would want to roto-tiller thru scene.materials and add an ambientColor of medium gray to all of them.  That's going to burn a hundredth of a second.

After that, you ONLY adjust scene.ambientColor, and all the materials in the entire scene... should react to that "master scene ambient light setting", right?  That is your scene's ambientLight, yes?  no?

I watched a lot of cartoons this morning... so, I could be all screwed-up, reality-wise.  :)

Share this post


Link to post
Share on other sites
9 hours ago, Wingnut said:

I watched a lot of cartoons this morning... so, I could be all screwed-up, reality-wise.  :)

Yes, for sure I could do that, but isn't the whole point of an Ambient Light that it applies to everything uniformly? By default.

 

Quote
Ambient light means the light that is already present in a scene, before any additional lighting is added. It usually refers to natural light, either outdoors or coming through windows etc. It can also mean artificial lights such as normal roomlights.

So I would need to manually disable it for meshes, rather than manually enable it.

Cmon Wingnut, I know you're a wiz, how do I make StandardMaterial's default ambientColor different from the source file without changing the source file? :P I might be wrong, but seems like that will be closest to the definition.

Share this post


Link to post
Share on other sites
7 hours ago, Phuein said:

isn't the whole point of an Ambient Light that it applies to everything uniformly? By default. 

Doesn't scene.ambientColor do exactly that?  It offers each material in the scene... the exact same ambientColor/intensity additive.

And by-default, all BJS-created materials react the same way to that ambient light (no reaction at all). 

Some materials could reflect the blues, others reflect the reds, etc... per material-programmer settings on each material.

Can I assume that you think all materials should have some gray ambientColor by default?  And each should have the same gray, so they each react exactly the same as each other?

Wouldn't that add a lot of .ambientColor settings (scene bytes) to materials... for folks who don't want to use ambient light at all?  Do you think those people would be happy about the unnecessary bytes and unnecessary scene-load time?

If I were me, I'd have all my metals set with ONE shade of gray, all wood to another, all glass to another, all plastics to another, etc, etc.

Maybe I'm missing your point, here.  (PS:  I'm no wizard... I just yammer-on like I am, often).  :D

I suppose it was initial core programmer's decision to have all materials zero-reactive to scene.ambientColor... by default.

If you would have been the initial programmer of StandardMaterial class, would you have set a default material.ambientColor of maybe 127, 127, 127 (half-gray)?

Perhaps that would have been a good idea, but perhaps too late, now... lose backwards compat.  *shrug* 

Let's invite @Deltakosh and others to give more opinions.  I'm not the materials expert you might think I am.  :)

Share this post


Link to post
Share on other sites

https://github.com/BabylonJS/Babylon.js/blob/master/src/Materials/babylon.standardMaterial.ts#L173

There it is, of course.  Let's say we added a property... StandardMaterial.defaultAmbientColor and then changed that line to something like...

public ambientColor = (this.defaultAmbientColor ? this.defaultAmbientColor : new Color3(0, 0, 0));

THEN... at the top of your code...

BABYLON.StandardMaterial.prototype.defaultAmbientColor = new BABYLON.Color3(.5, .5, .5);

That would cause all StandardMaterials that the scene creates... to have their .ambientColor == StandardMaterial.defaultAmbientColor

Would that solve anything?  heh.  Probably not.  Just thinkin'. 

Would it be used often enough to justify the possible bloat?   Dunno.  I'm not much of a coder.  My expertise lies in selling drugs to children. ;)  j/k, of course. 

Share this post


Link to post
Share on other sites
Quote

Can I assume that you think all materials should have some gray ambientColor by default?

No. An ambient light lets you choose the light's color that is applied, according to the light's intensity, to all meshes. It doesn't change any materials directly, just the visual result.

Without knowing better about how BJS handles this, I assume this would be the same as setting StandardMaterial.ambientColor = new BABYLON.Color3(1,1,1). Meaning that the scene.ambientColor decides the output, as expected. Then, the user can disable it for specific materials.

I'm definitely not sure about the best way to apply this to the engine. :D That's why I'm asking for an override in my code, as a temporary quick fix maybe. Don't want to do this for every material instance manually.

EDIT: I'm now realizing that in BABYLON.StandardMaterial only statics are exposed. So if there was a static for AmbientColor = new BABYLON.Color3(1, 1, 1) and it was also applied as public ambientColor = AmbientColor, that would be one way to easily change StandardMaterial without much fuss. (But on that logic we'd have to allow access to all the colors / values that have defaults! hah!) TypeScript confuses me, slightly.

Share this post


Link to post
Share on other sites
6 hours ago, Phuein said:

An ambient light lets you choose the light's color that is applied, according to the light's intensity

Again, that's exactly what scene.ambientColor does.... except no intensity setting.

The intensity is derived from "how much white-ness" is set in each material.ambientColor.  (that's sort of badly worded, but you get the drift)

But I think I see your point.  I think ambientColor is simply "summed" into the final color result.

If ambientColor allowed "50%-summed" or "25%-summed or "double-summed", that would be the same as an .intensity for scene.ambientColor.

Interesting.  Hopefully we'll hear from the designers of material class... soon.

Share this post


Link to post
Share on other sites
20 hours ago, V!nc3r said:

Is it simply not the hemispheric light you talking about?

No, an ambient light has no direction.

 

12 hours ago, Deltakosh said:

So :)

to set up ambient color, just set scene.ambientColor. You can then tune it per material with material.ambientColor (where you can actually define the intensity)

https://www.babylonjs-playground.com/#GEWNUD

This is not a viable solution, when there are many materials. I would have to keep doing this for every material, instead of relying on an actual ambient light for the whole scene.

Also, it falls off the definition of an ambient light; which is the purpose of my op.

Share this post


Link to post
Share on other sites

And why not just made a quick for statement?

scene.ambientColor = BABYLON.Color3.White();
for(let i = 0; i < scene.materials.length; i++){
    scene.materials[i].ambientColor = BABYLON.Color3.White(); 
} 

With this few lines, you have tweaked all your scene.

Quick example.

Share this post


Link to post
Share on other sites

Because then you would have to call that for loop every time a new material is applied. The whole point of an ambient light is to avoid tinkering with each material.

Share this post


Link to post
Share on other sites
34 minutes ago, Phuein said:

call that for loop every time a new material is applied

Nope, the loop can be used at scene launch, then if you create a new material you surely have to do tweaks on it, among other things: set up its ambientColor.

I don't know ThreeJS, but I just try a few test on their editor, it seems that:

  • the ThreeJS ambientLight you talking about in your first post is exactly the same than a default BJS scene.ambientColor
  • the default ThreeJS standardMaterial only have one color property in comparison to BJS StandardMaterial which have diffuseColor & ambientColor. It's just that in the ThreeJS editor, color is white by default.

Share this post


Link to post
Share on other sites

Good discussion.  Interesting spirit from Phuein over...

4 hours ago, Phuein said:

avoid tinkering with each material

:) A simple addMaterial(somemesh) function could auto-set a default .ambientColor (like .5, .5, .5) on any late-created StandardMaterial.  That's not much of a "tinker".  It could use the same value that was used in the for-loop mentioned by @V!nc3r.

hmm.  I guess we need to determine exactly what Phuein means by "tinker"  :)

Perhaps, StandardMaterial could allow an options parameter?  new BABYLON.StandardMaterial('newmat", {ambient: BABYLON.Color3.Gray()}, scene);

What would THAT do for you, P?  :) Anything good?   (It likely gave Deltakosh and other material experts... a brain tumor and a Wingnut-disapproving head shake)  :)

Share this post


Link to post
Share on other sites

Ambient light is something I also  found as a difference in when switching to Babylon from THREE. I'm not aware of any direct mirror in Babylon to achieve this, I've found setting on every material like suggested above to work but you could also try modifying a hemispheric light's color properties to try to simulate ambiance eg. https://playground.babylonjs.com/#UKNERM#31

Share this post


Link to post
Share on other sites

I do not see the problem of having to set mat.ambientColor to white? It is a simple process and it gives you all the control you may need down the line.

Also this statement is not true:

Quote

Because then you would have to call that for loop every time a new material is applied

When a new material is added (By you I guess :)), you only have to set its ambientColor to white and you're done.

 

Then when all your materials have ambientColor set to white, you can control your ambient from scene.ambientColor as you wish.

Share this post


Link to post
Share on other sites

Yeah, but let's say scene has 20 materials initially loaded.  Phuein needs to do the initial loop to set the ambientColors.

5 minutes later, Phuein has to load-in another 20 materials... and has to do the loop again.

10 minutes later, another 20 materials arrive.  Another loop thru all the new materials.

One could set ambientColors in the loadTask onSuccess(), I suppose... so only the newest mesh/materials would need to be looped-thru.

Otherwise, what?  An in-project override of BABYLON.StandardMaterial class... that sets default material.ambientColor to user-preferred gray/white?  Yeah... custom standardMaterial.  hehe.  A chunk of extra code in your project.  Just extra bytes, but not much perf loss.  Borrow the entire StandardMaterial class from https://raw.githubusercontent.com/BabylonJS/Babylon.js/master/dist/babylon.max.js and insert into your project code, then modify.  erf. 

Oh wait...  another idea.  Top of project code:  

BABYLON.StandardMaterial.registerAfterCreation = function () {
     this.ambientColor = new BABYLON.Color3(.5, .5, .5);
};

That would work, but... nooooo, there isn't any registerAfterCreation() on SM.  :) 

Why do I talk?  I got nuthin'.

Share this post


Link to post
Share on other sites
On 9/18/2018 at 5:25 AM, Phuein said:

Because then you would have to call that for loop every time a new material is applied

scene.materials is not observable, but you could make your own class that monitors for changes using a map (http://doc.babylonjs.com/api/classes/babylon.material#id).  at least that would be somewhat more automatic, assuming you don't have full control over when materials are added.

 

edit: I am wrong - looks like it was added two days ago!! :)

Share this post


Link to post
Share on other sites

You can do scene.onNewMaterialAddedObservable.add(function(mat){

mat.ambientColor = BABYLON.Color3.White;

});

 

And to make sure we are all on the same page, the final color of each pixel is built with scene.ambientColor* material.ambientColor which gives you more precise control that what you can get from 3.js

 

Share this post


Link to post
Share on other sites

Hrm, cool, there's an onNewMaterialAddedObservable. Nifty.

Hold on though. I appreciate the work-arounds, but I'm confused. Isn't the whole point of an Ambient Light that it is set to White on all materials by default? That it is a quick ambient light, basically, no extra code necessary.

Having .ambientLight in materials giving us more control is great. But it should be optional, and default to the expected value of White...Unless I'm wrong with the definition and purpose of Ambient Light in 3D. :P I come from 3D modelling (Blender, 3DSMax) and Unreal Engine, where its a set standard. THREE expectedly follows it (jeez their editor is uninviting compared to BJS' playground.) Why is the BJS standard the reverse, using Black? image.png.a4f44ece5fefd9f31cfb7852b000b797.png

Kosh = Hater of ambiance?! REVEALED! :D

Share this post


Link to post
Share on other sites

Well it was a decision taken long time ago (at the very beginning of the engine, 6 years ago). The reason is lost in my memory :)

But because we value backward compatibility we cannot change it now. And because we have a simple way to control that (with the observable) that's not a big deal

 

Share this post


Link to post
Share on other sites

Agreed. But why can't I change the default ambientColor property in StandardMaterial without remaking/workarounds? Something akin to:

BABYLON.StandardMaterial.prototype.ambientColor = new BABYLON.Color3(1, 1, 1)

An override, no need for loops. Why don't the class defaults draw from public variables that can be modified? I noticed this pattern in the engine.

Share this post


Link to post
Share on other sites

I think https://github.com/BabylonJS/Babylon.js/blob/master/src/Materials/babylon.standardMaterial.ts#L173

...will override your "good ingenuity" idea.  Sorry.   I really like the observable idea, to be frank.

On 9/18/2018 at 7:02 PM, Deltakosh said:

scene.onNewMaterialAddedObservable.add(function(mat){
     mat.ambientColor = BABYLON.Color3.White();   //  slightly modded from original Deltakosh version
});

What's wrong with that?

At some point, you'll probably need to get off-of your "material ambientColor should be white by default" -soapbox, and do a little coping and dealing.  :) 

I think I calculated that the "loop thru all materials" could have run around 871 quadrillion times... in the time you have used trying to justify a rare-usage mod to SM.  heh.  

Just own-up to the power of BJS... to mop the floor with hobby-grade frameworks like 3JS.  Leave behind the weaknesses of lesser frameworks, and move-on-up to the pros, eh?  :D

(Just havin' some fun, don't take it "heavy", please.)  :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.