Skip to content

Instantly share code, notes, and snippets.

@pekkavaa
Last active March 15, 2022 14:31
Show Gist options
  • Save pekkavaa/4b170e21ccd3aa12e747b7702464a727 to your computer and use it in GitHub Desktop.
Save pekkavaa/4b170e21ccd3aa12e747b7702464a727 to your computer and use it in GitHub Desktop.
NumPy triangle rasterizer
import numpy as np
import matplotlib.pyplot as plt
from numpy import array
width = 100
height = 80
# The triangle
d = np.array([ [ [0.9, 0.5], [0.5, 0.8], [0.1, 0.15] ] ])
# Calculates the distance from the edge v0-v1 to point p
def edgefunc(v0, v1, p):
px = p[:, 1]
py = p[:, 0]
return (v0[:,0] - v1[:,0])*px + (v1[:,1] - v0[:,1])*py + (v0[:,1]*v1[:,0] - v0[:,0]*v1[:,1])
# Calculate the area of the parallelogram formed by the triangle
area = edgefunc(d[:, 2, :], d[:, 1, :], d[:, 0, :])
# Create a grid of sampling positions
ys = np.linspace(0, 1, height, endpoint=False)
xs = np.linspace(0, 1, width, endpoint=False)
xpos = np.tile(xs, (height, 1))
ypos = np.tile(ys, (width, 1)).transpose()
# Reshape the sampling positions to a H x W x 2 tensor
pos = np.moveaxis(array(list(zip(ypos, xpos))), 1, 2)
pos = np.reshape(pos, (height*width, 2))
# Evaluate the edge functions at every position
w0 = edgefunc(d[:, 2, :], d[:, 1, :], pos)
w1 = edgefunc(d[:, 0, :], d[:, 2, :], pos)
w2 = edgefunc(d[:, 1, :], d[:, 0, :], pos)
# Only pixels inside the triangle will have color
mask = (w0 > 0) & (w1 > 0) & (w2 > 0)
data = np.zeros((height * width, 3), dtype=np.uint8)
data[:,0] = (w0 / area[0])*255*mask
data[:,1] = (w1 / area[0])*255*mask
data[:,2] = (w2 / area[0])*255*mask
plt.imshow(np.reshape(data, (height, width, 3)), interpolation='nearest')
plt.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment