def add_house(self, house, no_walls=False, no_ceil=False, no_floor=False, use_separate_walls=False, static=False): for node in house.nodes: if not node.valid: continue if not hasattr(node, 'body'): node.body = None if node.type == 'Object': node.body = self.add_object(node, static=static) if node.type == 'Room': ceil = False if no_ceil else not (hasattr(node, 'hideCeiling') and node.hideCeiling == 1) wall = False if (no_walls or use_separate_walls) else not ( hasattr(node, 'hideWalls') and node.hideWalls == 1) floor = False if no_floor else not (hasattr(node, 'hideFloor') and node.hideFloor == 1) node.body = self.add_room(node, wall=wall, floor=floor, ceiling=ceil) if node.type == 'Box': half_widths = list(map(lambda x: 0.5 * x, node.dimensions)) node.body = self.add_box(obj_id=node.id, half_extents=half_widths, transform=Transform.from_node(node), static=static) if use_separate_walls and not no_walls: for wall in house.walls: wall['body'] = self.add_wall(wall)
def get_render_obb(self): o = Obj(self.modelId) bbox_dims = o.bbox_max - o.bbox_min model_matrix = Transform(scale=bbox_dims[:3], translation=o.bbox_min[:3]).as_mat4() full_matrix = np.matmul(np.transpose(self.get_transformation()), model_matrix) obb = OBB.from_local2world_transform(full_matrix) obb_tris = np.asarray(obb.get_triangles(), dtype=np.float32) rendered_obb = torch.from_numpy( TopDownView.render_object_full_size_helper(obb_tris, self.room.size)) return rendered_obb
def add_wall(self, node): h = node['height'] p0 = np.transpose(np.matrix(node['points'][0])) p1 = np.transpose(np.matrix(node['points'][1])) c = (p0 + p1) * 0.5 c[1] = h * 0.5 dp = p1 - p0 dp_l = np.linalg.norm(dp) dp = dp / dp_l angle = np.arccos(dp[0]) rot_q = Quaternion(axis=[0, 1, 0], radians=angle) half_extents = np.array([dp_l, h, node['depth']]) * 0.5 return self.add_box(obj_id=node['id'], half_extents=half_extents, transform=Transform(translation=c, rotation=rot_q), static=True)
def add_house_room_only(self, house, room, no_walls=False, no_ceil=True, no_floor=False, use_separate_walls=False, only_architecture=False, static=False): #walls, ceil, floor logic not fleshed out due to current limited use case room_node = [node for node in house.nodes if node.id == room.id] if len(room_node) < 1: raise Exception("Missing Room") if only_architecture: house.nodes = room_node else: house.nodes = [node for node in room.nodes] house.nodes.append(room_node[0]) for node in house.nodes: if not node.valid: continue if not hasattr(node, 'body'): node.body = None if node.type == 'Object': node.body = self.add_object(node, static=static) if node.type == 'Room': ceil = False if no_ceil else not (hasattr(node, 'hideCeiling') and node.hideCeiling == 1) wall = False if (no_walls or use_separate_walls) else not ( hasattr(node, 'hideWalls') and node.hideWalls == 1) floor = False if no_floor else not (hasattr(node, 'hideFloor') and node.hideFloor == 1) node.body = self.add_room(node, wall=wall, floor=floor, ceiling=ceil) if node.type == 'Box': half_widths = list(map(lambda x: 0.5 * x, node.dimensions)) node.body = self.add_box(obj_id=node.id, half_extents=half_widths, transform=Transform.from_node(node), static=static) if use_separate_walls and not no_walls: for wall in house.walls: wall['body'] = self.add_wall(wall)
def add_object(self, node, create_vis_mesh=False, static=False): model_id = node.modelId.replace( '_mirror', '') # TODO: need to otherwise account for mirror? object_dir = os.path.join(self._data_dir_base, 'object') basename = f'{object_dir}/{model_id}/{model_id}' vis_obj_filename = f'{basename}.obj' if create_vis_mesh else None col_obj_filename = f'{basename}.vhacd.obj' if not os.path.exists(col_obj_filename): print( 'WARNING: collision mesh {col_obj_filename} unavailable, using visual mesh instead.' ) col_obj_filename = f'{basename}.obj' return self.add_mesh(obj_id=node.id, obj_file=col_obj_filename, transform=Transform.from_node(node), vis_mesh_file=vis_obj_filename, static=static)
def get_candidate_transform(self, node, max_iterations=100): num_checks = 0 zmin = self._objects.room.zmin while True: num_checks += 1 p = self._objects.room.obb.sample() ray_from = [p[0], zmin - .5, p[2]] ray_to = [p[0], zmin + .5, p[2]] intersection = ags._objects.simulator.ray_test(ray_from, ray_to) if intersection.id == self.room_id + 'f' or num_checks > max_iterations: break xform = Transform() xform.set_translation([p[0], zmin + .1, p[2]]) angle = random() * 2 * math.pi angular_resolution = 2 * math.pi / self._num_angle_divisions angle = round(angle / angular_resolution) * angular_resolution xform.set_rotation(radians=angle) return xform
def add_architecture(n, obj_file, suffix): return self.add_mesh(obj_id=n.id + suffix, obj_file=obj_file, transform=Transform(), vis_mesh_file=None, static=True)
def from_node(cls, node, aligned_dims): xform = Transform.from_mat4x4_flat_row_major(node.transform) return cls(center=xform.translation, half_widths=aligned_dims * xform.scale * 0.5, rotation_matrix=xform.rotation.rotation_matrix)
def from_local2world_transform(cls, transform): xform = Transform.from_mat4(transform) return cls(center=xform.translation, half_widths=xform.scale, rotation_matrix=xform.rotation.rotation_matrix)
def render(self, room): projection = self.pgen.get_projection(room) visualization = np.zeros((self.size, self.size)) nodes = [] for node in room.nodes: modelId = node.modelId #Camelcase due to original json t = np.asarray(node.transform).reshape(4, 4) o = Obj(modelId) t = projection.to_2d(t) o.transform(t) save_t = t t = projection.to_2d() bbox_min = np.dot(np.asarray([node.xmin, node.zmin, node.ymin, 1]), t) bbox_max = np.dot(np.asarray([node.xmax, node.zmax, node.ymax, 1]), t) xmin = math.floor(bbox_min[0]) ymin = math.floor(bbox_min[2]) xsize = math.ceil(bbox_max[0]) - xmin + 1 ysize = math.ceil(bbox_max[2]) - ymin + 1 description = {} description["modelId"] = modelId description["transform"] = node.transform description["bbox_min"] = bbox_min description["bbox_max"] = bbox_max description["id"] = node.id description["child"] = [c.id for c in node.child ] if node.child else None description["parent"] = node.parent.id if isinstance( node.parent, Node) else node.parent #if description["parent"] is None or description["parent"] == "Ceiling": # print(description["modelId"]) # print(description["parent"]) # print(node.zmin - room.zmin) #print("FATAL ERROR") #Since it is possible that the bounding box information of a room #Was calculated without some doors/windows #We need to handle these cases if ymin < 0: ymin = 0 if xmin < 0: xmin = 0 #xmin = 0 #ymin = 0 #xsize = 256 #ysize = 256 #print(list(bbox_min), list(bbox_max)) #print(xmin, ymin, xsize, ysize) rendered = self.render_object(o, xmin, ymin, xsize, ysize, self.size) description["height_map"] = torch.from_numpy(rendered).float() #tmp = np.zeros((self.size, self.size)) #tmp[xmin:xmin+rendered.shape[0],ymin:ymin+rendered.shape[1]] = rendered #visualization += tmp # Compute the pixel-space dimensions of the object before it has been # transformed (i.e. in object space) objspace_bbox_min = np.dot(o.bbox_min, t) objspace_bbox_max = np.dot(o.bbox_max, t) description['objspace_dims'] = np.array([ objspace_bbox_max[0] - objspace_bbox_min[0], objspace_bbox_max[2] - objspace_bbox_min[2] ]) # Render an OBB height map as well bbox_dims = o.bbox_max - o.bbox_min model_matrix = Transform(scale=bbox_dims[:3], translation=o.bbox_min[:3]).as_mat4() full_matrix = np.matmul(np.transpose(save_t), model_matrix) obb = OBB.from_local2world_transform(full_matrix) obb_tris = np.asarray(obb.get_triangles(), dtype=np.float32) bbox_min = np.min(np.min(obb_tris, 0), 0) bbox_max = np.max(np.max(obb_tris, 0), 0) xmin, ymin = math.floor(bbox_min[0]), math.floor(bbox_min[2]) xsize, ysize = math.ceil(bbox_max[0]) - xmin + 1, math.ceil( bbox_max[2]) - ymin + 1 rendered_obb = self.render_object_helper(obb_tris, xmin, ymin, xsize, ysize, self.size) description["height_map_obb"] = torch.from_numpy( rendered_obb).float() description['bbox_min_obb'] = bbox_min description['bbox_max_obb'] = bbox_max tmp = np.zeros((self.size, self.size)) tmp[xmin:xmin + rendered.shape[0], ymin:ymin + rendered.shape[1]] = rendered visualization += tmp nodes.append(description) if hasattr(room, "transform"): t = projection.to_2d(np.asarray(room.transform).reshape(4, 4)) else: t = projection.to_2d() #Render the floor o = Obj(room.modelId + "f", room.house_id, is_room=True) o.transform(t) floor = self.render_object(o, 0, 0, self.size, self.size, self.size) visualization += floor floor = torch.from_numpy(floor).float() #Render the walls o = Obj(room.modelId + "w", room.house_id, is_room=True) o.transform(t) wall = self.render_object(o, 0, 0, self.size, self.size, self.size) visualization += wall wall = torch.from_numpy(wall).float() return (visualization, (floor, wall, nodes))