First I will consider here:
Note that the tolerance here has to be related to a 0 to 1 factor and I just give a 0.03 out of the blue. this can be computed in relation to distance and a radius if u need more precision.
The steps are:
- for each object
- create a list of points, mesh points or by subdividing curves
- test if the point is inside rendered area, by screen factor 0 to 1
- create 0 if off screen or LOD (1, 2, 3 ...)
- produce a list of integers that store the state of each object
Key moments:
- for splines use mathutils.geometry.interpolate_bezier to subdivide it
(we use points, so we need segments to be little here)
- for on screen use bpy_extras.object_utils.world_to_camera_view that gives a factor related to screen (0-1 for on screen, rest is off)
The code example would then be something like this:
# check if mesh or spline points are in view, (o.g. variant 1, 2016)
from mathutils.geometry import interpolate_bezier
from bpy_extras.object_utils import world_to_camera_view
def pointsOfMesh_or_subdivideSpline(object):
points = []
if getattr(object, 'type', '') == 'MESH':
points = [v.co for v in object.data.vertices]
elif getattr(object, 'type', '') == "CURVE":
splines = object.data.splines
for spline in splines:
if getattr(spline, 'type', '') == 'BEZIER':
resolution = spline.resolution_u + 1
last = 0 if spline.use_cyclic_u else 1
lenP = len(spline.bezier_points)
for i, p1 in enumerate(spline.bezier_points):
if i < lenP - last:
p2 = spline.bezier_points[(i + 1) % lenP]
knot1 = p1.co
handle1 = p1.handle_right
handle2 = p2.handle_left
knot2 = p2.co
_points = interpolate_bezier(knot1, handle1, handle2, knot2, resolution)
points.extend(_points)
return points
def testInView(coord, tolerance):
pointInView = False
z = -1
if scene is not None and camera is not None and coord is not None:
xFactor, yFactor, z = world_to_camera_view(scene, camera, coord)
# add this if you use ortho !!!:
#if camera.data.type != "PERSPECTIVE":
# sx, sy = camera.data.shift_x, camera.data.shift_y
# xFactor, yFactor = xFactor - 2 * sx, yFactor - 2 * sy
# !! tolerance can be computed with above z and radius or so
if -tolerance < xFactor < 1 + tolerance and -tolerance < yFactor < 1 + tolerance and z > 0:
pointInView = True
return pointInView, z
objectsInViewList = []
LOD2limit = max(LOD2limit, LOD3limit) #clamp lod 2 to lod 3
# mesh points or spline subdivision points with a tolerance
for object in ObjectList:
if object is None or getattr(object, 'type', '') not in ['MESH', 'CURVE']:
objectsInViewList.append(0)
else:
matrix = object.matrix_world
zlist = []
# see if any point is in view
points = pointsOfMesh_or_subdivideSpline(object)
for point in points:
pointInView, z = testInView(matrix * point, tolerance)
if pointInView: zlist.append(z)
# these LODs are just an example
if zlist == []: LOD = 0
elif min(zlist) < LOD3limit: LOD = 3
elif LOD3limit <= min(zlist) < LOD2limit: LOD = 2
else: LOD = 1
objectsInViewList.append(LOD)
so you get a list of 0 (hide) or LOD for each object in list
Again, note that tolerance is related to screen factor, so I just use a 0.03 here, but you can further calculate it related to z
Testing, just to see
All inputs there, I assume you have defined somehow.
(I intentionally use None and lamp to see..)
Compare the result 0,1,2, list with the obvious state of objects
Note that bezier 001 is slightly off screen, but I still get a 1, cause of the tolerance.
Note that I use Animation Nodes/ script node for convenience here, skips a lot of formalities, registering etc and I can use bogus obj list etc, plus it updates real time.
However, just to illustrate how the code works