Getting lights to render

Hi there, I’ve been playing around with the Asteroid Sample Code - I’ve made quite a number of interesting little alterations, mostly by way of trying to teach myself how to use python (in the context of the panda engine). I’ve been using the asteroid sample because I thought the simplicity of an (essentially) 2D environment would make things easier… And so far they have.

But what I’m trying to do now is attach a spotlight to the ship, so that the player can only see a cone in front of the ship (I’ll put a point light on as well so that we can see slightly behind the ship). Anyway, I first put in an ambient light (worked perfectly), but when I tried to put in point or spot lights (I haven’t tried directional) they came up black. Or rather, everything else disappeared. Black screen. No light. Nada. And so I was unhappy :frowning:

I’ll show you the code I used (I set it only to illuminate the ship, so that I could see that the game was working; that way the asteroids come up, but the ship is black):

    self.plight = PointLight('self.plight')
    self.plight.setColor(VBase4(1,1,1,1))
    plnp = render.attachNewNode(self.plight.upcastToPandaNode())
    plnp.reparentTo(self.ship)
    self.ship.setLight(plnp)

Oh yeah, I changed the ship texture to be white on black (not that this should make a difference).

This is only the pointlight code (obviously), but I would have thought the problem would be the same.

The problem is that light will only hit a polygon that’s facing toward the light. A polygon that’s facing away from a light, or facing perpendicular to a light, will not be illuminated. (Ambient lights excepted, since they’re not directional).

In a 2D game, all the sprites are really polygons facing directly toward the viewer. It sounds like you made your spotlight exactly perpendicular to that direction. So no light.

That would make a lot of sense… Is there a way to project the light in such a way as to be like a spotlight or torch from the end of the gun? Perhaps if it were elevated slightly towards the camera, then angled down? (How would I do that in the code? :confused: )

Help much appreciated :slight_smile:

EDIT:: I tried positioning the light (after that code, parenting it to the ship) with position (0,x,0), which appears to move the light out of the screen (ie up). Anyway, bizarrely, the further I move it “up”, the brighter everything seems to get - which seems weird, since that should mean it’s getting further away from the plane of play. Thoughts?

FURTHER EDIT:: Right, so having implemented that, I’ve run up with another problem (which I have a horrible feeling you’re about to tell me is an engine “feature” related to performance). It is this: I thought another cool effect would be to attach little red lights to all the bullets, so that they would light up the area into which they are fired. First test went spiffingly, I had to go through creating a new array to hold all my new lights in so that they could be destroyed at the same time as the shots (lest the leave a spooky red glow). So having done that, I ran into a problem: when the game starts, every shot has its little red glow as expected. After about 30 shots or so (I can’t say I’ve counted), the red glow stops appearing - or rather it’s intermittent; one in every 10 or so will have it, the rest will simply be white (no glow, just the normal texture). What might be the reason for this do you think? (Perhaps I’m not properly cleaning something up?)

ps. I tried bulletobject.light.remove() - it crashed the game. Apparently the bullet object had no light object, despite the light being parented to the bullet :frowning:

A polygon can face toward a light, or away from it, but there’s a continous degree of angles in-between. For example, a polygon which faces perfectly toward the light (0 degrees) will get the most light. A polygon which is perpendicular (90 degrees) will get no light. A polygon in-between (45 degrees) will get some light, but not as much as the polygon facing straight toward the light.

So as you raise the light, it makes the polygons face more and more toward the light.

The other phenomenon you talk about, “getting further away from the plane of play,” is called attenuation. But attenuation is disabled unless you explicitly turn it on. So that’s not having any effect.

Next question: the light limit. The reason the lights are having intermittent effects is that a given model can only be lit by a small number of lights: I think it may be 32 or something like that. If you ask more than 32 lights to affect the whole scene, the system will have to ignore some of them.

The solution to this is to carefully control which lights affect which models by using “setLight” more carefully - set this light on this model, set that light on that model, instead of using setLight on the whole scene. For example, each ship could use an algorithm to find the 10 most important light sources. Unfortunately, this is not easy or convenient.

Last question: I’d have to see your code to know why it’s crashing.

I’m not worrying too hard about the last bit, what I’ve done is this:

Each time a bullet is created, a light source is also created and parented to the bullet. The bullet is then added to a list of bullets, the light source to a list of lights.

Upon creation, each bullet and life are set to expire after a given time (this is in the sample asteroid code for the bullets), and if they collide with something, this is set to zero, so that the bullet/light should expire next cycle.

What’s weird though, is that (I tried to say this before, but reading my post I don’t think I made it very clear) when if remove the bullet object, the light (which is parented to it) isn’t removed alongside it (ie. it remains in space, so that that section of the screen has a constant glow). This is why I then created the list of light objects: so that the lights could be individually removed.

So this approach seems to work: when a bullet collides and is destroyed, the light goes too. Which is why I think it’s a little weird that I can’t continue to produce light sources, since I remove them alongside the bullets; I could understand if there were a large number of lights on the screen at one time, but once I’ve lightsource.remove() 'd them, they shouldn’t continue to affect the scene? Or am I not doing something right?

The code I’m using to update the lights and bullets is:

    #update bullets
    newBulletArray = []
    newLightArray = []
    for obj in self.bullets:
      self.updatePos(obj, dt)         #Update the bullet
      #Bullets have an experation time (see definition of fire)
      #If a bullet has not expired, add it to the new bullet list so that it
      #will continue to exist
      if self.getExpires(obj) > task.time: 
          newBulletArray.append(obj)
      else: 
          obj.remove()              #Otherwise remove it from the scene
    
    for obj in self.Lights:
      if self.getExpires(obj) > task.time:
          newLightArray.append(obj)
      else:
          obj.remove()



    #Set the bullet array to be the newly updated array
    self.Lights = newLightArray
    self.bullets = newBulletArray 

(The bullet part was in the original sample). Every time bullet expiration is referenced throughout the rest of the code, light source expiration is inserted as well.

Oh, I have another query, but perhaps it’s not really relevant here… I’ll ask anyway: In normal python, we can remove objects (or variables or whatever) from memory by using

del object

or      del object.subobject

Why can’t we do that in panda - we have to use object.remove() instead?

EDIT::

Main problem solved - the issue lay in the fact that I didn’t realise that doing a lightsource.remove() didn’t also remove said light source from the lists of light sources affecting a given object (in this case the main render object). So the entire scene was continuing to be lit by lights which were no longer present, making it think I had way more lights than I did (and so it refused to deal with new ones properly). My new solution is a little nicer:

def removelight(self, light):
    if render.hasLight(light):
        render.clearLight(light)
    light.remove()