Generating Topo Map from Object
On 10/08/2017 at 12:55, xxxxxxxx wrote:
This is driving me crazy...
I have an object with a few vertices and try to create a topo map from it (an image with color based on the Y value).
Here's the script I use:
import c4d def main() : doc = c4d.documents.GetActiveDocument() png = c4d.bitmaps.BaseBitmap() png.Init(257, 257) obj = doc.GetFirstObject() for i,pt in enumerate(obj.GetAllPoints()) : mx = 128 + int(pt.x) my = 128 - int(pt.z) col = 128 + pt.y png.SetPixel(mx, my, col, col, col) png.Save("e: est.png", c4d.FILTER_PNG) if __name__=='__main__': main()
The resulting PNG should look like a checker board, however, it absolutely doesn't:
I'm doing something really really wrong, but I have no clue what it could be...
Here's the C4D file I use: http://35.io/media/test.c4d
On 10/08/2017 at 15:03, xxxxxxxx wrote:
I can't see any bug or any unexcepted event. You mesh is not evently distrubuted. By that I mean each raw are not valid int so basicly you round it (so it's why some pixel are never printed).
Another solution for you would be to use https://developers.maxon.net/docs/Cinema4DPythonSDK/html/modules/c4d.utils/GeRayCollider/index.html#c4d.utils.GeRayCollider and create an even spaced grid and not use actual geometry.
So it will end with something like this
import c4d def get_height(ray, x, y, height=10000) : start_pos = c4d.Vector(x, height, y) ray_dir = c4d.Vector(0, -1, 0) ray_lenght = height*2 if ray.Intersect(start_pos, ray_dir, ray_lenght) : intersection = ray.GetNearestIntersection() hit_pos = intersection["hitpos"] return hit_pos.y return 0 def optimize(obj, tolerance) : doc = c4d.documents.GetActiveDocument() doc.AddUndo(c4d.UNDOTYPE_CHANGE, obj) settings = c4d.BaseContainer() settings[c4d.MDATA_OPTIMIZE_TOLERANCE] = tolerance settings[c4d.MDATA_OPTIMIZE_POINTS] = True settings[c4d.MDATA_OPTIMIZE_POLYGONS] = True settings[c4d.MDATA_OPTIMIZE_UNUSEDPOINTS] = True c4d.utils.SendModelingCommand(command=c4d.MCOMMAND_OPTIMIZE, list=[obj], mode=c4d.MODELINGCOMMANDMODE_ALL, bc=settings, doc=doc) def main() : doc = c4d.documents.GetActiveDocument() obj = doc.GetFirstObject() optimize(obj, 0.001) ray = c4d.utils.GeRayCollider() ray.Init(obj) bmp = c4d.bitmaps.BaseBitmap() bmp.Init(256, 256) bounding_box_y = obj.GetRad().y for x in range(-128, 128) : for y in range(-128, 128) : h = get_height(ray, x, y) mx = 128 + int(x) my = 255 - (128 + int(y)) normalized_height = c4d.utils.Smoothstep(-bounding_box_y, bounding_box_y, h) heigt_color = normalized_height * 255 bmp.SetPixel(mx, my, heigt_color, heigt_color, heigt_color) c4d.bitmaps.ShowBitmap(bmp) if __name__=='__main__': main()
Btw I this example I assume, the obj is in the default c4d orientation and his pivot is centered in the object.
On 11/08/2017 at 02:48, xxxxxxxx wrote:
Thx for the input. I was looking at GeRayCollider, but was afraid that the performance of calculating all those intersections is waaay lower than just getting the Z values of "known" points. The grid should be perfectly distributed, i.e. if I look at the X/Z coordinates of the mesh, they are all on pure integers (0, 1, ...., 256) for both axes... that's why I'm confused by getting these rounding artifacts.
I'll do the ray thing to see what happens performance wise.
On 11/08/2017 at 05:19, xxxxxxxx wrote:
I guess you will understand in a second with this picture why I said your mesh is not a trully even spaced grid.
About performence Ray are pretty fast, just make sure to init the ray object before the loop and not inside the loop.
On 11/08/2017 at 13:06, xxxxxxxx wrote:
I guess our view on what "evenly spaced" means is different :). What I mean is that the coordinates of the points are perfectly aligned to 256, 254, 252, ... 0, ... -2, ... -256 (X and Y). There are "two grids", the outer on all even integers and the inner on all odd integers. Theoretically, this should lead to a perfect checker board pattern in the depth map (with every other pixel not set), but it doesn't. I don't understand where the rounding errors come from...
On 14/08/2017 at 09:17, xxxxxxxx wrote:
It's of course a bit hard to tell without knowing your scene. But for example keep in mind int() will always truncate the decimals, so for example int(0.99999999) will result in zero. So maybe you want to try proper rounding first to see if it changes anything.