webgpu-app/tools/obj/tangent.py
2026-07-16 15:21:09 -05:00

82 lines
2.3 KiB
Python

import numpy as np
PNT = list[tuple[float, float, float, # position
float, float, # texture
float, float, float, float]] # normal
def get_position(vertex_buffer: list[PNT], index):
return vertex_buffer[index][0:3]
def get_texture(vertex_buffer: list[PNT], index):
return vertex_buffer[index][3:5]
def get_normal(vertex_buffer: list[PNT], index):
return vertex_buffer[index][5:8]
def normalize(v):
return v / np.linalg.norm(v)
def generate_tangents(vertex_buffer: list[PNT],
index_buffer: list[int]):
vertex_count = len(vertex_buffer)
triangle_count = len(index_buffer) // 3
tan_s = np.zeros((vertex_count, 3,))
tan_t = np.zeros((vertex_count, 3,))
for t in range(triangle_count):
i0 = index_buffer[t * 3 + 0]
i1 = index_buffer[t * 3 + 1]
i2 = index_buffer[t * 3 + 2]
p0 = get_position(vertex_buffer, i0)
p1 = get_position(vertex_buffer, i1)
p2 = get_position(vertex_buffer, i2)
uv0 = get_texture(vertex_buffer, i0)
uv1 = get_texture(vertex_buffer, i1)
uv2 = get_texture(vertex_buffer, i2)
x1 = p1[0] - p0[0]
x2 = p2[0] - p0[0]
y1 = p1[1] - p0[1]
y2 = p2[1] - p0[1]
z1 = p1[2] - p0[2]
z2 = p2[2] - p0[2]
s1 = uv1[0] - uv0[0]
s2 = uv2[0] - uv0[0]
t1 = uv1[1] - uv0[1]
t2 = uv2[1] - uv0[1]
d = (s1 * t2 - s2 * t1)
r = 1.0 / d if d != 0 else 0
sdir = np.array([(t2 * x1 - t1 * x2) * r,
(t2 * y1 - t1 * y2) * r,
(t2 * z1 - t1 * z2) * r])
tdir = np.array([(s1 * x2 - s2 * x1) * r,
(s1 * y2 - s2 * y1) * r,
(s1 * z2 - s2 * z1) * r])
tan_s += sdir
tan_t += tdir
tangents = []
for v in range(vertex_count):
n = np.array(get_normal(vertex_buffer, v))
s = tan_s[v]
# orthagonalize
tangent = normalize(s - n * np.dot(n, s))
h = np.dot(np.cross(n, s), tan_t[v])
w = -1.0 if h < 0.0 else 1.0
tangent_w = (tangent[0], tangent[1], tangent[2], w)
#print(tangent_w)
tangents.append(tangent_w)
return tangents