def autoCrop(dummy): margin = bpy.context.scene.automatic_render_border_margin sc = bpy.context.scene sc.render.use_border = True x, y = [], [] objetos = [bpy.context.visible_objects[:] if len( bpy.context.selected_objects) == 0 else bpy.context.selected_objects[:]] for ob in objetos[0]: if ob.type in ["MESH", "FONT", "CURVE", "META"] and ob.is_visible(sc): nmesh = ob.to_mesh(sc, True, "RENDER") for vert in nmesh.vertices: gl = ob.matrix_world * vert.co cc = world_to_camera_view(sc, sc.camera, gl) x.append(cc[0]) y.append(cc[1]) bpy.data.meshes.remove(nmesh) if ob.dupli_type == "GROUP" and ob.type == "EMPTY": for iob in ob.dupli_group.objects: if iob.type == "MESH" and ob.is_visible(sc): nmesh = iob.to_mesh(sc, True, "RENDER") for vert in nmesh.vertices: gl = ob.matrix_world * iob.matrix_world * vert.co cc = world_to_camera_view(sc, sc.camera, gl) x.append(cc[0]) y.append(cc[1]) bpy.data.meshes.remove(nmesh) x.sort() y.sort() sc.render.border_min_x = x[0] - margin sc.render.border_max_x = x[-1] + margin sc.render.border_min_y = y[0] - margin sc.render.border_max_y = y[-1] + margin del x del y
def coords_within_image(self, coords): scene = bpy.context.scene scene.update() cs, ce = self.camera.data.clip_start, self.camera.data.clip_end object_names = [obj.name for obj in list(bpy.data.objects)] random_objects = [] image_coords = [] for name in object_names: if 'random' == name[:6]: obj = bpy.data.objects[name] mat_world = obj.matrix_world verts = (mat_world * vert.co for vert in obj.data.vertices) coords_2d = [ world_to_camera_view(scene, self.camera, coord) for coord in verts ] image_coords.append(coords_2d) random_objects.append(obj) def random_object_is_blocking(obj_coords, limit_coord): for co in obj_coords: if np.abs(co.x - limit_coord.x) < 0.01 and np.abs( co.y - limit_coord.y) < 0.01 and co.z < limit_coord.z: return True return False for idx, coord in enumerate(coords): coord = mathutils.Vector(coord) co_ndc = world_to_camera_view(scene, self.camera, coord) if not ((0.0 < co_ndc.x < 1.0 and 0.0 < co_ndc.y < 1.0 and cs < co_ndc.z < ce)): return False update_objects = [] update_image_coords = [] for i in range(len(image_coords)): if random_object_is_blocking(image_coords[i], co_ndc): obstacle = random_objects[i] print('POP', obstacle.name) bpy.data.objects.remove(obstacle) else: update_objects.append(random_objects[i]) update_image_coords.append(image_coords[i]) random_objects = update_objects image_coords = update_image_coords return True
def get_normal_from_points(sc, obj, p1, p2): '''Given two points, return their 2d normal vector in camera view.''' cam = sc.camera rp = sc.render.resolution_percentage / 100.0 p1_cam = world_to_camera_view(sc, cam, p1) p2_cam = world_to_camera_view(sc, cam, p2) normal = (p2_cam - p1_cam).xy normal.x *= sc.render.resolution_x * rp normal.y *= sc.render.resolution_y * rp normal = normal.normalized() return normal
def compute_camera_size(context, center, fill_mode, aspect): """Determine how large an object needs to be to fit or fill the camera's field of view.""" scene = context.scene camera = scene.camera view_frame = camera.data.view_frame(scene=scene) frame_size = \ Vector([max(v[i] for v in view_frame) for i in range(3)]) - \ Vector([min(v[i] for v in view_frame) for i in range(3)]) camera_aspect = frame_size.x / frame_size.y # Convert the frame size to the correct sizing at a given distance if camera.type == 'ORTHO': frame_size = frame_size.xy else: # Perspective transform distance = world_to_camera_view(scene, camera, center).z frame_size = distance * frame_size.xy / (-view_frame[0].z) # Determine what axis to match to the camera match_axis = 0 # match the Y axis size match_aspect = aspect if (fill_mode == 'FILL' and aspect > camera_aspect) or \ (fill_mode == 'FIT' and aspect < camera_aspect): match_axis = 1 # match the X axis size match_aspect = 1.0 / aspect # scale the other axis to the correct aspect frame_size[1 - match_axis] = frame_size[match_axis] / match_aspect return frame_size
def obj_bounding_rect(scene, cam, obj): # use generator expressions () or list comprehensions [] # Had problem with negative y-coord - added obj.matrix_world from # https://www.reddit.com/r/blender/comments/4s8k3f/help_with_finding_whether_a_vertex_is_visible/ obj_mat_world = obj.matrix_world verts = (obj_mat_world * vert.co for vert in obj.data.vertices) coords_2d = [world_to_camera_view(scene, cam, coord) for coord in verts] # 2d data printout: # rnd = lambda i: round(i) # for x, y, distance_to_lens in coords_2d: # print("{},{}".format(rnd(res_x*x), rnd(res_y*y))) x0 = coords_2d[0].x y0 = coords_2d[0].y x1 = x0 y1 = y0 # print('x,y') for x, y, distance_to_lens in coords_2d: if (x < x0): x0 = x if (y < y0): y0 = y if (x > x1): x1 = x if (y > y1): y1 = y return x0, y0, x1, y1
def find_plane_corner(object_name, x, y, axis, camera=None, *args, **kwargs): """Find the location in camera space of a plane's corner""" if args or kwargs: # I've added args / kwargs as a compatibility measure with future versions warnings.warn("Unknown Parameters Passed to \"Images as Planes\". Maybe you need to upgrade?") plane = bpy.data.objects[object_name] # Passing in camera doesn't work before 2.78, so we use the current one camera = camera or bpy.context.scene.camera # Hack to ensure compositor updates on future changes register_watched_object(camera) register_watched_object(plane) scale = plane.scale * 2.0 v = plane.dimensions.copy() v.x *= x / scale.x v.y *= y / scale.y v = plane.matrix_world @ v camera_vertex = world_to_camera_view( bpy.context.scene, camera, v) return camera_vertex[axis]
def project_keypoints_onto_image(keypoints, scene, obj, camera): """Converts 3D keypoints of an object into their corresponding 2D coordinates on the image. This function takes a list of keypoints represented as 3D coordinates in object space, and then projects them onto the camera to get their corresponding 2D coordinates on the image. It uses the current location and orientation of the input Blender objects. Typical usage would be to call this function after `Frame.setup <starfish.Frame.setup>` and then store the 2D locations as metadata for that frame:: frame.setup(scene, obj, camera, sun) frame.keypoints = project_keypoints_onto_image(keypoints, scene, obj, camera) with open('meta...', 'w') as f: f.write(frame.dumps()) :param keypoints: a list of 3D coordinates corresponding to the locations of the keypoints in the object space, e.g. the output of `generate_keypoints <starfish.annotation.generate_keypoints>` :param scene: (BlendDataObject): the scene to use for aspect ratio calculations. Note that this should be the scene that you intend to perform the final render in, not necessarily the one that your objects exist in. If you render in a scene that has an output resolution with a different aspect ratio than the output resolution of this scene, then the results may be incorrect. :param obj: (BlendDataObject): the object to use :param camera: (BlendDataObject): the camera to use :return: a list of (y, x) coordinates in the same order as ``keypoints`` where (0, 0) is the top left corner of the image and (1, 1) is the bottom right """ from bpy_extras.object_utils import world_to_camera_view results = [] for keypoint in keypoints: camera_coord = world_to_camera_view( scene, camera, obj.matrix_world @ Vector(keypoint)) results.append((1 - camera_coord.y, camera_coord.x)) return results
def visible_face_from_vertex( vertex: bpy.types.MeshVertex, scene: bpy.types.Scene, mesh_object: bpy.types.Object) -> bpy.types.MeshPolygon: """Convert the vertex's coordinates into camera space, and check whether its coordinates are within the frustum. Then cast a ray at it to see whether it's occluded.""" cam = scene.camera cc = world_to_camera_view(scene, cam, mesh_object.matrix_world @ vertex.co) cs = cam.data.clip_start ce = cam.data.clip_end # If the vertex's screen coordinates are within camera view if 0.0 < cc.x < 1.0 and 0.0 < cc.y < 1.0 and cs < cc.z < ce: # Convert the screen coordinates to a 3D vector frame = cam.data.view_frame(scene=scene) top_left = frame[3] pixel_vector = Vector((cc.x, cc.y, top_left[2])) pixel_vector.rotate(cam.matrix_world.to_quaternion()) # Convert to target object space wmatrix_inv = mesh_object.matrix_world.inverted() origin = wmatrix_inv @ (pixel_vector + cam.matrix_world.translation) # Destination is the original vertex, in the same object space destination = wmatrix_inv @ vertex.co direction = (destination - origin).normalized() # Cast a ray from those screen coordinates to the vertex result, location, normal, index = mesh_object.ray_cast( origin, direction) if result and index > -1: # Return the face the vertex belongs to return mesh_object.data.polygons[index] return False
def make_flattened(bm_output, flattened_name): #remap to flat plane for oscistudio to see global cam global vamp_scale res_y = bpy.context.scene.render.resolution_y res_x = bpy.context.scene.render.resolution_x cam_x_scale = res_x / 500 cam_y_scale = res_y / 500 vamp_scale = bpy.context.scene.vamp_params.vamp_scale # determine location based on xy cam scale flat_loc = Vector( (-0.5 * cam_x_scale * vamp_scale, -0.5 * cam_y_scale * vamp_scale, 0)) # first, make flatSliced flat_sliced = bpy.data.objects[flattened_name] mat_world = flat_sliced.matrix_world # use bm_output, remap vertices FlatVerts = [] for v in bm_output.verts: co_ndc = world_to_camera_view(scene, cam, v.co) v.co.x = co_ndc[0] * cam_x_scale * vamp_scale v.co.y = co_ndc[1] * cam_y_scale * vamp_scale v.co.z = 0 bm_output.to_mesh(flat_sliced.data) flat_sliced.location = flat_loc layer = bpy.context.view_layer layer.update() return {'FINISHED'}
def DefRenderOnlyInCamera(): # crea grupos if "INCAMERA" not in bpy.data.groups: bpy.data.groups.new("INCAMERA") if "NOTINCAMERA" not in bpy.data.groups: bpy.data.groups.new("NOTINCAMERA") # limpio grupos for ob in bpy.data.objects: if ob.name in bpy.data.groups["INCAMERA"].objects: bpy.data.groups["INCAMERA"].objects.unlink(ob) if ob.name in bpy.data.groups["NOTINCAMERA"].objects: bpy.data.groups["NOTINCAMERA"].objects.unlink(ob) # ordeno grupos for ob in bpy.data.objects: obs = False if ob.type == "MESH": tm = ob.to_mesh(bpy.context.scene, True, "RENDER") for vert in tm.vertices: cam = world_to_camera_view( bpy.context.scene, bpy.context.scene.camera, vert.co + ob.location) if cam[0] >= -0 and cam[0] <= 1 and cam[1] >= 0 and cam[1] <= 1: obs = True del(tm) else: obs = True if obs: bpy.data.groups["INCAMERA"].objects.link(ob) else: bpy.data.groups["NOTINCAMERA"].objects.link(ob)
def getVisibleVertices(obj, cam, scene): # In world coordinates, get a bvh tree and vertices bvh, vertices = BVHTreeAndVerticesInWorldFromObj(obj) visible_vertices = [] for i, v in enumerate(vertices): #print("vertex #") #print(i) # Get the 2D projection of the vertex co2D = world_to_camera_view(scene, cam, v) #print(co2D) #print("\n") # By default, deselect it obj.data.vertices[i].select = False # If inside the camera view if 0.0 <= co2D.x <= 1.0 and 0.0 <= co2D.y <= 1.0: #print(i,"this vertex is inside camera view") # Try a ray cast, in order to test the vertex visibility from the camera location, normal, index, distance = bvh.ray_cast( cam.location, (v - cam.location).normalized()) #print("cam.location, (v - cam.location).normalized() , location, normal, index, distance") #print(cam.location, (v - cam.location).normalized() , location, normal, index, distance) # If the ray hits something and if this hit is close to the vertex, we assume this is the vertex if location and (v - location).length < limit: obj.data.vertices[i].select = True #print("selected vertex is:", i) #print(getCoords(obj.data.vertices[i])) visible_vertices.append([v.x, v.y, v.z]) #print("\n\n") print("#verts:", NUMVERTS, " #visible vertices:", len(visible_vertices)) del bvh print("visible vertices:", visible_vertices) return visible_vertices
def get_render_location(self, context, coord): scene = context.scene co_2d = object_utils.world_to_camera_view(scene, scene.camera, coord) # Get pixel coords render_scale = scene.render.resolution_percentage / 100 render_size = (int(scene.render.resolution_x * render_scale), int(scene.render.resolution_y * render_scale)) return [round(co_2d.x * render_size[0]), round(co_2d.y * render_size[1])]
def get_z(shape): global z_map global scene z = z_map.get(shape.id.first) if z == None: o = bpy.data.objects[shape.name] z = world_to_camera_view(scene, scene.camera, o.location)[2] z_map[shape.id.first] = z return z
def get_z_curve(self, curve, func=GetShapeF1D()): shape = func(curve)[0] # get the shapes z-index z = self.z_map.get(shape.id.first) if z is None: o = bpy.data.objects[shape.name] z = world_to_camera_view(self.scene, self.scene.camera, o.location).z self.z_map[shape.id.first] = z return z
def get_render_location(mypoint): v1 = mathutils.Vector(mypoint) scene = bpy.context.scene co_2d = object_utils.world_to_camera_view(scene, scene.camera, v1) # Get pixel coords render_scale = scene.render.resolution_percentage / 100 render_size = (int(scene.render.resolution_x * render_scale), int(scene.render.resolution_y * render_scale)) return [round(co_2d.x * render_size[0]), round(co_2d.y * render_size[1])]
def helper_getBB2D(scene, cam, obj): bb3d = obj.bound_box bb3d_list = [mathutils.Vector(p) for p in bb3d] coords_2d = [ object_utils.world_to_camera_view(scene, cam, obj.matrix_world @ p) for p in bb3d_list ] xx = [p.x for p in coords_2d] yy = [p.y for p in coords_2d] return (min(xx), min(yy), max(xx), max(yy))
def coordinate_within_image(coord): coord = mathutils.Vector(coord) scene = bpy.context.scene cam = bpy.data.objects['Camera'] cs, ce = cam.data.clip_start, cam.data.clip_end co_ndc = world_to_camera_view(scene, cam, coord) within_image = False if (0.0 < co_ndc.x < 1.0 and 0.0 < co_ndc.y < 1.0): within_image = True return within_image
def helper_mkJsonBB2D(scene, cam, obj): bb3d = obj.objectPtr.bound_box bb3d_list = [mathutils.Vector(p) for p in bb3d] coords_2d = [ object_utils.world_to_camera_view(scene, cam, obj.objectPtr.matrix_world @ p) for p in bb3d_list ] xx = [p.x for p in coords_2d] yy = [p.y for p in coords_2d] jsonData = {"x1": min(xx), "y1": min(yy), "x2": max(xx), "y2": max(yy)} return jsonData
def animate_render_border(scene): scene = bpy.context.scene camera = scene.camera border = scene.animated_render_border if border.enable and camera.type == "CAMERA": #If object is chosen but consequently renamed, it can't be tracked. if border.type == "Object" and border.object != "" and border.object in bpy.data.objects or \ border.type == "Group" and border.group != "" and border.group in bpy.data.groups: objs = [] if border.type == "Object": objs = [border.object] elif border.type == "Group": objs = (object.name for object in bpy.data.groups[border.group].objects if object.type =="MESH") coords_2d = [] for obj in objs: verts = [] if border.use_bounding_box: verts = (Vector(corner) for corner in bpy.data.objects[obj].bound_box) else: verts = (vert.co for vert in bpy.data.objects[obj].data.vertices) wm = bpy.data.objects[obj].matrix_world #Vertices will be in local space unless multiplied by the world matrix for coord in verts: coords_2d.append(world_to_camera_view(scene, camera, wm*coord)) minX = 1 maxX = 0 minY = 1 maxY = 0 for x, y, distance_to_lens in coords_2d: if x<minX: minX = x if x>maxX: maxX = x if y<minY: minY = y if y>maxY: maxY = y margin = border.margin scene.render.border_min_x = minX - (margin/100) scene.render.border_max_x = maxX + (margin/100) scene.render.border_min_y = minY - (margin/100) scene.render.border_max_y = maxY + (margin/100)
def location_in_camera_view(camera, location): scene = bpy.context.scene cs, ce = camera.data.clip_start, camera.data.clip_end in_view = False co_ndc = world_to_camera_view(scene, camera, location) in_view = (0.0 < co_ndc.x < 1.0 and 0.0 < co_ndc.y < 1.0 and cs < co_ndc.z < ce) #print("Center view: " + str(in_view) + " with loc: " + str(obj.location) + " and camera rel position: " + str(Vector((co_ndc.x, co_ndc.y, co_ndc.z)))) return in_view
def depth_to_camera(obj, camera): dg = bpy.context.evaluated_depsgraph_get() lq = obj.evaluated_get(dg) ng = bpy.context.evaluated_depsgraph_get() cq = camera.evaluated_get(ng) mat = lq.matrix_world min_z = 1000 max_z = -1 for v in lq.data.vertices: co_ndc = world_to_camera_view(bpy.context.scene, cq, mat @ v.co) max_z = max(max_z, co_ndc.z) min_z = min(min_z, co_ndc.z) return min_z, max_z
def export(context): '''Create export data and write to file.''' sc = context.scene cam = sc.camera hqz_params = context.scene.hqz_parameters rp = sc.render.resolution_percentage / 100.0 if hqz_params.animation: start_frame = sc.frame_start frame_range = range(sc.frame_start, sc.frame_end + 1) else: start_frame = sc.frame_current frame_range = (start_frame,) if hqz_params.batch: write_batch_script(hqz_params, frame_range) for frame in frame_range: print('Exporting frame', frame) export_data = {} if hqz_params.animation: sc.frame_set(frame) export_data['resolution'] = [ int(sc.render.resolution_x * rp), int(sc.render.resolution_y * rp)] export_data['viewport'] = [ 0, 0, sc.render.resolution_x * rp, sc.render.resolution_y * rp] export_data['exposure'] = hqz_params.exposure export_data['gamma'] = hqz_params.gamma export_data['rays'] = hqz_params.rays if hqz_params.time != 0.0: export_data['timelimit'] = hqz_params.time export_data['seed'] = hqz_params.seed # LIGHTS export_data['lights'] = [] for lamp in sc.objects: if lamp.type == 'LAMP' and lamp.is_visible(sc): lamp_obstacle = False if not lamp_obstacle: light = [] use_spectral = lamp.data.hqz_lamp.use_spectral_light spectral_start = lamp.data.hqz_lamp.spectral_start spectral_end = lamp.data.hqz_lamp.spectral_end wav = color_to_wavelength(lamp.data.color) lamp_loc = lamp.matrix_world.to_translation() x, y, z = world_to_camera_view( sc, cam, lamp_loc) x *= sc.render.resolution_x * rp y *= sc.render.resolution_y * rp # Check that lamp is not behind camera if z > 0: y = sc.render.resolution_y * rp - y light.append(lamp.data.energy) light.append(x) light.append(y) if lamp.data.type == 'SPOT': lamp_angle = get_object_rot(sc, lamp) lamp_size = degrees(lamp.data.spot_size) / 2.0 lamp_min = (lamp_angle - lamp_size) lamp_max = (lamp_angle + lamp_size) light.append([lamp_min, lamp_max]) else: light.append([0, 360]) light_start = ( lamp.data.hqz_lamp.light_start * (sc.render.resolution_y * rp)) light_end = ( lamp.data.hqz_lamp.light_end * (sc.render.resolution_y * rp)) light.append([light_start, light_end]) if lamp.data.type == 'SPOT': light.append([lamp_min, lamp_max]) else: light.append([0, 360]) if use_spectral: light.append([spectral_start, spectral_end]) else: light.append(wav) export_data['lights'].append(light) export_data['objects'] = [] # get Blender edge list edge_list = [] for obj in sc.objects: if obj.type == 'MESH' and obj.is_visible(sc): mesh = bpy.data.meshes.new_from_object( sc, obj, apply_modifiers=True, settings='PREVIEW') for edge in mesh.edges: if edge.use_freestyle_mark: continue edgev = {} vertices = list(edge.vertices) edgev["material"] = obj.hqz_material_id v1 = obj.matrix_world * mesh.vertices[vertices[0]].co v2 = obj.matrix_world * mesh.vertices[vertices[1]].co v1_cam = world_to_camera_view( sc, cam, v1) v2_cam = world_to_camera_view( sc, cam, v2) edgev["v1"] = v1_cam edgev["v2"] = v2_cam if hqz_params.normals_export: v1_normal_offset = ( v1 + obj.matrix_world * mesh.vertices[vertices[0]].normal ) v2_normal_offset = ( v2 + obj.matrix_world * mesh.vertices[vertices[1]].normal ) n1 = get_normal_from_points(sc, obj, v1, v1_normal_offset) n1_angle = degrees(Vector((1.0, 0.0)).angle_signed(n1)) n2 = get_normal_from_points(sc, obj, v2, v2_normal_offset) n2_angle = degrees(n1.angle_signed(n2)) if hqz_params.normals_invert: n1_angle += 180 n2_angle += 180 edgev["n1"] = n1_angle edgev["n2"] = n2_angle edge_list.append(edgev) bpy.data.meshes.remove(mesh) # OBJECTS for edge in edge_list: # if check_inside( # context, # edge["v1"].x * sc.render.resolution_x * rp, # edge["v1"].y * sc.render.resolution_y * rp # ): edge_data = [] # MATERIAL edge_data.append(edge["material"]) # VERT1 XPOS edge_data.append( edge["v1"].x * sc.render.resolution_x * rp) # VERT1 YPOS edge_data.append( (1 - edge["v1"].y) * sc.render.resolution_y * rp) # VERT1 NORMAL if hqz_params.normals_export: edge_data.append(edge["n1"]) # VERT2 DELTA XPOS edge_data.append( (edge["v2"].x - edge["v1"].x) * sc.render.resolution_x * rp ) # VERT2 DELTA YPOS edge_data.append( (edge["v1"].y - edge["v2"].y) * sc.render.resolution_y * rp ) # VERT2 NORMAL if hqz_params.normals_export: edge_data.append(edge["n2"]) export_data['objects'].append(edge_data) # Materials export_data['materials'] = [] for material in hqz_params.materials: mat_data = [] mat_data.append([material.diffuse, "d"]) mat_data.append([material.transmission, "t"]) mat_data.append([material.specular, "r"]) export_data['materials'].append(mat_data) save_path = hqz_params.directory + hqz_params.file + '_' + str(frame).zfill(4) + '.json' d = os.path.dirname(save_path) os.makedirs(d, exist_ok=True) file = open(save_path, 'w') file.write(json.dumps( export_data, indent=None if hqz_params.debug else 2, sort_keys=True)) file.close()
def export(self, context): '''Create export data and write to file.''' sc = context.scene cam = sc.camera hqz_params = context.scene.hqz_parameters rp = sc.render.resolution_percentage / 100.0 if not hqz_params.hqz_bin_path: self.report({'WARNING'}, 'Please select hqz binary.') if not hqz_params.export_filepath: self.report({'ERROR'}, 'Please choose export file name.') return {'CANCELLED'} if cam is None: self.report({'ERROR'}, 'No camera found in scene.') return {'CANCELLED'} if hqz_params.animation: start_frame = sc.frame_start frame_range = range(sc.frame_start, sc.frame_end + 1) else: start_frame = sc.frame_current frame_range = (start_frame,) export_dir = os.path.dirname( bpy.path.abspath(hqz_params.export_filepath) ) os.makedirs(export_dir, exist_ok=True) if hqz_params.render_script_path: write_render_script(export_dir, hqz_params, frame_range) export_data = {} for frame in frame_range: print('Exporting frame', frame) if hqz_params.animation: sc.frame_set(frame) # SETTINGS export_data['resolution'] = [ int(sc.render.resolution_x * rp), int(sc.render.resolution_y * rp)] export_data['viewport'] = [ 0, 0, sc.render.resolution_x * rp, sc.render.resolution_y * rp] export_data['exposure'] = hqz_params.exposure export_data['gamma'] = hqz_params.gamma export_data['rays'] = hqz_params.rays if hqz_params.time != 0.0: export_data['timelimit'] = hqz_params.time export_data['seed'] = hqz_params.seed # LIGHTS export_data['lights'] = [] for lamp in sc.objects: if lamp.type == 'LAMP' and lamp.is_visible(sc): lamp_obstacle = False if not lamp_obstacle: hqz_light = [] use_spectral = lamp.data.hqz_lamp.use_spectral_light spectral_start = lamp.data.hqz_lamp.spectral_start spectral_end = lamp.data.hqz_lamp.spectral_end wav = color_to_wavelength(lamp.data.color) lamp_loc = lamp.matrix_world.to_translation() x, y, z = world_to_camera_view( sc, cam, lamp_loc) x *= sc.render.resolution_x * rp y *= sc.render.resolution_y * rp if z > 0: # Check that lamp is not behind camera y = sc.render.resolution_y * rp - y hqz_light.append(lamp.data.energy) hqz_light.append(x) hqz_light.append(y) if lamp.data.type == 'SPOT': lamp_angle = get_object_rot(sc, lamp) lamp_size = degrees(lamp.data.spot_size) / 2.0 lamp_min = (lamp_angle - lamp_size) lamp_max = (lamp_angle + lamp_size) hqz_light.append([lamp_min, lamp_max]) else: hqz_light.append([0, 360]) light_start = ( lamp.data.hqz_lamp.light_start * (sc.render.resolution_y * rp)) light_end = ( lamp.data.hqz_lamp.light_end * (sc.render.resolution_y * rp)) hqz_light.append([light_start, light_end]) if lamp.data.type == 'SPOT': hqz_light.append([lamp_min, lamp_max]) else: hqz_light.append([0, 360]) if use_spectral: hqz_light.append([spectral_start, spectral_end]) else: hqz_light.append(wav) export_data['lights'].append(hqz_light) export_data['objects'] = [] # OBJECTS for obj in sc.objects: if ( obj.type in {'MESH', 'CURVE', 'FONT', 'SURFACE'} and obj.is_visible(sc) ): mesh = bpy.data.meshes.new_from_object( sc, obj, apply_modifiers=True, settings='PREVIEW') for edge in mesh.edges: if edge.use_freestyle_mark: continue edge_data = [] vertices = list(edge.vertices) # MATERIAL edge_data.append(obj.hqz_material_id) v1 = obj.matrix_world * mesh.vertices[vertices[0]].co v2 = obj.matrix_world * mesh.vertices[vertices[1]].co v1_cam = world_to_camera_view( sc, cam, v1) v2_cam = world_to_camera_view( sc, cam, v2) # VERT1 XPOS edge_data.append( v1_cam.x * sc.render.resolution_x * rp) # VERT1 YPOS edge_data.append( (1 - v1_cam.y) * sc.render.resolution_y * rp) # VERT2 DELTA XPOS edge_data.append( (v2_cam.x - v1_cam.x) * sc.render.resolution_x * rp ) # VERT2 DELTA YPOS edge_data.append( (v1_cam.y - v2_cam.y) * sc.render.resolution_y * rp ) if hqz_params.normals_export: v1_normal_offset = ( obj.matrix_world * (mesh.vertices[vertices[0]].co + mesh.vertices[vertices[0]].normal) ) v2_normal_offset = ( obj.matrix_world * (mesh.vertices[vertices[1]].co + mesh.vertices[vertices[1]].normal) ) n1 = get_normal_from_points( sc, obj, v1, v1_normal_offset) n2 = get_normal_from_points( sc, obj, v2, v2_normal_offset) if n1.length_squared and n2.length_squared: # Do not export normals if parallel to camera axis n1_angle = degrees(Vector((1.0, 0.0)).angle_signed(n1)) n2_angle = degrees(n1.angle_signed(n2)) if hqz_params.normals_invert: n1_angle += 180 # VERT1 NORMAL edge_data.insert(3, n1_angle) # VERT2 NORMAL edge_data.append(n2_angle) export_data['objects'].append(edge_data) bpy.data.meshes.remove(mesh) # Materials export_data['materials'] = [] for material in hqz_params.materials: mat_data = [] mat_data.append([material.diffuse, "d"]) mat_data.append([material.transmission, "t"]) mat_data.append([material.specular, "r"]) export_data['materials'].append(mat_data) save_path = (hqz_params.export_filepath + '.' + str(frame).zfill(4) + '.json') d = os.path.dirname(save_path) os.makedirs(d, exist_ok=True) file = open(save_path, 'w') file.write(json.dumps( export_data, indent=None if hqz_params.debug else 2, sort_keys=True) ) file.close() return {'FINISHED'}
def animated_render_border(scene): scene = bpy.context.scene camera = scene.camera border = scene.animated_render_border cameraExists = False if camera: if camera.type == "CAMERA": cameraExists = True if border.enable and cameraExists: #If object is chosen but consequently renamed, it can't be tracked. if validObject() or validGroup(): objs = [] if border.type == "Object": objs = [bpy.data.objects[border.object]] elif border.type == "Group": objs = (object for object in bpy.data.groups[border.group].objects if object.type in trackableObjectTypes) #Type of objects that can be tracked coords_2d = [] for obj in objs: verts = [] if border.use_bounding_box or obj.type in noVertexObjectTypes: #Objects that have no vertices #Lattices and Armatures can't use bounding box in pre 2.76 version of blender. if bpy.app.version < (2, 76, 0) and obj.type in ["ARMATURE","LATTICE"]: if obj.type == "LATTICE": verts = (vert.co_deform for vert in obj.data.points) elif obj.type == "ARMATURE": if border.bone == "": verts = (chain.from_iterable((bone.head, bone.tail) for bone in obj.pose.bones)) else: bone = bpy.data.objects[border.object].pose.bones[border.bone] verts = [bone.head, bone.tail] else: verts = (Vector(corner) for corner in obj.bound_box) elif obj.type == "MESH": verts = (vert.co for vert in obj.data.vertices) elif obj.type == "CURVE": verts = (vert.co for spline in obj.data.splines for vert in spline.bezier_points) elif obj.type == "SURFACE": verts = (vert.co for spline in obj.data.splines for vert in spline.points) elif obj.type == "LATTICE": verts = (vert.co_deform for vert in obj.data.points) elif obj.type == "ARMATURE": if border.bone == "": verts = (chain.from_iterable((bone.head, bone.tail) for bone in obj.pose.bones)) else: bone = bpy.data.objects[border.object].pose.bones[border.bone] verts = [bone.head, bone.tail] wm = obj.matrix_world #Vertices will be in local space unless multiplied by the world matrix for coord in verts: coords_2d.append(world_to_camera_view(scene, camera, wm*coord)) #If a group is empty there will be no coordinates if len(coords_2d) > 0: minX = 1 maxX = 0 minY = 1 maxY = 0 for x, y, distance_to_lens in coords_2d: #Points behind camera will have negative coordinates, this makes them positive if distance_to_lens<0: y = y *-1 x = x *-1 if x<minX: minX = x if x>maxX: maxX = x if y<minY: minY = y if y>maxY: maxY = y margin = border.margin/100 #Haven't worked out why I'm multiplying 'shift_x' and 'shift_y' by 2 if scene.render.resolution_x > scene.render.resolution_y: aspectRatio = 2 * (scene.render.resolution_x / scene.render.resolution_y) * (scene.render.pixel_aspect_x / scene.render.pixel_aspect_y) cameraShiftX = scene.camera.data.shift_x * 2 cameraShiftY = scene.camera.data.shift_y * aspectRatio else: aspectRatio = 2 * (scene.render.resolution_y / scene.render.resolution_x) * (scene.render.pixel_aspect_y / scene.render.pixel_aspect_x) cameraShiftX = scene.camera.data.shift_x*aspectRatio cameraShiftY = scene.camera.data.shift_y*2 scene.render.border_min_x = (minX - margin) - cameraShiftX scene.render.border_max_x = (maxX + margin) - cameraShiftX scene.render.border_min_y = (minY - margin) - cameraShiftY scene.render.border_max_y = (maxY + margin) - cameraShiftY elif border.type == "Keyframe": scene.render.border_min_x = border.border_min_x scene.render.border_max_x = border.border_max_x scene.render.border_min_y = border.border_min_y scene.render.border_max_y = border.border_max_y