Light 'em up

i tried to add torches to my dungeon, but i need a LOT more than 8 lights.

at first, i need one magic light to light everything up a little but so there are no completely dark places. then, i want every torch to be a lightsource which affects a small area. i can split up the dungeon so that the areas affected by the torches to not share any triangles and avoid the “8 lights at once”-limit.



my problem is: it doesn’t work. :’(

at first, in my dungeon root, i disabled the world roots sunlight:

setLightCombineMode(LightState.COMBINE_RECENT_ENABLED);
    final LightState l_lightState = Core.getInstance().getDisplay().getRenderer().createLightState();
    l_lightState.setEnabled(false);



this seems to work.
but adding lights leads to some walls being totally bright and some being black.

final LightState l_lightState = Core.getInstance().getDisplay().getRenderer().createLightState();
      final PointLight l_pointLight = new PointLight();
      l_pointLight.setLocation(l_center);
      l_pointLight.setEnabled(true);
      l_pointLight.setAttenuate(true);
      l_pointLight.setQuadratic(1.5F);
      l_pointLight.setDiffuse(ColorRGBA.white);
      l_pointLight.setAmbient(ColorRGBA.white);
      l_pointLight.setSpecular(ColorRGBA.white);
      l_pointLight.setShadowCaster(true);
      l_lightState.attach(l_pointLight);
      l_spatial.setRenderState(l_lightState);



this might be the result of me having no idea what these lines do:
      l_pointLight.setAttenuate(true);
      l_pointLight.setQuadratic(1.5F);
      l_pointLight.setDiffuse(ColorRGBA.white);
      l_pointLight.setAmbient(ColorRGBA.white);
      l_pointLight.setSpecular(ColorRGBA.white);

i had a look at testlights, but it didn't give me any information.

Did you check out the lightStateController test?


at first, i need one magic light

I take it the global ambient light won't cut it?

the ligtstatecontrollertest uses exactly what need, but doesn't tell me how it works. how can i set the lights range?

what's the effect of the quadratic/linear/constant values?

      Light attenuation

In a real world, the light intensity should decrease in inverse proportion to the distance.

In OpenGl, we also can defines the light attenuation with the distance.
OpenGl calculates an attenuation factor (between 0 and 1) that is multiplied to the ambient, diffuse and specular color. By default, they are no attenuation (attenuation factor is 1) so you have to defines your own attenuation.

The attenuation formula is (defult attenuation factor is 1) :
    attenuation factor = 1/(GL_CONSTANT_ATTENUATION + GL_LINEAR_ATTENUATION*d + GL_QUADRATIC_ATTENUATION*d
I take it the global ambient light won't cut it?


i tried:

   final PointLight l_global = new PointLight();
    l_global.setEnabled(true);
    l_global.setAttenuate(false);
    l_global.setAmbient(new ColorRGBA(0.3F, 0.3F, 0.3F, 0.3F));
    l_lightState.attach(l_global);



but i don't get ambient light. i get bright walls and dark walls, depending on their orientation and the lights position.

LightState ls;

ls.setGlobalAmbient( ColorRGBA );

happy

i recently made a light tweaker, like jme's shadow tweaker.

It helps to play with the attenuate values.

Its nothing special, but its a useful debug utility.



import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.Hashtable;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import com.jme.light.Light;
import com.jme.light.SpotLight;

public class LightTweaker extends JFrame {
    private float FLOAT_FACTOR = 1000.0f;
    private Light light;
   
    public LightTweaker(SpotLight l) {
        light = l;
       
        getContentPane().setLayout(new GridBagLayout());
        setTitle("FlashlightTweaker");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5, 5, 5, 5);
        gbc.gridy = 1;
        gbc.gridwidth = 3;
        JLabel label = new JLabel("Constant:");
        add(label, gbc);

        gbc.gridwidth = 1;
        final JSlider sldConstant = createFloatSlider(0, 3);
        sldConstant.setValue(1);
        add(sldConstant,  gbc);
        sldConstant.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                light.setConstant(sldConstant.getValue()/FLOAT_FACTOR);
                sldConstant.setToolTipText(""+sldConstant.getValue()/FLOAT_FACTOR);
            }
        });
       
        gbc.gridy = 2;
        gbc.gridwidth = 3;
        label = new JLabel("Linear:");
        add(label, gbc);

        gbc.gridwidth = 1;
        final JSlider sldLinear = createFloatSlider(0, 0.1f);
        add(sldLinear,  gbc);
        sldLinear.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                light.setLinear(sldLinear.getValue()/FLOAT_FACTOR);
                sldLinear.setToolTipText(""+sldLinear.getValue()/FLOAT_FACTOR);
            }
        });       
       
        gbc.gridy = 3;
        gbc.gridwidth = 3;
        label = new JLabel("Quadratic:");
        add(label, gbc);

        gbc.gridwidth = 1;
        final JSlider sldQuadratic = createFloatSlider(0, 0.1f);
        add(sldQuadratic,  gbc);
        sldQuadratic.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                light.setQuadratic(sldQuadratic.getValue()/FLOAT_FACTOR);
                sldQuadratic.setToolTipText(""+sldQuadratic.getValue()/FLOAT_FACTOR);
            }
        });
       
        gbc.gridy = 4;
        gbc.gridwidth = 3;
        label = new JLabel("Exponent:");
        add(label, gbc);

        if (light instanceof SpotLight) {
           gbc.gridwidth = 1;
           final JSlider sldExp = createSlider(0, 128, 5);
           add(sldExp,  gbc);
           sldExp.addChangeListener(new ChangeListener() {
               public void stateChanged(ChangeEvent e) {
                   ((SpotLight)light).setExponent(sldExp.getValue());
               }
           });
        }
        pack();
    }
   
    private JSlider createSlider(int min, int max, int space) {
        JSlider sld = new JSlider(min, max, 0);
        sld.setPaintLabels(true);
        sld.setMajorTickSpacing(space);
        sld.setSnapToTicks(false);
        sld.setFont(new Font("Arial", Font.PLAIN, 8));
        return sld;
    }


    private JSlider createFloatSlider(float min, float max) {
        int iMin = (int)(min*FLOAT_FACTOR);
        int iMax = (int)(max*FLOAT_FACTOR);

        JSlider sld = new JSlider(iMin, iMax, 0);
        sld.setPaintLabels(true);
//      sld.setMajorTickSpacing(iSpace);
        sld.setSnapToTicks(false);
        sld.setFont(new Font("Arial", Font.PLAIN, 8));

        Hashtable<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>();
        labelTable.put(new Integer(0), new JLabel(""+min));
        labelTable.put(new Integer(iMin), new JLabel(""+min));
        labelTable.put(new Integer(iMax/2), new JLabel(""+(max/2)));
        labelTable.put(new Integer(iMax), new JLabel(""+max));
        sld.setLabelTable(labelTable);

        sld.setPaintLabels(true);
        return sld;
    }

}



