Orient-Anything / render /speedup.py
zhang-ziang
render engine
2d48693
raw
history blame
3.39 kB
# import cython
import numpy as np
from math import sqrt
def normalize(x, y, z):
unit = sqrt(x * x + y * y + z * z)
if unit == 0:
return 0, 0, 0
return x / unit, y / unit, z / unit
def get_min_max(a, b, c):
min = a
max = a
if min > b:
min = b
if min > c:
min = c
if max < b:
max = b
if max < c:
max = c
return int(min), int(max)
def dot_product(a0, a1, a2, b0, b1, b2):
r = a0 * b0 + a1 * b1 + a2 * b2
return r
def cross_product(a0, a1, a2, b0, b1, b2):
x = a1 * b2 - a2 * b1
y = a2 * b0 - a0 * b2
z = a0 * b1 - a1 * b0
return x,y,z
# @cython.boundscheck(False)
def generate_faces(triangles, width, height):
""" draw the triangle faces with z buffer
Args:
triangles: groups of vertices
FYI:
* zbuffer, https://github.com/ssloy/tinyrenderer/wiki/Lesson-3:-Hidden-faces-removal-(z-buffer)
* uv mapping and perspective correction
"""
i, j, k, length = 0, 0, 0, 0
bcy, bcz, x, y, z = 0.,0.,0.,0.,0.
a, b, c = [0.,0.,0.],[0.,0.,0.],[0.,0.,0.]
m, bc = [0.,0.,0.],[0.,0.,0.]
uva, uvb, uvc = [0.,0.],[0.,0.],[0.,0.]
minx, maxx, miny, maxy = 0,0,0,0
length = triangles.shape[0]
zbuffer = {}
faces = []
for i in range(length):
a = triangles[i, 0, 0], triangles[i, 0, 1], triangles[i, 0, 2]
b = triangles[i, 1, 0], triangles[i, 1, 1], triangles[i, 1, 2]
c = triangles[i, 2, 0], triangles[i, 2, 1], triangles[i, 2, 2]
uva = triangles[i, 0, 3], triangles[i, 0, 4]
uvb = triangles[i, 1, 3], triangles[i, 1, 4]
uvc = triangles[i, 2, 3], triangles[i, 2, 4]
minx, maxx = get_min_max(a[0], b[0], c[0])
miny, maxy = get_min_max(a[1], b[1], c[1])
pixels = []
for j in range(minx, maxx + 2):
for k in range(miny - 1, maxy + 2):
# 必须显式转换成 double 参与底下的运算,不然结果是错的
x = j
y = k
m[0], m[1], m[2] = cross_product(c[0] - a[0], b[0] - a[0], a[0] - x, c[1] - a[1], b[1] - a[1], a[1] - y)
if abs(m[2]) > 0:
bcy = m[1] / m[2]
bcz = m[0] / m[2]
bc = (1 - bcy - bcz, bcy, bcz)
else:
continue
# here, -0.00001 because of the precision lose
if bc[0] < -0.00001 or bc[1] < -0.00001 or bc[2] < -0.00001:
continue
z = 1 / (bc[0] / a[2] + bc[1] / b[2] + bc[2] / c[2])
# Blender 导出来的 uv 数据,跟之前的顶点数据有一样的问题,Y轴是个反的,
# 所以这里的纹理图片要旋转一下才能 work
v = (uva[0] * bc[0] / a[2] + uvb[0] * bc[1] / b[2] + uvc[0] * bc[2] / c[2]) * z * width
u = height - (uva[1] * bc[0] / a[2] + uvb[1] * bc[1] / b[2] + uvc[1] * bc[2] / c[2]) * z * height
# https://en.wikipedia.org/wiki/Pairing_function
idx = ((x + y) * (x + y + 1) + y) / 2
if zbuffer.get(idx) is None or zbuffer[idx] < z:
zbuffer[idx] = z
pixels.append((i, j, k, int(u) - 1, int(v) - 1))
faces.append(pixels)
return faces