def __get_normalize_transform(self, active_view): centroid = active_view.center scale = active_view.scale normalize_transform = Transform.scale(Vector(scale, scale, scale)) *\ Transform.translate(Vector(*(-1 * centroid))) return normalize_transform
def __add_cone(self, shape): y_dir = np.array([0.0, 1.0, 0.0]) v = shape.end_points[1] - shape.end_points[0] center = 0.5 * (shape.end_points[0] + shape.end_points[1]) height = norm(v) scale = Transform.scale(Vector(shape.radius, height, shape.radius)) axis = np.cross(y_dir, v) axis_len = norm(axis) angle = degrees(atan2(axis_len, np.dot(y_dir, v))) if (axis_len > 1e-6): axis /= axis_len rotate = Transform.rotate(Vector(*axis), angle) else: axis = np.array([1.0, 0.0, 0.0]) rotate = Transform.rotate(Vector(*axis), angle) translate = Transform.translate(Vector(*center)) cone_file = self.file_resolver.resolve("cone.ply") cone_transform = translate * rotate * scale setting = { "type": "ply", "filename": cone_file, "toWorld": cone_transform } return setting
def __add_floor(self): rotate_transform = Transform.rotate(Vector(-1, 0, 0), 90) scale_transform = Transform.scale(Vector(100, 100, 100)) translate_transform = Transform.translate( Vector(0.0, self.floor_height, 0.0)) total_transform = translate_transform * scale_transform\ * rotate_transform if self.scene.active_view.background == "d": reflectance = Spectrum(0.05) elif self.scene.active_view.background == "l": reflectance = Spectrum(0.5) else: reflectance = Spectrum(0.0) floor = self.plgr.create({ "type": "rectangle", "toWorld": total_transform, "bsdf": { "type": "roughdiffuse", "diffuseReflectance": reflectance, "alpha": 0.5 } }) self.mitsuba_scene.addChild(floor)
def transform_lookAt(self, origin, target, up, scale=None): # Blender is Z up but Mitsuba is Y up, convert the lookAt transform = Transform.lookAt( Point(origin[0], origin[2], -origin[1]), Point(target[0], target[2], -target[1]), Vector(up[0], up[2], -up[1])) if scale is not None: transform *= Transform.scale(Vector(scale, scale, 1)) return transform
def axis_unit_vector(axis: str): """ Create a unit vector along the given axis :param axis: 3D axis x, y, or z :return: A Vector of length one along the specified axis """ if axis == 'x': return Vector(1, 0, 0) elif axis == 'y': return Vector(0, 1, 0) elif axis == 'z': return Vector(0, 0, 1) else: raise ValueError("Choose between x, y, and z")
def getCameraAltitudeHeight(self, main_scene_xml_file_prifix, pos_x, pos_z): currdir = os.path.split(os.path.realpath(__file__))[0] sys.path.append(currdir + '/bin/rt/' + current_rt_program + '/python/2.7/') os.environ[ 'PATH'] = currdir + '/bin/rt/' + current_rt_program + os.pathsep + os.environ[ 'PATH'] import mitsuba from mitsuba.core import Vector, Point, Ray, Thread from mitsuba.render import SceneHandler import platform scenepath = session.get_scenefile_path() fileResolver = Thread.getThread().getFileResolver() logger = Thread.getThread().getLogger() logger.clearAppenders() scenepath = scenepath.encode('utf-8') fileResolver.appendPath(scenepath) filepath = os.path.join(session.get_scenefile_path(), main_scene_xml_file_prifix + terr_scene_file).encode("utf-8") scene = SceneHandler.loadScene(fileResolver.resolve(filepath)) scene.configure() scene.initialize() ray = Ray() ray.setOrigin(Point(pos_x, 999999999, pos_z)) ray.setDirection(Vector(0, -1, 0)) its = scene.rayIntersect(ray) if not its is None: return its.p[1] else: print("Camera is outside of the scene, do not use relative height") return 0
def rayIntersect(self, o, xyz): origin = Point(self.X(o[0]), o[2], self.Y(o[1])) vector = Vector(-xyz[0], xyz[2], -xyz[1]) ray = Ray() ray.setOrigin(origin) ray.setDirection(vector) its = self.scene.rayIntersect(ray) if its is None: return None else: itsp = its.p return self.X(itsp[0]), self.Y(itsp[2]), itsp[1]
def __add_active_camera(self): active_view = self.scene.active_view camera = self.scene.active_camera if active_view.transparent_bg: pixel_format = "rgba" else: pixel_format = "rgb" crop_bbox = np.array(camera.crop_bbox) if np.amax(crop_bbox) <= 1.0: # bbox is relative. crop_bbox[:, 0] *= self.image_width crop_bbox[:, 1] *= self.image_height assert (np.all(crop_bbox >= 0)) assert (np.all(crop_bbox[:, 0] <= self.image_width)) assert (np.all(crop_bbox[:, 1] <= self.image_height)) mitsuba_camera = self.plgr.create({ "type": "perspective", "fov": float(camera.fovy), "fovAxis": "y", "toWorld": Transform.lookAt(Point(*camera.location), Point(*camera.look_at_point), Vector(*camera.up_direction)), "film": { "type": "ldrfilm", "width": self.image_width, "height": self.image_height, "cropOffsetX": int(crop_bbox[0, 0]), "cropOffsetY": int(crop_bbox[0, 1]), "cropWidth": int(crop_bbox[1, 0] - crop_bbox[0, 0]), "cropHeight": int(crop_bbox[1, 1] - crop_bbox[0, 1]), "banner": False, "pixelFormat": pixel_format, "rfilter": { "type": "gaussian" } }, "sampler": { "type": "halton", "sampleCount": 4, } }) self.mitsuba_scene.addChild(mitsuba_camera)
def makeScene(): scene = Scene() pmgr = PluginManager.getInstance() # make shapes for i in range(100): shapeProps = Properties("sphere") shapeProps["center"] = Point(i, i, i) shapeProps["radius"] = 0.1 shape = pmgr.createObject(shapeProps) shape.configure() scene.addChild(shape) # make perspective sensor sensorProps = Properties("perspective") sensorProps["toWorld"] = Transform.lookAt(Point(0, 0, 10), Point(0, 0, 0), Vector(0, 1, 0)) sensorProps["fov"] = 45.0 sensor = pmgr.createObject(sensorProps) # make film filmProps = Properties("ldrfilm") filmProps["width"] = 640 filmProps["height"] = 480 film = pmgr.createObject(filmProps) film.configure() sensor.addChild("film", film) sensor.configure() scene.addChild(sensor) scene.configure() return scene
def forest_generate_according_tree_pos_file_for3d(config_file_path): import mitsuba from mitsuba.core import Vector, Point, Ray, Thread from mitsuba.render import SceneHandler from mitsuba.render import RenderQueue, RenderJob from mitsuba.render import Scene from mitsuba.render import Intersection f = open(config_file_path, 'r') cfg = json.load(f) tree_pos = combine_file_path(session.get_input_dir(), cfg["scene"]["forest"]["tree_pos_file"]) if cfg["scene"]["forest"]["tree_pos_file"] == "" or ( not os.path.exists(tree_pos)): return # 读取地形数据 计算每个树的高程 if cfg["scene"]["terrain"]["terrain_type"] != "PLANE" and cfg["scene"][ "terrain"]["terrain_type"] == "RASTER": demfile = combine_file_path(session.get_input_dir(), cfg["scene"]["terrain"]["terr_file"]) img_w, img_h, dem_arr = RasterHelper.read_dem_as_array(demfile) dem_arr = dem_arr - dem_arr.min() scenepath = session.get_scenefile_path() if "Windows" in platform.system(): scenepath = str(scenepath.replace('\\', '\\\\')) # 得到高程信息 通过光线跟踪的方法精确得到高程信息 fileResolver = Thread.getThread().getFileResolver() logger = Thread.getThread().getLogger() logger.clearAppenders() fileResolver.appendPath(scenepath) # 由于batch模式不会改变地形几何结构,因此在用地形打点计算树木的高程时,用第一个terrain文件即可,所以加上了_0_ scene = SceneHandler.loadScene( fileResolver.resolve(str(terr_scene_file))) scene.configure() scene.initialize() tf = open(tree_pos) objectPosFile = open( os.path.join(session.get_input_dir(), "object_pos_3dView.txt"), 'w') # 创建一个虚拟根节点,最后再删除 for line in tf: arr = line.replace("\n", "").split(" ") objectName = arr[0] x = float(arr[1]) y = float(arr[2]) xScale = cfg["scene"]["terrain"]["extent_width"] zScale = cfg["scene"]["terrain"]["extent_height"] treeX = 0.5 * xScale - x treeZ = 0.5 * zScale - y if cfg["scene"]["terrain"]["terrain_type"] != "PLANE": ray = Ray() ray.setOrigin(Point(treeX, 9999, treeZ)) ray.setDirection(Vector(0, -1, 0)) its = scene.rayIntersect(ray) if not its is None: linestr = objectName + " " + str(treeX) + " " + str( its.p[1]) + " " + str(treeZ) + "\n" else: # log("warning: precise height not found.") if cfg["scene"]["terrain"]["terrain_type"] == "RASTER": im_r = int((y / float(zScale)) * img_h) im_c = int((x / float(xScale)) * img_w) if im_r >= img_h: im_r = img_h - 1 if im_c >= img_w: im_c = img_w - 1 linestr = objectName + " " + str(treeX) + " " + str( dem_arr[im_r][im_c]) + " " + str(treeZ) + "\n" else: linestr = objectName + " " + str(treeX) + " " + str( 0) + " " + str(treeZ) + "\n" else: linestr = objectName + " " + str(treeX) + " " + str( 0) + " " + str(treeZ) + "\n" objectPosFile.write(linestr) objectPosFile.close()
def __add_quarter(self): scale = self.scene.active_view.scale radius = 12.13 * scale thickness = 0.875 * scale face_scale = Transform.scale(Vector(radius)) tail_offset = Transform.translate(Vector(0, 0, thickness)) head_offset = Transform.translate(Vector(0, 0, -thickness)) *\ Transform.scale(Vector(1.0, 1.0, -1.0)) bbox_diag = 0.5 * norm(self.transformed_bbox_max - self.transformed_bbox_min) custom_transform = Transform.translate( Vector(0.5, self.floor_height + radius + 0.01, -bbox_diag - 0.01)) head_texture = self.file_resolver.resolve("head.png") tail_texture = self.file_resolver.resolve("tail.png") side_texture = self.file_resolver.resolve("side.png") quarter_ring = self.plgr.create({ "type": "cylinder", "p0": Point(0.0, 0.0, thickness), "p1": Point(0.0, 0.0, -thickness), "radius": radius, "toWorld": custom_transform, "bsdf": { "type": "bumpmap", "texture": { "type": "scale", "scale": 0.01, "texture": { "type": "bitmap", "filename": side_texture, "gamma": 1.0, "uscale": 100.0, }, }, "bsdf": { "type": "roughconductor", "distribution": "ggx", "alpha": 0.5, "material": "Ni_palik" #"diffuseReflectance": Spectrum(0.5) } } }) head = self.plgr.create({ "type": "disk", "toWorld": custom_transform * head_offset * face_scale, "bsdf": { "type": "diffuse", "reflectance": { "type": "bitmap", "filename": head_texture } } }) tail = self.plgr.create({ "type": "disk", "toWorld": custom_transform * tail_offset * face_scale, "bsdf": { "type": "diffuse", "reflectance": { "type": "bitmap", "filename": tail_texture } } }) self.mitsuba_scene.addChild(quarter_ring) self.mitsuba_scene.addChild(head) self.mitsuba_scene.addChild(tail)
def forest_generate_according_tree_pos_file(config_file_path, forest_file_name, linestart, lineend, forest_prifix=""): import mitsuba from mitsuba.core import Vector, Point, Ray, Thread from mitsuba.render import SceneHandler from mitsuba.render import RenderQueue, RenderJob from mitsuba.render import Scene from mitsuba.render import Intersection f = open(config_file_path, 'r') cfg = json.load(f) tree_pos = combine_file_path(session.get_input_dir(), cfg["scene"]["forest"]["tree_pos_file"]) if cfg["scene"]["forest"]["tree_pos_file"] == "" or ( not os.path.exists(tree_pos)): return # 保存场景中树的位置 forest*.xml # f = open(os.path.join(session.get_scenefile_path(),forest_file_name),'w') f = codecs.open( os.path.join(session.get_scenefile_path(), forest_file_name), "w", "utf-8-sig") doc = minidom.Document() root = doc.createElement("scene") doc.appendChild(root) root.setAttribute("version", "0.5.0") #读取地形数据 计算每个树的高程 if cfg["scene"]["terrain"]["terrain_type"] != "PLANE" and cfg["scene"][ "terrain"]["terrain_type"] == "RASTER": demfile = combine_file_path(session.get_input_dir(), cfg["scene"]["terrain"]["terr_file"]) img_w, img_h, dem_arr = RasterHelper.read_dem_as_array(demfile) dem_arr = dem_arr - dem_arr.min() #读取object boundingbox 数据 bound_path = os.path.join(session.get_input_dir(), obj_bounding_box_file) if os.path.exists(bound_path): fobj = open(bound_path) bound_dict = dict() for line in fobj: arr = line.split(":") objName = arr[0] arr = list(map(lambda x: float(x), arr[1].split(" "))) bound_dict[objName] = [ arr[3] - arr[0], arr[4] - arr[1], arr[5] - arr[2] ] scenepath = session.get_scenefile_path() # if "Windows" in platform.system(): # scenepath = str(scenepath.replace('\\', '\\\\')) #得到高程信息 通过光线跟踪的方法精确得到高程信息 fileResolver = Thread.getThread().getFileResolver() logger = Thread.getThread().getLogger() logger.clearAppenders() fileResolver.appendPath(str(scenepath)) # 由于batch模式不会改变地形几何结构,因此在用地形打点计算树木的高程时,用第一个terrain文件即可,所以加上了_0_ # if(forest_prifix != ""): # forest_prifix = forest_prifix[0:len(forest_prifix)-1] +"_0_" scene = SceneHandler.loadScene( fileResolver.resolve(str(forest_prifix + terr_scene_file))) # scene = SceneHandler.loadScene(fileResolver.resolve(r"E:\Research\20-LESS\RealScene\SimProj\calLAI\Parameters\_scenefile\terrain1.xml")) scene.configure() scene.initialize() tf = open(tree_pos) hidden_objects = SceneGenerate.get_hidded_objects() #创建一个虚拟根节点,最后再删除 treeIdx = 0 for line in tf: if treeIdx >= linestart and treeIdx <= lineend: arr = line.replace("\n", "").strip().split(" ") objectName = arr[0] if objectName in hidden_objects: continue shapenode = doc.createElement("shape") root.appendChild(shapenode) shapenode.setAttribute("type", "instance") refnode = doc.createElement("ref") shapenode.appendChild(refnode) refnode.setAttribute("id", objectName) trnode = doc.createElement("transform") shapenode.appendChild(trnode) trnode.setAttribute("name", "toWorld") if len(arr) == 6: # fit with scale_node = doc.createElement("scale") trnode.appendChild(scale_node) scale_node.setAttribute( "x", str(float(arr[4]) / bound_dict[objectName][0])) scale_node.setAttribute( "z", str(float(arr[4]) / bound_dict[objectName][0])) scale_node.setAttribute( "y", str(float(arr[5]) / bound_dict[objectName][1])) if len(arr) == 5: # for rotation of the tree angle = arr[len(arr) - 1] rotatenode = doc.createElement("rotate") trnode.appendChild(rotatenode) rotatenode.setAttribute("y", '1') rotatenode.setAttribute("angle", angle) translatenode = doc.createElement("translate") trnode.appendChild(translatenode) x = float(arr[1]) y = float(arr[2]) z = float(arr[3]) xScale = cfg["scene"]["terrain"]["extent_width"] zScale = cfg["scene"]["terrain"]["extent_height"] # treeX = xScale - x * (2 * xScale) / float(img_w) # treeZ = zScale - y * (2 * zScale) / float(img_h) treeX = 0.5 * xScale - x treeZ = 0.5 * zScale - y translatenode.setAttribute("x", str(treeX)) translatenode.setAttribute("z", str(treeZ)) if cfg["scene"]["terrain"]["terrain_type"] != "PLANE": ray = Ray() ray.setOrigin(Point(treeX, 9999, treeZ)) ray.setDirection(Vector(0, -1, 0)) its = scene.rayIntersect(ray) if not its is None: translatenode.setAttribute("y", str(its.p[1] + z)) # translatenode.setAttribute("y", str(z)) else: # log("warning: precise height not found.") if cfg["scene"]["terrain"]["terrain_type"] == "RASTER": im_r = int((y / float(zScale)) * img_h) im_c = int((x / float(xScale)) * img_w) if im_r >= img_h: im_r = img_h - 1 if im_c >= img_w: im_c = img_w - 1 translatenode.setAttribute( "y", str(dem_arr[im_r][im_c] + z)) else: translatenode.setAttribute("y", str(z)) else: translatenode.setAttribute("y", str(z)) treeIdx += 1 xm = doc.toprettyxml() # xm = xm.replace('<?xml version="1.0" ?>', '') f.write(xm) f.close() log("INFO: Objects and positions generated.")
def do_simulation_multiangle_seq(seqname): currdir = os.path.split(os.path.realpath(__file__))[0] sys.path.append(currdir + '/bin/rt/' + current_rt_program + '/python/2.7/') os.environ['PATH'] = currdir + '/bin/rt/' + current_rt_program + os.pathsep + os.environ['PATH'] import mitsuba from mitsuba.core import Vector, Point, Ray, Thread, Scheduler, LocalWorker, PluginManager, Transform from mitsuba.render import SceneHandler from mitsuba.render import RenderQueue, RenderJob from mitsuba.render import Scene import multiprocessing scheduler = Scheduler.getInstance() for i in range(0, multiprocessing.cpu_count()): scheduler.registerWorker(LocalWorker(i, 'wrk%i' % i)) scheduler.start() scene_path = session.get_scenefile_path() fileResolver = Thread.getThread().getFileResolver() fileResolver.appendPath(str(scene_path)) scene = SceneHandler.loadScene(fileResolver.resolve( str(os.path.join(session.get_scenefile_path(), main_scene_xml_file)))) scene.configure() scene.initialize() queue = RenderQueue() sceneResID = scheduler.registerResource(scene) bsphere = scene.getKDTree().getAABB().getBSphere() radius = bsphere.radius targetx, targety, targetz = bsphere.center[0], bsphere.center[1], bsphere.center[2] f = open(seqname + ".conf", 'r') params = json.load(f) obs_azimuth = params['seq1']['obs_azimuth'] obs_zenith = params['seq2']['obs_zenith'] cfgfile = session.get_config_file() f = open(cfgfile, 'r') cfg = json.load(f) viewR = cfg["sensor"]["obs_R"] mode = cfg["sensor"]["film_type"] azi_arr = map(lambda x: float(x), obs_azimuth.strip().split(":")[1].split(",")) zeni_arr = map(lambda x: float(x), obs_zenith.strip().split(":")[1].split(",")) seq_header = multi_file_prefix + "_" + seqname index = 0 for azi in azi_arr: for zeni in zeni_arr: distFile = os.path.join(session.get_output_dir(), seq_header + ("_VA_%.2f" % azi).replace(".", "_") + ("_VZ_%.2f" % zeni).replace(".", "_")) newScene = Scene(scene) pmgr = PluginManager.getInstance() newSensor = pmgr.createObject(scene.getSensor().getProperties()) theta = zeni / 180.0 * math.pi phi = (azi - 90) / 180.0 * math.pi scale_x = radius scale_z = radius toWorld = Transform.lookAt( Point(targetx - viewR * math.sin(theta) * math.cos(phi), targety + viewR * math.cos(theta), targetz - viewR * math.sin(theta) * math.sin(phi)), # original Point(targetx, targety, targetz), # target Vector(0, 0, 1) # up ) * Transform.scale( Vector(scale_x, scale_z, 1) # 视场大小 ) newSensor.setWorldTransform(toWorld) newFilm = pmgr.createObject(scene.getFilm().getProperties()) newFilm.configure() newSensor.addChild(newFilm) newSensor.configure() newScene.addSensor(newSensor) newScene.setSensor(newSensor) newScene.setSampler(scene.getSampler()) newScene.setDestinationFile(str(distFile)) job = RenderJob('Simulation Job' + "VA_"+str(azi)+"_VZ_"+str(zeni), newScene, queue, sceneResID) job.start() queue.waitLeft(0) queue.join() # handle npy if mode == "spectrum" and (output_format not in ("npy", "NPY")): for azi in azi_arr: for zeni in zeni_arr: distFile = os.path.join(session.get_output_dir(), seq_header + ("_VA_%.2f" % azi).replace(".", "_") + ("_VZ_%.2f" % zeni).replace( ".", "_")) data = np.load(distFile + ".npy") bandlist = cfg["sensor"]["bands"].split(",") RasterHelper.saveToHdr_no_transform(data, distFile, bandlist, output_format) os.remove(distFile + ".npy")
def vector(self, x, y, z): # Blender is Z up but Mitsuba is Y up, convert the vector return Vector(x, z, -y)