diff --git a/configs/graph_default.yaml b/configs/graph_default.yaml index 176860e8d..d5c08b7a6 100644 --- a/configs/graph_default.yaml +++ b/configs/graph_default.yaml @@ -103,6 +103,4 @@ optimizers: viewer: enable: False zmq_url: tcp://127.0.0.1:6000 - min_render_image_height: 100 - max_render_image_height: 1000 num_rays_per_chunk: 4096 diff --git a/pyrad/viewer/app/src/Viewer.jsx b/pyrad/viewer/app/src/Viewer.jsx index 77a0784d3..1248b50bd 100644 --- a/pyrad/viewer/app/src/Viewer.jsx +++ b/pyrad/viewer/app/src/Viewer.jsx @@ -128,6 +128,34 @@ export class Viewer extends Component { } } + send_min_resolution_over_websocket(value){ + if (this.state.websocket.readyState === WebSocket.OPEN) { + let cmd = "set_min_resolution"; + let path = "Min Resolution"; + let data = { + type: cmd, + path: path, + min_resolution: value, + }; + let message = msgpack.encode(data); + this.state.websocket.send(message); + } + } + + send_max_resolution_over_websocket(value){ + if (this.state.websocket.readyState === WebSocket.OPEN) { + let cmd = "set_max_resolution"; + let path = "Max Resolution"; + let data = { + type: cmd, + path: path, + max_resolution: value, + }; + let message = msgpack.encode(data); + this.state.websocket.send(message); + } + } + set_object(path, object) { if (!(object instanceof THREE.Camera)) { this.state.scene_tree.find(path.concat([""])).set_object(object); @@ -175,15 +203,13 @@ export class Viewer extends Component { } } + // TODO(evonne): eventually change name to setup backend functions set_output_options(object) { if (this.created_controls === false) { let output_options_control = new (function () { this.output_options = "default"; })(); - let params = { - switch: false, - }; - // add controls + // add output options this.state.gui .add(output_options_control, "output_options", object) .name("Output Options") @@ -191,13 +217,39 @@ export class Viewer extends Component { .onChange((value) => { this.send_output_type_over_websocket(value); }); + // add pause training switch + let switch_params = { + switch: false, + }; this.state.gui - .add(params, "switch") + .add(switch_params, "switch") .name("Pause Training?") .listen() .onChange((value) => { this.send_training_state_over_websocket(value); }); + // add min resolution + let min_slider_params = { + value: 50 + } + this.state.gui + .add(min_slider_params, "value", 25, 100) + .name("Min Resolution") + .listen() + .onFinishChange((value) => { + this.send_min_resolution_over_websocket(value); + }) + // add max resolution + let max_slider_params = { + value: 1000 + } + this.state.gui + .add(max_slider_params, "value", 800, 2000) + .name("Max Resolution") + .listen() + .onFinishChange((value) => { + this.send_max_resolution_over_websocket(value); + }) } this.created_controls = true; } diff --git a/pyrad/viewer/server/server.py b/pyrad/viewer/server/server.py index b37606302..75abdb27a 100644 --- a/pyrad/viewer/server/server.py +++ b/pyrad/viewer/server/server.py @@ -108,6 +108,10 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler): find_node(self.bridge.tree, path).object = data elif type_ == "set_output_type": find_node(self.bridge.tree, path).object = data + elif type_ == "set_max_resolution": + find_node(self.bridge.tree, path).object = data + elif type_ == "set_min_resolution": + find_node(self.bridge.tree, path).object = data elif type_ == "set_training_state": find_node(self.bridge.tree, path).object = data elif type_ == "offer": @@ -196,6 +200,10 @@ class ZMQWebSocketBridge(object): find_node(self.tree, path).object = data elif cmd == "set_output_type": find_node(self.tree, path).object = data + elif cmd == "set_max_resolution": + find_node(self.tree, path).object = data + elif cmd == "set_min_resolution": + find_node(self.tree, path).object = data elif cmd == "set_training_state": find_node(self.tree, path).object = data elif cmd == "get_object": diff --git a/pyrad/viewer/server/viewer_utils.py b/pyrad/viewer/server/viewer_utils.py index cabccbedf..516ed13fd 100644 --- a/pyrad/viewer/server/viewer_utils.py +++ b/pyrad/viewer/server/viewer_utils.py @@ -98,17 +98,17 @@ class CheckThread(threading.Thread): def run(self): self.state.check_done_render = False + is_interrupt = False while not self.state.check_done_render: # check camera data = self.state.vis["/Cameras/Main Camera"].get_object() - if data is None: - return - camera_object = data["object"]["object"] - if self.state.prev_camera_matrix is None or not np.array_equal( - camera_object["matrix"], self.state.prev_camera_matrix - ): - self.state.check_interrupt_vis = True - self.state.prev_camera_matrix = camera_object["matrix"] + if data is not None: + camera_object = data["object"]["object"] + if self.state.prev_camera_matrix is None or not np.allclose( + camera_object["matrix"], self.state.prev_camera_matrix + ): + is_interrupt = True + self.state.prev_camera_matrix = camera_object["matrix"] # check output type data = self.state.vis["/Output Type"].get_object() @@ -117,7 +117,25 @@ class CheckThread(threading.Thread): else: output_type = data["output_type"] if self.state.prev_output_type != output_type: - self.state.check_interrupt_vis = True + is_interrupt = True + + # check max render + data = self.state.vis["/Max Resolution"].get_object() + if data is not None: + max_resolution = int(data["max_resolution"]) + if self.state.max_resolution != max_resolution: + is_interrupt = True + self.state.max_resolution = max_resolution + + # check min render + data = self.state.vis["/Min Resolution"].get_object() + if data is not None: + min_resolution = int(data["min_resolution"]) + if self.state.min_resolution != min_resolution: + is_interrupt = True + self.state.min_resolution = min_resolution + + self.state.check_interrupt_vis = is_interrupt time.sleep(0.001) @@ -139,6 +157,8 @@ class VisualizerState: # visualizer specific variables self.prev_camera_matrix = None self.prev_output_type = "default" + self.min_resolution = 50 + self.max_resolution = 1000 self.res_upscale_factor = 1 self.check_interrupt_vis = False self.check_done_render = True @@ -232,7 +252,7 @@ class VisualizerState: return camera_object = data["object"]["object"] # hacky way to prevent overflow check to see if < 100; TODO(make less hacky) - if self.prev_camera_matrix is not None and np.array_equal(camera_object["matrix"], self.prev_camera_matrix): + if self.prev_camera_matrix is not None and np.allclose(camera_object["matrix"], self.prev_camera_matrix): self.res_upscale_factor = min(self.res_upscale_factor * 2, 100) else: self.prev_camera_matrix = camera_object["matrix"] @@ -246,9 +266,18 @@ class VisualizerState: output_type = data["output_type"] self.prev_output_type = output_type + # check and perform min/max update + data = self.vis["/Max Resolution"].get_object() + if data is not None: + self.max_resolution = int(data["max_resolution"]) + + data = self.vis["/Min Resolution"].get_object() + if data is not None: + self.min_resolution = int(data["min_resolution"]) + image_height = min( - self.config.min_render_image_height * self.res_upscale_factor, - self.config.max_render_image_height, + self.min_resolution * self.res_upscale_factor, + self.max_resolution, ) intrinsics_matrix, camera_to_world_h = get_intrinsics_matrix_and_camera_to_world_h( camera_object, image_height=image_height