I'm working on a ray tracing project in Python and encountering a TypeError that I'm having trouble resolving. The error occurs in the vec3_sub function, where I'm trying to subtract two vectors. Here's the relevant code snippet:
def vec3_sub(v1, v2):
return (v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2])
The error traceback points to this line:
color = raytrace(E, vec3_norm(vec3_sub(Q, E)), scene)
And the specific error message is:
TypeError: unsupported operand type(s) for -: 'list' and 'int'
I understand that the error is indicating an issue with subtracting a list and an integer, but I'm not sure how to resolve it in the context of my ray tracing code.
For reference, the vec3_sub function is intended to subtract corresponding components of two vectors. E and Q are defined as follows:
E = (0, 0.35, -1)
Q = (x, y, [0] * (w * h))
Full code with numpy (working)
from PIL import Image
import numpy as np
def extract(cond, x):
if isinstance(x, (int, float)):
return x
else:
return np.extract(cond, x)
def vec3_mul(v, other):
return (v[0] * other, v[1] * other, v[2] * other)
def vec3_add(v1, v2):
return (v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2])
def vec3_sub(v1, v2):
return (v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2])
def vec3_dot(v1, v2):
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]
def vec3_abs(v):
return vec3_dot(v, v)
def vec3_norm(v):
mag = np.sqrt(vec3_abs(v))
return vec3_mul(v, 1.0 / np.where(mag == 0, 1, mag))
def vec3_components(v):
return v
def vec3_extract(v, cond):
return (extract(cond, v[0]), extract(cond, v[1]), extract(cond, v[2]))
def vec3_place(v, cond):
r = (np.zeros(cond.shape), np.zeros(cond.shape), np.zeros(cond.shape))
np.place(r[0], cond, v[0])
np.place(r[1], cond, v[1])
np.place(r[2], cond, v[2])
return r
FARAWAY = 1.0e39
def raytrace(O, D, scene, bounce=0):
distances = [s_intersect(O, D, s) for s in scene]
nearest = np.minimum.reduce(distances)
color = (0, 0, 0)
for (s, d) in zip(scene, distances):
hit = (nearest != FARAWAY) & (d == nearest)
if np.any(hit):
color = vec3_add(color, vec3_place(s_light(vec3_extract(O, hit), vec3_extract(D, hit), extract(hit, d), scene, bounce, s), hit))
return color
def s_intersect(O, D, s):
b = 2 * vec3_dot(D, vec3_sub(O, s[0]))
c = vec3_abs(s[0]) + vec3_abs(O) - 2 * vec3_dot(s[0], O) - (s[1] * s[1])
disc = (b ** 2) - (4 * c)
sq = np.sqrt(np.maximum(0, disc))
h0 = (-b - sq) / 2
h1 = (-b + sq) / 2
h = np.where((h0 > 0) & (h0 < h1), h0, h1)
pred = (disc > 0) & (h > 0)
return np.where(pred, h, FARAWAY)
def s_light(O, D, d, scene, bounce, s):
M = vec3_add(O, vec3_mul(D, d))
N = vec3_mul(vec3_sub(M, s[0]), 1.0 / s[1])
toL = vec3_norm(vec3_sub(L, M))
toO = vec3_norm(vec3_sub(E, M))
nudged = vec3_add(M, vec3_mul(N, 0.0001))
light_distances = [s_intersect(nudged, toL, scene_obj) for scene_obj in scene]
light_nearest = np.minimum.reduce(light_distances)
seelight = light_distances[scene.index(s)] == light_nearest
color = (0.05, 0.05, 0.05)
lv = np.maximum(vec3_dot(N, toL), 0)
color = vec3_add(color, vec3_mul(s[2], lv * seelight))
if bounce < 2:
rayD = vec3_norm(vec3_sub(D, vec3_mul(N, 2 * vec3_dot(N, D))))
color = vec3_add(color, vec3_mul(raytrace(nudged, rayD, scene, bounce + 1), s[3]))
phong = vec3_dot(N, vec3_norm(vec3_add(toL, toO)))
color = vec3_add(color, vec3_mul((1, 1, 1), np.power(np.clip(phong, 0, 1), 50) * seelight))
return color
scene = [
((.75, .1, 1), .6, (0, 0, 1), 0.5),
((-.75, .1, 2.25), .6, (.5, .223, .5), 0.5),
((-2.75, .1, 3.5), .6, (1, .572, .184), 0.5),
((0, -99999.5, 0), 99999, (.75, .75, .75), 0.25),
]
(w, h) = (400, 300)
L = (5, 5, -10)
E = (0, 0.35, -1)
r = float(w) / h
S = (-1, 1 / r + .25, 1, -1 / r + .25)
x = np.tile(np.linspace(S[0], S[2], w), h)
y = np.repeat(np.linspace(S[1], S[3], h), w)
Q = (x, y, 0)
color = raytrace(E, vec3_norm(vec3_sub(Q, E)), scene)
rgb_image = [Image.fromarray((255 * np.clip(c, 0, 1).reshape((h, w))).astype(np.uint8), "L") for c in vec3_components(color)]
Image.merge("RGB", rgb_image).show()
Full code without numpy (not working)
from PIL import Image
import math
def extract(cond, x):
if isinstance(x, (int, float)):
return x
else:
return (x[0] if cond else 0, x[1] if cond else 0, x[2] if cond else 0)
def vec3_mul(v, other):
return (v[0] * other, v[1] * other, v[2] * other)
def vec3_add(v1, v2):
return (v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2])
def vec3_sub(v1, v2):
return (v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2])
def vec3_dot(v1, v2):
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]
def vec3_abs(v):
return vec3_dot(v, v)
def vec3_norm(v):
mag = math.sqrt(vec3_abs(v))
return vec3_mul(v, 1.0 / (1 if mag == 0 else mag))
def vec3_components(v):
return v
def vec3_extract(v, cond):
return (extract(cond, v[0]), extract(cond, v[1]), extract(cond, v[2]))
def vec3_place(v, cond):
r = ((0 if not cond else v[0]), (0 if not cond else v[1]), (0 if not cond else v[2]))
return r
FARAWAY = 1.0e39
def raytrace(O, D, scene, bounce=0):
distances = [s_intersect(O, D, s) for s in scene]
nearest = min(distances)
color = (0, 0, 0)
for (s, d) in zip(scene, distances):
hit = (nearest != FARAWAY) and (d == nearest)
if hit:
color = vec3_add(color, vec3_place(s_light(vec3_extract(O, hit), vec3_extract(D, hit), extract(hit, d), scene, bounce, s), hit))
return color
def s_intersect(O, D, s):
b = 2 * vec3_dot(D, vec3_sub(O, s[0]))
c = vec3_abs(s[0]) + vec3_abs(O) - 2 * vec3_dot(s[0], O) - (s[1] * s[1])
disc = (b ** 2) - (4 * c)
sq = math.sqrt(max(0, disc))
h0 = (-b - sq) / 2
h1 = (-b + sq) / 2
h = (h0 if (h0 > 0) and (h0 < h1) else h1)
pred = (disc > 0) and (h > 0)
return (h if pred else FARAWAY)
def s_light(O, D, d, scene, bounce, s):
M = vec3_add(O, vec3_mul(D, d))
N = vec3_mul(vec3_sub(M, s[0]), 1.0 / s[1])
toL = vec3_norm(vec3_sub(L, M))
toO = vec3_norm(vec3_sub(E, M))
nudged = vec3_add(M, vec3_mul(N, 0.0001))
light_distances = [s_intersect(nudged, toL, scene_obj) for scene_obj in scene]
light_nearest = min(light_distances)
seelight = light_distances[scene.index(s)] == light_nearest
color = (0.05, 0.05, 0.05)
lv = max(vec3_dot(N, toL), 0)
color = vec3_add(color, vec3_mul(s[2], lv * seelight))
if bounce < 2:
rayD = vec3_norm(vec3_sub(D, vec3_mul(N, 2 * vec3_dot(N, D))))
color = vec3_add(color, vec3_mul(raytrace(nudged, rayD, scene, bounce + 1), s[3]))
phong = vec3_dot(N, vec3_norm(vec3_add(toL, toO)))
color = vec3_add(color, vec3_mul((1, 1, 1), math.pow(max(min(phong, 1), 0), 50) * seelight))
return color
scene = [
((.75, .1, 1), .6, (0, 0, 1), 0.5),
((-.75, .1, 2.25), .6, (.5, .223, .5), 0.5),
((-2.75, .1, 3.5), .6, (1, .572, .184), 0.5),
((0, -99999.5, 0), 99999, (.75, .75, .75), 0.25),
]
(w, h) = (400, 300)
L = (5, 5, -10)
E = (0, 0.35, -1)
r = w / h
S = (-1, 1 / r + .25, 1, -1 / r + .25)
x = [i for i in range(w) for _ in range(h)]
y = [j for _ in range(w) for j in range(h)]
Q = (x, y, [0] * (w * h))
color = raytrace(E, vec3_norm(vec3_sub(Q, E)), scene)
rgb_image = [Image.fromarray((255 * max(min(c, 1), 0)).astype('uint8'), 'L').convert('RGB') for c in vec3_components(color)]
Image.merge('RGB', rgb_image).show()
Eis an int but the third component ofQis a list (in the code without numpy).print(E, Q)say?0in the third component ofQbut i got another error:Traceback (most recent call last): File "h:\raytrace-master\rt3.py", line 96, in <module> color = raytrace(E, vec3_norm(vec3_sub(Q, E)), scene) ^^^^^^^^^^^^^^ File "h:\raytrace-master\rt3.py", line 17, in vec3_sub return (v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]) ~~~~~~^~~~~~~ TypeError: unsupported operand type(s) for -: 'list' and 'int'.xandyare also lists. You would have to write arithmetic functions which behave similar to numpy ones or create your ownarrayimplementation with operator overloading. Anyway, it would be much simpler to use numpy than to reimplement a part of it.