123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- # THIS FILE IS A PART OF VCStudio
- # PYTHON 3
- ##############################################################################
- # Now you are probably asking yourself. Network? Render? How are these related?
- # Actually it's a complicated answer. So let's walk through the idea of the
- # Renderer implementation in VCStudio.
- # Why do we need renderer in the first place? Doesn't blender already has one?
- # Well yes. And I would not care if I was always sitting on a biffy, nice
- # machine. But back in 2016, 2017 when I was making I'm Not Even Human I realized
- # one very ennoying fact.
- # My lap top at the time could not manage the loads of the files. And while
- # rendering Blender would crash very often. Of course I was not dumb as was
- # rendering into image files and not straight into video. So I could start
- # rendering from the last frame.
- # Unfortunatly it was happening way too often. So I started looking at ways to
- # unload things from the memory so Blender would crash less. One of those ways
- # is rendering using a console. Type blender -b <filename> -a and it will launch
- # blender without UI saving some memory. Also I could do a simple script that
- # restores Blender when if it does crashes.
- # By the time of Blender-Organizer 4.0 I had a system of rendering that will
- # look into a folder and see if any file between start and end frame are missing
- # and render them. Instead of trying to render every single frame in sequense.
- # Also in Blender-Organizer 4.0 I made a very clever thing. I openned the
- # rendering not in a terminal, but rather in it's own process that is piped to
- # a little UI window. Where I show some quick analytics. Tho there was one
- # problem. Closing the window was closing the blender. Or if not there was no
- # way to cancel it. And it would continue till the end or till the crash.
- # So here since VCStudio is a complite re-write of Blender-Organizer I can try
- # to re-implement the renderer in a slightly better way.
- # I will run a script that recieves stuff from the pipe and has an ability to
- # kill the blender's process. And this script will have no UI. But will instead
- # use LOCAL NETWORK to talk to VCStudio. I'm using 127.0.0.1 for this so on
- # any normal system even without Internet connection it should work. Since this
- # IP adress simply means THIS COMPUTER.
- # I will probably implement some LOCAL NETWORK talk ability later for the
- # multiuser.
- # This file is collection of functions for Rendering network sub-system. The UI
- # are contained in studio folder. Render it self is a separate file.
- ##############################################################################
- import os
- import json
- import socket
- def read_renders(win):
-
- # This function will listen for 127.0.0.1 port 54545 for data about current
- # renders. NOTE: I'm not doing any encryption and will use UDP protocol.
- # so it's quite simple to mess arround with it. NO SECURITY. But I don't see
- # any use in hacking it appart from maybe making VCStudio think it's rendering
- # a different frame or something.
-
- # First thing. And you probably think that I'm crazy but bare with me. I
- # need to see if a active_renders.data exists. And will read from it on
- # each frame. I know. A bit of not cool. But to be honest. The language
- # files are also read at every frame. Yeah...
-
- if not os.path.exists(win.project+"/set/active_renders.data"):
- m = open(win.project+"/set/active_renders.data", "w")
- m.close()
-
- # Now we are going to read it on every frame to see that renders are still
- # there.
-
- r = open(win.project+"/set/active_renders.data")
- r = r.read()
- r = r.split("\n")
-
- filenames = []
-
- for filename in r:
- if filename:
-
- # So basically the file contains list of files currently placed for
- # rendering. The renderer will go one by one and when finised will
- # remove the filename from this file. Also to cancel the render the
- # filename should be removed. The rest will be done using a very
- # crappy UDP network protocol on localhost.
-
- # Now if you just openned the VCStudio. While maybe render were
- # doing their job somewhere on the background. You want to re-new
- # all of the data.
-
- # So...
-
- if filename not in win.renders:
-
- # We are going to read the JSON file of the render.
-
- folder = filename[:filename.rfind("/")]+"/extra"
- savefile = folder+filename[filename.rfind("/"):]+".json"
-
- # It might not exits so we are going to do this with try.
-
- try:
- with open(win.project+savefile) as json_file:
- data = json.load(json_file)
-
- win.renders[filename] = data
-
- except:
- pass
-
- # Now let's make a list of all lines anyway
-
- if filename not in filenames:
- filenames.append(filename)
-
- # Now let's remove any of them renders that are finished or otherwise
- # removed from the file.
-
- for stuff in list(win.renders.keys()):
-
- if stuff not in filenames:
- del win.renders[stuff]
- try:
- if stuff == win.current["renders_window"]["filename"]:
- win.current["renders_window"]["filename"] = ""
- except:
- pass
-
- # Now that we know about the data. Let's read the stream from the network
-
- string_read = ""
-
- try:
- UDP_IP = "127.0.0.1"
- UDP_PORT = 54545
-
- sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- sock.bind((UDP_IP, UDP_PORT))
-
- # Now usually it will wait for a message untill one appears. But render
- # could be finished. Or some error might accur. Or it could be that no
- # render what so ever. So I don't want the UI to freez. So I'm going to
- # put a timeout. Very short timeout.
-
- sock.settimeout(0.005)
-
- # This comes with it's own problems. Mainly I tested I need to send
- # about 500 messages at ones for it to be recognized at all. But it's
- # not a big deal what so ever. Just need to keep in mind. 500 messages.
-
- data, addr = sock.recvfrom(1024)
- data = data.decode('utf8')
-
- sock.close()
-
- string_read = data
-
- except:
- pass
-
- # Now let's do something with this data we read from the stream.
- # We gonna complitelly ignore anything unrelated. Such as not from
- # the project.
-
- if "network_render_timeout_frame" not in win.current:
- win.current["network_render_timeout_frame"] = win.current["frame"]
-
- if string_read.startswith("VCStudio : "):
- if ": RENDERING :" in string_read:
-
- blend, blend_string = string_read.split(" : ")[2], string_read.split(" : ")[3]
-
- # So we've got 2 peaces of data from the renderer. Blender. Which
- # is a path to the blend file. Similar to the one in
- # active_renders.data file that we read previously.
-
- # And we've got a raw string that blender outputs during render.
- # Example:
- # Fra:70 Mem:93.09M (Peak 97.78M) | Time:00:01.83 | Rendering 26 / 64 samples
-
- # You can find a string like this in the top banner inside the blender.
-
- # From this string we can find out a bunch of things. But not everything is
- # that simple. Cycles and Eevee for exmple output different strings. Any
- # other, wild render engine will output it's own string.
-
- # Now I'd like to actually load the data from the JSON file at every step
- # like this. Because our rendering script will be recording and saving
- # render times of each frame into the file. I need it for analytics.
-
- if blend in win.renders:
-
- folder = blend[:blend.rfind("/")]+"/extra"
- savefile = folder+blend[blend.rfind("/"):]+".json"
-
- # It might not exits so we are going to do this with try.
-
- try:
- with open(win.project+savefile) as json_file:
- data = json.load(json_file)
-
- win.renders[blend] = data
- except:
- pass
-
- win.renders[blend]["rendering"] = blend_string
-
- # Next is let's try finding out the current frame rendering. It's
- # probably not that hard. Every string usually starts with Fra:<number>
-
- # So let's try doing it.
- frame = 0
- try:
- frame = int(blend_string[4:blend_string.find(" ")])
- except:
- pass
-
- win.renders[blend]["current_frame"] = frame
-
- # The rest of it I will do in the UI.
-
- win.current["network_render_timeout_frame"] = win.current["frame"]
-
-
- # Now sometimes for no particular reason the whole rendering thing could crash
- # or in other words. If there is no data sent. We want to clean the renderings
- # and make it so the user sees that renders DO NOT render. For this there should
- # be a timeout system. Basically if in a given amount of frames there is no message
- # from the renderer script. We going to say that it's not rendering.
-
- if win.current["frame"] - win.current["network_render_timeout_frame"] > 100:
- for blend in win.renders:
- win.renders[blend]["rendering"] = False
-
- def stop_render(win):
-
- # This function will stop the rendering. It will bombard the renderer with
- # stop messages.
-
- for i in range(5000):
- cs1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- cs1.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- cs1.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
- cs1.sendto(bytes("VCStudio : RENDER STOP", 'utf-8'), ('127.0.0.1', 54545))
-
-
-
|