Open kolibril13 opened 1 year ago
The context error is happening with this operator call:
It hasn't proved to be problematic in the past running scripts via bpy
. You could maybe try overriding the context, just for that function call: https://docs.blender.org/api/current/bpy.ops.html#overriding-context
But it might be something that has to be handled more internally with MN.
I'v got something to render, but still didn't see the molecule. Using one tricks from the stackexchange, also didn't work on the first click, but render something on the second click. I guess something with starting the context. I don't know much about bpy, but it looks like the context override might be a good direction. Since in the context of Gradio, every new call to generate, should start from a new fresh context. do you have more directions here @BradyAJohnston? thanks
import gradio as gr
import bpy
from tqdm import tqdm
from math import pi
import tempfile
import molecularnodes as mn
window = bpy.context.window
screen = window.screen
def get_areas(type):
return [area for area in screen.areas if area.type == type]
def get_regions(areas):
return [region for region in areas[0].regions if region.type == 'WINDOW']
def generate(progress=gr.Progress(track_tqdm=True)):
area_type = 'VIEW_3D'
areas = get_areas(area_type)
with bpy.context.temp_override(window=window, area=areas[0], region=get_regions(areas)[0], screen=screen):
for obj in bpy.context.scene.objects:
if obj.type == 'MESH':
bpy.data.objects.remove(obj, do_unlink=True)
molecule = mn.load.molecule_rcsb("7TYG", starting_style="cartoon", center_molecule=True) # <- this line would causes the error 🐛
molecule.select_set(True)
bpy.context.view_layer.objects.active = molecule
bpy.ops.view3d.camera_to_view_selected()
camera = bpy.data.objects["Camera"]
camera.data.dof.use_dof = True
camera.data.dof.focus_distance = 5
camera.data.dof.aperture_fstop = 4
camera.data.angle = pi / 3
camera.data.type = "PERSP"
with tempfile.NamedTemporaryFile(suffix=".JPEG", delete=False) as f:
bpy.context.scene.render.resolution_y = 1000
bpy.context.scene.render.resolution_x = 1000
bpy.context.scene.render.image_settings.file_format = "JPEG"
bpy.context.scene.render.filepath = f.name
with tqdm() as pbar:
def elapsed(dummy):
pbar.update()
bpy.app.handlers.render_stats.append(elapsed)
bpy.context.scene.frame_set(1)
bpy.context.scene.frame_current = 1
bpy.ops.render.render(animation=False, write_still=True)
bpy.data.images["Render Result"].save_render(
filepath=bpy.context.scene.render.filepath
)
bpy.app.handlers.render_stats.clear()
return f.name
with gr.Blocks() as demo:
with gr.Row():
with gr.Column():
render_btn = gr.Button("Render")
with gr.Column(scale=3):
image = gr.Image(type="filepath")
render_btn.click(
generate,
outputs=[image],
)
demo.queue(concurrency_count=1)
demo.launch(debug=True, inline=True)
I've got it working initially. Definitely a context problem, and should be one that I can fix in molecularnodes
itself by specifying the context.
I got around it by appending the required nodes first:
https://huggingface.co/spaces/bradyajohnston/gradio-molecular-nodes/blob/main/app.py
import gradio as gr
import bpy
from tqdm import tqdm
from math import pi
import tempfile
import molecularnodes as mn
import os
window = bpy.context.window
screen = window.screen
style = 'cartoon'
nodes_to_append = ["MN_color_set",
"MN_color_common",
"MN_color_attribute_random",
mn.nodes.styles_mapping[style]]
def get_areas(type):
return [area for area in screen.areas if area.type == type]
def get_regions(areas):
return [region for region in areas[0].regions if region.type == 'WINDOW']
for node in nodes_to_append:
bpy.ops.wm.append(
'INVOKE_DEFAULT',
directory = os.path.join(mn.nodes.mn_data_file, 'NodeTree'),
filename = node,
link = False
)
def generate(progress=gr.Progress(track_tqdm=True)):
area_type = 'VIEW_3D'
areas = get_areas(area_type)
with bpy.context.temp_override(window=window, area=areas[0], region=get_regions(areas)[0], screen=screen):
for obj in bpy.context.scene.objects:
if obj.type == 'MESH':
bpy.data.objects.remove(obj, do_unlink=True)
molecule = mn.load.molecule_rcsb("7TYG", starting_style=style, center_molecule=True) # <- this line would causes the error 🐛
molecule.select_set(True)
bpy.context.view_layer.objects.active = molecule
bpy.ops.view3d.camera_to_view_selected()
camera = bpy.data.objects["Camera"]
camera.data.dof.use_dof = True
camera.data.dof.focus_distance = 5
camera.data.dof.aperture_fstop = 4
camera.data.angle = pi / 3
camera.data.type = "PERSP"
with tempfile.NamedTemporaryFile(suffix=".JPEG", delete=False) as f:
bpy.context.scene.render.resolution_y = 1000
bpy.context.scene.render.resolution_x = 1000
bpy.context.scene.render.image_settings.file_format = "JPEG"
bpy.context.scene.render.filepath = f.name
with tqdm() as pbar:
def elapsed(dummy):
pbar.update()
bpy.app.handlers.render_stats.append(elapsed)
bpy.context.scene.frame_set(1)
bpy.context.scene.frame_current = 1
bpy.ops.render.render(animation=False, write_still=True)
bpy.data.images["Render Result"].save_render(
filepath=bpy.context.scene.render.filepath
)
bpy.app.handlers.render_stats.clear()
return f.name
with gr.Blocks() as demo:
with gr.Row():
with gr.Column():
render_btn = gr.Button("Render")
with gr.Column(scale=3):
image = gr.Image(type="filepath")
render_btn.click(
generate,
outputs=[image],
)
demo.queue(concurrency_count=1)
demo.launch(debug=True, inline=True)
The rendering is slow for me at least because I'm not paying for GPUs, but it works. This along with a bunch of other issues I want to improve before releasing a new version to pip
, but then it should be more streamlined.
Very cool @BradyAJohnston! I want to lean more about bpy!, thanks for testing it, please share on social! 👏
Wow, that's great to hear, thanks for making this happen, this is really exciting! 👏 And good news: I've applied for a community Grant to get GPU access at hugging face for this project, and that Grant just got approved 🎉🎉🎉 https://huggingface.co/spaces/kolibril13/blender-with-solara/discussions/1#651d704566df2227d9df0090
Nice @kolibril13, leave a comment when it's up and running and I'll have a bit of a ply around if I have some time.
it's now up and running here: https://huggingface.co/spaces/sci-blender/blender-with-solara I've transferred the repo from my personal account to a new hugging face organization called sci-blender, and I've invited you two there @BradyAJohnston, @radames (Quick note: The GPU access was not affected by the repo transfer, we still have the nvidia t4 small :) ) So when you accept the invite, you two should be able to directly commit to that project as well.
I've also just tested the script a bit: Locally, on my Mac M1, it takes 1 second to render the image. On hugging face with GPU, it takes 60 seconds to render. so I think the script is currently not taking advantage of the GPU on huggingface.
@radames you wrote the function enable_GPUS()
https://github.com/radames/Gradio-Blender-bpy/blob/main/app.py#L11-L31
for your torrus-gradio example.
I removed that function for the current hugging face instance, so probably a new enable_GPUS function can be added to this new repo at https://huggingface.co/spaces/sci-blender/blender-with-solara
cool! we can try this, does this render engine make sense @BradyAJohnston ?
def enable_GPUS():
bpy.data.scenes[0].render.engine = "CYCLES" #"CYCLES"
# Set the device_type
bpy.context.preferences.addons[
"cycles"
].preferences.compute_device_type = "CUDA" # or "OPENCL"
# Set the device and feature set
bpy.context.scene.cycles.device = "GPU"
for scene in bpy.data.scenes:
scene.cycles.device = "GPU"
bpy.context.preferences.addons["cycles"].preferences.get_devices()
print(bpy.context.preferences.addons["cycles"].preferences.compute_device_type)
for d in bpy.context.preferences.addons["cycles"].preferences.devices:
d["use"] = True # Using all devices, include GPU and CPU
print(d["name"])
enable_GPUS()
I've add the code above and it works! it takes about 10s now, It would be great to add some Gradio params, to change the the molecular view
@radames: great to hear that it now take 10 s instead of 60 seconds on hugging face! :) It takes 1 second on a local Mac, so I'm curious if there's an option for even faster rendering on hugging face. I just posted this interest in https://blender.chat/channel/python, maybe someone there has an idea to give us even more GPU boost.
@BradyAJohnston : I just added another commit to the project, and now there's a build error:
https://huggingface.co/spaces/sci-blender/blender-with-solara
ERROR: Cannot install -r requirements.txt (line 2) and bpy because these package versions have conflicting dependencies.
The conflict is caused by:
The user requested bpy
molecularnodes 2.11.0 depends on bpy<4.0 and >=3.5.0
The user requested bpy
molecularnodes 2.10.0 depends on bpy<4.0.0 and >=3.5.0
It was working a few days ago. Any idea what might be going wrong here? EDIT: I've just simplified the example and the error is not there anymore, so this is something we can look at later.
I've now simplified the webapp at https://huggingface.co/spaces/sci-blender/blender-with-solara to this minimal example, so it becomes easier to focus on the GPU incorperation:
import gradio as gr
import bpy
import tempfile
def generate():
with tempfile.NamedTemporaryFile(suffix=".JPEG", delete=False) as f:
bpy.context.scene.render.resolution_y = 200
bpy.context.scene.render.resolution_x = 400
bpy.context.scene.render.image_settings.file_format = "JPEG"
bpy.context.scene.render.filepath = f.name
bpy.ops.render.render(animation=False, write_still=True)
bpy.data.images["Render Result"].save_render(
filepath=bpy.context.scene.render.filepath
)
bpy.app.handlers.render_stats.clear()
return f.name
with gr.Blocks() as demo:
with gr.Row():
with gr.Column():
render_btn = gr.Button("Render")
with gr.Column(scale=3):
image = gr.Image(type="filepath")
render_btn.click(
generate,
outputs=[image],
)
demo.queue(concurrency_count=1)
demo.launch(debug=True, inline=True)
Interestingly, the CPU example renders differently on a mac M1 and on huggingface.
hi @radames , hi @BradyAJohnston,
it's been some time, but now I came back to our molecular nodes as a standalone app at https://huggingface.co/spaces/sci-blender/blender-with-gradio
Unfortunately, we have now an error when we try to install bpy with the nvidia t4 small from the community grant:
ERROR: Cannot install -r requirements.txt (line 2) and bpy because these package versions have conflicting dependencies.
The conflict is caused by:
The user requested bpy
molecularnodes 2.11.0 depends on bpy<4.0 and >=3.5.0
The user requested bpy
molecularnodes 2.10.0 depends on bpy<4.0.0 and >=3.5.0
To fix this you could try to:
1. loosen the range of package versions you've specified
2. remove package versions to allow pip attempt to solve the dependency conflict
I've tried to fix bpy==3.6.0
but that brings that error as well.
Interestingly, the app runs fine on the system without the gpu:
any ideas how to build the app with gpu?
hi @kolibril13, I'm sorry they've remove the grant if there is no activity, do you have plans to progress it?
hi @radames,
They did not remove the grant! :) I was only comparing CPU basic with the Nvidia T4 small setting. I got to know that the installation of the packages works fine on the CPU basic plan, but I get the "conflicting dependencies" error when I switch to the Nvidia T4 small plan. Any ideas to make this work?
hi @radames thanks for creating this project, which converts python blender pipelines to stand-alone web apps.
I want to share an idea for a follow-up project: @bradyajohnston just created the "molecularnode" package, which brings rendering of molecules to python. here's his recent tweet about that:
Now, I think it would be awesome to convert these molecule plotting pipelines into a web app as well.
Therefore, I've made a fork of Gradio-Blender-bpy and simplified the code into a minimal example, just the basic square. https://huggingface.co/spaces/kolibril13/gradio-molecule-blender-bpy
Then I created two notebooks for debugging, one that is very close to the minimal webapp, another one with 6 extra lines that also import the molecule. That works all correcly.
However, when I now modify the webapp by adding the line
mn.load.molecule_rcsb
to the minimal webapp and uncomment these 6 lines with the "#":I get a "context is incorrect" the error:
this seems to be a common error (see https://blender.stackexchange.com/questions/6101/poll-failed-context-incorrect-example-bpy-ops-view3d-background-image-add).
Do you have an idea how to set the default context here the right way?