在python中栅格化三角形的快速方法

时间:2014-10-23 17:29:05

标签: python 3d geometry 2d rasterizing

在python中,我希望尽可能快地从3D三角形栅格化2D三角形,并剪切超出z边界的像素。我可以将3D坐标转换为2D,我似乎无法进行光栅化工作。我使用的是设置像素的方法,其中(x,y,颜色)和(0,0)位于左上角。

感谢您的帮助。 这是我使用的三角形代码。

def triangle(self,v = vec2(0,0),v1 = vec2(0,0),v2 = vec2(0,0), colour = 0xFFFFFF):
    sort = sortVecByY(v,v1,v2)
    a = sort[0]
    b = sort[1]
    c = sort[2]

    if b.y == c.y:
        self.flatBottomTri(a,b,c,colour)
    elif a.y == b.y:
        self.flatTopTri(a,b,c,colour)
    else:
        d = vec2(int(a.x + (float((b.y-a.y)/(c.y-a.y))) * (c.x - a.x)),b.y)
        self.flatBottomTri(a,b,d,colour)
        self.flatTopTri(b,d,c,colour)
def flatBottomTri(self,v1,v2,v3,colour):
    r1 = (v2.y - v1.y)
    s1 = 0
    if r1 != 0.0:
        s1 = (v2.x - v1.x) / r1

    r2 = (v3.y - v1.y)
    s2 = 0
    if r2 != 0.0:
        s2 = (v3.x - v1.x) / (v3.y - v1.y)

    x1 = v1.x
    x2 = v1.x + 0.5

    for sy in range(v1.y,v2.y):
        for x in range(int(x1),int(x2)):
            self.set(x,sy,colour)
        x1 += s1
        x2 += s2

def flatTopTri(self,v1,v2,v3,colour):
    s1 = (v3.x - v1.x) / (v3.y - v1.y)
    s2 = (v3.x - v2.x) / (v3.y - v2.y)

    x1 = v3.x
    x2 = v3.x + 0.5

    for sy in range(v3.y,v1.y,-1):
        x1 -= s1
        x2 -= s2
        for x in range(int(x1),int(x2)):
            self.set(x,sy,colour)

1 个答案:

答案 0 :(得分:0)

对于我的 shapeimager 包 (github.com/pedrohasselmann/shapeimager),我让下面的类工作得非常快。

它是用 Cython 编写的,并且摆脱了 GIL。 TriangleAccumulator() 从表示其角的 3D 位置的向量中返回像素填充的三角形。 它在 0.3 秒内运行了 50 万个三角形。

cdef bint point_in_triangle(float[::1] xp,
                         float[::1] yp,
                         float x, 
                         float y) nogil:
 
 cdef:
   float dX = x - xp[0]
   float dY = y - yp[0]
   float dX20 = xp[2] - xp[0]
   float dY20 = yp[2] - yp[0]
   float dX10 = xp[1] - xp[0]
   float dY10 = yp[1] - yp[0]

   float s = (dY20*dX) - (dX20*dY)
   float t = (dX10*dY) - (dY10*dX)
   float D = (dX10*dY20) - (dY10*dX20)

 if D>0:
     return (s>=0) & (t>=0) & ((s + t)<=D)
 else:
     return (s<=0) & (t<=0) & ((s + t)>=D)


cdef (float, float) minmax(float[::1] arr) nogil:
    cdef float min = INFINITY
    cdef float max = -INFINITY
    cdef ssize_t i, L = arr.shape[0]
    for i in range(L):
        if arr[i] < min:
            min = arr[i]
        if arr[i] > max:
            max = arr[i]
    return min, max


cdef class TriangleAccumulator:

cdef:
   short width, height
   int n
   unsigned int[:, ::1] image
   unsigned short[::1] rr, cc
   unsigned int[::1] ff

def __cinit__(self, short width, 
                    short height, 
                    short x):

    self.n = 0
    self.width = width
    self.height = height
    shape = (height, width)
    
    self.image = np.zeros(shape, dtype=uint32)
    self.rr = np.empty(x*(self.width-1)*(self.height-1), dtype=uint16, order='C')
    self.cc = np.empty(x*(self.width-1)*(self.height-1), dtype=uint16, order='C')
    self.ff = np.empty(x*(self.width-1)*(self.height-1), dtype=uint32, order='C')

def reset(self):
   self.image[:, :] = 0


@cython.boundscheck(False)  # Deactivate bounds checking
@cython.wraparound(False)   # Deactivate negative indexing.
@cython.nonecheck(False)
@cython.cdivision(True)
cdef void superimpose_polygon(self, 
                              float[::1] ya, 
                              float[::1] xa, 
                              unsigned int value) nogil:

    cdef float minya, maxya, minxa, maxxa
    minya, maxya = minmax(ya)
    minxa, maxxa = minmax(xa)

    cdef:
       ssize_t minr = int(max(0, minya))
       ssize_t maxr = int(ceil(maxya))
       ssize_t minc = int(max(0, minxa))
       ssize_t maxc = int(ceil(maxxa))
       unsigned short r, c

    maxr = min(self.height -1, maxr)
    maxc = min(self.width  -1, maxc)

    for r in range(minr, maxr+1):
        for c in range(minc, maxc+1):
            if point_in_triangle(xa, ya, c, r):#point_in_polygon(xa, ya, c, r):
                self.image[r, c] = value
                self.rr[self.n] = r
                self.cc[self.n] = c
                self.ff[self.n] = value
                self.n +=1