Ridley5 opened this issue on Jul 26, 2010 · 1724 posts
bagginsbill posted Tue, 10 August 2010 at 8:18 PM
Quote - > Quote - A classic way to calculate normals as Poser4 does, there are other ways to do it with different visual results.
The code is in C ( I use Begin for { and End for }).
I don't see any problem with speed for this, the only part that is worth to optimize is NormalizeVector that requires division and square root that is slow. I can be done in Assembler with SSE and it will be very fast..Yep, that's almost precisely how I'm doing it, just vectorized via Numeric. Except that you're using a trick to save a few subtractions when computing the face normals that I had forgotten about.
Look:
def compute_normals(self):<br></br> verts = self.verts<br></br> polys = self.geom.Polygons()<br></br> sets = self.geom.Sets()<br></br><br></br> normals = num.zeros([self.nr_verts, 3], "double")<br></br><br></br> for i, p in enumerate(polys):<br></br> nv = p.NumVertices()<br></br> start = p.Start()<br></br><br></br> indices = sets[start : start + nv]<br></br><br></br> points = num.take(verts, indices)<br></br> s = points - num.take(verts, rotate_rows(indices, 1))<br></br> t = rotate_rows(s, -1)<br></br> n = rotate_rows(num.sum(s * rotate_columns(t, -1)<br></br> - t * rotate_columns(s, -1)), -1)<br></br> n = n / num.sqrt(num.dot(n, n))<br></br><br></br> for v in indices:<br></br> normals[v] += n<br></br><br></br> self.normals = normalize_rows(normals)<br></br>
:laugh:
Slick. I figured the numeric library would make this fast and easy.
You may be reaching a point where the C calls you're making are a tiny fraction of the time and it takes a while just to find them.
By that I mean, for example, on each iteration of the loop, you're doing:
lookup "num" in globals 4 times
lookup (in num) "take" 2 times
lookup (in num) "sum"
lookup (in num) "dot"
lookup (in num) "sqrt"
lookup rotate_rows in globals 3 times
lookup rotate_columns in globals 2 times
That's 14 object lookups on each iteration. All of them are constants - they don't change.
So you can probably get another speedup by factoring those out before the loop into locals.
l_take = num.take
l_sum = num.sum
l_rotate_rows = rotate_rows
etc. and then just use them instead of doing all those lookups thousands and thousands of times.
Nice work.
Renderosity forum reply notifications are wonky. If I read a follow-up in a thread, but I don't myself reply, then notifications no longer happen AT ALL on that thread. So if I seem to be ignoring a question, that's why. (Updated September 23, 2019)