问field的元素交换问题。

两种方法都无法交换,最后P[0], P[1] 都是 P[1]的值。

P = Point2.field(shape=(7))

P[0], P[1] = P[1], P[0]

temp = P[0]
P[0] = P[1]
P[1] = temp

我现在的处理方法比较丑

P[0].x, P[0].y, P[1].x, P[1].y = P[1].x, P[1].y, P[0].x, P[0].y

有比较优雅的方式吗?

方便发一下Point2是怎么定义的吗? :grinning:

代码1

import taichi as ti

ti.init(ti.cpu)

Color = ti.types.vector(3, ti.f32)
Point = ti.types.vector(2, ti.i32)
Point2 = ti.types.struct(
    x=ti.i32, y=ti.i32, c=Color,
)

width = 1024
height = 1024
pixels = Color.field(shape=(width, height))
center = Point([width // 2, height // 2])


@ti.data_oriented
class Triangle:
    LEFT = True
    RIGHT = False

    def __init__(self, P):
        self.P = P
        self.nTotalScanLine = 0
        self.SpanLeft = None
        self.SpanRight = None

    def SortPoint(self):
        if self.P[0].y > self.P[1].y:
            self.P[0].x, self.P[0].y, self.P[1].x, self.P[1].y = self.P[1].x, self.P[1].y, self.P[0].x, self.P[0].y
            self.P[0].c.x, self.P[0].c.y, self.P[0].c.z, self.P[1].c.x, self.P[1].c.y, self.P[1].c.z = self.P[
                1].c.x, self.P[1].c.y, self.P[1].c.z, self.P[0].c.x, self.P[0].c.y, self.P[0].c.z
        if self.P[0].y > self.P[2].y:
            self.P[0].x, self.P[0].y, self.P[2].x, self.P[2].y = self.P[2].x, self.P[2].y, self.P[0].x, self.P[0].y
            self.P[0].c.x, self.P[0].c.y, self.P[0].c.z, self.P[2].c.x, self.P[2].c.y, self.P[2].c.z = self.P[
                2].c.x, self.P[2].c.y, self.P[2].c.z, self.P[0].c.x, self.P[0].c.y, self.P[0].c.z
        if self.P[1].y > self.P[2].y:
            self.P[1].x, self.P[1].y, self.P[2].x, self.P[2].y = self.P[2].x, self.P[2].y, self.P[1].x, self.P[1].y
            self.P[1].c.x, self.P[1].c.y, self.P[1].c.z, self.P[2].c.x, self.P[2].c.y, self.P[2].c.z = self.P[
                2].c.x, self.P[2].c.y, self.P[2].c.z, self.P[1].c.x, self.P[1].c.y, self.P[1].c.z

    def SortPoint2(self):
        if self.P[0].y > self.P[1].y:
            self.P[0], self.P[1] = self.P[1], self.P[0]
        if self.P[0].y > self.P[2].y:
            self.P[0], self.P[2] = self.P[2], self.P[0]
        if self.P[1].y > self.P[2].y:
            self.P[1], self.P[2] = self.P[2], self.P[1]

    def Interp(self, m, m0, m1, c0, c1):
        color = (m1 - m) / (m1 - m0) * c0 + (m - m0) / (m1 - m0) * c1
        return color

    def EdgeFlag(self, PStart, PEnd, bFeature):
        dx = PEnd.x - PStart.x
        dy = PEnd.y - PStart.y
        m = dx / dy
        x = PStart.x
        for y in range(PStart.y, PEnd.y):
            color = self.Interp(y, PStart.y, PEnd.y, PStart.c, PEnd.c)
            if bFeature:
                self.SpanLeft[self.nIndex].x = ti.round(x)
                self.SpanLeft[self.nIndex].y = y
                self.SpanLeft[self.nIndex].c = color
                self.nIndex += 1
            else:
                self.SpanRight[self.nIndex].x = ti.round(x)
                self.SpanRight[self.nIndex].y = y
                self.SpanRight[self.nIndex].c = color
                self.nIndex += 1
            x += m

    def Fill(self):
        print("before: ", self.P)
        self.SortPoint()
        # self.SortPoint2()
        print("after: ", self.P)
        nTotalScanLine = self.P[2].y - self.P[0].y + 1
        self.SpanLeft = Point2.field(shape=(nTotalScanLine))
        self.SpanRight = Point2.field(shape=(nTotalScanLine))
        nDeltz = (self.P[2].x - self.P[0].x) * (self.P[1].y - self.P[0].y) - \
            (self.P[2].y - self.P[0].y) * (self.P[1].x - self.P[0].x)
        if nDeltz > 0:
            self.nIndex = 0
            self.EdgeFlag(self.P[0], self.P[1], Triangle.LEFT)
            self.EdgeFlag(self.P[1], self.P[2], Triangle.LEFT)
            self.nIndex = 0
            self.EdgeFlag(self.P[0], self.P[2], Triangle.RIGHT)
        else:
            self.nIndex = 0
            self.EdgeFlag(self.P[0], self.P[2], Triangle.LEFT)
            self.nIndex = 0
            self.EdgeFlag(self.P[0], self.P[1], Triangle.RIGHT)
            self.EdgeFlag(self.P[1], self.P[2], Triangle.RIGHT)
        for y in range(self.P[0].y, self.P[2].y):
            n = y - self.P[0].y
            for x in range(self.SpanLeft[n].x, self.SpanRight[n].x):
                color = self.Interp(
                    x, self.SpanLeft[n].x, self.SpanRight[n].x, self.SpanLeft[n].c, self.SpanRight[n].c)
                pixels[x, y] = color


pixels.fill(Color([1.0, 1.0, 1.0]))
P = Point2.field(shape=(3))
P[0].x = -300 + center.x
P[0].y = -300 + center.y
P[0].c = Color([1.0, 0.0, 0.0])
P[1].x = 100 + center.x
P[1].y = 300 + center.y
P[1].c = Color([0.0, 1.0, 0.0])
P[2].x = 200 + center.x
P[2].y = -100 + center.y
P[2].c = Color([0.0, 0.0, 1.0])
triangle = Triangle(P)
triangle.Fill()
gui = ti.GUI("10", (width, height))
while gui.running:
    gui.set_image(pixels)
    gui.show()

代码2

import taichi as ti

ti.init(ti.cpu)

Color = ti.types.vector(3, ti.f32)
Point = ti.types.vector(2, ti.i32)

width = 1024
height = 1024
pixels = Color.field(shape=(width, height))
center = Point([width // 2, height // 2])


@ti.data_oriented
class Triangle:
    LEFT = True
    RIGHT = False

    def __init__(self, P):
        self.P = P
        self.nTotalScanLine = 0
        self.SpanLeft = None
        self.SpanRight = None

    def SortPoint(self):
        if self.P[0].y > self.P[1].y:
            self.P[0].x, self.P[0].y, self.P[1].x, self.P[1].y = self.P[1].x, self.P[1].y, self.P[0].x, self.P[0].y
        if self.P[0].y > self.P[2].y:
            self.P[0].x, self.P[0].y, self.P[2].x, self.P[2].y = self.P[2].x, self.P[2].y, self.P[0].x, self.P[0].y
        if self.P[1].y > self.P[2].y:
            self.P[1].x, self.P[1].y, self.P[2].x, self.P[2].y = self.P[2].x, self.P[2].y, self.P[1].x, self.P[1].y

    def SortPoint2(self):
        if self.P[0].y > self.P[1].y:
            self.P[0], self.P[1] = self.P[1], self.P[0]
        if self.P[0].y > self.P[2].y:
            self.P[0], self.P[2] = self.P[2], self.P[0]
        if self.P[1].y > self.P[2].y:
            self.P[1], self.P[2] = self.P[2], self.P[1]

    def EdgeFlag(self, PStart, PEnd, bFeature):
        dx = PEnd.x - PStart.x
        dy = PEnd.y - PStart.y
        m = dx / dy
        x = PStart.x
        for y in range(PStart.y, PEnd.y):
            if (bFeature):
                self.SpanLeft[self.nIndex] = Point(ti.round(x), y)
                self.nIndex += 1
            else:
                self.SpanRight[self.nIndex] = Point(ti.round(x), y)
                self.nIndex += 1
            x += m

    def Fill(self):
        print("before: ", self.P)
        self.SortPoint()
        # self.SortPoint2()
        print("after: ", self.P)
        nTotalScanLine = self.P[2].y - self.P[0].y + 1
        self.SpanLeft = Point.field(shape=(nTotalScanLine))
        self.SpanRight = Point.field(shape=(nTotalScanLine))
        nDeltz = (self.P[2].x - self.P[0].x) * (self.P[1].y - self.P[0].y) - \
            (self.P[2].y - self.P[0].y) * (self.P[1].x - self.P[0].x)
        if nDeltz > 0:
            self.nIndex = 0
            self.EdgeFlag(self.P[0], self.P[1], Triangle.LEFT)
            self.EdgeFlag(self.P[1], self.P[2], Triangle.LEFT)
            self.nIndex = 0
            self.EdgeFlag(self.P[0], self.P[2], Triangle.RIGHT)
        else:
            self.nIndex = 0
            self.EdgeFlag(self.P[0], self.P[2], Triangle.LEFT)
            self.nIndex = 0
            self.EdgeFlag(self.P[0], self.P[1], Triangle.RIGHT)
            self.EdgeFlag(self.P[1], self.P[2], Triangle.RIGHT)
        for y in range(self.P[0].y, self.P[2].y):
            n = y - self.P[0].y
            for x in range(self.SpanLeft[n].x, self.SpanRight[n].x):
                color = Color([1.0, 0.0, 0.0])
                pixels[x, y] = color


pixels.fill(Color([1.0, 1.0, 1.0]))
P = Point.field(shape=(3))
P[0] = Point([-300, -300]) + center
P[1] = Point([100, 300]) + center
P[2] = Point([200, -100]) + center
triangle = Triangle(P)
triangle.Fill()
gui = ti.GUI("09", (width, height))
while gui.running:
    gui.set_image(pixels)
    gui.show()

代码1是三角形插值着色,代码2是三角形填充一个颜色。

顺便问问,单一个ti.struct,怎么new出来?
我只会 ti.Struct.field,然后每个属性赋值。 :smiling_face_with_tear:

  1. 我这边复现了元素无法交换的问题,感觉是因为shallow copy;struct field暂时没有比较优雅的方法,这个我提了一个issue

  2. new一个ti.struct可以考虑像下面这样的方式?

pt = Point2({'x':1, 'y':2, 'c':Color([1.0, 0.0, 0.0])})
1 个赞