usage:


new LightTweaker(yourLight).setVisible(true);

That sounds a LOT like one of Nate Stevens example programs.  If you could extend it to be able to change the type of light and specular, diffuse, and ambient values that could be a GREAT tool to be put into jME itself. (Maybe also have material values)



It a GREAT way to 'play' with the values :smiley:

about that 8 light limit… does it mean 8 lights per node, or 8 lights at all per frame?

in my dungeon there are up to ~100 lights visible, but only 2 per node - and yet, not all of them are working. if i turn around, some switch on and some switch off.

The limit is 8 lights per lighting equation, which basically means 8 lights per mesh.



Mr Coder is doing some refactoring in the light area, particularly in sorting and using the best lights.  You may be able to see that in the coming weeks, but perhaps he could comment on his findings here when he has the time.

i "solved" my problem by disabling the occlusion mapping from testfragmentprogramstate and using just a simple texture. it seems the vertex/fragment program ignores the attenuation

SO when do we get to see a screenie (or vid) with these lights, it sounds super sweet :smiley:

the parallax one with missing attenuation (and the player as a light source):





the one with normal textures looks pretty crappy right now. i’ll wait for the final wall/ground/ceiling models before i show it :stuck_out_tongue_winking_eye:

and here, some buggy torches and wornd positioned lights:





but you can see where it’s going at.



is there a way to set a light to the future center of a bounding box? when i’m building the dungeon and position the torches, i only have the relative position inside the zone, but i need the absolute position for the light. in this screen, i made a good guess where the torch is, but using it’s actual bouning box center would be better.



here’s a fixed one:




Hmm, tough one.  I will have to think on it for a bit…

what i've done so far is removing the limit on number of lights per lightstate, and added in functionality in core for sorting by distance/prioritizing the lights of which the first 8 is used(if you have that many). so you won't have to mess with adding every spatial to a lightcontrollermanager (and giving all those spatials their own lightstate which was required), and you can choose to sort lights on whatever level you want(root or only the spatial moved etc)…



this is in 2.0 though :wink:

ooohhh mmmaaann.  When do we get to play? :smiley:

veeery soon  :stuck_out_tongue: (starting to sound like a broken record?)

Man, I am still (and probably will be forever) about the awesomeness of jME.  Just to know theres a v2.0 coming out…, well it's like christmas :smiley:



Side Note: Is awesomeness actually a word??