Files
PolyGun/demos/DDA light test/light.py
2024-06-02 15:20:04 +02:00

81 lines
2.8 KiB
Python

import numpy as np
import numba
from ray_casting import light_cast
# left, top, right, bottom
offsets = np.array([[0.0, 0.5], [0.5, 0.0], [1.0, 0.5], [0.5, 1.0]])
normals = np.array([[-1, 0], [0, -1], [1, 0], [0, 1]], dtype=np.float64)
@numba.njit
def inverse_square_law(distance):
return 1 / ((distance + 1) ** 2)
@numba.njit
def process_light(map_arr, emissive_positions):
light_arr = np.zeros(map_arr.shape, dtype=np.float32)
# for each map block
for y in range(map_arr.shape[1]):
for x in range(map_arr.shape[0]):
# skip if block is not air
if map_arr[y, x] != 0:
continue
#print("===============")
#print(emissive_positions)
#print("===============")
# for each emissive block
for emissive_pos in emissive_positions:
#temp_emissive_pos = np.array(emissive_pos)
#print("===============")
# for each wall of emissive block
for i in range(4):
# calculate source position, normal axis and normal sign
#source = temp_emissive_pos + offsets[i]
source = emissive_pos + offsets[i]
#print(source)
# normal axis is alternating: x, y, x, y
source_normal_axis = i % 2
# normal sign is switching in the middle: -1, -1, 1, 1
source_normal_sign = -1 if i < 2 else 1
target = np.array([x + 0.5, y + 0.5])
# cast light
hit, dir, dir_3d = light_cast(map_arr, source, target, source_normal_axis, source_normal_sign)
#print(hit, dir)
# skip if hit (light was blocked by some wall)
if hit:
continue
# calculate distance
distance = np.linalg.norm(source - target)
## calculate light intensity
# area depending on distance
intensity = inverse_square_law(distance)
#intensity = distance
# multiply by dot product of normal and direction
#print(normals[i].dtype, dir.dtype)
# area depending on direction the emissive face is seen by the target
intensity *= np.dot(normals[i], dir)
# and the other way around (we assume target normal is always facing up in 3D in this scenario)
intensity *= np.dot(np.array([0, 0, -1], dtype=np.float64), dir_3d)
# add intensity to light array
light_arr[y, x] += intensity
return light_arr