两种方法都无法交换,最后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
有比较优雅的方式吗?
两种方法都无法交换,最后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是怎么定义的吗?
代码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,然后每个属性赋值。
我这边复现了元素无法交换的问题,感觉是因为shallow copy;struct field暂时没有比较优雅的方法,这个我提了一个issue
new一个ti.struct可以考虑像下面这样的方式?
pt = Point2({'x':1, 'y':2, 'c':Color([1.0, 0.0, 0.0])})