我在python中有一個簡單的raytracer。渲染圖像200x200需要4分鐘,這對我來說絕對是太多了。我想改善這種情況。一些要點:我每個像素拍攝多條光線(提供抗鋸齒),每個像素總共有16條光線。 200x200x16是總共640000射線。必須測試每條射線對場景中多個球體對象的影響。雷也是一個相當瑣碎對象提高光線跟蹤命中功能的性能
class Ray(object):
def __init__(self, origin, direction):
self.origin = numpy.array(origin)
self.direction = numpy.array(direction)
球稍微複雜一些,而且攜帶命中/ nohit邏輯:
class Sphere(object):
def __init__(self, center, radius, color):
self.center = numpy.array(center)
self.radius = numpy.array(radius)
self.color = color
@profile
def hit(self, ray):
temp = ray.origin - self.center
a = numpy.dot(ray.direction, ray.direction)
b = 2.0 * numpy.dot(temp, ray.direction)
c = numpy.dot(temp, temp) - self.radius * self.radius
disc = b * b - 4.0 * a * c
if (disc < 0.0):
return None
else:
e = math.sqrt(disc)
denom = 2.0 * a
t = (-b - e)/denom
if (t > 1.0e-7):
normal = (temp + t * ray.direction)/self.radius
hit_point = ray.origin + t * ray.direction
return ShadeRecord.ShadeRecord(normal=normal,
hit_point=hit_point,
parameter=t,
color=self.color)
t = (-b + e)/denom
if (t > 1.0e-7):
normal = (temp + t * ray.direction)/self.radius hit_point = ray.origin + t * ray.direction
return ShadeRecord.ShadeRecord(normal=normal,
hit_point=hit_point,
parameter=t,
color=self.color)
return None
現在,我進行了一些分析,並且看起來最長處理時間在命中()功能
ncalls tottime percall cumtime percall filename:lineno(function)
2560000 118.831 0.000 152.701 0.000 raytrace/objects/Sphere.py:12(hit)
1960020 42.989 0.000 42.989 0.000 {numpy.core.multiarray.array}
1 34.566 34.566 285.829 285.829 raytrace/World.py:25(render)
7680000 33.796 0.000 33.796 0.000 {numpy.core._dotblas.dot}
2560000 11.124 0.000 163.825 0.000 raytrace/World.py:63(f)
640000 10.132 0.000 189.411 0.000 raytrace/World.py:62(hit_bare_bones_object)
640023 6.556 0.000 170.388 0.000 {map}
這並不讓我感到意外,我想盡可能減少這個值。我通過排隊分析,其結果是
Line # Hits Time Per Hit % Time Line Contents
==============================================================
12 @profile
13 def hit(self, ray):
14 2560000 27956358 10.9 19.2 temp = ray.origin - self.center
15 2560000 17944912 7.0 12.3 a = numpy.dot(ray.direction, ray.direction)
16 2560000 24132737 9.4 16.5 b = 2.0 * numpy.dot(temp, ray.direction)
17 2560000 37113811 14.5 25.4 c = numpy.dot(temp, temp) - self.radius * self.radius
18 2560000 20808930 8.1 14.3 disc = b * b - 4.0 * a * c
19
20 2560000 10963318 4.3 7.5 if (disc < 0.0):
21 2539908 5403624 2.1 3.7 return None
22 else:
23 20092 75076 3.7 0.1 e = math.sqrt(disc)
24 20092 104950 5.2 0.1 denom = 2.0 * a
25 20092 115956 5.8 0.1 t = (-b - e)/denom
26 20092 83382 4.2 0.1 if (t > 1.0e-7):
27 20092 525272 26.1 0.4 normal = (temp + t * ray.direction)/self.radius
28 20092 333879 16.6 0.2 hit_point = ray.origin + t * ray.direction
29 20092 299494 14.9 0.2 return ShadeRecord.ShadeRecord(normal=normal, hit_point=hit_point, parameter=t, color=self.color)
所以,似乎大多數時間都在此塊的代碼是花:
temp = ray.origin - self.center
a = numpy.dot(ray.direction, ray.direction)
b = 2.0 * numpy.dot(temp, ray.direction)
c = numpy.dot(temp, temp) - self.radius * self.radius
disc = b * b - 4.0 * a * c
在哪裏我實在不明白了很多進行優化。你有沒有想法如何使這個代碼更高性能,而不去C?
+1非常好。我不知道Python,所以作爲一個問題:numpy.dot調用C實現?如果不是,也許你可以通過執行手動點積計算來提高速度。 – Phrogz
是的,n是在C中實現的。這就是爲什麼我有這樣的感覺,重新實現C中的點擊函數並沒有太大的收穫。 –
是你的方向向量單位向量?你可以使它們成爲'__init__'中的單位向量嗎?如果是這樣,你的點積算術變得更簡單。 – underrun