Your browser does not seem to support JavaScript. As a result, your viewing experience will be diminished, and you have been placed in read-only mode.
Please download a browser that supports JavaScript, or enable it if it's disabled (i.e. NoScript).
On 08/03/2013 at 06:17, xxxxxxxx wrote:
Hi all,
I have a little problem.
I've a big amount of objects. Each object is modified with the following instructions: Select all points and optimize Select all polygons, untriangulate and generate N-Gons. The result are many objects. But not always the normals point to outside.
So: I'm looking for an Idea how to select these objects where the normals point to inside of the object.
Does anybody have an idea how to solve the problem??
Thanks a lot
On 08/03/2013 at 06:48, xxxxxxxx wrote:
it depends. you have only quite limited access to the polygon normals in python. in pseudocoode:
if ((obj_world_coords + point[n] + normal_point[n]).GetLength() > (obj_world_coords + point[n] ).GetLength()) : #positive else : #negative
you can get the normals with PolygonObject.CreatePhongNormals or you can calculate the normals for yourself for a polygon, but when the normals are being flipped due to some modeling operations the results returned won't be the same as in the editor, so a phong tag is the best way, if you can create one or there is already one.
for ply in polygonObject.GetAllPolygons() : a, b, c = polygonObject.GetPoint(ply.a), polygonObject.GetPoint(ply.b), polygonObject.GetPoint(ply.c) normal = ((a - b) % (b - c)).GetNormalized()
On 10/03/2013 at 03:09, xxxxxxxx wrote:
Hi Ronald,
I've been thinking about this yesterday and came up with an algorithm that seems to be consistent with non-overlapping (meaning no self-intersections!) and closed meshes.
The c4dtools package now includes this algorithm since version 1.2.5 in the c4dtools.misc.normalalign module. The source-code can be found here.
The idea is to shoot rays from three different positions in the world into the polygon-object for each polygon and test the angle between the polygon-normal and the ray. When the face is "on the opposite side" of the object, therefore the polygon's normal is intended to backface the camera, this is figured out by how many intersections have occure before the ray hit the polygon that is currently being tested.
The ray's must be shot from three different positions since otherwise we would not be able to tell if a polygon's normal points into the right direction when it's surface normal is exactly orthogonal to the ray shot in.
Here's an excerpt from the code:
def test_object_normals(op, info=None, logger=None) : r""" Tests the polygon-object *op*'s normals if they're pointing to the in or outside of the object. Returns a list of boolean variables where each index defines wether the associated polygon's normal is pointing into the right direction or not. The algorithm works best on completely closed shapes with one segment only. The polygon-object should also be valid, therefore not more than two polygons per edge, etc. The results might be incorrect with an invalid mesh structure. :param op: A :class:`c4d.PolygonObject` instance to test. :param info: A :class:`~c4dtools.utils.PolygonObjectInfo` instance for the passed object, or None to generate on demand. :return: :class:`list` of `bool` and the PolygonObjectInfo instance. """ if not info: info = PolygonObjectInfo() info.init(op) if info.polycount <= 0: return [] collider = GeRayCollider() if not collider.Init(op) : raise RuntimeError('GeRayCollider could not be initialized.') mg = op.GetMg() mp = op.GetMp() size = op.GetRad() # Define three camera position for the object. We could simply use # one if there wouldn't be the special case where a polygon's normal # is exactly in an angle of 90°, where we can not define wether the # normal is correctly aligned or not. maxp = mp + size + c4d.Vector(size.GetLength() * 2) cam1 = c4d.Vector(maxp.x, 0, 0) cam2 = c4d.Vector(0, maxp.y, 0) cam3 = c4d.Vector(0, 0, maxp.z) # Check each polygon from each camera position for the angle between # them. If one of the angles is greater than 90°, the face is pointing # into the wrong direction. result = [] iterator = enumerate(zip(info.normals, info.midpoints)) for index, (normal, midpoint) in iterator: normal_aligned = False for cam in [cam1, cam2, cam3]: # Compute the direction vector from the cam to the midpoint # of the polygon and the ray length to garuantee a hit with # the polygon. direction = (midpoint - cam) length = direction.GetLengthSquared() direction.Normalize() # Compute the intersections point from the cam to the midpoint # of the polygon. collider.Intersect(cam, direction, length) intersections = {} for i in xrange(collider.GetIntersectionCount()) : isect = collider.GetIntersection(i) # The GeRayCollider class may yield doubled intersections, # we filter them out this way. if isect['face_id'] not in intersections: intersections[isect['face_id']] = isect # Sort the intersections by distance to the cam. intersections = sorted( intersections.values(), key=lambda x: x['distance']) # Find the intersection with the current polygon and how # many polygons have been intersected before this polygon # was intersection. isect_index = -1 isect = None for i, isect in enumerate(intersections) : if isect['face_id'] == index: isect_index = i break # We actually *have* to find an intersection, it would be # a strange error if we wouldn't have found one. if isect_index < 0: if logger: message = "No intersection with face %d from cam %s" logger.warning(message % (index, cam)) continue angle = VectorAngle(normal, direction * -1) # If there has been one intersection with another face before # the intersection with the current polygon, the polygon is # assumed to be intended to face away from the camera. Same for # all other odd numbers of intersection that have occured # before the intersection with the current face. if isect_index % 2: angle = (math.pi / 2) - angle if not xor(isect['backface'], isect_index % 2) : normal_aligned = True result.append(normal_aligned) return result, info
Note : Requires utf-8 encoding when used, since the comments contain the non-ascii character ° .
-Niklas