0

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()
6
  • 1
    The third component of E is an int but the third component of Q is a list (in the code without numpy). Commented Dec 20, 2023 at 17:26
  • what does print(E, Q) say? Commented Dec 20, 2023 at 17:30
  • @MichaelButscher I put 0 in the third component of Q but 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'. Commented Dec 20, 2023 at 17:35
  • I oversaw that x and y are also lists. You would have to write arithmetic functions which behave similar to numpy ones or create your own array implementation with operator overloading. Anyway, it would be much simpler to use numpy than to reimplement a part of it. Commented Dec 20, 2023 at 17:51
  • To be honest i'm translating my python code to c# and it would be simpler to translate the code without numpy and with normal python code. If it's possible for you, Can you write me an answer for fixed code? Commented Dec 20, 2023 at 17:57

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.