how to value based on distance, and angle

This is my current working code,

Now I need to modify it, so lamps that are over X units, priority is angle dependent and distance dependendet, where as
lights under X unit are distant dependent

I can most likely solve this, but I need help with the math.


import bge




def main():


    cont = bge.logic.getCurrentController()
    own = cont.owner
    
    if 'Lights' not in own:
        Lights=[]
        Spots=[]
        for child in own.children:
            if 'Host' in child:
                Lights.append(child)
            if 'SHost' in child:
                Spots.append(child)
                child.setOcclusion(False, False)    
            child.removeParent()
        own['Lights']=Lights
        own['Spots']=Spots
        print('set lights list')
        Hooks=[]
        SHooks=[]
        for objects in bge.logic.getCurrentScene().objects:
            if 'LHook' in objects:
               Hooks.append(objects)
            if 'SHook' in objects:
                SHooks.append(objects)
                   
        own['Hooks']=Hooks
        own['SHooks']=SHooks       
        
    else:
        
                
        lamps = own['Lights'].copy()
        spots = own['Spots'].copy()
        sortStart=[]
        sortStart2=[]
        index=0
        in_use=[]
        for Hooks in own['Hooks']:
            sortStart.append([Hooks,own.getDistanceTo(Hooks)])
        for SHooks in own['SHooks']:
            sortStart2.append([SHooks,own.getDistanceTo(SHooks)])
            
            
        sortedHooks = sorted(sortStart, key=lambda tup: tup[1])   
        sortedHooks2 = sorted(sortStart2, key=lambda tup: tup[1])   
        for Hooks in sortedHooks:
            if len(lamps)!=0:
                Hooks[0]['LHook']=lamps[0]
                lamps[0].energy=Hooks[0]['Energy']
                lamps[0]['Host']=Hooks[0]
                lamps[0].worldPosition=Hooks[0].worldPosition
                lamps[0].color = (Hooks[0].color[0],Hooks[0].color[1],Hooks[0].color[2])
                
                lamps[0].children[0].color=Hooks[0].color
                lamps[0].setParent(Hooks[0])
                lamps.pop(0)    
        
        
        read=[]
        for Hooks in sortedHooks2:
            if len(spots)!=0:
                Hooks[0]['LHook']=spots[0]
                spots[0].energy=Hooks[0]['Energy']
                spots[0]['Host']=Hooks[0]
                spots[0].worldPosition=Hooks[0].worldPosition
                spots[0].color = (Hooks[0].color[0],Hooks[0].color[1],Hooks[0].color[2])
                spots[0].worldOrientation=Hooks[0].worldOrientation
                spots[0].children[0].color=Hooks[0].color
                spots[0].setParent(Hooks[0])
                spots[0].children[0].worldPosition=own.worldPosition+(own.worldOrientation.col[1]*1.5)
                read.append(Hooks[0])
                own['Read']=str(read)
                spots.pop(0)          
                  
            
            
                        
                
                
                
                


main()



anything sure , but maybe use mathutils.geometry.line_intersection() can be more simple .
since you have ever one point as reference, rather than make mess with distance AND angles

is complex!
anyway work as expected
in my blend test i used just 2 spots that turn .

and i used both the distance of the camera “far” , and the distance of the spot(lit distance)


import bge
from mathutils import Vector, geometry




def lightmanipulator(cont):
    cam = cont.owner
    
    def get_distance_from_line_intersection(cam, spot):
        v1 = cam.worldPosition
        v2 = v1 -cam.worldOrientation.col[2]*cam.far
        v3 = spot.worldPosition
        v4 = v3 -spot.worldOrientation.col[2]*spot.distance
        intersections = geometry.intersect_line_line(v1,v2,v3,v4)
        p1, p2 = intersections
        bge.render.drawLine(v1,v2,[0,1,0])
        bge.render.drawLine(v3,v4,[0,0,1])
        bge.render.drawLine(p1,p2,[1,0,0])
        return cam.getDistanceTo(intersections[0])
    
    spots = cam.scene.lights
    spot_sorted = sorted(spots, key=lambda spot: get_distance_from_line_intersection(cam,spot))
    energy = 10.0
    for spot in spot_sorted: 
        spot.energy = energy
        energy*=0.01 #give low energy to the "farest & angled"
        

Well, what is the behaviour? Is the distance linearly important, or quadratic, quartic? The same for the angle.

E.g


from math import pi
    
def find_light_priorities(cont):
    own = cont.owner
    scene = cont.scene
    
    threshold_distance = 50
    angle_threshold = pi / 2 #90 degrees
    forward_vector = own.getAxisVect((0, 1, 0))
    own_position = own.worldPosition
    
    for light in scene.lights:
        to_light = light.worldPosition - own_position
        
        distance = to_light.length
        weight = distance / threshold_distance
        
        if fractional_distance > 1.0:
            angle = to_light.angle(forward_vector)
            angular_falloff = max(1 - angle / angle_threshold, 0.0)
            weight *= angular_falloff
        
        print(light, weight)

can you post a .blend ?

I still wanted to populate lamp hooks that were near to the player and off angle (no shadow/illumination pop)

So most valuable lamps (first on list) = Closest, but as distance gets greater, the distance off angle from the camera matters more,

I’ll need to read about intersect,

edit: agoose, the equations would need to be adjusted by user experience - ie, I have never done this before, and I don’t know if anyone else has. this is for the dynamic light manager resource,

PS:
using zip() you can avoid a bit of code since it ends the loop when one list is ended, so is perfect in this case:


for light,dummy in zip(lights, dummies_sorted):
    light.enrgy = dummy["Energy"]

that my blend if matter :eyebrowlift2:

Attachments

spot_angled_intersection.blend (84.1 KB)

it looks close to what I need marco, however the lights that are 180 off angle would only be measured from distance from the player (or maybe distance from the closest point on the light angle line?

basically we are ranking light hooks importance to the scene and populating those, and soon potentially ‘ramping’ up to the light hooks energy, so we are only ever using X lamps, and there is no sudden pop when they move.

hi BPR,

for some reason when i readed “angles” , i m focused on the cone of lamp (spot) rather than the cone of the camera .
but the intersection is calculated on 2 lines “infinite” (i noticed this later)
so my code require some adjustament at least
the code of agoose should do the angle job much better.

anyway…
another way, very very simple is use sphereInsideFrustum, this remove a bunch of “candidates”
supposing that you can cover all “requests” (dummy request), it should be just perfect.
if not , you can sort the dummies that remain by distance. (more near more matter)
it is very “linear” and the angle is already keeped in count.
i strongly suggest to try this method

[ie:this should be a build-in! if we are able to disable effectively the lamps! without use dummies]

that is the code i mean:




def replace_dummies_lamps(cam, lights, dummies):
	dummies = [i for i in dummies if cam.sphereInsideFrustum(i.worldPosition, i["distance"]) != 2]
	if len(dummies) > len(lights):
		dummies = sorted(dummies, key=cam.getDistanceTo)
		
	for light, dummy in zip(lights, dummies):
		light.energy = dummy["energy"]
		light.distance = dummy["distance"]
		light.color = dummy.color[:3]
		light.worldPosition = dummy.worldPosition.copy()
		light.worldOrientation = dummy.worldOrientation.copy()


def main():
	# (...)
	
	cam = own.scene.active_camera
	replace_dummies_lamps(cam, own["points_real"], own["points_dummies"])
	replace_dummies_lamps(cam, own["spots_real"], own["spots_dummies"])
	
main()



not tested but is right .
the param “distance” can be “harcodized” (writing 22.0 or what is as default)

and I get the property own[‘points_dummies’] and own[‘points_real’] the same way as before?



if 'StoredList' not in own:
    ObjectList=[]
    for objects in scene.objects:
        if 'property' in objects:
            objectList.append(objects)
    own['StoredList']=objectList